#![warn(missing_docs)]
pub mod algos;
pub mod error;
pub use crate::{algos::*, error::MedError};
use indxvec::{
printing::{GR, UN},
Vecops,
};
pub type ME = MedError<String>;
#[derive(Default)]
pub struct MStats {
pub centre: f64,
pub dispersion: f64,
}
impl std::fmt::Display for MStats {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"centre: {GR}{:<10e}{UN}\tdispersion: {GR}{:<10e}{UN}",
self.centre, self.dispersion
)
}
}
pub trait Medianf64 {
fn medianf64(self) -> Result<f64, ME>;
fn zeromedianf64(self) -> Result<Vec<f64>, ME>;
fn mediancorrf64(self, v: &[f64]) -> Result<f64, MedError<String>>;
fn madf64(self, med: f64) -> Result<f64, ME>;
fn medstatsf64(self) -> Result<MStats, ME>;
}
impl Medianf64 for &[f64] {
fn medianf64(self) -> Result<f64, ME> {
let n = self.len();
match n {
0 => {
return Err(MedError::SizeError(
"medianf64: zero length data".to_owned(),
))
}
1 => return Ok(self[0]),
2 => return Ok((self[0] + self[1]) / 2.0),
_ => (),
};
let mut fset = self.to_owned();
if (n & 1) == 1 {
Ok(med_odd(&mut fset))
} else {
Ok(med_even(&mut fset))
}
}
fn zeromedianf64(self) -> Result<Vec<f64>, ME> {
let median = self.medianf64()?;
Ok(self.iter().map(|s| s - median).collect())
}
fn mediancorrf64(self, v: &[f64]) -> Result<f64, ME> {
let mut sx2 = 0_f64;
let mut sy2 = 0_f64;
let smedian = self.medianf64()?;
let vmedian = v.medianf64()?;
let sxy: f64 = self
.iter()
.zip(v)
.map(|(&xt, yt)| {
let x = xt - smedian;
let y = *yt - vmedian;
sx2 += x * x;
sy2 += y * y;
x * y
})
.sum();
Ok(sxy / (sx2 * sy2).sqrt())
}
fn madf64(self, med: f64) -> Result<f64, ME> {
self.iter()
.map(|s| (s - med).abs())
.collect::<Vec<f64>>()
.medianf64()
}
fn medstatsf64(self) -> Result<MStats, ME> {
let centre = self.medianf64()?;
Ok(MStats {
centre,
dispersion: self.madf64(centre)?,
})
}
}
pub trait Median<T> {
fn median(self, quantify: &mut impl FnMut(&T) -> f64) -> Result<f64, ME>;
fn odd_strict_median(self) -> T
where
T: Ord + Clone;
fn even_strict_median(self) -> (T, T)
where
T: Ord + Clone;
fn zeromedian(self, quantify: &mut impl FnMut(&T) -> f64) -> Result<Vec<f64>, ME>;
fn mediancorr(self, v: &[T], quantify: &mut impl FnMut(&T) -> f64)
-> Result<f64, MedError<String>>;
fn mad(self, med: f64, quantify: &mut impl FnMut(&T) -> f64) -> Result<f64, ME>;
fn medstats(self, quantify: &mut impl FnMut(&T) -> f64) -> Result<MStats, ME>;
}
impl<T> Median<T> for &[T] {
fn median(self, quantify: &mut impl FnMut(&T) -> f64) -> Result<f64, ME> {
let fset = self.iter().map(quantify).collect::<Vec<f64>>();
fset.medianf64()
}
fn odd_strict_median(self) -> T
where
T: Ord + Clone,
{
self.max_1_min_k(self.len() / 2 + 1)
}
fn even_strict_median(self) -> (T, T)
where
T: Ord + Clone,
{
self.max_2_min_k(self.len() / 2 + 1)
}
fn zeromedian(self, quantify: &mut impl FnMut(&T) -> f64) -> Result<Vec<f64>, ME> {
let median = self.median(quantify)?;
Ok(self.iter().map(|s| quantify(s) - median).collect())
}
fn mediancorr(self, v: &[T], quantify: &mut impl FnMut(&T) -> f64) -> Result<f64, ME> {
let mut sx2 = 0_f64;
let mut sy2 = 0_f64;
let selfmedian = self.median(quantify)?;
let vmedian = v.median(quantify)?;
let sxy: f64 = self
.iter()
.zip(v)
.map(|(xt, yt)| {
let x = quantify(xt) - selfmedian;
let y = quantify(yt) - vmedian;
sx2 += x * x;
sy2 += y * y;
x * y
})
.sum();
Ok(sxy / (sx2 * sy2).sqrt())
}
fn mad(self, med: f64, quantify: &mut impl FnMut(&T) -> f64) -> Result<f64, ME> {
self.iter()
.map(|s| ((quantify(s) - med).abs()))
.collect::<Vec<f64>>()
.median(&mut |f: &f64| *f)
}
fn medstats(self, quantify: &mut impl FnMut(&T) -> f64) -> Result<MStats, ME> {
let centre = self.median(quantify)?;
Ok(MStats {
centre,
dispersion: self.mad(centre, quantify)?,
})
}
}