Solver API¶
Polynomial system solving via Gröbner bases. The groebner Cargo feature is included in all PyPI wheels by default since 2.3.1 — no special build flag needed.
- alkahest.solve(equations: list[Expr], variables: list[Expr]) list[dict] or GroebnerBasis¶
Solve a system of polynomial equations symbolically.
Uses Lex Gröbner basis computation followed by triangular back-substitution. Quadratic factors are solved exactly with symbolic square roots.
- Parameters:
equations – List of polynomial expressions (each equal to zero).
variables – Variables to solve for. Free symbols that appear in equations but are omitted here are treated as parameters.
- Returns:
list[dict[Expr, Expr]]— one dict per solution, mapping variable → value (symbolic, e.g.sqrt(2)/2).[](empty list) — if the system is inconsistent.GroebnerBasis— for underdetermined (infinite) solution sets.
Example:
pool = ExprPool() x = pool.symbol("x") y = pool.symbol("y") # Linear system sols = solve([x + y - pool.integer(1), x - y], [x, y]) # → [{x: 1/2, y: 1/2}] # Circle ∩ line (irrational) sols = solve([x**2 + y**2 - pool.integer(1), y - x], [x, y]) # → [{x: sqrt(2)/2, y: sqrt(2)/2}, # {x: -sqrt(2)/2, y: -sqrt(2)/2}] # Parametric: omit free symbols from variables sols = solve([x**2 - y], [x]) # → [{x: sqrt(y)}, {x: -sqrt(y)}]
Note
Solutions are symbolic by default. Evaluate numerically with
eval_expr()when needed:from alkahest import eval_expr for sol in sols: for var, val in sol.items(): print(f"{var} ≈ {eval_expr(val, {}):.6f}")
Pass
numeric=Trueto return float values directly instead of symbolicExprsolutions.A univariate of degree ≥ 3 is factored over ℚ (or ℚ[params]) first; each irreducible factor is solved by formula, by an even / palindromic / pure-cubic reduction to radicals, or as exact
root_of()valuesRootOf(f, k). An irreducible parametric factor of degree ≥ 3 raisesE-SOLVE-002.Only the unknowns must be polynomial: a sub-expression free of them (
sin(q1),cos(q1 - q2),sqrt(a)) is a coefficient, so equations of motion solve for the accelerations. Every such answer is substituted back into the equations as written; one that relies on an identity between the coefficients the solve could not see (sin**2 + cos**2 == 1) is refused withE-SOLVE-001.One equation in one unknown is also solved in closed form, over the reals, when it reduces by logs (
ka*exp(-ka*t) - ke*exp(-ke*t)→log(ke/ka)/(ke - ka)), has a Lambert-W shape (x*exp(a*x) - b,a*x + b*log(x) - c,x**x - c), or issin/cos/tanof an affine argument equal to a constant. Trigonometric equations return the whole periodic family in an integer symbolk(asin(c) + 2*pi*k,pi - asin(c) + 2*pi*k);numeric=Truereturns thek = 0member of each family. Hypotheses (k ∈ Integer,ke/ka > 0,ke - ka ≠ 0) are listed bysolve_side_conditions(). A Lambert equation with a second real root on theW₋₁branch is refused.
- alkahest.root_of(poly: Expr, var: Expr, index: int) Expr¶
The
index-th distinct root ofpoly(a polynomial invarover ℚ), exactly. Roots are ordered real roots ascending, then non-real roots by real part, then imaginary part. Returns a rational number for a rational root, otherwiseRootOf(f, k)for the irreducible factorfofpolythe root belongs to. ARootOfhas no free symbols, is a constant todiff/subs, and evaluates witheval_expr,evaluate(..., mode="complex")and, to any precision,interval_eval. RaisesSolverErrorE-SOLVE-008on a non-polynomial or constantpolyor an out-of-rangeindex.Example:
r = root_of(x**3 - x - 1, x, 0) # RootOf(x^3 - x - 1, 0) eval_expr(r, {}) # 1.3247179572447...
GroebnerBasis¶
- class alkahest.GroebnerBasis¶
A Gröbner basis for a polynomial ideal.
A basis is a sequence:
len(gb),gb[i]and iteration all yield its generators asGbPoly.- classmethod compute(polys: list[Expr], vars: list[Expr], order: str = 'lex') GroebnerBasis¶
Compute a Gröbner basis using the F4 algorithm.
- Parameters:
order – Monomial order —
"lex"(default),"grlex", or"grevlex". Use"lex"for elimination;"grevlex"is generally fastest. For"lex"on a zero-dimensional ideal the grevlex-then-FGLM strategy is used automatically.
- order¶
The monomial order the generators are reduced under, as a string.
- to_exprs(vars: list[Expr] | None = None) list[Expr]¶
The generators as expressions, each meaning
g = 0. This is the read path for elimination results.
- reduce(p: GbPoly | Expr) GbPoly¶
Reduce p modulo the ideal and return the remainder. Call
GbPoly.to_expr()on it to read it back; it is zero exactly whencontains()is true.
- eliminate(vars: list[Expr]) GroebnerBasis¶
The elimination ideal
I ∩ k[remaining vars]: drops every generator whose support mentions one of vars. Under a"lex"basis with the eliminated variables ordered first, what is left is a Gröbner basis for that ideal.Useful for implicitization of parametric curves and surfaces.
- class alkahest.GbPoly¶
A sparse multivariate polynomial over ℚ, as used by the Gröbner machinery. It stores exponent vectors, so reading one back needs the variable list its slots refer to — polynomials Alkahest hands out carry that list.
- is_zero¶
- n_vars¶
- n_terms¶
- terms() list[tuple[tuple[int, ...], int | Fraction]]¶
(exponents, coefficient)pairs, in ascending exponent-vector order. Coefficients are exact.
- to_expr(vars: list[Expr] | None = None) Expr¶
Convert back to an
Expr. Defaults tovariables(); raisesValueErrorif vars names fewer variables than the polynomial uses.
- alkahest.expr_to_gbpoly(expr: Expr, vars: list[Expr]) GbPoly¶
Convert a polynomial expression into the
GbPolyrepresentation — the inverse ofGbPoly.to_expr(). Exponent slotirefers tovars[i], and the result remembers vars, so it can be passed straight toGroebnerBasis.reduce(),GroebnerBasis.contains()orGroebnerBasis.compute_raw.Raises
ValueErrorif expr is not polynomial in vars.