Hi everybody,
I'm setting up a library for some basic data science in Rust. I'm starting with some basic distance metrics.
I have a Structure Points to store two points and the features contained:
#[derive(Debug,Clone)]
struct Points<T>{
point_base: Vec<T>,
point_cfr: Vec<T>,
n_features: usize}
impl<T: std::fmt::Debug> Points<T> {
fn new(vbase:Vec<T>,vcfr:Vec<T>) -> Result<Points<T>,MetricError> {
let n_ft = vbase.len();
if n_ft == vcfr.len() {
Ok(Points::<T>{point_base:vbase,point_cfr:vcfr,n_features:n_ft})
} else {
Err(MetricError::DifferetFeaturesNumber(vbase.len(),vcfr.len()))
}
}
fn new_uncheck(vbase:Vec<T>,vcfr:Vec<T>,n_ft:usize) -> Result<Points<T>,MetricError> {
Ok(Points::<T>{point_base:vbase,point_cfr:vcfr,n_features:n_ft})
}
}
The Points can be passed to the metric (an enum) in order to set the parameters of the metrics and check the type of input is coherent with the metric:
#[derive(Debug,Clone)]
enum Dist_Metric {
Euclidean(Points<f64>),
Manhattan(Points<f64>),
Chebyshev(Points<f64>),
Minkowski(Points<f64>,f64),
StdEuclidean(Points<f64>,f64),
Hamming(Points<isize>),
Canberra(Points<isize>),
Braycurtis(Points<isize>),
Jaccard(Points<bool>),
}
impl Dist_Metric {
fn calculate_distnce(metric:Dist_Metric) -> f64 {
match metric {
Dist_Metric::Euclidean(points) => {
(0..points.n_features.clone()).map(|i| (points.vector_base[i]-points.vector_cfr[i]).powi(2)).sum::<f64>().sqrt()
},
Dist_Metric::Manhattan(points) => {
(0..points.n_features.clone()).map(|i| (points.vector_base[i]-points.vector_cfr[i]).abs()).sum::<f64>()
},
Dist_Metric::Chebyshev(points) => {
(0..points.n_features.clone()).map(|i| (points.vector_base[i]-points.vector_cfr[i]).abs()).fold(0., f64::max)
},
Dist_Metric::Minkowski(points,p) => {
(0..points.n_features.clone()).map(|i| (points.vector_base[i]-points.vector_cfr[i]).powf(p)).sum::<f64>().powf(1./p)
},
Dist_Metric::StdEuclidean(points,v) => {
(0..points.n_features.clone()).map(|i| ((points.vector_base[i]-points.vector_cfr[i]).powi(2))/v).sum::<f64>().sqrt()
},
Dist_Metric::Hamming(points) => {
0.
},
Dist_Metric::Canberra(points) => {
0.
},
Dist_Metric::Braycurtis(points) => {
0.
},
Dist_Metric::Jaccard(points) => {
0.
},
}
}
}
Now I'm writing the constructor for the Dist_Metric enum. Is it possible the create a generic implementation of new to handle the creation or I should create a a new function for each variant (something like new_Euclidean, new_Manhattan, etc. )
Thanks,