Skip to content

A hundred arms become sixty-two rules: Common is data, the last set (#746) - #1083

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
feat/common-is-data
Aug 26, 2026
Merged

A hundred arms become sixty-two rules: Common is data, the last set (#746)#1083
Rafael-SOWNet merged 1 commit into
masterfrom
feat/common-is-data

Conversation

@Rafael-SOWNet

@Rafael-SOWNet Rafael-SOWNet commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

The last set, and the largest: Patterns.CommonRules has a hundred arms, and the great
majority of them are one shape written out in every orientation its operands can take. A
switch has to write all of them. A commutative pattern says them at once:

x + a*x    x + x*a    a*x + x    x*a + x        →  one rule

The collapsing is proven, not assumed

Every orientation gathered here is one the switch writes out.
MatchedRulesAgreeWithTheSwitchTest runs both forms over 3,487 generated expressions
with an empty firesWhereTheSwitchDoesNot — so a pattern that reached one shape more than
its arms did would fail rather than pass quietly. Where the switch writes only one
orientation, the rule is a node pattern and stays one.

Order is load-bearing here more than in any set so far: a * a → a ^ 2 sits in the middle
of the file and would swallow half of what is above it if it moved up. The rules are in the
arms' order, and the agreement run is what says that is enough.

What the agreement run caught

Ten rules bind their operands as Number rather than as Entity, so c1 * c2 folds to
a literal in the switch where Entity arithmetic builds a node. The run reported all
sixteen affected expressions at once — no hand-written case list would have contained
1 * y + -y.

Measured — and this set is now cheaper than the switch it replaces

master (8c5157b2) this branch
SimplifyEasy 97,048 ns 93,115 ns — −4.1%
SimplifyEasy allocated 128,100 B 128,100 B — identical
ParseEasy 5,782 ns 5,793 ns
SolveEasy 4,794,652 ns 4,843,467 ns

That took two changes underneath it, and neither was foreseen when this branch was written:

The first version of this PR was red on the kernel gate at 3.33x. Diagnosing it turned up
both, and each landed on its own measurement rather than under this one.

Rational(var one, var den) when one == 1 && den != 1 is now IsWholeReciprocal and
DenominatorOf in Patterns.Common.cs, asked by both forms rather than restated.

This is 30 of 30 rule sets running as data. Part of #746 tier 1.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Bjumi5K7fg8yx6UK1mZTQd

…last set

`Patterns.CommonRules` is the largest `switch` in the transformation layer and the one
the exchange was always going to be judged on: a hundred arms, and the great majority of
them one shape written out in every orientation its operands can take. A `switch` has to
write all of them; a commutative pattern says them at once. So `x + a*x`, `x + x*a`,
`a*x + x` and `x*a + x` are four arms and one rule.

None of that collapsing is a guess about what the arms cover. Every orientation gathered
here is one the `switch` writes out, and `MatchedRulesAgreeWithTheSwitchTest` runs both
forms over 3,487 generated expressions with an empty `firesWhereTheSwitchDoesNot` -- so a
pattern that reached one shape more than its arms did would fail rather than pass quietly.
Where the `switch` writes only one orientation, the rule is a node pattern and stays one.

Order is load-bearing here more than in any set so far. `a * a` becoming `a ^ 2` sits in
the middle of the file and would swallow half of what is above it if it moved up; the
rules are in the arms' order and the agreement run is what says that is enough.

Ten rules bind their operands as `Number` rather than as `Entity`, so `c1 * c2` folds to a
literal in the `switch` where `Entity` arithmetic would build a node. The agreement run
found all sixteen affected expressions at once, `1 * y + -y` among them, which is what
running two forms over generated inputs is for and what no hand-written case list would
have done.

`Rational(var one, var den) when one == 1 && den != 1` is now `IsWholeReciprocal` and
`DenominatorOf` in `Patterns.Common.cs`, asked by both forms rather than restated here.

**Measured, and the set is now cheaper than the `switch` it replaces**: `SimplifyEasy`
93,115 ns against master's 97,048 ns, -4.1%, with allocation identical at 128,100 B and
`ParseEasy` and `SolveEasy` unmoved. That took two changes underneath it. Written first,
this set cost **+34.6%** -- 128,995 ns to 173,659 ns -- because sixty-two rules were asked
at every node against a `switch`'s single jump; #1085 indexes a set's rules by the root
type each pattern requires and took `SimplifyEasy` down 36% on master alone. And its
twenty commutative patterns cost 169,708,912 B of `SolveMediumHard` against 165,054,016 B
before #1080, because a commutative pattern could not take the single-match path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bjumi5K7fg8yx6UK1mZTQd
@Rafael-SOWNet
Rafael-SOWNet merged commit fe0cffd into master Aug 26, 2026
31 checks passed
@Rafael-SOWNet
Rafael-SOWNet deleted the feat/common-is-data branch August 26, 2026 20:55
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.

1 participant