use crate::ExtremaCandidate;
use num_traits::Float;
fn compute_barycentric_weights_with_key<'a, A, F, T>(
x: &'a [A],
key: F,
) -> impl Iterator<Item = T> + 'a
where
F: Fn(&A) -> T + 'a,
T: Float + 'a,
{
let stride = (x.len() - 2) / 15 + 1;
let one = T::one();
let two = T::from(2).unwrap();
x.iter().enumerate().map(move |(k, xk)| {
let mut prod = one;
for a in 0..stride {
for j in (a..x.len()).step_by(stride) {
if j != k {
prod = prod * ((key(xk) - key(&x[j])) * two);
}
}
}
prod.recip()
})
}
pub fn compute_barycentric_weights<T: Float>(x: &[T]) -> impl Iterator<Item = T> + '_ {
compute_barycentric_weights_with_key(x, |x| *x)
}
pub fn compute_delta<T: Float>(wk: &[T], desired: &[T], weights: &[T]) -> T {
let mut delta_numer = T::zero();
let mut delta_denom = T::zero();
for (k, ((&w, &des), &wei)) in wk
.iter()
.zip(desired.iter())
.zip(weights.iter())
.enumerate()
{
delta_numer = delta_numer + w * des;
let z = w / wei;
if k % 2 != 0 {
delta_denom = delta_denom - z;
} else {
delta_denom = delta_denom + z;
}
}
delta_numer / delta_denom
}
#[allow(dead_code)]
pub fn compute_delta_from_candidates<T: Float>(candidates: &[ExtremaCandidate<T>]) -> T {
let wk = compute_barycentric_weights_with_key(candidates, |a| a.x);
let mut delta_numer = T::zero();
let mut delta_denom = T::zero();
for (k, (w, a)) in wk.zip(candidates.iter()).enumerate() {
delta_numer = delta_numer + w * a.desired;
let z = w / a.weight;
if k % 2 != 0 {
delta_denom = delta_denom - z;
} else {
delta_denom = delta_denom + z;
}
}
delta_numer / delta_denom
}
pub fn compute_lagrange_abscisa<'a, T: Float>(
delta: T,
desired: &'a [T],
weights: &'a [T],
) -> impl Iterator<Item = T> + 'a {
desired
.iter()
.zip(weights.iter())
.enumerate()
.map(move |(k, (&des, &wei))| {
let z = delta / wei;
if k % 2 != 0 { des + z } else { des - z }
})
}
pub fn compute_freq_response<T: Float>(x0: T, x: &[T], wk: &[T], yk: &[T]) -> T {
let mut h_numer = T::zero();
let mut h_denom = T::zero();
for ((&xk, &w), &y) in x.iter().zip(wk.iter()).zip(yk.iter()) {
if x0 == xk {
return y;
}
let z = w / (x0 - xk);
h_numer = h_numer + z * y;
h_denom = h_denom + z;
}
h_numer / h_denom
}
fn compute_error_common<T, D, W>(
x0: T,
x: &[T],
wk: &[T],
yk: &[T],
desired: D,
weights: W,
) -> (T, T, T)
where
T: Float,
D: Fn(T) -> T,
W: Fn(T) -> T,
{
let h = compute_freq_response(x0, x, wk, yk);
let f = x0.acos();
let d = desired(f);
let w = weights(f);
let error = w * (d - h);
(error, d, w)
}
pub fn compute_error<T, D, W>(x0: T, x: &[T], wk: &[T], yk: &[T], desired: D, weights: W) -> T
where
T: Float,
D: Fn(T) -> T,
W: Fn(T) -> T,
{
compute_error_common(x0, x, wk, yk, desired, weights).0
}
pub fn compute_extrema_candidate<T, D, W>(
x0: T,
x: &[T],
wk: &[T],
yk: &[T],
desired: D,
weights: W,
) -> ExtremaCandidate<T>
where
T: Float,
D: Fn(T) -> T,
W: Fn(T) -> T,
{
let (error, d, w) = compute_error_common(x0, x, wk, yk, desired, weights);
ExtremaCandidate {
x: x0,
error,
desired: d,
weight: w,
}
}