ndarray_histogram/quantile/
interpolate.rsuse num_traits::{Float, FromPrimitive, NumOps, ToPrimitive};
fn float_quantile_index<F: Float>(q: F, len: usize) -> F {
q * (F::from(len - 1).unwrap())
}
fn float_quantile_index_fraction<F: Float>(q: F, len: usize) -> F {
float_quantile_index(q, len).fract()
}
pub(crate) fn lower_index<F: Float>(q: F, len: usize) -> usize {
float_quantile_index(q, len).floor().to_usize().unwrap()
}
pub(crate) fn higher_index<F: Float>(q: F, len: usize) -> usize {
float_quantile_index(q, len).ceil().to_usize().unwrap()
}
pub trait Interpolate<T> {
#[doc(hidden)]
fn needs_lower<F: Float>(q: F, len: usize) -> bool;
#[doc(hidden)]
fn needs_higher<F: Float>(q: F, len: usize) -> bool;
#[doc(hidden)]
fn interpolate<F: Float>(lower: Option<T>, higher: Option<T>, q: F, len: usize) -> T;
private_decl! {}
}
pub struct Higher;
pub struct Lower;
pub struct Nearest;
pub struct Midpoint;
pub struct Linear;
impl<T> Interpolate<T> for Higher {
fn needs_lower<F: Float>(_q: F, _len: usize) -> bool {
false
}
fn needs_higher<F: Float>(_q: F, _len: usize) -> bool {
true
}
fn interpolate<F: Float>(_lower: Option<T>, higher: Option<T>, _q: F, _len: usize) -> T {
higher.unwrap()
}
private_impl! {}
}
impl<T> Interpolate<T> for Lower {
fn needs_lower<F: Float>(_q: F, _len: usize) -> bool {
true
}
fn needs_higher<F: Float>(_q: F, _len: usize) -> bool {
false
}
fn interpolate<F: Float>(lower: Option<T>, _higher: Option<T>, _q: F, _len: usize) -> T {
lower.unwrap()
}
private_impl! {}
}
impl<T> Interpolate<T> for Nearest {
fn needs_lower<F: Float>(q: F, len: usize) -> bool {
float_quantile_index_fraction(q, len) < F::from(0.5).unwrap()
}
fn needs_higher<F: Float>(q: F, len: usize) -> bool {
!<Self as Interpolate<T>>::needs_lower(q, len)
}
fn interpolate<F: Float>(lower: Option<T>, higher: Option<T>, q: F, len: usize) -> T {
if <Self as Interpolate<T>>::needs_lower(q, len) {
lower.unwrap()
} else {
higher.unwrap()
}
}
private_impl! {}
}
impl<T> Interpolate<T> for Midpoint
where
T: NumOps + Clone + FromPrimitive,
{
fn needs_lower<F: Float>(_q: F, _len: usize) -> bool {
true
}
fn needs_higher<F: Float>(_q: F, _len: usize) -> bool {
true
}
fn interpolate<F: Float>(lower: Option<T>, higher: Option<T>, _q: F, _len: usize) -> T {
let denom = T::from_u8(2).unwrap();
let lower = lower.unwrap();
let higher = higher.unwrap();
lower.clone() + (higher - lower) / denom
}
private_impl! {}
}
impl<T> Interpolate<T> for Linear
where
T: NumOps + Clone + FromPrimitive + ToPrimitive,
{
fn needs_lower<F: Float>(_q: F, _len: usize) -> bool {
true
}
fn needs_higher<F: Float>(_q: F, _len: usize) -> bool {
true
}
fn interpolate<F: Float>(lower: Option<T>, higher: Option<T>, q: F, len: usize) -> T {
let fraction = float_quantile_index_fraction(q, len).to_f64().unwrap();
let lower = lower.unwrap();
let higher = higher.unwrap();
let lower_f64 = lower.to_f64().unwrap();
let higher_f64 = higher.to_f64().unwrap();
lower + T::from_f64(fraction * (higher_f64 - lower_f64)).unwrap()
}
private_impl! {}
}