Skip to content

feat(program): a sum through a relation is a sum over a join - #607

Merged
FBumann merged 2 commits into
claude/mathspec-relations-proof-rwfu3wfrom
claude/mathspec-relations-proof-rwfu3w-join-sum
Sep 22, 2026
Merged

FBumann merged 2 commits into
claude/mathspec-relations-proof-rwfu3wfrom
claude/mathspec-relations-proof-rwfu3w-join-sum

Conversation

@FBumann

@FBumann FBumann commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Prompt: Would it be clearer if we do a larger refactor along this rename? [...] Do this as a follow up! [...] Stacked PR

Note

The following content was generated by AI.

What this changes

The program has one relation node, Join. at(x, by=R, over=a, into=b) lowers to Join(x, columns). sum(x, by=R, over=a, into=b) lowers to Sum(Join(x, columns), over=<the dims the join drops>), the Sum node that already exists. The YAML surface is unchanged.

Stacked on #605, which it needs for the words. Both carry main at alpha.111; its new Program.names_read branch over the relation nodes takes the one Join.

The break. GroupSum and Lookup are gone. The struct #605 called Join is JoinColumns, since the node takes the name; JoinNode.join is JoinNode.columns. fan_in reports Join as one-to-one and the Sum over it as many-to-one, as before. No alias and no deprecation, per the alpha stream. lpspec follows on its own branch once this is released.

Why it is the same model

The absence page already describes the composition. Out of a Sum, an absent summand is one term fewer and the row stands; out of a bare join, absence spreads. Those are today's sum(by=) and at semantics, so nothing on that page moves. The frame rule composes the same way: the join adds the grouped dims and keeps the joined ones, the sum drops the dims over= named. The dim checker and the typesetter read the resolved AST, not the program, so neither changed beyond the struct's name.

Separability keeps its verdicts: a Sum whose operand is a Join reports the grouping message for the dims it drops, and that Join is not also reported as an undecided coordinate read. tests/test_separability.py passes unchanged.

Coverage that moved
  • test_lowering.py: the lowering cases and test_a_relation_lowers_with_the_join_each_call_names assert Sum(Join(...), over) and Join(...); the fan-in table has the same two rows in the new shape; test_a_divisor_under_a_join_is_still_named descends through Join.
  • tests/fixtures/every_program_node.yaml is unchanged: grouped and looked_up both reach Join, and reduced reaches Sum, so test_every_program_node_is_one_some_file_lowers_to holds with one node fewer.
  • test_golden.CARRIERS names JoinColumns.
Gates

pixi is unavailable here, so the gates ran from a uv venv on Python 3.12, on the head with main merged.

gate result
pytest 1534 passed, 6 skipped
ruff check, ruff format --check clean
mkdocs build --strict clean before the merge, with the unreachable docs.python.org inventory dropped for the run; tests/test_docs.py holds every generated page current after it
prettier --check clean on the two touched pages
tools.schema and the page generators re-run; nothing moved
compile-tex, typos, reuse lint, pyrefly not run, not installed here

Why

After #605 the two nodes carried the same Join and differed only in whether a group-by followed, decided at resolution. That welded the join and the sum into a third kind of reduction. With the join as its own node, the program is the relational algebra the words describe: one join, and the sum you already have over it. lpspec already computes it that way, one join with no aggregate and a drop of dims, both collapsing in the terminal group-by, so its engine loses a branch rather than gaining one.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SWBcNGLjNH2i4AqRsfyxaN

`GroupSum` and `Lookup` are one node, `Join`, and `sum(by=)` lowers to the existing `Sum` over it, its `over` the dims the join drops; `at` lowers to the bare `Join`. The columns a call names move to `JoinColumns`. The YAML surface is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWBcNGLjNH2i4AqRsfyxaN
@FBumann
FBumann added this pull request to stack #608 September 22, 2026 12:02
@read-the-docs-community

read-the-docs-community Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Main's new uses of the relation nodes take the one Join node.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWBcNGLjNH2i4AqRsfyxaN
@FBumann
FBumann removed this pull request from stack #608 September 22, 2026 12:17
@FBumann
FBumann merged commit 53ba4a2 into claude/mathspec-relations-proof-rwfu3w Sep 22, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants