transitive.scm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey
  3. ; General transitive closure
  4. ; (make-graph-from-predecessors nodes node-parents node-temp set-node-temp!)
  5. ; -> graph
  6. ; (make-graph-from-successors nodes node-kids node-temp set-node-temp!)
  7. ; -> graph
  8. ;
  9. ; (transitive-or! graph elements set-elements! element-temp set-element-temp!)
  10. ; (transitive-or-with-kill! graph elements set-elements! node-kills element-temp set-element-temp!)
  11. ; (transitive-or-with-pass! graph elements set-elements! node-passes element-temp set-element-temp!)
  12. ;
  13. ; (transitive-and! graph elements set-elements! element-temp set-element-temp!)
  14. ; (transitive-and-with-kill! graph elements set-elements! node-kills element-temp set-element-temp!)
  15. ; (transitive-and-with-pass! graph elements set-elements! node-passes element-temp set-element-temp!)
  16. ;----------------
  17. (define (make-graph-from-predecessors user-nodes user-node-parents node-temp set-node-temp!)
  18. (let ((nodes (make-nodes user-nodes set-node-temp!)))
  19. (connect-nodes-using-parents! nodes user-node-parents node-temp)
  20. (for-each (lambda (node)
  21. (set-node-temp! (node-data node) #f))
  22. nodes)
  23. (make-graph nodes)))
  24. (define (make-graph-from-successors user-nodes user-node-kids node-temp set-node-temp!)
  25. (let ((nodes (make-nodes user-nodes set-node-temp!)))
  26. (connect-nodes-using-children! nodes user-node-kids node-temp)
  27. (for-each (lambda (node)
  28. (set-node-temp! (node-data node) #f))
  29. nodes)
  30. (make-graph nodes)))
  31. (define (make-nodes user-nodes set-node-temp!)
  32. (map (lambda (data)
  33. (let ((node (node-maker data '() '())))
  34. (set-node-temp! data node)
  35. node))
  36. user-nodes))
  37. (define-record-type graph
  38. (nodes ; list of nodes
  39. )
  40. ())
  41. (define make-graph graph-maker)
  42. (define-record-type node
  43. (data ; user's data
  44. (parents) ; predecessors
  45. (kids)) ; successors
  46. (elt-set ; elements
  47. kill-set ; elements that are not passed
  48. changed? ; change flag for iteration
  49. ))
  50. ;------------------------------
  51. ; Six false fronts for the real procedure.
  52. (define (transitive-or! graph elts set-elts! elt-hash set-elt-hash!)
  53. (do-it graph elts set-elts! #f #f elt-hash set-elt-hash!
  54. (transitive-or-closure! or-update-node)))
  55. (define (transitive-or-with-kill! graph elts set-elts! kill-elts elt-hash set-elt-hash!)
  56. (do-it graph elts set-elts! kill-elts #f elt-hash set-elt-hash!
  57. (transitive-or-closure! or-update-node-with-kill)))
  58. (define (transitive-or-with-pass! graph elts set-elts! pass-elts elt-hash set-elt-hash!)
  59. (do-it graph elts set-elts! pass-elts #t elt-hash set-elt-hash!
  60. (transitive-or-closure! or-update-node-with-kill)))
  61. (define (transitive-and! graph elts set-elts! elt-hash set-elt-hash!)
  62. (do-it graph elts set-elts! #f #f elt-hash set-elt-hash!
  63. (transitive-and-closure! and-update-node)))
  64. (define (transitive-and-with-kill! graph elts set-elts! kill-elts elt-hash set-elt-hash!)
  65. (do-it graph elts set-elts! kill-elts #f elt-hash set-elt-hash!
  66. (transitive-and-closure! and-update-node-with-kill)))
  67. (define (transitive-and-with-pass! graph elts set-elts! pass-elts elt-hash set-elt-hash!)
  68. (do-it graph elts set-elts! pass-elts #t elt-hash set-elt-hash!
  69. (transitive-and-closure! and-update-node-with-kill)))
  70. (define (do-it graph elts set-elts! kill-elts pass? elt-hash set-elt-hash! op)
  71. (let* ((nodes (graph-nodes graph))
  72. (elt-unhash-vec (add-elements! nodes elts kill-elts pass?
  73. elt-hash set-elt-hash!)))
  74. (op nodes)
  75. (record-results! nodes elt-unhash-vec set-elts!)
  76. (do ((i 0 (+ i 1)))
  77. ((= i (vector-length elt-unhash-vec)))
  78. (set-elt-hash! (vector-ref elt-unhash-vec i) #f))
  79. (values)))
  80. ;----------------
  81. ; Setting the kids field of the nodes
  82. (define (connect-nodes-using-children! nodes children node-slot)
  83. (for-each
  84. (lambda (node)
  85. (set-node-kids! node
  86. (map (lambda (kid)
  87. (let ((t (node-slot kid)))
  88. (if (not (node? t))
  89. (missing-node-error kid "child" node))
  90. (set-node-parents! t
  91. (cons node
  92. (node-parents t)))
  93. t))
  94. (children (node-data node)))))
  95. nodes))
  96. (define (connect-nodes-using-parents! nodes parents node-slot)
  97. (for-each
  98. (lambda (node)
  99. (set-node-parents! node
  100. (map (lambda (parent)
  101. (let ((t (node-slot parent)))
  102. (if (not (node? t))
  103. (missing-node-error t "parent" node))
  104. (set-node-kids! t
  105. (cons node
  106. (node-kids t)))
  107. t))
  108. (parents (node-data node)))))
  109. nodes))
  110. (define (missing-node-error node relationship relation)
  111. (error (format #f "Transitive - ~S, ~A of ~S, not in list of nodes"
  112. node relationship (node-data relation))))
  113. ;----------------
  114. (define (add-elements! nodes node-elements node-kills pass?
  115. element-temp set-element-temp!)
  116. (let ((unhash-vec (element-hasher nodes node-elements element-temp set-element-temp!))
  117. (element-hash (make-element-hash element-temp)))
  118. (for-each (lambda (node)
  119. (set-node-elt-set! node
  120. (make-element-set (node-elements (node-data node))
  121. element-hash)))
  122. nodes)
  123. (if node-kills
  124. (for-each (lambda (node)
  125. (let ((kill-set (make-element-set (node-kills (node-data node))
  126. element-hash)))
  127. (set-node-kill-set! node (if pass?
  128. (integer-set-not kill-set)
  129. kill-set))))
  130. nodes))
  131. unhash-vec))
  132. (define (make-element-set elts elt-hash)
  133. (let loop ((elts elts) (set (make-empty-integer-set)))
  134. (if (null? elts)
  135. set
  136. (loop (cdr elts)
  137. (cond ((elt-hash (car elts))
  138. => (lambda (hash)
  139. (add-to-integer-set set hash)))
  140. (else set))))))
  141. ;----------------
  142. ; Counting the elements and assigning numbers to them
  143. (define-record-type element-hash
  144. (number ; the element-hash record is just a way of tagging this number
  145. ) ; with a unique predicate
  146. ())
  147. (define (element-hasher nodes elts elt-hash set-elt-hash!)
  148. (let loop ((to-do '()) (ts nodes) (all-elts '()) (count 0))
  149. (cond ((null? to-do)
  150. (if (null? ts)
  151. (real-element-hasher all-elts count)
  152. (loop (elts (node-data (car ts))) (cdr ts) all-elts count)))
  153. ((element-hash? (elt-hash (car to-do)))
  154. (loop (cdr to-do) ts all-elts count))
  155. (else
  156. (set-elt-hash! (car to-do) (element-hash-maker count))
  157. (loop (cdr to-do) ts (cons (car to-do) all-elts) (+ count 1))))))
  158. (define (real-element-hasher elts count)
  159. (let ((unhash-vec (make-vector count)))
  160. (do ((i (- count 1) (- i 1))
  161. (elts elts (cdr elts)))
  162. ((null? elts))
  163. (vector-set! unhash-vec i (car elts)))
  164. unhash-vec))
  165. (define (make-element-hash elt-hash)
  166. (lambda (elt)
  167. (let ((hash (elt-hash elt)))
  168. (if (element-hash? hash)
  169. (element-hash-number hash)
  170. #f))))
  171. ;----------------
  172. ; Turn the element sets into lists of elements and clean up stray pointers
  173. ; at the same time.
  174. (define (record-results! nodes elt-unhash-vec set-elts!)
  175. (for-each (lambda (node)
  176. (set-elts! (node-data node)
  177. (map-over-integer-set
  178. (lambda (i) (vector-ref elt-unhash-vec i))
  179. (node-elt-set node)))
  180. (set-node-elt-set! node #f)
  181. (set-node-kill-set! node #f))
  182. nodes))
  183. ;----------------
  184. ; The OR algorithm - keeps passing elements around until the changes stop.
  185. (define (transitive-or-closure! op)
  186. (lambda (nodes)
  187. (for-each (lambda (node)
  188. (set-node-changed?! node #t))
  189. nodes)
  190. (let loop ((to-do nodes))
  191. (if (not (null? to-do))
  192. (let* ((node (car to-do))
  193. (elt-set (node-elt-set node)))
  194. (set-node-changed?! node #f)
  195. (let kids-loop ((ts (node-kids node))
  196. (to-do (cdr to-do)))
  197. (cond ((null? ts)
  198. (loop to-do))
  199. ((and (op (car ts) elt-set)
  200. (not (node-changed? (car ts))))
  201. (set-node-changed?! (car ts) #t)
  202. (kids-loop (cdr ts) (cons (car ts) to-do)))
  203. (else
  204. (kids-loop (cdr ts) to-do)))))))))
  205. ; The weird function INTEGER-SET-SUBTRACT&IOR-WITH-TEST! takes three integer
  206. ; sets, subtracts the second from the first and inclusive OR's the result
  207. ; with the third. It returns the resulting set and a flag which is #T if
  208. ; the result is not the same as the original third set. The inclusive OR
  209. ; may be destructive.
  210. (define (or-update-node-with-kill node elt-set)
  211. (receive (set change?)
  212. (integer-set-subtract&ior-with-test! elt-set
  213. (node-kill-set node)
  214. (node-elt-set node))
  215. (set-node-elt-set! node set)
  216. change?))
  217. (define (or-update-node node elt-set)
  218. (receive (set change?)
  219. (integer-set-ior-with-test! elt-set
  220. (node-elt-set node))
  221. (set-node-elt-set! node set)
  222. change?))
  223. ; Implementations using simpler, nondestructive operations (these might be
  224. ; done more efficiently if they had access to the underlying representation
  225. ; of integer sets).
  226. (define (integer-set-subtract&ior-with-test! set1 set2 set3)
  227. (let ((result (integer-set-ior set3 (integer-set-subtract set1 set2))))
  228. (values result (not (integer-set-equal? set3 result)))))
  229. (define (integer-set-ior-with-test! set1 set3)
  230. (let ((result (integer-set-ior set3 set1)))
  231. (values result (not (integer-set-equal? set3 result)))))
  232. ;----------------
  233. ; The AND algorithm - keeps a to-do list of nodes whose parents' elements
  234. ; have changed, instead of a list of nodes whose elements have changed.
  235. (define (transitive-and-closure! op)
  236. (lambda (nodes)
  237. (let loop ((to-do (filter (lambda (node)
  238. (if (not (null? (node-parents node)))
  239. (begin
  240. (set-node-changed?! node #t)
  241. #t)
  242. #f))
  243. nodes)))
  244. (if (not (null? to-do))
  245. (let ((node (car to-do)))
  246. (set-node-changed?! node #f)
  247. (if (op node)
  248. (let kids-loop ((ts (node-kids node))
  249. (to-do (cdr to-do)))
  250. (cond ((null? ts)
  251. (loop to-do))
  252. ((node-changed? (car ts))
  253. (kids-loop (cdr ts) to-do))
  254. (else
  255. (set-node-changed?! (car ts) #t)
  256. (kids-loop (cdr ts) (cons (car ts) to-do)))))
  257. (loop (cdr to-do))))))))
  258. ; These are the same as for OR except that we AND together the parents'
  259. ; elt-sets instead of using the one provided.
  260. (define (and-update-node-with-kill node)
  261. (receive (set change?)
  262. (integer-set-subtract&ior-with-test! (parents-elt-set node)
  263. (node-kill-set node)
  264. (node-elt-set node))
  265. (set-node-elt-set! node set)
  266. change?))
  267. (define (and-update-node node)
  268. (receive (set change?)
  269. (integer-set-ior-with-test! (parents-elt-set node)
  270. (node-elt-set node))
  271. (set-node-elt-set! node set)
  272. change?))
  273. (define (parents-elt-set node)
  274. (do ((parents (cdr (node-parents node))
  275. (cdr parents))
  276. (elts (node-elt-set (car (node-parents node)))
  277. (integer-set-and elts (node-elt-set (car parents)))))
  278. ((null? parents)
  279. elts)))
  280. ;------------------------------------------------------------
  281. ; Testing
  282. ; GRAPH is ((<symbol> name
  283. ; (element*) elements
  284. ; (element*) kills
  285. ; . <symbol*>)*) children
  286. ;
  287. '((node1 (elt1 elt2) () node2)
  288. (node2 (elt3) (elt2) node1 node3)
  289. (node3 () () ))
  290. '((a (1) () b)
  291. (b () () ))
  292. '((a (1 2 3 4) (1) b)
  293. (b () (2) c)
  294. (c () (3) d)
  295. (d (5) (4) a))
  296. (define (test-transitive graph down? or? pass?)
  297. (let* ((elts '())
  298. (get-elt (lambda (sym)
  299. (cond ((first (lambda (v)
  300. (eq? sym (vector-ref v 0)))
  301. elts)
  302. => identity)
  303. (else
  304. (let ((new (vector sym #f)))
  305. (set! elts (cons new elts))
  306. new)))))
  307. (vertices (map (lambda (n)
  308. (vector (car n)
  309. (map get-elt (cadr n))
  310. (map get-elt (caddr n))
  311. #f #f))
  312. graph)))
  313. (for-each (lambda (data vertex)
  314. (vector-set! vertex 3 (map (lambda (s)
  315. (first (lambda (v)
  316. (eq? s (vector-ref v 0)))
  317. vertices))
  318. (cdddr data))))
  319. graph
  320. vertices)
  321. (let ((the-graph ((if down?
  322. make-graph-from-successors
  323. make-graph-from-predecessors)
  324. vertices
  325. (lambda (x) (vector-ref x 3))
  326. (lambda (x) (vector-ref x 4))
  327. (lambda (x v) (vector-set! x 4 v)))))
  328. (if (every? (lambda (n) (null? (caddr n))) graph)
  329. ((if or? transitive-or! transitive-and!)
  330. the-graph
  331. (lambda (v) (vector-ref v 1)) ; elts
  332. (lambda (v x) (vector-set! v 1 x)) ; set-elts!
  333. (lambda (e) (vector-ref e 1)) ; elt-hash
  334. (lambda (e x) (vector-set! e 1 x))) ; set-elt-hash!
  335. ((if or?
  336. (if pass?
  337. transitive-or-with-pass!
  338. transitive-or-with-kill!)
  339. (if pass?
  340. transitive-and-with-pass!
  341. transitive-and-with-kill!))
  342. the-graph
  343. (lambda (v) (vector-ref v 1)) ; elts
  344. (lambda (v x) (vector-set! v 1 x)) ; set-elts!
  345. (lambda (v) (vector-ref v 2)) ; kills
  346. (lambda (e) (vector-ref e 1)) ; elt-hash
  347. (lambda (e x) (vector-set! e 1 x))))) ; set-elt-hash!
  348. (map (lambda (v)
  349. (list (vector-ref v 0)
  350. (map (lambda (e) (vector-ref e 0))
  351. (vector-ref v 1))))
  352. vertices)))