Skip to content

A factorisation multiplies back to what it factored (#1092) - #1093

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
fix/factor-keeps-its-content
Aug 27, 2026
Merged

A factorisation multiplies back to what it factored (#1092)#1093
Rafael-SOWNet merged 1 commit into
masterfrom
fix/factor-keeps-its-content

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Collaborator

Closes #1092.

MathS.Polynomials.Factor("4 * x2 - 4 * y2", "x")   // was (x + y) * (x - y)

The 4 is gone, and (answer - input).Simplify() is -3 * x ^ 2 + 3 * y ^ 2. That is a
factorisation which is not equal to what it factored — the one property a factorisation has.

before now
Factor("4 * x2 - 4 * y2", "x") (x + y) * (x - y) 4 * (x + y) * (x - y)
Factor("2 * x2 - 2 * y2", "x") (x + y) * (x - y) 2 * (x + y) * (x - y)
Factor("6 * x4 - 6 * y4", "x") three factors, no 6 6 * (x + y) * (x ^ 2 + y ^ 2) * (x - y)
Factor("3 * x * y + 3 * y", "x") y * 3 * (x + 1) unchanged
Factor("2 * x2 - 2", "x") 2 * (x + 1) * (x - 1) unchanged

Measured on a build of each side.

Where it came from

KroneckerFactorization.Factor documents its result as "each of positive degree in main" — a
constant content is deliberately not among the factors it returns, and the caller has to
reinstate it. MathS.Polynomials.Kronecker assembled them into a product and never did.

Only "multivariate and the content is a pure number" lands in the gap. A content with a
variable in it (3 * x * y + 3 * y → content 3 * y) goes through
FactorAfterTakingOutTheContent, which reinstates it; a univariate polynomial never reaches the
substitution.

The content is recovered by dividing the polynomial by the assembled product — the same
discipline as the rest of this layer. A quotient that is missing or is not a constant means the
product does not account for the polynomial, and then there is no answer to give.

Why nothing caught it

Every candidate here is checked by exact division, which is what makes a refusal the worst this
layer can do. But that check is on the individual factors. Nothing ever compared the
assembled product against the input, so a constant lost during assembly was lost silently.

AFactorisationMultipliesBackToWhatItFactored asserts exactly that property, on value rather
than on spelling — the only way to catch it. It fails 6 of its 11 cases without this change.

Found while wiring the polynomial layer into Entity.Factorize for #1018, where this wrong
answer would have reached a far more used API. That is why this is a separate PR and goes first.

Full suite: 8747 passed, 0 failed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Bjumi5K7fg8yx6UK1mZTQd

`MathS.Polynomials.Factor("4 * x^2 - 4 * y^2", "x")` returned `(x + y) * (x - y)`. The 4
is gone, and the difference from the input is `-3x^2 + 3y^2` -- a factorisation that is
not equal to what it factored, which is the one property a factorisation has.

`KroneckerFactorization.Factor` documents its result as "each of positive degree in main",
so a constant content is deliberately not among the factors it returns and the caller has
to put it back. `Kronecker` assembled them into a product and never did. Only multivariate
polynomials whose content is a *pure number* land in the gap: a content with a variable in
it goes through `FactorAfterTakingOutTheContent`, which reinstates it, and a univariate
polynomial never reaches the substitution at all.

Recovered by dividing the polynomial by the assembled product rather than by tracking the
content separately -- the same discipline as everything else here. A quotient that is
missing or is not a constant means the product does not account for the polynomial, and
then there is no answer to give.

**Why nothing caught it.** Every candidate in this layer is checked by exact division,
which is what makes a refusal the worst it can do -- but that check is on the individual
*factors*. Nothing compared the assembled product against the input, so a constant lost
during assembly was lost silently. The new test asserts exactly that property, on value
rather than on spelling, and fails 6 of its 11 cases without this change.

Found while wiring the polynomial layer into `Entity.Factorize` for #1018, where the wrong
answer would have reached a far more used API.
@Rafael-SOWNet
Rafael-SOWNet force-pushed the fix/factor-keeps-its-content branch from 79324fa to f1fe4c8 Compare August 27, 2026 14:47
@Rafael-SOWNet
Rafael-SOWNet merged commit d33007f into master Aug 27, 2026
31 checks passed
@Rafael-SOWNet
Rafael-SOWNet deleted the fix/factor-keeps-its-content branch August 27, 2026 15:11
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.

MathS.Polynomials.Factor drops a constant content, so the factorisation is not equal to its input

1 participant