123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- ; Part of Scheme 48 1.9. See file COPYING for notices and license.
- ; Authors: Richard Kelsey
- ; Code to determine the separation vertices of a graph
- ; NODES is a list of nodes
- ; (TO node) returns a list of the nodes which are connected to this one
- ; (SLOT-NODE node) and (SET-SLOT! node value) are used by the algorithm to
- ; associate data with nodes (in the absence of a tables).
- (define (separation-vertices nodes to slot set-slot!)
- (cond ((null? nodes)
- (values '() '()))
- ((null? (cdr nodes))
- (values nodes (list nodes)))
- (else
- (receive (separators components)
- (real-separation-vertices (make-vertices nodes to slot set-slot!))
- (for-each (lambda (n) (set-slot! n #f)) nodes)
- (values separators components)))))
- (define-record-type vertex :vertex
- (really-make-vertex data edges dfs-index)
- vertex?
- (data vertex-data) ; user's data
- (edges vertex-edges ; list of edges from this vertex
- set-vertex-edges!)
- (dfs-index vertex-dfs-index ; ordering from depth-first-search
- set-vertex-dfs-index!)
- (level vertex-level ; value used in algorithm...
- set-vertex-level!)
- (parent vertex-parent ; parent of this node in DFS tree
- set-vertex-parent!))
- (define (make-vertex data)
- (really-make-vertex data '() 0))
- (define-record-type edge :edge
- (make-edge from to unused?)
- (from edge-from) ; two (unordered) vertices
- (to edge-to)
- (unused? edge-unused ; used to mark edges that have been traversed
- set-edge-unused!))
- (define (make-edge from to)
- (really-make-edge from to #t))
- (define (other-vertex edge v)
- (if (eq? v (edge-from edge))
- (edge-to edge)
- (edge-from edge)))
- (define (maybe-add-edge from to)
- (if (and (not (eq? from to))
- (not (any? (lambda (e)
- (or (eq? to (edge-from e))
- (eq? to (edge-to e))))
- (vertex-edges from))))
- (let ((e (make-edge from to)))
- (set-vertex-edges! from (cons e (vertex-edges from)))
- (set-vertex-edges! to (cons e (vertex-edges to))))))
- (define (make-vertices nodes to slot set-slot!)
- (let ((vertices (map (lambda (n)
- (let ((v (make-vertex n)))
- (set-slot! n v)
- v))
- nodes)))
- (for-each (lambda (n)
- (for-each (lambda (n0)
- (maybe-add-edge (slot n) (slot n0)))
- (to n)))
- nodes)
- vertices))
-
- ; The numbers are the algorithm step numbers from page 62 of Graph Algorithms,
- ; Shimon Even, Computer Science Press, 1979.
- ; Them Us
- ; L(v) (vertex-level v)
- ; k(v) (vertex-dfs-index v)
- ; f(v) (vertex-parent v)
- ; S stack
- ; s start
- (define (real-separation-vertices vertices)
- (do-vertex (car vertices) 0 '() (car vertices) '() '()))
- ; 2
- (define (do-vertex v i stack start v-res c-res)
- (let ((i (+ i 1)))
- (set-vertex-level! v i)
- (set-vertex-dfs-index! v i)
- (find-unused-edge v i (cons v stack) start v-res c-res)))
- ; 3
- (define (find-unused-edge v i stack start v-res c-res)
- (let ((e (first edge-unused? (vertex-edges v))))
- (if e
- (do-edge e v i stack start v-res c-res)
- (no-unused-edge v i stack start v-res c-res))))
- ; 4
- (define (do-edge e v i stack start v-res c-res)
- (let ((u (other-vertex e v)))
- (set-edge-unused?! e #f)
- (cond ((= 0 (vertex-dfs-index u))
- (set-vertex-parent! u v)
- (do-vertex u i stack start v-res c-res))
- (else
- (if (> (vertex-level v)
- (vertex-dfs-index u))
- (set-vertex-level! v (vertex-dfs-index u)))
- (find-unused-edge v i stack start v-res c-res)))))
- ; 5
- (define (no-unused-edge v i stack start v-res c-res)
- (let* ((parent (vertex-parent v))
- (p-dfs-index (vertex-dfs-index parent)))
- (cond ((= 1 p-dfs-index)
- (gather-nonseparable-with-start v i stack start v-res c-res))
- ((< (vertex-level v) p-dfs-index)
- (if (< (vertex-level v)
- (vertex-level parent))
- (set-vertex-level! parent (vertex-level v)))
- (find-unused-edge parent i stack start v-res c-res))
- (else
- (gather-nonseparable v i stack start v-res c-res)))))
- ; 7
- (define (gather-nonseparable v i stack start v-res c-res)
- (let* ((parent (vertex-parent v))
- (data (vertex-data parent)))
- (receive (vertices stack)
- (pop-down-to stack v)
- (find-unused-edge parent
- i
- stack
- start
- (if (not (memq? data v-res))
- (cons data v-res)
- v-res)
- (cons (cons data (map vertex-data vertices)) c-res)))))
- ; 9
- (define (gather-nonseparable-with-start v i stack start v-res c-res)
- (receive (vertices stack)
- (pop-down-to stack v)
- (let* ((data (vertex-data start))
- (c-res (cons (cons data (map vertex-data vertices)) c-res)))
- (if (not (any? edge-unused? (vertex-edges start)))
- (values v-res c-res)
- (find-unused-edge start
- i
- stack
- start
- (if (not (memq? data v-res))
- (cons data v-res)
- v-res)
- c-res)))))
- (define (pop-down-to stack v)
- (do ((stack stack (cdr stack))
- (res '() (cons (car stack) res)))
- ((eq? v (car stack))
- (values (cons v res) (cdr stack)))))
- (define (test-separation-vertices graph)
- (let ((nodes (map (lambda (n)
- (vector (car n) #f #f))
- graph)))
- (for-each (lambda (data node)
- (vector-set! node 1 (map (lambda (s)
- (first (lambda (v)
- (eq? s (vector-ref v 0)))
- nodes))
- (cdr data))))
- graph
- nodes)
- (receive (separation-vertices components)
- (separation-vertices nodes
- (lambda (v) (vector-ref v 1))
- (lambda (v) (vector-ref v 2))
- (lambda (v val) (vector-set! v 2 val)))
- (values (map (lambda (v) (vector-ref v 0)) separation-vertices)
- (map (lambda (l)
- (map (lambda (v) (vector-ref v 0))
- l))
- components)))))
-
|