Skip to content

Put the canonicalizers where a caller will look for them, and settle the -ize spelling (#746) - #940

Merged
Rafael-SOWNet merged 2 commits into
masterfrom
feat/canonicalise-entry-points
Aug 14, 2026
Merged

Put the canonicalizers where a caller will look for them, and settle the -ize spelling (#746)#940
Rafael-SOWNet merged 2 commits into
masterfrom
feat/canonicalise-entry-points

Conversation

@Rafael-SOWNet

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

Copy link
Copy Markdown
Collaborator

Both canonicalisers existed only as Transformation objects, reachable by someone who already knew the transformation layer existed. This puts them beside Simplify, Expand and Factorize.

Entity Canonicalize()                     // the commutative structure
Entity? CanonicalizeAsRationalFunction()  // rational functions over Q, or null

Wiring them into the pipeline turned out not to be a thing to do

Simplify already runs CanonicalOrder before its rules — that is what lets a binary rule find sin(x)^2 + cos(x)^2 buried in a longer sum. And Canonicalization is InnerSimplification composed with the sort, so it cannot go inside InnerSimplified without containing itself.

What was missing was reach, not application.

The rational one refuses, and says so by answering nothing

null where the expression is not a rational function over ℚ — the library's own way of saying "no answer", and it keeps the boundary in the signature. A form whose whole value is that equal trees mean equal expressions must not hand back a normalisation that merely resembles one.

Cancelling still carries its condition: x/x is 1 provided not x = 0, and is not equal to the canonical form of 1. There is a test saying exactly that.

Nothing is applied by default

Pinned by a test: InnerSimplified still leaves y + x alone, and Simplify still leaves 1/x + 1/y split. Turning either on by default moves every commutative operand order in every printed answer — a release's decision, not a method's.

And the spelling is settled, in the direction the surface already went

The second commit renames five members so that one operation has one spelling:

Was Is Shipped?
Entity.Canonicalise Canonicalize no
Entity.CanonicaliseAsRationalFunction CanonicalizeAsRationalFunction no
Transformation.Canonicalisation Canonicalization no
Transformation.RationalCanonicalisation RationalCanonicalization no
Transformation.Rationalisation Rationalization v2.1.0
RewriteRules.RationaliseDenominator RationalizeDenominator v2.1.0

The rest of the surface is Factorize, Latexize, Stringize, Normalization, Factorization, so the odd ones out were the -ise five.

The last two are in the v2.1.0 tag and so get a BREAKING-CHANGES.md entry. It breaks a build rather than an answer — the compiler names the missing member. The one silent part is the rule set's Name, which comes from nameof, so a caller matching the string "RationaliseDenominator" now sees "RationalizeDenominator".

Prose keeps British spelling. Factorize has always sat beside the word "factorisation" and still does; the convention is about identifiers, not documentation. A private LongDivision.Canonicalise helper predating this work was renamed too, so a grep for the British spelling now returns only prose.

Measured

Suite 7087 passed / 0 failed, 17 of them new, run after the rename. docsamples against a build of the first commit: 84 samples, 0 compile errors, 0 output mismatches, 57 outputs verified. Library, unit tests, benchmark project and the F# wrapper all build under -c Release; the two Windows-only sample projects fail on Linux exactly as they do on master. PublicApi.txt records every addition and rename, and the alphabetical ordering was re-checked because s and z do not sort alike.

🤖 Generated with Claude Code

Rafael-SOWNet and others added 2 commits August 14, 2026 16:40
Both existed only as Transformation objects, reachable by someone who already knew the
transformation layer existed. Entity.Canonicalise() and Entity.CanonicaliseAsRationalFunction() put
them beside Simplify, Expand and Factorize, which is where a caller looks.

Wiring them into the pipeline is a different question and the answer is that there is nothing to
wire. Simplify already runs CanonicalOrder before its rules -- that is what makes a binary rule find
sin(x)^2 + cos(x)^2 buried in a longer sum -- and Canonicalisation *is* InnerSimplification composed
with the sort, so it cannot go inside InnerSimplified without containing itself. What was missing was
reach, not application.

The rational one returns null where the expression is not a rational function over Q, which is the
library's own way of saying "no answer" and keeps the boundary in the signature: a form whose whole
value is that equal trees mean equal expressions must not hand back a normalisation that resembles
one.

Neither is applied by anything, and a test pins that: InnerSimplified still leaves "y + x" alone and
Simplify still leaves "1/x + 1/y" split. Turning either on by default moves every commutative operand
order in every printed answer, and that is a release's decision rather than a method's.

Measured: suite 7087 passed / 0 failed, 17 of them new.

#746

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…746)

The public surface is Factorize, Latexize, Stringize, Normalization, Factorization. Five members
were not, so the same operation had two spellings depending on which one a caller reached for.

  Entity.Canonicalise                 -> Canonicalize
  Entity.CanonicaliseAsRationalFunction -> CanonicalizeAsRationalFunction
  Transformation.Canonicalisation     -> Canonicalization
  Transformation.RationalCanonicalisation -> RationalCanonicalization
  Transformation.Rationalisation      -> Rationalization
  RewriteRules.RationaliseDenominator -> RationalizeDenominator

The first four have not shipped. The last two are in the v2.1.0 tag, so they get a
BREAKING-CHANGES entry: the compiler names the missing member, which makes it a build error rather
than a wrong answer, and the only silent part is the rule set's Name, which comes from nameof.

Prose keeps British spelling. Factorize has always sat beside the word "factorisation" and still
does; the convention is about identifiers, not about the documentation.

Also renamed a private LongDivision.Canonicalise helper that predates this work, so that a grep for
the British spelling now returns only prose.

Measured: suite 7087 passed / 0 failed. Library, unit tests, benchmark project and the F# wrapper
all build under -c Release; the two Windows-only sample projects fail on Linux as they did before.

#746

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@Rafael-SOWNet Rafael-SOWNet changed the title Put the canonicalisers where a caller will look for them (#746) Put the canonicalizers where a caller will look for them, and settle the -ize spelling (#746) Aug 14, 2026
@Rafael-SOWNet
Rafael-SOWNet merged commit 3e3a391 into master Aug 14, 2026
25 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.

1 participant