datalog: findall aggregate (159/159)
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
(findall L V Goal) — bind L to the distinct V values for which Goal holds, or the empty list when none. One-line addition to dl-do-aggregate that returns the unreduced list. Tests cover EDB, derived relation, and empty cases. Useful for "give me all the X such that ..." queries without scalar reduction.
This commit is contained in:
@@ -19,7 +19,7 @@
|
|||||||
;;
|
;;
|
||||||
;; Empty input: count → 0, sum → 0, min/max → no binding (rule fails).
|
;; Empty input: count → 0, sum → 0, min/max → no binding (rule fails).
|
||||||
|
|
||||||
(define dl-aggregate-rels (list "count" "sum" "min" "max"))
|
(define dl-aggregate-rels (list "count" "sum" "min" "max" "findall"))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
dl-aggregate?
|
dl-aggregate?
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
(cond
|
(cond
|
||||||
((= op "count") (len vals))
|
((= op "count") (len vals))
|
||||||
((= op "sum") (dl-sum-vals vals 0))
|
((= op "sum") (dl-sum-vals vals 0))
|
||||||
|
((= op "findall") vals)
|
||||||
((= op "min")
|
((= op "min")
|
||||||
(cond
|
(cond
|
||||||
((= (len vals) 0) :empty)
|
((= (len vals) 0) :empty)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"lang": "datalog",
|
"lang": "datalog",
|
||||||
"total_passed": 156,
|
"total_passed": 159,
|
||||||
"total_failed": 0,
|
"total_failed": 0,
|
||||||
"total": 156,
|
"total": 159,
|
||||||
"suites": [
|
"suites": [
|
||||||
{"name":"tokenize","passed":26,"failed":0,"total":26},
|
{"name":"tokenize","passed":26,"failed":0,"total":26},
|
||||||
{"name":"parse","passed":18,"failed":0,"total":18},
|
{"name":"parse","passed":18,"failed":0,"total":18},
|
||||||
@@ -11,9 +11,9 @@
|
|||||||
{"name":"builtins","passed":19,"failed":0,"total":19},
|
{"name":"builtins","passed":19,"failed":0,"total":19},
|
||||||
{"name":"semi_naive","passed":8,"failed":0,"total":8},
|
{"name":"semi_naive","passed":8,"failed":0,"total":8},
|
||||||
{"name":"negation","passed":10,"failed":0,"total":10},
|
{"name":"negation","passed":10,"failed":0,"total":10},
|
||||||
{"name":"aggregates","passed":10,"failed":0,"total":10},
|
{"name":"aggregates","passed":13,"failed":0,"total":13},
|
||||||
{"name":"api","passed":9,"failed":0,"total":9},
|
{"name":"api","passed":9,"failed":0,"total":9},
|
||||||
{"name":"demo","passed":10,"failed":0,"total":10}
|
{"name":"demo","passed":10,"failed":0,"total":10}
|
||||||
],
|
],
|
||||||
"generated": "2026-05-08T08:57:57+00:00"
|
"generated": "2026-05-08T09:02:31+00:00"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# datalog scoreboard
|
# datalog scoreboard
|
||||||
|
|
||||||
**156 / 156 passing** (0 failure(s)).
|
**159 / 159 passing** (0 failure(s)).
|
||||||
|
|
||||||
| Suite | Passed | Total | Status |
|
| Suite | Passed | Total | Status |
|
||||||
|-------|--------|-------|--------|
|
|-------|--------|-------|--------|
|
||||||
@@ -11,6 +11,6 @@
|
|||||||
| builtins | 19 | 19 | ok |
|
| builtins | 19 | 19 | ok |
|
||||||
| semi_naive | 8 | 8 | ok |
|
| semi_naive | 8 | 8 | ok |
|
||||||
| negation | 10 | 10 | ok |
|
| negation | 10 | 10 | ok |
|
||||||
| aggregates | 10 | 10 | ok |
|
| aggregates | 13 | 13 | ok |
|
||||||
| api | 9 | 9 | ok |
|
| api | 9 | 9 | ok |
|
||||||
| demo | 10 | 10 | ok |
|
| demo | 10 | 10 | ok |
|
||||||
|
|||||||
@@ -199,6 +199,33 @@
|
|||||||
(list (quote popular) (quote P)))
|
(list (quote popular) (quote P)))
|
||||||
(list {:P (quote p1)}))
|
(list {:P (quote p1)}))
|
||||||
|
|
||||||
|
;; findall: collect distinct values into a list.
|
||||||
|
(dl-at-test-set! "findall over EDB"
|
||||||
|
(dl-query
|
||||||
|
(dl-program
|
||||||
|
"p(a). p(b). p(c).
|
||||||
|
all_p(L) :- findall(L, X, p(X)).")
|
||||||
|
(list (quote all_p) (quote L)))
|
||||||
|
(list {:L (list (quote a) (quote b) (quote c))}))
|
||||||
|
|
||||||
|
(dl-at-test-set! "findall over derived"
|
||||||
|
(dl-query
|
||||||
|
(dl-program
|
||||||
|
"parent(a, b). parent(b, c). parent(c, d).
|
||||||
|
ancestor(X, Y) :- parent(X, Y).
|
||||||
|
ancestor(X, Z) :- parent(X, Y), ancestor(Y, Z).
|
||||||
|
desc(L) :- findall(L, X, ancestor(a, X)).")
|
||||||
|
(list (quote desc) (quote L)))
|
||||||
|
(list {:L (list (quote b) (quote c) (quote d))}))
|
||||||
|
|
||||||
|
(dl-at-test-set! "findall empty"
|
||||||
|
(dl-query
|
||||||
|
(dl-program
|
||||||
|
"p(1).
|
||||||
|
all_q(L) :- findall(L, X, q(X)).")
|
||||||
|
(list (quote all_q) (quote L)))
|
||||||
|
(list {:L (list)}))
|
||||||
|
|
||||||
;; Aggregate vs single distinct.
|
;; Aggregate vs single distinct.
|
||||||
(dl-at-test-set! "distinct counted once"
|
(dl-at-test-set! "distinct counted once"
|
||||||
(dl-query
|
(dl-query
|
||||||
|
|||||||
@@ -186,9 +186,10 @@ large graphs.
|
|||||||
|
|
||||||
### Phase 8 — aggregation (Datalog+)
|
### Phase 8 — aggregation (Datalog+)
|
||||||
- [x] `(count R V Goal)`, `(sum R V Goal)`, `(min R V Goal)`,
|
- [x] `(count R V Goal)`, `(sum R V Goal)`, `(min R V Goal)`,
|
||||||
`(max R V Goal)` — first arg is the result variable, second is the
|
`(max R V Goal)`, `(findall L V Goal)` — first arg is the result
|
||||||
aggregated variable, third is the goal literal. Live in
|
variable, second is the aggregated variable, third is the goal
|
||||||
`lib/datalog/aggregates.sx`.
|
literal. `findall` returns the distinct-value list itself; the
|
||||||
|
others reduce. Live in `lib/datalog/aggregates.sx`.
|
||||||
- [x] `dl-eval-aggregate`: runs `dl-find-bindings` on the goal under the
|
- [x] `dl-eval-aggregate`: runs `dl-find-bindings` on the goal under the
|
||||||
current subst (which provides outer-context bindings), collects
|
current subst (which provides outer-context bindings), collects
|
||||||
distinct values of the aggregated var, applies the aggregate.
|
distinct values of the aggregated var, applies the aggregate.
|
||||||
@@ -269,6 +270,13 @@ large graphs.
|
|||||||
|
|
||||||
_Newest first._
|
_Newest first._
|
||||||
|
|
||||||
|
- 2026-05-08 — Phase 8 extension: `findall L V Goal` aggregate. Bind
|
||||||
|
L to the list of distinct V values for which Goal holds (or the
|
||||||
|
empty list when no matches). Implemented as a one-line case in
|
||||||
|
`dl-do-aggregate`. 3 new tests: EDB, derived relation, empty.
|
||||||
|
Useful for "give me all the X such that …" queries without
|
||||||
|
scalar reduction.
|
||||||
|
|
||||||
- 2026-05-08 — Phase 5d semantic fix: anonymous `_` variables are
|
- 2026-05-08 — Phase 5d semantic fix: anonymous `_` variables are
|
||||||
renamed per occurrence at `dl-add-rule!` and `dl-query` time so
|
renamed per occurrence at `dl-add-rule!` and `dl-query` time so
|
||||||
`(p X _) (p _ Y)` no longer unifies the two `_`s. New helpers
|
`(p X _) (p _ Y)` no longer unifies the two `_`s. New helpers
|
||||||
|
|||||||
Reference in New Issue
Block a user