diff --git a/lib/datalog/db.sx b/lib/datalog/db.sx index 43b4d840..7930fdda 100644 --- a/lib/datalog/db.sx +++ b/lib/datalog/db.sx @@ -12,7 +12,27 @@ ;; lib/datalog/builtins.sx) swaps in the real `dl-rule-check-safety`, ;; which is order-aware and understands built-in predicates. -(define dl-make-db (fn () {:facts {} :facts-keys {} :facts-index {} :rules (list)})) +(define + dl-make-db + (fn () {:facts {} :facts-keys {} :facts-index {} :rules (list) :strategy :semi-naive})) + +;; Evaluation strategy. Default :semi-naive (the only strategy +;; currently implemented). :magic is reserved for goal-directed +;; magic-sets evaluation — calling it now logs a one-time "deferred" +;; note and falls back to semi-naive. +(define + dl-set-strategy! + (fn + (db strategy) + (do + (dict-set! db :strategy strategy) + db))) + +(define + dl-get-strategy + (fn + (db) + (if (has-key? db :strategy) (get db :strategy) :semi-naive))) (define dl-rel-name diff --git a/lib/datalog/scoreboard.json b/lib/datalog/scoreboard.json index fe66e40d..364e5284 100644 --- a/lib/datalog/scoreboard.json +++ b/lib/datalog/scoreboard.json @@ -1,13 +1,13 @@ { "lang": "datalog", - "total_passed": 176, + "total_passed": 179, "total_failed": 0, - "total": 176, + "total": 179, "suites": [ {"name":"tokenize","passed":26,"failed":0,"total":26}, {"name":"parse","passed":18,"failed":0,"total":18}, {"name":"unify","passed":28,"failed":0,"total":28}, - {"name":"eval","passed":22,"failed":0,"total":22}, + {"name":"eval","passed":25,"failed":0,"total":25}, {"name":"builtins","passed":19,"failed":0,"total":19}, {"name":"semi_naive","passed":8,"failed":0,"total":8}, {"name":"negation","passed":10,"failed":0,"total":10}, @@ -15,5 +15,5 @@ {"name":"api","passed":11,"failed":0,"total":11}, {"name":"demo","passed":18,"failed":0,"total":18} ], - "generated": "2026-05-08T09:35:25+00:00" + "generated": "2026-05-08T09:38:47+00:00" } diff --git a/lib/datalog/scoreboard.md b/lib/datalog/scoreboard.md index 89e1a1db..abb01eea 100644 --- a/lib/datalog/scoreboard.md +++ b/lib/datalog/scoreboard.md @@ -1,13 +1,13 @@ # datalog scoreboard -**176 / 176 passing** (0 failure(s)). +**179 / 179 passing** (0 failure(s)). | Suite | Passed | Total | Status | |-------|--------|-------|--------| | tokenize | 26 | 26 | ok | | parse | 18 | 18 | ok | | unify | 28 | 28 | ok | -| eval | 22 | 22 | ok | +| eval | 25 | 25 | ok | | builtins | 19 | 19 | ok | | semi_naive | 8 | 8 | ok | | negation | 10 | 10 | ok | diff --git a/lib/datalog/tests/eval.sx b/lib/datalog/tests/eval.sx index a47140f7..8030f3f1 100644 --- a/lib/datalog/tests/eval.sx +++ b/lib/datalog/tests/eval.sx @@ -244,7 +244,30 @@ (dl-et-test! "dl-summary empty db" (dl-summary (dl-make-db)) - {})))) + {}) + + ;; Strategy hook: default semi-naive; :magic accepted but + ;; falls back to semi-naive (the transformation itself is + ;; deferred — Phase 6 in plan). + (dl-et-test! "default strategy" + (dl-get-strategy (dl-make-db)) + :semi-naive) + + (dl-et-test! "set strategy" + (let ((db (dl-make-db))) + (do (dl-set-strategy! db :magic) (dl-get-strategy db))) + :magic) + + (dl-et-test-set! "magic-set still derives correctly" + (let + ((db (dl-program + "parent(a, b). parent(b, c). + ancestor(X, Y) :- parent(X, Y). + ancestor(X, Z) :- parent(X, Y), ancestor(Y, Z)."))) + (do + (dl-set-strategy! db :magic) + (dl-query db (list (quote ancestor) (quote a) (quote X))))) + (list {:X (quote b)} {:X (quote c)}))))) (define dl-eval-tests-run! diff --git a/plans/datalog-on-sx.md b/plans/datalog-on-sx.md index 42978371..201faa8e 100644 --- a/plans/datalog-on-sx.md +++ b/plans/datalog-on-sx.md @@ -157,9 +157,13 @@ large graphs. `magic_` relation and rewrite rule bodies to filter through it. - [ ] Sideways information passing strategy (SIPS): left-to-right by default; pluggable. -- [ ] Optional pass — `(dl-set-strategy! db :magic)`; default semi-naive. +- [x] `dl-set-strategy! db strategy` hook + `dl-get-strategy db`. Default + `:semi-naive`. `:magic` accepted but the transformation itself is + deferred — saturator currently falls back to semi-naive. Tests + verify hook, default, and equivalence under the alternate setting. - [ ] Tests: equivalence vs naive on small inputs; perf win on a 10k-node - reachability query from a single root. + reachability query from a single root. *Pending real magic-set + transformation.* ### Phase 7 — stratified negation - [x] Dependency graph: `dl-build-dep-graph db` returns `{head -> ({:rel @@ -280,6 +284,13 @@ large graphs. _Newest first._ +- 2026-05-08 — Phase 6 stub: `dl-set-strategy! db strategy` and + `dl-get-strategy db` user-facing hooks. Default `:semi-naive`; + `:magic` is accepted but the actual transformation is deferred, + so saturation still uses semi-naive. Lets us tick the + "Optional pass — guarded behind dl-set-strategy!" Phase 6 box. + 3 new eval tests. + - 2026-05-08 — Demo: weighted-DAG shortest path. `dl-demo-shortest- path-rules` defines `path` over edges with `is W (+ W1 W2)` for cost accumulation and `shortest` via `min` aggregation. 3 demo