/predicates-test.rkt

http://github.com/clklein/predicates · Racket · 461 lines · 331 code · 56 blank · 74 comment · 8 complexity · 2b2314c03876e89cc54310d08ebf7083 MD5 · raw file

  1. #lang racket
  2. (require "predicates.rkt"
  3. rackunit)
  4. (define (table env)
  5. (sort (dict-map env cons)
  6. string<=?
  7. #:key (curry format "~s")))
  8. (parameterize ([randomize-rules? #t])
  9. (let ()
  10. (define-predicate
  11. [(plus z (? y) (? y))
  12. "plus-z"]
  13. [(plus (? x) (? y) (? z))
  14. (plus (s (? x)) (? y) (s (? z)))
  15. "plus-s"])
  16. (check-equal? (generate (plus z (s z) (? q)) 1)
  17. '((q (s z))))
  18. (check-equal? (generate (plus (s (s z)) z (? q)) 3)
  19. '((q (s (s z)))))
  20. (check-equal? (generate (plus (s z) z (? q)) 1) #f)
  21. (parameterize ([current-permutations
  22. ; plus-z
  23. (make-permutations '((0 1) ()))])
  24. (check-equal? (table (generate (plus (? x) (? y) (s (s z))) 3))
  25. '((x z) (y (s (s z))))))
  26. (parameterize ([current-permutations
  27. ; plus-s (plus-s plus-z)
  28. (make-permutations '((1 0) (0) (1 0) (0) (0 1) ()))])
  29. (check-equal? (table (generate (plus (? x) (? y) (s (s z))) 3))
  30. '((x (s (s z))) (y z))))
  31. (parameterize ([current-permutations
  32. ; plus-s plus-z
  33. (make-permutations '((1 0) (0) (0 1) ()))])
  34. (check-equal? (table (generate (plus (? x) (? y) (s (s z))) 3))
  35. '((x (s z)) (y (s z)))))
  36. (parameterize ([current-permutations
  37. ; plus-s (plus-s plus-z)
  38. ; but not before trying
  39. ; plus-z,
  40. ; plus-s plus-z, and
  41. ; plus-s (plus-s (plus-s plus-z))
  42. (make-permutations '((0 1) (0) (0 1) (0) (1 0) ()))])
  43. (check-equal? (table (generate (plus (? x) z (s (s z))) 3))
  44. '((x (s (s z)))))))
  45. (let ()
  46. (define-predicate
  47. [(eq (? x) (? x))
  48. "eq"])
  49. (check-equal? (generate (eq (? x) (cons 1 (? x))) +inf.0) #f)
  50. (check-not-false (generate (eq (? x) (? x)) +inf.0)))
  51. (let ()
  52. (define-predicate
  53. [(r2 (? x))
  54. (r3 (? x))
  55. (r1 (? x))
  56. "r1"])
  57. (define-predicate
  58. [(r2 (? x))
  59. "r2"])
  60. (define-predicate
  61. [(r3 (? x))
  62. "r3a"]
  63. [(r3 (? x))
  64. (r3 (? x))
  65. "r3b"])
  66. ; revists a choice that consumes too much of the size bound
  67. (parameterize ([current-permutations
  68. (make-permutations
  69. '(; only r1 rule
  70. (0)
  71. ; premises right to left
  72. (1 0)
  73. ; r3b first
  74. (1 0)
  75. ; only premise
  76. (0)
  77. ; r3a first this time
  78. (0 1)
  79. ; no premises
  80. ()
  81. ; no size remains for r1's other premise
  82. ; backtrack to r3b for r3b's premise
  83. ; only r3b premise
  84. (0)
  85. ; size exhausted again
  86. ; now try r3a
  87. ; no premises
  88. ()
  89. ; only r2 rule
  90. (0)
  91. ; no premises
  92. ()))])
  93. (check-not-false (generate (r1 (? x)) 3)))
  94. ; same choice may succeed with bound interpreted as depth
  95. (parameterize ([current-permutations
  96. (make-permutations
  97. '(; only r1 rule
  98. (0)
  99. ; premises right to left
  100. (1 0)
  101. ; r3b first
  102. (1 0)
  103. ; only premise
  104. (0)
  105. ; r3a first this time
  106. (0 1)
  107. ; no premises
  108. ()
  109. ; only r2 rule
  110. (0)
  111. ; no premises
  112. ()))]
  113. [bound-measure 'depth])
  114. (check-not-false (generate (r1 (? x)) 3)))
  115. (parameterize ([current-permutations
  116. (make-permutations
  117. '(; only r1 rule
  118. (0)
  119. ; premises right to left
  120. (1 0)
  121. ; r3b first
  122. (1 0)
  123. ; only premise
  124. (0)
  125. ; depth exhausted
  126. ; try r3a instead
  127. ; no premises
  128. ()
  129. ; now return to r1's other premise
  130. ; only r2 rule
  131. (0)
  132. ; no premises
  133. ()))]
  134. [bound-measure 'depth])
  135. (check-not-false (generate (r1 (? x)) 2))))
  136. (let ()
  137. (define-predicate
  138. [(r2 (? x))
  139. (r3 (? x))
  140. (r1 (? x))
  141. "r1"])
  142. (define-predicate
  143. [(eq (? x) a)
  144. (r2 (? x))
  145. "r2a"]
  146. [(eq (? x) b)
  147. (r2 (? x))
  148. "r2b"])
  149. (define-predicate
  150. [(r3 b)
  151. "r3"])
  152. (define-predicate
  153. [(eq (? x) (? x))
  154. "eq"])
  155. ; revists a choice that instantiates a variable in an dead-end way
  156. (parameterize ([current-permutations
  157. (make-permutations
  158. '(; only r1 rule
  159. (0)
  160. ; premises left to right
  161. (0 1)
  162. ; r2a first
  163. (0 1)
  164. ; only premise
  165. (0)
  166. ; only eq rule
  167. (0)
  168. ; no premises
  169. ()
  170. ; only r3 rule
  171. (0)
  172. ; fail
  173. ; only r2b premise
  174. (0)
  175. ; only eq rule
  176. (0)
  177. ; no premises
  178. ()
  179. ; only r3 rule
  180. (0)
  181. ; no premises
  182. ()))])
  183. (check-not-false (generate (r1 (? x)) +inf.0)))
  184. ; same example without reconsidering the r2 derivation
  185. (parameterize ([current-permutations
  186. (make-permutations
  187. '(; only r1 rule
  188. (0)
  189. ; premises left to right
  190. (0 1)
  191. ; r2a first
  192. (0 1)
  193. ; only premise
  194. (0)
  195. ; only eq rule
  196. (0)
  197. ; no premises
  198. ()
  199. ; only r3 rule
  200. (0)))]
  201. [revisit-solved-goals? #f])
  202. (check-false (generate (r1 (? x)) +inf.0)))
  203. ; but other rules are still tried when one fails
  204. (parameterize ([current-permutations
  205. (make-permutations
  206. '(; only r1 rule
  207. (0)
  208. ; premises left to right
  209. (0 1)
  210. ; r2a first
  211. (0 1)
  212. ; only premise
  213. (0)
  214. ; only eq rule
  215. (0)
  216. ; does not unify
  217. ; now try r2b
  218. ; only premise
  219. (0)
  220. ; only eq rule
  221. (0)
  222. ; no premises
  223. ()
  224. ; now turn to r1's other premise
  225. ; only r3 rule
  226. (0)
  227. ; no premises
  228. ()))]
  229. [revisit-solved-goals? #f])
  230. (check-not-false (generate (r1 b) +inf.0))))
  231. )
  232. ; unbounded-predicates
  233. (let ()
  234. (define-predicate
  235. [(q (? x))
  236. (p (? x))
  237. "p"])
  238. (define-predicate
  239. [(q a)
  240. "qa"]
  241. [(r)
  242. (q b)
  243. "qb"])
  244. (define-predicate
  245. [(r)
  246. "r"])
  247. (check-false (generate (p a) 1))
  248. (parameterize ([unbounded-predicates (list q)])
  249. (check-not-false (generate (p a) 1)))
  250. (parameterize ([unbounded-predicates (list q)])
  251. (check-false (generate (p b) 1)))
  252. (parameterize ([unbounded-predicates (list q r)])
  253. (check-not-false (generate (p b) 1))))
  254. ; user-goal-solver
  255. (let ()
  256. (define-predicate
  257. [(q a (? x))
  258. (p (? x))
  259. "p"])
  260. (define-predicate
  261. [(q (? x) (? y))
  262. "q"])
  263. (check-false (generate (p (? x)) 1))
  264. (parameterize ([user-goal-solver (λ (p t e) #f)])
  265. (check-false (generate (p (? x)) 1)))
  266. (parameterize ([user-goal-solver
  267. (λ (p t e)
  268. (and (equal? p q)
  269. (match t
  270. [(list 'a (lvar y))
  271. (cstrs (hash-set (cstrs-eqs e) y 'b) (cstrs-dqs e))])))]) ; expose eqs/dqs to user goals?
  272. (check-equal? (generate (p (? x)) 1) '((x b)))))
  273. (let ()
  274. (define-predicate
  275. [(eq (? x) ,'a)
  276. (r ,'(? x))
  277. "r"])
  278. (define-predicate
  279. [(eq (? x) (? x))
  280. "eq"])
  281. (check-equal? (generate (r (? ,'y)) +inf.0)
  282. '((y a))))
  283. (define (solve0 t u e)
  284. (let ([res (unify t u (cstrs e '()))])
  285. (and res
  286. (cstrs-eqs res))))
  287. (define-syntax (test-solve stx)
  288. (syntax-case stx ()
  289. [(_ t u e e)
  290. (quasisyntax/loc stx
  291. (check-equal?
  292. (cond [(solve0 `t `u (make-immutable-hash `e)) => table]
  293. [else #f])
  294. #,(syntax-case #'e’ ()
  295. [#f #'#f]
  296. [_ #`(table (make-immutable-hash `e’))])))]))
  297. (test-solve 1 1 ((x . 3)) ((x . 3)))
  298. (test-solve 1 2 () #f)
  299. (test-solve (cons 1 2) (cons 1 2)
  300. ((x . 3))
  301. ((x . 3)))
  302. (test-solve (cons 1 2) (cons 1 3) () #f)
  303. (test-solve ,(lvar 'x) 3
  304. ((x . 3))
  305. ((x . 3)))
  306. (test-solve ,(lvar 'x) 3
  307. ((x . ,(lvar 'y)) (y . 3))
  308. ((x . 3) (y . 3)))
  309. (test-solve ,(lvar 'x) 4
  310. ((x . 3))
  311. #f)
  312. (test-solve ,(lvar 'x) 3
  313. ((x . ,(lvar 'y)) (y . 4))
  314. #f)
  315. (test-solve ,(lvar 'x)
  316. (cons 1 ,(lvar 'x))
  317. ()
  318. #f)
  319. (test-solve ,(lvar 'y)
  320. (cons 1 ,(lvar 'x))
  321. ((x . ,(lvar 'y)) (y . ,(lvar 'z)))
  322. #f)
  323. (test-solve (cons ,(lvar 'x) ,(lvar 'x))
  324. (cons (cons 1 ,(lvar 'y)) (cons ,(lvar 'y) 1))
  325. ()
  326. ((x . (cons 1 ,(lvar 'y))) (y . 1)))
  327. (test-solve (cons ,(lvar 'x) ,(lvar 'x))
  328. (cons (cons 1 ,(lvar 'y)) (cons ,(lvar 'y) 2))
  329. ()
  330. #f)
  331. (test-solve (cons ,(lvar 'x) (cons ,(lvar 'y) (cons ,(lvar 'z) (cons ,(lvar 'x) ,(lvar 'y)))))
  332. (cons ,(lvar 'y) (cons ,(lvar 'z) (cons 0 (cons 0 0))))
  333. ()
  334. ((x . 0) (y . 0) (z . 0)))
  335. (test-solve (cons ,(lvar 'x) (cons ,(lvar 'y) (cons ,(lvar 'z) ,(lvar 'x))))
  336. (cons ,(lvar 'y) (cons ,(lvar 'z) (cons 0 1)))
  337. ()
  338. #f)
  339. (define (c-table c)
  340. (list
  341. (sort (dict-map (cstrs-eqs c) cons)
  342. string<=?
  343. #:key (curry format "~s"))
  344. (sort (cstrs-dqs c)
  345. string<=?
  346. #:key (curry format "~s"))))
  347. (define-syntax (test-unify stx)
  348. (syntax-case stx ()
  349. [(_ t u c c’)
  350. (quasisyntax/loc stx
  351. (check-equal?
  352. (cond [(unify `t `u (cstrs (make-immutable-hash (car `c)) (cdr `c))) => c-table]
  353. [else #f])
  354. #,(syntax-case #'c’ ()
  355. [#f #'#f]
  356. [_ #`(c-table (cstrs (make-immutable-hash (car `c’)) (cdr `c)))])))]))
  357. (define-syntax (test-disunify stx)
  358. (syntax-case stx ()
  359. [(_ t u c c)
  360. (quasisyntax/loc stx
  361. (check-equal?
  362. (cond [(disunify `t `u (check-and-resimplify (cstrs (make-immutable-hash (car `c)) (cdr `c)))) => c-table]
  363. [else #f])
  364. #,(syntax-case #'c’ ()
  365. [#f #'#f]
  366. [_ #`(c-table (cstrs (make-immutable-hash (car `c)) (cdr `c’)))])))]))
  367. (test-disunify 1 2 (() . ()) (() . ()))
  368. (test-disunify 1 ,(lvar 'x) (() . ()) (() . (((,(lvar 'x))(1)))))
  369. (test-disunify ,(lvar 'x) 1 (((x . 1)) . (() ())) #f)
  370. (test-disunify (cons 1 2) (cons 1 3) (() . ()) (() . ()))
  371. (test-disunify ,(lvar 'x) 4
  372. (((x . ,(lvar 'y)) (y . 3)) . ())
  373. (((x . ,(lvar 'y)) (y . 3)) . ()))
  374. (test-disunify ,(lvar 'x) 3
  375. (((x . ,(lvar 'y)) (y . 3)) . ())
  376. #f)
  377. (test-disunify 1 ,(lvar 'z)
  378. ( ((x . ,(lvar 'y)) (y . (,(lvar 'y) ,(lvar 'z)))) . ( ((,(lvar 'y) ,(lvar 'z)) (2 2)) ) )
  379. ( ((x . ,(lvar 'y)) (y . (,(lvar 'y) ,(lvar 'z)))) . ( ((,(lvar 'z)) (1)) ) ))
  380. (test-disunify 1 ,(lvar 'z)
  381. ( ((x . ,(lvar 'y)) (y . (,(lvar 'x) ,(lvar 'z)))) . ( ((,(lvar 'y) ,(lvar 'y)) (2 1)) ) )
  382. ( ((x . ,(lvar 'y)) (y . (,(lvar 'x) ,(lvar 'z)))) . ( ((,(lvar 'z)) (1)) ) ))
  383. (test-unify 1 ,(lvar 'x)
  384. ( () . (((,(lvar 'x))(1))) )
  385. #f)
  386. (test-unify ,(lvar 'x) 3
  387. (((x . ,(lvar 'y)) (y . 3)) . ())
  388. (((x . 3) (y . 3)) . ()))
  389. (let ()
  390. (define-predicate
  391. [(not-in (? x) ())
  392. "not-in-empty"]
  393. [(not-in (? x) (? l))
  394. (neq (? x) (? y))
  395. (not-in (? x) ((? y) (? l)))
  396. "not-in-list"])
  397. (check-equal?
  398. (generate (not-in a (a (b (c ())))) +inf.0)
  399. #f)
  400. (check-equal?
  401. (generate (not-in d (a (b (c ())))) +inf.0)
  402. '())
  403. (check-equal?
  404. (generate (not-in c (a (b (c ())))) +inf.0)
  405. #f))