Skip to content

Commit

Permalink
Fix FA and improve black hole algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
HeleNoir committed Sep 29, 2023
1 parent 06fb885 commit 5a2cd02
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 36 deletions.
11 changes: 7 additions & 4 deletions src/components/replacement/bh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,18 @@ impl<P> Component<P> for EventHorizon
let fitness_sum = offspring.iter().map(|x| x.objective().value()).sum::<f64>();
let radius = f_bh / fitness_sum;

let rng = &mut state.random_mut();

let best_ind = state.populations().current().best_individual().cloned();
let best = best_ind.unwrap().solution().clone();
let distances = offspring.iter().map(|o| squared_euclidean(o.solution(), &best).sqrt()).collect::<Vec<f64>>();
let distances = offspring
.iter()
.map(|o| squared_euclidean(o.solution(), &best).sqrt())
.collect::<Vec<f64>>();

for (u, mut i) in offspring.iter().enumerate() {
if distances[u] < radius {
let rand: Vec<f64> = (0..problem.dimension()).map(|_| rng.gen_range(problem.domain()[0].clone())).collect();
let rand: Vec<f64> = (0..problem.dimension())
.map(|_| state.random_mut().gen_range(problem.domain()[0].clone()))
.collect();
let j = Individual::new_unevaluated(rand);
i = &j;
}
Expand Down
77 changes: 77 additions & 0 deletions src/components/swarm/bh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
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};

/// Updates the positions in the black hole algorithm.
///
/// Originally proposed for, and used as operator in [`bh`].
/// The operator is similar to the [`ParticleVelocitiesUpdate`] in [`pso`].
/// Specifically, they are identical when for [`pso`]:
/// inertia weight = 0,
/// c_1 = 0,
/// c_2 = 1,
/// v_max = 1
///
/// [`bh`]: crate::heuristics::bh
#[derive(Clone, Serialize)]
pub struct BlackHoleParticlesUpdate<I: Identifier = Global> {
id: PhantomId<I>,
}

impl<I: Identifier> BlackHoleParticlesUpdate<I> {
pub fn from_params() -> Self {
Self {
id: PhantomId::default(),
}
}

pub fn new_with_id<P>() -> Box<dyn Component<P>>
where
P: LimitedVectorProblem<Element = f64>,
{
Box::new(Self::from_params())
}
}

impl BlackHoleParticlesUpdate<Global> {
pub fn new<P>() -> Box<dyn Component<P>>
where
P: LimitedVectorProblem<Element = f64>,
{
Self::new_with_id()
}
}

impl<P, I> Component<P> for BlackHoleParticlesUpdate<I>
where
P: LimitedVectorProblem<Element = f64>,
I: Identifier,
{
fn init(&self, _problem: &P, _state: &mut State<P>) -> ExecResult<()> {
Ok(())
}

fn execute(&self, _problem: &P, state: &mut State<P>) -> ExecResult<()> {
let mut 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();

// Perform the update step.
for x in xs {
for i in 0..x.len() {
// Calculate change in position
let pos = distr.sample(&mut *state.random_mut()) * (xg[i] - x[i]);
// Add value to particle position
x[i] += pos;
}
}
Ok(())
}
}
21 changes: 5 additions & 16 deletions src/components/swarm/fa.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::array::from_mut;
use std::ops::Deref;

use better_any::{Tid, TidAble};
use derive_more::{Deref, DerefMut};
Expand Down Expand Up @@ -69,20 +68,13 @@ impl<P, I> Component<P> for FireflyPositionsUpdate<I>

fn execute(&self, problem: &P, state: &mut State<P>) -> ExecResult<()> {



// Prepare parameters
let &Self {
beta, gamma, ..
} = self;
let a = state.get_value::<RandomizationParameter>();

// Get necessary state

//let binding = state.borrow_mut::<Evaluator<P, I>>();
//let mut evaluator = binding.deref();
//let mut populations = state.populations_mut();
let mut rng = state.random_mut();
// Get population from state
let mut individuals = state.populations_mut().pop();

// scale for adapting to problem domain
Expand All @@ -91,30 +83,27 @@ impl<P, I> Component<P> for FireflyPositionsUpdate<I>
.map(|p| (p.end - p.start).abs())
.collect::<Vec<f64>>();


// Perform the update step.
// compare all individuals
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<f64> = (0..problem.dimension()).map(|_| rng.gen_range(0.0..1.0)).collect();
let rands: Vec<f64> = (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)| {
// calculate "attractiveness"
//let b = ;
// calculate value that should be added to current position
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;

state.holding::<Evaluator<P, I>>(
|evaluator: &mut Evaluator<P, I>, state| {
evaluator.evaluate(problem, state, from_mut(&mut individuals[i]));
evaluator
.as_inner_mut()
.evaluate(problem, state, from_mut(&mut individuals[i]));
Ok(())
},
)?;
Expand Down
3 changes: 2 additions & 1 deletion src/components/swarm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod bh;
pub mod fa;
pub mod pso;
pub mod pso;
15 changes: 2 additions & 13 deletions src/heuristics/bh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,17 @@
//! In Information Sciences 222, 175–184.
//! DOI:<http://dx.doi.org/10.1016/j.ins.2012.08.023>
use eyre::WrapErr;

use crate::{
component::ExecResult,
components::{boundary, initialization, mapping, swarm},
components::{boundary, initialization, swarm},
conditions::Condition,
configuration::Configuration,
identifier::{Global, Identifier},
lens::ValueOf,
logging::Logger,
problems::{LimitedVectorProblem, SingleObjectiveProblem},
state::common,
Component,
};
use crate::components::replacement;
use crate::prelude::selection::selection;

/// Parameters for [`real_bh`].
pub struct RealProblemParameters {
Expand All @@ -49,13 +44,7 @@ pub fn real_bh<P>(
.update_best_individual()
.do_(bh::<P, Global>(
Parameters {
particle_update: swarm::pso::ParticleVelocitiesUpdate::new(
0.0,
0.0,
1.0,
1.0,
)
.wrap_err("failed to construct particle velocities update")?,
particle_update: swarm::bh::BlackHoleParticlesUpdate::new(),
constraints: boundary::Saturation::new(),
},
condition,
Expand Down
2 changes: 0 additions & 2 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
use std::marker::PhantomData;

use derivative::Derivative;
use crate::problems::VectorProblem;
use crate::{SingleObjective, SingleObjectiveProblem};

/// Allows enumeration for functions which normally don't support enumeration, e.g. [`Vec::retain`].
///
Expand Down

0 comments on commit 5a2cd02

Please sign in to comment.