/cKanren/eigen.rkt

http://github.com/calvis/cKanren · Racket · 259 lines · 156 code · 56 blank · 47 comment · 6 complexity · b80bf8f6d5e128b696e0d2b9f5c8c7ab MD5 · raw file

  1. #lang racket
  2. (require "src/base.rkt" "tree-unify.rkt"
  3. "attributes.rkt" "neq.rkt" "src/mk-structs.rkt"
  4. "src/framework.rkt" "src/triggers.rkt")
  5. (require "tester.rkt")
  6. ;; a "fresh" for EigenVars
  7. (provide eigen)
  8. ;; an EigenVar is just a special kind of Var
  9. (define-var-type eigenvar "ev"
  10. #:methods gen:unifiable
  11. [(define (compatible? ev v s c e)
  12. (and (var? v) (in-scope? ev v c e)))
  13. (define (gen-unify ev v p s c e)
  14. (unify p (ext-s v ev s) c e))])
  15. ;; a macro for introducing new EigenVars
  16. (define-syntax-rule (eigen (x ...) g ...)
  17. (fresh-aux eigenvar (x ...)
  18. (track-eigen x '()) ...
  19. (conj g ...)
  20. (leave-eigen x) ...))
  21. ;; EigenVar [List-of Var] -> ConstraintTransformer
  22. ;; fails when x is involved in unification of variables not in scope
  23. (define-constraint (track-eigen x [in-scope update-scope])
  24. ;; track any change in scope by responding to #f
  25. #:reaction
  26. [(enter-scope #f)
  27. => (lambda (y) (add-constraint (track-eigen x (cons y in-scope))))]
  28. #:reaction
  29. [(leave-scope #f)
  30. => (lambda (y) (add-constraint (track-eigen x (remq y in-scope))))]
  31. ;; track associations to x
  32. #:reaction
  33. [(any-association-event x)
  34. => (lambda (p)
  35. (conj (add-constraint (track-eigen x in-scope))
  36. (check-associations x p in-scope)))])
  37. ;; [List-of Value] -> [List-of Var]
  38. ;; updates the EigenVar scope list
  39. (define (update-scope x . rest)
  40. (filter*/var? (apply walk x rest)))
  41. ;; EigenVar SubstitutionPrefix [List-of Var] -> ConstraintTransformer
  42. ;; the prefix is a list of either (x . something) or (somevar . x)
  43. (define (check-associations x prefix in-scope)
  44. (transformer
  45. #:package (a [s c e])
  46. (if (andmap (prefix-okay? x s in-scope) prefix) succeed fail)))
  47. (define (prefix-okay? x s in-scope)
  48. (match-lambda
  49. [(cons u v)
  50. (cond
  51. ;; a binding (x . something)
  52. [(and (eq? u x) (not (eq? v x))) #f]
  53. ;; a binding (somevar . x)
  54. [(memq u in-scope)
  55. (define p^
  56. (filter (lambda (p) (memq u (filter*/var? (cdr p)))) s))
  57. (andmap (curryr memq in-scope) p^)]
  58. [else #f])]))
  59. ;; TODO: this should just be #:persistent
  60. (define-constraint (leave-eigen x)
  61. (add-constraint (leave-eigen x)))
  62. ;; when you leave scope, get rid of both constraints
  63. (define-constraint-interaction
  64. [(track-eigen x ls) (leave-eigen x)] => [succeed])
  65. ;; if you try to unify a symbol/number with an EigenVar, fails
  66. (define-constraint-interaction
  67. [(track-eigen x ls) (symbol x)] => [fail])
  68. (define-constraint-interaction
  69. [(track-eigen x ls) (number x)] => [fail])
  70. ;; EigenVar Var ConstraintStore Event -> Boolean
  71. ;; returns #t iff it is okay to unify ev and v based on ev's scope
  72. ;; TODO: should check event
  73. (define (in-scope? ev v c e)
  74. (define eigen-rands
  75. (filter/rator track-eigen c))
  76. (define the-rands
  77. (findf (lambda (rands) (eq? (car rands) ev))
  78. eigen-rands))
  79. (memq v (cadr the-rands)))
  80. ;; Test the eigen variable implementation in miniKanren
  81. (module+ test
  82. ;; there exists q st. forall x, x = q
  83. (test (run* (q) (eigen (x) (== x q))) '())
  84. ;; forall x, there exists y st. x = y
  85. (test (run* (q) (eigen (x) (fresh (y) (== x y)))) '(_.0))
  86. (test (run* (q) (eigen (x) (fresh (y) (== x y) (== q y)))) '())
  87. (test (run* (q) (eigen (x) (fresh (y) (== x y) (== y q)))) '())
  88. (test (run* (q) (eigen (x) (symbol x))) '())
  89. (test (run* (q) (eigen (x) (number x))) '())
  90. (test (run* (q) (eigen (e) (fresh (x) (number x) (== x e)))) '())
  91. (test (run* (q) (eigen (e) (fresh (x) (== x e) (number x)))) '())
  92. (test (run* (q) (eigen (e) (fresh (x) (== x e)))) '(_.0))
  93. (test (run* (q) (eigen (e) (symbol e))) '())
  94. (test (run* (q) (eigen (e1) (== e1 5))) '())
  95. (test (run* (q) (eigen (e1 e2) (== e1 e2))) '())
  96. (test
  97. (run* (q)
  98. (eigen (e1)
  99. (fresh (x y)
  100. (== e1 `(,x . ,y)))))
  101. '())
  102. (test (run* (q) (eigen (x) (== q x))) '())
  103. (test (run* (q) (eigen (x) (fresh (r) (== r x)))) '(_.0))
  104. (test (run* (q) (eigen (a) (fresh (x) (== `(1 2 3 ,x 4) a))))
  105. '())
  106. (test (run* (q) (fresh (x) (eigen (a) (== `(1 2 3 ,x 4) a))))
  107. '())
  108. ;; HARD
  109. (test
  110. (run* (q)
  111. (eigen (x)
  112. (fresh (y)
  113. (== `(,x) y)
  114. (== y q))))
  115. '())
  116. (test (run* (q) (eigen (e) (fresh (y) (== `(,y) q) (== y e)))) '())
  117. (test (run* (q) (eigen (e) (fresh (y) (== y e) (== `(,y) q)))) '())
  118. ;; there exists x st. forall a, `(1 2 3 ,a 4) is x
  119. (test (run* (q) (fresh (x) (eigen (a) (== `(1 2 3 ,a 4) x))))
  120. '())
  121. ;; forall e, there exists a list `(1 2 3 ,e 4)
  122. (test (run* (q) (eigen (e) (fresh (x) (== `(1 2 3 ,e 4) x))))
  123. '(_.0))
  124. (test (run* (q) (eigen (e1) (eigen (e2) (fresh (x y) (== x e1) (== y e2) (== x y)))))
  125. '())
  126. (test
  127. (run* (q) (eigen (e1) (eigen (e2) (fresh (x y) (== x y) (== x e1) (== y e2)))))
  128. '())
  129. (test
  130. (run* (q) (eigen (e1) (eigen (e2) (fresh (x y) (== x e1) (== x y) (== y e2)))))
  131. '())
  132. (test
  133. (run* (q)
  134. (eigen (e e2)
  135. (fresh (x)
  136. (== `(,x . ,x) `(,e . ,e2)))))
  137. '())
  138. (test
  139. (run* (q)
  140. (eigen (e)
  141. (fresh (x)
  142. (== `(,e . ,q) `(,x . ,x)))))
  143. '())
  144. ;; Tests below this point fail.
  145. #;
  146. (test "eigen test 9"
  147. (run 1 (q) (eigen (x) (absento x q)))
  148. '(_.0))
  149. ;; there exists q st. forall x, x != q
  150. (test (run* (q) (eigen (x) (=/= x q))) '())
  151. (test (run* (q) (eigen (e) (=/= 5 e))) '())
  152. (test (run* (q) (eigen (e1 e2) (=/= e1 e2))) '())
  153. (test "eigen-=/=-1"
  154. ;; exists Q . forall E . Q =/= E
  155. ;; false (pick E = Q)
  156. (run 1 (q) (eigen (e) (=/= q e)))
  157. '())
  158. (test "eigen-=/=-2"
  159. ;; forall E . exists X . E =/= X
  160. ;; true (pick X =/= E)
  161. (run 1 (q) (eigen (e) (fresh (x) (=/= e x))))
  162. '(_.0))
  163. (test "eigen-=/=-3a"
  164. ;; forall E1 E2 . E1 =/= E2
  165. ;; false (pick E1 = E2)
  166. (run 1 (q) (eigen (e1 e2) (=/= e1 e2)))
  167. '())
  168. (test "eigen-=/=-3b"
  169. ;; forall E1 . forall E2 . E1 =/= E2
  170. ;; false (pick E2 = E1)
  171. (run 1 (q) (eigen (e1) (eigen (e2) (=/= e1 e2))))
  172. '())
  173. (test "eigen-=/=-4"
  174. ;; forall E1 . E1 =/= E1
  175. ;; false (pick any legal term for E1)
  176. (run 1 (q) (eigen (e1) (=/= e1 e1)))
  177. '())
  178. (test "eigen-=/=-5"
  179. ;; forall E1 . E1 =/= 5
  180. ;; false (pick E1 = 5)
  181. (run 1 (q) (eigen (e1) (=/= e1 5)))
  182. '())
  183. (test "eigen-=/=-list-1"
  184. ;; forall A . exists X . `(1 2 3 ,A 4) =/= X
  185. ;; true (pick X to be any non-list value, for example)
  186. (run 1 (q) (eigen (a) (fresh (x) (=/= `(1 2 3 ,a 4) x))))
  187. '(_.0))
  188. (test "eigen-=/=-list-2"
  189. ;; forall A . exists X . `(1 2 3 ,X 4) =/= A
  190. ;; true (if A is `(1 2 3 ,Y 4), choose X =/= Y)
  191. (run 1 (q) (eigen (a) (fresh (x) (=/= `(1 2 3 ,x 4) a))))
  192. '(_.0))
  193. (test "eigen-=/=-list-3"
  194. ;; exists X . forall A . `(1 2 3 ,A 4) =/= X
  195. ;; true (pick X to be any non-list value, for example)
  196. (run 1 (q) (fresh (x) (eigen (a) (=/= `(1 2 3 ,a 4) x))))
  197. '(_.0))
  198. (test "eigen-=/=-list-4"
  199. ;; exists X . forall A . `(1 2 3 ,X 4) =/= A
  200. ;; false (if X is any legal term, choose A = `(1 2 3 ,X 4))
  201. (run 1 (q) (fresh (x) (eigen (a) (=/= `(1 2 3 ,x 4) a))))
  202. '())
  203. )