-
Notifications
You must be signed in to change notification settings - Fork 29
/
traverse.lisp
81 lines (74 loc) · 3.75 KB
/
traverse.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
(in-package :graph-db)
(defclass traversal ()
((end-vertex :accessor end-vertex :initarg :end-vertex :initform nil)
(reverse-path :accessor reverse-path :initarg :path :initform nil)))
(defmethod traversal-path ((traversal traversal))
(reverse (reverse-path traversal)))
(defmethod depth ((traversal traversal))
(length (reverse-path traversal)))
(defun make-traversal (vertex path)
(make-instance 'traversal
:end-vertex vertex
:path path))
(defmethod copy-traversal ((traversal traversal))
(make-traversal (end-vertex traversal)
(copy-list (reverse-path traversal))))
(defmethod update-traversal ((traversal traversal) (vertex vertex) (edge edge))
(let ((new-traversal
(make-instance 'traversal
:end-vertex vertex
:path (copy-list (reverse-path traversal)))))
(push edge (reverse-path new-traversal))
new-traversal))
(defmethod traverse ((vertex vertex) &key (graph *graph*) (order :bfs)
(direction :both) (uniqueness :global)
edge-type max-depth return-paths)
;; FIXME: respect order and uniqueness
;; currently bfs, global uniqueness.
(declare (ignore order uniqueness))
(let ((queue (make-queue :elements
(list
(make-instance 'traversal
:end-vertex vertex))))
(result-table (make-hash-table :test 'equalp))
(memory (make-hash-table :test 'equalp)))
(loop until (empty-queue-p queue) do
(let* ((traversal (dequeue queue))
(vertex (end-vertex traversal)))
(unless (and max-depth
(> (depth traversal) max-depth))
(when (or (eql direction :out) (eql direction :both))
(map-edges (lambda (edge)
(let* ((to-vertex (lookup-vertex (to edge)))
(new-traversal
(update-traversal traversal
to-vertex
edge)))
(unless (gethash to-vertex memory)
(setf (gethash to-vertex memory) t)
(enqueue queue new-traversal))
(when (typep edge edge-type)
(setf (gethash to-vertex result-table)
new-traversal))))
graph
:vertex vertex
:direction :out))
(when (or (eql direction :in) (eql direction :both))
(map-edges (lambda (edge)
(let* ((from-vertex (lookup-vertex (from edge)))
(new-traversal
(update-traversal traversal
from-vertex
edge)))
(unless (gethash from-vertex memory)
(setf (gethash from-vertex memory) t)
(enqueue queue new-traversal))
(when (typep edge edge-type)
(setf (gethash from-vertex result-table)
new-traversal))))
graph
:vertex vertex
:direction :in)))))
(if return-paths
(loop for p being the hash-values in result-table collecting p)
(loop for v being the hash-keys in result-table collecting v))))