use mathhook_core::algebra::groebner::{MonomialOrder, MonomialOrdering};
use mathhook_core::core::Expression;
use mathhook_core::symbol;
use std::cmp::Ordering;
#[test]
fn test_grevlex_by_total_degree() {
let x = symbol!(x);
let y = symbol!(y);
let vars = vec![x.clone(), y.clone()];
let x1 = Expression::symbol(x.clone());
let x2 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
let order = MonomialOrder::Grevlex;
let cmp = order.compare_monomials(&x2, &x1, &vars);
assert_eq!(
cmp,
Ordering::Greater,
"x² (degree 2) should be greater than x (degree 1)"
);
}
#[test]
fn test_grevlex_same_degree_reverse_lex() {
let x = symbol!(x);
let y = symbol!(y);
let vars = vec![x.clone(), y.clone()];
let x2 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
let xy = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::symbol(y.clone()),
]);
let order = MonomialOrder::Grevlex;
let cmp = order.compare_monomials(&x2, &xy, &vars);
assert_eq!(
cmp,
Ordering::Greater,
"x² should be greater than xy in grevlex"
);
}
#[test]
fn test_grevlex_classic_example() {
let x = symbol!(x);
let y = symbol!(y);
let vars = vec![x.clone(), y.clone()];
let x2y = Expression::mul(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::symbol(y.clone()),
]);
let xy2 = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::pow(Expression::symbol(y.clone()), Expression::integer(2)),
]);
let order = MonomialOrder::Grevlex;
let cmp = order.compare_monomials(&x2y, &xy2, &vars);
assert_eq!(
cmp,
Ordering::Greater, "x²y should be greater than xy² in this implementation"
);
}
#[test]
fn test_grevlex_three_variables() {
let x = symbol!(x);
let y = symbol!(y);
let z = symbol!(z);
let vars = vec![x.clone(), y.clone(), z.clone()];
let xyz = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::symbol(y.clone()),
Expression::symbol(z.clone()),
]);
let x2z = Expression::mul(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::symbol(z.clone()),
]);
let xy2 = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::pow(Expression::symbol(y.clone()), Expression::integer(2)),
]);
let order = MonomialOrder::Grevlex;
let cmp1 = order.compare_monomials(&x2z, &xyz, &vars);
let cmp2 = order.compare_monomials(&xy2, &x2z, &vars);
let cmp3 = order.compare_monomials(&xy2, &xyz, &vars);
if cmp1 == Ordering::Less && cmp2 == Ordering::Less {
assert_eq!(
cmp3,
Ordering::Less,
"Transitivity: if a<b and b<c then a<c"
);
} else if cmp1 == Ordering::Greater && cmp2 == Ordering::Greater {
assert_eq!(
cmp3,
Ordering::Greater,
"Transitivity: if a>b and b>c then a>c"
);
}
}
#[test]
fn test_grevlex_sorting() {
let x = symbol!(x);
let y = symbol!(y);
let z = symbol!(z);
let vars = vec![x.clone(), y.clone(), z.clone()];
let order = MonomialOrder::Grevlex;
let y2 = Expression::pow(Expression::symbol(y.clone()), Expression::integer(2));
let xy = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::symbol(y.clone()),
]);
let x2 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
let z2 = Expression::pow(Expression::symbol(z.clone()), Expression::integer(2));
let xz = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::symbol(z.clone()),
]);
let mut monomials = [y2.clone(), xy.clone(), x2.clone(), z2.clone(), xz.clone()];
monomials.sort_by(|a, b| order.compare_monomials(a, b, &vars));
assert_eq!(monomials[0], z2, "First should be z²");
assert_eq!(monomials[1], xz, "Second should be xz");
assert_eq!(monomials[2], y2, "Third should be y²");
assert_eq!(monomials[3], xy, "Fourth should be xy");
assert_eq!(monomials[4], x2, "Fifth should be x²");
}
#[test]
fn test_grevlex_vs_implementation_degree_3() {
let x = symbol!(x);
let y = symbol!(y);
let z = symbol!(z);
let vars = vec![x.clone(), y.clone(), z.clone()];
let order = MonomialOrder::Grevlex;
let z3 = Expression::pow(Expression::symbol(z.clone()), Expression::integer(3));
let x3 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(3));
let xyz = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::symbol(y.clone()),
Expression::symbol(z.clone()),
]);
let y3 = Expression::pow(Expression::symbol(y.clone()), Expression::integer(3));
let x2y = Expression::mul(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::symbol(y.clone()),
]);
let xy2 = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::pow(Expression::symbol(y.clone()), Expression::integer(2)),
]);
let xz2 = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::pow(Expression::symbol(z.clone()), Expression::integer(2)),
]);
let yz2 = Expression::mul(vec![
Expression::symbol(y.clone()),
Expression::pow(Expression::symbol(z.clone()), Expression::integer(2)),
]);
let x2z = Expression::mul(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::symbol(z.clone()),
]);
let y2z = Expression::mul(vec![
Expression::pow(Expression::symbol(y.clone()), Expression::integer(2)),
Expression::symbol(z.clone()),
]);
let mut monomials = vec![
z3.clone(),
x3.clone(),
xyz.clone(),
y3.clone(),
x2y.clone(),
xy2.clone(),
xz2.clone(),
yz2.clone(),
x2z.clone(),
y2z.clone(),
];
monomials.sort_by(|a, b| order.compare_monomials(a, b, &vars));
let expected = vec![
z3.clone(), yz2.clone(), xz2.clone(), y2z.clone(), xyz.clone(), x2z.clone(), y3.clone(), xy2.clone(), x2y.clone(), x3.clone(), ];
assert_eq!(monomials.len(), expected.len());
for (i, (actual, expected)) in monomials.iter().zip(expected.iter()).enumerate() {
assert_eq!(actual, expected, "Position {}: Order mismatch", i);
}
}
#[test]
fn test_constant_monomial() {
let x = symbol!(x);
let y = symbol!(y);
let vars = vec![x.clone(), y.clone()];
let one = Expression::integer(1);
let x1 = Expression::symbol(x.clone());
let order = MonomialOrder::Grevlex;
let cmp = order.compare_monomials(&one, &x1, &vars);
assert_eq!(cmp, Ordering::Less, "Constant should be smallest");
}
#[test]
fn test_grevlex_with_coefficients() {
let x = symbol!(x);
let y = symbol!(y);
let vars = vec![x.clone(), y.clone()];
let three_x2 = Expression::mul(vec![
Expression::integer(3),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
]);
let two_xy = Expression::mul(vec![
Expression::integer(2),
Expression::symbol(x.clone()),
Expression::symbol(y.clone()),
]);
let order = MonomialOrder::Grevlex;
let cmp = order.compare_monomials(&three_x2, &two_xy, &vars);
assert_eq!(cmp, Ordering::Greater, "x² > xy (coefficients ignored)");
}
#[test]
fn test_grevlex_reflexivity() {
let x = symbol!(x);
let y = symbol!(y);
let vars = vec![x.clone(), y.clone()];
let xy = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::symbol(y.clone()),
]);
let order = MonomialOrder::Grevlex;
let cmp = order.compare_monomials(&xy, &xy, &vars);
assert_eq!(cmp, Ordering::Equal);
}
#[test]
fn test_grevlex_antisymmetry() {
let x = symbol!(x);
let y = symbol!(y);
let vars = vec![x.clone(), y.clone()];
let x2 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
let xy = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::symbol(y.clone()),
]);
let order = MonomialOrder::Grevlex;
let cmp1 = order.compare_monomials(&x2, &xy, &vars);
let cmp2 = order.compare_monomials(&xy, &x2, &vars);
assert_eq!(cmp1, Ordering::Greater);
assert_eq!(cmp2, Ordering::Less);
}
#[test]
fn test_grevlex_transitivity() {
let x = symbol!(x);
let y = symbol!(y);
let z = symbol!(z);
let vars = vec![x.clone(), y.clone(), z.clone()];
let xy2 = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::pow(Expression::symbol(y.clone()), Expression::integer(2)),
]);
let x2z = Expression::mul(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::symbol(z.clone()),
]);
let xyz = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::symbol(y.clone()),
Expression::symbol(z.clone()),
]);
let order = MonomialOrder::Grevlex;
let cmp1 = order.compare_monomials(&xyz, &x2z, &vars);
let cmp2 = order.compare_monomials(&x2z, &xy2, &vars);
let cmp3 = order.compare_monomials(&xyz, &xy2, &vars);
if cmp1 == Ordering::Less && cmp2 == Ordering::Less {
assert_eq!(cmp3, Ordering::Less, "xyz < x²z < xy² → xyz < xy²");
}
}