Disjunction (OR): Strategy B — materialized union - #3
Closed
oflatt-claude wants to merge 2 commits into
Closed
Conversation
Introduce `(OR (branch) (branch) ...)` in rule queries, where each branch is a parenthesized list of facts (a conjunctive subquery); the rule matches when any branch matches. Only variables bound in every branch may appear in the actions. This commit establishes the surface syntax, semantics, behavioral tests, and a design doc. The current backend is a parse-time rule-splitting prototype that distributes a body into the cartesian product of branch choices; per review it will be replaced by a materialized-union subquery (design doc Strategy B) so the disjunction is executed natively without rule blowup or redundant firing. - src/ast/parse.rs: parse and expand `OR`; handle multi-command `fail` expansion - tests/disjunction.rs: 6 behavioral tests (semantics + rejection cases) - docs/disjunction-design.md: syntax, semantics, and efficient-execution design - CHANGELOG.md: feature entry Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the parse-time rule-splitting prototype with a materialized-union lowering. `OR` is now a real AST fact (`GenericFact::Or`); each disjunction is compiled to an internal relation keyed on the branches' common variables, populated by one auxiliary rule per branch, and the `OR` in the body becomes a single atom over that relation. This avoids rule blowup and redundant firing and reuses seminaive evaluation and the worst-case-optimal join unchanged; the cost is one extra derivation step of latency (run to fixpoint). - egglog-ast: add `GenericFact::Or`; recurse in Display/visit/map/map_symbols - src/ast/parse.rs: parse `(OR (branch)...)` into `Fact::Or` - src/ast/disjunction.rs: lower `OR` to relation + per-branch rules; enforce the common-variable interface rule; look up sorts via `typecheck_facts` - src/typechecking.rs: `OrBranchLocalEscapes` / `EmptyOrBranch` errors - tests/disjunction.rs: strategy-independent behavioral tests (run to fixpoint) - docs/disjunction-design.md, CHANGELOG.md: document the implemented strategy Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Owner
Author
|
Superseded by #5, which implements Strategy B as a query-planner materialization (union bag joined via tree decomposition) instead of an egglog→egglog transformation. The egglog→egglog approach here added internal relations/rules and a fixpoint-iteration of latency, which is too slow. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements
ORdisjunction in rule bodies via a materialized union (Strategy B fromdocs/disjunction-design.md). This is the native, non-rule-splitting implementation.How it works
ORis a real AST fact (GenericFact::Or). Each disjunction is lowered (src/ast/disjunction.rs, before typechecking) to:R_or(V)keyed on the branches' common variablesV = ⋂ᵢ vars(branchᵢ),VintoR_or,ORin the body replaced by a single atomR_or(V).The rest of the rule joins
R_oras an ordinary relation. Sorts forVare looked up on demand viatypecheck_facts, so nocore-relationschanges are needed — it reuses seminaive evaluation and the worst-case-optimal join unchanged.Properties vs. rule-splitting: no rule blowup (
Σbranches, not∏), results deduplicated (a relation is a set). Cost: one extra derivation step of latency, so rules run to a fixpoint.Semantics: only variables common to every branch may cross the
ORboundary (used in the actions or the rest of the body); a branch-local variable used outside is a compile error (OrBranchLocalEscapes). Nested and multipleORs are handled bottom-up.Tests
tests/disjunction.rs: 9/9 (strategy-independent — run to fixpoint, assert on the DB).eggharness: 747/747 (desugar, 32-thread, proof treatments)make nits: cleanRelationship to the other PRs
🤖 Generated with Claude Code