relations: Phase 3 path explanation + distance + mixed-kind reachability (explain.sx, reach_any) + 24 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 53s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 53s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
86
lib/relations/explain.sx
Normal file
86
lib/relations/explain.sx
Normal file
@@ -0,0 +1,86 @@
|
||||
;; lib/relations/explain.sx — the connecting path: relations' answer to acl's
|
||||
;; proof tree.
|
||||
;;
|
||||
;; A `reach(K,a,b)` derivation is a chain of one-hop `rel` facts a→…→b. The path
|
||||
;; IS that derivation read off as the node sequence. lib/datalog/ records derived
|
||||
;; facts but not provenance, so we re-derive the chain over the saturated edge
|
||||
;; set — but breadth-first, so the path returned is a SHORTEST derivation (fewest
|
||||
;; hops). Every consecutive pair in the result is a real rel(x,y,kind) fact; no
|
||||
;; edges are invented. Cycles are handled by a visited set, so cyclic data
|
||||
;; terminates rather than looping.
|
||||
;;
|
||||
;; (relations-path db a b kind) → (a … b) | nil
|
||||
;; (relations-distance db a b k) → hop count | nil
|
||||
|
||||
(define relations-last (fn (xs) (nth xs (- (len xs) 1))))
|
||||
|
||||
(define
|
||||
relations-filter-unseen
|
||||
(fn (xs seen) (filter (fn (x) (not (relations-member? x seen))) xs)))
|
||||
|
||||
;; Breadth-first over the kind's edge set. `queue` is a list of partial paths
|
||||
;; (each a node list ending at its frontier node); `visited` is every node ever
|
||||
;; enqueued, so each node is expanded once and the first path to reach b is a
|
||||
;; shortest one.
|
||||
(define
|
||||
relations-path-bfs
|
||||
(fn
|
||||
(db b kind queue visited)
|
||||
(if
|
||||
(= (len queue) 0)
|
||||
nil
|
||||
(let
|
||||
((path (first queue)))
|
||||
(let
|
||||
((node (relations-last path)))
|
||||
(if
|
||||
(= node b)
|
||||
path
|
||||
(let
|
||||
((succs (relations-filter-unseen (relations-children-of db node kind) visited)))
|
||||
(relations-path-bfs
|
||||
db
|
||||
b
|
||||
kind
|
||||
(append
|
||||
(rest queue)
|
||||
(map (fn (s) (append path (list s))) succs))
|
||||
(append visited succs)))))))))
|
||||
|
||||
;; The connecting chain a→…→b under kind (shortest), or nil if unreachable.
|
||||
;; a = b returns the trivial one-node path.
|
||||
(define
|
||||
relations-path
|
||||
(fn
|
||||
(db a b kind)
|
||||
(if
|
||||
(= a b)
|
||||
(list a)
|
||||
(relations-path-bfs db b kind (list (list a)) (list a)))))
|
||||
|
||||
;; Hop count of the shortest path (0 for a=b), or nil if unreachable.
|
||||
(define
|
||||
relations-distance
|
||||
(fn
|
||||
(db a b kind)
|
||||
(let
|
||||
((p (relations-path db a b kind)))
|
||||
(if (= p nil) nil (- (len p) 1)))))
|
||||
|
||||
;; --- current-db convenience layer ---
|
||||
|
||||
(define
|
||||
relations/path
|
||||
(fn (a b kind) (relations-path (relations-ensure-db!) a b kind)))
|
||||
|
||||
(define
|
||||
relations/distance
|
||||
(fn (a b kind) (relations-distance (relations-ensure-db!) a b kind)))
|
||||
|
||||
(define
|
||||
relations/descendants-any
|
||||
(fn (node) (relations-descendants-any (relations-ensure-db!) node)))
|
||||
|
||||
(define
|
||||
relations/reachable-any?
|
||||
(fn (a b) (relations-reachable-any? (relations-ensure-db!) a b)))
|
||||
Reference in New Issue
Block a user