use crate::natural::Natural;
use crate::natural_polynomial::conversion::string::from_string::from_string_with;
use crate::natural_polynomial::conversion::string::to_string::Language;
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
use malachite_base::named::Named;
use malachite_base::num::basic::traits::{One, Two, Zero};
use malachite_base::num::conversion::traits::ExactFrom;
use malachite_base::polynomial::Polynomial;
use malachite_base::vars::{Var, VarScheme};
pub mod arithmetic;
pub mod comparison;
pub mod conversion;
pub mod exhaustive;
#[cfg(feature = "random")]
pub mod random;
pub(crate) static ZERO: Natural = Natural::ZERO;
#[derive(Clone, Default, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(
feature = "serde",
serde(try_from = "SerdeNaturalPolynomial", into = "SerdeNaturalPolynomial")
)]
pub struct NaturalPolynomial {
coefficients: Vec<Natural>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub(crate) struct SerdeNaturalPolynomial(pub(crate) Vec<Natural>);
impl Zero for NaturalPolynomial {
const ZERO: Self = Self {
coefficients: Vec::new(),
};
}
impl NaturalPolynomial {
#[cfg(feature = "test_build")]
pub fn is_valid(&self) -> bool {
self.coefficients.last() != Some(&Natural::ZERO)
}
fn trim(&mut self) {
while self.coefficients.last() == Some(&Natural::ZERO) {
self.coefficients.pop();
}
}
#[inline]
pub fn coefficients_asc(&self) -> &[Natural] {
&self.coefficients
}
}
impl Polynomial for NaturalPolynomial {
type Coefficient = Natural;
type CoefficientOutput<'a>
= &'a Natural
where
Self: 'a;
fn one() -> Self {
Self {
coefficients: vec![Natural::ONE],
}
}
fn two() -> Self {
Self {
coefficients: vec![Natural::TWO],
}
}
fn x() -> Self {
Self {
coefficients: vec![Natural::ZERO, Natural::ONE],
}
}
fn from_coefficients_asc(coefficients: Vec<Natural>) -> Self {
let mut p = Self { coefficients };
p.trim();
p
}
#[inline]
fn into_coefficients_asc(self) -> Vec<Natural> {
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) -> &Natural {
usize::try_from(index)
.ok()
.and_then(|i| self.coefficients.get(i))
.unwrap_or(&ZERO)
}
#[inline]
fn leading_coefficient(&self) -> &Natural {
self.coefficients.last().unwrap_or(&ZERO)
}
#[inline]
fn is_monic(&self) -> bool {
self.coefficients.last().is_some_and(|c| *c == 1u32)
}
fn mutate_coefficient<F: FnOnce(&mut Natural) -> T, T>(&mut self, index: u64, f: F) -> T {
let index = usize::exact_from(index);
if index >= self.coefficients.len() {
self.coefficients.resize(index + 1, Natural::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(Natural::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 != 0u32)
.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![Natural::ZERO; usize::exact_from(len) - kept];
coefficients.extend(self.coefficients[..kept].iter().rev().cloned());
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, Natural::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!(NaturalPolynomial);