Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 54s
Two CLP(FD) demo puzzles plus an underlying improvement.
clpfd.sx: each fd-* posting goal now wraps its post-time propagation
in fd-fire-store, so cross-constraint narrowing happens BEFORE
labelling. Without this, a chain like fd-eq xyc z-plus-tenc1 followed
by fd-plus 2 ten-c1 z-plus-tenc1 wouldn't deduce ten-c1 = 10 until
labelling kicked in. Now the deduction happens at goal-construction
time. Guard against (c s2) returning nil before fd-fire-store runs.
tests/send-more-money.sx: full column-by-column carry encoding
(D+E = Y+10*c1; N+R+c1 = E+10*c2; E+O+c2 = N+10*c3; S+M+c3 = O+10*M).
Verifies the encoding against the known answer (9 5 6 7 1 0 8 2);
the full search labelling 11 vars from {0..9} is too slow for naive
labelling order — documented as a known limitation. Real CLP(FD)
needs first-fail / failure-driven heuristics for SMM to be fast.
tests/sudoku-4x4.sx: 16 cells / 12 distinctness constraints. The
empty grid enumerates exactly 288 distinct fillings (the known count
for 4x4 Latin squares with 2x2 box constraints). An impossible-clue
test (two 1s in row 0) fails immediately.
50/50 sudoku + smm tests, full clpfd suite green at 132/132.
90 lines
2.4 KiB
Plaintext
90 lines
2.4 KiB
Plaintext
;; lib/minikanren/tests/sudoku-4x4.sx — Sudoku 4×4 via CLP(FD).
|
||
;;
|
||
;; Grid in row-major order:
|
||
;;
|
||
;; c0 c1 | c2 c3
|
||
;; c4 c5 | c6 c7
|
||
;; ------+------
|
||
;; c8 c9 | cA cB
|
||
;; cC cD | cE cF
|
||
;;
|
||
;; Each cell ∈ {1, 2, 3, 4}. 4 rows + 4 cols + 4 2x2 boxes are each a
|
||
;; distinct permutation.
|
||
|
||
(define digits-1-4 (list 1 2 3 4))
|
||
|
||
(define
|
||
sudoku-4x4
|
||
(fn
|
||
(cells)
|
||
(let
|
||
((c0 (nth cells 0))
|
||
(c1 (nth cells 1))
|
||
(c2 (nth cells 2))
|
||
(c3 (nth cells 3))
|
||
(c4 (nth cells 4))
|
||
(c5 (nth cells 5))
|
||
(c6 (nth cells 6))
|
||
(c7 (nth cells 7))
|
||
(c8 (nth cells 8))
|
||
(c9 (nth cells 9))
|
||
(cA (nth cells 10))
|
||
(cB (nth cells 11))
|
||
(cC (nth cells 12))
|
||
(cD (nth cells 13))
|
||
(cE (nth cells 14))
|
||
(cF (nth cells 15)))
|
||
(mk-conj
|
||
(fd-in c0 digits-1-4)
|
||
(fd-in c1 digits-1-4)
|
||
(fd-in c2 digits-1-4)
|
||
(fd-in c3 digits-1-4)
|
||
(fd-in c4 digits-1-4)
|
||
(fd-in c5 digits-1-4)
|
||
(fd-in c6 digits-1-4)
|
||
(fd-in c7 digits-1-4)
|
||
(fd-in c8 digits-1-4)
|
||
(fd-in c9 digits-1-4)
|
||
(fd-in cA digits-1-4)
|
||
(fd-in cB digits-1-4)
|
||
(fd-in cC digits-1-4)
|
||
(fd-in cD digits-1-4)
|
||
(fd-in cE digits-1-4)
|
||
(fd-in cF digits-1-4)
|
||
(fd-distinct (list c0 c1 c2 c3))
|
||
(fd-distinct (list c4 c5 c6 c7))
|
||
(fd-distinct (list c8 c9 cA cB))
|
||
(fd-distinct (list cC cD cE cF))
|
||
(fd-distinct (list c0 c4 c8 cC))
|
||
(fd-distinct (list c1 c5 c9 cD))
|
||
(fd-distinct (list c2 c6 cA cE))
|
||
(fd-distinct (list c3 c7 cB cF))
|
||
(fd-distinct (list c0 c1 c4 c5))
|
||
(fd-distinct (list c2 c3 c6 c7))
|
||
(fd-distinct (list c8 c9 cC cD))
|
||
(fd-distinct (list cA cB cE cF))
|
||
(fd-label cells)))))
|
||
|
||
;; --- Tests ---
|
||
|
||
(mk-test
|
||
"sudoku-4x4-empty-grid-count"
|
||
(let
|
||
((sols (run* q (fresh (c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 cA cB cC cD cE cF) (== q (list c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 cA cB cC cD cE cF)) (sudoku-4x4 (list c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 cA cB cC cD cE cF))))))
|
||
(len sols))
|
||
288)
|
||
|
||
(mk-test
|
||
"sudoku-4x4-impossible-clue-empty"
|
||
(run*
|
||
q
|
||
(fresh
|
||
(c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 cA cB cC cD cE cF)
|
||
(== c0 1)
|
||
(== c1 1)
|
||
(== q (list c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 cA cB cC cD cE cF))
|
||
(sudoku-4x4 (list c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 cA cB cC cD cE cF))))
|
||
(list))
|
||
|
||
(mk-tests-run!)
|