add a few tests for monomials and polynomials ops
This commit is contained in:
139
src/poly/flat.rs
139
src/poly/flat.rs
@@ -1,13 +1,13 @@
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
|
|
||||||
use std::ops::{Add, Sub, BitXor, Mul};
|
use std::ops::{Add, BitXor, Mul, Sub};
|
||||||
|
|
||||||
use crate::fmt::num_to_superscript;
|
|
||||||
use super::var::{StaticVar, Var};
|
use super::var::{StaticVar, Var};
|
||||||
|
use crate::fmt::num_to_superscript;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Poly<V: Var> {
|
pub struct Poly<V: Var> {
|
||||||
mono: HashMap<Mono<V>, i32>,
|
mono: HashMap<Mono<V>, i32>,
|
||||||
}
|
}
|
||||||
@@ -58,25 +58,25 @@ pub struct Mono<V: Var> {
|
|||||||
pub term: Vec<(V, u32)>,
|
pub term: Vec<(V, u32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V:Var> Mono<V>{
|
impl<V: Var> Mono<V> {
|
||||||
pub fn contains(&self, other:&Mono<V>)->bool{
|
pub fn contains(&self, other: &Mono<V>) -> bool {
|
||||||
let mut self_it=self.term.iter().peekable();
|
let mut self_it = self.term.iter().peekable();
|
||||||
let mut other_it=other.term.iter().peekable();
|
let mut other_it = other.term.iter().peekable();
|
||||||
|
|
||||||
while let Some((o_term,o_exp))=other_it.peek(){
|
while let Some((o_term, o_exp)) = other_it.peek() {
|
||||||
if let Some((s_term,s_exp))=self_it.peek(){
|
if let Some((s_term, s_exp)) = self_it.peek() {
|
||||||
if s_term<o_term{
|
if s_term < o_term {
|
||||||
self_it.next();
|
self_it.next();
|
||||||
continue;
|
continue;
|
||||||
}else if s_term>o_term{
|
} else if s_term > o_term {
|
||||||
return false;
|
return false;
|
||||||
}else if o_exp<=s_exp{
|
} else if o_exp <= s_exp {
|
||||||
self_it.next();
|
self_it.next();
|
||||||
other_it.next();
|
other_it.next();
|
||||||
}else{
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,11 +103,9 @@ impl<V: Var, U: Into<V>> FromIterator<(U, u32)> for Mono<V> {
|
|||||||
term.sort();
|
term.sort();
|
||||||
|
|
||||||
// Check duplicate variables
|
// Check duplicate variables
|
||||||
assert!(
|
assert!((term[..])
|
||||||
(term[..])
|
|
||||||
.windows(2)
|
.windows(2)
|
||||||
.all(|window| window[0].0 != window[1].0)
|
.all(|window| window[0].0 != window[1].0));
|
||||||
);
|
|
||||||
|
|
||||||
Mono { term }
|
Mono { term }
|
||||||
}
|
}
|
||||||
@@ -122,7 +120,7 @@ impl<V: Var> Display for Mono<V> {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|(t, p)| match p {
|
.map(|(t, p)| match p {
|
||||||
1 => format!("{t}"),
|
1 => format!("{t}"),
|
||||||
_ => format!("{t}{}",num_to_superscript(p.to_string())),
|
_ => format!("{t}{}", num_to_superscript(p.to_string())),
|
||||||
})
|
})
|
||||||
.join("")
|
.join("")
|
||||||
)
|
)
|
||||||
@@ -223,3 +221,106 @@ impl<V: Var> Sub for Poly<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mono_contains() {
|
||||||
|
let a: Mono<StaticVar> = [("x", 2), ("y", 1)].into();
|
||||||
|
|
||||||
|
// Lower exponent of same variable is contained
|
||||||
|
assert!(a.contains(&Mono::from([("x", 1)])));
|
||||||
|
|
||||||
|
// Higher exponent of same variable is not contained
|
||||||
|
assert!(!a.contains(&Mono::from([("x", 3)])));
|
||||||
|
|
||||||
|
// Identical monomial is contained
|
||||||
|
assert!(a.contains(&Mono::from([("x", 2), ("y", 1)])));
|
||||||
|
|
||||||
|
// Variable absent from self is not contained
|
||||||
|
assert!(!a.contains(&Mono::from([("x", 2), ("z", 1)])));
|
||||||
|
|
||||||
|
// Subset of variables with lower exponents is contained
|
||||||
|
assert!(a.contains(&Mono::from([("x", 1), ("y", 1)])));
|
||||||
|
|
||||||
|
// Single variable with exact exponent is contained
|
||||||
|
assert!(a.contains(&Mono::from([("x", 2)])));
|
||||||
|
|
||||||
|
// Insufficient exponent in self means not contained
|
||||||
|
assert!(!Mono::<StaticVar>::from([("x", 1)]).contains(&Mono::from([("x", 2)])));
|
||||||
|
|
||||||
|
// Missing variable in self means not contained
|
||||||
|
assert!(!Mono::<StaticVar>::from([("x", 1), ("y", 1)]).contains(&Mono::from([("x", 2)])));
|
||||||
|
assert!(!Mono::<StaticVar>::from([("x", 1)]).contains(&Mono::from([("x", 1), ("y", 1)])));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mono_mul() {
|
||||||
|
// Same variable: exponents add
|
||||||
|
let a: Mono<StaticVar> = [("x", 2)].into();
|
||||||
|
let b: Mono<StaticVar> = [("x", 3)].into();
|
||||||
|
assert_eq!(a * b, Mono::from([("x", 5)]));
|
||||||
|
|
||||||
|
// Disjoint variables: both appear in result
|
||||||
|
let a: Mono<StaticVar> = [("x", 2)].into();
|
||||||
|
let b: Mono<StaticVar> = [("y", 3)].into();
|
||||||
|
assert_eq!(a * b, Mono::from([("x", 2), ("y", 3)]));
|
||||||
|
|
||||||
|
// Mixed: shared and disjoint variables
|
||||||
|
let a: Mono<StaticVar> = [("x", 1), ("y", 2)].into();
|
||||||
|
let b: Mono<StaticVar> = [("y", 1), ("z", 3)].into();
|
||||||
|
assert_eq!(a * b, Mono::from([("x", 1), ("y", 3), ("z", 3)]));
|
||||||
|
|
||||||
|
// Commutativity
|
||||||
|
let a: Mono<StaticVar> = [("x", 2), ("z", 1)].into();
|
||||||
|
let b: Mono<StaticVar> = [("y", 3)].into();
|
||||||
|
assert_eq!(a.clone() * b.clone(), b * a);
|
||||||
|
|
||||||
|
// Multiply by constant monomial (empty term vec = 1)
|
||||||
|
let a: Mono<StaticVar> = [("x", 4)].into();
|
||||||
|
let one: Mono<StaticVar> = Mono { term: vec![] };
|
||||||
|
assert_eq!(a.clone() * one, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_poly_add() {
|
||||||
|
// Distinct monomials are collected as separate terms
|
||||||
|
let a: Poly<StaticVar> = [(1, [("x", 2)]), (2, [("y", 1)])].into();
|
||||||
|
let b: Poly<StaticVar> = [(3, [("z", 1)])].into();
|
||||||
|
let expected: Poly<StaticVar> = [(1, [("x", 2)]), (2, [("y", 1)]), (3, [("z", 1)])].into();
|
||||||
|
assert_eq!(a + b, expected);
|
||||||
|
|
||||||
|
// Coefficients of matching monomials are summed
|
||||||
|
let a: Poly<StaticVar> = [(2, [("x", 1)])].into();
|
||||||
|
let b: Poly<StaticVar> = [(3, [("x", 1)])].into();
|
||||||
|
let expected: Poly<StaticVar> = [(5, [("x", 1)])].into();
|
||||||
|
assert_eq!(a + b, expected);
|
||||||
|
|
||||||
|
// Terms that cancel sum to zero are dropped
|
||||||
|
let a: Poly<StaticVar> = [(1, [("x", 1)])].into();
|
||||||
|
let b: Poly<StaticVar> = [(-1, [("x", 1)])].into();
|
||||||
|
let expected: Poly<StaticVar> = Poly::default();
|
||||||
|
assert_eq!(a + b, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_poly_sub() {
|
||||||
|
// Distinct monomials are collected as separate terms with negated rhs coefficients
|
||||||
|
let a: Poly<StaticVar> = [(3, [("x", 2)])].into();
|
||||||
|
let b: Poly<StaticVar> = [(1, [("y", 1)])].into();
|
||||||
|
let expected: Poly<StaticVar> = [(3, [("x", 2)]), (-1, [("y", 1)])].into();
|
||||||
|
assert_eq!(a - b, expected);
|
||||||
|
|
||||||
|
// Coefficients of matching monomials are subtracted
|
||||||
|
let a: Poly<StaticVar> = [(5, [("x", 1)])].into();
|
||||||
|
let b: Poly<StaticVar> = [(3, [("x", 1)])].into();
|
||||||
|
let expected: Poly<StaticVar> = [(2, [("x", 1)])].into();
|
||||||
|
assert_eq!(a - b, expected);
|
||||||
|
|
||||||
|
// Subtracting equal polynomials yields zero
|
||||||
|
let a: Poly<StaticVar> = [(4, [("x", 2)]), (1, [("y", 1)])].into();
|
||||||
|
let b: Poly<StaticVar> = [(4, [("x", 2)]), (1, [("y", 1)])].into();
|
||||||
|
assert_eq!(a - b, Poly::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user