;; lib/minikanren/tests/tabling.sx — Phase 7 piece A: naive memoization.

;; --- Fibonacci canary: tabled vs naive --

(define
  tab-fib-o
  (table-2
    "fib"
    (fn
      (n result)
      (conde
        ((== n 0) (== result 0))
        ((== n 1) (== result 1))
        ((fresh (n-1 n-2 r-1 r-2) (lto-i 1 n) (minuso-i n 1 n-1) (minuso-i n 2 n-2) (tab-fib-o n-1 r-1) (tab-fib-o n-2 r-2) (pluso-i r-1 r-2 result)))))))

(mk-tab-clear!)

(mk-test "tab-fib-zero" (run* q (tab-fib-o 0 q)) (list 0))
(mk-tab-clear!)
(mk-test "tab-fib-one" (run* q (tab-fib-o 1 q)) (list 1))
(mk-tab-clear!)
(mk-test "tab-fib-two" (run* q (tab-fib-o 2 q)) (list 1))
(mk-tab-clear!)
(mk-test "tab-fib-five" (run* q (tab-fib-o 5 q)) (list 5))
(mk-tab-clear!)
(mk-test "tab-fib-ten" (run* q (tab-fib-o 10 q)) (list 55))
(mk-tab-clear!)
(mk-test
  "tab-fib-twenty"
  (run* q (tab-fib-o 20 q))
  (list 6765))

;; --- ground-term predicate ---

(mk-test "tab-ground-term-num" (mk-tab-ground-term? 5) true)
(mk-test "tab-ground-term-str" (mk-tab-ground-term? "hi") true)
(mk-test
  "tab-ground-term-list"
  (mk-tab-ground-term? (list 1 2 3))
  true)
(mk-test "tab-ground-term-var" (mk-tab-ground-term? (mk-var "x")) false)
(mk-test
  "tab-ground-term-nested"
  (mk-tab-ground-term?
    (list 1 (list 2 (mk-var "y")) 3))
  false)

;; --- caching reduces work — count cache hits via repeated query ---

(mk-test
  "tab-cache-replay"
  (begin
    (mk-tab-clear!)
    (let
      ((first (run* q (tab-fib-o 10 q)))
        (second (run* q (tab-fib-o 10 q))))
      (and (= first (list 55)) (= second (list 55)))))
  true)

(mk-tests-run!)
