;; lib/prolog/tests/string_agg.sx -- sub_atom/5 + aggregate_all/3 (define pl-sa-test-count 0) (define pl-sa-test-pass 0) (define pl-sa-test-fail 0) (define pl-sa-test-failures (list)) (define pl-sa-test! (fn (name got expected) (begin (set! pl-sa-test-count (+ pl-sa-test-count 1)) (if (= got expected) (set! pl-sa-test-pass (+ pl-sa-test-pass 1)) (begin (set! pl-sa-test-fail (+ pl-sa-test-fail 1)) (append! pl-sa-test-failures (str name "\n expected: " expected "\n got: " got))))))) (define pl-sa-goal (fn (src env) (pl-instantiate (nth (first (pl-parse (str "g :- " src "."))) 2) env))) (define pl-sa-db (pl-mk-db)) (define pl-sa-num-val (fn (env key) (pl-num-val (pl-walk-deep (dict-get env key))))) (define pl-sa-list-to-atoms (fn (t) (let ((w (pl-walk-deep t))) (cond ((and (pl-atom? w) (= (pl-atom-name w) "[]")) (list)) ((and (pl-compound? w) (= (pl-fun w) ".") (= (len (pl-args w)) 2)) (cons (pl-atom-name (first (pl-args w))) (pl-sa-list-to-atoms (nth (pl-args w) 1)))) (true (list)))))) (define pl-sa-prog-src "member(X, [X|_]). member(X, [_|T]) :- member(X, T).") (pl-db-load! pl-sa-db (pl-parse pl-sa-prog-src)) ;; -- sub_atom/5 -- (pl-sa-test! "sub_atom ground: sub_atom(abcde,0,3,2,abc)" (pl-solve-once! pl-sa-db (pl-sa-goal "sub_atom(abcde, 0, 3, 2, abc)" {}) (pl-mk-trail)) true) (pl-sa-test! "sub_atom ground: sub_atom(abcde,2,2,1,cd)" (pl-solve-once! pl-sa-db (pl-sa-goal "sub_atom(abcde, 2, 2, 1, cd)" {}) (pl-mk-trail)) true) (pl-sa-test! "sub_atom ground mismatch fails" (pl-solve-once! pl-sa-db (pl-sa-goal "sub_atom(abcde, 0, 2, 3, cd)" {}) (pl-mk-trail)) false) (pl-sa-test! "sub_atom empty sub at start" (pl-solve-once! pl-sa-db (pl-sa-goal "sub_atom(abcde, 0, 0, 5, '')" {}) (pl-mk-trail)) true) (pl-sa-test! "sub_atom whole string" (pl-solve-once! pl-sa-db (pl-sa-goal "sub_atom(hello, 0, 5, 0, hello)" {}) (pl-mk-trail)) true) (define pl-sa-env-b1 {}) (pl-solve-once! pl-sa-db (pl-sa-goal "sub_atom(abcde, B, 2, A, cd)" pl-sa-env-b1) (pl-mk-trail)) (pl-sa-test! "sub_atom bound SubAtom gives B=2" (pl-sa-num-val pl-sa-env-b1 "B") 2) (pl-sa-test! "sub_atom bound SubAtom gives A=1" (pl-sa-num-val pl-sa-env-b1 "A") 1) (define pl-sa-env-b2 {}) (pl-solve-once! pl-sa-db (pl-sa-goal "sub_atom(hello, B, L, A, ello)" pl-sa-env-b2) (pl-mk-trail)) (pl-sa-test! "sub_atom ello: B=1" (pl-sa-num-val pl-sa-env-b2 "B") 1) (pl-sa-test! "sub_atom ello: L=4" (pl-sa-num-val pl-sa-env-b2 "L") 4) (pl-sa-test! "sub_atom ello: A=0" (pl-sa-num-val pl-sa-env-b2 "A") 0) (pl-sa-test! "sub_atom ab: 6 total solutions" (let ((env {})) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(count, sub_atom(ab, _, _, _, _), N)" env) (pl-mk-trail)) (pl-sa-num-val env "N")) 6) (pl-sa-test! "sub_atom a: 3 total solutions" (let ((env {})) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(count, sub_atom(a, _, _, _, _), N)" env) (pl-mk-trail)) (pl-sa-num-val env "N")) 3) ;; -- aggregate_all/3 -- (pl-sa-test! "aggregate_all count member [a,b,c] = 3" (let ((env {})) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(count, member(_, [a,b,c]), N)" env) (pl-mk-trail)) (pl-sa-num-val env "N")) 3) (pl-sa-test! "aggregate_all count fail = 0" (let ((env {})) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(count, fail, N)" env) (pl-mk-trail)) (pl-sa-num-val env "N")) 0) (pl-sa-test! "aggregate_all count always succeeds" (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(count, fail, _)" {}) (pl-mk-trail)) true) (define pl-sa-env-bag1 {}) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(bag(X), member(X, [a,b,c]), L)" pl-sa-env-bag1) (pl-mk-trail)) (pl-sa-test! "aggregate_all bag [a,b,c]" (pl-sa-list-to-atoms (dict-get pl-sa-env-bag1 "L")) (list "a" "b" "c")) (define pl-sa-env-bag2 {}) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(bag(X), member(X, []), L)" pl-sa-env-bag2) (pl-mk-trail)) (pl-sa-test! "aggregate_all bag empty goal = []" (pl-sa-list-to-atoms (dict-get pl-sa-env-bag2 "L")) (list)) (pl-sa-test! "aggregate_all sum [1,2,3,4] = 10" (let ((env {})) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(sum(X), member(X, [1,2,3,4]), S)" env) (pl-mk-trail)) (pl-sa-num-val env "S")) 10) (pl-sa-test! "aggregate_all max [3,1,4,1,5,9,2,6] = 9" (let ((env {})) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(max(X), member(X, [3,1,4,1,5,9,2,6]), M)" env) (pl-mk-trail)) (pl-sa-num-val env "M")) 9) (pl-sa-test! "aggregate_all max empty fails" (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(max(X), member(X, []), M)" {}) (pl-mk-trail)) false) (pl-sa-test! "aggregate_all min [3,1,4,1,5,9,2,6] = 1" (let ((env {})) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(min(X), member(X, [3,1,4,1,5,9,2,6]), M)" env) (pl-mk-trail)) (pl-sa-num-val env "M")) 1) (pl-sa-test! "aggregate_all min empty fails" (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(min(X), member(X, []), M)" {}) (pl-mk-trail)) false) (define pl-sa-env-set1 {}) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(set(X), member(X, [b,a,c,a,b]), S)" pl-sa-env-set1) (pl-mk-trail)) (pl-sa-test! "aggregate_all set [b,a,c,a,b] = [a,b,c]" (pl-sa-list-to-atoms (dict-get pl-sa-env-set1 "S")) (list "a" "b" "c")) (define pl-sa-env-set2 {}) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(set(X), fail, S)" pl-sa-env-set2) (pl-mk-trail)) (pl-sa-test! "aggregate_all set fail = []" (pl-sa-list-to-atoms (dict-get pl-sa-env-set2 "S")) (list)) (pl-sa-test! "aggregate_all sum empty = 0" (let ((env {})) (pl-solve-once! pl-sa-db (pl-sa-goal "aggregate_all(sum(X), fail, S)" env) (pl-mk-trail)) (pl-sa-num-val env "S")) 0) (define pl-string-agg-tests-run! (fn () {:failed pl-sa-test-fail :passed pl-sa-test-pass :total pl-sa-test-count :failures pl-sa-test-failures}))