radiate_core/
diversity.rs1use crate::{
2 Chromosome, Gene, Genotype,
3 chromosomes::{NumericAllele, gene::NumericGene},
4 fitness::Novelty,
5 math::distance,
6};
7use std::sync::Arc;
8
9pub trait Distance<T>: Send + Sync {
10 fn distance(&self, one: &T, two: &T) -> f32;
11}
12
13pub struct DistanceDiversityAdapter<C: Chromosome> {
14 diversity: Arc<dyn Diversity<C>>,
15}
16
17impl<C: Chromosome> DistanceDiversityAdapter<C> {
18 pub fn new(diversity: Arc<dyn Diversity<C>>) -> Self {
19 Self { diversity }
20 }
21}
22
23impl<C: Chromosome> Distance<Genotype<C>> for DistanceDiversityAdapter<C> {
24 fn distance(&self, one: &Genotype<C>, two: &Genotype<C>) -> f32 {
25 self.diversity.measure(one, two)
26 }
27}
28
29pub trait Diversity<C: Chromosome>: Send + Sync {
34 fn measure(&self, geno_one: &Genotype<C>, geno_two: &Genotype<C>) -> f32;
35}
36
37impl<C: Chromosome, F> Diversity<C> for F
38where
39 F: Fn(&Genotype<C>, &Genotype<C>) -> f32 + Send + Sync,
40{
41 fn measure(&self, geno_one: &Genotype<C>, geno_two: &Genotype<C>) -> f32 {
42 (self)(geno_one, geno_two)
43 }
44}
45
46#[derive(Clone)]
50pub struct HammingDistance;
51
52impl<G, C> Diversity<C> for HammingDistance
53where
54 C: Chromosome<Gene = G>,
55 G: Gene,
56 G::Allele: PartialEq,
57{
58 fn measure(&self, geno_one: &Genotype<C>, geno_two: &Genotype<C>) -> f32 {
59 let mut distance = 0.0;
60 let mut total_genes = 0.0;
61 for (chrom_one, chrom_two) in geno_one.iter().zip(geno_two.iter()) {
62 for (gene_one, gene_two) in chrom_one.iter().zip(chrom_two.iter()) {
63 total_genes += 1.0;
64 if gene_one.allele() != gene_two.allele() {
65 distance += 1.0;
66 }
67 }
68 }
69
70 distance / total_genes
71 }
72}
73
74impl<P: AsRef<[f32]>> Distance<P> for HammingDistance {
75 fn distance(&self, one: &P, two: &P) -> f32 {
76 let vec_one = one.as_ref();
77 let vec_two = two.as_ref();
78
79 distance::hamming(vec_one, vec_two)
80 }
81}
82
83impl Novelty<Vec<f32>> for HammingDistance {
84 fn description(&self, phenotype: &Vec<f32>) -> Vec<f32> {
85 phenotype.clone()
86 }
87}
88
89#[derive(Clone)]
93pub struct EuclideanDistance;
94
95impl<G, C> Diversity<C> for EuclideanDistance
96where
97 C: Chromosome<Gene = G>,
98 G: NumericGene,
99 G::Allele: NumericAllele,
100{
101 fn measure(&self, geno_one: &Genotype<C>, geno_two: &Genotype<C>) -> f32 {
102 let mut distance = 0.0;
103 let mut total_genes = 0.0;
104 for (chrom_one, chrom_two) in geno_one.iter().zip(geno_two.iter()) {
105 for (gene_one, gene_two) in chrom_one.iter().zip(chrom_two.iter()) {
106 let one_as_f32 = gene_one.allele_as_f32();
107 let two_as_f32 = gene_two.allele_as_f32();
108
109 if let Some((one, two)) = one_as_f32.zip(two_as_f32) {
110 if one.is_nan() || two.is_nan() {
111 continue;
112 }
113
114 let diff = one - two;
115 distance += diff * diff;
116 total_genes += 1.0;
117 }
118 }
119 }
120
121 if total_genes == 0.0 {
122 return 0.0;
123 }
124
125 (distance / total_genes).sqrt()
126 }
127}
128
129impl<P: AsRef<[f32]>> Distance<P> for EuclideanDistance {
130 fn distance(&self, one: &P, two: &P) -> f32 {
131 let vec_one = one.as_ref();
132 let vec_two = two.as_ref();
133
134 distance::euclidean(vec_one, vec_two)
135 }
136}
137
138impl Novelty<Vec<f32>> for EuclideanDistance {
139 fn description(&self, phenotype: &Vec<f32>) -> Vec<f32> {
140 phenotype.clone()
141 }
142}
143
144#[derive(Clone)]
145pub struct CosineDistance;
146
147impl<G, C> Diversity<C> for CosineDistance
148where
149 C: Chromosome<Gene = G>,
150 G: NumericGene,
151 G::Allele: NumericAllele,
152{
153 fn measure(&self, geno_one: &Genotype<C>, geno_two: &Genotype<C>) -> f32 {
154 let mut dot_product = 0.0;
155 let mut norm_one = 0.0;
156 let mut norm_two = 0.0;
157
158 for (chrom_one, chrom_two) in geno_one.iter().zip(geno_two.iter()) {
159 for (gene_one, gene_two) in chrom_one.iter().zip(chrom_two.iter()) {
160 let one_as_f32 = gene_one.allele_as_f32();
161 let two_as_f32 = gene_two.allele_as_f32();
162
163 if let Some((one, two)) = one_as_f32.zip(two_as_f32) {
164 if one.is_nan() || two.is_nan() {
165 continue;
166 }
167
168 dot_product += one * two;
169 norm_one += one * one;
170 norm_two += two * two;
171 }
172 }
173 }
174
175 if norm_one == 0.0 || norm_two == 0.0 {
176 return 1.0;
177 }
178
179 1.0 - (dot_product / (norm_one.sqrt() * norm_two.sqrt()))
180 }
181}
182
183impl<P: AsRef<[f32]>> Distance<P> for CosineDistance {
184 fn distance(&self, one: &P, two: &P) -> f32 {
185 let vec_one = one.as_ref();
186 let vec_two = two.as_ref();
187
188 distance::cosine(vec_one, vec_two)
189 }
190}
191
192impl Novelty<Vec<f32>> for CosineDistance {
193 fn description(&self, phenotype: &Vec<f32>) -> Vec<f32> {
194 phenotype.clone()
195 }
196}