diff --git a/src/components/replacement/bh.rs b/src/components/replacement/bh.rs index 481c4ad..2191886 100644 --- a/src/components/replacement/bh.rs +++ b/src/components/replacement/bh.rs @@ -1,11 +1,11 @@ //! Replacement components for the Black Hole algorithm (BH). -use rand::Rng; -use serde::{Deserialize, Serialize}; -use crate::{Component, ExecResult, Individual, SingleObjectiveProblem, State}; use crate::population::BestIndividual; use crate::problems::LimitedVectorProblem; use crate::utils::squared_euclidean; +use crate::{Component, ExecResult, Individual, SingleObjectiveProblem, State}; +use rand::Rng; +use serde::{Deserialize, Serialize}; #[derive(Clone, Serialize, Deserialize)] pub struct EventHorizon; @@ -28,30 +28,35 @@ impl

Component

for EventHorizon fn execute(&self, problem: &P, state: &mut State

) -> ExecResult<()> { let mut populations = state.populations_mut(); - let mut offspring = populations.pop(); + let offspring = populations.pop(); let f_bh = state.best_objective_value().unwrap().value(); let fitness_sum = offspring.iter().map(|x| x.objective().value()).sum::(); let radius = f_bh / fitness_sum; - let best_ind = state.populations().current().best_individual().cloned(); + let best_ind = offspring.best_individual().cloned(); let best = best_ind.unwrap().solution().clone(); let distances = offspring .iter() .map(|o| squared_euclidean(o.solution(), &best).sqrt()) .collect::>(); - for (u, mut i) in offspring.iter().enumerate() { - if distances[u] < radius { + let mut new_offspring: Vec> = vec![]; + for (u, i) in offspring.iter().enumerate() { + // do not replace best individual + if distances[u] < radius && distances[u] != 0.0 { let rand: Vec = (0..problem.dimension()) .map(|_| state.random_mut().gen_range(problem.domain()[0].clone())) .collect(); let j = Individual::new_unevaluated(rand); - i = &j; + //println!("{:?}, {:?}", u, &j); + new_offspring.push(j); + } else { + new_offspring.push(i.clone()); } } - populations.push(offspring); + populations.push(new_offspring); Ok(()) } -} \ No newline at end of file +} diff --git a/src/components/replacement/mod.rs b/src/components/replacement/mod.rs index 14d203f..8bea95c 100644 --- a/src/components/replacement/mod.rs +++ b/src/components/replacement/mod.rs @@ -8,8 +8,8 @@ use crate::{ Individual, Problem, State, }; -pub mod common; pub mod bh; +pub mod common; pub mod sa; pub use common::{ diff --git a/src/components/replacement/sa.rs b/src/components/replacement/sa.rs index abed9ba..5e86de3 100644 --- a/src/components/replacement/sa.rs +++ b/src/components/replacement/sa.rs @@ -49,7 +49,6 @@ impl Component

for ExponentialAnnealingAcceptance Ok(()) } - #[ensures(state.populations().current().len() == 1, "population after should contain a single individual")] #[ensures(state.populations().len() == old(state.populations().len()) - 1)] fn execute(&self, _problem: &P, state: &mut State

) -> ExecResult<()> { @@ -76,7 +75,6 @@ impl Component

for ExponentialAnnealingAcceptance } else { populations.pop(); } - Ok(()) } } diff --git a/src/components/swarm/bh.rs b/src/components/swarm/bh.rs index 9501ef1..2cb59fe 100644 --- a/src/components/swarm/bh.rs +++ b/src/components/swarm/bh.rs @@ -1,10 +1,13 @@ -use rand::{ - distributions::{Distribution, Uniform}, -}; +use rand::distributions::{Distribution, Uniform}; use serde::Serialize; - -use crate::{component::ExecResult, components::Component, identifier::{Global, Identifier, PhantomId}, problems::{LimitedVectorProblem}, State}; use crate::population::{AsSolutionsMut, BestIndividual}; +use crate::{ + component::ExecResult, + components::Component, + identifier::{Global, Identifier, PhantomId}, + problems::{LimitedVectorProblem}, + SingleObjectiveProblem, State +}; /// Updates the positions in the black hole algorithm. /// @@ -31,7 +34,7 @@ impl BlackHoleParticlesUpdate { pub fn new_with_id

() -> Box> where - P: LimitedVectorProblem, + P: SingleObjectiveProblem + LimitedVectorProblem, { Box::new(Self::from_params()) } @@ -40,7 +43,7 @@ impl BlackHoleParticlesUpdate { impl BlackHoleParticlesUpdate { pub fn new

() -> Box> where - P: LimitedVectorProblem, + P: SingleObjectiveProblem + LimitedVectorProblem, { Self::new_with_id() } @@ -48,7 +51,7 @@ impl BlackHoleParticlesUpdate { impl Component

for BlackHoleParticlesUpdate where - P: LimitedVectorProblem, + P: SingleObjectiveProblem + LimitedVectorProblem, I: Identifier, { fn init(&self, _problem: &P, _state: &mut State

) -> ExecResult<()> { @@ -56,12 +59,14 @@ impl Component

for BlackHoleParticlesUpdate } fn execute(&self, _problem: &P, state: &mut State

) -> ExecResult<()> { - let mut distr = Uniform::new(0.0, 1.0); + let distr = Uniform::new(0.0, 1.0); // Get necessary state like global best `xg` let best = state.populations().current().best_individual().cloned(); - let xg = best.unwrap().solution(); - let xs = state.populations_mut().current_mut().as_solutions_mut(); + let binding = best.unwrap(); + let xg = binding.solution(); + let mut binding2 = state.populations_mut(); + let xs = binding2.current_mut().as_solutions_mut(); // Perform the update step. for x in xs { @@ -74,4 +79,4 @@ impl Component

for BlackHoleParticlesUpdate } Ok(()) } -} \ No newline at end of file +} diff --git a/src/components/swarm/fa.rs b/src/components/swarm/fa.rs index 588497f..260ed71 100644 --- a/src/components/swarm/fa.rs +++ b/src/components/swarm/fa.rs @@ -2,13 +2,18 @@ use std::array::from_mut; use better_any::{Tid, TidAble}; use derive_more::{Deref, DerefMut}; -use itertools::{izip}; +use itertools::izip; use rand::Rng; use serde::Serialize; -use crate::{component::ExecResult, components::Component, identifier::{Global, Identifier, PhantomId}, problems::{LimitedVectorProblem}, CustomState, State}; use crate::state::common; use crate::state::common::Evaluator; +use crate::{ + component::ExecResult, + components::Component, + identifier::{Global, Identifier, PhantomId}, + problems::{LimitedVectorProblem}, + CustomState, State}; /// Updates the and firefly positions. /// @@ -67,35 +72,37 @@ impl Component

for FireflyPositionsUpdate } fn execute(&self, problem: &P, state: &mut State

) -> ExecResult<()> { - // Prepare parameters - let &Self { - beta, gamma, .. - } = self; + let &Self { beta, gamma, .. } = self; let a = state.get_value::(); // Get population from state let mut individuals = state.populations_mut().pop(); // scale for adapting to problem domain - let scales = problem.domain() + let scales = problem + .domain() .iter() .map(|p| (p.end - p.start).abs()) .collect::>(); // Perform the update step. - for i in 0..individuals.len() { + for i in 0..individuals.len() { for j in 0..individuals.len() { // if individual j is "more attractive" (i.e. has lower fitness), move towards j if individuals[i].objective() > individuals[j].objective() { // draw random values from uniform distribution between 0 and 1 // according to paper: also possible to use normal distribution, depending on problem - let rands: Vec = (0..problem.dimension()).map(|_| state.random_mut().gen_range(0.0..1.0)).collect(); + let rands: Vec = (0..problem.dimension()) + .map(|_| state.random_mut().gen_range(0.0..1.0)) + .collect(); let mut current = individuals[i].clone(); izip!(current.solution_mut(), individuals[j].solution(), &scales, rands) .map(|(xi, xj, scale, rand)| { - let pos = beta * (-gamma * (*xi - xj).powf(2.0)).exp() * (xj - *xi) + a * (rand - 0.5) * scale; - (xi, pos) }) + let pos = beta * (-gamma * (*xi - xj).powf(2.0)).exp() * (xj - *xi) + + a * (rand - 0.5) * scale; + (xi, pos) + }) .for_each(|(xi, pos)| *xi += pos); individuals[i] = current; @@ -103,7 +110,11 @@ impl Component

for FireflyPositionsUpdate |evaluator: &mut Evaluator, state| { evaluator .as_inner_mut() - .evaluate(problem, state, from_mut(&mut individuals[i])); + .evaluate( + problem, + state, + from_mut(&mut individuals[i]) + ); Ok(()) }, )?; diff --git a/src/components/swarm/pso.rs b/src/components/swarm/pso.rs index 78052c1..14b870d 100644 --- a/src/components/swarm/pso.rs +++ b/src/components/swarm/pso.rs @@ -335,17 +335,17 @@ impl GlobalBestParticleUpdate { } pub fn new

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

for GlobalBestParticleUpdate - where - P: SingleObjectiveProblem + LimitedVectorProblem, - I: Identifier, +where + P: SingleObjectiveProblem + LimitedVectorProblem, + I: Identifier, { fn init(&self, _problem: &P, state: &mut State

) -> ExecResult<()> { state @@ -422,4 +422,4 @@ impl ParticleSwarmUpdate { ) -> Box> { Self::new_with_id() } -} \ No newline at end of file +} diff --git a/src/heuristics/bh.rs b/src/heuristics/bh.rs index 8024502..1061b60 100644 --- a/src/heuristics/bh.rs +++ b/src/heuristics/bh.rs @@ -9,7 +9,7 @@ use crate::{ component::ExecResult, - components::{boundary, initialization, swarm}, + components::{boundary, initialization, replacement, swarm}, conditions::Condition, configuration::Configuration, identifier::{Global, Identifier}, @@ -17,7 +17,6 @@ use crate::{ problems::{LimitedVectorProblem, SingleObjectiveProblem}, Component, }; -use crate::components::replacement; /// Parameters for [`real_bh`]. pub struct RealProblemParameters { @@ -31,12 +30,10 @@ pub fn real_bh

( params: RealProblemParameters, condition: Box>, ) -> ExecResult> - where - P: SingleObjectiveProblem + LimitedVectorProblem, +where + P: SingleObjectiveProblem + LimitedVectorProblem, { - let RealProblemParameters { - num_particles, - } = params; + let RealProblemParameters { num_particles } = params; Ok(Configuration::builder() .do_(initialization::RandomSpread::new(num_particles)) @@ -46,6 +43,7 @@ pub fn real_bh

( Parameters { particle_update: swarm::bh::BlackHoleParticlesUpdate::new(), constraints: boundary::Saturation::new(), + replacement: replacement::bh::EventHorizon::new(), }, condition, )) @@ -56,17 +54,19 @@ pub fn real_bh

( pub struct Parameters

{ pub particle_update: Box>, pub constraints: Box>, + pub replacement: Box>, } /// A generic single-objective Black Hole algorithm (BH) template. pub fn bh(params: Parameters

, condition: Box>) -> Box> - where - P: SingleObjectiveProblem + LimitedVectorProblem, - I: Identifier, +where + P: SingleObjectiveProblem, + I: Identifier, { let Parameters { particle_update, constraints, + replacement, } = params; Configuration::builder() @@ -76,7 +76,7 @@ pub fn bh(params: Parameters

, condition: Box>) -> Box< .do_(constraints) .evaluate_with::() .update_best_individual() - .do_(replacement::bh::EventHorizon::new()) + .do_(replacement) .evaluate_with::() .update_best_individual() .do_(Logger::new()) diff --git a/src/heuristics/fa.rs b/src/heuristics/fa.rs index 503d435..a68371d 100644 --- a/src/heuristics/fa.rs +++ b/src/heuristics/fa.rs @@ -8,7 +8,6 @@ //! SAGA 2009. Lecture Notes in Computer Science, vol 5792. Springer, Berlin, Heidelberg. //! DOI: - use crate::{ component::ExecResult, components::{boundary, initialization, mapping, swarm}, @@ -37,8 +36,8 @@ pub fn real_fa

( params: RealProblemParameters, condition: Box>, ) -> ExecResult> - where - P: SingleObjectiveProblem + LimitedVectorProblem, +where + P: SingleObjectiveProblem + LimitedVectorProblem, { let RealProblemParameters { pop_size, @@ -54,11 +53,7 @@ pub fn real_fa

( .update_best_individual() .do_(fa::( Parameters { - firefly_update: swarm::fa::FireflyPositionsUpdate::new( - alpha, - beta, - gamma, - ), + firefly_update: swarm::fa::FireflyPositionsUpdate::new(alpha, beta, gamma), constraints: boundary::Saturation::new(), alpha_update: Box::from(mapping::sa::GeometricCooling::new( delta, @@ -79,9 +74,9 @@ pub struct Parameters

{ /// A generic single-objective Firefly Algorithm (FA) template. pub fn fa(params: Parameters

, condition: Box>) -> Box> - where - P: SingleObjectiveProblem, - I: Identifier, +where + P: SingleObjectiveProblem, + I: Identifier, { let Parameters { firefly_update, @@ -100,4 +95,4 @@ pub fn fa(params: Parameters

, condition: Box>) -> Box< .do_(Logger::new()) }) .build_component() -} \ No newline at end of file +} diff --git a/src/heuristics/pso.rs b/src/heuristics/pso.rs index 81e0fe9..fdec30c 100644 --- a/src/heuristics/pso.rs +++ b/src/heuristics/pso.rs @@ -75,7 +75,8 @@ where start_weight, end_weight, ValueOf::>>::new(), - ValueOf::>::new(), + ValueOf::>::new( + ), )), state_update: swarm::pso::ParticleSwarmUpdate::new(), }, diff --git a/src/utils.rs b/src/utils.rs index a1d1956..e322537 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -46,7 +46,6 @@ impl serde::Serialize for SerializablePhantom { } /// Calculates squared Euclidean distance between two vectors. -pub fn squared_euclidean (a: &Vec, b: &Vec) -> f64 -{ +pub fn squared_euclidean (a: &[f64], b: &Vec) -> f64 { a.iter().zip(b).map(|(p, q)| (p - q).powf(2.0)).sum::() -} \ No newline at end of file +}