Skip to content

Thirteen rule sets describe the rules they run - #1108

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
registry-repoint
Aug 30, 2026
Merged

Thirteen rule sets describe the rules they run#1108
Rafael-SOWNet merged 1 commit into
masterfrom
registry-repoint

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Collaborator

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.

Thirteen of them now describe what they run. #1107 made that possible by giving AsAddressable() the
rule's exact growth, its tier, and somewhere for its identity to live.

Which thirteen, and why those

CollapseMultipleFractions, the three CommonDenominator sets, 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: Common would lose 33 descriptions today and
Power 22. 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 eight
CollapseMultipleFractions rules had no comment at all and their identities were read off the
patterns. 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.

Was Is
Rules[i].Name the arm's rendered pattern, Mulf(var any1, Divf(Integer(1), var any2)) the rule's name, reciprocal-factor-becomes-a-quotient
Rules.Count, two factorial sets 8 3
RewriteRules.All.Sum(set => set.Rules.Count) 407 397
Rules[i].Description null, for all 38 of these arms the identity, for all 38
Rules[i].Soundness null — an arm declares no tier the rule's own tier
Rules[i].PatternSource the C# the arm was written in the pattern the matcher holds

The two counts that fall are not rewrites lost. ExpandFactorialDivisions and
FactorizeFactorialMultiplications are eight arms each that the data form writes as three: the other
five 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] reported Collects. That was the string-length proxy guessing. 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, so
no single value is true of the rule.

The two ExpandMultipleAngle rules went the other way. The proxy had guessed Expands and happened
to be right, so the exact Unknown would have lost real information; they 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. That is what RewriteRuleGrowth.Unknown exists to prompt.

The test suite is what found this. GrowthSaysWhichWayTheSetMoves failed on ExpandMultipleAngle
the moment the proxy's guess was gone, which is how the declaration got written rather than the
assertion got relaxed.

What is untouched

RuleConfluenceTest, DerivationPathTest and RewriteRecordingTest all pass unchanged — they are
about Common and Power, which this does not repoint. Three tests changed: the two registry counts,
and my own RuleMetadataTest list of which sets carry a per-rule tier, which is now named rather than
counted so that repointing a set is a visible change.

Still explicitly not here: deleting the ~27 dead switch methods. They are the oracle
MatchedRulesAgreeWithTheSwitchTest proves the data form against, so deleting them deletes the
evidence 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.

`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
Rafael-SOWNet merged commit cd38e18 into master Aug 30, 2026
31 checks passed
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.
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