Skip to content

The rational canonical form keeps the points where the expression has no value - #1740

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
the-rational-canonical-form-keeps-the-domain
Oct 4, 2026
Merged

Rafael-SOWNet merged 1 commit into
masterfrom
the-rational-canonical-form-keeps-the-domain

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

Fixes #1618.

CanonicalizeAsRationalFunction gave an expression a value where it has none: dividing by a quotient moves that quotient's denominator into the numerator, and nothing said the denominator had to be nonzero. On master 6bbed69f against this branch:

….CanonicalizeAsRationalFunction() of master this
1/(1/x) x x provided not x = 0
1/(1 + 1/x) x / (x + 1) x / (x + 1) provided not x = 0
(a/b)/(c/d) a * d / (b * c) a * d / (b * c) provided not d = 0
(1/x)^(-1) x x provided not x = 0
(x/y)^(-2) y ^ 2 / x ^ 2 y ^ 2 / x ^ 2 provided not y = 0
x/(y/x) x ^ 2 / y x ^ 2 / y provided not x = 0
0/x 0 0 provided not x = 0
x^2/x^2 1 provided not x ^ 2 = 0 1 provided not x = 0
(x^2 - 1)/(x^2 + 2x + 1) + 1/(x + 1) x / (x + 1) provided not x ^ 2 + 2 * x + 1 = 0 x / (x + 1)

What changes. The form gathers through the step AsSingleFraction takes (#1622), SingleQuotient.OverLeastCommonDenominator, which collects each denominator it turns over, so the two agree on what a single quotient of an expression is and on where it has a value. Those denominators are kept as a condition beside the factors a cancellation removes, and so is the denominator under a numerator that vanishes. The condition is part of a form whose point is that equal trees mean equal functions, so it is written canonically too: the square-free part of what was excluded -- E / gcd(E, dE/dx_1, …, dE/dx_n) -- without the factors the reduced denominator still excludes. So x^2/x^2 and x/x meet, and the last row says nothing the denominator does not already say. A sum widens nothing: it is defined exactly where its terms are, and the common denominator vanishes exactly where one of theirs does.

Tests: RationalCanonicalFormTest -- 1/(1/x) meets x^2/x, x^2/x^2 meets x/x and (a/b)/(c/d) meets a d^2/(b c d); 1/(1/x), 1/(1 + 1/x) and 0/x no longer collide with x, x/(x + 1) and 0; seven expressions evaluated at the point where they have no value, form and expression both NaN; and the denominator's exclusion not repeated. Each of the new rows fails on master.

Measured. The suite passes, 14,760 tests with 13 skipped, on this change over #1622's last head; cut from master after #1622 merged, the canonical-form, single-fraction, transformation and corpus tests pass, 928 of them. Simplify reaches the form inside the interval-membership rule, so the corpus gate is among them. BREAKING-CHANGES.md has the entry, both columns measured on a build, v2.5.0 against this change.

The allocation gate run here failed on EvalPolynomialFresh, 13,672 against 12,536 B/op, with the machine at a load of thirteen and the benchmark at 28 times its baseline time. That benchmark substitutes a decimal into x^3 + 2 x^2 - x + 1 and evaluates it, which this change does not reach, and measured directly -- the same call twenty thousand times after a warm-up -- it allocates 12,536 B/op on this branch, on master 6bbed69f and on 8f3757cd alike. CI's gate is the one to read.

🤖 Generated with Claude Code

https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura

… no value

Dividing by a quotient moves its denominator into the numerator, and the
form gave the result a value where the expression had none: 1/(1/x) was x.
The denominators a quotient turns over are kept as a condition now, with
the factors a cancellation removes and the denominator under a vanishing
numerator, written square-free and without what the reduced denominator
still excludes. The form gathers through the step AsSingleFraction takes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
@Rafael-SOWNet Rafael-SOWNet added this to the 2.6.0 milestone Oct 4, 2026
@Rafael-SOWNet
Rafael-SOWNet merged commit 61bd8e7 into master Oct 4, 2026
34 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.

The rational canonical form of 1/(1/x) is x, which has a value at 0

1 participant