Repository navigation
A rule's declared growth is checked against the corpus (#825) - #1158
Merged
Merged
Conversation
`RewriteRuleGrowth` is a claim about every expression a rule fires on -- Collects says the replacement is smaller, Rearranges the same size, Expands larger -- and for the thirty-five rules with a pattern on both sides it is counted from the two patterns. For the rest it is declared by hand and nothing checked it. It is worth checking because growth is load-bearing rather than documentation. Saturation.RulesUpTo selects by it, so a rule saying Collects or Rearranges is one equality saturation fires and a rule left at Unknown is one it does not. A declaration wrong in the shrinking direction tells the saturation a rewrite is safe to run when nobody established that. Running the declarations against the generated corpus finds one that is wrong. `a-common-factor-is-collected-out-of-a-whole-sum` said Collects, on the stated grounds that "the whole point of it is to be smaller". Over fourteen hundred expressions it fires forty-two times, never shrinks, and grows by as much as eight nodes: `-x + x + -1/2` becomes `x * (-1 + 1) + -1/2`, seven nodes for seven. Collects wants every firing smaller, Rearranges every one the same size, Expands every one bigger, and the measurements refute all three, so Unknown is the only one of the four that is true and that is what it now says. Deliberately not fixed by making the rule decline where it does not shrink. That changes what the rule does rather than what it says about itself, and the folding that turns `x * (-1 + 1)` into zero would have to be checked first -- `-x + x` may be reaching zero through exactly this step. The corpus can only refute. Firing on fourteen hundred expressions without contradicting a claim is evidence for it and not proof, since the claim is about every expression there is; the test fails on a contradiction and says nothing about a rule it could not make fire. Eighty-four rules reach it, eighteen of them carrying a declaration. The other sixty-six are the measured evidence for declaring more of them, and it distinguishes the ones that can be from the ones that cannot: `a-negative-factor-in-a-denominator-comes-out` is +2 across all eighty-four of its firings, `two-powers-of-one-base-multiply-by-adding-exponents` is -2 across all of its, while `a-term-added-to-itself-doubles` ranges -2 to 0 and is honestly Unknown. Full suite 9552 passed, 0 failed. Part of #825. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
This was referenced Sep 4, 2026
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.
RewriteRuleGrowthis a claim about every expression a rule fires on:Collectssays thereplacement is smaller,
Rearrangesthe same size,Expandslarger. For the 35 rules with apattern on both sides it is counted from the two patterns. For the rest it is declared by hand, and
nothing checked it.
Running those declarations against the generated corpus finds one that is wrong.
The one it caught
a-common-factor-is-collected-out-of-a-whole-sumdeclaredCollects, and the reason was in thecode:
Over fourteen hundred expressions it fires 42 times, never shrinks, and grows by as much as eight
nodes:
Which of the four is true, checked rather than chosen:
Collectswants every firing smaller and adelta of 0 refutes it;
Rearrangeswants every one the same size and +8 refutes it;Expandswantsevery one bigger and 0 refutes it.
Unknownis the only one left, and that is what it now says,with the counterexample recorded next to it.
Why this is not documentation
Saturation.RulesUpToselects by growth. A rule sayingCollectsorRearrangesis one equalitysaturation fires; one left at
Unknownis one it does not. So that rule has been inSafeRulesona claim nobody tested, and a declaration wrong in the shrinking direction tells the saturation a
rewrite is safe to run when nobody established it.
That also means the 262 undeclared rules are not a documentation backlog. Each declaration is a
behavioural change, which is why this PR adds the check and no new declarations.
What is deliberately not done
The rule is not made to collect for real. Declining where it does not shrink would make
Collectstrue, but that changes what the rule does rather than what it says about itself — andx * (-1 + 1)folding to zero looks like how-x + xreaches0, so it would have to beestablished that the step is not load-bearing first. Separate change, separate measurement.
What the corpus can and cannot say
It can only refute. Firing on fourteen hundred expressions without contradicting a claim is
evidence for it, not proof, since the claim is about every expression there is. So the test fails on
a contradiction and says nothing about a rule it could not make fire — and the doc now says the same
to anyone declaring one.
84 rules reach the corpus, 18 of them carrying a declaration, and the test asserts both counts so
that it cannot pass by never running.
The other 66
They are the measured evidence for declaring more, and — the useful part — the measurement separates
the ones that can be declared from the ones that cannot:
+2on all 84 firingsa-negative-factor-in-a-denominator-comes-out-2on all firingstwo-powers-of-one-base-multiply-by-adding-exponents0on all 84 firingsa-thing-times-a-quotient-keeps-the-divisor-outermost-2to0a-term-added-to-itself-doubles— honestlyUnknown0to+4a-sum-chain-is-sorted-and-grouped— honestlyUnknownA declaration still has to be arguable from the code; the corpus is what stops one being a guess,
and what refutes it when it is.
Part of #825.