Commit Graph

4 Commits

Author SHA1 Message Date
d66ddc614b datalog: aggregates work as top-level query goals (183/183)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 40s
Bug: dl-match-lit (the naive matcher used by dl-find-bindings)
was missing dl-aggregate? dispatch — it was only present in
dl-fbs-aux (semi-naive). Symptom:
  (dl-query db '(count N X (p X)))
silently returned ().

Two fixes:
- Add aggregate branch to dl-match-lit before the positive case.
- dl-query-user-vars now projects only the result var (first arg)
  of an aggregate goal — the aggregated var and inner-goal vars
  are existentials and should not leak into substitutions.

2 new aggregate tests cover count and findall as direct query goals.
2026-05-08 09:45:15 +00:00
b95d8c5a63 datalog: stratifier rejects recursion through aggregation (165/165)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 53s
Bug: dl-check-stratifiable iterated body literals looking only for
explicit :neg literals, missing aggregate cycles. Now also walks
aggregates via dl-aggregate-dep-edge — q(N) :- count(N, X, q(X))
correctly errors out at saturation time.

3 new tests cover:
- recursion-through-aggregation rejected
- negation + aggregation coexist when in different strata
- min over empty derived relation produces no result
2026-05-08 09:13:10 +00:00
55286cc5bc datalog: findall aggregate (159/159)
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.
2026-05-08 09:02:43 +00:00
6d04cf7bf2 datalog: aggregation count/sum/min/max (Phase 8, 134/134)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
New lib/datalog/aggregates.sx: (count R V Goal), (sum R V Goal),
(min R V Goal), (max R V Goal). dl-eval-aggregate runs
dl-find-bindings on the goal under the outer subst, collects
distinct values of V, applies the operator, binds R. Empty input:
count/sum return 0; min/max produce no binding (rule fails).

Group-by emerges naturally from outer-subst substitution into the
goal — `popular(P) :- post(P), count(N, U, liked(U, P)), >=(N, 3).`
counts per-post.

Stratifier extended: dl-aggregate-dep-edge contributes a
negation-like edge so the aggregate's goal relation is fully
derived before the aggregate fires (non-monotonicity respected).
Safety relaxed for aggregates: goal-internal vars are existentials,
only the result var becomes bound.
2026-05-08 08:28:45 +00:00