#[inline]
pub fn residual_scale(coeffs: &[f64]) -> f64 {
coeffs.iter().fold(1.0_f64, |m, c| m.max(c.abs()))
}
#[inline]
pub fn scaled_coeffs(coeffs: &[f64]) -> Vec<f64> {
let scale = residual_scale(coeffs);
coeffs.iter().map(|c| c / scale).collect()
}
#[inline]
pub fn derivative_coeffs(coeffs: &[f64]) -> Vec<f64> {
let degree = coeffs.len() - 1;
(0..degree)
.map(|i| coeffs[i] * (degree - i) as f64)
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn residual_scale_floors_at_one() {
assert_eq!(residual_scale(&[0.1, 0.2]), 1.0);
assert_eq!(residual_scale(&[10.0, 150.0, 10.0]), 150.0);
assert_eq!(residual_scale(&[-3.0, 2.0]), 3.0);
}
#[test]
fn scaled_coeffs_has_unit_max_magnitude() {
let coeffs = vec![10.0, 34.0, 75.0, 94.0, 150.0, 94.0, 75.0, 34.0, 10.0];
let scaled = scaled_coeffs(&coeffs);
assert_eq!(residual_scale(&scaled), 1.0);
for (a, b) in coeffs.iter().zip(scaled.iter()) {
assert!((a / 150.0 - b).abs() < 1e-15);
}
}
#[test]
fn derivative_of_linear() {
assert_eq!(derivative_coeffs(&[2.0, 3.0]), vec![2.0]);
}
}