From 4f73795a66b0641ffd4f71a01bee2dc21bc5e03d Mon Sep 17 00:00:00 2001 From: Helena Stegherr Date: Tue, 20 Aug 2024 15:37:39 +0200 Subject: [PATCH 1/3] Add new diversity measures from Mascarenhas et al --- src/components/measures/diversity.rs | 180 ++++++++++++++++++++++++++- 1 file changed, 179 insertions(+), 1 deletion(-) diff --git a/src/components/measures/diversity.rs b/src/components/measures/diversity.rs index afea2ed..f02915d 100644 --- a/src/components/measures/diversity.rs +++ b/src/components/measures/diversity.rs @@ -11,9 +11,13 @@ //! Review and Study of Genotypic Diversity Measures for Real-Coded Representations. //! IEEE Transactions on Evolutionary Computation 16, 5 (October 2012), 695–710. //! DOI: +//! +//! \[3\] A. Mascarenhas, Y. Kobayashi and C. Aranha. 2024. +//! Novel Genotypic Diversity Metrics for Real-Coded Optimization on Multi-Modal Problems. +//! 2024 IEEE Congress on Evolutionary Computation (CEC), Yokohama, Japan, pp. 1-8. +//! DOI: . use std::{any::type_name, marker::PhantomData}; - use better_any::{Tid, TidAble}; use derivative::Derivative; use serde::Serialize; @@ -354,3 +358,177 @@ where diversity_measure(self, problem, state) } } + + +/// Measures the minimum sum of individual distances as described by Mascarenhas et al. +/// +/// The value is stored in the [`Diversity`] state. +#[derive(Clone, Serialize)] +pub struct MinimumIndividualDistance; + +impl MinimumIndividualDistance { + pub fn from_params() -> Self { + Self + } + + pub fn new

() -> Box> + where + P: VectorProblem, + { + Box::new(Self::from_params()) + } +} + +impl

DiversityMeasure

for MinimumIndividualDistance +where + P: VectorProblem, +{ + fn measure(&self, _problem: &P, solutions: &[&Vec]) -> f64 { + let n = solutions.len(); + + let mut min_dist = vec![-1.0; n]; + + for (ind1_i, ind1) in solutions.iter().enumerate() { + + for ind2 in solutions.iter() { + if ind1 == ind2 { + continue; + } + + let mut sum_d = 0.0; + for (x1, x2) in ind1.iter().zip(ind2.iter()) { + sum_d += (x1 - x2).powi(2); + } + let d = sum_d.sqrt(); // Euclidean distance + + if d < min_dist[ind1_i] || min_dist[ind1_i] == -1.0 { + min_dist[ind1_i] = d; + } + } + } + min_dist.iter().sum::() + } +} + +impl

Component

for MinimumIndividualDistance +where + P: VectorProblem, +{ + fn init(&self, _problem: &P, state: &mut State

) -> ExecResult<()> { + state.insert(Diversity::::new()); + Ok(()) + } + + fn execute(&self, problem: &P, state: &mut State

) -> ExecResult<()> { + diversity_measure(self, problem, state) + } +} + + +/// Measures the radius diversity as described by Mascarenhas et al. +/// +/// The value is stored in the [`Diversity`] state. +/// +/// *The code for this measure was generated with the help of ChatGPT (GPT-3.5) using the code +/// provided by Mascarenhas et al. at and +/// .* +#[derive(Clone, Serialize)] +pub struct RadiusDiversity; + +impl RadiusDiversity { + pub fn from_params() -> Self { + Self + } + + pub fn new

() -> Box> + where + P: VectorProblem, + { + Box::new(Self::from_params()) + } +} + +impl

DiversityMeasure

for RadiusDiversity +where + P: VectorProblem, +{ + fn measure(&self, _problem: &P, solutions: &[&Vec]) -> f64 { + + // Calculate the distance matrix using the Euclidean distance + let mut dist_matrix = vec![vec![0.0; solutions.len()]; solutions.len()]; + for i in 0..solutions.len() { + for j in 0..solutions.len() { + if i != j { + let sum_sq: f64 = solutions[i].iter() + .zip(solutions[j].iter()) + .map(|(x1, x2)| (x1 - x2).powi(2)) + .sum(); + dist_matrix[i][j] = sum_sq.sqrt(); + } + } + } + + let mut selected_flag = vec![false; solutions.len()]; + let original_indices: Vec = (0..solutions.len()).collect(); + + let sigma = dist_matrix.iter().flat_map(|row| row.iter()).cloned().fold(f64::NEG_INFINITY, f64::max); + let max_indices: Vec = dist_matrix.iter() + .enumerate() + .flat_map(|(i, row)| row.iter().enumerate().map(move |(j, &val)| (i, j, val))) + .filter(|&(_, _, val)| val == sigma) + .map(|(i, _j, _)| i) + .take(2) + .collect(); + + selected_flag[max_indices[0]] = true; + selected_flag[max_indices[1]] = true; + + let mut selected_indices = vec![max_indices[0], max_indices[1]]; + let mut sigma_list = vec![0.0, sigma]; + + while selected_indices.len() < solutions.len() { + let shortest_distances_list: Vec = (0..solutions.len()) + .filter(|&i| !selected_flag[i]) + .map(|i| { + (0..solutions.len()) + .filter(|&j| selected_flag[j]) + .map(|j| dist_matrix[i][j]) + .fold(f64::INFINITY, f64::min) + }) + .collect(); + + let max_index = shortest_distances_list.iter() + .cloned() + .enumerate() + .fold((0, f64::NEG_INFINITY), |(max_idx, max_val), (idx, val)| { + if val > max_val { (idx, val) } else { (max_idx, max_val) } + }).0; + + let max_original_index = original_indices.iter() + .filter(|&&idx| !selected_flag[idx]) + .nth(max_index) + .unwrap(); + + selected_flag[*max_original_index] = true; + selected_indices.push(*max_original_index); + let sigma = shortest_distances_list[max_index]; + sigma_list.push(sigma); + } + + sigma_list.iter().sum() + } +} + +impl

Component

for RadiusDiversity +where + P: VectorProblem, +{ + fn init(&self, _problem: &P, state: &mut State

) -> ExecResult<()> { + state.insert(Diversity::::new()); + Ok(()) + } + + fn execute(&self, problem: &P, state: &mut State

) -> ExecResult<()> { + diversity_measure(self, problem, state) + } +} \ No newline at end of file From dd3a2d2eea10f1073f3cf52e03cab1d1911db70b Mon Sep 17 00:00:00 2001 From: Helena Stegherr Date: Thu, 29 Aug 2024 10:43:26 +0200 Subject: [PATCH 2/3] Fix DE mutation --- src/components/mutation/de.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/mutation/de.rs b/src/components/mutation/de.rs index a4ffa51..11b6035 100644 --- a/src/components/mutation/de.rs +++ b/src/components/mutation/de.rs @@ -63,7 +63,7 @@ where let size = (self.y * 2 + 1) as usize; - if !population.len() % size == 0 { + if population.len() % size != 0 { return Err(eyre!("the population must be in the format [`y` * 2 + 1]*, where the first individual is the base of the mutation")) .suggestion("try to use an appropriate selection method for this mutation"); } From 201aa389cf5d665b9484ac242b4d04b8edd2516a Mon Sep 17 00:00:00 2001 From: Helena Stegherr Date: Thu, 29 Aug 2024 10:51:11 +0200 Subject: [PATCH 3/3] Fix formatting --- src/components/measures/diversity.rs | 34 ++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/components/measures/diversity.rs b/src/components/measures/diversity.rs index f02915d..eda9bfe 100644 --- a/src/components/measures/diversity.rs +++ b/src/components/measures/diversity.rs @@ -18,6 +18,7 @@ //! DOI: . use std::{any::type_name, marker::PhantomData}; + use better_any::{Tid, TidAble}; use derivative::Derivative; use serde::Serialize; @@ -359,7 +360,6 @@ where } } - /// Measures the minimum sum of individual distances as described by Mascarenhas et al. /// /// The value is stored in the [`Diversity`] state. @@ -389,7 +389,6 @@ where let mut min_dist = vec![-1.0; n]; for (ind1_i, ind1) in solutions.iter().enumerate() { - for ind2 in solutions.iter() { if ind1 == ind2 { continue; @@ -424,7 +423,6 @@ where } } - /// Measures the radius diversity as described by Mascarenhas et al. /// /// The value is stored in the [`Diversity`] state. @@ -453,13 +451,13 @@ where P: VectorProblem, { fn measure(&self, _problem: &P, solutions: &[&Vec]) -> f64 { - // Calculate the distance matrix using the Euclidean distance let mut dist_matrix = vec![vec![0.0; solutions.len()]; solutions.len()]; for i in 0..solutions.len() { for j in 0..solutions.len() { if i != j { - let sum_sq: f64 = solutions[i].iter() + let sum_sq: f64 = solutions[i] + .iter() .zip(solutions[j].iter()) .map(|(x1, x2)| (x1 - x2).powi(2)) .sum(); @@ -471,8 +469,13 @@ where let mut selected_flag = vec![false; solutions.len()]; let original_indices: Vec = (0..solutions.len()).collect(); - let sigma = dist_matrix.iter().flat_map(|row| row.iter()).cloned().fold(f64::NEG_INFINITY, f64::max); - let max_indices: Vec = dist_matrix.iter() + let sigma = dist_matrix + .iter() + .flat_map(|row| row.iter()) + .cloned() + .fold(f64::NEG_INFINITY, f64::max); + let max_indices: Vec = dist_matrix + .iter() .enumerate() .flat_map(|(i, row)| row.iter().enumerate().map(move |(j, &val)| (i, j, val))) .filter(|&(_, _, val)| val == sigma) @@ -497,14 +500,21 @@ where }) .collect(); - let max_index = shortest_distances_list.iter() + let max_index = shortest_distances_list + .iter() .cloned() .enumerate() .fold((0, f64::NEG_INFINITY), |(max_idx, max_val), (idx, val)| { - if val > max_val { (idx, val) } else { (max_idx, max_val) } - }).0; + if val > max_val { + (idx, val) + } else { + (max_idx, max_val) + } + }) + .0; - let max_original_index = original_indices.iter() + let max_original_index = original_indices + .iter() .filter(|&&idx| !selected_flag[idx]) .nth(max_index) .unwrap(); @@ -531,4 +541,4 @@ where fn execute(&self, problem: &P, state: &mut State

) -> ExecResult<()> { diversity_measure(self, problem, state) } -} \ No newline at end of file +}