Skip to content

The square-free part is taken where the coefficients are polynomials - #1054

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
feat/square-free-part-is-multivariate
Aug 25, 2026
Merged

Rafael-SOWNet merged 1 commit into
masterfrom
feat/square-free-part-is-multivariate

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

Part of #746 tier 1, item 43. Follows #1053, which did the same for Factor's content.

What was wrong

MathS.Polynomials.SquareFreePart refused every polynomial in more than one variable — not because
the mathematics is univariate, but because the code was written against a representation whose
coefficients are rational numbers.

p / gcd(p, dp/dx) is the square-free part whatever ring the coefficients live in: a repeated factor
appears in the derivative one time fewer than in the polynomial, so dividing by the common part
leaves each distinct factor exactly once. The multivariate representation already has all three
operations — DerivativeIn, the recursive PolynomialGcd that MathS.Polynomials.Gcd is built
from, and exact division.

2.3.0 now
SquareFreePart("(x - y) ^ 2 * (x + y)", "x") null x ^ 2 - y ^ 2
SquareFreePart("(x - y) ^ 3", "x") null x - y
SquareFreePart("(x + a) ^ 2 * (x + b)", "x") null a * b + a * x + b * x + x ^ 2
SquareFreePart("y ^ 2 * x ^ 2 * (x + 1)", "x") null x ^ 2 + x
SquareFreePart("x ^ 2 * y ^ 2", "x") null x
SquareFreePart("y", "x") null null
SquareFreePart("sin(y) * x ^ 2", "x") null null

The two that look wrong and are not

x ^ 2 * y ^ 2 gives x, not x * y ^ 2. The content has always been dropped: the univariate
path takes the primitive part first, so SquareFreePart("4 * x ^ 2", "x") is x rather than
4 * x. y ^ 2 is the content here for exactly the same reason. That is the existing convention
applied to a wider ring, not a new one — and it was checked against the univariate path rather than
assumed. The expectation I wrote first was the wrong one, which is why the test says so explicitly.

y is still refused: it is constant in x, and the univariate path refuses that too.

Scope

The multivariate path is reached only where the rational path declined, so nothing that already
answered can change.

Verification

Tests compare numerically at twenty random points per case rather than as strings, for the reason
recorded on #1053 — Simplify does not prove two arrangements of a product equal, and a string
comparison reports a defect that is not one.

Suite: 8569 passed, 0 failed, 14 skipped.

`MathS.Polynomials.SquareFreePart` refused every polynomial in more than one
variable, for the same reason `Factor` did: it was written against a
representation whose coefficients are rational numbers.

`p / gcd(p, dp/dx)` is the square-free part whatever ring the coefficients live
in -- a repeated factor appears in the derivative one time fewer than in the
polynomial, so dividing by the common part leaves each distinct factor exactly
once. Nothing about that is univariate, and the multivariate representation has
all three operations already: `DerivativeIn`, the recursive `PolynomialGcd` that
`Gcd` is built from, and exact division.

    SquareFreePart("(x - y) ^ 2 * (x + y)", "x")   null  ->  x ^ 2 - y ^ 2
    SquareFreePart("(x - y) ^ 3", "x")             null  ->  x - y
    SquareFreePart("(x + a) ^ 2 * (x + b)", "x")   null  ->  (x + a) * (x + b)
    SquareFreePart("x ^ 2 * y ^ 2", "x")           null  ->  x
    SquareFreePart("y", "x")                       null  ->  null

The last two are worth saying out loud. The content is dropped, as it always
was: `SquareFreePart("4 * x ^ 2", "x")` is `x` and not `4 * x`, because the
univariate path takes the primitive part first -- so `x ^ 2 * y ^ 2` is `x` with
`y ^ 2` as the content, which is the existing convention applied to a wider ring
rather than a new one. That was checked against the univariate path rather than
assumed; the expectation written first was the wrong one.

Reached only where the rational path declined, so nothing that already answered
can change. Tests compare numerically at twenty points per case rather than as
strings, for the reason #1053 records.

Suite 8569/0.

Part of #746 tier 1, item 43.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bjumi5K7fg8yx6UK1mZTQd
@Rafael-SOWNet
Rafael-SOWNet merged commit d99d65a into master Aug 25, 2026
31 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