pub struct SparseMultivariatePolynomial<D: Domain, O: MonomialOrder = Grevlex> {
pub order: O,
/* private fields */
}Expand description
A sparse multivariate polynomial with coefficients in a domain D and
monomial ordering O.
§Example
use ocas_domain::{IntegerDomain, Integer};
use ocas_poly::sparse::Grevlex;
use ocas_poly::SparseMultivariatePolynomial;
let domain = IntegerDomain;
let p = SparseMultivariatePolynomial::<IntegerDomain, Grevlex>::from_terms(
domain,
2,
vec![(vec![1, 0], Integer::from(2)), (vec![0, 1], Integer::from(3))],
);
let q = SparseMultivariatePolynomial::<IntegerDomain, Grevlex>::from_terms(
domain,
2,
vec![(vec![1, 0], Integer::from(1)), (vec![0, 0], Integer::from(1))],
);
let r = p.mul(&q);
assert_eq!(r.coeff(&[1, 0]), Integer::from(2));
assert_eq!(r.coeff(&[0, 1]), Integer::from(3));
assert_eq!(r.coeff(&[2, 0]), Integer::from(2));Fields§
§order: OThe monomial ordering used for leading-term and sorting operations.
Implementations§
Source§impl<D: Domain, O: MonomialOrder> SparseMultivariatePolynomial<D, O>
impl<D: Domain, O: MonomialOrder> SparseMultivariatePolynomial<D, O>
Sourcepub fn new(domain: D, n_vars: usize) -> Self
pub fn new(domain: D, n_vars: usize) -> Self
Create the zero polynomial in n_vars variables over domain
with the default monomial ordering.
Sourcepub fn new_with_order(domain: D, n_vars: usize, order: O) -> Self
pub fn new_with_order(domain: D, n_vars: usize, order: O) -> Self
Create the zero polynomial with an explicit monomial ordering.
§Example
use ocas_domain::IntegerDomain;
use ocas_poly::sparse::{SparseMultivariatePolynomial, WeightOrder};
let order = WeightOrder::from_slice(&[2, 1]);
let p = SparseMultivariatePolynomial::<_, WeightOrder>::new_with_order(
IntegerDomain, 2, order,
);
assert_eq!(p.n_vars(), 2);Sourcepub fn from_terms(
domain: D,
n_vars: usize,
terms: Vec<(Vec<usize>, D::Element)>,
) -> Self
pub fn from_terms( domain: D, n_vars: usize, terms: Vec<(Vec<usize>, D::Element)>, ) -> Self
Create a polynomial from a list of (exponent vector, coefficient) pairs.
Zero coefficients and empty terms are dropped automatically.
§Example
use ocas_domain::{IntegerDomain, Integer};
use ocas_poly::sparse::Grevlex;
use ocas_poly::SparseMultivariatePolynomial;
let domain = IntegerDomain;
let p = SparseMultivariatePolynomial::<IntegerDomain, Grevlex>::from_terms(
domain,
2,
vec![(vec![1, 0], Integer::from(2)), (vec![0, 1], Integer::from(3))],
);
assert_eq!(p.n_terms(), 2);
assert_eq!(p.coeff(&[1, 0]), Integer::from(2));Sourcepub fn terms_ref(&self) -> &HashMap<SmallVec<[usize; 4]>, D::Element>
pub fn terms_ref(&self) -> &HashMap<SmallVec<[usize; 4]>, D::Element>
Return a reference to the internal term map (exponent → coefficient).
Sourcepub fn set_term_external(&mut self, exp: Vec<usize>, coeff: D::Element)
pub fn set_term_external(&mut self, exp: Vec<usize>, coeff: D::Element)
Set the coefficient of a monomial (public version of set_term).
Zero coefficients remove the term.
Sourcepub fn total_degree(&self) -> Option<usize>
pub fn total_degree(&self) -> Option<usize>
Return the total degree, or None for the zero polynomial.
Sourcepub fn coeff(&self, exp: &[usize]) -> D::Element
pub fn coeff(&self, exp: &[usize]) -> D::Element
Return the coefficient of the given monomial, or zero if absent.
Sourcepub fn add(&self, other: &Self) -> Self
pub fn add(&self, other: &Self) -> Self
Add another polynomial.
Panics if the polynomials have different numbers of variables.
Sourcepub fn sub(&self, other: &Self) -> Self
pub fn sub(&self, other: &Self) -> Self
Subtract another polynomial.
Panics if the polynomials have different numbers of variables.
Sourcepub fn mul_scalar(&self, scalar: &D::Element) -> Self
pub fn mul_scalar(&self, scalar: &D::Element) -> Self
Multiply by a scalar coefficient.
Sourcepub fn mul(&self, other: &Self) -> Self
pub fn mul(&self, other: &Self) -> Self
Multiply two polynomials.
Panics if the polynomials have different numbers of variables.
Sourcepub fn sorted_terms(&self) -> Vec<(&SmallVec<[usize; 4]>, &D::Element)>
pub fn sorted_terms(&self) -> Vec<(&SmallVec<[usize; 4]>, &D::Element)>
Return the terms sorted according to the monomial ordering.
Sourcepub fn leading_term(&self) -> Option<(&SmallVec<[usize; 4]>, &D::Element)>
pub fn leading_term(&self) -> Option<(&SmallVec<[usize; 4]>, &D::Element)>
Return the leading term (exponent_vector, coefficient) or None
for the zero polynomial.
This scans the HashMap in O(n) without allocating — faster than
sorted_terms() for repeated calls during reduction.
Sourcepub fn leading_monomial(&self) -> Option<&SmallVec<[usize; 4]>>
pub fn leading_monomial(&self) -> Option<&SmallVec<[usize; 4]>>
Return the leading monomial (exponent vector) or None.
Sourcepub fn leading_coeff(&self) -> Option<&D::Element>
pub fn leading_coeff(&self) -> Option<&D::Element>
Return the leading coefficient or None.
Sourcepub fn mul_monomial(&self, exp: &[usize]) -> Self
pub fn mul_monomial(&self, exp: &[usize]) -> Self
Multiply every term’s exponent vector by exp element-wise.
Panics if exp.len() != self.n_vars.
Sourcepub fn reduce(&self, basis: &[Self]) -> Self
pub fn reduce(&self, basis: &[Self]) -> Self
Reduce self by the given basis (a list of polynomials).
Implements multivariate polynomial division: repeatedly look for a
basis element whose leading monomial divides the current leading
monomial, subtract the appropriate multiple, or else move the leading
term into the remainder. Requires that div on the domain succeeds
(i.e. the domain is effectively a field).
Sourcepub fn spoly(&self, other: &Self) -> Self
pub fn spoly(&self, other: &Self) -> Self
Compute the S-polynomial of self and other:
S(f, g) = f·lc(g)·x^(lcm-lm(f)) - g·lc(f)·x^(lcm-lm(g))
Sourcepub fn content(&self) -> D::Elementwhere
D: EuclideanDomain,
pub fn content(&self) -> D::Elementwhere
D: EuclideanDomain,
Compute the content: the GCD of all coefficients.
For the zero polynomial the content is zero.
§Example
use ocas_domain::{Integer, IntegerDomain};
use ocas_poly::SparseMultivariatePolynomial;
use ocas_poly::Lex;
let p = SparseMultivariatePolynomial::<_, Lex>::from_terms(
IntegerDomain, 1,
vec![(vec![2], Integer::from(6)), (vec![1], Integer::from(9)), (vec![0], Integer::from(3))],
);
assert_eq!(p.content(), Integer::from(3));Sourcepub fn primitive_part(&self) -> Selfwhere
D: EuclideanDomain,
pub fn primitive_part(&self) -> Selfwhere
D: EuclideanDomain,
Return the primitive part: self / content.
The result has content 1 (or is zero).
§Example
use ocas_domain::{Integer, IntegerDomain};
use ocas_poly::SparseMultivariatePolynomial;
use ocas_poly::Lex;
let p = SparseMultivariatePolynomial::<_, Lex>::from_terms(
IntegerDomain, 1,
vec![(vec![2], Integer::from(6)), (vec![0], Integer::from(3))],
);
let pp = p.primitive_part();
// After dividing by content=3: 2*x^2 + 1
assert_eq!(pp.coeff(&[2]), Integer::from(2));
assert_eq!(pp.coeff(&[0]), Integer::from(1));Sourcepub fn div_exact(&self, divisor: &Self) -> Self
pub fn div_exact(&self, divisor: &Self) -> Self
Divide this polynomial by another, assuming the division is exact (no remainder).
Each term of self is divided by the corresponding factor from
divisor. This is used in rational-function canonicalization where
the GCD is known to divide both numerator and denominator.
§Panics
Panics if the division is not exact.
Sourcepub fn degree_in(&self, var_index: usize) -> usize
pub fn degree_in(&self, var_index: usize) -> usize
Return the degree of this polynomial in the given variable.
Returns 0 for the zero polynomial (by convention) or if the variable does not appear.
Sourcepub fn coeff_of_var_pow(&self, var_index: usize, pow: usize) -> Self
pub fn coeff_of_var_pow(&self, var_index: usize, pow: usize) -> Self
Return the coefficient polynomial of x_var^pow: the sum of all terms
whose exponent in var_index equals pow, with that exponent zeroed
out. The result has the same number of variables and does not depend
on var_index.
Sourcepub fn leading_coeff_in(&self, var_index: usize) -> Self
pub fn leading_coeff_in(&self, var_index: usize) -> Self
Return the leading coefficient when this polynomial is viewed as a
univariate polynomial in var_index. The result is a polynomial in
the remaining variables (same n_vars, exponent of var_index is 0).
Sourcepub fn derivative(&self, var_index: usize) -> Self
pub fn derivative(&self, var_index: usize) -> Self
Compute the formal partial derivative with respect to var_index.
Sourcepub fn taylor_coefficients(&self, var_index: usize, a: &D::Element) -> Vec<Self>
pub fn taylor_coefficients(&self, var_index: usize, a: &D::Element) -> Vec<Self>
Compute the Taylor coefficients in variable var_index around a:
f = Σ_j t_j · (x_var - a)^j where each t_j does not depend on
var_index (its exponent is zeroed).
Returns t_0, t_1, ..., t_d with d = degree_in(var_index).
Sourcepub fn drop_main_var(&self) -> Self
pub fn drop_main_var(&self) -> Self
Drop variable 0, which must not occur in any term. Returns a
polynomial in n_vars - 1 variables with indices shifted down.
Panics in debug builds if variable 0 occurs with a non-zero exponent.
Sourcepub fn embed_new_main(&self) -> Self
pub fn embed_new_main(&self) -> Self
Embed into one more variable by inserting a new variable 0 with exponent 0 (all existing variable indices shift up by one).
Sourcepub fn drop_variable(&self, var_index: usize) -> Self
pub fn drop_variable(&self, var_index: usize) -> Self
Drop variable var_index from the polynomial, producing a polynomial
in one fewer variable. Only safe when no term has a nonzero exponent
for var_index (otherwise those terms are silently dropped).
Sourcepub fn extend_vars(&self, new_n_vars: usize) -> Self
pub fn extend_vars(&self, new_n_vars: usize) -> Self
Extend to new_n_vars variables by appending zero exponents.
Requires new_n_vars >= self.n_vars. Existing variable indices
are unchanged; new variables are appended at the end.
Sourcepub fn permute_variables(&self, perm: &[usize]) -> Self
pub fn permute_variables(&self, perm: &[usize]) -> Self
Permute variables: the result’s exponent at position i is the old
exponent at position perm[i]. perm must be a permutation of
0..n_vars.
Sourcepub fn checked_div_exact(&self, divisor: &Self) -> Option<Self>
pub fn checked_div_exact(&self, divisor: &Self) -> Option<Self>
Divide this polynomial by divisor, returning the quotient only if
the division is exact (zero remainder).
Sourcepub fn eval_keep(&self, var_index: usize, value: &D::Element) -> Self
pub fn eval_keep(&self, var_index: usize, value: &D::Element) -> Self
Evaluate variable var_index at value while keeping the total
number of variables unchanged (the variable disappears from the
support but all indices are preserved).
This is the substitution used by multivariate Hensel lifting, where variable positions must stay fixed across recursion levels.
Sourcepub fn max_exp(&self) -> Option<&SmallVec<[usize; 4]>>
pub fn max_exp(&self) -> Option<&SmallVec<[usize; 4]>>
Return the exponent vector of the leading monomial, or None for zero.
This is an alias for leading_monomial that
matches the Symbolica naming convention used in the F4 algorithm.
Sourcepub fn max_coeff(&self) -> Option<&D::Element>
pub fn max_coeff(&self) -> Option<&D::Element>
Return the leading coefficient, or None for zero.
This is an alias for leading_coeff that
matches the Symbolica naming convention used in the F4 algorithm.
Sourcepub fn exponents_iter(&self) -> impl Iterator<Item = &SmallVec<[usize; 4]>>
pub fn exponents_iter(&self) -> impl Iterator<Item = &SmallVec<[usize; 4]>>
Iterate over all exponent vectors in sorted order (descending by the monomial ordering).
The F4 algorithm uses this to enumerate every monomial in a polynomial for symbolic preprocessing.
Sourcepub fn make_monic_inplace(&mut self) -> bool
pub fn make_monic_inplace(&mut self) -> bool
Divide every term by the leading coefficient, making the polynomial
monic. Returns false if the polynomial is zero or the leading
coefficient has no inverse.
Sourcepub fn zero_with_capacity(&self, _cap: usize) -> Self
pub fn zero_with_capacity(&self, _cap: usize) -> Self
Create a zero polynomial with the same domain and variable count.
This is identical to zero but named to match the
Symbolica convention used in F4 code.
Sourcepub fn append_monomial(&mut self, coeff: D::Element, exp: &[usize])
pub fn append_monomial(&mut self, coeff: D::Element, exp: &[usize])
Append a single monomial term coeff * x^exp.
If the monomial already exists, the coefficients are summed. Zero coefficients remove the term.
Sourcepub fn eval(&self, var_index: usize, value: &D::Element) -> Self
pub fn eval(&self, var_index: usize, value: &D::Element) -> Self
Evaluate the polynomial by substituting value for variable var_index.
Returns a polynomial in one fewer variable (all remaining variables
keep their relative order). If var_index is the only variable, the
result is a zero-variable (constant) polynomial.
§Example
use ocas_domain::{Integer, IntegerDomain};
use ocas_poly::SparseMultivariatePolynomial;
use ocas_poly::Lex;
let p = SparseMultivariatePolynomial::<_, Lex>::from_terms(
IntegerDomain, 2,
vec![
(vec![1, 1], Integer::from(1)), // x*y
(vec![0, 1], Integer::from(2)), // 2*y
],
);
// Substitute x=3: result = 3*y + 2*y = 5*y
let r = p.eval(0, &Integer::from(3));
assert_eq!(r.coeff(&[1]), Integer::from(5));Source§impl SparseMultivariatePolynomial<IntegerDomain, Lex>
impl SparseMultivariatePolynomial<IntegerDomain, Lex>
Sourcepub fn factor(&self) -> Vec<(Self, usize)>
pub fn factor(&self) -> Vec<(Self, usize)>
Factor this bivariate integer polynomial into irreducible factors with multiplicities.
With a constant leading coefficient in $x$ the polynomial is treated as univariate in $x$ with coefficients in $\mathbb{Z}[y]$ and factored via Wang’s bivariate Hensel-lifting algorithm. With a non-constant leading coefficient the general EEZ path with Wang leading-coefficient imposition (p-adic coefficient Hensel lifting) is used instead.
§Example
use ocas_domain::{Integer, IntegerDomain};
use ocas_poly::SparseMultivariatePolynomial;
use ocas_poly::Lex;
// (x^2 + y + 1)(x + y + 2)
let f = SparseMultivariatePolynomial::<_, Lex>::from_terms(
IntegerDomain, 2,
vec![
(vec![3, 0], Integer::from(1)),
(vec![2, 1], Integer::from(1)),
(vec![2, 0], Integer::from(2)),
(vec![1, 1], Integer::from(1)),
(vec![1, 0], Integer::from(1)),
(vec![0, 2], Integer::from(1)),
(vec![0, 1], Integer::from(3)),
(vec![0, 0], Integer::from(2)),
],
);
let factors = f.factor();
assert!(factors.len() >= 2);Source§impl SparseMultivariatePolynomial<FiniteField, Lex>
impl SparseMultivariatePolynomial<FiniteField, Lex>
Sourcepub fn factor(&self) -> Vec<(Self, usize)>
pub fn factor(&self) -> Vec<(Self, usize)>
Factor this multivariate polynomial over a prime finite field into irreducible factors with multiplicities.
Bivariate polynomials use the evaluation–Hensel path; polynomials in three or more variables use EEZ Hensel lifting. Both currently require the leading coefficient in the main variable to be a nonzero field constant.
Trait Implementations§
Source§impl<D: Clone + Domain, O: Clone + MonomialOrder> Clone for SparseMultivariatePolynomial<D, O>
impl<D: Clone + Domain, O: Clone + MonomialOrder> Clone for SparseMultivariatePolynomial<D, O>
Source§fn clone(&self) -> SparseMultivariatePolynomial<D, O>
fn clone(&self) -> SparseMultivariatePolynomial<D, O>
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<D: Debug + Domain, O: Debug + MonomialOrder> Debug for SparseMultivariatePolynomial<D, O>
impl<D: Debug + Domain, O: Debug + MonomialOrder> Debug for SparseMultivariatePolynomial<D, O>
impl<D: Eq + Domain, O: Eq + MonomialOrder> Eq for SparseMultivariatePolynomial<D, O>
Source§impl<D: PartialEq + Domain, O: PartialEq + MonomialOrder> PartialEq for SparseMultivariatePolynomial<D, O>
impl<D: PartialEq + Domain, O: PartialEq + MonomialOrder> PartialEq for SparseMultivariatePolynomial<D, O>
impl<D: PartialEq + Domain, O: PartialEq + MonomialOrder> StructuralPartialEq for SparseMultivariatePolynomial<D, O>
Auto Trait Implementations§
impl<D, O> Freeze for SparseMultivariatePolynomial<D, O>
impl<D, O> RefUnwindSafe for SparseMultivariatePolynomial<D, O>
impl<D, O> Send for SparseMultivariatePolynomial<D, O>
impl<D, O> Sync for SparseMultivariatePolynomial<D, O>
impl<D, O> Unpin for SparseMultivariatePolynomial<D, O>
impl<D, O> UnsafeUnpin for SparseMultivariatePolynomial<D, O>where
D: UnsafeUnpin,
O: UnsafeUnpin,
impl<D, O> UnwindSafe for SparseMultivariatePolynomial<D, O>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more