wb.scm 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. (define head car)
  2. (define tail cdr)
  3. (define empty? null?)
  4. (define (nth list n) (if (<= n 0) (car list) (nth (cdr list) (- n 1))))
  5. (define (test-check cc quoted x)
  6. (if (not x)
  7. (begin (print "failure: " (car quoted)) (cc))
  8. (begin (print "success: " (car quoted)))))
  9. (define-for-syntax (assert->test-check-in-expr is-assert-symbol? inject-replacement expr)
  10. (if (not (list? expr)) expr
  11. (if (null? expr) '()
  12. (if (is-assert-symbol? (car expr))
  13. (inject-replacement (map (lambda (e) (assert->test-check-in-expr is-assert-symbol? inject-replacement e)) (cdr expr)))
  14. (map (lambda (e) (assert->test-check-in-expr is-assert-symbol? inject-replacement e)) expr)))))
  15. (define symbol<? (lambda (s1 s2) (string<? (symbol->string s1) (symbol->string s2))))
  16. (define-syntax test-steps!
  17. (ir-macro-transformer (lambda (form inject compare?)
  18. (let ((body
  19. (map (lambda (expr)
  20. (assert->test-check-in-expr
  21. ; so we can replace expression if it starts with the symbol 'assert ...
  22. (lambda (x) (compare? 'assert x))
  23. ; ... by a call to test-check, on the call/cc's return, the quoted form and the test expression itself.
  24. (lambda (x) (cons (inject 'test-check) (cons (inject 'return) (cons `(quote ,x) x))))
  25. expr))
  26. (cdr form))))
  27. ; make a call/cc expression so we can jump out of execution on the first falsified test assertion
  28. `(call/cc (lambda (,(inject 'return)) (begin ,@body)))))))
  29. ; weight-balanced binary trees, a type of self-balancing binary trees.
  30. ; a leaf is represented as 'nil of size 0
  31. ; an inner node is key, left, right, size
  32. (define (wb-empty) '())
  33. ; serves as ('wb-tree #f #f #f 0))
  34. (define (wb-key object) (nth object 1))
  35. (define (wb-l object) (nth object 2))
  36. (define (wb-r object) (nth object 3))
  37. (define (wb-size object) (if (wb-empty? object) 0 (nth object 4)))
  38. (define (wb-singleton k)
  39. (list 'wb-tree k (wb-empty) (wb-empty) 1))
  40. (define (wb-construct k l r)
  41. (list 'wb-tree k l r (+ 1 (wb-size l) (wb-size r))))
  42. (define (wb-empty? tree) (eq? '() tree))
  43. (define (wb-set < list)
  44. (foldr (lambda (x tree) (wb-insert < tree x)) (wb-empty) list))
  45. ; traverse in order
  46. (define (wb->list tree)
  47. (if (wb-empty? tree) '()
  48. (cons (wb-key tree) (append (wb->list (wb-l tree)) (wb->list (wb-r tree))))))
  49. ; for debugging purposes
  50. (define (balanced? tree)
  51. (if (wb-empty? tree) #t
  52. (and (balanced? (wb-l tree))
  53. (balanced? (wb-r tree))
  54. (balancing-method-is-balanced? (wb-l tree) (wb-r tree))
  55. (balancing-method-is-balanced? (wb-r tree) (wb-l tree)))))
  56. ; depends on isBalanced predicate "depending on wb algorithm"
  57. ; invariant: size[n] = size[n.left] + size[n.right] + 1
  58. (define (wb-insert < tree kx)
  59. (if (wb-empty? tree) (wb-singleton kx)
  60. (let ((ky (wb-key tree)))
  61. (if (< kx ky) (balance-r ky (wb-insert < (wb-l tree) kx) (wb-r tree))
  62. (if (< ky kx) (balance-l ky (wb-l tree) (wb-insert < (wb-r tree) kx))
  63. (wb-construct kx (wb-l tree) (wb-r tree)))))))
  64. ; useful for sets to check if contained, or for maps to retrieve value
  65. (define (wb-lookup < tree kx)
  66. (if (wb-empty? tree) #f ; is enough ... (wb-fail 'nil)
  67. (let ((ky (wb-key tree)))
  68. (if (< kx ky) (wb-lookup < (wb-l tree) kx)
  69. (if (< ky kx) (wb-lookup < (wb-r tree) kx)
  70. ky)))))
  71. (define (is-wb-fail? x)
  72. (and (list? x)
  73. (not (null? x))
  74. (eq? (car x) 'wb-fail)))
  75. (define (wb-fail info) (list 'wb-fail info))
  76. (define (wb-fail-info f) (cadr f))
  77. (define (wb-insert-if-not-present < tree kx)
  78. (if (wb-empty? tree) (wb-singleton kx)
  79. (let ((ky (wb-key tree)))
  80. (if (< kx ky)
  81. (let ((new-subtree-or-fail (wb-insert-if-not-present < (wb-l tree) kx)))
  82. (if (is-wb-fail? new-subtree-or-fail) new-subtree-or-fail
  83. (balance-r ky new-subtree-or-fail (wb-r tree))))
  84. (if (< ky kx)
  85. (let ((new-subtree-or-fail (wb-insert-if-not-present < (wb-r tree) kx)))
  86. (if (is-wb-fail? new-subtree-or-fail) new-subtree-or-fail
  87. (balance-l ky (wb-l tree) new-subtree-or-fail)))
  88. (wb-fail ky))))))
  89. (define <-by-fst (lambda (kv1 kv2) (< (car kv1) (car kv2))))
  90. (define (<-by-fst-by <) (lambda (kv1 kv2) (< (car kv1) (car kv2))))
  91. (define (wbmap-insert tree kv)
  92. (wb-insert <-by-fst tree kv))
  93. ; by key only in case of maps:
  94. (define (wbmap-delete tree kx)
  95. (wb-delete <-by-fst tree (list kx)))
  96. (define (wbmap-lookup tree kx)
  97. (wb-lookup <-by-fst tree (list kx)))
  98. (define (wbmap-lookup-by < tree kx)
  99. (wb-lookup (<-by-fst-by <) tree (list kx)))
  100. (define (wbmap-insert-by < tree kv)
  101. (wb-insert (<-by-fst-by <) tree kv))
  102. (define (wbmap-insert-by-if-not-present < tree kv)
  103. (wb-insert-if-not-present (<-by-fst-by <) tree kv))
  104. (define (wb-delete < tree kx)
  105. ; element not present, ignore (or better, return error if desired)
  106. (if (wb-empty? tree) tree
  107. (let ((ky (wb-key tree)))
  108. (if (< kx ky) (balance-l ky (wb-delete < (wb-l tree) kx) (wb-r tree))
  109. (if (< ky kx) (balance-r ky (wb-l tree) (wb-delete < (wb-r tree) kx))
  110. (wb-build-from-deleted (wb-l tree) (wb-r tree)))))))
  111. (define (wb-build-from-deleted l r)
  112. (cond ((wb-empty? l) r)
  113. ((wb-empty? r) l)
  114. (else (let
  115. ((x (wb-pop-minimum r)))
  116. (balance-r (car x) l (cdr x))))))
  117. (define (wb-pop-minimum tree)
  118. (let ((k (wb-key tree))
  119. (l (wb-l tree)))
  120. (if (wb-empty? l) (cons k (wb-r tree))
  121. (let ((x (wb-pop-minimum l)))
  122. (cons (car x) (balance-l k (cdr x) (wb-r tree)))))))
  123. (define (balance-l k l r)
  124. (if (balancing-method-is-balanced? l r)
  125. (wb-construct k l r)
  126. (rotate-l k l r)))
  127. (define (balance-r k l r)
  128. (if (balancing-method-is-balanced? r l)
  129. (wb-construct k l r)
  130. (rotate-r k l r)))
  131. (define (rotate-l k l r)
  132. (if (balancing-method-is-single? (wb-l r) (wb-r r))
  133. (single-l k l r)
  134. (double-l k l r)))
  135. (define (rotate-r k l r)
  136. (if (balancing-method-is-single? (wb-r l) (wb-l l))
  137. (single-r k l r)
  138. (double-r k l r)))
  139. (define (single-l k l r)
  140. (wb-construct (wb-key r) (wb-construct k l (wb-l r)) (wb-r r)))
  141. (define (single-r k l r)
  142. (wb-construct (wb-key l) (wb-l l) (wb-construct k (wb-r l) r)))
  143. (define (double-l k l r)
  144. (let ((rl (wb-l r)))
  145. (wb-construct (wb-key rl) (wb-construct k l (wb-l rl)) (wb-construct (wb-key r) (wb-r rl) (wb-r r)))))
  146. (define (double-r k l r)
  147. (let ((lr (wb-r l)))
  148. (wb-construct (wb-key lr) (wb-construct (wb-key l) (wb-l l) (wb-l lr)) (wb-construct k r (wb-r lr)))))
  149. ; Parameters chosen according to:
  150. ; Hirai and Yamamoto, ``Balancing weight-balanced trees'', JFP 21 (3), 2011
  151. ; Nievergelt & Reingold: (+ 1 (sqrt 2)), (sqrt 2)
  152. (define delta (+ 1 (sqrt 2))) ; 3)
  153. (define gamma (sqrt 2)) ; 2)
  154. (define (balancing-method-is-balanced? a b)
  155. (>= (* delta (+ 1 (wb-size a))) (+ 1 (wb-size b))))
  156. (define (balancing-method-is-single? a b)
  157. (< (+ 1 (wb-size a)) (* gamma (+ 1 (wb-size b)))))
  158. (define (depth tree)
  159. (if (wb-empty? tree) 0 (+ 1 (max (depth (wb-l tree)) (depth (wb-r tree))))))
  160. ; ----------------------
  161. (define unit-test-wb
  162. (test-steps!
  163. (print "weight-balanced tree tests")
  164. (define a #f)
  165. (set! a (wb-empty))
  166. (assert (wb-empty? a))
  167. (set! a (wb-insert < a 1))
  168. (assert (not (wb-empty? a)))
  169. (assert (= (wb-size a) 1))
  170. (set! a (wb-insert < a 1))
  171. (assert (= (wb-size a) 1))
  172. (set! a (wb-insert < a 2))
  173. (assert (= (wb-size a) 2))
  174. (set! a (wb-delete < a 1))
  175. (assert (= (wb-size a) 1))
  176. (assert (= 16 (wb-size (wb-set < (list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)))))))
  177. ; lo and behold: a test suite!
  178. (define (unit-tests-run-all)
  179. unit-test-wb)