This repository has been archived on 2024-10-22. You can view files and clone it, but cannot push or open issues or pull requests.
guile-prescheme/ps-compiler/util/strong.scm
2022-08-04 16:46:09 +10:00

149 lines
5.3 KiB
Scheme

;;; Ported from Scheme 48 1.9. See file COPYING for notices and license.
;;;
;;; Port Author: Andrew Whatson
;;;
;;; Original Authors: Richard Kelsey
;;;
;;; scheme48-1.9.2/ps-compiler/util/strong.scm
;;;
;;; Code to find the strongly connected components of a graph.
;;; (TO <vertex>) are the vertices that have an edge to <vertex>.
;;; (SLOT <vertex>) and (SET-SLOT! <vertex> <value>) is a settable slot
;;; used by the algorithm.
;;;
;;; The components are returned in a backwards topologically sorted list.
(define-module (ps-compiler util strong)
#:use-module (prescheme s48-defrecord)
#:export (strongly-connected-components))
(define (strongly-connected-components vertices to slot set-slot!)
(make-vertices vertices to slot set-slot!)
(let loop ((to-do vertices) (index 0) (stack #t) (comps '()))
(let ((to-do (find-next-vertex to-do slot)))
(cond ((null? to-do)
(for-each (lambda (n) (set-slot! n #f)) vertices)
comps)
(else
(call-with-values
(lambda ()
(do-vertex (slot (car to-do)) index stack comps))
(lambda (index stack comps)
(loop to-do index stack comps))))))))
(define (find-next-vertex vertices slot)
(do ((vertices vertices (cdr vertices)))
((or (null? vertices)
(= 0 (vertex-index (slot (car vertices)))))
vertices)))
(define-record-type vertex
(data ;; user's data
)
((edges '()) ;; list of vertices
(stack #f) ;; next vertex on the stack
(index 0) ;; time at which this vertex was reached in the traversal
(parent #f) ;; a vertex pointing to this one
(lowpoint #f) ;; lowest index in this vertices strongly connected component
))
(define (make-vertices vertices to slot set-slot!)
(let ((maybe-slot (lambda (n)
(let ((s (slot n)))
(if (vertex? s)
s
(error "graph edge points to non-vertex" n))))))
(for-each (lambda (n)
(set-slot! n (vertex-maker n)))
vertices)
(for-each (lambda (n)
(set-vertex-edges! (slot n) (map maybe-slot (to n))))
vertices)
(values)))
;; The numbers are the algorithm step numbers from page 65 of Graph Algorithms,
;; Shimon Even, Computer Science Press, 1979.
;; 2
(define (do-vertex vertex index stack comps)
(let ((index (+ index '1)))
(set-vertex-index! vertex index)
(set-vertex-lowpoint! vertex index)
(set-vertex-stack! vertex stack)
(get-strong vertex index vertex comps)))
;; 3
(define (get-strong vertex index stack comps)
(if (null? (vertex-edges vertex))
(end-vertex vertex index stack comps)
(follow-edge vertex index stack comps)))
;; 7
(define (end-vertex vertex index stack comps)
(call-with-values
(lambda ()
(if (= (vertex-index vertex) (vertex-lowpoint vertex))
(unwind-stack vertex stack comps)
(values stack comps)))
(lambda (stack comps)
(cond ((vertex-parent vertex)
=> (lambda (parent)
(if (> (vertex-lowpoint parent) (vertex-lowpoint vertex))
(set-vertex-lowpoint! parent (vertex-lowpoint vertex)))
(get-strong parent index stack comps)))
(else
(values index stack comps))))))
(define (unwind-stack vertex stack comps)
(let loop ((n stack) (c '()))
(let ((next (vertex-stack n))
(c (cons (vertex-data n) c)))
(set-vertex-stack! n #f)
(if (eq? n vertex)
(values next (cons c comps))
(loop next c)))))
;; 4
(define (follow-edge vertex index stack comps)
(let* ((next (pop-vertex-edge! vertex))
(next-index (vertex-index next)))
(cond ((= next-index 0)
(set-vertex-parent! next vertex)
(do-vertex next index stack comps))
(else
(if (and (< next-index (vertex-index vertex))
(vertex-stack next)
(< next-index (vertex-lowpoint vertex)))
(set-vertex-lowpoint! vertex next-index))
(get-strong vertex index stack comps)))))
(define (pop-vertex-edge! vertex)
(let ((edges (vertex-edges vertex)))
(set-vertex-edges! vertex (cdr edges))
(car edges)))
;; GRAPH is ((<symbol> . <symbol>*)*)
;;(define (test-strong graph)
;; (let ((vertices (map (lambda (n)
;; (vector (car n) #f #f))
;; graph)))
;; (for-each (lambda (data vertex)
;; (vector-set! vertex 1 (map (lambda (s)
;; (first (lambda (v)
;; (eq? s (vector-ref v 0)))
;; vertices))
;; (cdr data))))
;; graph
;; vertices)
;; (map (lambda (l)
;; (map (lambda (n) (vector-ref n 0)) l))
;; (strongly-connected-components vertices
;; (lambda (v) (vector-ref v 1))
;; (lambda (v) (vector-ref v 2))
;; (lambda (v val)
;; (vector-set! v 2 val))))))