|
|
|
(module graph mzscheme
|
|
|
|
|
|
|
|
(provide digraph)
|
|
|
|
|
|
|
|
(define (zero-thunk) 0)
|
|
|
|
|
|
|
|
;; digraph:
|
|
|
|
;; ('a list) * ('a -> 'a list) * ('a -> 'b) * ('b * 'b -> 'b) * (-> 'b)
|
|
|
|
;; -> ('a -> 'b)
|
|
|
|
;; DeRemer and Pennello 1982
|
|
|
|
;; Computes (f x) = (f- x) union Union{(f y) | y in (edges x)}
|
|
|
|
;; We use a hash-table to represent the result function 'a -> 'b set, so
|
|
|
|
;; the values of type 'a must be comparable with eq?.
|
|
|
|
(define (digraph nodes edges f- union fail)
|
|
|
|
(letrec [
|
|
|
|
;; Will map elements of 'a to 'b sets
|
|
|
|
(results (make-hash-table))
|
|
|
|
(f (lambda (x) (hash-table-get results x fail)))
|
|
|
|
|
|
|
|
;; Maps elements of 'a to integers.
|
|
|
|
(N (make-hash-table))
|
|
|
|
(get-N (lambda (x) (hash-table-get N x zero-thunk)))
|
|
|
|
(set-N (lambda (x d) (hash-table-put! N x d)))
|
|
|
|
|
|
|
|
(stack null)
|
|
|
|
(push (lambda (x)
|
|
|
|
(set! stack (cons x stack))))
|
|
|
|
(pop (lambda ()
|
|
|
|
(begin0
|
|
|
|
(car stack)
|
|
|
|
(set! stack (cdr stack)))))
|
|
|
|
(depth (lambda () (length stack)))
|
|
|
|
|
|
|
|
;; traverse: 'a ->
|
|
|
|
(traverse
|
|
|
|
(lambda (x)
|
|
|
|
(push x)
|
|
|
|
(let ((d (depth)))
|
|
|
|
(set-N x d)
|
|
|
|
(hash-table-put! results x (f- x))
|
|
|
|
(for-each (lambda (y)
|
|
|
|
(if (= 0 (get-N y))
|
|
|
|
(traverse y))
|
|
|
|
(hash-table-put! results
|
|
|
|
x
|
|
|
|
(union (f x) (f y)))
|
|
|
|
(set-N x (min (get-N x) (get-N y))))
|
|
|
|
(edges x))
|
|
|
|
(if (= d (get-N x))
|
|
|
|
(let loop ((p (pop)))
|
|
|
|
(set-N p +inf.0)
|
|
|
|
(hash-table-put! results p (f x))
|
|
|
|
(if (not (eq? x p))
|
|
|
|
(loop (pop))))))))]
|
|
|
|
(for-each (lambda (x)
|
|
|
|
(if (= 0 (get-N x))
|
|
|
|
(traverse x)))
|
|
|
|
nodes)
|
|
|
|
f))
|
|
|
|
|
|
|
|
)
|