Thirteen rule sets describe the rules they run - #1108
Merged
Conversation
`RewriteRuleSet.Rules` is what the registry reports a set is made of, and it came from `RuleRegistryGenerator` reading the `switch` that defined the set. Twenty-seven of the thirty sets stopped running that `switch` some releases ago -- they run `MatchedRuleSet.ApplyHere` -- and went on describing it. That is #825's open half and what #746 tier 2 names as gating the rest. **Which thirteen, and why those.** CollapseMultipleFractions, the three CommonDenominator sets, DivisionPreparing, ExpandFactorialDivisions, ExpandMultipleAngle, ExpandTrigonometric, Expansion, FactorizeFactorialMultiplications, NormalTrigonometricForm, PhiFunction and PolynomialLongDivision. Not one of them had a single *described* arm -- the generator only has a description where somebody wrote a comment above the arm, and for these nobody had -- so repointing them adds metadata rather than trading it. The sets left alone would trade: `Common` would lose 33 descriptions today and `Power` 22, and porting those is the next change rather than this one. The identities come from the comments the data rules already carry, checked against each rule's own pattern and replacement rather than copied: `a * (1 / b) = a / b`, `(a / b) / (c / d) = (a * d) / (b * c)`, `tan(a) = sin(a) / cos(a)`. Thirty-two rules gain one. Across the registry the number of described rules goes from **95 to 135**. **What changes for a caller**, measured on a build rather than read off the diff and recorded in BREAKING-CHANGES.md: - `Rules[i].Name` goes from the arm's rendered pattern to the rule's name -- `Mulf(var any1, Divf(Integer(1), var any2))` becomes `reciprocal-factor-becomes-a-quotient`. - `Rules.Count` falls for the two factorial sets, 8 to 3, and the registry total 407 to 397. **Not rewrites lost**: the other five arms are the same rewrite spelled once for each side a factorial can sit on, which is one commutative pattern. Every other repointed set is one arm to one rule. - `Rules[i].Description` goes from null to the identity, for all 38. - `Rules[i].Soundness` goes from null to the rule's own tier. **And one growth becomes less certain, correctly.** `ExpandFactorialDivisions[0]` reported `Collects`, which the string-length proxy guessed; the exact answer for a code-built rule nobody declared is `Unknown`, and `Unknown` is right here -- a quotient of factorials collects when the offsets are one apart and expands when they are five. The two `ExpandMultipleAngle` rules went the other way and are now *declared* `Expands`, since the Chebyshev expansion of `sin(n * a)` is a sum of n terms where the pattern is one node, for every n the rule fires on. Three tests changed, and one of them is the one that found the growth question: `GrowthSaysWhichWayTheSetMoves` failed on ExpandMultipleAngle because the proxy's guess was gone, which is what prompted declaring it. `RuleConfluenceTest`, `DerivationPathTest` and `RewriteRecordingTest` all still pass untouched -- they are about `Common` and `Power`, which this does not repoint. Full suite: 8974 passed, 14 skipped, 0 failed. Part of #746 tier 2 and #825.
Rafael-SOWNet
added a commit
that referenced
this pull request
Aug 30, 2026
The second tranche of the repoint. #1108 took the thirteen sets with no described arm at all, where the change could only add metadata. These six are the other free case: **one arm to one rule**, so their existing descriptions carry across unchanged and the rules that had none gain one. CollapseTrigonometricFunctions, InvertNegativeMultipliers, InvertNegativePowers, PerfectSquare, PolynomialGcdCancellation, SetOperator. Nineteen rules; sixteen already carried their identity as a comment and three did not, and those three were read off the rules rather than guessed from their names: - `a-quotient-of-polynomials-is-put-in-lowest-terms` divides both sides by the gcd; - `a-sum-or-difference-that-is-a-perfect-square` is `a +- 2*sqrt(a)*sqrt(b) + b`; - `an-intersection-distributes-over-a-union-on-its-left` is the mirror of the rule above it, whose comment covers both -- the two exist separately because each builds its answer with the operands in the order it found them. Where a comment carried commentary as well as the identity, only the identity is taken: `sin(a) / cos(a) = tan(a)` without the sentence about how the pattern says "of the same argument", which is a remark about the encoding rather than the mathematics. **No count moves.** The registry stays at 397 arms, which is the check that these six really are one for one -- `AddressableRulesTest` did not fire, and it is the assertion that would have. Described rules go from 135 to **147**, measured rather than computed: seven of these nineteen were already described from their arms, so the arithmetic is not simply +19 and the first version of this message had it one out. Rules carrying a tier of their own go from 40 to 59. Nineteen of the thirty sets now describe what they run. Of the eleven left, three are the CanonicalOrder family, which still *runs* its `switch` -- describing it is honest there. The other seven are where repointing still costs something: `Common` would lose 33 descriptions today and `Power` 22, and porting those identities is the next change. Full suite: 8974 passed, 14 skipped, 0 failed. No public API change. Part of #746 tier 2 and #825.
This was referenced Aug 30, 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.
RewriteRuleSet.Rulesis what the registry reports a set is made of, and it came fromRuleRegistryGeneratorreading theswitchthat defined the set. Twenty-seven of the thirty setsstopped running that
switchsome releases ago — they runMatchedRuleSet.ApplyHere— and went ondescribing it. That is #825's open half, and what #746 tier 2 names as gating the rest.
Thirteen of them now describe what they run. #1107 made that possible by giving
AsAddressable()therule's exact growth, its tier, and somewhere for its identity to live.
Which thirteen, and why those
CollapseMultipleFractions, the threeCommonDenominatorsets,DivisionPreparing,ExpandFactorialDivisions,ExpandMultipleAngle,ExpandTrigonometric,Expansion,FactorizeFactorialMultiplications,NormalTrigonometricForm,PhiFunction,PolynomialLongDivision.Not one of them had a single described arm. The generator only has a description where somebody
wrote a comment above the arm, and for these nobody had — so repointing them adds metadata rather
than trading it. The sets left alone would trade:
Commonwould lose 33 descriptions today andPower22. Porting those is the next change, not this one.The identities come from the comments the data rules already carry, checked against each rule's own
pattern and replacement rather than copied —
a * (1 / b) = a / b,(a / b) / (c / d) = (a * d) / (b * c),tan(a) = sin(a) / cos(a). Four of the eightCollapseMultipleFractionsrules had no comment at all and their identities were read off thepatterns. Thirty-two rules gain one, and across the registry the number of described rules goes from
95 to 135.
What changes for a caller
Measured on a build of each version rather than read off the diff, and recorded in
BREAKING-CHANGES.md.Rules[i].NameMulf(var any1, Divf(Integer(1), var any2))reciprocal-factor-becomes-a-quotientRules.Count, two factorial sets83RewriteRules.All.Sum(set => set.Rules.Count)407397Rules[i].Descriptionnull, for all 38 of these armsRules[i].Soundnessnull— an arm declares no tierRules[i].PatternSourceThe two counts that fall are not rewrites lost.
ExpandFactorialDivisionsandFactorizeFactorialMultiplicationsare eight arms each that the data form writes as three: the otherfive are the same rewrite spelled once for each side a factorial can sit on, which is one commutative
pattern. Every other repointed set is one arm to one rule.
One growth becomes less certain, and that is the right answer
ExpandFactorialDivisions[0]reportedCollects. That was the string-length proxy guessing. Theexact answer for a code-built rule nobody declared is
Unknown— andUnknownis right here: aquotient of factorials collects when the offsets are one apart and expands when they are five, so
no single value is true of the rule.
The two
ExpandMultipleAnglerules went the other way. The proxy had guessedExpandsand happenedto be right, so the exact
Unknownwould have lost real information; they are now declaredExpands, since the Chebyshev expansion ofsin(n * a)is a sum of n terms where the pattern is onenode, for every n the rule fires on. That is what
RewriteRuleGrowth.Unknownexists to prompt.The test suite is what found this.
GrowthSaysWhichWayTheSetMovesfailed onExpandMultipleAnglethe moment the proxy's guess was gone, which is how the declaration got written rather than the
assertion got relaxed.
What is untouched
RuleConfluenceTest,DerivationPathTestandRewriteRecordingTestall pass unchanged — they areabout
CommonandPower, which this does not repoint. Three tests changed: the two registry counts,and my own
RuleMetadataTestlist of which sets carry a per-rule tier, which is now named rather thancounted so that repointing a set is a visible change.
Still explicitly not here: deleting the ~27 dead
switchmethods. They are the oracleMatchedRulesAgreeWithTheSwitchTestproves the data form against, so deleting them deletes theevidence the exchange was safe. That is a maintainer decision for #825.
State
Full suite: 8974 passed, 14 skipped, 0 failed. No public API change.
Part of #746 tier 2 and #825.