use crate::genotypes::Binary as BinaryGenotype;
pub fn hamming_distance(dna_a: &[BinaryGenotype], dna_b: &[BinaryGenotype]) -> f64 {
let max_len = dna_a.len().max(dna_b.len());
let mut distance = 0usize;
for i in 0..max_len {
let a_val = dna_a.get(i).map(|g| g.value);
let b_val = dna_b.get(i).map(|g| g.value);
if a_val != b_val {
distance += 1;
}
}
distance as f64
}
pub fn euclidean_distance<T>(
dna_a: &[crate::genotypes::Range<T>],
dna_b: &[crate::genotypes::Range<T>],
) -> f64
where
T: Into<f64> + Copy + Sync + Send + Clone + Default + std::fmt::Debug,
{
let min_len = dna_a.len().min(dna_b.len());
let mut sum_sq = 0.0f64;
for i in 0..min_len {
let a_val: f64 = dna_a[i].value().into();
let b_val: f64 = dna_b[i].value().into();
sum_sq += (a_val - b_val).powi(2);
}
if dna_a.len() > min_len {
for gene in &dna_a[min_len..] {
let v: f64 = gene.value().into();
sum_sq += v.powi(2);
}
}
if dna_b.len() > min_len {
for gene in &dna_b[min_len..] {
let v: f64 = gene.value().into();
sum_sq += v.powi(2);
}
}
sum_sq.sqrt()
}
pub trait DistanceMetric<G> {
fn distance(dna_a: &[G], dna_b: &[G]) -> f64;
}
pub struct HammingDistance;
impl DistanceMetric<BinaryGenotype> for HammingDistance {
fn distance(dna_a: &[BinaryGenotype], dna_b: &[BinaryGenotype]) -> f64 {
hamming_distance(dna_a, dna_b)
}
}
pub struct EuclideanDistance;
impl<T> DistanceMetric<crate::genotypes::Range<T>> for EuclideanDistance
where
T: Into<f64> + Copy + Sync + Send + Clone + Default + std::fmt::Debug,
{
fn distance(dna_a: &[crate::genotypes::Range<T>], dna_b: &[crate::genotypes::Range<T>]) -> f64 {
euclidean_distance(dna_a, dna_b)
}
}