use ndarray::Array1;
#[derive(Debug, Clone, PartialEq)]
pub struct StateVector(pub Array1<f32>);
impl StateVector {
pub fn zeros(dim: usize) -> Self {
Self(Array1::zeros(dim))
}
pub fn dim(&self) -> usize {
self.0.len()
}
pub fn norm(&self) -> f32 {
self.0.mapv(|x| x * x).sum().sqrt()
}
}
#[derive(Debug, Clone)]
pub struct Residual {
pub vector: Array1<f32>,
}
impl Residual {
pub fn between(goal: &StateVector, current: &StateVector) -> Self {
assert_eq!(
goal.dim(),
current.dim(),
"residual: goal dim {} != current dim {}",
goal.dim(),
current.dim()
);
Self { vector: &goal.0 - ¤t.0 }
}
pub fn norm(&self) -> f32 {
self.vector.mapv(|x| x * x).sum().sqrt()
}
pub fn converged(&self, epsilon: f32) -> bool {
self.norm() <= epsilon
}
}
#[cfg(test)]
mod tests {
use super::*;
use ndarray::array;
#[test]
fn residual_is_goal_minus_current() {
let goal = StateVector(array![1.0, 1.0, 0.0]);
let current = StateVector(array![0.0, 1.0, 0.5]);
let r = Residual::between(&goal, ¤t);
assert_eq!(r.vector, array![1.0, 0.0, -0.5]);
}
#[test]
fn zero_residual_converges() {
let s = StateVector(array![0.3, 0.7]);
let r = Residual::between(&s, &s);
assert!(r.converged(1e-6));
assert!(!Residual::between(&StateVector(array![1.0, 0.0]), &s).converged(0.1));
}
}