;; lib/minikanren/tests/graph.sx — directed-graph reachability via patho. (define test-edges (list (list :a :b) (list :b :c) (list :c :d) (list :a :c) (list :d :e))) (define edgeo (fn (from to) (membero (list from to) test-edges))) (define patho (fn (x y path) (conde ((edgeo x y) (== path (list x y))) ((fresh (z mid-path) (edgeo x z) (patho z y mid-path) (conso x mid-path path)))))) ;; --- direct edges --- (mk-test "patho-direct" (run* q (patho :a :b q)) (list (list :a :b))) (mk-test "patho-no-direct-edge" (run* q (patho :e :a q)) (list)) ;; --- indirect --- (mk-test "patho-multi-hop" (let ((paths (run* q (patho :a :d q)))) (and (= (len paths) 2) (and (some (fn (p) (= p (list :a :b :c :d))) paths) (some (fn (p) (= p (list :a :c :d))) paths)))) true) (mk-test "patho-to-leaf" (let ((paths (run* q (patho :a :e q)))) (and (= (len paths) 2) (and (some (fn (p) (= p (list :a :b :c :d :e))) paths) (some (fn (p) (= p (list :a :c :d :e))) paths)))) true) ;; --- enumeration with multiplicity --- ;; Each path contributes one tuple, so reachable nodes can repeat. Here ;; targets are: b (1 path), c (2 paths), d (2 paths), e (2 paths) = 7. (mk-test "patho-enumerate-from-a-with-multiplicity" (let ((targets (run* q (fresh (path) (patho :a q path))))) (and (= (len targets) 7) (and (some (fn (t) (= t :b)) targets) (and (some (fn (t) (= t :c)) targets) (and (some (fn (t) (= t :d)) targets) (some (fn (t) (= t :e)) targets)))))) true) ;; --- unreachable target --- (mk-test "patho-unreachable" (run* q (patho :a :z q)) (list)) (mk-tests-run!)