1 (in-package #:metabang.graph)
3 ;;; ---------------------------------------------------------------------------
5 ;;; ---------------------------------------------------------------------------
7 (defstruct (vertex-datum (:conc-name node-) (:type list))
9 (depth most-positive-fixnum)
12 ;;; ---------------------------------------------------------------------------
14 (defmethod initialize-vertex-data ((graph basic-graph))
15 (let ((vertex-data (make-container 'simple-associative-container)))
16 (iterate-vertexes graph (lambda (v)
17 (setf (item-at vertex-data v)
18 (make-vertex-datum :color :white))))
19 (values vertex-data)))
21 ;;; ---------------------------------------------------------------------------
22 ;;; breadth-first-search by GWK
23 ;;; ---------------------------------------------------------------------------
25 (defmethod breadth-first-visitor ((graph basic-graph) (source t) fn)
26 (breadth-first-visitor graph (find-vertex graph source) fn))
28 ;;; ---------------------------------------------------------------------------
30 (defmethod breadth-first-visitor ((graph basic-graph) (source basic-vertex) fn)
32 (let ((vertex-data (initialize-vertex-data graph))
33 (queue (make-container 'basic-queue)))
35 (let ((source-datum (item-at vertex-data source)))
36 (setf (node-color source-datum) :grey
37 (node-depth source-datum) 0)
38 (enqueue queue source)
40 (loop until (empty-p queue) do
41 (let* ((current-vertex (first-item queue))
42 (current (item-at vertex-data current-vertex)))
43 ;(format t "~%~A:" current-vertex)
44 (iterate-children current-vertex
45 (lambda (child-vertex)
46 ;(format t "~A " child-vertex)
47 (let ((child (item-at vertex-data child-vertex)))
48 (when (eq (node-color child) :white)
49 (setf (node-color child) :grey
50 (node-depth child) (1+ (node-depth current))
51 (node-parent child) current-vertex)
52 (enqueue queue child-vertex)))))
55 (setf (node-color current) :black)
56 (funcall fn current-vertex)))
60 ;;; ---------------------------------------------------------------------------
62 (defmethod breadth-first-search-graph ((graph basic-graph) (source t))
63 (breadth-first-search-graph graph (find-vertex graph source)))
65 ;;; ---------------------------------------------------------------------------
67 (defmethod breadth-first-search-graph ((graph basic-graph) (source basic-vertex))
69 (let ((vertex-data (initialize-vertex-data graph))
70 (queue (make-container 'basic-queue)))
72 (let ((source-datum (item-at vertex-data source)))
73 (setf (node-color source-datum) :grey
74 (node-depth source-datum) 0)
75 (enqueue queue source)
77 (loop until (empty-p queue) do
78 (let* ((current-vertex (first-item queue))
79 (current (item-at vertex-data current-vertex)))
80 ;(format t "~%~A:" current-vertex)
81 (iterate-children current-vertex
82 (lambda (child-vertex)
83 ;(format t "~A " child-vertex)
84 (let ((child (item-at vertex-data child-vertex)))
85 (when (eq (node-color child) :white)
86 (setf (node-color child) :grey
87 (node-depth child) (1+ (node-depth current))
88 (node-parent child) current-vertex)
89 (enqueue queue child-vertex)))))
92 (setf (node-color current) :black)))
96 ;;; ---------------------------------------------------------------------------
97 ;;; single-source-shortest-paths - gwk
98 ;;; ---------------------------------------------------------------------------
101 (defmethod single-source-shortest-paths ((graph basic-graph))
102 (let ((vertex-data (initialize-vertex-data graph))
103 (queue (make-container 'priority-queue-on-container 'binary-search-tree)))
104 (let ((source-datum (item-at vertex-data source)))
105 (setf (node-depth source-datum) 0))
108 ;;; ---------------------------------------------------------------------------
109 ;;; connected-components - gwk
110 ;;; ---------------------------------------------------------------------------
112 (defmethod connected-components ((graph basic-graph))
113 (let ((union (make-container 'union-find-container)))
116 (lambda (v) (insert-item union v)))
120 (let ((node-1 (representative-node union (vertex-1 e)))
121 (node-2 (representative-node union (vertex-2 e))))
122 (unless (eq (find-set node-1) (find-set node-2))
123 (graft-nodes node-1 node-2)))))
124 (iterate-elements union 'find-set)
127 ;;; ---------------------------------------------------------------------------
129 (defmethod connected-component-count ((graph basic-graph))
130 ;;?? Gary King 2005-11-28: Super ugh
134 (connected-components graph)
135 :transform #'parent)))
138 ;;?? Gary King 2005-11-28: fails on big graphs? iterator design
139 ;;?? Gary King 2005-11-28: ideally we don't want to cons up the list at all
142 (make-iterator (connected-components graph) :unique t :transform #'parent))))
144 (defmethod find-connected-components ((graph basic-graph))
146 (make-iterator (connected-components graph) :unique t :transform #'parent)
149 (subgraph-containing graph (element component)
150 :depth most-positive-fixnum))))
153 (defmethod find-connected-components ((graph basic-graph))
155 (found-elements (make-container 'simple-associative-container)))
157 (connected-components graph)
159 (let ((element (element (parent component))))
160 (unless (item-at found-elements element)
161 (setf (item-at found-elements element) t)
163 (push (subgraph-containing graph (element component)
164 most-positive-fixnum)
171 ;;; ---------------------------------------------------------------------------
172 ;;; minimum-spanning-tree based on kruskal's algorithm detailed in clrs2 -jjm
173 ;;; ---------------------------------------------------------------------------
175 (defmethod mst-find-set ((vertex basic-vertex))
177 (unless (previous-node vertex)
178 (return-from mst-find-set nil))
179 (unless (eq vertex (previous-node vertex))
180 (setf (previous-node vertex) (mst-find-set (previous-node vertex))))
181 (previous-node vertex))
183 ;;; ---------------------------------------------------------------------------
185 (defmethod mst-make-set ((vertex basic-vertex))
186 (setf (previous-node vertex) vertex
189 ;;; ---------------------------------------------------------------------------
191 (defmethod mst-tree-union ((v1 basic-vertex) (v2 basic-vertex))
192 (mst-link (mst-find-set v1) (mst-find-set v2)))
194 ;;; ---------------------------------------------------------------------------
196 (defmethod mst-link ((v1 basic-vertex) (v2 basic-vertex))
197 (cond ((> (rank v1) (rank v2))
198 (setf (previous-node v2) v1))
199 (t (setf (previous-node v1) v2)
200 (when (= (rank v1) (rank v2))
203 ;;; ---------------------------------------------------------------------------
204 ;;; jjm's implementation of mst depends on this
205 ;;; todo - figure out some what to add and edge we create to a graph rather
206 ;;; than always using add-edge-between-vertexes interface
207 ;;; ---------------------------------------------------------------------------
209 (defmethod add-edges-to-graph ((graph basic-graph) (edges list)
210 &key (if-duplicate-do :ignore))
214 (bind ((v1 (element (source-vertex edge)))
215 (v2 (element (target-vertex edge))))
216 (add-edge-between-vertexes
217 graph v1 v2 :edge-class (type-of edge)
218 :edge-type (if (directed-edge-p edge)
222 :edge-id (edge-id edge)
223 :element (element edge)
227 :if-duplicate-do if-duplicate-do))))
230 ;;; ---------------------------------------------------------------------------
232 (defmethod edge-lessp-by-weight ((e1 basic-edge) (e2 basic-edge))
233 (< (weight e1) (weight e2)))
235 ;;; ---------------------------------------------------------------------------
236 ;;; minumum spanning tree
237 ;;; ---------------------------------------------------------------------------
240 (defmethod minimum-spanning-tree ((graph basic-graph)
242 (edge-sorter #'edge-lessp-by-weight))
249 (loop for edge in (sort (edges graph) edge-sorter) do
250 (bind ((v1 (source-vertex edge))
251 (v2 (target-vertex edge)))
253 (unless (eq (mst-find-set v1)
256 (mst-tree-union v1 v2)))
259 (cond ((= (length result) (- (length (vertexes graph)) 1))
261 (t (values nil result)))))))
263 ;;; ---------------------------------------------------------------------------
266 (defmethod minimum-spanning-tree ((vertex-list list)
268 (edge-sorter #'edge-lessp-by-weight))
270 (v-edges (remove-duplicates
271 (flatten (mapcar #'edges vertex-list)) :test #'eq)))
280 (loop for edge in (sort v-edges edge-sorter) do
281 (bind ((v1 (source-vertex edge))
282 (v2 (target-vertex edge))
283 (v1-set (mst-find-set v1))
284 (v2-set (mst-find-set v2)))
286 (when (or (not v1-set)
288 (return-from minimum-spanning-tree nil))
291 (unless (eq (mst-find-set v1)
294 (mst-tree-union v1 v2)))
297 (cond ((= (length result) (- (length vertex-list) 1))
299 (t (values nil result)))))))
301 ;;; ---------------------------------------------------------------------------
302 ;;; uses mst to determine if the graph is connected
303 ;;; ---------------------------------------------------------------------------
305 (defmethod connected-graph-p ((graph basic-graph) &key
306 (edge-sorter 'edge-lessp-by-weight))
307 (minimum-spanning-tree graph :edge-sorter edge-sorter))
310 ;;; ---------------------------------------------------------------------------
313 (bind ((g (make-container 'graph-container)))
314 (add-edge-between-vertexes g :v :y :edge-type :directed)
315 (add-edge-between-vertexes g :u :x :edge-type :directed)
316 (add-edge-between-vertexes g :x :v :edge-type :directed)
317 (add-edge-between-vertexes g :u :v :edge-type :directed)
318 (add-edge-between-vertexes g :y :x :edge-type :directed)
319 (add-edge-between-vertexes g :w :y :edge-type :directed)
320 (add-edge-between-vertexes g :w :z :edge-type :directed)
321 (add-edge-between-vertexes g :z :z :edge-type :directed
322 :if-duplicate-do :force)
323 (minimum-spanning-tree g))
325 ;;; ---------------------------------------------------------------------------
326 ;;; GWK's implementation of kruskal's - slightly faster, but it doesn't return
327 ;;; a tree (still faster even if it does). Will decide later if which to use
328 ;;; ignoring for now -jjm
329 ;;; ---------------------------------------------------------------------------
332 (defmethod minimum-spanning-tree ((graph basic-graph) &key (weight 'weight))
334 (union (make-container 'union-find-container))
335 (edges (sort (edges graph) #'< :key weight)))
337 graph (lambda (v) (insert-item union v)))
339 (let ((node-1 (representative-node union (vertex-1 edge)))
340 (node-2 (representative-node union (vertex-2 edge))))
341 (unless (eq (find-set node-1) (find-set node-2))
342 (graft-nodes node-1 node-2)
347 ;;; ---------------------------------------------------------------------------
350 (loop for f in '(mst-kruskal minimum-spanning-tree-kruskal) do
351 (fluid-bind (((random-seed *random-generator*) 1))
352 (bind ((g (generate-undirected-graph-via-vertex-probabilities
353 *random-generator* (make-instance 'graph-container :default-edge-type :directed)
356 #2A((0.2 0.1) (nil 0.2))
358 (form-keyword "H" (format nil "~2,'0D~4,'0D" kind count))))
360 (timeit (:report :values)
361 (loop for n from 1 to 100 do
362 (funcall f g (lambda (a b)
363 (declare (ignore a b))
366 ;;; ---------------------------------------------------------------------------
367 ;;; end minimum spanning tree
368 ;;; ---------------------------------------------------------------------------
371 ;;; ---------------------------------------------------------------------------
372 ;;; depth-first-search - clrs2
373 ;;; todo - figure out how to name this depth-first-search, which is already
374 ;;; defined in search.lisp
375 ;;; ---------------------------------------------------------------------------
377 ;;; ---------------------------------------------------------------------------
378 ;;; should probably make this special
379 ;;; ---------------------------------------------------------------------------
381 (defparameter *depth-first-search-timer* -1)
383 ;;; ---------------------------------------------------------------------------
384 ;;; undirected edges are less than edges that are directed
385 ;;; ---------------------------------------------------------------------------
387 #+ignore ;;; incorrect, methinks - jjm
388 (defmethod edge-lessp-by-direction ((e1 basic-edge) (e2 basic-edge))
389 (cond ((or (every #'directed-edge-p (list e1 e2))
390 (every #'undirected-edge-p (list e1 e2)))
392 ((and (undirected-edge-p e1) (directed-edge-p e2))
396 (defmethod edge-lessp-by-direction ((e1 basic-edge) (e2 basic-edge))
397 (and (undirected-edge-p e1) (directed-edge-p e2)))
399 ;;; ---------------------------------------------------------------------------
401 (defmethod out-edge-for-vertex-p ((edge basic-edge) (vertex basic-vertex))
402 (cond ((and (directed-edge-p edge)
403 (eq vertex (source-vertex edge)))
405 ((and (undirected-edge-p edge)
406 (or (eq vertex (source-vertex edge))
407 (eq vertex (target-vertex edge))))
411 ;;; ---------------------------------------------------------------------------
412 ;;; depth-first-search
413 ;;; ---------------------------------------------------------------------------
415 (defmethod dfs ((graph basic-graph) (root t) fn &key
416 (out-edge-sorter #'edge-lessp-by-direction))
417 (dfs graph (find-vertex graph root) fn :out-edge-sorter out-edge-sorter))
419 ;;; ---------------------------------------------------------------------------
421 (defmethod dfs ((graph basic-graph) (root basic-vertex) fn &key
422 (out-edge-sorter #'edge-lessp-by-direction))
423 (setf *depth-first-search-timer* -1)
428 (setf (color v) :white
429 (previous-node v) nil
430 (discovery-time v) -1
431 (finish-time v) -1)))
436 (setf (color e) nil)))
438 (loop with vl = (remove root (vertexes graph) :test #'eql)
439 for v in (push root vl) do
440 (when (eql (color v) :white)
441 (dfs-visit graph v fn out-edge-sorter)))
444 (sort (copy-list (vertexes graph)) #'< :key #'finish-time)
447 ;;; ---------------------------------------------------------------------------
449 (defmethod dfs-visit ((graph graph-container) (u basic-vertex)
453 (incf *depth-first-search-timer*)
454 (setf (color u) :gray
455 (discovery-time u) *depth-first-search-timer*)
458 (loop for edge in (sort (collect-elements
461 (out-edge-for-vertex-p e u))) sorter) do
462 (bind ((v (other-vertex edge u)))
465 (setf (color edge) (color v)))
467 (when (eql (color v) :white)
468 (setf (previous-node v) u)
470 (dfs-visit graph v fn sorter))))
472 (incf *depth-first-search-timer*)
474 (setf (color u) :black
475 (finish-time u) *depth-first-search-timer*))
477 ;;; ---------------------------------------------------------------------------
479 ;;; ---------------------------------------------------------------------------
482 (bind ((g (make-container 'graph-container)))
483 (add-edge-between-vertexes g :v :y :edge-type :directed)
484 (add-edge-between-vertexes g :u :x :edge-type :directed)
485 (add-edge-between-vertexes g :x :v :edge-type :directed)
486 (add-edge-between-vertexes g :u :v :edge-type :directed)
487 (add-edge-between-vertexes g :y :x :edge-type :directed)
488 (add-edge-between-vertexes g :w :y :edge-type :directed)
489 (add-edge-between-vertexes g :w :z :edge-type :directed)
490 (add-edge-between-vertexes g :z :z :edge-type :directed
491 :if-duplicate-do :force)
492 (assert (equal '(:X :Y :V :U :Z :W)
493 (mapcar #'element (dfs g :u #'identity)))))
495 ;;; ---------------------------------------------------------------------------
497 (defmethod dfs-tree-edge-p ((edge graph-container-edge))
498 (eql (color edge) :white))
500 ;;; ---------------------------------------------------------------------------
502 (defmethod dfs-back-edge-p ((edge graph-container-edge))
503 (eql (color edge) :gray))
505 ;;; ---------------------------------------------------------------------------
506 ;;; not correct - has to look at combination of discovery-time and finish-time
507 ;;; ---------------------------------------------------------------------------
509 (defmethod dfs-forward-edge-p ((edge graph-container-edge))
510 (warn "implementation is not correct.")
511 (unless (and (dfs-tree-edge-p edge)
512 (dfs-back-edge-p edge))
513 (< (discovery-time (source-vertex edge))
514 (discovery-time (target-vertex edge)))))
516 ;;; ---------------------------------------------------------------------------
517 ;;; not correct - has to look at combination of discovery-time and finish-time
518 ;;; ---------------------------------------------------------------------------
520 (defmethod dfs-cross-edge-p ((edge graph-container-edge))
521 (warn "implementation is not correct.")
522 (unless (and (dfs-tree-edge-p edge)
523 (dfs-back-edge-p edge))
524 (> (discovery-time (source-vertex edge))
525 (discovery-time (target-vertex edge)))))
527 ;;; ---------------------------------------------------------------------------
529 (defmethod dfs-edge-type ((edge graph-container-edge))
530 (cond ((dfs-tree-edge-p edge)
532 ((dfs-back-edge-p edge)
534 ((dfs-forward-edge-p edge)
536 ((dfs-cross-edge-p edge)
540 ;;; ---------------------------------------------------------------------------
542 ;;; ---------------------------------------------------------------------------
544 ;;; ---------------------------------------------------------------------------
545 ;;; mapping functions
546 ;;; ---------------------------------------------------------------------------
548 ;;; ---------------------------------------------------------------------------
550 ;;; ---------------------------------------------------------------------------
552 (defmethod map-over-all-combinations-of-k-vertexes ((graph basic-graph) k fn)
553 (bind ((vertex-count (size graph))
554 (symbols (make-list k :initial-element vertex-count))
555 (vertexes (vertexes graph)))
556 (iterate-over-indexes
558 (lambda (vertex-indexes)
559 (when (apply #'< vertex-indexes)
560 (funcall fn (mapcar (lambda (vertex-index)
561 (nth-element vertexes vertex-index))
562 vertex-indexes)))))))
564 ;;; ---------------------------------------------------------------------------
568 (g (make-container 'graph-container)))
569 (add-edge-between-vertexes g :u :v :edge-type :directed)
570 (add-edge-between-vertexes g :u :x :edge-type :directed)
571 (add-edge-between-vertexes g :x :v :edge-type :directed)
572 (add-edge-between-vertexes g :v :y :edge-type :directed)
573 (add-edge-between-vertexes g :y :x :edge-type :directed)
574 (add-edge-between-vertexes g :w :y :edge-type :directed)
575 (add-edge-between-vertexes g :w :z :edge-type :directed)
577 (map-over-all-combinations-of-k-vertexes
580 (lambda (vertex-list)
581 (bind ((graph-from-vertexes (make-graph-from-vertexes vertex-list)))
582 (when (mst-kruskal graph-from-vertexes #'identity-sorter)
583 (push graph-from-vertexes result)))))
586 ;;; ---------------------------------------------------------------------------
588 ;;; todo: merge these two defs
589 ;;; ---------------------------------------------------------------------------
591 (defmethod map-over-all-combinations-of-k-edges ((graph basic-graph) k fn)
592 (bind ((edge-count (edge-count graph))
593 (symbols (make-list k :initial-element edge-count))
594 (edges (edges graph)))
596 (iterate-over-indexes
598 (lambda (edge-indexes)
599 (when (apply #'< edge-indexes)
600 (funcall fn (mapcar (lambda (edge-index)
601 (nth-element edges edge-index))
604 ;;; ---------------------------------------------------------------------------
606 (defmethod map-over-all-combinations-of-k-edges ((vertex basic-vertex) k fn)
607 (bind ((edge-count (edge-count vertex))
608 (symbols (make-list k :initial-element edge-count))
609 (edges (edges vertex)))
611 (iterate-over-indexes
613 (lambda (edge-indexes)
614 (when (apply #'< edge-indexes)
615 (funcall fn (mapcar (lambda (edge-index)
616 (nth-element edges edge-index))
618 ;;; ---------------------------------------------------------------------------
621 (map-over-all-combinations-of-k-edges
622 (generate-undirected-graph-via-verex-probabilities
623 *random-generator* 'graph-container
626 #2A((0.2 0.1) (nil 0.2))
628 (form-keyword "H" (format nil "~2,'0D~4,'0D" kind count))))
633 (format t "~A -- ~A " (element (vertex-1 e)) (element (vertex-2 e))))
640 ;;; ***************************************************************************
642 ;;; ***************************************************************************