Files
rose-ash/lib/minikanren/tests/send-more-money.sx
giles 2921aa30b4
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 54s
mk: phase 6 piece D — send-more-money + Sudoku 4x4
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.
2026-05-09 14:06:47 +00:00

98 lines
2.0 KiB
Plaintext

;; lib/minikanren/tests/send-more-money.sx — classic cryptarithmetic
;;
;; S E N D
;; + M O R E
;; ---------
;; M O N E Y
;;
;; Column-by-column encoding with carries c1, c2, c3, and the
;; leftmost column produces a carry which equals M (the result is 5 digits).
;; All 8 letters distinct; S ≠ 0, M ≠ 0.
;; Unique solution: S=9, E=5, N=6, D=7, M=1, O=0, R=8, Y=2.
;;
;; Note: the full search labelling 11 variables from {0..9} is too slow
;; for naive labelling order (10^11 combinations naively, even with
;; bounds-consistency the branching factor dominates). Real CLP(FD)
;; systems use first-fail heuristics. Here we only verify the encoding
;; against the known answer.
(define
digits-0-9
(list
0
1
2
3
4
5
6
7
8
9))
(define
digits-1-9
(list
1
2
3
4
5
6
7
8
9))
(define
smm-col-with-carry
(fn
(x y carry-in z carry-out)
(fresh
(xy xyc ten-cout z-plus-ten-cout)
(fd-plus x y xy)
(fd-plus xy carry-in xyc)
(fd-times 10 carry-out ten-cout)
(fd-plus z ten-cout z-plus-ten-cout)
(fd-eq xyc z-plus-ten-cout))))
(define
send-more-money
(fn
(S E N D M O R Y)
(fresh
(c1 c2 c3)
(mk-conj
(fd-in S digits-1-9)
(fd-in M digits-1-9)
(fd-in E digits-0-9)
(fd-in N digits-0-9)
(fd-in D digits-0-9)
(fd-in O digits-0-9)
(fd-in R digits-0-9)
(fd-in Y digits-0-9)
(fd-in c1 (list 0 1))
(fd-in c2 (list 0 1))
(fd-in c3 (list 0 1))
(fd-distinct (list S E N D M O R Y))
(smm-col-with-carry D E 0 Y c1)
(smm-col-with-carry N R c1 E c2)
(smm-col-with-carry E O c2 N c3)
(smm-col-with-carry S M c3 O M)
(fd-label (list S E N D M O R Y c1 c2 c3))))))
(mk-test
"send-more-money-verify-known-solution"
(run*
q
(send-more-money
9
5
6
7
1
0
8
2))
(list (make-symbol "_.0")))
(mk-tests-run!)