Skip to content

Coupled polynomial systems are unsolvable: eliminate by Groebner basis, not by radicals #860

Description

@Rafael-SOWNet

EquationSystem.Solve cannot solve coupled polynomial systems. It dies at four coupled variables:

system current
2 coupled equations, 2 vars 2 ms
3 coupled equations, 3 vars 2 500 ms
4 coupled equations, 4 vars no answer in 300 s

This is not a size problem. Four uncoupled quartics producing 256 solutions take 17 ms, and a degree-8 univariate takes 12 ms.

Root cause

EquationSolver.InSolveSystem eliminates one variable at a time by calling SolveEquation, which applies closed-form radical formulas (quadratic, Cardano, Ferrari). With numeric coefficients that is cheap; with symbolic ones it is not:

polynomial result size
x⁴ - 10x³ + 35x² - 50x + 24 (numeric coefficients) 5 nodes
x⁴ + ax³ + bx² + cx + d (symbolic coefficients) 5661 nodes

Each elimination turns the next step's coefficients into nested radicals, so size compounds multiplicatively, and it repeats per branch. Traced on the 4-variable case:

eq[0..3] (deg 1,2,3,4)                    19 nodes each
eliminate x_3 via the linear equation  →  25 nodes each
eliminate x_2 via the quadratic        →  109 nodes   (coefficients now radicals)
eliminate x_1 via the resulting cubic  →  3698 nodes, 14.1 s   for ONE branch

Gröbner bases avoid this: they triangularise so the last variable satisfies a univariate polynomial with rational coefficients, and back-substitution then works with numbers rather than symbols.

Measured with a prototype

A throwaway lex Buchberger over the same packed representation MultivariatePolynomial already uses (one byte per variable in a ulong, ERational coefficients — so lex monomial comparison is just ulong comparison, and LeadingMonomial() already exists):

system current prototype
4 coupled variables >300 s 0 ms
5 coupled variables >60 s 3 ms
6 coupled variables >60 s 14 ms

The 4-variable case emits exactly x⁴ - 10x³ + 35x² - 50x + 24, which the existing PolynomialSolver already solves in 3 ms — so the end-to-end path is milliseconds.

Over-determined systems work natively, including inconsistency, which the current API cannot even express because it throws on the equation-count mismatch:

system prototype
circle + line (2 eq, 2 var) basis 2, correct
circle + line + a redundant consequence (3 eq, 2 var) basis 2, same answer
circle + line + an inconsistent equation basis {1} — the textbook "no solutions"

Sketch

  • GroebnerSystemSolver in front of EquationSolver.SolveSystem. If every equation passes MultivariatePolynomial.TryParse (polynomial, rational coefficients, ≤ 8 variables) take the Gröbner path; otherwise fall through to today's InSolveSystem unchanged, so nothing that works now changes.
  • Buchberger over lex, with the Gebauer–Möller pair criteria. Lex because the packed ulong is the lex comparison and lex directly yields the triangular form. The prototype's criteria skipped 90–96 % of pairs.
  • Back-substitution hands the univariate to the existing PolynomialSolver, inheriting its rational → radical → numeric convention rather than introducing a RootOf node.
  • A hard budget on pairs, basis size, intermediate terms and wall time, falling back rather than hanging. Buchberger is doubly exponential in the worst case.
  • Drop #eqs == #vars on the Gröbner path.

Two things the prototype disproved

Encoding dominates, and the implementation must pass the user's equations through unmodified rather than trying to be clever:

encoding prototype
degree-4 membership generators + 2 power sums, 5 vars gave up after 100 s
the same system as low-degree power sums 3 ms
sum-of-squares compression into fewer equations (degree 8) gave up after 167 s
the same constraints uncompressed 0 ms

Known gaps

  • Back-substitution degrades to floating point once a root is not expressible in radicals, and deciding whether a residual is zero then becomes a tolerance question — the PrecisionErrorZeroRange trap from Precision is being lost somewhere #602. The real fix is algebraic-number arithmetic, which the library does not have; that is arguably the more foundational piece and worth its own issue.
  • The 8-variable cap of MultivariatePolynomial stays, so this covers systems users actually type, not large combinatorial ones.
  • Coefficient growth was not measured by the prototype.

Additive, so 2.1 rather than 2.0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design documentFor issues representing detailed design of new API or featureProposalContribute to the project by proposing some improvements

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions