2 ;;; GRAPHS - graph theory package for Maxima
4 ;;; Copyright (C) 2007 Andrej Vodopivec <andrej.vodopivec@gmail.com>
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.
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.
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
23 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
25 ;; This file provides read/write support for the graph6 format and
26 ;; read support for the sparse6 format. The description of the formats
28 ;; http://cs.anu.edu.au/~bdm/data/formats.txt
30 ;; There are sites which provide large collections of graphs in these
32 ;; http://cs.anu.edu.au/~bdm/data/graphs.html
33 ;; http://people.csse.uwa.edu.au/gordon/data.html
35 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
37 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
46 (+ 63 (boole boole-and
63 (ash n -
12)))
47 (+ 63 (boole boole-and
63 (ash n -
6)))
48 (+ 63 (boole boole-and
63 n
)))))
52 (loop while
(> n
0) do
53 (setq val
(cons (+ 63 (boole boole-and n
63)) val
))
57 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
59 ;; encode to graph6 string
62 (defmfun $graph6_encode
(gr)
63 (require-graph 'graph6_decode
1 gr
)
66 (defun graph6-string (gr)
67 (let ((n ($graph_order gr
))
68 (names (get-canonical-names (vertices gr
)))
73 (loop for i from
1 to
(1- n
) do
74 (loop for j from
0 to
(1- i
) do
75 (let ((u (car (rassoc i names
)))
76 (v (car (rassoc j names
))))
77 (setq e-val
(ash e-val
1))
78 (if (is-edge-in-graph (list (min u v
) (max u v
)) gr
)
81 ;; add zeros to the right
82 (let ((n1 (mod (/ (* n
(1- n
)) 2) 6)))
84 (setq e-val
(ash e-val
(- 6 n1
)))))
86 ;; change bits to string
87 (format nil
"~{~c~}" (mapcar #'code-char
88 (append (get-n n
) (cdr (get-r e-val
))))) ))
90 (defmfun $graph6_export
(graphs fl
)
92 (merror "`graph6_export': second argument is not a string."))
93 (unless ($listp graphs
)
94 (merror "`graph6_export': first argument is not a list."))
95 (with-open-file (stream fl
:direction
:output
:if-exists
:supersede
)
96 (dolist (g (cdr graphs
))
97 (format stream
"~a~%" ($graph6_encode g
))))
100 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
102 ;; decode from graph6 string
105 (defmfun $graph6_decode
(str)
107 (unless (stringp str
)
108 (merror "`graph6_decode': argument is not a string."))
110 ;; read bits from string
111 (if (and (> (length str
) 10)
112 (string= ">>graph6<<" (subseq str
0 10)))
113 (setq str
(subseq str
10)))
115 ;; check if it is actually sparse6
116 (when (string= ":" (subseq str
0 1))
117 (merror "`graph6_decode': wrong format."))
120 (let ((n) (g) (e-bits) (e-val 0)
121 (bits (mapcar #'char-code
(coerce str
'list
))))
123 (if (< (car bits
) 126)
125 (setq n
(- (car bits
) 63))
126 (setq e-bits
(cdr bits
)))
128 (setq bits
(cdr bits
))
129 (setq n
(+ (ash (- (car bits
) 63) 12)
130 (ash (- (cadr bits
) 63) 6)
131 (- (caddr bits
) 63)))
132 (setq e-bits
(cdddr bits
))))
135 (setq e-val
(ash e-val
6))
136 (incf e-val
(- v
63)))
138 ;; remove trailing zeros
139 (let ((n1 (mod (/ (* n
(1- n
)) 2) 6)))
141 (setq e-val
(ash e-val
(- n1
6)))))
144 (setq g
($empty_graph n
))
145 (loop for i from
(1- n
) downto
0 do
146 (loop for j from
(1- i
) downto
0 do
147 (if (> (boole boole-and e-val
1) 0)
148 (add-edge (list j i
) g
))
149 (setq e-val
(ash e-val -
1))))
152 (defmfun $graph6_import
(fl)
154 (merror "`graph6_import': argument is not a string."))
155 (with-open-file (stream fl
)
157 (do ((line (read-line stream nil
'eof
)
158 (read-line stream nil
'eof
)))
160 (setq lst
(cons ($graph6_decode line
) lst
)))
161 `((mlist simp
) ,@lst
))))
163 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
165 ;; decode from sparse6 string
168 (defmfun $sparse6_decode
(str)
170 (unless (stringp str
)
171 (merror "`sparse6_decode': argument is not a string."))
173 ;; read bits from string
174 (if (and (> (length str
) 11)
175 (string= ">>sparse6<<" (subseq str
0 11)))
176 (setq str
(subseq str
11)))
178 ;; the first character must be ':' and it is ignored
179 (unless (string= ":" (subseq str
0 1))
180 (merror "`sparse6_decode': wrong format."))
181 (setq str
(subseq str
1))
184 (let ((n) (g) (e-bits) (e-val 0) (k 0)
185 (bits (mapcar #'char-code
(coerce str
'list
))))
187 (if (< (car bits
) 126)
189 (setq n
(- (car bits
) 63))
190 (setq e-bits
(cdr bits
)))
192 (setq bits
(cdr bits
))
193 (setq n
(+ (ash (- (car bits
) 63) 12)
194 (ash (- (cadr bits
) 63) 6)
195 (- (caddr bits
) 63)))
196 (setq e-bits
(cdddr bits
))))
199 (setq e-val
(ash e-val
6))
200 (incf e-val
(- v
63)))
203 (setq k
(integer-length (1- n
)))
206 (setq g
($empty_graph n
))
207 (let ((v 0) (bi) (xi) (i (1- (integer-length e-val
))))
209 (loop while
(>= i k
) do
210 (setq bi
(if (logbitp i e-val
) 1 0))
213 (loop for l from
0 to
(1- k
) do
215 (when (logbitp i e-val
)
223 ($add_edge
`((mlist simp
) ,xi
,v
) g
)))
228 (defmfun $sparse6_import
(fl)
230 (merror "`sparse6_import': argument is not a string."))
231 (with-open-file (stream fl
)
233 (do ((line (read-line stream nil
'eof
)
234 (read-line stream nil
'eof
)))
236 (setq lst
(cons ($sparse6_decode line
) lst
)))
237 `((mlist simp
) ,@lst
))))
239 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
241 ;; encode to sparse6 string
244 (defmfun $sparse6_encode
(gr)
245 (require-graph 'sparse_encode
1 gr
)
248 (defun sparse6-string (gr)
249 (let* ((vrt (reverse (vertices gr
)))
250 (n ($graph_order gr
))
251 (k (integer-length (1- n
)))
252 (names (get-canonical-names vrt
))
253 (edges (mapcar #'(lambda (u) (list (cdr (assoc (first u
) names
))
254 (cdr (assoc (second u
) names
))))
260 (setq edges
(sort edges
261 #'(lambda (u v
) (or (< (second u
) (second v
))
262 (and (= (second u
) (second v
))
263 (< (first u
) (first v
)))))))
269 (setq e-val
(+ (ash e-val
(1+ k
)) x
))
271 (setq e-val
(1+ (ash e-val
1)))
274 (setq e-val
(+ (ash e-val k
) x
))
276 (setq e-val
(+ (ash e-val k
) y
))
278 (setq e-val
(+ (ash e-val
(1+ k
)) x
))))))))
280 (unless (= (mod (integer-length e-val
) 6) 0)
281 (let ((n1 (mod (integer-length e-val
) 6)))
282 (setq e-val
(1- (ash (1+ e-val
) (- 6 n1
))))))
284 (format nil
":~{~c~}" (mapcar #'code-char
285 (append (get-n n
) (get-r e-val
)))) ))
287 (defmfun $sparse6_export
(graphs fl
)
289 (merror "`sparse6_export': second argument is not a string."))
290 (unless ($listp graphs
)
291 (merror "`sparse6_export': first argument is not a list."))
292 (with-open-file (stream fl
:direction
:output
:if-exists
:supersede
)
293 (dolist (g (cdr graphs
))
294 (format stream
"~a~%" ($sparse6_encode g
))))
299 ;;; dig6 is similar to graph6 but for directed graphs
300 ;;; (dig6 is used in SAGE)
303 (defmfun $dig6_encode
(gr)
304 (require-digraph 'dig6_decode
1 gr
)
307 (defun dig6-string (gr)
308 (let ((n ($graph_order gr
))
309 (names (get-canonical-names (vertices gr
)))
314 (loop for i from
0 to
(1- n
) do
315 (loop for j from
0 to
(1- n
) do
316 (let ((u (car (rassoc i names
)))
317 (v (car (rassoc j names
))))
318 (setq e-val
(ash e-val
1))
319 (if (is-edge-in-graph (list u v
) gr
)
322 ;; add zeros to the right
323 (let ((n1 (mod (* n n
) 6)))
325 (setq e-val
(ash e-val
(- 6 n1
)))))
327 ;; change bits to string
328 (format nil
"~{~c~}" (mapcar #'code-char
329 (append (get-n n
) (cdr (get-r e-val
))))) ))
331 (defmfun $dig6_export
(graphs fl
)
333 (merror "`dig6_export': second argument is not a string."))
334 (unless ($listp graphs
)
335 (merror "`dig6_export': first argument is not a list."))
336 (with-open-file (stream fl
:direction
:output
:if-exists
:supersede
)
337 (dolist (g (cdr graphs
))
338 (format stream
"~a~%" ($dig6_encode g
))))
342 (defmfun $dig6_decode
(str)
344 (unless (stringp str
)
345 (merror "`dig6_decode': argument is not a string."))
347 ;; read bits from string
348 (if (and (> (length str
) 8)
349 (string= ">>dig6<<" (subseq str
0 8)))
350 (setq str
(subseq str
0)))
353 (let ((n) (g) (e-bits) (e-val 0)
354 (bits (mapcar #'char-code
(coerce str
'list
))))
356 (if (< (car bits
) 126)
358 (setq n
(- (car bits
) 63))
359 (setq e-bits
(cdr bits
)))
361 (setq bits
(cdr bits
))
362 (setq n
(+ (ash (- (car bits
) 63) 12)
363 (ash (- (cadr bits
) 63) 6)
364 (- (caddr bits
) 63)))
365 (setq e-bits
(cdddr bits
))))
368 (setq e-val
(ash e-val
6))
369 (incf e-val
(- v
63)))
371 ;; remove trailing zeros
372 (let ((n1 (mod (* n n
) 6)))
374 (setq e-val
(ash e-val
(- n1
6)))))
377 (setq g
($empty_digraph n
))
378 (loop for i from
(1- n
) downto
0 do
379 (loop for j from
(1- n
) downto
0 do
380 (if (> (boole boole-and e-val
1) 0)
381 (add-edge (list j i
) g
))
382 (setq e-val
(ash e-val -
1))))
385 (defmfun $dig6_import
(fl)
387 (merror "`dig6_import': argument is not a string."))
388 (with-open-file (stream fl
)
390 (do ((line (read-line stream nil
'eof
)
391 (read-line stream nil
'eof
)))
393 (setq lst
(cons ($dig6_decode line
) lst
)))
394 `((mlist simp
) ,@lst
))))