#[inline]
pub fn lagrange_weights(x: f64, coeffs: &[f64], points: &[f64]) -> Vec<f64>
{
let mut weights = vec![0.0; points.len()];
let mut normalization_factor = 0.0;
for (&point, weight) in points.iter().zip(weights.iter_mut())
{
if (point-x).abs() < f64::EPSILON
{
*weight = 1.0;
return weights;
}
}
coeffs.iter().zip(points).zip(weights.iter_mut()).for_each(|((&coeff, &xi), weight)|
{
*weight = coeff / (x-xi);
normalization_factor += *weight;
});
weights.iter_mut().for_each(|w|*w /= normalization_factor);
weights
}
#[allow(unused)]
#[inline]
pub fn lagrange_weights_cache(x: f64, coeffs: &[f64], points: &[f64], weights: &mut [f64]) -> usize
{
weights.fill(0.0);
let mut normalization_factor = 0.0;
for (&point, weight) in points.iter().zip(weights.iter_mut())
{
if (point-x).abs() < f64::EPSILON
{
*weight = 1.0;
return points.len();
}
}
coeffs.iter().zip(points).zip(weights.iter_mut()).for_each(|((&coeff, &xi), weight)|
{
*weight = coeff / (x-xi);
normalization_factor += *weight;
});
weights.iter_mut().for_each(|w|*w /= normalization_factor);
points.len()
}
pub fn lagrange_coeffs(points: &[f64]) -> Vec<f64>
{
let mut coeffs = Vec::with_capacity(points.len());
for i in 0..points.len() {
let mut li = 1.0;
for j in 0..points.len() {
if i != j {
if points[j] == points[i]
{
continue;
}
li *= points[i] - points[j];
}
}
coeffs.push(1.0 / li);
}
coeffs
}
#[allow(unused)]
pub fn jacobian_lagrange_weights<const D: usize>( x: [f64; D], points: &[[f64; D]]) -> Vec<[f64; D]> {
let n = points.len();
let mut jacobian_weights = vec![[0.0; D]; n];
for i in 0..n {
#[allow(clippy::needless_range_loop)]
for d in 0..D {
let mut derivative = 0.0;
for k in 0..n {
if i != k {
let mut product = 1.0;
for j in 0..n {
if j != i && j != k {
product *= (x[d] - points[j][d]) / (points[i][d] - points[j][d]);
}
}
derivative += product / (points[i][d] - points[k][d]);
}
}
jacobian_weights[i][d] = derivative;
}
}
jacobian_weights
}
#[test]
fn test_lagrange_weights()
{
use crate::tables::clenshaw_curtis_table::cc_nodes;
let points = cc_nodes(8);
let weights= lagrange_weights(0.2, &lagrange_coeffs(&points), &points);
println!("sum={}",weights.iter().zip(&points).map(|(&w,x)|w*x*x).sum::<f64>());
assert!((1.0-weights.iter().zip(points).map(|(&w,x)|w*x*x).sum::<f64>()/(0.2*0.2)).abs() < 1e-14);
}
#[test]
fn test_lagrange_derivative()
{
use crate::tables::clenshaw_curtis_table::cc_nodes;
let points = cc_nodes(2).iter().map(|x|[*x;1]).collect::<Vec<_>>();
let derivatives= jacobian_lagrange_weights([0.2], &points);
assert!((1.0-derivatives.iter().zip(points).map(|(&w,x)|w[0]*x[0]*x[0]).sum::<f64>()/(0.4)).abs() < 1e-14);
}