use num_traits::{Float, FloatConst};
pub fn compute_cheby_coefficients<T: Float + FloatConst>(p_values: &mut [T]) -> Vec<T> {
halve_first_and_last(p_values);
let n = p_values.len() - 1;
let scale = T::from(2).unwrap() / T::from(n).unwrap();
let mut bk: Vec<T> = (0..=n)
.map(|j| {
let f = T::from(j).unwrap() * T::PI() / T::from(n).unwrap();
let x = f.cos();
clenshaw(p_values, x) * scale
})
.collect();
halve_first_and_last(&mut bk);
bk
}
fn clenshaw<T: Float>(a: &[T], x: T) -> T {
assert!(a.len() >= 2);
let mut b2 = T::zero();
let mut b1 = *a.last().unwrap();
let two_x = T::from(2).unwrap() * x;
for &ak in a[1..a.len() - 1].iter().rev() {
let tmp = two_x * b1 - b2 + ak;
b2 = b1;
b1 = tmp;
}
x * b1 - b2 + a[0]
}
fn halve_first_and_last<T: Float>(a: &mut [T]) {
assert!(a.len() >= 2);
let scale = T::from(0.5).unwrap();
let x = a.first_mut().unwrap();
*x = *x * scale;
let x = a.last_mut().unwrap();
*x = *x * scale;
}
pub fn chebyshev_nodes<T: Float + FloatConst>(n: usize) -> impl Iterator<Item = T> {
let scale = T::PI() / T::from(n).unwrap();
(0..=n).map(move |j| (T::from(j).unwrap() * scale).cos())
}