use crate::{BaselineError, Result};
pub fn validate_signal(y: &[f64]) -> Result<()> {
if y.is_empty() {
return Err(BaselineError::EmptyInput);
}
for (index, value) in y.iter().enumerate() {
if !value.is_finite() {
return Err(BaselineError::NonFiniteInput { index });
}
}
Ok(())
}
pub fn validate_output(name: &'static str, expected: usize, actual: usize) -> Result<()> {
if expected != actual {
return Err(BaselineError::LengthMismatch {
name,
expected,
actual,
});
}
Ok(())
}
#[must_use]
pub fn rms(values: &[f64]) -> f64 {
if values.is_empty() {
return 0.0;
}
let sum_sq = values.iter().map(|value| value * value).sum::<f64>();
(sum_sq / values.len() as f64).sqrt()
}
#[must_use]
pub fn logistic(value: f64) -> f64 {
if value >= 0.0 {
let z = (-value).exp();
1.0 / (1.0 + z)
} else {
let z = value.exp();
z / (1.0 + z)
}
}
#[derive(Debug, Clone)]
pub struct IterWorkspace {
pub weights: Vec<f64>,
pub previous_weights: Vec<f64>,
pub residual: Vec<f64>,
pub rhs: Vec<f64>,
}
impl IterWorkspace {
#[must_use]
pub fn new(n: usize) -> Self {
Self {
weights: vec![1.0; n],
previous_weights: vec![1.0; n],
residual: vec![0.0; n],
rhs: vec![0.0; n],
}
}
pub fn resize(&mut self, n: usize) {
self.weights.resize(n, 1.0);
self.previous_weights.resize(n, 1.0);
self.residual.resize(n, 0.0);
self.rhs.resize(n, 0.0);
}
}