mod arithmetic;
mod conversion;
mod display;
mod division;
use super::traits::Ring;
use num_rational::Ratio;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Poly<T: Ring> {
coeffs: Vec<T>,
}
pub type IntPoly = Poly<i64>;
pub type RationalPoly = Poly<Ratio<i64>>;
impl<T: Ring> Poly<T> {
#[inline(always)]
pub fn from_coeffs(mut coeffs: Vec<T>) -> Self {
while coeffs.last().is_some_and(|c| c.is_zero()) {
coeffs.pop();
}
Self { coeffs }
}
#[inline(always)]
pub fn zero() -> Self {
Self { coeffs: Vec::new() }
}
#[inline(always)]
pub fn constant(c: T) -> Self {
if c.is_zero() {
Self::zero()
} else {
Self { coeffs: vec![c] }
}
}
#[inline(always)]
pub fn is_zero(&self) -> bool {
self.coeffs.is_empty()
}
#[inline(always)]
pub fn is_constant(&self) -> bool {
self.coeffs.len() <= 1
}
#[inline(always)]
pub fn degree(&self) -> Option<usize> {
if self.coeffs.is_empty() {
None
} else {
Some(self.coeffs.len() - 1)
}
}
#[inline(always)]
pub fn leading_coeff(&self) -> T {
self.coeffs.last().cloned().unwrap_or_else(T::zero)
}
#[inline(always)]
pub fn coeff(&self, i: usize) -> T {
self.coeffs.get(i).cloned().unwrap_or_else(T::zero)
}
#[inline(always)]
pub fn coefficients(&self) -> &[T] {
&self.coeffs
}
}
impl IntPoly {
#[inline(always)]
pub fn monomial(n: usize) -> Self {
let mut coeffs = vec![0; n + 1];
coeffs[n] = 1;
Self { coeffs }
}
#[inline(always)]
pub fn term(coeff: i64, power: usize) -> Self {
if coeff == 0 {
Self::zero()
} else {
let mut coeffs = vec![0; power + 1];
coeffs[power] = coeff;
Self { coeffs }
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_construction() {
let p = IntPoly::from_coeffs(vec![1, 2, 3]);
assert_eq!(p.degree(), Some(2));
assert_eq!(p.leading_coeff(), 3);
assert_eq!(p.coeff(0), 1);
assert_eq!(p.coeff(1), 2);
assert_eq!(p.coeff(2), 3);
assert_eq!(p.coeff(3), 0);
}
#[test]
fn test_zero_polynomial() {
let z = IntPoly::zero();
assert!(z.is_zero());
assert_eq!(z.degree(), None);
assert_eq!(z.leading_coeff(), 0);
}
#[test]
fn test_trailing_zeros_removed() {
let p = IntPoly::from_coeffs(vec![1, 2, 0, 0, 0]);
assert_eq!(p.degree(), Some(1));
assert_eq!(p.coefficients(), &[1, 2]);
}
#[test]
fn test_constant_polynomial() {
let p = IntPoly::constant(5);
assert!(p.is_constant());
assert_eq!(p.degree(), Some(0));
assert_eq!(p.coeff(0), 5);
let z = IntPoly::constant(0);
assert!(z.is_zero());
assert_eq!(z.degree(), None);
}
#[test]
fn test_rational_poly_construction() {
let p =
RationalPoly::from_coeffs(vec![Ratio::new(1, 2), Ratio::new(3, 4), Ratio::new(5, 6)]);
assert_eq!(p.degree(), Some(2));
assert_eq!(p.leading_coeff(), Ratio::new(5, 6));
assert_eq!(p.coeff(0), Ratio::new(1, 2));
}
#[test]
fn test_rational_poly_zero() {
let z = RationalPoly::zero();
assert!(z.is_zero());
assert_eq!(z.degree(), None);
assert_eq!(z.leading_coeff(), Ratio::new(0, 1));
}
}