diff --git a/lib/datalog/demo.sx b/lib/datalog/demo.sx index d4a9a29a..036feae9 100644 --- a/lib/datalog/demo.sx +++ b/lib/datalog/demo.sx @@ -104,6 +104,30 @@ (tag-pair T1 T2) (count N P (cotagged P T1 T2)))))) +;; ── Demo 6: weighted-DAG shortest path ───────────────────────── +;; "What's the cheapest way from X to Y?" Edge weights with `is` +;; arithmetic to sum costs, then `min` aggregation to pick the +;; shortest. Termination requires the graph to be a DAG (cycles +;; would produce infinite distances without a bound; programs +;; built on this should add a depth filter `(<, D, MAX)` if cycles +;; are possible). +;; +;; EDB: +;; (edge FROM TO COST) +;; IDB: +;; (path FROM TO COST) — any path +;; (shortest FROM TO COST) — minimum cost path +(define + dl-demo-shortest-path-rules + (quote + ((path X Y W <- (edge X Y W)) + (path X Z W + <- + (edge X Y W1) + (path Y Z W2) + (is W (+ W1 W2))) + (shortest X Y W <- (path X Y _) (min W C (path X Y C)))))) + ;; ── Loader stub ────────────────────────────────────────────────── ;; Wiring to PostgreSQL would replace these helpers with calls into ;; rose-ash's internal HTTP RPC (fetch_data → /internal/data/...). diff --git a/lib/datalog/scoreboard.json b/lib/datalog/scoreboard.json index 4f2c96eb..fe66e40d 100644 --- a/lib/datalog/scoreboard.json +++ b/lib/datalog/scoreboard.json @@ -1,8 +1,8 @@ { "lang": "datalog", - "total_passed": 173, + "total_passed": 176, "total_failed": 0, - "total": 173, + "total": 176, "suites": [ {"name":"tokenize","passed":26,"failed":0,"total":26}, {"name":"parse","passed":18,"failed":0,"total":18}, @@ -13,7 +13,7 @@ {"name":"negation","passed":10,"failed":0,"total":10}, {"name":"aggregates","passed":16,"failed":0,"total":16}, {"name":"api","passed":11,"failed":0,"total":11}, - {"name":"demo","passed":15,"failed":0,"total":15} + {"name":"demo","passed":18,"failed":0,"total":18} ], - "generated": "2026-05-08T09:30:37+00:00" + "generated": "2026-05-08T09:35:25+00:00" } diff --git a/lib/datalog/scoreboard.md b/lib/datalog/scoreboard.md index 4242dc6f..89e1a1db 100644 --- a/lib/datalog/scoreboard.md +++ b/lib/datalog/scoreboard.md @@ -1,6 +1,6 @@ # datalog scoreboard -**173 / 173 passing** (0 failure(s)). +**176 / 176 passing** (0 failure(s)). | Suite | Passed | Total | Status | |-------|--------|-------|--------| @@ -13,4 +13,4 @@ | negation | 10 | 10 | ok | | aggregates | 16 | 16 | ok | | api | 11 | 11 | ok | -| demo | 15 | 15 | ok | +| demo | 18 | 18 | ok | diff --git a/lib/datalog/tests/demo.sx b/lib/datalog/tests/demo.sx index c594a63d..1559f800 100644 --- a/lib/datalog/tests/demo.sx +++ b/lib/datalog/tests/demo.sx @@ -237,6 +237,31 @@ (quote (tag-pair-count cooking vegetarian N))) (list {:N 2})) + ;; ── Shortest path on a weighted DAG ────────────────── + (dl-demo-test-set! "shortest a→d via DAG" + (dl-query + (dl-demo-make + (quote ((edge a b 5) (edge b c 3) (edge a c 10) (edge c d 2))) + dl-demo-shortest-path-rules) + (quote (shortest a d W))) + (list {:W 10})) + + (dl-demo-test-set! "shortest a→c picks 2-hop" + (dl-query + (dl-demo-make + (quote ((edge a b 5) (edge b c 3) (edge a c 10))) + dl-demo-shortest-path-rules) + (quote (shortest a c W))) + (list {:W 8})) + + (dl-demo-test-set! "shortest unreachable empty" + (dl-query + (dl-demo-make + (quote ((edge a b 5) (edge b c 3))) + dl-demo-shortest-path-rules) + (quote (shortest a d W))) + (list)) + (dl-demo-test-set! "no access without grant" (dl-query (dl-demo-make diff --git a/plans/datalog-on-sx.md b/plans/datalog-on-sx.md index c92f6e78..42978371 100644 --- a/plans/datalog-on-sx.md +++ b/plans/datalog-on-sx.md @@ -280,6 +280,13 @@ large graphs. _Newest first._ +- 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 + tests cover direct/multi-hop choice, multi-hop wins on cheaper + route, and unreachable-empty. Added `dl-summary db` inspection + helper returning `{: count}` (4 eval tests). + - 2026-05-08 — Phase 5e perf: first-arg index per relation. db gains `:facts-index {: {: tuples}}` mirroring the existing `:facts-keys` membership index. `dl-add-fact!` populates