#![doc = include_str!("../README.md")]
#![cfg_attr(not(any(feature = "std", test, doctest)), no_std)]
pub mod internal;
#[cfg(any(test, doctest))]
mod tests;
pub use ::num_complex::Complex;
use {
crate::internal::*,
::arrayvec::ArrayVec,
::core::{fmt::Debug, ops::Deref},
::num_traits::{
float::{Float, FloatConst},
identities::Zero,
MulAdd,
},
};
pub fn aberth<
const TERMS: usize,
F: Float + FloatConst + MulAdd<Output = F> + Debug,
C: ComplexCoefficient<F> + Into<Complex<F>>,
>(
polynomial: &[C; TERMS],
max_iterations: u32,
epsilon: F,
) -> Roots<ArrayVec<Complex<F>, TERMS>> {
let degree = TERMS - 1;
let polynomial: &[Complex<F>; TERMS] = &polynomial.map(|v| v.into());
let mut dydx: ArrayVec<_, TERMS> = ArrayVec::new_const();
unsafe {
dydx.set_len(degree);
derivative::<F>(polynomial, dydx.as_mut());
}
let mut guesses: ArrayVec<_, TERMS> = ArrayVec::new_const();
unsafe {
guesses.set_len(TERMS);
initial_guesses(polynomial, guesses.as_mut());
guesses.set_len(degree);
}
let mut output: ArrayVec<_, TERMS> = ArrayVec::new_const();
unsafe {
for _ in 0..degree {
output.push_unchecked(Complex::zero());
}
}
let stop_reason = aberth_raw(
polynomial,
dydx.as_ref(),
guesses.as_mut(),
output.as_mut(),
max_iterations,
epsilon,
);
Roots {
roots: output,
stop_reason,
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Roots<Arr> {
pub roots: Arr,
pub stop_reason: StopReason,
}
impl<Arr> Deref for Roots<Arr> {
type Target = Arr;
fn deref(&self) -> &Arr {
&self.roots
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum StopReason {
Converged( u32),
MaxIteration( u32),
Failed( u32),
}
#[cfg(feature = "std")]
pub use feature_std::AberthSolver;
#[cfg(feature = "std")]
mod feature_std {
use {
crate::{internal::*, Roots},
::core::fmt::Debug,
::num_complex::Complex,
::num_traits::{
cast,
float::{Float, FloatConst},
identities::Zero,
MulAdd,
},
};
impl<F: Clone> Roots<&[Complex<F>]> {
pub fn to_owned(&self) -> Roots<Vec<Complex<F>>> {
Roots {
roots: self.roots.to_vec(),
stop_reason: self.stop_reason,
}
}
}
#[derive(Debug, Clone)]
pub struct AberthSolver<F>
where
F: Float,
{
pub max_iterations: u32,
pub epsilon: F,
data: Vec<Complex<F>>,
}
impl<F: Float + FloatConst + MulAdd<Output = F> + Default + Debug> Default
for AberthSolver<F>
{
fn default() -> Self {
AberthSolver::new()
}
}
impl<F: Float + FloatConst + MulAdd<Output = F> + Default + Debug>
AberthSolver<F>
{
pub fn new() -> Self {
AberthSolver {
max_iterations: 100,
data: Vec::new(),
epsilon: cast(0.001).unwrap(),
}
}
pub fn find_roots<C: ComplexCoefficient<F>>(
&mut self,
polynomial: &[C],
) -> Roots<&[Complex<F>]> {
let len = polynomial.len();
let degree = len - 1;
self
.data
.resize_with(len + degree + len + degree, Complex::zero);
let (complex_poly, tail) = self.data.split_at_mut(len);
let (dydx, tail) = tail.split_at_mut(degree);
let (guesses, output) = tail.split_at_mut(len);
polynomial
.iter()
.enumerate()
.for_each(|(i, &coefficient)| complex_poly[i] = coefficient.into());
initial_guesses(complex_poly, guesses);
let guesses = &mut guesses[0..degree];
derivative(complex_poly, dydx);
let stop_reason = aberth_raw(
complex_poly,
dydx,
guesses,
output,
self.max_iterations,
self.epsilon,
);
Roots {
roots: output,
stop_reason,
}
}
}
}