use crate::named::Named;
use crate::num::basic::traits::Zero;
use crate::num::basic::unsigneds::PrimitiveUnsigned;
use crate::num::conversion::traits::ExactFrom;
use crate::polynomial::Polynomial;
use crate::unsigned_polynomial::conversion::string::from_string::from_string_with;
use crate::unsigned_polynomial::conversion::string::to_string::Language;
use crate::vars::{Var, VarScheme};
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
pub mod arithmetic;
pub mod comparison;
pub mod conversion;
pub mod exhaustive;
#[cfg(feature = "random")]
pub mod random;
#[derive(Clone, Default, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(
feature = "serde",
serde(
try_from = "SerdeUnsignedPolynomial<T>",
into = "SerdeUnsignedPolynomial<T>"
)
)]
pub struct UnsignedPolynomial<T: PrimitiveUnsigned> {
coefficients: Vec<T>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub(crate) struct SerdeUnsignedPolynomial<T: PrimitiveUnsigned>(pub(crate) Vec<T>);
impl<T: PrimitiveUnsigned> Zero for UnsignedPolynomial<T> {
const ZERO: Self = Self {
coefficients: Vec::new(),
};
}
impl<T: PrimitiveUnsigned> UnsignedPolynomial<T> {
#[cfg(feature = "test_build")]
pub fn is_valid(&self) -> bool {
self.coefficients.last() != Some(&T::ZERO)
}
fn trim(&mut self) {
while self.coefficients.last() == Some(&T::ZERO) {
self.coefficients.pop();
}
}
#[inline]
pub fn coefficients_asc(&self) -> &[T] {
&self.coefficients
}
}
macro_rules! impl_named_unsigned_polynomial {
($t:ident, $name:expr) => {
impl Named for UnsignedPolynomial<$t> {
const NAME: &'static str = $name;
}
};
}
impl<T: PrimitiveUnsigned> Polynomial for UnsignedPolynomial<T> {
type Coefficient = T;
type CoefficientOutput<'a>
= T
where
Self: 'a;
fn one() -> Self {
Self {
coefficients: vec![T::ONE],
}
}
fn two() -> Self {
Self {
coefficients: vec![T::TWO],
}
}
fn x() -> Self {
Self {
coefficients: vec![T::ZERO, T::ONE],
}
}
fn from_coefficients_asc(coefficients: Vec<T>) -> Self {
let mut p = Self { coefficients };
p.trim();
p
}
#[inline]
fn into_coefficients_asc(self) -> Vec<T> {
self.coefficients
}
#[inline]
fn degree(&self) -> Option<u64> {
self.coefficients.len().checked_sub(1).map(u64::exact_from)
}
#[inline]
fn len(&self) -> u64 {
u64::exact_from(self.coefficients.len())
}
#[inline]
fn coefficient(&self, index: u64) -> T {
usize::try_from(index)
.ok()
.and_then(|i| self.coefficients.get(i))
.copied()
.unwrap_or(T::ZERO)
}
#[inline]
fn leading_coefficient(&self) -> T {
self.coefficients.last().copied().unwrap_or(T::ZERO)
}
#[inline]
fn is_monic(&self) -> bool {
self.coefficients.last() == Some(&T::ONE)
}
fn mutate_coefficient<F: FnOnce(&mut T) -> U, U>(&mut self, index: u64, f: F) -> U {
let index = usize::exact_from(index);
if index >= self.coefficients.len() {
self.coefficients.resize(index + 1, T::ZERO);
}
let out = f(&mut self.coefficients[index]);
self.trim();
out
}
fn zero_coefficients(&mut self, start: u64, end: u64) {
assert!(start <= end);
let len = self.coefficients.len();
let Ok(start) = usize::try_from(start) else {
return;
};
if start >= len {
return;
}
let end = usize::try_from(end).map_or(len, |end| end.min(len));
if end == len {
self.coefficients.truncate(start);
self.trim();
} else {
self.coefficients[start..end].fill(T::ZERO);
}
}
fn truncate(&self, len: u64) -> Self {
let kept = usize::try_from(len).map_or(self.coefficients.len(), |len| {
len.min(self.coefficients.len())
});
let kept = self.coefficients[..kept]
.iter()
.rposition(|c| *c != T::ZERO)
.map_or(0, |i| i + 1);
Self {
coefficients: self.coefficients[..kept].to_vec(),
}
}
fn truncate_assign(&mut self, len: u64) {
if let Ok(len) = usize::try_from(len)
&& len < self.coefficients.len()
{
self.coefficients.truncate(len);
self.trim();
}
}
fn reverse(&self, len: u64) -> Self {
let kept = usize::try_from(len).map_or(self.coefficients.len(), |len| {
len.min(self.coefficients.len())
});
if kept == 0 {
return Self::ZERO;
}
let mut coefficients = vec![T::ZERO; usize::exact_from(len) - kept];
coefficients.extend(self.coefficients[..kept].iter().rev().copied());
Self::from_coefficients_asc(coefficients)
}
fn reverse_assign(&mut self, len: u64) {
let kept = usize::try_from(len).map_or(self.coefficients.len(), |len| {
len.min(self.coefficients.len())
});
if kept == 0 {
*self = Self::ZERO;
return;
}
self.coefficients.truncate(kept);
self.coefficients.reverse();
let len = usize::exact_from(len);
self.coefficients.resize(len, T::ZERO);
self.coefficients.rotate_right(len - kept);
self.trim();
}
fn to_string_with<S: VarScheme + ?Sized>(&self, var: Var<'_, S>) -> String {
let mut s = String::new();
self.write_with_var(var, Language::Plain, &mut s).unwrap();
s
}
fn to_latex_string_with<S: VarScheme + ?Sized>(&self, var: Var<'_, S>) -> String {
let mut s = String::new();
self.write_with_var(var, Language::Latex, &mut s).unwrap();
s
}
fn to_typst_string_with<S: VarScheme + ?Sized>(&self, var: Var<'_, S>) -> String {
let mut s = String::new();
self.write_with_var(var, Language::Typst, &mut s).unwrap();
s
}
#[inline]
fn from_string_with<S: VarScheme + ?Sized>(var: Var<'_, S>, s: &str) -> Option<Self> {
from_string_with(var, s)
}
}
impl_named_unsigned_polynomial!(u8, "UnsignedPolynomial<u8>");
impl_named_unsigned_polynomial!(u16, "UnsignedPolynomial<u16>");
impl_named_unsigned_polynomial!(u32, "UnsignedPolynomial<u32>");
impl_named_unsigned_polynomial!(u64, "UnsignedPolynomial<u64>");
impl_named_unsigned_polynomial!(u128, "UnsignedPolynomial<u128>");
impl_named_unsigned_polynomial!(usize, "UnsignedPolynomial<usize>");