1 (in-package #:metabang.graph)
5 (defstruct (vertex-datum (:conc-name node-) (:type list))
7 (depth most-positive-fixnum)
11 (defmethod initialize-vertex-data ((graph basic-graph))
12 (let ((vertex-data (make-container 'simple-associative-container)))
13 (iterate-vertexes graph (lambda (v)
14 (setf (item-at vertex-data v)
15 (make-vertex-datum :color :white))))
16 (values vertex-data)))
18 ;;; breadth-first-search by GWK
20 (defmethod breadth-first-visitor ((graph basic-graph) (source t) fn)
21 (breadth-first-visitor graph (find-vertex graph source) fn))
24 (defmethod breadth-first-visitor ((graph basic-graph) (source basic-vertex) fn)
26 (let ((vertex-data (initialize-vertex-data graph))
27 (queue (make-container 'basic-queue)))
29 (let ((source-datum (item-at vertex-data source)))
30 (setf (node-color source-datum) :grey
31 (node-depth source-datum) 0)
32 (enqueue queue source)
34 (loop until (empty-p queue) do
35 (let* ((current-vertex (first-item queue))
36 (current (item-at vertex-data current-vertex)))
37 ;(format t "~%~A:" current-vertex)
38 (iterate-children current-vertex
39 (lambda (child-vertex)
40 ;(format t "~A " child-vertex)
41 (let ((child (item-at vertex-data child-vertex)))
42 (when (eq (node-color child) :white)
43 (setf (node-color child) :grey
44 (node-depth child) (1+ (node-depth current))
45 (node-parent child) current-vertex)
46 (enqueue queue child-vertex)))))
49 (setf (node-color current) :black)
50 (funcall fn current-vertex)))
55 (defmethod breadth-first-search-graph ((graph basic-graph) (source t))
56 (breadth-first-search-graph graph (find-vertex graph source)))
59 (defmethod breadth-first-search-graph ((graph basic-graph) (source basic-vertex))
61 (let ((vertex-data (initialize-vertex-data graph))
62 (queue (make-container 'basic-queue)))
64 (let ((source-datum (item-at vertex-data source)))
65 (setf (node-color source-datum) :grey
66 (node-depth source-datum) 0)
67 (enqueue queue source)
69 (loop until (empty-p queue) do
70 (let* ((current-vertex (first-item queue))
71 (current (item-at vertex-data current-vertex)))
72 ;(format t "~%~A:" current-vertex)
73 (iterate-children current-vertex
74 (lambda (child-vertex)
75 ;(format t "~A " child-vertex)
76 (let ((child (item-at vertex-data child-vertex)))
77 (when (eq (node-color child) :white)
78 (setf (node-color child) :grey
79 (node-depth child) (1+ (node-depth current))
80 (node-parent child) current-vertex)
81 (enqueue queue child-vertex)))))
84 (setf (node-color current) :black)))
88 ;;; single-source-shortest-paths - gwk
91 (defmethod single-source-shortest-paths ((graph basic-graph))
92 (let ((vertex-data (initialize-vertex-data graph))
93 (queue (make-container 'priority-queue-on-container 'binary-search-tree)))
94 (let ((source-datum (item-at vertex-data source)))
95 (setf (node-depth source-datum) 0))
98 ;;; connected-components - gwk
100 (defmethod connected-components ((graph basic-graph))
101 (let ((union (make-container 'union-find-container)))
104 (lambda (v) (insert-item union v)))
108 (let ((node-1 (representative-node union (vertex-1 e)))
109 (node-2 (representative-node union (vertex-2 e))))
110 (unless (eq (find-set node-1) (find-set node-2))
111 (graft-nodes node-1 node-2)))))
112 (iterate-elements union 'find-set)
116 (defmethod connected-component-count ((graph basic-graph))
117 ;;?? Gary King 2005-11-28: Super ugh
121 (connected-components graph)
122 :transform #'parent)))
125 ;;?? Gary King 2005-11-28: fails on big graphs? iterator design
126 ;;?? Gary King 2005-11-28: ideally we don't want to cons up the list at all
129 (make-iterator (connected-components graph) :unique t :transform #'parent))))
131 (defmethod find-connected-components ((graph basic-graph))
133 (make-iterator (connected-components graph) :unique t :transform #'parent)
136 (subgraph-containing graph (element component)
137 :depth most-positive-fixnum))))
140 (defmethod find-connected-components ((graph basic-graph))
142 (found-elements (make-container 'simple-associative-container)))
144 (connected-components graph)
146 (let ((element (element (parent component))))
147 (unless (item-at found-elements element)
148 (setf (item-at found-elements element) t)
150 (push (subgraph-containing graph (element component)
151 most-positive-fixnum)
158 ;;; minimum-spanning-tree based on kruskal's algorithm detailed in clrs2 -jjm
160 (defmethod mst-find-set ((vertex basic-vertex))
162 (unless (previous-node vertex)
163 (return-from mst-find-set nil))
164 (unless (eq vertex (previous-node vertex))
165 (setf (previous-node vertex) (mst-find-set (previous-node vertex))))
166 (previous-node vertex))
169 (defmethod mst-make-set ((vertex basic-vertex))
170 (setf (previous-node vertex) vertex
174 (defmethod mst-tree-union ((v1 basic-vertex) (v2 basic-vertex))
175 (mst-link (mst-find-set v1) (mst-find-set v2)))
178 (defmethod mst-link ((v1 basic-vertex) (v2 basic-vertex))
179 (cond ((> (rank v1) (rank v2))
180 (setf (previous-node v2) v1))
181 (t (setf (previous-node v1) v2)
182 (when (= (rank v1) (rank v2))
185 ;;; jjm's implementation of mst depends on this
186 ;;; todo - figure out some what to add and edge we create to a graph rather
187 ;;; than always using add-edge-between-vertexes interface
189 (defmethod add-edges-to-graph ((graph basic-graph) (edges list)
190 &key (if-duplicate-do :ignore))
194 (let ((v1 (element (source-vertex edge)))
195 (v2 (element (target-vertex edge))))
196 (add-edge-between-vertexes
197 graph v1 v2 :edge-class (type-of edge)
198 :edge-type (if (directed-edge-p edge)
202 :edge-id (edge-id edge)
203 :element (element edge)
207 :if-duplicate-do if-duplicate-do))))
211 (defmethod edge-lessp-by-weight ((e1 basic-edge) (e2 basic-edge))
212 (< (weight e1) (weight e2)))
214 ;;; minumum spanning tree
217 (defmethod minimum-spanning-tree ((graph basic-graph)
219 (edge-sorter #'edge-lessp-by-weight))
226 (loop for edge in (sort (edges graph) edge-sorter) do
227 (let ((v1 (source-vertex edge))
228 (v2 (target-vertex edge)))
230 (unless (eq (mst-find-set v1)
233 (mst-tree-union v1 v2)))
236 (cond ((= (length result) (- (length (vertexes graph)) 1))
238 (t (values nil result)))))))
242 (defmethod minimum-spanning-tree ((vertex-list list)
244 (edge-sorter #'edge-lessp-by-weight))
246 (v-edges (remove-duplicates
247 (flatten (mapcar #'edges vertex-list)) :test #'eq)))
254 (loop for edge in (sort v-edges edge-sorter) do
255 (let ((v1 (source-vertex edge))
256 (v2 (target-vertex edge))
257 (v1-set (mst-find-set v1))
258 (v2-set (mst-find-set v2)))
260 (when (or (not v1-set)
262 (return-from minimum-spanning-tree nil))
265 (unless (eq (mst-find-set v1)
268 (mst-tree-union v1 v2)))
271 (cond ((= (length result) (- (length vertex-list) 1))
273 (t (values nil result)))))))
275 ;;; uses mst to determine if the graph is connected
277 (defmethod connected-graph-p ((graph basic-graph) &key
278 (edge-sorter 'edge-lessp-by-weight))
279 (minimum-spanning-tree graph :edge-sorter edge-sorter))
284 (let ((g (make-container 'graph-container)))
285 (add-edge-between-vertexes g :v :y :edge-type :directed)
286 (add-edge-between-vertexes g :u :x :edge-type :directed)
287 (add-edge-between-vertexes g :x :v :edge-type :directed)
288 (add-edge-between-vertexes g :u :v :edge-type :directed)
289 (add-edge-between-vertexes g :y :x :edge-type :directed)
290 (add-edge-between-vertexes g :w :y :edge-type :directed)
291 (add-edge-between-vertexes g :w :z :edge-type :directed)
292 (add-edge-between-vertexes g :z :z :edge-type :directed
293 :if-duplicate-do :force)
294 (minimum-spanning-tree g))
296 ;;; GWK's implementation of kruskal's - slightly faster, but it doesn't return
297 ;;; a tree (still faster even if it does). Will decide later if which to use
298 ;;; ignoring for now -jjm
301 (defmethod minimum-spanning-tree ((graph basic-graph) &key (weight 'weight))
303 (union (make-container 'union-find-container))
304 (edges (sort (edges graph) #'< :key weight)))
306 graph (lambda (v) (insert-item union v)))
308 (let ((node-1 (representative-node union (vertex-1 edge)))
309 (node-2 (representative-node union (vertex-2 edge))))
310 (unless (eq (find-set node-1) (find-set node-2))
311 (graft-nodes node-1 node-2)
318 (loop for f in '(mst-kruskal minimum-spanning-tree-kruskal) do
319 (fluid-bind (((random-seed *random-generator*) 1))
320 (bind ((g (generate-undirected-graph-via-vertex-probabilities
321 *random-generator* (make-instance 'graph-container :default-edge-type :directed)
324 #2A((0.2 0.1) (nil 0.2))
326 (form-keyword "H" (format nil "~2,'0D~4,'0D" kind count))))
328 (timeit (:report :values)
329 (loop for n from 1 to 100 do
330 (funcall f g (lambda (a b)
331 (declare (ignore a b))
334 ;;; end minimum spanning tree
337 ;;; depth-first-search - clrs2
338 ;;; todo - figure out how to name this depth-first-search, which is already
339 ;;; defined in search.lisp
341 ;;; should probably make this special
343 (defparameter *depth-first-search-timer* -1)
345 ;;; undirected edges are less than edges that are directed
347 #+ignore ;;; incorrect, methinks - jjm
348 (defmethod edge-lessp-by-direction ((e1 basic-edge) (e2 basic-edge))
349 (cond ((or (every #'directed-edge-p (list e1 e2))
350 (every #'undirected-edge-p (list e1 e2)))
352 ((and (undirected-edge-p e1) (directed-edge-p e2))
356 (defmethod edge-lessp-by-direction ((e1 basic-edge) (e2 basic-edge))
357 (and (undirected-edge-p e1) (directed-edge-p e2)))
360 (defmethod out-edge-for-vertex-p ((edge basic-edge) (vertex basic-vertex))
361 (cond ((and (directed-edge-p edge)
362 (eq vertex (source-vertex edge)))
364 ((and (undirected-edge-p edge)
365 (or (eq vertex (source-vertex edge))
366 (eq vertex (target-vertex edge))))
370 ;;; depth-first-search
372 (defmethod dfs ((graph basic-graph) (root t) fn &key
373 (out-edge-sorter #'edge-lessp-by-direction))
374 (dfs graph (find-vertex graph root) fn :out-edge-sorter out-edge-sorter))
377 (defmethod dfs ((graph basic-graph) (root basic-vertex) fn &key
378 (out-edge-sorter #'edge-lessp-by-direction))
379 (setf *depth-first-search-timer* -1)
384 (setf (color v) :white
385 (previous-node v) nil
386 (discovery-time v) -1
387 (finish-time v) -1)))
392 (setf (color e) nil)))
394 (loop with vl = (remove root (vertexes graph) :test #'eql)
395 for v in (push root vl) do
396 (when (eql (color v) :white)
397 (dfs-visit graph v fn out-edge-sorter)))
400 (sort (copy-list (vertexes graph)) #'< :key #'finish-time)
404 (defmethod dfs-visit ((graph graph-container) (u basic-vertex)
408 (incf *depth-first-search-timer*)
409 (setf (color u) :gray
410 (discovery-time u) *depth-first-search-timer*)
413 (loop for edge in (sort (collect-elements
416 (out-edge-for-vertex-p e u))) sorter) do
417 (let ((v (other-vertex edge u)))
420 (setf (color edge) (color v)))
422 (when (eql (color v) :white)
423 (setf (previous-node v) u)
425 (dfs-visit graph v fn sorter))))
427 (incf *depth-first-search-timer*)
429 (setf (color u) :black
430 (finish-time u) *depth-first-search-timer*))
435 (let ((g (make-container 'graph-container)))
436 (add-edge-between-vertexes g :v :y :edge-type :directed)
437 (add-edge-between-vertexes g :u :x :edge-type :directed)
438 (add-edge-between-vertexes g :x :v :edge-type :directed)
439 (add-edge-between-vertexes g :u :v :edge-type :directed)
440 (add-edge-between-vertexes g :y :x :edge-type :directed)
441 (add-edge-between-vertexes g :w :y :edge-type :directed)
442 (add-edge-between-vertexes g :w :z :edge-type :directed)
443 (add-edge-between-vertexes g :z :z :edge-type :directed
444 :if-duplicate-do :force)
445 (assert (equal '(:X :Y :V :U :Z :W)
446 (mapcar #'element (dfs g :u #'identity)))))
449 (defmethod dfs-tree-edge-p ((edge graph-container-edge))
450 (eql (color edge) :white))
453 (defmethod dfs-back-edge-p ((edge graph-container-edge))
454 (eql (color edge) :gray))
456 ;;; not correct - has to look at combination of discovery-time and finish-time
458 (defmethod dfs-forward-edge-p ((edge graph-container-edge))
459 (warn "implementation is not correct.")
460 (unless (and (dfs-tree-edge-p edge)
461 (dfs-back-edge-p edge))
462 (< (discovery-time (source-vertex edge))
463 (discovery-time (target-vertex edge)))))
465 ;;; not correct - has to look at combination of discovery-time and finish-time
467 (defmethod dfs-cross-edge-p ((edge graph-container-edge))
468 (warn "implementation is not correct.")
469 (unless (and (dfs-tree-edge-p edge)
470 (dfs-back-edge-p edge))
471 (> (discovery-time (source-vertex edge))
472 (discovery-time (target-vertex edge)))))
475 (defmethod dfs-edge-type ((edge graph-container-edge))
476 (cond ((dfs-tree-edge-p edge)
478 ((dfs-back-edge-p edge)
480 ((dfs-forward-edge-p edge)
482 ((dfs-cross-edge-p edge)
488 ;;; mapping functions
492 (defmethod map-over-all-combinations-of-k-vertexes ((graph basic-graph) k fn)
493 (let* ((vertex-count (size graph))
494 (symbols (make-list k :initial-element vertex-count))
495 (vertexes (vertexes graph)))
496 (iterate-over-indexes
498 (lambda (vertex-indexes)
499 (when (apply #'< vertex-indexes)
500 (funcall fn (mapcar (lambda (vertex-index)
501 (nth-element vertexes vertex-index))
502 vertex-indexes)))))))
507 (g (make-container 'graph-container)))
508 (add-edge-between-vertexes g :u :v :edge-type :directed)
509 (add-edge-between-vertexes g :u :x :edge-type :directed)
510 (add-edge-between-vertexes g :x :v :edge-type :directed)
511 (add-edge-between-vertexes g :v :y :edge-type :directed)
512 (add-edge-between-vertexes g :y :x :edge-type :directed)
513 (add-edge-between-vertexes g :w :y :edge-type :directed)
514 (add-edge-between-vertexes g :w :z :edge-type :directed)
516 (map-over-all-combinations-of-k-vertexes
519 (lambda (vertex-list)
520 (let ((graph-from-vertexes (make-graph-from-vertexes vertex-list)))
521 (when (mst-kruskal graph-from-vertexes #'identity-sorter)
522 (push graph-from-vertexes result)))))
526 ;;; todo: merge these two defs
528 (defmethod map-over-all-combinations-of-k-edges ((graph basic-graph) k fn)
529 (let* ((edge-count (edge-count graph))
530 (symbols (make-list k :initial-element edge-count))
531 (edges (edges graph)))
533 (iterate-over-indexes
535 (lambda (edge-indexes)
536 (when (apply #'< edge-indexes)
537 (funcall fn (mapcar (lambda (edge-index)
538 (nth-element edges edge-index))
542 (defmethod map-over-all-combinations-of-k-edges ((vertex basic-vertex) k fn)
543 (let* ((edge-count (edge-count vertex))
544 (symbols (make-list k :initial-element edge-count))
545 (edges (edges vertex)))
547 (iterate-over-indexes
549 (lambda (edge-indexes)
550 (when (apply #'< edge-indexes)
551 (funcall fn (mapcar (lambda (edge-index)
552 (nth-element edges edge-index))
556 (map-over-all-combinations-of-k-edges
557 (generate-undirected-graph-via-verex-probabilities
558 *random-generator* 'graph-container
561 #2A((0.2 0.1) (nil 0.2))
563 (form-keyword "H" (format nil "~2,'0D~4,'0D" kind count))))
568 (format t "~A -- ~A " (element (vertex-1 e)) (element (vertex-2 e))))
575 ;;; ***************************************************************************
577 ;;; ***************************************************************************