use num::ToPrimitive;
use crate::{PolyError, Result};
#[allow(rustdoc::broken_intra_doc_links)]
#[derive(Debug)]
pub struct Polynomial<T> {
pub coef: Vec<T>,
}
impl<T> Polynomial<T>
where
T: num::complex::ComplexFloat,
{
pub fn build(coef: &[T]) -> Result<Self> {
match coef.iter().any(|x| x.is_nan() | x.is_infinite()) {
true => Err(PolyError::InvalidCoefficients),
false => Ok(Polynomial {
coef: coef.to_vec(),
}),
}
}
pub fn trim(&mut self) {
self.coef = crate::utils::trim_trailing_zeros(&self.coef)
}
pub fn eval(&self, x: T) -> T {
self.coef
.iter()
.rev()
.copied()
.reduce(|res, coef| coef + x * res)
.unwrap_or(T::zero())
}
pub fn eval_derivs(&self, x: T, n: usize) -> Vec<T> {
let mut res: Vec<T> = vec![T::zero(); n];
let last_idx = self.coef.len() - 1;
let nmax = self.coef.len().min(res.len()) - 1;
res.iter_mut()
.take(nmax + 1)
.for_each(|e| *e = *self.coef.last().unwrap());
for i in 0..last_idx {
let k = last_idx - i;
res[0] = x * res[0] + self.coef[k - 1];
let jmax = if nmax < k { nmax } else { k - 1 };
for j in 1..=jmax {
res[j] = x * res[j] + res[j - 1];
}
}
let mut f = T::one();
for (i, d) in res.iter_mut().enumerate().take(nmax + 1).skip(2) {
f = f * T::from(i).unwrap();
*d = *d * f;
}
res
}
#[doc(alias = "gsl_poly_solve_quadratic")]
pub fn solve_real_quadratic(&self) -> Result<Vec<f64>> {
crate::utils::check_if_correct_order(&self.coef, 2)?;
crate::utils::check_if_real_coefficients(&self.coef)?;
let a = self.coef[2].re().to_f64().expect("Error converting to f64");
let b = self.coef[1].re().to_f64().expect("Error converting to f64");
let c = self.coef[0].re().to_f64().expect("Error converting to f64");
crate::solve::solve_real_quadratic(a, b, c)
}
}