extern crate groebner;
use groebner::{groebner_basis, is_groebner_basis, MonomialOrder, Polynomial, PolynomialRing};
use num_rational::BigRational;
const TEST_VARIABLES: [&str; 10] = ["x", "y", "z", "w", "u", "v", "a", "b", "c", "d"];
#[allow(clippy::expect_used)]
fn test_ring(nvars: usize, order: MonomialOrder) -> PolynomialRing<BigRational> {
PolynomialRing::new(TEST_VARIABLES[..nvars].iter().copied(), order)
.expect("test ring should be valid")
}
#[allow(clippy::expect_used)]
fn create_polynomial(
terms: Vec<(i32, i32, Vec<u32>)>, nvars: usize,
order: MonomialOrder,
) -> Polynomial<BigRational> {
let expression = terms_to_expression(terms, nvars);
test_ring(nvars, order)
.parse(&expression)
.expect("test polynomial should parse")
}
fn create_int_polynomial(
terms: Vec<(i32, Vec<u32>)>, nvars: usize,
order: MonomialOrder,
) -> Polynomial<BigRational> {
create_polynomial(
terms
.into_iter()
.map(|(coefficient, exponents)| (coefficient, 1, exponents))
.collect(),
nvars,
order,
)
}
fn terms_to_expression(terms: Vec<(i32, i32, Vec<u32>)>, nvars: usize) -> String {
if terms.is_empty() {
return "0".to_string();
}
let mut expression = String::new();
for (index, (numerator, denominator, exponents)) in terms.into_iter().enumerate() {
let negative = numerator < 0;
let abs_numerator = numerator.abs();
if index == 0 {
if negative {
expression.push('-');
}
} else if negative {
expression.push_str(" - ");
} else {
expression.push_str(" + ");
}
let is_constant = exponents.iter().all(|&exponent| exponent == 0);
let mut factors = Vec::new();
if abs_numerator != 1 || denominator != 1 || is_constant {
if denominator == 1 {
factors.push(abs_numerator.to_string());
} else {
factors.push(format!("{abs_numerator}/{denominator}"));
}
}
for (variable, exponent) in TEST_VARIABLES[..nvars].iter().zip(exponents) {
match exponent {
0 => {}
1 => factors.push((*variable).to_string()),
exponent => factors.push(format!("{variable}^{exponent}")),
}
}
expression.push_str(&factors.join("*"));
}
expression
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_groebner_cox_little_oshea() {
let f = create_polynomial(
vec![(1, 1, vec![2, 0]), (2, 1, vec![1, 2])],
2,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(1, 1, vec![1, 1]), (2, 1, vec![0, 3]), (-1, 1, vec![0, 0])],
2,
MonomialOrder::Lex,
);
let expected = vec![
create_polynomial(vec![(1, 1, vec![1, 0])], 2, MonomialOrder::Lex), create_polynomial(
vec![(1, 1, vec![0, 3]), (-1, 2, vec![0, 0])],
2,
MonomialOrder::Lex,
), ];
let basis = groebner_basis(vec![f, g], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert_eq!(basis, expected);
}
#[test]
fn test_groebner_y_x_order() {
let f = create_polynomial(
vec![(2, 1, vec![2, 1]), (1, 1, vec![0, 2])],
2,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(2, 1, vec![3, 0]), (1, 1, vec![1, 1]), (-1, 1, vec![0, 0])],
2,
MonomialOrder::Lex,
);
let basis = groebner_basis(vec![f, g], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
}
#[test]
fn test_three_variable_simple() {
let f = create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 0, 2])],
3,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(1, 1, vec![0, 1, 0]), (-1, 1, vec![0, 0, 3])],
3,
MonomialOrder::Lex,
);
let basis = groebner_basis(vec![f, g], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
assert_eq!(basis.len(), 2);
}
#[test]
fn test_grlex_ordering() {
let f = create_polynomial(
vec![(1, 1, vec![3, 0]), (-2, 1, vec![1, 1])],
2,
MonomialOrder::GrLex,
);
let g = create_polynomial(
vec![(1, 1, vec![2, 1]), (1, 1, vec![1, 0]), (-2, 1, vec![0, 2])],
2,
MonomialOrder::GrLex,
);
let expected = vec![
create_polynomial(vec![(1, 1, vec![2, 0])], 2, MonomialOrder::GrLex), create_polynomial(vec![(1, 1, vec![1, 1])], 2, MonomialOrder::GrLex), create_polynomial(
vec![(-1, 2, vec![1, 0]), (1, 1, vec![0, 2])],
2,
MonomialOrder::GrLex,
), ];
let basis = groebner_basis(vec![f, g], MonomialOrder::GrLex, true)
.expect("Groebner computation failed");
assert_eq!(basis, expected);
}
#[test]
fn test_three_variable_complex_lex() {
let f = create_polynomial(
vec![(-1, 1, vec![2, 0, 0]), (1, 1, vec![0, 1, 0])],
3,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(-1, 1, vec![3, 0, 0]), (1, 1, vec![0, 0, 1])],
3,
MonomialOrder::Lex,
);
let expected = vec![
create_polynomial(
vec![(1, 1, vec![2, 0, 0]), (-1, 1, vec![0, 1, 0])],
3,
MonomialOrder::Lex,
), create_polynomial(
vec![(1, 1, vec![1, 1, 0]), (-1, 1, vec![0, 0, 1])],
3,
MonomialOrder::Lex,
), create_polynomial(
vec![(1, 1, vec![1, 0, 1]), (-1, 1, vec![0, 2, 0])],
3,
MonomialOrder::Lex,
), create_polynomial(
vec![(1, 1, vec![0, 3, 0]), (-1, 1, vec![0, 0, 2])],
3,
MonomialOrder::Lex,
), ];
let basis = groebner_basis(vec![f, g], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert_eq!(basis, expected);
}
#[test]
fn test_three_variable_complex_grlex() {
let f = create_polynomial(
vec![(-1, 1, vec![2, 0, 0]), (1, 1, vec![0, 1, 0])],
3,
MonomialOrder::GrLex,
);
let g = create_polynomial(
vec![(-1, 1, vec![3, 0, 0]), (1, 1, vec![0, 0, 1])],
3,
MonomialOrder::GrLex,
);
let expected = [
create_polynomial(
vec![(1, 1, vec![0, 3, 0]), (-1, 1, vec![0, 0, 2])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(1, 1, vec![2, 0, 0]), (-1, 1, vec![0, 1, 0])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(1, 1, vec![1, 1, 0]), (-1, 1, vec![0, 0, 1])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(1, 1, vec![1, 0, 1]), (-1, 1, vec![0, 2, 0])],
3,
MonomialOrder::GrLex,
), ];
let basis = groebner_basis(vec![f, g], MonomialOrder::GrLex, true)
.expect("Groebner computation failed");
assert_eq!(basis, expected);
}
#[test]
fn test_parametric_curve() {
let f = create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 2, 0])],
3,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(-1, 1, vec![0, 3, 0]), (1, 1, vec![0, 0, 1])],
3,
MonomialOrder::Lex,
);
let expected = vec![
create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 2, 0])],
3,
MonomialOrder::Lex,
), create_polynomial(
vec![(1, 1, vec![0, 3, 0]), (-1, 1, vec![0, 0, 1])],
3,
MonomialOrder::Lex,
), ];
let basis = groebner_basis(vec![f, g], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert_eq!(basis, expected);
}
#[test]
fn test_parametric_curve_grlex() {
let f = create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 2, 0])],
3,
MonomialOrder::GrLex,
);
let g = create_polynomial(
vec![(-1, 1, vec![0, 3, 0]), (1, 1, vec![0, 0, 1])],
3,
MonomialOrder::GrLex,
);
let expected = vec![
create_polynomial(
vec![(1, 1, vec![2, 0, 0]), (-1, 1, vec![0, 1, 1])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(1, 1, vec![1, 1, 0]), (-1, 1, vec![0, 0, 1])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(-1, 1, vec![1, 0, 0]), (1, 1, vec![0, 2, 0])],
3,
MonomialOrder::GrLex,
), ];
let basis = groebner_basis(vec![f, g], MonomialOrder::GrLex, true)
.expect("Groebner computation failed");
assert_eq!(basis, expected);
}
#[test]
fn test_twisted_cubic() {
let f = create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 0, 2])],
3,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(1, 1, vec![0, 1, 0]), (-1, 1, vec![0, 0, 3])],
3,
MonomialOrder::Lex,
);
let expected = vec![f.clone(), g.clone()];
let basis = groebner_basis(vec![f, g], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert_eq!(basis, expected);
}
#[test]
fn test_twisted_cubic_grlex() {
let f = create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 0, 2])],
3,
MonomialOrder::GrLex,
);
let g = create_polynomial(
vec![(1, 1, vec![0, 1, 0]), (-1, 1, vec![0, 0, 3])],
3,
MonomialOrder::GrLex,
);
let expected = [
create_polynomial(
vec![(1, 1, vec![2, 0, 0]), (-1, 1, vec![0, 1, 1])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(1, 1, vec![1, 0, 1]), (-1, 1, vec![0, 1, 0])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(-1, 1, vec![1, 0, 0]), (1, 1, vec![0, 0, 2])],
3,
MonomialOrder::GrLex,
), ];
let basis = groebner_basis(vec![f, g], MonomialOrder::GrLex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
assert_eq!(basis.len(), 3);
assert_eq!(basis, expected);
let has_x2_term = basis.iter().any(|p| {
p.terms
.iter()
.any(|t| t.monomial.exponents == vec![2, 0, 0])
});
let has_xz_term = basis.iter().any(|p| {
p.terms
.iter()
.any(|t| t.monomial.exponents == vec![1, 0, 1])
});
let has_z2_term = basis.iter().any(|p| {
p.terms
.iter()
.any(|t| t.monomial.exponents == vec![0, 0, 2])
});
assert!(has_x2_term);
assert!(has_xz_term);
assert!(has_z2_term);
}
#[test]
fn test_variety_intersection() {
let f = create_polynomial(
vec![(-1, 1, vec![0, 2, 0]), (1, 1, vec![0, 0, 1])],
3,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 3, 0])],
3,
MonomialOrder::Lex,
);
let expected = vec![
create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 3, 0])],
3,
MonomialOrder::Lex,
), create_polynomial(
vec![(1, 1, vec![0, 2, 0]), (-1, 1, vec![0, 0, 1])],
3,
MonomialOrder::Lex,
), ];
let basis = groebner_basis(vec![f, g], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert_eq!(basis, expected);
}
#[test]
fn test_variety_intersection_grlex() {
let f = create_polynomial(
vec![(-1, 1, vec![0, 2, 0]), (1, 1, vec![0, 0, 1])],
3,
MonomialOrder::GrLex,
);
let g = create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 3, 0])],
3,
MonomialOrder::GrLex,
);
let expected = vec![
create_polynomial(
vec![(-1, 1, vec![2, 0, 0]), (1, 1, vec![0, 0, 3])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(1, 1, vec![1, 1, 0]), (-1, 1, vec![0, 0, 2])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(1, 1, vec![0, 2, 0]), (-1, 1, vec![0, 0, 1])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(-1, 1, vec![1, 0, 0]), (1, 1, vec![0, 1, 1])],
3,
MonomialOrder::GrLex,
), ];
let basis = groebner_basis(vec![f, g], MonomialOrder::GrLex, true)
.expect("Groebner computation failed");
assert_eq!(basis, expected);
}
#[test]
fn test_space_curve() {
let f = create_polynomial(
vec![(1, 1, vec![0, 1, 0]), (-1, 1, vec![0, 0, 2])],
3,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 0, 3])],
3,
MonomialOrder::Lex,
);
let expected = vec![
create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 0, 3])],
3,
MonomialOrder::Lex,
), create_polynomial(
vec![(1, 1, vec![0, 1, 0]), (-1, 1, vec![0, 0, 2])],
3,
MonomialOrder::Lex,
), ];
let basis = groebner_basis(vec![f, g], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert_eq!(basis, expected);
}
#[test]
fn test_space_curve_grlex() {
let f = create_polynomial(
vec![(1, 1, vec![0, 1, 0]), (-1, 1, vec![0, 0, 2])],
3,
MonomialOrder::GrLex,
);
let g = create_polynomial(
vec![(1, 1, vec![1, 0, 0]), (-1, 1, vec![0, 0, 3])],
3,
MonomialOrder::GrLex,
);
let expected = vec![
create_polynomial(
vec![(1, 1, vec![0, 3, 0]), (-1, 1, vec![2, 0, 0])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(1, 1, vec![1, 0, 1]), (-1, 1, vec![0, 2, 0])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(1, 1, vec![0, 1, 1]), (-1, 1, vec![1, 0, 0])],
3,
MonomialOrder::GrLex,
), create_polynomial(
vec![(1, 1, vec![0, 0, 2]), (-1, 1, vec![0, 1, 0])],
3,
MonomialOrder::GrLex,
), ];
let basis = groebner_basis(vec![f, g], MonomialOrder::GrLex, true)
.expect("Groebner computation failed");
assert_eq!(basis, expected);
}
#[test]
fn test_circle_and_parabola() {
let f = create_polynomial(
vec![(4, 1, vec![2, 2]), (4, 1, vec![1, 1]), (1, 1, vec![0, 0])],
2,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(1, 1, vec![2, 0]), (1, 1, vec![0, 2]), (-1, 1, vec![0, 0])],
2,
MonomialOrder::Lex,
);
let basis = groebner_basis(vec![f, g], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
}
#[test]
fn test_katsura_3_system() {
let f1 = create_int_polynomial(
vec![
(1, vec![1, 0, 0]),
(2, vec![0, 1, 0]),
(2, vec![0, 0, 1]),
(-1, vec![0, 0, 0]),
],
3,
MonomialOrder::Lex,
);
let f2 = create_int_polynomial(
vec![
(1, vec![2, 0, 0]),
(2, vec![0, 2, 0]),
(2, vec![0, 0, 2]),
(-1, vec![1, 0, 0]),
],
3,
MonomialOrder::Lex,
);
let f3 = create_int_polynomial(
vec![(2, vec![1, 1, 0]), (2, vec![0, 1, 1]), (-1, vec![0, 1, 0])],
3,
MonomialOrder::Lex,
);
let basis = groebner_basis(vec![f1, f2, f3], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
assert_eq!(basis.len(), 3);
assert_eq!(
basis[0]
.leading_monomial()
.expect("Leading monomial computation failed")
.exponents,
vec![1, 0, 0]
); assert_eq!(
basis[1]
.leading_monomial()
.expect("Leading monomial computation failed")
.exponents,
vec![0, 1, 0]
); assert_eq!(
basis[2]
.leading_monomial()
.expect("Leading monomial computation failed")
.exponents,
vec![0, 0, 4]
); }
#[test]
fn test_katsura_3_grlex() {
let f1 = create_int_polynomial(
vec![
(1, vec![1, 0, 0]),
(2, vec![0, 1, 0]),
(2, vec![0, 0, 1]),
(-1, vec![0, 0, 0]),
],
3,
MonomialOrder::GrLex,
);
let f2 = create_int_polynomial(
vec![
(1, vec![2, 0, 0]),
(2, vec![0, 2, 0]),
(2, vec![0, 0, 2]),
(-1, vec![1, 0, 0]),
],
3,
MonomialOrder::GrLex,
);
let f3 = create_int_polynomial(
vec![(2, vec![1, 1, 0]), (2, vec![0, 1, 1]), (-1, vec![0, 1, 0])],
3,
MonomialOrder::GrLex,
);
let basis = groebner_basis(vec![f1, f2, f3], MonomialOrder::GrLex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
}
#[test]
fn test_cyclic_4_system() {
let f1 = create_int_polynomial(
vec![
(1, vec![1, 0, 0, 0]),
(1, vec![0, 1, 0, 0]),
(1, vec![0, 0, 1, 0]),
(1, vec![0, 0, 0, 1]),
],
4,
MonomialOrder::Lex,
);
let f2 = create_int_polynomial(
vec![
(1, vec![1, 1, 0, 0]),
(1, vec![1, 0, 0, 1]),
(1, vec![0, 1, 1, 0]),
(1, vec![0, 1, 0, 1]),
],
4,
MonomialOrder::Lex,
);
let f3 = create_int_polynomial(
vec![
(1, vec![1, 1, 1, 0]),
(1, vec![1, 1, 0, 1]),
(1, vec![1, 0, 1, 1]),
(1, vec![0, 1, 1, 1]),
],
4,
MonomialOrder::Lex,
);
let f4 = create_int_polynomial(
vec![(1, vec![1, 1, 1, 1]), (-1, vec![0, 0, 0, 0])],
4,
MonomialOrder::Lex,
);
let basis = groebner_basis(vec![f1, f2, f3, f4], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
assert_eq!(basis.len(), 5);
let leading_exponents: Vec<_> = basis
.iter()
.map(|p| {
p.leading_monomial()
.expect("Leading monomial computation failed")
.exponents
.clone()
})
.collect();
assert_eq!(leading_exponents[0][0], 1);
assert!(leading_exponents[4][3] >= 4); }
#[test]
fn test_cyclic_4_grlex() {
let f1 = create_int_polynomial(
vec![
(1, vec![1, 0, 0, 0]),
(1, vec![0, 1, 0, 0]),
(1, vec![0, 0, 1, 0]),
(1, vec![0, 0, 0, 1]),
],
4,
MonomialOrder::GrLex,
);
let f2 = create_int_polynomial(
vec![
(1, vec![1, 1, 0, 0]),
(1, vec![1, 0, 0, 1]),
(1, vec![0, 1, 1, 0]),
(1, vec![0, 1, 0, 1]),
],
4,
MonomialOrder::GrLex,
);
let f3 = create_int_polynomial(
vec![
(1, vec![1, 1, 1, 0]),
(1, vec![1, 1, 0, 1]),
(1, vec![1, 0, 1, 1]),
(1, vec![0, 1, 1, 1]),
],
4,
MonomialOrder::GrLex,
);
let f4 = create_int_polynomial(
vec![(1, vec![1, 1, 1, 1]), (-1, vec![0, 0, 0, 0])],
4,
MonomialOrder::GrLex,
);
let basis = groebner_basis(vec![f1, f2, f3, f4], MonomialOrder::GrLex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
}
#[test]
fn test_simple_ideal() {
let f1 = create_polynomial(
vec![(1, 1, vec![2, 0]), (-1, 1, vec![0, 1])],
2,
MonomialOrder::Lex,
);
let f2 = create_polynomial(
vec![(1, 1, vec![1, 1]), (-1, 1, vec![0, 0])],
2,
MonomialOrder::Lex,
);
let basis = groebner_basis(vec![f1, f2], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
}
#[test]
fn test_monomial_ordering_properties() {
let f = create_polynomial(
vec![(1, 1, vec![2, 1]), (1, 1, vec![1, 2])],
2,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(1, 1, vec![1, 1]), (-1, 1, vec![0, 0])],
2,
MonomialOrder::Lex,
);
let basis_lex = groebner_basis(vec![f.clone(), g.clone()], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
let basis_grlex = groebner_basis(vec![f, g], MonomialOrder::GrLex, true)
.expect("Groebner computation failed");
assert!(is_groebner_basis(&basis_lex).expect("Groebner basis check failed"));
assert!(is_groebner_basis(&basis_grlex).expect("Groebner basis check failed"));
assert!(!basis_lex.is_empty());
assert!(!basis_grlex.is_empty());
}
#[test]
fn test_reduction_properties() {
let f = create_polynomial(
vec![(1, 1, vec![2, 0]), (1, 1, vec![1, 1])],
2,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(1, 1, vec![1, 0]), (-1, 1, vec![0, 1])],
2,
MonomialOrder::Lex,
);
let basis = vec![g];
let remainder = f.reduce(&basis).expect("Polynomial reduction failed");
assert!(remainder.terms.len() <= f.terms.len());
}
#[test]
fn test_s_polynomial() {
let f = create_polynomial(
vec![(1, 1, vec![2, 0]), (2, 1, vec![1, 2])],
2,
MonomialOrder::Lex,
);
let g = create_polynomial(
vec![(1, 1, vec![1, 1]), (2, 1, vec![0, 3]), (-1, 1, vec![0, 0])],
2,
MonomialOrder::Lex,
);
let s_poly = f.s_polynomial(&g).expect("S-polynomial computation failed");
assert!(!s_poly.is_zero());
}
#[test]
fn test_empty_and_single_polynomial() {
let empty_basis = groebner_basis::<BigRational>(vec![], MonomialOrder::Lex, true);
assert!(matches!(
empty_basis,
Err(groebner::GroebnerError::EmptyInput)
));
let single = create_polynomial(vec![(1, 1, vec![1, 0])], 2, MonomialOrder::Lex);
let single_basis = groebner_basis(vec![single.clone()], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert_eq!(single_basis.len(), 1);
assert!(is_groebner_basis(&single_basis).expect("Groebner basis check failed"));
}
#[test]
fn test_zero_polynomial() {
let zero = Polynomial::zero(2, MonomialOrder::Lex);
let nonzero = create_polynomial(vec![(1, 1, vec![1, 0])], 2, MonomialOrder::Lex);
let basis = groebner_basis(vec![zero, nonzero.clone()], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert_eq!(basis.len(), 1);
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
}
#[test]
fn test_constant_polynomial() {
let constant = create_polynomial(vec![(1, 1, vec![0, 0])], 2, MonomialOrder::Lex);
let other = create_polynomial(vec![(1, 1, vec![1, 0])], 2, MonomialOrder::Lex);
let basis = groebner_basis(vec![constant, other], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
}
#[test]
fn test_linear_system() {
let f1 = create_polynomial(
vec![(1, 1, vec![1, 0]), (1, 1, vec![0, 1]), (-1, 1, vec![0, 0])],
2,
MonomialOrder::Lex,
);
let f2 = create_polynomial(
vec![(1, 1, vec![1, 0]), (-1, 1, vec![0, 1])],
2,
MonomialOrder::Lex,
);
let basis = groebner_basis(vec![f1, f2], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
}
#[test]
fn test_quadratic_system() {
let f1 = create_polynomial(
vec![(1, 1, vec![2, 0]), (1, 1, vec![0, 2]), (-1, 1, vec![0, 0])],
2,
MonomialOrder::Lex,
);
let f2 = create_polynomial(
vec![(1, 1, vec![2, 0]), (-1, 1, vec![0, 2])],
2,
MonomialOrder::Lex,
);
let basis = groebner_basis(vec![f1, f2], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
}
#[test]
fn test_homogeneous_ideal() {
let f1 = create_polynomial(
vec![(1, 1, vec![2, 0]), (1, 1, vec![0, 2])],
2,
MonomialOrder::Lex,
);
let f2 = create_polynomial(
vec![(1, 1, vec![1, 1]), (1, 1, vec![0, 0])],
2,
MonomialOrder::Lex,
);
let basis = groebner_basis(vec![f1, f2], MonomialOrder::Lex, true)
.expect("Groebner computation failed");
assert!(!basis.is_empty());
assert!(is_groebner_basis(&basis).expect("Groebner basis check failed"));
}
}