Skip to content

Move the polynomial kernel out of Functions/Simplification - #868

Open
Rafael-SOWNet wants to merge 7 commits into
masterfrom
refactor/polynomial-kernel-placement
Open

Move the polynomial kernel out of Functions/Simplification#868
Rafael-SOWNet wants to merge 7 commits into
masterfrom
refactor/polynomial-kernel-placement

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Collaborator

Depends on #865 — branched from it, because it touches MultivariatePolynomial too and a rename plus an edit to the same file is a conflict nobody needs. Merge #865 first and this becomes a three-file move.

MultivariatePolynomial, PolynomialGcd and PolynomialFactoring sat under Functions/Simplification because simplification was the first thing that needed them. They are kernel algebra: the solvers, the evaluator and the simplifier all depend on them, and they depend on none of those.

PolynomialGcd makes the point. It is reached from:

from
Functions/Simplification Simplificator, Patterns
Core/Transformations RewriteRules
Functions/Evaluation Evaluation.Continuous.Arithmetics.Classes
Core/Entity Entity.Continuous.Rounding.Classes

Filing it under one of those said something untrue about the other three.

They now live in Functions/Algebra/Polynomials, beside the Functions/Algebra/Groebner added by #865 — which was put there for exactly this reason and would otherwise have entrenched the confusion by sitting next to nothing.

Nothing but the location changes

Namespaces are deliberately left alone. All three were already namespace AngouriMath.Functions rather than matching their folder, which is how this codebase works — so moving the files needs no using edits and no consumer is touched at all. Changing the namespaces too would have turned a zero-risk move into a churn across a dozen files for no gain.

  • PolynomialGcd.cs and PolynomialFactoring.cs are byte-identical to what they were (verified by diffing against HEAD).
  • MultivariatePolynomial.cs gains a remark saying which way the dependencies run, so the next person looking for a home for a polynomial routine has one.
  • git diff -M --stat records 3 renames, 0 insertions, 0 deletions — history follows the files.
  • The .csproj globs sources, so no project file changes. No .editorconfig section was keyed on the old path.

Verification

  • 6102 C# tests pass — the same count as before the move
  • 130 F# wrapper tests pass

A relocation that changed a test count would be a relocation that changed behaviour.

🤖 Generated with Claude Code

Rafael-SOWNet and others added 7 commits August 10, 2026 03:02
Towards #860.

EquationSystem.Solve eliminated one variable at a time by calling SolveEquation, which
applies the closed-form radical formulas. With numeric coefficients those are cheap;
with symbolic ones they are not, and since each elimination turns the next one's
coefficients into nested radicals the size compounds -- the same quartic is 5 nodes with
numeric coefficients and 5661 with symbolic ones. Four coupled variables did not finish
in 300s while four uncoupled ones with 256 solutions took 17ms, so the cost was never
the size of the system.

    4 coupled variables    no answer in 300 s  ->     24 solutions,  23 ms
    5 coupled variables            over  60 s  ->    120 solutions, 129 ms

A Groebner basis eliminates without radicals: the lexicographic basis is triangular and
leaves the last variable a univariate with rational coefficients, which PolynomialSolver
already handles. The basis is computed under degree-reverse-lexicographic, which is the
order that can be computed at all -- lexicographic dies at five variables on dense input
from coefficient swell -- and converted by FGLM.

Bounded, because Buchberger is doubly exponential in the worst case. Two of the four
ceilings exist because measurement put them there rather than theory: coefficient width,
after a system was seen to run away with 53 pairs and 64 terms and 188-digit rationals,
which no count of pairs or terms would have caught; and quotient dimension, checked
before FGLM starts rather than discovered inside it, because a system can have a basis
that computes in milliseconds and a conversion that never finishes.

The path is deliberately narrow: it answers only where every solution is rational. The
first cut verified candidates with a full Simplify, which is unbounded work outside every
budget -- on a degree-nine univariate it spent longer failing to prove a nested radical
satisfied the system than the old solver takes to solve the whole thing, and hung the
suite. With rational coordinates the check is exact arithmetic and immediate. So this
takes the systems that were hanging and leaves the rest exactly as they were, including
the equation-count refusal.

Over-determined systems are solved rather than refused, and an inconsistent one reports
itself as having no solutions instead of throwing. Both are breaking and recorded.
Fewer equations than unknowns still throws: that ideal is not zero-dimensional.

MultivariatePolynomial becomes partial so the operations only this needs live in
Functions/Algebra/Groebner beside their consumer. Moving the rest of the polynomial
kernel out of Functions/Simplification is a separate, mechanical change.

Verified: 6079 C# tests and 130 F# tests pass, with the suite at its usual runtime.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…stem-solver

# Conflicts:
#	BREAKING-CHANGES.md
#	Sources/.editorconfig
… search

The restriction to rational solutions was the right fix for the wrong reason. What hung
the suite was verifying candidates with Simplify, which searches -- it generates
candidate forms and picks between them, so how long it takes to settle a nested radical
is not bounded by anything. Restricting the input was one way to avoid that. Bounding the
check is a better one.

InnerSimplified is a single structural pass, and it is enough:

    sqrt(2)^2 - 2                        zero in  13 ms
    (3^(1/3))^3 - 3                      zero in  13 ms
    ((1+sqrt(5))/2)^2 - (1+sqrt(5))/2-1  zero in   3 ms
    sqrt(3 + 2*sqrt(2)) - 1 - sqrt(2)    zero in   3 ms
    a Cardano cube root of unity         zero in  15 ms

So the rational-only gate is gone and radical solutions are in reach:

    x^2 - 2, y - x       ->  (sqrt(2), sqrt(2)), (-sqrt(2), -sqrt(2))     57 ms
    x^2 - 2, y^2 - 3     ->  4 solutions, all exact                       11 ms
    x^3 - 2, y - x       ->  3 solutions, including complex cube roots    104 ms

It reads as one pass proving what it can rather than as a narrower input class, which is
also what it actually is: InnerSimplified only ever proves zero and never disproves it, so
a candidate it cannot settle is declined and the system falls back. That costs coverage,
never correctness, and no tolerance is involved at any point.

One existing test moves from the fallback into this path and gets faster and exact with
it: the system with a 0.1 coefficient went from 629 ms of numeric answers to 22 ms of
radicals. The degree-nine system stays out, since decimal roots leave nothing to prove an
identity with, and now costs 941 ms rather than 282 -- bounded, and worth the rest.

Verified: 6102 C# tests and 130 F# tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
MultivariatePolynomial, PolynomialGcd and PolynomialFactoring sat under
Functions/Simplification because simplification was the first thing to need them. They
are kernel algebra: the solvers, the evaluator and the simplifier all depend on them and
they depend on none of those. PolynomialGcd is reached from simplification, from
Core/Transformations and from evaluation -- three separate layers -- so filing it under
one of the three said something untrue about the other two.

They now live in Functions/Algebra/Polynomials, beside Functions/Algebra/Groebner, which
was put there for the same reason and would otherwise have entrenched the confusion by
sitting next to nothing.

Nothing but the location changes. Namespaces are left alone: all three were already
`AngouriMath.Functions` rather than matching their folder, which is how this codebase
works, so moving the files needs no `using` edits anywhere and no consumer is touched.
Two of the three are byte-identical to what they were; the third gains a remark saying
which way the dependencies run, so the next person to look for a home for a polynomial
routine has one.

Verified: 6102 C# tests and 130 F# tests pass, the same counts as before the move, and
git records all three as renames rather than as deletions and additions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…stem-solver

# Conflicts:
#	BREAKING-CHANGES.md
…-kernel-placement

# Conflicts:
#	Sources/AngouriMath/Functions/Algebra/Polynomials/MultivariatePolynomial.cs
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