#![warn(missing_docs)]
pub mod algos;
pub mod algosf64;
pub mod error;
use crate::{algos::*, algosf64::{med_oddf64,med_evenf64}, error::{MedError,merror}};
use indxvec::{ printing::{GR, UN, YL}};
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,
"{YL}centre: {GR}{:.5}{YL} ± spread: {GR}{:.5}{UN}",
self.centre, self.dispersion
)
}
}
pub trait Medianf64 {
fn median(self) -> Result<f64, Me>;
fn zeromedian(self) -> Result<Vec<f64>, Me>;
fn mediancorr(self,v: &[f64]) -> Result<f64, Me>;
fn mad(self, med: f64) -> Result<f64, Me>;
fn medstats(self) -> Result<MStats, Me>;
}
impl Medianf64 for &[f64] {
fn median(self) -> Result<f64, Me> {
let n = self.len();
match n {
0 => {
return Err(merror("size","medianf64: zero length data"))
}
1 => return Ok(self[0]),
2 => return Ok((self[0] + self[1]) / 2.0),
_ => ()
};
let mut s = self.to_owned();
if (n & 1) == 1 {
Ok(med_oddf64(&mut s))
} else {
let (med1,med2) = med_evenf64(&mut s);
Ok((med1+med2)/2.)
}
}
fn zeromedian(self) -> Result<Vec<f64>, Me> {
let median = self.median()?;
Ok(self.iter().map(|s| s - median).collect())
}
fn mediancorr(self, v: &[f64]) -> Result<f64, Me> {
let mut sx2 = 0_f64;
let mut sy2 = 0_f64;
let smedian = self.median()?;
let vmedian = v.median()?;
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 mad(self, med: f64) -> Result<f64, Me> {
self.iter()
.map(|&s| (s - med).abs())
.collect::<Vec<f64>>()
.median()
}
fn medstats(self) -> Result<MStats, Me> {
let centre = self.median()?;
Ok(MStats {
centre,
dispersion: self.mad(centre)?,
})
}
}
pub trait Median<T> {
fn median(&self, quantify: impl Fn(&T) -> f64) -> Result<f64, Me>;
fn generic_odd(&self) -> Result<&T, Me>;
fn generic_even(&self) -> Result<(&T,&T), Me>;
fn zeromedian(&self, quantify: impl Copy + Fn(&T) -> f64) -> Result<Vec<f64>, Me>;
fn mediancorr(&self,v: &[T],quantify: impl Copy + Fn(&T) -> f64) -> Result<f64, Me>;
fn mad(&self, med: f64, quantify: impl Fn(&T) -> f64) -> Result<f64, Me>;
fn medstats(&self, quantify: impl Copy + Fn(&T) -> f64) -> Result<MStats, Me>;
}
impl<T> Median<T> for &[T]
where T:PartialOrd
{
fn median(&self, quantify: impl Fn(&T) -> f64) -> Result<f64, Me>
{
let n = self.len();
match n {
0 => {
return Err(merror("size",format!("median: zero length data {n}")))
}
1 => return Ok(quantify(&self[0])),
2 => return Ok((quantify(&self[0]) + quantify(&self[1])) / 2.),
_ => ()
};
let mut s = quant_vec(self,quantify);
if (n & 1) == 1 {
Ok(med_oddf64(&mut s))
} else {
let (m1,m2) = med_evenf64(&mut s);
Ok((m1+m2)/2.0)
}
}
fn generic_odd(&self) -> Result<&T, Me>
{
let n = self.len();
match n {
0 => {
return Err(merror("size",format!("generic_odd_median: zero length data {n}")))
}
1 => return Ok(&self[0]),
_ => ()
};
if (n & 1) == 1 {
Ok(med_odd(self))
} else {
Err(merror("size",format!("generic_odd: even length data {n}")))
}
}
fn generic_even(&self) -> Result<(&T,&T), Me>
{
let n = self.len();
match n {
0 => {
return Err(merror("size",format!("generic_odd_median: zero length data {n}")))
}
2 => return Ok((&self[0],&self[1])),
_ => ()
};
if (n & 1) == 0 {
Ok(med_even(self))
} else {
Err(merror("size",format!("generic_even: odd length data {n}")))
}
}
fn zeromedian(&self, quantify: impl Copy + Fn(&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: impl Copy + Fn(&T) -> f64) -> Result<f64, Me> {
let fself = quant_vec(self,quantify);
let fv = quant_vec(v,quantify);
fself.mediancorr(&fv)
}
fn mad(&self, med: f64, quantify: impl Fn(&T) -> f64) -> Result<f64, Me> {
self.iter()
.map(|s| ((quantify(s) - med).abs()))
.collect::<Vec<f64>>()
.median()
}
fn medstats(&self, quantify: impl Copy + Fn(&T) -> f64) -> Result<MStats, Me> {
let centre = self.median(quantify)?;
Ok(MStats {
centre,
dispersion: self.mad(centre, quantify)?,
})
}
}