use std::convert::TryFrom;
use std::fmt::{Display, Formatter};
use smartcore::metrics::distance::{
Distance as SmartcoreDistance, euclidian::Euclidian, hamming::Hamming, manhattan::Manhattan,
minkowski::Minkowski,
};
use smartcore::numbers::basenum::Number;
pub mod error;
pub use error::DistanceError;
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum Distance {
Euclidean,
Manhattan,
Minkowski(u16),
Mahalanobis,
Hamming,
}
impl Display for Distance {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Euclidean => write!(f, "Euclidean"),
Self::Manhattan => write!(f, "Manhattan"),
Self::Minkowski(n) => write!(f, "Minkowski(p = {n})"),
Self::Mahalanobis => write!(f, "Mahalanobis"),
Self::Hamming => write!(f, "Hamming"),
}
}
}
#[derive(Clone, Debug)]
pub enum KNNRegressorDistance<T: Number> {
Euclidean(Euclidian<T>),
Manhattan(Manhattan<T>),
Minkowski(Minkowski<T>),
Hamming(Hamming<T>),
}
impl<T: Number> SmartcoreDistance<Vec<T>> for KNNRegressorDistance<T> {
fn distance(&self, a: &Vec<T>, b: &Vec<T>) -> f64 {
match self {
Self::Euclidean(d) => d.distance(a, b),
Self::Manhattan(d) => d.distance(a, b),
Self::Minkowski(d) => d.distance(a, b),
Self::Hamming(d) => d.distance(a, b),
}
}
}
impl<T: Number> TryFrom<Distance> for KNNRegressorDistance<T> {
type Error = DistanceError;
fn try_from(distance: Distance) -> Result<Self, Self::Error> {
Ok(match distance {
Distance::Euclidean => Self::Euclidean(Euclidian::new()),
Distance::Manhattan => Self::Manhattan(Manhattan::new()),
Distance::Minkowski(p) => Self::Minkowski(Minkowski::new(p)),
Distance::Hamming => Self::Hamming(Hamming::new()),
Distance::Mahalanobis => {
return Err(DistanceError::UnsupportedDistance(distance));
}
})
}
}
impl<T: Number> KNNRegressorDistance<T> {
pub fn from(distance: Distance) -> Result<Self, DistanceError> {
Self::try_from(distance)
}
}