-
Notifications
You must be signed in to change notification settings - Fork 0
/
graph-util.cl
106 lines (78 loc) · 2.66 KB
/
graph-util.cl
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
;; DOT graphing routines
(defun dot-name (exp)
(substitute-if #\_ (complement #'alphanumericp) (prin1-to-string exp)))
(defparameter *max-label-length* 30)
;; Convert an expression into a DOT-compatible label
;; exp -> str -> str[30] | s:str | s != "-"
(defun dot-label (exp)
(if exp
(let ((s (write-to-string exp :pretty nil)))
(if (> (length s) *max-label-length*)
(concatenate 'string (subseq s 0 (- *max-label-length* 3)) "...")
s))
""))
;; Convert a list of nodes into DOT format
;; [node->label] -> str([DOT(node->label)])
(defun nodes->dot (nodes)
(mapc (lambda (node)
(fresh-line)
(princ (dot-name (car node)))
(princ "[label=\"")
(princ (dot-label node))
(princ "\";"))
nodes))
;; Convert a list of edges into DOT format
(defun edges->dot (edges)
(mapc (lambda (node)
(mapc (lambda (edge)
(fresh-line)
(princ (dot-name (car node)))
(princ "->")
(princ (dot-name (car edge)))
(princ "[label=\"")
(princ (dot-label (cdr edge)))
(princ "\"];"))
(cdr node)))
edges))
;; Generate a DOT graph from a list of edges and a list of nodes
(defun graph-dot (nodes edges)
(princ "digraph{")
(nodes->dot nodes)
(edges->dot edges)
(princ "}"))
;; DOT->.png conversion routines
(defun dot->png (fname thunk)
(with-open-file (*standard-output*
fname
:direction :output
:if-exists :supersede)
(funcall thunk))
(ext:shell (concatenate 'string "dot -Tpng -O " fname)))
(defun graph->png (fname nodes edges)
(dot->png fname
(lambda ()
(graph-dot nodes edges))))
;; Convert a list on undirectional edges to DOT format
;; The duplicate egde elimination via maplist is notably elegant
(defun uedges->dot (edges)
(maplist (lambda (lst)
(mapc (lambda (edge)
(unless (assoc (car edge) (cdr lst))
(fresh-line)
(princ (dot-name (caar lst)))
(princ "--")
(princ (dot-name (car edge)))
(princ "[label=\"")
(princ (dot-label (cdr edge)))
(princ "\"];")))
(cdar lst)))
edges))
(defun ugraph->dot (nodes edges)
(princ "graph{")
(nodes->dot nodes)
(uedges->dot edges)
(princ "}"))
(defun ugraph->png (fname nodes edges)
(dot->png fname
(lambda ()
(ugraph->dot nodes edges))))