use num_complex::{Complex, ComplexFloat};
use std::cmp::Ordering;
use crate::error::{Error, Result};
use crate::matrix::{FloatComplex, matrix_access_mut, matrix_mul, matrix_trans, matrix_inv};
pub fn poly_val<T>(p: &[T], k: usize, x: T) -> T
where
T: Copy + std::ops::Mul<Output = T> + std::ops::Add<Output = T> + From<f32>,
{
let mut xk = T::from(1.0);
let mut y = T::from(0.0);
for i in 0..k {
y = y + p[i] * xk;
xk = xk * x;
}
y
}
pub fn poly_fit<T>(x: &[T], y: &[T], n: usize, p: &mut [T], k: usize) -> Result<()>
where
T: FloatComplex
{
let mut x_matrix = vec![T::default(); n * k];
for r in 0..n {
let mut v = T::one();
for c in 0..k {
matrix_access_mut(&mut x_matrix, n, k, r, c, v);
v = v * x[r];
}
}
let mut xt_matrix = x_matrix.clone();
matrix_trans(&mut xt_matrix, n, k);
let mut xty = vec![T::default(); k];
matrix_mul(&xt_matrix, k, n, y, n, 1, &mut xty, k, 1)?;
let mut x2 = vec![T::default(); k * k];
matrix_mul(&xt_matrix, k, n, &x_matrix, n, k, &mut x2, k, k)?;
let mut g = x2.clone();
matrix_inv(&mut g, k, k)?;
matrix_mul(&g, k, k, &xty, k, 1, p, k, 1)?;
Ok(())
}
pub fn poly_expandbinomial<T>(n: usize, c: &mut [T]) -> ()
where
T: Copy + std::ops::Mul<Output = T> + std::ops::Add<Output = T> + From<f32>,
{
if n == 0 {
c[0] = T::from(0.0);
return;
}
c[0] = T::from(1.0);
for i in 1..=n {
c[i] = T::from(0.0);
}
for i in 0..n {
for j in (1..=i+1).rev() {
c[j] = c[j] + c[j-1];
}
}
}
pub fn poly_expandbinomial_pm<T>(m: usize, k: usize, c: &mut [T]) -> ()
where
T: Copy + std::ops::Mul<Output = T> + std::ops::Add<Output = T> + std::ops::Sub<Output = T> + From<f32>,
{
let n = m + k;
if n == 0 {
c[0] = T::from(0.0);
return;
}
c[0] = T::from(1.0);
for i in 1..=n {
c[i] = T::from(0.0);
}
for i in 0..m {
for j in (1..=i+1).rev() {
c[j] = c[j] + c[j-1];
}
}
for i in m..n {
for j in (1..=i+1).rev() {
c[j] = c[j] - c[j-1];
}
}
}
pub fn poly_expandroots<T>(r: &[T], n: usize, p: &mut [T]) -> ()
where
T: Copy + std::ops::Mul<Output = T> + std::ops::Add<Output = T> + std::ops::Neg<Output = T> + From<f32>,
{
if n == 0 {
p[0] = T::from(0.0);
return;
}
p[0] = T::from(1.0);
for i in 1..=n {
p[i] = T::from(0.0);
}
for i in 0..n {
for j in (1..=i+1).rev() {
p[j] = -r[i] * p[j] + p[j-1];
}
p[0] = -r[i] * p[0];
}
}
pub fn poly_expandroots2<T>(a: &[T], b: &[T], n: usize, p: &mut [T]) -> ()
where
T: Copy + std::ops::Mul<Output = T> + std::ops::Add<Output = T> + std::ops::Neg<Output = T> + std::ops::Div<Output = T> + From<f32>,
{
let mut g = T::from(1.0);
let mut r = vec![T::from(0.0); n];
for i in 0..n {
g = g * -b[i];
r[i] = a[i] / b[i];
}
poly_expandroots(&r, n, p);
for i in 0..=n {
p[i] = g * p[i];
}
}
pub fn poly_mul<T>(a: &[T], order_a: usize, b: &[T], order_b: usize, c: &mut [T]) -> ()
where
T: Copy + std::ops::Mul<Output = T> + std::ops::Add<Output = T> + From<f32>,
{
let na = order_a + 1;
let nb = order_b + 1;
let nc = na + nb - 1;
for i in 0..nc {
c[i] = T::from(0.0);
}
for i in 0..na {
for j in 0..nb {
c[i+j] = c[i+j] + a[i] * b[j];
}
}
}
pub fn poly_interp_lagrange<T>(x: &[T], y: &[T], n: usize, x0: T) -> T
where
T: Copy + std::ops::Mul<Output = T> + std::ops::Add<Output = T> + std::ops::Sub<Output = T> + std::ops::Div<Output = T> + From<f32>,
{
let mut y0 = T::from(0.0);
for i in 0..n {
let mut g = T::from(1.0);
for j in 0..n {
if i == j {
continue;
}
g = g * (x0 - x[j]) / (x[i] - x[j]);
}
y0 = y0 + y[i] * g;
}
y0
}
pub fn poly_fit_lagrange<T>(x: &[T], y: &[T], n: usize, p: &mut [T]) -> ()
where
T: Copy + std::ops::Mul<Output = T> + std::ops::Add<Output = T> + std::ops::Sub<Output = T> + std::ops::Div<Output = T> + std::ops::Neg<Output = T> + From<f32>,
{
let k = n - 1;
for i in 0..n {
p[i] = T::from(0.0);
}
let mut roots = vec![T::from(0.0); k];
let mut c = vec![T::from(0.0); n];
for i in 0..n {
let mut idx = 0;
let mut g = T::from(1.0);
for j in 0..n {
if i == j {
continue;
}
roots[idx] = x[j];
g = g * (x[i] - x[j]);
idx += 1;
}
g = y[i] / g;
poly_expandroots(&roots, k, &mut c);
for j in 0..n {
p[j] = p[j] + g * c[j];
}
}
}
pub fn poly_fit_lagrange_barycentric<T>(x: &[T], n: usize, w: &mut [T]) -> ()
where
T: Copy + std::ops::Mul<Output = T> + std::ops::Add<Output = T> + std::ops::Sub<Output = T> + std::ops::Div<Output = T> + std::ops::Neg<Output = T> + From<f32> + PartialEq,
{
for j in 0..n {
w[j] = T::from(1.0);
for k in 0..n {
if j == k {
continue;
}
w[j] = w[j] * (x[j] - x[k]);
}
if w[j] == T::from(0.0) {
w[j] = w[j] + T::from(1.0e-9);
}
w[j] = T::from(1.0) / w[j];
}
let w0 = w[0] + T::from(1.0e-9);
for j in 0..n {
w[j] = w[j] / w0;
}
}
pub fn poly_val_lagrange_barycentric<T>(x: &[T], y: &[T], w: &[T], x0: T, n: usize) -> T
where
T: FloatComplex,
{
let mut t0 = T::from(0.0).unwrap();
let mut t1 = T::from(0.0).unwrap();
let tol = T::Real::from(1.0e-6);
for j in 0..n {
let g = x0 - x[j];
if g.abs() < tol {
return y[j];
}
t0 = t0 + w[j] * y[j] / g;
t1 = t1 + w[j] / g;
}
t0 / t1
}
pub fn poly_findroots_durandkerner(
p: &[f64],
k: usize,
roots: &mut [Complex<f64>],
) -> Result<()> {
if k < 2 {
return Err(Error::Range("order must be greater than 0".to_owned()));
}
if p[k - 1] != 1.0 {
return Err(Error::Range("p[k-1] must be equal to 1".to_owned()));
}
let num_roots = k - 1;
let mut r0 = vec![0.0; num_roots];
let mut r1 = vec![0.0; num_roots];
let mut g: f64;
let mut gmax = 0.0;
for i in 0..k {
g = p[i].abs();
if i == 0 || g > gmax {
gmax = g;
}
}
let t0 = 0.9 * (1.0 + gmax) * Complex::new(0.0, 1.1526).exp().re();
let mut t = 1.0;
for i in 0..num_roots {
r0[i] = t;
t *= t0;
}
let max_num_iterations = 50;
let mut continue_iterating = true;
let mut i = 0;
let tol = 1e-6;
while continue_iterating {
for j in 0..num_roots {
let f = poly_val(p, k, r0[j]);
let mut fp = 1.0;
for l in 0..num_roots {
if l == j {
continue;
}
fp *= r0[j] - r0[l];
}
r1[j] = r0[j] - f / fp;
}
let mut delta = 0.0;
for j in 0..num_roots {
let e = r0[j] - r1[j];
delta += (e * e.conj()).re();
}
delta /= num_roots as f64 * gmax;
if delta < tol || i == max_num_iterations {
continue_iterating = false;
}
r0.copy_from_slice(&r1);
i += 1;
}
for i in 0..k {
roots[i] = Complex::new(r1[i], 0.0);
}
Ok(())
}
pub fn poly_findroots_bairstow(
p: &[f64],
k: usize,
roots: &mut [Complex<f64>],
) -> Result<()> {
let mut p0 = vec![0.0; k];
let mut p1 = vec![0.0; k];
let mut p_buf;
let mut pr_buf = &mut p1;
p0.copy_from_slice(p);
let mut n = k;
let r = k % 2;
let l = (k - r) / 2;
let mut root_index = 0;
for i in 0..l - 1 + r {
if i % 2 == 0 {
p_buf = &mut p0;
pr_buf = &mut p1;
} else {
p_buf = &mut p1;
pr_buf = &mut p0;
}
if p_buf[n - 1] == 0.0 {
p_buf[n - 1] = 1e-12;
}
let mut u = p_buf[n - 2] / p_buf[n - 1];
let mut v = p_buf[n - 3] / p_buf[n - 1];
if n > 3 {
poly_findroots_bairstow_persistent(p_buf, n, pr_buf, &mut u, &mut v)?;
}
let r0 = Complex::new(-0.5 * u, 0.0) + 0.5 * Complex::new(u * u - 4.0 * v, 0.0).sqrt();
let r1 = Complex::new(-0.5 * u, 0.0) - 0.5 * Complex::new(u * u - 4.0 * v, 0.0).sqrt();
roots[root_index] = r0;
roots[root_index + 1] = r1;
root_index += 2;
n -= 2;
}
if r == 0 {
roots[root_index] = Complex::new(-pr_buf[0] / pr_buf[1], 0.0);
}
Ok(())
}
fn poly_findroots_bairstow_recursion(
p: &[f64],
k: usize,
p1: &mut [f64],
u: &mut f64,
v: &mut f64,
) -> Result<()> {
if k < 3 {
return Err(Error::Range(format!("invalid polynomial length: {}", k)));
}
let tol = 1e-12;
let num_iterations_max = 20;
let n = k - 1;
let mut b = vec![0.0; k];
let mut f = vec![0.0; k];
b[n] = 0.0;
b[n - 1] = 0.0;
f[n] = 0.0;
f[n - 1] = 0.0;
let mut num_iterations = 0;
loop {
if num_iterations == num_iterations_max {
return Err(Error::NoConvergence(format!("failed to converge after {} iterations", num_iterations_max)));
}
num_iterations += 1;
for i in (0..=n - 2).rev() {
b[i] = p[i + 2] - *u * b[i + 1] - *v * b[i + 2];
f[i] = b[i + 2] - *u * f[i + 1] - *v * f[i + 2];
}
let c = p[1] - *u * b[0] - *v * b[1];
let g = b[1] - *u * f[0] - *v * f[1];
let d = p[0] - *v * b[0];
let h = b[0] - *v * f[0];
let q0 = *v * g * g;
let q1 = h * (h - *u * g);
let metric = (q0 + q1).abs();
if metric < tol {
*u *= 0.5;
*v *= 0.5;
continue;
}
let q = 1.0 / (*v * g * g + h * (h - *u * g));
let du = -q * (-h * c + g * d);
let dv = -q * (-g * *v * c + (g * *u - h) * d);
let step = du.abs() + dv.abs();
*u += du;
*v += dv;
if step < tol {
break;
}
}
for i in 0..k - 2 {
p1[i] = b[i];
}
Ok(())
}
fn poly_findroots_bairstow_persistent(
p: &[f64],
k: usize,
p1: &mut [f64],
u: &mut f64,
v: &mut f64,
) -> Result<()> {
let num_iterations_max = 10;
for i in 0..num_iterations_max {
if poly_findroots_bairstow_recursion(p, k, p1, u, v).is_ok() {
return Ok(());
} else if i < num_iterations_max - 1 {
*u = (i as f64 * 1.1).cos() * (i as f64 * 0.2).exp();
*v = (i as f64 * 1.1).sin() * (i as f64 * 0.2).exp();
}
}
Err(Error::NoConvergence(format!("failed to converge after {} iterations", num_iterations_max)))
}
pub fn poly_sort_roots_compare(a: &Complex<f64>, b: &Complex<f64>) -> Ordering {
let ar = a.re;
let br = b.re;
let ai = a.im;
let bi = b.im;
if ar == br {
if ai > bi {
Ordering::Less
} else {
Ordering::Greater
}
} else if ar > br {
Ordering::Greater
} else {
Ordering::Less
}
}
pub fn polyf_findroots(p: &[f32], k: usize, roots: &mut [Complex<f32>]) -> Result<()> {
if k < 2 {
return Err(Error::Range(format!("invalid polynomial length: {}", k)));
}
let p_double: Vec<f64> = p.iter().map(|&x| x as f64).collect();
let mut roots_double = vec![Complex::new(0.0, 0.0); k - 1];
poly_findroots_bairstow(&p_double, k, &mut roots_double)?;
roots_double.sort_by(poly_sort_roots_compare);
for i in 0..k - 1 {
roots[i] = Complex::new(roots_double[i].re as f32, roots_double[i].im as f32);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
use test_macro::autotest_annotate;
#[test]
#[autotest_annotate(autotest_polyf_fit_q3n3)]
fn test_polyf_fit_q3n3() {
let x = [-1.0, 0.0, 1.0];
let y = [1.0, 0.0, 1.0];
let p_test = [0.0, 0.0, 1.0];
let n = 3;
let mut p = [0.0; 3];
let k = 3;
let tol = 1e-3;
poly_fit(&x, &y, n, &mut p, k).unwrap();
assert_relative_eq!(p[0], p_test[0], epsilon = tol);
assert_relative_eq!(p[1], p_test[1], epsilon = tol);
assert_relative_eq!(p[2], p_test[2], epsilon = tol);
}
#[test]
#[autotest_annotate(autotest_polyf_lagrange_issue165)]
fn test_polyf_lagrange_issue165() {
let x = [-1.0, 0.0, 1.0];
let y = [7.059105, 24.998369, 14.365907];
let mut p = [0.0f32; 3];
let n = 3;
let tol = 1e-3;
poly_fit_lagrange(&x, &y, n, &mut p);
let mut y_out = vec![0.0; n];
for j in 0..n {
y_out[j] = poly_val(&p, n, x[j]);
assert_relative_eq!(y[j], y_out[j], epsilon = tol);
}
poly_fit(&x, &y, n, &mut p, n).unwrap();
for j in 0..n {
y_out[j] = poly_val(&p, n, x[j]);
assert_relative_eq!(y[j], y_out[j], epsilon = tol);
}
}
#[test]
#[autotest_annotate(autotest_polyf_lagrange)]
fn test_polyf_lagrange() {
let x = [1.0, 2.0, 3.0];
let y = [1.0, 8.0, 27.0];
let mut p = [0.0f32; 3];
let n = 3;
let tol = 1e-3f32;
poly_fit_lagrange(&x, &y, n, &mut p);
let mut y_out = vec![0.0; n];
for j in 0..n {
y_out[j] = poly_val(&p, n, x[j]);
assert_relative_eq!(y[j], y_out[j], epsilon = tol);
}
}
#[test]
#[autotest_annotate(autotest_polyf_expandroots_4)]
fn test_polyf_expandroots_4() {
let roots = [-2.0, -1.0, -4.0, 5.0, 3.0];
let c_test = [120.0, 146.0, 1.0, -27.0, -1.0, 1.0];
let n = 5;
let mut p = vec![0.0; n+1];
let tol = 1e-3;
poly_expandroots(&roots, n, &mut p);
assert_relative_eq!(p[0], c_test[0], epsilon = tol);
assert_relative_eq!(p[1], c_test[1], epsilon = tol);
assert_relative_eq!(p[2], c_test[2], epsilon = tol);
assert_relative_eq!(p[3], c_test[3], epsilon = tol);
assert_relative_eq!(p[4], c_test[4], epsilon = tol);
assert_relative_eq!(p[5], c_test[5], epsilon = tol);
}
#[test]
#[autotest_annotate(autotest_polyf_expandroots_11)]
fn test_polyf_expandroots_11() {
let roots = [-1.0, -2.0, -3.0, -4.0, -5.0, -6.0, -7.0, -8.0, -9.0, -10.0, -11.0];
let c_test = [39916800.0, 120543840.0, 150917976.0, 105258076.0, 45995730.0, 13339535.0, 2637558.0, 357423.0, 32670.0, 1925.0, 66.0, 1.0];
let n = 11;
let mut p = vec![0.0; n+1];
let tol = 1e-6f32;
poly_expandroots(&roots, n, &mut p);
assert_relative_eq!(p[0], c_test[0], epsilon = (tol*c_test[0]).abs());
assert_relative_eq!(p[1], c_test[1], epsilon = (tol*c_test[1]).abs());
assert_relative_eq!(p[2], c_test[2], epsilon = (tol*c_test[2]).abs());
assert_relative_eq!(p[3], c_test[3], epsilon = (tol*c_test[3]).abs());
assert_relative_eq!(p[4], c_test[4], epsilon = (tol*c_test[4]).abs());
assert_relative_eq!(p[5], c_test[5], epsilon = (tol*c_test[5]).abs());
assert_relative_eq!(p[6], c_test[6], epsilon = (tol*c_test[6]).abs());
assert_relative_eq!(p[7], c_test[7], epsilon = (tol*c_test[7]).abs());
assert_relative_eq!(p[8], c_test[8], epsilon = (tol*c_test[8]).abs());
assert_relative_eq!(p[9], c_test[9], epsilon = (tol*c_test[9]).abs());
assert_relative_eq!(p[10], c_test[10], epsilon = (tol*c_test[10]).abs());
assert_relative_eq!(p[11], c_test[11], epsilon = (tol*c_test[11]).abs());
}
#[test]
#[autotest_annotate(autotest_polycf_expandroots_4)]
fn test_polycf_expandroots_4() {
use num_complex::Complex32;
let theta = 1.7f32;
let a = [
-Complex32::new(0.0, theta).exp(),
-Complex32::new(0.0, -theta).exp()
];
let mut c = vec![Complex32::new(0.0, 0.0); 3];
let c_test = [
Complex32::new(1.0, 0.0),
Complex32::new(2.0 * theta.cos(), 0.0),
Complex32::new(1.0, 0.0)
];
let tol = 1e-3f32;
poly_expandroots(&a, 2, &mut c);
assert_relative_eq!(c[0].re, c_test[0].re, epsilon = tol);
assert_relative_eq!(c[0].im, c_test[0].im, epsilon = tol);
assert_relative_eq!(c[1].re, c_test[1].re, epsilon = tol);
assert_relative_eq!(c[1].im, c_test[1].im, epsilon = tol);
assert_relative_eq!(c[2].re, c_test[2].re, epsilon = tol);
assert_relative_eq!(c[2].im, c_test[2].im, epsilon = tol);
}
#[test]
#[autotest_annotate(autotest_polyf_expandroots2_3)]
fn test_polyf_expandroots2_3() {
let n = 3;
let a = [2.0, 3.0, -1.0];
let b = [5.0, -2.0, -3.0];
let mut c = vec![0.0f32; n + 1];
let c_test = [-6.0, 29.0, -23.0, -30.0];
let tol = 1e-3f32;
poly_expandroots2(&a, &b, n, &mut c);
assert_relative_eq!(c[0], c_test[0], epsilon = tol);
assert_relative_eq!(c[1], c_test[1], epsilon = tol);
assert_relative_eq!(c[2], c_test[2], epsilon = tol);
assert_relative_eq!(c[3], c_test[3], epsilon = tol);
}
#[test]
#[autotest_annotate(autotest_polyf_mul_2_3)]
fn test_polyf_mul_2_3() {
let a = [2.0, -4.0, 3.0];
let b = [-9.0, 3.0, -2.0, 5.0];
let mut c = vec![0.0f32; 6];
let c_test = [-18.0, 42.0, -43.0, 27.0, -26.0, 15.0];
let tol = 1e-3f32;
poly_mul(&a, 2, &b, 3, &mut c);
assert_relative_eq!(c[0], c_test[0], epsilon = tol);
assert_relative_eq!(c[1], c_test[1], epsilon = tol);
assert_relative_eq!(c[2], c_test[2], epsilon = tol);
assert_relative_eq!(c[3], c_test[3], epsilon = tol);
assert_relative_eq!(c[4], c_test[4], epsilon = tol);
assert_relative_eq!(c[5], c_test[5], epsilon = tol);
}
#[test]
#[autotest_annotate(autotest_poly_expandbinomial_n6)]
fn test_poly_expandbinomial_n6() {
let n = 6;
let mut c = vec![0.0f32; n + 1];
let c_test = [1.0, 6.0, 15.0, 20.0, 15.0, 6.0, 1.0];
let tol = 1e-3f32;
poly_expandbinomial(n, &mut c);
assert_relative_eq!(c[0], c_test[0], epsilon = tol);
assert_relative_eq!(c[1], c_test[1], epsilon = tol);
assert_relative_eq!(c[2], c_test[2], epsilon = tol);
assert_relative_eq!(c[3], c_test[3], epsilon = tol);
assert_relative_eq!(c[4], c_test[4], epsilon = tol);
assert_relative_eq!(c[5], c_test[5], epsilon = tol);
assert_relative_eq!(c[6], c_test[6], epsilon = tol);
}
#[test]
#[autotest_annotate(autotest_poly_binomial_expand_pm_m6_k1)]
fn test_poly_expandbinomial_pm_m6_k1() {
let m = 5;
let k = 1;
let n = m + k;
let mut c = vec![0.0f32; n + 1];
let c_test = [1.0, 4.0, 5.0, 0.0, -5.0, -4.0, -1.0];
let tol = 1e-3f32;
poly_expandbinomial_pm(m, k, &mut c);
assert_relative_eq!(c[0], c_test[0], epsilon = tol);
assert_relative_eq!(c[1], c_test[1], epsilon = tol);
assert_relative_eq!(c[2], c_test[2], epsilon = tol);
assert_relative_eq!(c[3], c_test[3], epsilon = tol);
assert_relative_eq!(c[4], c_test[4], epsilon = tol);
assert_relative_eq!(c[5], c_test[5], epsilon = tol);
assert_relative_eq!(c[6], c_test[6], epsilon = tol);
}
#[test]
#[autotest_annotate(autotest_poly_expandbinomial_pm_m5_k2)]
fn test_poly_expandbinomial_pm_m5_k2() {
let m = 5;
let k = 2;
let n = m + k;
let mut c = vec![0.0f32; n + 1];
let c_test = [1.0, 3.0, 1.0, -5.0, -5.0, 1.0, 3.0, 1.0];
let tol = 1e-3f32;
poly_expandbinomial_pm(m, k, &mut c);
assert_relative_eq!(c[0], c_test[0], epsilon = tol);
assert_relative_eq!(c[1], c_test[1], epsilon = tol);
assert_relative_eq!(c[2], c_test[2], epsilon = tol);
assert_relative_eq!(c[3], c_test[3], epsilon = tol);
assert_relative_eq!(c[4], c_test[4], epsilon = tol);
assert_relative_eq!(c[5], c_test[5], epsilon = tol);
assert_relative_eq!(c[6], c_test[6], epsilon = tol);
assert_relative_eq!(c[7], c_test[7], epsilon = tol);
}
fn polyf_findroots_testbench(p: &[f32], r: &[Complex<f32>], order: usize, tol: f32) {
let mut roots = vec![Complex::new(0.0, 0.0); order];
assert!(polyf_findroots(p, order + 1, &mut roots).is_ok());
for i in 0..order {
let e = (roots[i] - r[i]).norm();
assert!(e < tol, "root {} : {:e} > {:e}", i, e, tol);
}
}
#[test]
#[autotest_annotate(autotest_polyf_findroots_real)]
fn test_polyf_findroots_real() {
let p = [6.0, 11.0, -33.0, -33.0, 11.0, 6.0];
let r = [
Complex::new(-3.0, 0.0),
Complex::new(-1.0, 0.0),
Complex::new(-1.0 / 3.0, 0.0),
Complex::new(0.5, 0.0),
Complex::new(2.0, 0.0),
];
polyf_findroots_testbench(&p, &r, 5, 1e-6);
}
#[test]
#[autotest_annotate(autotest_polyf_findroots_complex)]
fn test_polyf_findroots_complex() {
let p = [3.0, 2.0, 1.0];
let r = [
Complex::new(-1.0, std::f32::consts::SQRT_2),
Complex::new(-1.0, -std::f32::consts::SQRT_2),
];
polyf_findroots_testbench(&p, &r, 2, 1e-6);
}
#[test]
#[autotest_annotate(autotest_polyf_findroots_mix)]
fn test_polyf_findroots_mix() {
let p = [-1.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0];
let r = [
Complex::new(-1.544928106217380, 0.0),
Complex::new(-0.8438580445415772, 1.251293921227189),
Complex::new(-0.8438580445415772, -1.251293921227189),
Complex::new(0.1464465720078399, 0.0),
Complex::new(0.5430988116463471, 1.282747429218130),
Complex::new(0.5430988116463471, -1.282747429218130),
];
polyf_findroots_testbench(&p, &r, 6, 1e-6);
}
#[test]
#[autotest_annotate(autotest_polyf_findroots_mix2)]
fn test_polyf_findroots_mix2() {
let p = [
-2.1218292415142059326171875000e-02,
1.6006522178649902343750000000e+00,
-1.2054302543401718139648437500e-01,
-8.4453743696212768554687500000e-01,
-1.1174567937850952148437500000e+00,
8.2108253240585327148437500000e-01,
2.2316795587539672851562500000e-01,
1.4220994710922241210937500000e+00,
-8.4215706586837768554687500000e-01,
1.3681684434413909912109375000e-01,
1.0689756833016872406005859375e-02,
];
let r = [
Complex::new(-17.67808709752869, 0.0),
Complex::new(-0.7645511425850682, 0.4932343666704793),
Complex::new(-0.7645511425850682, -0.4932343666704793),
Complex::new(-0.2764509491715267, 1.058805768356938),
Complex::new(-0.2764509491715267, -1.058805768356938),
Complex::new(0.01327054605125156, 0.0),
Complex::new(0.9170364272114475, 0.3838341863217226),
Complex::new(0.9170364272114475, -0.3838341863217226),
Complex::new(2.556937242081334, 1.448576080447611),
Complex::new(2.556937242081334, -1.448576080447611),
];
polyf_findroots_testbench(&p, &r, 10, 4e-6);
}
#[test]
fn test_poly_val_f32() {
let p = [1.0, -4.0, 6.0, 2.0];
let k = 4;
let x = 3.0;
let y = poly_val(&p, k, x);
assert_relative_eq!(y, 97.0, epsilon = 1e-6);
}
}