pub extern crate nalgebra;
use nalgebra::{allocator::Allocator, DefaultAllocator, Matrix, Vector};
use num_traits::Float;
use thiserror::Error;
mod solvers;
pub use solvers::*;
pub mod integrators;
pub const DEFAULT_TOL: f64 = 1e-6;
pub const DEFAULT_ITERMAX: usize = 50;
#[derive(Error, Debug, PartialEq)]
pub enum SolverError {
#[error("maximum number of iteration, {0}, reached")]
MaxIterReached(usize),
#[error("the resulting value is not a number (NaN)")]
NotANumber,
#[error("an input value is incorrect: {details}")]
IncorrectInput { details: &'static str },
#[error("encountered a singular or ill-defined Jacobian matrix")]
BadJacobian,
#[error("failed to convert between types (often between usize and T: Float)")]
TypeConversionError,
#[error("encountered an external error: {0}")]
ExternalError(String),
}
pub type SolverResult<T> = Result<T, SolverError>;
type VectorType<T, D> = Vector<T, D, <DefaultAllocator as Allocator<D>>::Buffer<T>>;
type MatrixType<T, R, C> = Matrix<T, R, C, <DefaultAllocator as Allocator<R, C>>::Buffer<T>>;
#[derive(Debug, Copy, Clone)]
pub struct MeanVariance<T> {
pub mean: T,
pub variance: T,
}
impl<T: Float> MeanVariance<T> {
pub fn new(mean: T, variance: T) -> SolverResult<Self> {
if variance < T::zero() {
return Err(SolverError::IncorrectInput {
details: "variance must be greater than 0",
});
}
Ok(Self { mean, variance })
}
pub fn zero() -> Self {
Self {
mean: T::zero(),
variance: T::zero(),
}
}
pub fn standard_deviation(&self) -> T {
self.variance.sqrt()
}
pub fn scale_mean(&self, factor: T) -> Self {
Self {
mean: self.mean * factor,
variance: self.variance * factor * factor,
}
}
pub fn add(&self, other: &Self) -> Self {
Self {
mean: self.mean + other.mean,
variance: self.variance + other.variance,
}
}
pub fn from_iterator_using_welford(
iterator: &mut impl Iterator<Item = T>,
use_bessel_correction: bool,
) -> SolverResult<Self> {
let mut mean = T::zero();
let mut sum_of_squares = T::zero();
let mut total_count: usize = 0;
for (count, sample) in iterator
.enumerate()
.map(|(count, i)| (T::from(count + 1).unwrap(), i))
{
let delta_mean = sample - mean;
mean = mean + delta_mean / count;
sum_of_squares = sum_of_squares + delta_mean * (sample - mean);
total_count += 1;
}
if total_count < 2 {
Err(SolverError::IncorrectInput {
details: "the iterator must be over at least 2 elements",
})
} else {
if use_bessel_correction {
total_count -= 1;
}
let total_count_as_t = T::from(total_count).ok_or(SolverError::TypeConversionError)?;
let variance = sum_of_squares / total_count_as_t;
Ok(Self { mean, variance })
}
}
}