Update the ChangeLog for bug #4008
[maxima.git] / share / graphs / graph_core.lisp
blob87b262198ebef0b04d3b5d88c19c0f387f3b0891
1 ;;;
2 ;;; GRAPHS - graph theory package for Maxima
3 ;;;
4 ;;; Copyright (C) 2007-2011 Andrej Vodopivec <andrej.vodopivec@gmail.com>
5 ;;;
6 ;;; This program is free software; you can redistribute it and/or modify
7 ;;; it under the terms of the GNU General Public License as published by
8 ;;; the Free Software Foundation; either version 2 of the License, or
9 ;;; (at your option) any later version.
10 ;;;
11 ;;; This program is distributed in the hope that it will be useful,
12 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ;;; GNU General Public License for more details.
15 ;;;
16 ;;; You should have received a copy of the GNU General Public License
17 ;;; along with this program; if not, write to the Free Software
18 ;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 ;;;
22 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 ;;;
24 ;;; graph and digraph datastructure
25 ;;;
26 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
28 (in-package :maxima)
30 ($put '$graphs 2.0 '$version)
32 (defstruct (graph
33 (:print-function
34 (lambda (stru strm depth)
35 (format strm "GRAPH(~a vertices, ~a edges)" (graph-order stru) (graph-size stru)))))
36 (size 0)
37 (order 0)
38 (vertices ())
39 (vertex-labels (make-hash-table))
40 (vertex-positions)
41 (edges ())
42 (edge-weights (make-hash-table :test #'equal))
43 (neighbors (make-hash-table)))
45 (defstruct (digraph
46 (:print-function
47 (lambda (stru strm depth)
48 (format strm "DIGRAPH(~a vertices, ~a arcs)" (digraph-order stru) (digraph-size stru)))))
49 (size 0)
50 (order 0)
51 (vertices ())
52 (vertex-labels (make-hash-table))
53 (edges ())
54 (vertex-positions)
55 (edge-weights (make-hash-table :test #'equal))
56 (in-neighbors (make-hash-table))
57 (out-neighbors (make-hash-table)))
59 (defun require-graph (m ar gr)
60 (unless (graph-p gr)
61 ($error (format nil "Argument ~a to `~a' is not a graph:" ar m) gr)))
63 (defun require-digraph (m ar gr)
64 (unless (digraph-p gr)
65 ($error (format nil "Argument ~a to `~a' is not a directed graph:" ar m) gr)))
67 (defun require-graph-or-digraph (m ar gr)
68 (unless (or (graph-p gr) (digraph-p gr))
69 ($error (format nil "Argument ~a to `~a' is not a graph:" ar m) gr)))
71 (defmfun $print_graph (gr)
72 (require-graph-or-digraph 'print_graph 1 gr)
73 (cond
74 ((graph-p gr)
75 (format t "~%Graph on ~d vertices with ~d edges."
76 (graph-order gr) (graph-size gr))
77 (when (> (graph-order gr) 0 )
78 (format t "~%Adjacencies:"))
79 (dolist (v (graph-vertices gr))
80 (format t "~% ~2d :" v)
81 (dolist (u (neighbors v gr))
82 (format t " ~2d" u))))
84 (format t "~%Digraph on ~d vertices with ~d arcs."
85 (digraph-order gr) (digraph-size gr))
86 (when (> (digraph-order gr) 0 )
87 (format t "~%Adjacencies:"))
88 (dolist (v (digraph-vertices gr))
89 (format t "~% ~2d :" v)
90 (dolist (u (out-neighbors v gr))
91 (format t " ~2d" u)))))
92 (format t "~%")
93 '$done)
95 (defmfun $is_graph (x)
96 (graph-p x))
98 (defmfun $is_digraph (x)
99 (digraph-p x))
101 (defmfun $is_graph_or_digraph (x)
102 (or (graph-p x) (digraph-p x)))
104 (defmfun $graph_order (gr)
105 (require-graph-or-digraph 'graph_order 1 gr)
106 (if (graph-p gr)
107 (graph-order gr)
108 (digraph-order gr)))
110 (defmfun $graph_size (gr)
111 (require-graph-or-digraph 'graph_size 1 gr)
112 (if (graph-p gr)
113 (graph-size gr)
114 (digraph-size gr)))
116 (defmfun $get_positions (gr)
117 (require-graph-or-digraph 'get_positions 1 gr)
118 (if (graph-p gr)
119 (graph-vertex-positions gr)
120 (digraph-vertex-positions gr)))
122 (defmfun $set_positions (pos gr)
123 (require-graph-or-digraph 'set_positions 2 gr)
124 (if (graph-p gr)
125 (setf (graph-vertex-positions gr) pos)
126 (setf (digraph-vertex-positions gr) pos)))
128 (defmfun $copy_graph (gr)
129 (require-graph-or-digraph 'copy_graph 1 gr)
130 (if (graph-p gr)
131 (let ((g (make-graph)))
132 (dolist (v (graph-vertices gr))
133 (add-vertex v g)
134 (let ((l (get-vertex-label v gr)))
135 (if l (set-vertex-label v l g))))
136 (dolist (e (graph-edges gr))
137 (add-edge e g)
138 (let ((w (get-edge-weight e gr)))
139 (if w (set-edge-weight e w g))))
140 ($set_positions ($get_positions gr) g)
142 (let ((g (make-digraph)))
143 (dolist (v (digraph-vertices gr))
144 (add-vertex v g)
145 (let ((l (get-vertex-label v gr)))
146 (if l (set-vertex-label v l g))))
147 (dolist (e (digraph-edges gr))
148 (add-edge e g)
149 (let ((w (get-edge-weight e gr)))
150 (if w (set-edge-weight e w g))))
151 ($set_positions ($get_positions gr) g)
152 g) ))
154 (defmfun $new_graph ()
155 (make-graph))
157 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
159 ;;; vertex operations
161 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
163 (defmfun $vertices (gr)
164 (require-graph-or-digraph 'vertices 1 gr)
165 (let ((vrt (vertices gr)))
166 `((mlist simp) ,@(copy-list vrt))))
168 (defun vertices (gr)
169 (if (graph-p gr) (graph-vertices gr) (digraph-vertices gr)))
171 (defun require-vertex (m i v)
172 (unless (integerp v)
173 ($error "Argument" i "to" m "is not a valid vertex.")))
175 (defun is-vertex-in-graph (i gr)
176 (not (equal (gethash i
177 (if (graph-p gr)
178 (graph-neighbors gr)
179 (digraph-out-neighbors gr))
180 'not-in-graph)
181 'not-in-graph)))
183 (defun require-vertex-in-graph (m i gr)
184 (unless (is-vertex-in-graph i gr)
185 ($error m ": vertex not in graph.")))
187 (defmfun $is_vertex_in_graph (i gr)
188 (require-vertex 'vertex_in_graph 1 i)
189 (require-graph-or-digraph 'vertex_in_graph 2 gr)
190 (is-vertex-in-graph i gr))
192 (defmfun $add_vertex (i &optional gr)
193 (unless gr
194 (setq gr i)
195 (setq i (1+ (apply #'max (vertices gr)))))
196 (require-vertex 'add_vertex 1 i)
197 (require-graph-or-digraph 'add_vertex 2 gr)
198 (when (is-vertex-in-graph i gr)
199 ($error "add_vertex: vertex is already in the graph!"))
200 (add-vertex i gr)
203 (defmfun $add_vertices (vl gr)
204 (require-graph-or-digraph 'add_vertices 2 gr)
205 (unless (or (integerp vl) ($listp vl))
206 ($error "Argument 1 to add_vertices is not a list."))
207 (if ($listp vl)
208 (dolist (v (cdr vl))
209 ($add_vertex v gr))
210 (let* ((n vl))
211 (setq vl ())
212 (dotimes (i n)
213 (setf vl (cons ($add_vertex gr) vl)))
214 (setf vl (cons '(mlist simp) (reverse vl)))))
217 (defun add-vertex (i gr)
218 (if (graph-p gr)
219 (progn
220 (incf (graph-order gr))
221 (push i (graph-vertices gr))
222 (setf (graph-vertex-positions gr) nil)
223 (setf (gethash i (graph-neighbors gr)) ()))
224 (progn
225 (incf (digraph-order gr))
226 (push i (digraph-vertices gr))
227 (setf (digraph-vertex-positions gr) nil)
228 (setf (gethash i (digraph-in-neighbors gr)) ())
229 (setf (gethash i (digraph-out-neighbors gr)) ())) ))
231 (defun neighbors (i gr)
232 (gethash i (if (graph-p gr)
233 (graph-neighbors gr)
234 (digraph-out-neighbors gr))) )
236 (defun in-neighbors (i gr)
237 (gethash i (digraph-in-neighbors gr)))
239 (defun out-neighbors (i gr)
240 (gethash i (digraph-out-neighbors gr)))
242 (defmfun $neighbors (i gr)
243 (require-vertex 'neighbors 1 i)
244 (require-graph 'neighbors 2 gr)
245 (require-vertex-in-graph 'neighbors i gr)
246 `((mlist simp) ,@(copy-list (neighbors i gr))))
248 (defmfun $out_neighbors (i gr)
249 (require-vertex 'out_neighbors 1 i)
250 (require-digraph 'out_neighbors 2 gr)
251 (require-vertex-in-graph 'out_neighbors i gr)
252 `((mlist simp) ,@(copy-list (out-neighbors i gr))))
254 (defmfun $in_neighbors (i gr)
255 (require-vertex 'in_neighbors 1 i)
256 (require-digraph 'in_neighbors 2 gr)
257 (require-vertex-in-graph 'in_neighbors i gr)
258 `((mlist simp) ,@(copy-list (in-neighbors i gr))))
260 (defmfun $degree_sequence (gr)
261 (require-graph 'degree_sequence 1 gr)
262 (let ((s ()))
263 (dolist (v (graph-vertices gr))
264 (push (length (neighbors v gr)) s))
265 (setq s (sort s #'<))
266 `((mlist simp) ,@s)))
268 (defmfun $remove_vertex (v gr)
269 (require-vertex 'remove_vertex 1 v)
270 (require-graph-or-digraph 'remove_vertex 2 gr)
271 (require-vertex-in-graph 'remove_vertex v gr)
272 (clear-vertex-label v gr)
273 (remove-vertex v gr))
275 (defmfun $remove_vertices (vl gr)
276 (require-graph-or-digraph 'remove_vertices 2 gr)
277 (when (not ($listp vl))
278 ($error "Argument 1 to remove_vertices is not a list."))
279 (dolist (v (cdr vl))
280 ($remove_vertex v gr))
281 '$done)
283 (defun remove-vertex (v gr)
284 (if (graph-p gr)
285 (progn
286 (dolist (u (neighbors v gr))
287 (let ((e (list (min u v) (max u v))))
288 (remove-edge e gr)))
289 (clear-vertex-label v gr)
290 (when (graph-vertex-positions gr)
291 (setf (graph-vertex-positions gr)
292 (cons '(mlist simp) (remove-if (lambda (x) (= (cadr x) v))
293 (cdr (graph-vertex-positions gr))))))
294 (setf (graph-vertices gr) (remove v (graph-vertices gr) :count 1))
295 (remhash v (graph-neighbors gr))
296 (decf (graph-order gr)))
297 (progn
298 (dolist (u (out-neighbors v gr))
299 (remove-edge (list v u) gr))
300 (dolist (u (in-neighbors v gr))
301 (remove-edge (list u v) gr))
302 (clear-vertex-label v gr)
303 (when (digraph-vertex-positions gr)
304 (setf (digraph-vertex-positions gr)
305 (cons '(mlist simp) (remove-if (lambda (x) (= (cadr x) v))
306 (cdr (digraph-vertex-positions gr))))))
307 (setf (digraph-vertices gr) (remove v (digraph-vertices gr) :count 1))
308 (remhash v (digraph-in-neighbors gr))
309 (remhash v (digraph-out-neighbors gr))
310 (decf (digraph-order gr))))
311 '$done)
313 (defmfun $first_vertex (gr)
314 (require-graph-or-digraph 'first_vertex 1 gr)
315 (cond
316 ((= 0 (if (graph-p gr) (graph-order gr) (digraph-order gr)))
317 ($error "first_vertex: no first vertex in an empty graph."))
318 (t (first (vertices gr)))))
320 (defmfun $max_degree (gr)
321 (require-graph 'max_degree 1 gr)
322 (cond
323 ((= 0 (graph-order gr))
324 ($error "max_degree: no max degree in an empty graph."))
326 (let* ((v (first (graph-vertices gr))) (d (length (neighbors v gr))))
327 (dolist (u (graph-vertices gr))
328 (when (> (length (neighbors u gr)) d)
329 (setq d (length (neighbors u gr)))
330 (setq v u)))
331 `((mlist simp) ,d ,v)))))
333 (defmfun $min_degree (gr)
334 (require-graph 'min_degree 1 gr)
335 (cond
336 ((= 0 (graph-order gr))
337 ($error "min_degree: no min degree in an empty graph."))
339 (let* ((v (first (graph-vertices gr))) (d (length (neighbors v gr))))
340 (dolist (u (graph-vertices gr))
341 (when (< (length (neighbors u gr)) d)
342 (setq d (length (neighbors u gr)))
343 (setq v u)))
344 `((mlist simp) ,d ,v)))))
346 (defmfun $average_degree (gr)
347 (require-graph 'average_degee 1 gr)
348 (m* 2 (m// (graph-size gr) (graph-order gr))))
350 (defmfun $vertex_degree (v gr)
351 (require-vertex 'vertex_degree 1 v)
352 (require-graph 'vertex_degree 2 gr)
353 (require-vertex-in-graph 'vertex_degree v gr)
354 (length (neighbors v gr)))
356 (defmfun $vertex_in_degree (v gr)
357 (require-vertex 'vertex_in_degree 1 v)
358 (require-digraph 'vertex_in_degree 2 gr)
359 (require-vertex-in-graph 'vertex_in_degree v gr)
360 (length (in-neighbors v gr)))
362 (defmfun $vertex_out_degree (v gr)
363 (require-vertex 'vertex_out_degree 1 v)
364 (require-digraph 'vertex_out_degree 2 gr)
365 (require-vertex-in-graph 'vertex_out_degree v gr)
366 (length (out-neighbors v gr)))
368 (defmfun $get_vertex_label (v gr &optional default)
369 (require-vertex 'get_vertex_label 1 v)
370 (require-graph-or-digraph 'get_vertex_label 2 gr)
371 (require-vertex-in-graph 'vertex_label v gr)
372 (or (get-vertex-label v gr) default))
374 (defun get-vertex-label (v gr)
375 (gethash v (if (graph-p gr)
376 (graph-vertex-labels gr)
377 (digraph-vertex-labels gr))))
379 (defmfun $clear_vertex_label (v gr)
380 (require-vertex 'clear_vertex_label 1 v)
381 (require-graph-or-digraph 'clear_vertex_label 2 gr)
382 (require-vertex-in-graph 'clear_label v gr)
383 (clear-vertex-label v gr))
385 (defun clear-vertex-label (v gr)
386 (remhash v (if (graph-p gr)
387 (graph-vertex-labels gr)
388 (digraph-vertex-labels gr)))
389 '$done)
391 (defmfun $set_vertex_label (v l gr)
392 (require-vertex 'set_vertex_label 1 v)
393 (require-graph-or-digraph 'set_vertex_label 3 gr)
394 (require-vertex-in-graph 'set_label v gr)
395 (set-vertex-label v l gr))
397 (defun set-vertex-label (v l gr)
398 (setf (gethash v (if (graph-p gr)
399 (graph-vertex-labels gr)
400 (digraph-vertex-labels gr)))
402 '$done)
404 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
406 ;;; edge operations
408 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
410 (defun require-medge (m ar e)
411 (cond
412 ((not (and ($listp e) (eql 2 ($length e))))
413 ($error "Argument" ar "to" m "is not an edge (0)."))
414 (t (let ((u ($first e)) (v ($second e)))
415 (unless (and (integerp u) (integerp v))
416 ($error "Argument" ar "to" m "is not an edge (1)."))
417 (when (eq u v)
418 ($error "Argument" ar "to" m "is not an edge (2)."))))))
420 (defun require-edge-in-graph (m e gr)
421 (unless (is-edge-in-graph e gr)
422 ($error m ": edge not in graph.")))
424 (defun m-edge-to-l-edge (e)
425 (let ((uv (cdr e)))
426 (list (apply #'min uv) (apply #'max uv))))
428 (defun m-edge-to-l-dedge (e)
429 (let ((uv (cdr e)))
430 (list (first uv) (second uv))))
432 (defun l-edge-to-m-edge (e)
433 `((mlist simp) ,@e))
435 (defmfun $is_edge_in_graph (e gr)
436 (require-medge 'is_edge_in_graph 1 e)
437 (require-graph-or-digraph 'is_edge_in_graph 2 gr)
438 (if (graph-p gr)
439 (is-edge-in-graph (m-edge-to-l-edge e) gr)
440 (is-edge-in-graph (m-edge-to-l-dedge e) gr)))
442 (defun is-edge-in-graph (e gr)
443 (if (graph-p gr)
444 (not (null (member (second e) (neighbors (first e) gr))))
445 (not (null (member (second e) (out-neighbors (first e) gr)))) ))
447 (defmfun $add_edge (e gr)
448 (require-medge 'add_edge 1 e)
449 (require-graph-or-digraph 'add_edge 2 gr)
450 (let* ((e1 (if (graph-p gr)
451 (m-edge-to-l-edge e)
452 (m-edge-to-l-dedge e)))
453 (u (first e1)) (v (second e1)))
454 (cond
455 ((not (and (is-vertex-in-graph u gr) (is-vertex-in-graph v gr)))
456 ($error "add_edge: end vertices are not in graph!"))
457 ((eq u v)
458 ($error "add_edge: end vertices are equal!"))
459 ((is-edge-in-graph e1 gr)
460 ($error "add_edge: edge already in graph!")))
461 (add-edge e1 gr)))
463 (defmfun $add_edges (el gr)
464 (require-graph-or-digraph 'add_edges 2 gr)
465 (if (not ($listp el))
466 ($error "Argument 1 to add_edges is not a list!")
467 (dolist (e (cdr el))
468 (require-medge 'add_edges 1 e)
469 ($add_edge e gr)))
470 '$done)
472 (defun add-edge (e gr)
473 (let ((u (first e)) (v (second e)))
474 (if (graph-p gr)
475 (progn
476 (push v (gethash u (graph-neighbors gr)))
477 (push u (gethash v (graph-neighbors gr)))
478 (push e (graph-edges gr))
479 (incf (graph-size gr)))
480 (progn
481 (push v (gethash u (digraph-out-neighbors gr)))
482 (push u (gethash v (digraph-in-neighbors gr)))
483 (push e (digraph-edges gr))
484 (incf (digraph-size gr))))
485 '$done))
487 (defun add-edges (elist gr)
488 (dolist (e elist)
489 (add-edge e gr)))
491 (defmfun $edges (gr)
492 (require-graph-or-digraph 'edges 1 gr)
493 (let ((e (mapcar #'(lambda (u) `((mlist simp) ,@(copy-list u)))
494 (edges gr))))
495 `((mlist simp) ,@e)))
497 (defun edges (gr)
498 (if (graph-p gr)
499 (graph-edges gr)
500 (digraph-edges gr)))
502 (defmfun $remove_edge (e gr)
503 (require-medge 'remove_edge 1 e)
504 (require-graph-or-digraph 'remove_edge 2 gr)
505 (unless ($is_edge_in_graph e gr)
506 ($error "remove_edge: edge" e "is not in graph."))
507 (remove-edge (if (graph-p gr)
508 (m-edge-to-l-edge e)
509 (m-edge-to-l-dedge e))
510 gr))
512 (defmfun $remove_edges (el gr)
513 (require-graph-or-digraph 'remove_edges 2 gr)
514 (unless ($listp el)
515 ($error "Argument 1 to remove_edges is not a list."))
516 (dolist (e (cdr el))
517 ($remove_edge e gr))
518 '$done)
520 (defun remove-edge (e gr)
521 (let ((u (first e)) (v (second e)))
522 (if (graph-p gr)
523 (progn
524 (setf (gethash u (graph-neighbors gr))
525 (remove v (gethash u (graph-neighbors gr)) :count 1))
526 (setf (gethash v (graph-neighbors gr))
527 (remove u (gethash v (graph-neighbors gr)) :count 1))
528 (clear-edge-weight e gr)
529 (decf (graph-size gr))
530 (setf (graph-edges gr)
531 (remove `(,u ,v) (graph-edges gr) :test #'equal :count 1)))
532 (progn
533 (setf (gethash u (digraph-out-neighbors gr))
534 (remove v (gethash u (digraph-out-neighbors gr)) :count 1))
535 (setf (gethash v (digraph-in-neighbors gr))
536 (remove u (gethash v (digraph-in-neighbors gr)) :count 1))
537 (clear-edge-weight e gr)
538 (decf (digraph-size gr))
539 (setf (digraph-edges gr)
540 (remove `(,u ,v) (digraph-edges gr) :test #'equal :count 1))))
541 '$done))
543 (defmfun $contract_edge (e gr)
544 (require-medge 'contract_edge 1 e)
545 (require-graph 'contract_edge 2 gr)
546 (let* ((e1 (m-edge-to-l-edge e)) (u (first e1)) (v (second e1)))
547 (dolist (x (neighbors v gr))
548 (unless (= x u)
549 (let ((e2 (list (min x u) (max x u))))
550 (unless (is-edge-in-graph e2 gr)
551 (add-edge e2 gr)))))
552 (remove-vertex v gr))
553 '$done)
555 (defmfun $contract_edges (el gr)
556 (require-graph-or-digraph 'contract_edges 2 gr)
557 (unless ($listp el)
558 ($error "Argument 1 to contract_edges is not a list."))
559 (dolist (e (cdr el))
560 ($contract_edge e gr))
561 '$done)
563 (defmfun $get_edge_weight (e gr &optional default not-present)
564 (require-medge 'get_edge_weight 1 e)
565 (require-graph-or-digraph 'get_edge_weight 2 gr)
566 (unless ($is_edge_in_graph e gr)
567 (if (null not-present)
568 ($error "get_edge_weight: edge not in graph")
569 (return-from $get_edge_weight not-present)))
570 (let ((w (if (graph-p gr)
571 (get-edge-weight (m-edge-to-l-edge e) gr)
572 (get-edge-weight (m-edge-to-l-dedge e) gr))))
573 (or w default 1)))
575 (defun get-edge-weight (e gr)
576 (let* ((edge-weights
577 (if (graph-p gr)
578 (graph-edge-weights gr)
579 (digraph-edge-weights gr))))
580 (gethash e edge-weights)))
582 (defmfun $clear_edge_weight (e gr)
583 (require-medge 'clear_edge_weight 1 e)
584 (require-graph-or-digraph 'clear_edge_weight 2 gr)
585 (unless ($is_edge_in_graph e gr)
586 ($error "clear_edge_weight: edge not in graph"))
587 (if (graph-p gr)
588 (clear-edge-weight (m-edge-to-l-edge e) gr)
589 (clear-edge-weight (m-edge-to-l-dedge e) gr)))
591 (defun clear-edge-weight (e gr)
592 (let*
593 ((edge-weights
594 (if (graph-p gr)
595 (graph-edge-weights gr)
596 (digraph-edge-weights gr))))
597 (remhash e edge-weights)
598 '$done))
600 (defmfun $set_edge_weight (e w gr)
601 (require-medge 'set_edge_weight 1 e)
602 (require-graph-or-digraph 'set_edge_weight 3 gr)
603 (unless ($is_edge_in_graph e gr)
604 ($error "set_edge_weight: edge not in graph"))
605 (if (graph-p gr)
606 (set-edge-weight (m-edge-to-l-edge e) w gr)
607 (set-edge-weight (m-edge-to-l-dedge e) w gr)))
609 (defun set-edge-weight (e w gr)
610 (let*
611 ((edge-weights
612 (if (graph-p gr)
613 (graph-edge-weights gr)
614 (digraph-edge-weights gr))))
615 (setf (gethash e edge-weights) w)
616 '$done))
618 (defmfun $connect_vertices (sources sinks gr)
619 (require-graph 'connect_vertices 3 gr)
620 (if ($listp sources)
621 (setq sources (cdr sources))
622 (setq sources `(,sources)))
623 (if ($listp sinks)
624 (setq sinks (cdr sinks))
625 (setq sinks `(,sinks)))
626 (dolist (u sources)
627 (dolist (v sinks)
628 ($add_edge `((mlist simp) ,u ,v) gr)))
629 '$done)
631 (defmfun $subdivide_edge (e gr)
632 (require-graph 'subdivide_edge 2 gr)
633 (require-edge-in-graph 'subdivide_edge (m-edge-to-l-edge e) gr)
634 (let ((new-vertex (1+ (apply #'max (vertices gr))))
635 (x ($first e))
636 (y ($second e)))
637 ($remove_edge (cons '(mlist simp) (list x y)) gr)
638 ($add_vertex new-vertex gr)
639 ($add_edge (cons '(mlist simp) (list x new-vertex)) gr)
640 ($add_edge (cons '(mlist simp) (list y new-vertex)) gr))
641 '$done)
643 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
645 ;; implementation of a set using hash tables
647 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
649 (defstruct ht-set
650 (content (make-hash-table)))
652 (defun new-set (&rest initial-content)
653 (let ((set (make-ht-set)))
654 (dolist (obj initial-content)
655 (set-add obj set))
656 set))
658 (defun set-member (obj set)
659 (gethash obj (ht-set-content set)))
661 (defun set-add (obj set)
662 (setf (gethash obj (ht-set-content set)) t))
664 (defun set-remove (obj set)
665 (remhash obj (ht-set-content set)))
667 (defun set-emptyp (set)
668 (= 0 (hash-table-count (ht-set-content set))))
670 (defun set-elements (set)
671 (let (elts)
672 (maphash #'(lambda (key val)
673 (declare (ignore val))
674 (push key elts))
675 (ht-set-content set))
676 elts))
679 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
681 ;;; graph definitions
683 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
685 (defmfun $empty_graph (n)
686 (let ((gr (make-graph)))
687 (dotimes (i n)
688 (add-vertex i gr))
689 gr))
691 (defmfun $empty_digraph (n)
692 (let ((gr (make-digraph)))
693 (dotimes (i n)
694 (add-vertex i gr))
695 gr))
697 (defmfun $create_graph (v_list e_list &optional dir)
698 (let ((directed nil))
699 ;; check if the graph is a directed graph
700 (cond ((atom dir)
701 (when dir (setq directed t)))
702 ((and (eq (caar dir) 'mequal)
703 (eq (cadr dir) '$directed)
704 (eq (caddr dir) t))
705 (setq directed t)))
706 (unless (or (integerp v_list) ($listp v_list))
707 ($error "Argument 1 to create_graph is not a list."))
708 (unless ($listp e_list)
709 ($error "Argument 2 to create_graph is not a list."))
710 (let ((gr (if directed (make-digraph) (make-graph))))
711 (if (integerp v_list)
712 (dotimes (v v_list)
713 ($add_vertex v gr))
714 (dolist (v (reverse (cdr v_list)))
715 (if ($listp v)
716 (progn
717 ($add_vertex ($first v) gr)
718 ($set_vertex_label ($first v) ($second v) gr))
719 ($add_vertex v gr))))
720 (dolist (e (cdr e_list))
721 (if ($listp ($first e))
722 (progn
723 ($add_edge ($first e) gr)
724 ($set_edge_weight ($first e) ($second e) gr))
725 ($add_edge e gr)))
726 gr)))
728 (defmfun $cycle_graph (n)
729 (let ((g ($empty_graph n)) pos)
730 (dotimes (i (1- n))
731 (add-edge (list i (1+ i)) g))
732 (add-edge (list 0 (1- n)) g)
733 (dotimes (i n)
734 (setq pos (cons `((mlist simp) ,i
735 ((mlist simp) ,(cos (* i 2 pi (/ n))) ,(sin (* i 2 pi (/ n)))))
736 pos)))
737 ($set_positions (cons '(mlist simp) pos) g)
740 (defmfun $cycle_digraph (n)
741 (let ((g ($empty_digraph n)))
742 (dotimes (i (1- n))
743 (add-edge (list i (1+ i)) g))
744 (add-edge (list (1- n) 0) g)
747 (defmfun $path_graph (n)
748 (let ((g ($empty_graph n)) pos)
749 (dotimes (i (1- n))
750 (add-edge (list i (1+ i)) g))
751 (dotimes (i n)
752 (setq pos (cons `((mlist simp) ,i
753 ((mlist simp) ,i 0))
754 pos)))
755 ($set_positions (cons '(mlist simp) pos) g)
758 (defmfun $path_digraph (n)
759 (let ((g ($empty_digraph n)))
760 (dotimes (i (1- n))
761 (add-edge (list i (1+ i)) g))
764 (defmfun $petersen_graph (&optional n d)
765 (if (null d)
766 (setq n 5 d 2)
767 (unless (and (integerp n) (integerp d))
768 ($error "Arguments to petersen_graph are not integers!")))
769 (let ((g ($empty_graph (* 2 n)))
770 (positions ()))
771 (dotimes (i n)
772 (add-edge `(,i ,(+ n i)) g)
773 (when (or (/= n (* 2 d))
774 (< i d))
775 (let* ((u (+ i n)) (v (+ (mod (+ i d) n) n))
776 (e1 (min v u)) (e2 (max v u)))
777 (add-edge `(,e1 ,e2) g)))
778 (let* ((u (mod (1+ i) n)) (e1 (min u i)) (e2 (max u i)))
779 (add-edge `(,e1 ,e2) g)))
780 (dotimes (i n)
781 (push `((mlist simp) ,i ((mlist simp)
782 ,(sin (/ (* 2 i pi) n))
783 ,(cos (/ (* 2 i pi) n))))
784 positions)
785 (push `((mlist simp) ,(+ n i) ((mlist simp)
786 ,(* 0.66 (sin (/ (* 2 i pi) n)))
787 ,(* 0.66 (cos (/ (* 2 i pi) n)))))
788 positions))
789 (setf (graph-vertex-positions g) (cons '(mlist simp) positions))
792 (defmfun $complement_graph (gr)
793 (require-graph 'complement_graph 1 gr)
794 (let*
795 ((co (make-graph))
796 (vrt (vertices gr)))
797 (dolist (v vrt)
798 (add-vertex v co))
799 (dolist (u vrt)
800 (dolist (v vrt)
801 (when (and (< u v) (not (is-edge-in-graph `(,u ,v) gr)))
802 (add-edge `(,u ,v) co))))
803 (setf (graph-vertex-positions co) (graph-vertex-positions gr))
804 co))
806 (defmfun $complete_graph (n)
807 (if (not (and (integerp n ) (>= n 0)))
808 ($error "Argument 1 to complete_graph is not a positive integer"))
809 (let ((g ($empty_graph n))
810 (pos))
811 (dotimes (i n)
813 ((j (1+ i) (1+ j)))
814 ((= j n))
815 (add-edge `(,i ,j) g)))
816 (dotimes (i n)
817 (push `((mlist simp) ,i ((mlist simp)
818 ,(cos (/ (* 2 i pi) n))
819 ,(sin (/ (* 2 i pi) n))))
820 pos))
821 (setf (graph-vertex-positions g) (cons '(mlist simp) pos))
824 (defmfun $from_adjacency_matrix (m)
825 (if (not ($matrixp m))
826 ($error "Argument 1 to from_adjacency_matrix is not a matrix"))
827 (if (not (= ($length m) ($length ($first m))))
828 ($error "Argument 1 to from_adjacency_matrix is not a square matrix"))
829 (let* ((n ($length m)) (g ($empty_graph n)))
830 (dotimes (i n)
831 (do ((j (1+ i) (1+ j)))
832 ((= j n))
833 (if (not (= 0 (nth (1+ i) (nth (1+ j) m))))
834 (add-edge `(,i ,j) g))))
837 (defmfun $graph_union (&rest gr-list)
838 (cond
839 ((= 0 (length gr-list))
840 ($empty_graph 0))
841 ((= 1 (length gr-list))
842 (first gr-list))
843 ((= 2 (length gr-list))
844 (graph-union (first gr-list) (second gr-list)))
846 (graph-union (first gr-list) (apply #'$graph_union (rest gr-list))))))
848 (defun graph-union (g1 g2)
849 (require-graph 'graph_union 1 g1)
850 (require-graph 'graph_union 2 g2)
851 (let ((g (make-graph)) (n (1+ (apply #'max (graph-vertices g1)))))
852 (dolist (v (graph-vertices g1))
853 (add-vertex v g))
854 (dolist (e (graph-edges g1))
855 (add-edge e g))
856 (dolist (v (graph-vertices g2))
857 (add-vertex (+ n v) g))
858 (dolist (e (graph-edges g2))
859 (add-edge (list (+ n (first e)) (+ n (second e))) g))
862 (defmfun $graph_join (g1 g2)
863 (require-graph 'graph_join 1 g1)
864 (require-graph 'graph_join 2 g2)
865 (let ((g (make-graph)) (n (1+ (apply #'max (graph-vertices g1)))))
866 (dolist (v (graph-vertices g1))
867 (add-vertex v g))
868 (dolist (e (graph-edges g1))
869 (add-edge e g))
870 (dolist (v (graph-vertices g2))
871 (add-vertex (+ n v) g))
872 (dolist (e (graph-edges g2))
873 (add-edge (list (+ n (first e)) (+ n (second e))) g))
874 (dolist (v (graph-vertices g1))
875 (dolist (u (graph-vertices g2))
876 (add-edge (list v (+ n u)) g)))
879 (defun get-canonical-names (l)
880 (let ((names ()) (i 0))
881 (dolist (v l)
882 (push `(,v . ,i) names)
883 (setq i (1+ i)))
884 names))
886 (defmfun $graph_product (&rest gr-list)
887 (cond
888 ((= 0 (length gr-list))
889 ($empty_graph 0))
890 ((= 1 (length gr-list))
891 (first gr-list))
892 ((= 2 (length gr-list))
893 (graph-product (first gr-list) (second gr-list)))
895 (graph-product (first gr-list) (apply #'$graph_product (rest gr-list))))))
897 (defun graph-product (g1 g2)
898 (require-graph 'graph_product 1 g1)
899 (require-graph 'graph_product 2 g2)
900 (let*
901 ((names1 (get-canonical-names (graph-vertices g1)))
902 (names2 (get-canonical-names (graph-vertices g2)))
903 (size1 (graph-order g1))
904 (size2 (graph-order g2))
905 (size (* size1 size2))
906 (g ($empty_graph size)))
907 (dolist (e (graph-edges g1))
908 (dolist (v (graph-vertices g2))
909 (let*
910 ((v1 (cdr (assoc (first e) names1)))
911 (v2 (cdr (assoc (second e) names1)))
912 (u (cdr (assoc v names2)))
913 (f (list (+ (* u size1) v1) (+ (* u size1) v2)))
914 (f (list (apply #'min f) (apply #'max f))))
915 (add-edge f g))))
916 (dolist (e (graph-edges g2))
917 (dolist (v (graph-vertices g1))
918 (let*
919 ((v1 (cdr (assoc (first e) names2)))
920 (v2 (cdr (assoc (second e) names2)))
921 (u (cdr (assoc v names1)))
922 (f (list (+ (* v1 size1) u) (+ (* v2 size1) u)))
923 (f (list (apply #'min f) (apply #'max f))))
924 (add-edge f g))))
927 (defmfun $line_graph (gr)
928 (require-graph 'line_graph 1 gr)
929 (let* ((edge-list
930 (get-canonical-names (graph-edges gr))) (n (graph-size gr))
931 (g ($empty_graph n)))
932 (dotimes (i n)
933 (do ((j (1+ i) (1+ j)))
934 ((= j n))
935 (let ((e (car (rassoc i edge-list))) (f (car (rassoc j edge-list))))
937 (or (member (first e) f) (member (second e) f))
938 (add-edge `(,i ,j) g)))))
941 (defmfun $random_graph (n p)
942 (if (not (integerp n))
943 ($error "Argument 1 to random_graph is not an integer"))
944 (if (not (floatp ($float p)))
945 ($error "Argument 2 to random_graph is not a float"))
946 (let ((g ($empty_graph n))
947 (p ($float p)))
948 (dotimes (i n)
949 (do ((j (1+ i) (1+ j)))
950 ((= j n))
951 (if (< (random 1.0) p)
952 (add-edge `(,i ,j) g))))
955 (defmfun $random_graph1 (n m)
956 #+sbcl (declare (notinline $random_graph1))
957 (unless (integerp n)
958 ($error "Argument 1 to random_graph is not an integer"))
959 (unless (integerp m)
960 ($error "Argument 2 to random_graph is not an integer"))
961 (when (< (* n (1- n)) (* 2 m))
962 ($error "random_graph1: no such graph"))
963 (when (< (* n (1- n)) (* 4 m))
964 (return-from $random_graph1
965 ($complement_graph ($random_graph1 n (- (/ (* n (1- n)) 2) m)))))
966 (let ((g ($empty_graph n)))
967 (do ((i 0)) ((= i m))
968 (let ((u (random n)) (v (random n)))
969 (unless (= u v)
970 (let ((e (list (min u v) (max u v))))
971 (unless (is-edge-in-graph e g)
972 (setq i (1+ i))
973 (add-edge e g))))))
976 (defmfun $random_bipartite_graph (a b p)
977 (unless (integerp a)
978 ($error "Argument 1 to random graph is not an integer"))
979 (unless (integerp b)
980 ($error "Argument b to random graph is not an integer"))
981 (let ((g ($empty_graph (+ a b))))
982 (dotimes (x a)
983 (dotimes (y b)
984 (when (< (random 1.0) p)
985 (add-edge (list x (+ a y)) g))))
988 (defmfun $random_digraph (n p)
989 (unless (integerp n)
990 ($error "Argument 1 to random_digraph is not an integer"))
991 (unless (floatp ($float p))
992 ($error "Argument 2 to random_digraph is not a float"))
993 (let ((g ($empty_digraph n))
994 (p ($float p)))
995 (dotimes (i n)
996 (dotimes (j n)
997 (when (and (not (= i j)) (< (random 1.0) p))
998 (add-edge `(,i ,j) g))))
1001 (defmfun $random_tournament (n)
1002 (unless (and (integerp n) (>= n 0))
1003 ($error "Argument 1 to random_tournament is not a positive integer"))
1004 (let ((g ($empty_digraph n)))
1005 (dotimes (i n)
1006 (do ((j (1+ i) (1+ j)))
1007 ((= j n))
1008 (if (and (not (= i j)) (< (random 1.0) 0.5))
1009 (add-edge `(,i ,j) g)
1010 (add-edge `(,j ,i) g))))
1013 (defmfun $random_tree (n)
1014 (unless (and (integerp n) (>= n 0))
1015 ($error "Argument 1 to random_tree is not a positive integer"))
1016 (let*
1017 ((tr ($empty_graph n))
1018 (vrt (remove 0 (graph-vertices tr) :count 1))
1019 (tree-vrt '(0)))
1020 (dotimes (i (1- n))
1021 (let
1022 ((u (nth (random (length vrt)) vrt))
1023 (v (nth (random (length tree-vrt)) tree-vrt)))
1024 (setq vrt (remove u vrt :count 1))
1025 (push u tree-vrt)
1026 (add-edge (list (min u v) (max u v)) tr)))
1027 tr))
1029 (defmfun $underlying_graph (gr)
1030 (require-digraph 'underlying_graph 1 gr)
1031 (let ((g (make-graph)))
1032 (dolist (v (vertices gr))
1033 (add-vertex v g))
1034 (dolist (e (digraph-edges gr))
1035 (let ((u (first e)) (v (second e)))
1036 (let ((e1 (list (apply #'min e) (apply #'max e))))
1037 (when (not (is-edge-in-graph e1 g))
1038 (add-edge `(,u ,v) g)))))
1041 (defmfun $induced_subgraph (vl gr)
1042 (require-graph 2 'induced_subgraph gr)
1043 (unless ($listp vl)
1044 ($error "First argument to induced_subgraph is not a list."))
1045 (let
1046 ((v_l (cdr vl))
1047 (g (make-graph)))
1048 (dolist (v v_l)
1049 (when (not (is-vertex-in-graph v gr))
1050 ($error
1051 "induced_subgraph: second argument is not a list of vertices"))
1052 (add-vertex v g)
1053 (let ((l (get-vertex-label v gr)))
1054 (when l
1055 (set-vertex-label v l g))))
1056 (dolist (e (graph-edges gr))
1057 (let ((u (first e)) (v (second e)))
1058 (when (and (member u v_l) (member v v_l))
1059 (add-edge e g))))
1062 (defmfun $wheel_graph (n)
1063 (unless (and (integerp n) (>= n 3))
1064 ($error "wheel_graph: first argument is no an integer greater than 3"))
1065 (let ((g ($cycle_graph n))
1066 (positions ()))
1067 (add-vertex n g)
1068 (dotimes (i n)
1069 (add-edge `(,i ,n) g))
1070 (dotimes (i n)
1071 (push `((mlist simp) ,i ((mlist simp)
1072 ,($sin (/ (* 2 i pi) n))
1073 ,($cos (/ (* 2 i pi) n))))
1074 positions))
1075 (push `((mlist simp) ,n ((mlist simp) 0 0)) positions)
1076 ($set_positions (cons '(mlist simp) positions) g)
1079 (defmfun $circulant_graph (n l)
1080 (unless (and (integerp n) (> n 0))
1081 ($error "Argument 1 to circulant_graph is not a positive integer."))
1082 (unless ($listp l)
1083 ($error "Argument 2 to circulant_graph is not a list."))
1084 (let ((g ($empty_graph n))
1085 (positions ()))
1086 (dolist (d (cdr l))
1087 (unless (and (integerp d) (> d 0))
1088 ($error
1089 "Argument 2 to circulant graph is no a list of positive integers"))
1090 (dotimes (i n)
1091 (let ((e `(,i ,(mod (+ i d) n))))
1092 (setq e (list (apply #'min e) (apply #'max e)))
1093 (add-edge e g))))
1094 (dotimes (i n)
1095 (push `((mlist simp) ,i ((mlist simp)
1096 ,($sin (m// (m* 2.0 i pi) n))
1097 ,($cos (m// (m* 2.0 i pi) n))))
1098 positions))
1099 ($set_positions (cons '(mlist simp) positions) g)
1102 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1104 ;;; graph properties
1106 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1108 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1110 ;;; Connected components
1113 (defmfun $connected_components (gr)
1114 (require-graph 'connected_components 1 gr)
1115 (when (= 0 (graph-order gr))
1116 (return-from $connected_components '((mlist simp))))
1117 (let ((components ()) (visited (make-hash-table)))
1118 (loop for v in (vertices gr) do
1119 (unless (gethash v visited)
1120 (let ((c ()) (active ()))
1121 (push v active)
1122 (loop while active do
1123 (let ((x (pop active)))
1124 (push x c)
1125 (setf (gethash x visited) t)
1126 (dolist (u (neighbors x gr))
1127 (unless (or (gethash u visited) (member u active))
1128 (push u active)))))
1129 (push `((mlist simp) ,@c) components))))
1130 `((mlist simp) ,@components)))
1132 (defmfun $is_connected (gr)
1133 (require-graph 'is_connected 1 gr)
1134 (<= ($length ($connected_components gr)) 1))
1136 (defmfun $is_tree (gr)
1137 (require-graph 'is_tree 1 gr)
1138 (and ($is_connected gr) (= (graph-order gr) (1+ (graph-size gr)))))
1140 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1142 ;;; Reachable vertices
1146 (defmfun $reachable_vertices (v gr)
1147 (require-graph-or-digraph 'reachable_vertices 2 gr)
1148 (require-vertex 'reachable_vertices 1 v)
1149 (require-vertex-in-graph 'reachable_vertices v gr)
1150 (when (= 0 (if (graph-p gr) (graph-order gr) (digraph-order gr)))
1151 (return-from $reachable_vertices '((mlist simp))))
1152 (let ((component ()) (visited (make-hash-table)))
1153 (unless (gethash v visited)
1154 (let ((active ()))
1155 (push v active)
1156 (loop while active do
1157 (let ((x (pop active)))
1158 (push x component)
1159 (setf (gethash x visited) t)
1160 (dolist (u (if (graph-p gr) (neighbors x gr) (out-neighbors x gr)))
1161 (unless (or (gethash u visited) (member u active))
1162 (push u active)))))))
1163 `((mlist simp) ,@component)))
1165 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1167 ;;; Adjacency matrix and Laplacian matrix
1170 (defmfun $adjacency_matrix (gr)
1171 (require-graph-or-digraph 'adjacency_matrix 1 gr)
1172 (let* ((n (if (graph-p gr) (graph-order gr) (digraph-order gr)))
1173 (m ($zeromatrix n n))
1174 (names (get-canonical-names (vertices gr))))
1175 (dolist (e (edges gr))
1176 (setf (nth (1+ (cdr (assoc (first e) names)))
1177 (nth (1+ (cdr (assoc (second e) names))) m)) 1)
1178 (when (graph-p gr)
1179 (setf (nth (1+ (cdr (assoc (second e) names)))
1180 (nth (1+ (cdr (assoc (first e) names))) m)) 1)))
1183 (defmfun $laplacian_matrix (gr)
1184 (require-graph 'laplacian_matrix 1 gr)
1185 (let ((m ($zeromatrix (graph-order gr) (graph-order gr)))
1186 (names (get-canonical-names (vertices gr))))
1187 (dolist (v (graph-vertices gr))
1188 (setf (nth (1+ (cdr (assoc v names)))
1189 (nth (1+ (cdr (assoc v names))) m))
1190 (length (neighbors v gr))))
1191 (dolist (e (graph-edges gr))
1192 (setf (nth (1+ (cdr (assoc (first e) names)))
1193 (nth (1+ (cdr (assoc (second e) names))) m)) -1)
1194 (setf (nth (1+ (cdr (assoc (second e) names)))
1195 (nth (1+ (cdr (assoc (first e) names))) m)) -1))
1198 (defmfun $graph_charpoly (gr x)
1199 (require-graph 'graph_charpoly 1 gr)
1200 (let (($ratmx t))
1201 ($charpoly ($adjacency_matrix gr) x)))
1203 (defmfun $graph_eigenvalues (gr)
1204 (require-graph 'graph_eigenvalues 1 gr)
1205 (let (($ratmx t))
1206 (mfuncall '$eigenvalues ($adjacency_matrix gr))))
1208 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1210 ;;; girth, odd_girth
1213 (defmfun $girth (gr)
1214 (require-graph 'girth 1 gr)
1215 (girth gr nil))
1217 (defmfun $odd_girth (gr)
1218 (require-graph 'odd_girth 1 gr)
1219 (girth gr t))
1221 (defun girth (gr odd)
1222 (let ((girth (1+ (graph-order gr))))
1223 (dolist (v (graph-vertices gr))
1224 (let
1225 ((visited (new-set v))
1226 (active (new-set v))
1227 (next)
1228 (depth 1))
1229 (do ()
1230 ((or (set-emptyp active)
1231 (> (* 2 depth) girth)
1232 (<= girth 3)))
1233 (setq next (new-set))
1234 (dolist (u (set-elements active))
1235 (dolist (w (neighbors u gr))
1236 (if (not (set-member w visited))
1237 (progn
1238 (set-add w visited)
1239 (set-add w next))
1240 (progn
1241 (if (set-member w active)
1242 (setq girth (- (* 2 depth) 1)))
1243 (if (and (not odd) (set-member w next))
1244 (setq girth (min girth (* 2 depth))))))))
1245 (setq active next)
1246 (setq depth (1+ depth)))))
1247 (if (> girth (graph-order gr))
1248 '$inf
1249 girth)))
1251 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1253 ;;; diameter, radius
1256 (defmfun $vertex_eccentricity (v gr)
1257 (require-graph 'vertex_eccentricity 1 gr)
1258 (require-vertex-in-graph 'vertex_eccentricity v gr)
1259 (let ((ecc (eccentricity (list v) gr)))
1260 (gethash v ecc)))
1262 (defun eccentricity (v_list gr)
1263 (unless ($is_connected gr)
1264 ($error "eccentricity: graph is not connected."))
1265 (let ((ecc (make-hash-table)))
1266 (dolist (v v_list)
1267 (let
1268 ((visited (new-set v))
1269 (active (new-set v))
1270 (next)
1271 (depth -1))
1272 (do ()
1273 ((set-emptyp active))
1274 (setq next (new-set))
1275 (dolist (u (set-elements active))
1276 (dolist (w (neighbors u gr))
1277 (when (not (set-member w visited))
1278 (set-add w visited)
1279 (set-add w next))))
1280 (setq active next)
1281 (setq depth (1+ depth)))
1282 (setf (gethash v ecc) depth)))
1283 ecc))
1285 (defmfun $diameter (gr)
1286 (require-graph 'diameter 1 gr)
1287 (let ((ecc (eccentricity (vertices gr) gr))
1288 (diameter 0))
1289 (maphash #'(lambda (key val)
1290 (declare (ignore key))
1291 (when (> val diameter)
1292 (setq diameter val)))
1293 ecc)
1294 diameter))
1296 (defmfun $radius (gr)
1297 (require-graph 'radius 1 gr)
1298 (let ((ecc (eccentricity (vertices gr) gr))
1299 (radius ($graph_order gr)))
1300 (maphash #'(lambda (key val)
1301 (declare (ignore key))
1302 (when (< val radius)
1303 (setq radius val)))
1304 ecc)
1305 radius))
1307 (defmfun $graph_center (gr)
1308 (require-graph 'graph_center 1 gr)
1309 (let ((ecc (eccentricity (vertices gr) gr))
1310 (per ())
1311 (radius ($graph_order gr)))
1312 (maphash #'(lambda (key val)
1313 (declare (ignore key))
1314 (when (< val radius)
1315 (setq radius val)))
1316 ecc)
1317 (maphash #'(lambda (key val)
1318 (when (= val radius)
1319 (push key per)))
1320 ecc)
1321 `((mlist simp) ,@per)))
1323 (defmfun $graph_periphery (gr)
1324 (require-graph 'graph_periphery 1 gr)
1325 (let ((ecc (eccentricity (vertices gr) gr))
1326 (center ())
1327 (diameter 0))
1328 (maphash #'(lambda (key val)
1329 (declare (ignore key))
1330 (when (> val diameter)
1331 (setq diameter val)))
1332 ecc)
1333 (maphash #'(lambda (key val)
1334 (when (= val diameter)
1335 (push key center)))
1336 ecc)
1337 `((mlist simp) ,@center)))
1339 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1341 ;;; bipartition
1344 (defmfun $bipartition (gr)
1345 (require-graph 'bipartition 1 gr)
1346 (when (= (graph-order gr) 0)
1347 (return-from $bipartition `((mlist simp) ((mlist simp)) ((mlist simp)))))
1348 (let ((components (cdr ($connected_components gr))) (A ()) (B ()))
1349 (dolist (c components)
1350 (let ((partition (bi-partition (first (cdr c)) gr)))
1351 (if (null partition)
1352 (return-from $bipartition `((mlist simp)))
1353 (progn
1354 (setq A (append A (first partition)))
1355 (setq B (append B (second partition)))))))
1356 `((mlist simp) ((mlist simp) ,@A) ((mlist simp) ,@B))))
1358 (defun bi-partition (v gr)
1359 (let
1360 ((A ())
1361 (B ())
1362 (visited (new-set))
1363 (active `(,v))
1364 (colors (make-hash-table)))
1365 (setf (gethash v colors) 1)
1366 (do ()
1367 ((null active))
1368 (let*
1369 ((w (pop active))
1370 (wc (gethash w colors)))
1371 (set-add w visited)
1372 (if (= wc 1)
1373 (push w A)
1374 (push w B))
1375 (dolist (u (neighbors w gr))
1376 (if (set-member u visited)
1377 (when (= (gethash u colors) wc)
1378 (return-from bi-partition ()))
1379 (unless (member u active)
1380 (push u active)
1381 (setf (gethash u colors) (- 1 wc)))))))
1382 `(,A ,B)))
1384 (defmfun $is_bipartite (gr)
1385 (require-graph 'is_bipartite 1 gr)
1386 (> ($length ($bipartition gr)) 1))
1388 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1390 ;;; 2-connectivity
1393 (defmfun $biconnected_components (gr)
1394 (require-graph 'biconnected_components 1 gr)
1395 (if (= 0 (graph-order gr))
1396 `((mlist simp))
1397 (let
1398 ((bicomp `((mlist simp)))
1399 (comp (cdr ($connected_components gr))))
1400 (dolist (c comp)
1401 (if (= ($length c) 1)
1402 (setq bicomp ($append bicomp `((mlist simp) ,c)))
1403 (setq bicomp ($append bicomp (bicomponents ($first c) gr)))))
1404 bicomp)))
1406 (defmfun $is_biconnected (gr)
1407 (require-graph 'is_biconnected 1 gr)
1408 (eql ($length ($biconnected_components gr)) 1))
1410 (defvar *dfs-bicomp-depth* 0)
1411 (defvar *dfs-bicomp-num* ())
1412 (defvar *dfs-bicomp-low-pt* ())
1413 (defvar *dfs-bicomp-edges* ())
1414 (defvar *bicomponents* ())
1416 (defun bicomponents (v gr)
1417 (let ((bicomp ()))
1418 (setq *dfs-bicomp-depth* 0)
1419 (setq *dfs-bicomp-num* (make-hash-table))
1420 (setq *dfs-bicomp-low-pt* (make-hash-table))
1421 (setq *dfs-bicomp-edges* (make-hash-table))
1422 (setq *bicomponents* ())
1423 (dolist (v (graph-vertices gr))
1424 (setf (gethash v *dfs-bicomp-num*) 0))
1425 (dfs-bicomponents gr v)
1426 (dolist (c *bicomponents*)
1427 (let ((curr-comp ()))
1428 (dolist (e c)
1429 (let ((u (first e)) (v (second e)))
1430 (unless (member u curr-comp)
1431 (push u curr-comp))
1432 (unless (member v curr-comp)
1433 (push v curr-comp))))
1434 (setq bicomp (cons `((mlist simp) ,@(sort curr-comp #'<)) bicomp))))
1435 `((mlist simp) ,@bicomp)))
1437 (defun dfs-bicomponents (gr w)
1438 (setq *dfs-bicomp-depth* (1+ *dfs-bicomp-depth*))
1439 (setf (gethash w *dfs-bicomp-num*) *dfs-bicomp-depth*)
1440 (setf (gethash w *dfs-bicomp-low-pt*) *dfs-bicomp-depth*)
1441 (dolist (u (neighbors w gr))
1442 (when (< (gethash u *dfs-bicomp-num*) (gethash w *dfs-bicomp-num*))
1443 (push `(,w ,u) *dfs-bicomp-edges*))
1444 (if (= 0 (gethash u *dfs-bicomp-num*))
1445 (progn
1446 (dfs-bicomponents gr u)
1447 (if (>= (gethash u *dfs-bicomp-low-pt*)
1448 (gethash w *dfs-bicomp-num*))
1449 (let ((e 0) (comp ()))
1450 (do ()
1451 ((equal e `(,w ,u)))
1452 (setq e (pop *dfs-bicomp-edges*))
1453 (push e comp))
1454 (push comp *bicomponents*))
1455 (setf (gethash w *dfs-bicomp-low-pt*)
1456 (min (gethash w *dfs-bicomp-low-pt*)
1457 (gethash u *dfs-bicomp-low-pt*)))))
1458 (setf (gethash w *dfs-bicomp-low-pt*)
1459 (min (gethash w *dfs-bicomp-low-pt*)
1460 (gethash u *dfs-bicomp-num*))))))
1462 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1464 ;;; strong connectivity
1467 (defvar *scon-low* nil)
1468 (defvar *scon-dfn* nil)
1469 (defvar *scon-comp* nil)
1470 (defvar *scon-st* nil)
1471 (defvar *scon-vrt* nil)
1472 (defvar *scon-depth* 0)
1474 (defmfun $strong_components (gr)
1475 (require-digraph 'strong_components 1 gr)
1476 (if (= 0 (digraph-order gr))
1477 `((mlist simp))
1478 (let ((res))
1479 (setq *scon-low* (make-hash-table))
1480 (setq *scon-dfn* (make-hash-table))
1481 (setq *scon-comp* ())
1482 (setq *scon-st* ())
1483 (setq *scon-vrt* (digraph-vertices gr))
1484 (loop while (not (null *scon-vrt*)) do
1485 (setq *scon-depth* 0)
1486 (dfs-strong-components gr (first *scon-vrt*))
1487 (dolist (c *scon-comp*)
1488 (push c res))
1489 (setq *scon-comp* ()))
1490 `((mlist simp) ,@res))))
1492 (defmfun $is_sconnected (gr)
1493 (require-digraph 'strong_components 1 gr)
1494 (eql ($length ($strong_components gr)) 1))
1496 (defun dfs-strong-components (gr v)
1497 (incf *scon-depth*)
1498 (setf (gethash v *scon-dfn*) *scon-depth*)
1499 (setf (gethash v *scon-low*) *scon-depth*)
1500 (setf *scon-vrt* (remove v *scon-vrt* :count 1))
1501 (push v *scon-st*)
1502 (dolist (u (neighbors v gr))
1503 (if (gethash u *scon-dfn*)
1504 (when (and (< (gethash u *scon-dfn*) (gethash v *scon-dfn*))
1505 (member u *scon-st*))
1506 (setf (gethash v *scon-low*)
1507 (min (gethash v *scon-low*)
1508 (gethash u *scon-dfn*))))
1509 (progn
1510 (dfs-strong-components gr u)
1511 (setf (gethash v *scon-low*)
1512 (min (gethash v *scon-low*)
1513 (gethash u *scon-low*))))))
1514 (when (= (gethash v *scon-low*) (gethash v *scon-dfn*))
1515 (let ((x (pop *scon-st*))
1516 (comp ()))
1517 (loop while (not (= x v)) do
1518 (push x comp)
1519 (setq x (pop *scon-st*)))
1520 (push x comp)
1521 (setq *scon-comp* (cons `((mlist simp) ,@comp) *scon-comp*)))))
1523 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1525 ;;; topological sorting
1528 (defmfun $topological_sort (dag)
1529 (require-digraph 'topological_sort 1 dag)
1530 (let ((in-degrees (make-hash-table))
1531 (q ())
1532 (n ($graph_size dag))
1533 (s ()))
1534 (dolist (v (vertices dag))
1535 (setf (gethash v in-degrees) 0))
1536 (dolist (e (edges dag))
1537 (incf (gethash (second e) in-degrees)))
1538 (dolist (v (vertices dag))
1539 (when (= (gethash v in-degrees) 0)
1540 (push v q)))
1541 (loop while (> (length q) 0) do
1542 (let ((v (pop q)))
1543 (push v s)
1544 (dolist (u (out-neighbors v dag))
1545 (decf (gethash u in-degrees))
1546 (decf n)
1547 (when (= (gethash u in-degrees) 0)
1548 (push u q)))))
1549 (if (= n 0)
1550 `((mlist simp) ,@(reverse s))
1551 '((mlist simp)))))
1553 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1555 ;;; max_flow (augmenting paths)
1558 (defmfun $max_flow (net source sink)
1559 (require-digraph 'max_flow 1 net)
1560 (require-vertex 'max_flow 2 source)
1561 (require-vertex 'max_flow 3 sink)
1562 (require-vertex-in-graph 'max_flow source net)
1563 (require-vertex-in-graph 'max_flow sink net)
1564 (let
1565 ((d (make-hash-table)) (active ()) (lbls (make-hash-table))
1566 (flow (make-hash-table :test #'equal)) (val 0)
1567 ($ratprint nil))
1568 (dolist (e (digraph-edges net))
1569 (setf (gethash e flow) 0))
1570 (dolist (v (digraph-vertices net))
1571 (setf (gethash v d) '$inf))
1572 (setf (gethash source lbls) `(,source -1 $inf))
1573 (push source active)
1574 (do ()
1575 ((null active))
1576 (let ((v (pop active)))
1577 (dolist (w (out-neighbors v net))
1578 (if (and (null (gethash w lbls))
1579 (mlsp (gethash `(,v ,w) flow)
1580 (or (get-edge-weight `(,v ,w) net) 1)))
1581 (progn
1582 (setf (gethash w d)
1583 (mfuncall '$min
1584 (m- (or (get-edge-weight `(,v ,w) net) 1)
1585 (gethash `(,v ,w) flow))
1586 (gethash v d)))
1587 (setf (gethash w lbls) `(,v 1 ,(gethash w d)))
1588 (push w active))))
1589 (dolist (w (in-neighbors v net))
1590 (if (and (null (gethash w lbls))
1591 (mgrp (gethash `(,w ,v) flow) 0))
1592 (progn
1593 (setf (gethash w d) (mfuncall '$min
1594 (gethash `(,w ,v) flow)
1595 (gethash v d)))
1596 (setf (gethash w lbls) `(,v -1 ,(gethash w d)))
1597 (push w active))))
1598 (if (gethash sink lbls)
1599 (let ((dd (third (gethash sink lbls))) (w sink))
1600 (setq val (m+ dd val))
1601 (do ()
1602 ((= w source))
1603 (let ((v1 (first (gethash w lbls)))
1604 (vl (second (gethash w lbls))))
1605 (if (= vl 1)
1606 (setf (gethash `(,v1 ,w) flow)
1607 (m+ (gethash `(,v1 ,w) flow) dd))
1608 (setf (gethash `(,w ,v1) flow)
1609 (m- (gethash `(,w ,v1) flow) dd)))
1610 (setq w v1)))
1611 (setq lbls (make-hash-table))
1612 (setf (gethash source lbls) `(,source -1 $inf))
1613 (dolist (v1 (digraph-vertices net))
1614 (setf (gethash v1 d) '$inf))
1615 (setq active `(,source))))))
1616 (let ((max-flow ()))
1617 (dolist (e (digraph-edges net))
1618 (push `((mlist simp) ((mlist simp) ,@e)
1619 ,(gethash e flow)) max-flow))
1620 `((mlist simp) ,val ((mlist simp) ,@max-flow)))))
1622 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1624 ;;; shortest path
1627 (defmfun $shortest_path (u v g)
1628 (require-graph-or-digraph 'shortest_path 3 g)
1629 (require-vertex 'shortest_path 1 u)
1630 (require-vertex 'shortest_path 2 v)
1631 (require-vertex-in-graph 'shortest_path v g)
1632 (require-vertex-in-graph 'shortest_path u g)
1633 (let ((active (make-hash-table)) (visited (make-hash-table)) (previous (make-hash-table)))
1634 (setf (gethash u active) t)
1635 (do ()
1636 ((or (= 0 (hash-table-count active)) (gethash v visited)))
1637 (let ((next (make-hash-table)))
1638 (loop for w being the hash-keys of active do
1639 (setf (gethash w visited) t)
1640 (dolist (x (neighbors w g))
1641 (unless (or (gethash x active) (gethash x visited) (gethash x next))
1642 (setf (gethash x previous) w)
1643 (setf (gethash x next) t))))
1644 (setq active next)))
1645 (if (gethash v visited)
1646 (let ((path (list v)))
1647 (do ((x v))
1648 ((= x u))
1649 (setq x (gethash x previous))
1650 (push x path))
1651 `((mlist simp) ,@path))
1652 `((mlist simp)))))
1654 (defmfun $vertex_distance (u v g)
1655 (require-graph-or-digraph 'shortest_path 3 g)
1656 (require-vertex 'shortest_path 1 u)
1657 (require-vertex 'shortest_path 2 v)
1658 (require-vertex-in-graph 'shortest_path v g)
1659 (require-vertex-in-graph 'shortest_path u g)
1660 (let ((d ($length ($shortest_path u v g))))
1661 (if (> d 0)
1662 (1- d)
1663 '$inf)))
1665 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1667 ;;; minimum spanning tree
1670 (defun edge-weight-1 (e gr)
1671 (cond ((gethash e (graph-edge-weights gr)))
1672 (t 1)))
1674 (defun graph-edges-with-weights (gr)
1675 (let ((edges (graph-edges gr)) (edges-with-weights ()))
1676 (dolist (e edges)
1677 (push `(,e ,(edge-weight-1 e gr)) edges-with-weights))
1678 edges-with-weights))
1680 (defun edges-by-weights (gr)
1681 (let ((edges (graph-edges-with-weights gr)))
1682 (sort edges #'(lambda (u v) (mlsp (second u) (second v))))))
1684 (defun in-same-part (u v p)
1685 (let ((up u) (vp v))
1686 (do ()
1687 ((= up (gethash up p)))
1688 (let ((up1 (gethash up p)))
1689 (setf (gethash up p) (gethash up1 p)))
1690 (setq up (gethash up p)))
1691 (do ()
1692 ((= vp (gethash vp p)))
1693 (let ((vp1 (gethash vp p)))
1694 (setf (gethash vp p) (gethash vp1 p)))
1695 (setq vp (gethash vp p)))
1696 (= up vp)))
1698 (defun join-parts (u v p)
1699 (let ((up u) (vp v))
1700 (do ()
1701 ((= up (gethash up p)))
1702 (setq up (gethash up p)))
1703 (do ()
1704 ((= vp (gethash vp p)))
1705 (setq vp (gethash vp p)))
1706 (setf (gethash up p) (gethash vp p))))
1708 (defmfun $minimum_spanning_tree (gr)
1709 (require-graph 'minimum_spanning_tree 1 gr)
1710 (let ((edges (edges-by-weights gr)) (tr (make-graph))
1711 (part (make-hash-table)))
1712 (dolist (v (graph-vertices gr))
1713 (add-vertex v tr)
1714 (setf (gethash v part) v))
1715 (dolist (e edges)
1716 (let ((u (caar e)) (v (cadar e)))
1717 (if (not (in-same-part u v part))
1718 (progn
1719 (add-edge `(,u ,v) tr)
1720 (join-parts u v part)))))
1721 tr))
1723 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1725 ;;; hamilton cycle
1728 (defvar *hamilton-cycle* ())
1730 (defmfun $hamilton_cycle (gr)
1731 (require-graph 'hamilton_cycle 1 gr)
1732 (let (*hamilton-cycle* (*v0* ($first_vertex gr)))
1733 (declare (special *v0*))
1734 (unless ($is_biconnected gr)
1735 (return-from $hamilton_cycle `((mlist simp))))
1736 (hamilton-cycle (list *v0*) gr)
1737 `((mlist simp) ,@(reverse *hamilton-cycle*))))
1739 (defun hamilton-cycle (part gr)
1740 (declare (special *v0*))
1741 (unless *hamilton-cycle*
1742 (if (= (length part) (if (graph-p gr)
1743 (graph-order gr)
1744 (digraph-order gr)))
1745 (if (member (car (last part)) (neighbors (first part) gr))
1746 (setq *hamilton-cycle* (append (last part) part))))
1747 (dolist (v (neighbors (car part) gr))
1748 (when (null (member v part))
1749 (if (< (length part) 3)
1750 (hamilton-cycle (cons v part) gr)
1751 (let ((gr1 ($copy_graph gr))
1752 (in-part (rest (reverse part))))
1753 ($remove_vertices (cons '(mlist simp) in-part) gr1)
1754 (unless (member v (neighbors *v0* gr))
1755 ($add_edge `((mlist simp) ,v ,*v0*) gr1))
1756 (when ($is_biconnected gr1)
1757 (hamilton-cycle (cons v part) gr))))))))
1759 (defmfun $hamilton_path (gr)
1760 (require-graph 'hamilton_path 1 gr)
1761 ;; first check if there exists a HC
1762 (let ((hc ($hamilton_cycle gr)))
1763 (when (cdr hc)
1764 (return-from $hamilton_path ($rest hc))))
1765 ;; check with all non-edges
1766 (let ((grc ($complement_graph gr)))
1767 (dolist (v (vertices gr))
1768 (dolist (u (neighbors v grc))
1769 (when (< v u)
1770 (let ((*v0* v)
1771 (*hamilton-cycle*)
1772 (part (list u v)))
1773 (declare (special *v0*))
1774 (hamilton-cycle part gr)
1775 (when *hamilton-cycle*
1776 (return-from $hamilton_path (cons '(mlist simp) (rest (reverse *hamilton-cycle*))))))))))
1777 '((mlist simp)))
1779 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1781 ;;; maximum clique
1784 (defvar *maximum-clique* ())
1786 (defmfun $vertices_by_degree (gr)
1787 (require-graph 'vertices_by_degrees 1 gr)
1788 (cons '(mlist simp) (vertices-by-degrees gr)))
1790 (defun vertices-by-degrees (gr)
1791 (let ((vrt ()))
1792 (dolist (v (vertices gr))
1793 (push `(,v ,(length (neighbors v gr))) vrt))
1794 (setq vrt (sort vrt #'(lambda (u v) (> (second u) (second v)))))
1795 (mapcar #'first vrt)))
1797 (defun greedy-color (gr)
1798 (let ((coloring (make-hash-table))
1799 (available-colors (make-hash-table)) (tmp ()))
1800 (dotimes (i (graph-order gr))
1801 (push i tmp))
1802 (setq tmp (reverse tmp))
1803 (dolist (v (graph-vertices gr))
1804 (setf (gethash v available-colors) (copy-tree tmp)))
1805 (dolist (v (vertices-by-degrees gr))
1806 (let ((c (car (gethash v available-colors))))
1807 (setf (gethash v coloring) c)
1808 (dolist (u (neighbors v gr))
1809 (setf (gethash u available-colors)
1810 (remove c (gethash u available-colors) :count 1)))))
1811 coloring))
1813 (defmfun $max_clique (gr)
1814 (require-graph 'max_clique 1 gr)
1815 (setq *maximum-clique* ())
1816 (let ((v) (coloring) (h ($copy_graph gr)))
1817 (do () ((or (>= (length *maximum-clique*) (graph-order h))
1818 (> (length *maximum-clique*) ($first ($max_degree h)))))
1819 ; (print *maximum-clique*)
1820 ; (print ($max_degree h))
1821 (setq coloring (greedy-color h))
1822 (setq v ($second ($max_degree h)))
1823 (extend-clique `(,v) (neighbors v h) coloring h)
1824 (remove-vertex v h)))
1825 `((mlist simp) ,@(sort *maximum-clique* #'<)))
1827 (defmfun $min_vertex_cover (gr)
1828 (require-graph 'min_vertex_cover 1 gr)
1829 (let ((bipart ($bipartition gr)))
1830 (if (null (cdr bipart))
1831 (let ((vc)
1832 (mc (cdr ($max_clique ($complement_graph gr)))))
1833 (loop for v in (vertices gr) do
1834 (unless (member v mc)
1835 (setq vc (cons v vc))))
1836 `((mlist simp) ,@vc))
1837 (maximum-matching-bipartite gr (cadr bipart) (caddr bipart) t))))
1839 (defmfun $max_independent_set (gr)
1840 (require-graph 'max_independent_set 1 gr)
1841 (if ($is_bipartite gr)
1842 (let ((mis)
1843 (vc (cdr ($min_vertex_cover gr))))
1844 (loop for v in (vertices gr) do
1845 (unless (member v vc)
1846 (setq mis (cons v mis))))
1847 `((mlist simp) ,@mis))
1848 ($max_clique ($complement_graph gr))))
1850 (defun extend-clique (clique neigh coloring gr)
1851 (if (= (length neigh) 0)
1852 ;; did we get to a maximal clique
1853 (if (> (length clique) (length *maximum-clique*))
1854 (progn
1855 (setq *maximum-clique* clique)
1856 (return-from extend-clique)))
1857 ;; can we do better?
1858 (let ((colors ()))
1859 (dolist (x neigh)
1860 (if (not (member (gethash x coloring) colors))
1861 (push (gethash x coloring) colors)))
1862 (if (> (+ (length clique) (length colors)) (length *maximum-clique*))
1863 ;; try improving
1864 (do () ((= (length neigh) 0))
1865 (let* ((x (first neigh)) (new-clique (cons x clique))
1866 (new-neigh ()))
1867 (dolist (y neigh)
1868 (if (is-edge-in-graph `(,(min x y) ,(max x y)) gr)
1869 (push y new-neigh)))
1870 (extend-clique new-clique new-neigh coloring gr)
1871 (setq neigh (remove x neigh))))))))
1873 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1875 ;;; colorings
1878 (defmfun $vertex_coloring (g)
1879 (require-graph 'vertex_coloring 1 g)
1880 (let ((col (dsatur g)) (res ()) (chnumber 0))
1881 (dolist (v (vertices g))
1882 (push `((mlist simp) ,v ,(gethash v col)) res)
1883 (setq chnumber (max chnumber (gethash v col))))
1884 `((mlist simp) ,chnumber ((mlist simp) ,@res))))
1886 (defmfun $chromatic_number (g)
1887 (require-graph 'chromatic_number 1 g)
1888 ($first ($vertex_coloring g)))
1890 (defmfun $edge_coloring (gr)
1891 (require-graph 'edge_coloring 1 gr)
1892 (let* ((edge-list (get-canonical-names (graph-edges gr)))
1893 (n (graph-size gr))
1894 (g ($empty_graph n)))
1895 (dotimes (i n)
1897 ((j (1+ i) (1+ j)))
1898 ((= j n))
1899 (let ((e (car (rassoc i edge-list))) (f (car (rassoc j edge-list))))
1901 (or (member (first e) f) (member (second e) f))
1902 (add-edge `(,i ,j) g)))))
1903 (let ((coloring (dsatur g))
1904 (ch-index -1)
1905 (res ()))
1906 (dotimes (i n)
1907 (push `((mlist simp) ((mlist simp) ,@(car (rassoc i edge-list)))
1908 ,(gethash i coloring)) res)
1909 (setq ch-index (max ch-index (gethash i coloring))))
1910 `((mlist simp) ,ch-index ((mlist simp) ,@res)))))
1912 (defmfun $chromatic_index (g)
1913 (require-graph 'chromatic_index 1 g)
1914 ($first ($vertex_coloring ($line_graph g))))
1916 (defun dsatur (g)
1917 (when (< (length (vertices g)) 2)
1918 (let ((col (make-hash-table)))
1919 (dolist (v (vertices g))
1920 (setf (gethash v col) 1))
1921 (return-from dsatur col)))
1922 (let* ((x)
1923 (vsize (length (vertices g)))
1924 (opt-chnumber (1+ vsize)) (back nil)
1925 (i 0) (k)
1926 (free-color)
1927 (xindex)
1928 (stop nil)
1929 (clique (greedy-clique g))
1930 (clique-size (length clique))
1931 (start clique-size)
1932 (A (make-array vsize))
1933 (F (make-hash-table))
1934 (f-opt (make-hash-table))
1935 (number-of-used-colors (make-hash-table :test #'equal))
1936 (dsat (make-hash-table))
1937 (uncolored (make-hash-table)))
1939 ;; Prepare data
1940 ;(format t "~%Preparing data")
1941 (dolist (v clique)
1942 (setf (aref A i) v)
1943 (setf (gethash v F) (1+ i))
1944 (setq i (1+ i)))
1945 (dolist (v (vertices g))
1946 (setf (gethash v dsat) 0)
1947 (setf (gethash v uncolored) (length (neighbors v g)))
1948 (if (not (member v clique))
1949 (progn
1950 (setf (aref A i) v)
1951 (setq i (1+ i))
1952 (setf (gethash v F) 0))))
1953 (dolist (v clique)
1954 (dolist (u (neighbors v g))
1955 (decf (gethash u uncolored))
1956 (setf (gethash `(,u ,(gethash v F)) number-of-used-colors) 1)
1957 (incf (gethash u dsat))))
1959 ;(format t "~%Clique size: ~d" (length clique))
1960 ;(format t "~%Clique: ~d" clique)
1961 (do () (nil)
1962 ;(format t "~%Starting with: ~d (~d)" start (aref A start))
1963 (do ((i start (1+ i))) ((or (= i vsize) stop))
1965 ;; Choose new vertex x
1966 (if back
1967 (progn
1968 (setq xindex start)
1969 (setq x (aref A xindex)))
1970 (let ((mdsat -1) (munc -1))
1971 (do ((j i (1+ j))) ((= j vsize))
1972 (if (or (> (gethash (aref A j) dsat) mdsat)
1973 (and (= (gethash (aref A j) dsat) mdsat)
1974 (> (gethash (aref A j) uncolored) munc)))
1975 (progn
1976 (setq x (aref A j))
1977 (setq xindex j)
1978 (setq mdsat (gethash x dsat))
1979 (setq munc (gethash x uncolored)))))))
1980 ;(format t "~%New vertex: ~d" x)
1982 ;; Choose free color
1983 (setq free-color 0)
1984 (if back
1985 (progn
1986 (setq back nil)
1987 (setq k (1+ (gethash x F))))
1988 (setq k 1))
1989 (do ((j k (1+ j))) ((or (>= j opt-chnumber) (> free-color 0)))
1990 (if (= 0 (gethash `(,x ,j) number-of-used-colors 0))
1991 (setq free-color j)))
1992 ;(format t "~%New color: ~d" free-color)
1994 (if (> free-color 0)
1995 ;; Color vertex x
1996 (progn
1997 (setf (gethash x F) free-color)
1998 ;; Update dsat index
1999 (dolist (u (neighbors x g))
2000 (incf (gethash `(,u ,free-color) number-of-used-colors 0))
2001 (if (= 1 (gethash `(,u ,free-color) number-of-used-colors 0))
2002 (incf (gethash u dsat)))
2003 (decf (gethash u uncolored)))
2004 ;; Update A
2005 (rotatef (aref A i) (aref A xindex)))
2006 ;; Unable to extend coloring - backtrack
2007 (progn
2008 (setq start (1- i))
2009 (setq stop t)
2010 (setq back t))))
2012 (setq stop nil)
2013 (if back
2014 ;; We have a backtrack step
2015 (progn
2016 (if (< start clique-size)
2017 (return-from dsatur f-opt))
2018 (setq x (aref A start))
2019 (setq k (gethash x F))
2020 ;; Delete the color of x
2021 (dolist (v (neighbors x g))
2022 (decf (gethash `(,v ,k) number-of-used-colors))
2023 (incf (gethash v uncolored))
2024 (if (= 0 (gethash `(,v ,k) number-of-used-colors))
2025 (decf (gethash v dsat)))))
2026 ;; We have a coloring!
2027 (progn
2028 ;; Save new optimal coloring
2029 (setq opt-chnumber 0)
2030 (dolist (v (vertices g))
2031 (setf (gethash v f-opt) (gethash v F))
2032 (setq opt-chnumber (max opt-chnumber (gethash v F))))
2033 ;(format t "~%Found new coloring: ~d" opt-chnumber)
2034 ;; Find new start
2035 (setq start -1)
2036 (do ((i 0 (1+ i))) ((> start -1))
2037 (if (= opt-chnumber (gethash (aref A i) f-opt))
2038 (progn
2039 (setq start (1- i)))))
2040 (setq back t)
2041 (if (or (< start clique-size)
2042 (= opt-chnumber clique-size))
2043 (return-from dsatur f-opt))
2044 ;; Delete colors from start
2045 (do ((i start (1+ i))) ((= i vsize))
2046 (dolist (v (neighbors (aref A i) g))
2047 (decf (gethash `(,v ,(gethash (aref A i) F))
2048 number-of-used-colors))
2049 (incf (gethash v uncolored))
2050 (if (= 0 (gethash `(,v ,(gethash (aref A i) F))
2051 number-of-used-colors))
2052 (decf (gethash v dsat)))))
2053 )))))
2055 (defun greedy-clique (g)
2056 (let ((clique ()))
2057 (dolist (v (vertices g))
2058 (let ((tmp-clique (extend-greedy-clique `(,v) (neighbors v g) g)))
2059 (if (> (length tmp-clique) (length clique))
2060 (setq clique tmp-clique))))
2061 clique))
2063 (defun extend-greedy-clique (clique neigh g)
2064 (if (= 0 (length neigh))
2065 (return-from extend-greedy-clique clique))
2066 (if (= 1 (length neigh))
2067 (return-from extend-greedy-clique (cons (car neigh) clique)))
2068 (let ((u nil) (new-neigh ()))
2069 (dolist (v neigh)
2070 (let ((tmp-neigh (copy-tree neigh)))
2071 (dolist (w neigh)
2072 (if (and (not (member w (neighbors v g))))
2073 (setq tmp-neigh (remove w tmp-neigh))))
2074 (if (>= (length tmp-neigh) (length new-neigh))
2075 (progn
2076 (setq u v)
2077 (setq new-neigh tmp-neigh)))))
2078 (if u
2079 (extend-greedy-clique (cons u clique) new-neigh g)
2080 clique)))
2082 ;;;;;;;
2084 ;; Expose lisp hashtable
2086 ;;;;;;
2088 (defmfun $hash_table ()
2089 (make-hash-table :test #'equal))
2091 (defmfun $get_hash (elt ht &optional default)
2092 (unless (hash-table-p ht)
2093 ($error "Second argument to `get_hash' is not a hash table!"))
2094 (gethash elt ht default))
2096 (defmfun $set_hash (elt ht value)
2097 (unless (hash-table-p ht)
2098 ($error "Second argument to `set_hash' is not a hash table!"))
2099 (setf (gethash elt ht) value)
2100 value)
2102 (defmfun $hash_table_data (ht)
2103 (unless (hash-table-p ht)
2104 ($error "First argument to `hash_table_info' is not a hash table!"))
2105 (let (res)
2106 (maphash
2107 (lambda (key val)
2108 (setq res (cons `((marrow simp) ,key ,val) res)))
2110 (cons '(mlist simp) res)))
2112 ;;;;;;;;;;;;;;;;;;;;;;;;;
2114 ;; This function is needed for draw_graph (get the temporary file to write in)
2116 ;;;;;;;;;;;;;;;;;;;;;;;;;
2118 (defmfun $temp_filename (file)
2119 (unless (stringp file)
2120 ($error "Argument to `temp_filename' is not a string"))
2121 (plot-temp-file file))
2123 (defmfun $read_string (str)
2124 (unless (stringp str)
2125 ($error "Argument to `read_string' is not a string"))
2126 (let ((num (read-from-string str)))
2127 (if (numberp num) num str)))