diff --git a/lib/datalog/scoreboard.json b/lib/datalog/scoreboard.json index b44085fa..9c238632 100644 --- a/lib/datalog/scoreboard.json +++ b/lib/datalog/scoreboard.json @@ -1,8 +1,8 @@ { "lang": "datalog", - "total_passed": 204, + "total_passed": 205, "total_failed": 0, - "total": 204, + "total": 205, "suites": [ {"name":"tokenize","passed":26,"failed":0,"total":26}, {"name":"parse","passed":18,"failed":0,"total":18}, @@ -13,8 +13,8 @@ {"name":"negation","passed":10,"failed":0,"total":10}, {"name":"aggregates","passed":18,"failed":0,"total":18}, {"name":"api","passed":14,"failed":0,"total":14}, - {"name":"magic","passed":20,"failed":0,"total":20}, + {"name":"magic","passed":21,"failed":0,"total":21}, {"name":"demo","passed":18,"failed":0,"total":18} ], - "generated": "2026-05-08T10:00:29+00:00" + "generated": "2026-05-08T10:02:51+00:00" } diff --git a/lib/datalog/scoreboard.md b/lib/datalog/scoreboard.md index 27c9bab8..3ad41dc4 100644 --- a/lib/datalog/scoreboard.md +++ b/lib/datalog/scoreboard.md @@ -1,6 +1,6 @@ # datalog scoreboard -**204 / 204 passing** (0 failure(s)). +**205 / 205 passing** (0 failure(s)). | Suite | Passed | Total | Status | |-------|--------|-------|--------| @@ -13,5 +13,5 @@ | negation | 10 | 10 | ok | | aggregates | 18 | 18 | ok | | api | 14 | 14 | ok | -| magic | 20 | 20 | ok | +| magic | 21 | 21 | ok | | demo | 18 | 18 | ok | diff --git a/lib/datalog/tests/magic.sx b/lib/datalog/tests/magic.sx index 568409ce..c9e82183 100644 --- a/lib/datalog/tests/magic.sx +++ b/lib/datalog/tests/magic.sx @@ -224,6 +224,29 @@ (= rules-before (len (dl-rules db)))))) true) + ;; Magic-sets benefit: query touches only one cluster of a + ;; multi-component graph. Semi-naive derives the full closure + ;; over both clusters; magic only the seeded one. + (dl-mt-test! "magic skips irrelevant clusters" + (let + ;; Two disjoint chains. Query is rooted in cluster 1. + ((db (dl-program + "parent(a, b). parent(b, c). + parent(x, y). parent(y, z). + ancestor(X, Y) :- parent(X, Y). + ancestor(X, Z) :- parent(X, Y), ancestor(Y, Z)."))) + (do + (dl-saturate! db) + (let + ((semi-count (len (dl-relation db "ancestor"))) + (magic-results + (dl-magic-query + db (list (quote ancestor) (quote a) (quote X))))) + ;; Semi-naive derives 6 (3 in each cluster). Magic + ;; gives 3 query results (a's reachable: b, c). + (and (= semi-count 6) (= (len magic-results) 2))))) + true) + (dl-mt-test! "magic-rewritten finds same answers" (let ((rules