@@ 0,0 1,65 @@
+use std::convert::Infallible;
+
+use nalgebra::SVector;
+use rand_distr::{Normal, NormalError};
+
+use crate::{local_search::LocalSearchCandidate, perturbation::{BoundedPerturbation, PerturbationOperator, RandomDistributionPerturbation}};
+
+pub trait EvolutionaryStrategy<TOut, TPerturbation: PerturbationOperator> {
+ type Err;
+
+ fn step(&mut self,
+ perturbation: &mut TPerturbation,
+ better: bool,
+ stats: &Vec<LocalSearchCandidate<TPerturbation::Chromosome, TOut>>
+ ) -> Result<(), Self::Err>;
+}
+
+fn normal_one_to_five<const LEN: usize>(perturbation: &mut RandomDistributionPerturbation<LEN, Normal<f64>>, better: bool) -> Result<(), NormalError> {
+ let exp: f64 = if better { 1.0 } else { 0.0 } - 0.2;
+ let sigma = perturbation.std_dev();
+
+ let new_sigma = sigma * exp.exp().powf(1.0 / LEN as f64);
+
+ perturbation.set_std_dev(new_sigma)?;
+ Ok(())
+}
+
+pub struct OneToFiveStrategy;
+impl<const LEN: usize, TOut> EvolutionaryStrategy<TOut, RandomDistributionPerturbation<LEN, Normal<f64>>> for OneToFiveStrategy {
+ type Err = NormalError;
+
+ fn step(&mut self,
+ perturbation: &mut RandomDistributionPerturbation<LEN, Normal<f64>>,
+ better: bool,
+ _: &Vec<LocalSearchCandidate<SVector::<f64, LEN>, TOut>>
+ ) -> Result<(), Self::Err> {
+ normal_one_to_five(perturbation, better)
+ }
+}
+
+impl<const LEN: usize, TOut> EvolutionaryStrategy<TOut, BoundedPerturbation<LEN, RandomDistributionPerturbation<LEN, Normal<f64>>>> for OneToFiveStrategy {
+ type Err = NormalError;
+
+ fn step(&mut self,
+ perturbation: &mut BoundedPerturbation<LEN, RandomDistributionPerturbation<LEN, Normal<f64>>>,
+ better: bool,
+ _: &Vec<LocalSearchCandidate<<BoundedPerturbation<LEN, RandomDistributionPerturbation<LEN, Normal<f64>>> as PerturbationOperator>::Chromosome, TOut>>
+ ) -> Result<(), Self::Err> {
+ normal_one_to_five(perturbation.inner_mut(), better)
+ }
+
+}
+
+pub struct IdentityStrategy;
+impl<TOut, TPerturbation: PerturbationOperator> EvolutionaryStrategy<TOut, TPerturbation> for IdentityStrategy {
+ type Err = Infallible;
+
+ fn step(&mut self,
+ _: &mut TPerturbation,
+ _: bool,
+ _: &Vec<LocalSearchCandidate<TPerturbation::Chromosome, TOut>>
+ ) -> Result<(), Self::Err> {
+ Ok(())
+ }
+}
@@ 1,5 1,5 @@
-use crate::binary_string::BinaryString;
-
+use std::fmt::Debug;
+use crate::evolutionary_strategy::{EvolutionaryStrategy, IdentityStrategy};
use crate::fitness::FitnessFunction;
use crate::terminating::TerminatingCondition;
use crate::perturbation::PerturbationOperator;
@@ 43,6 43,35 @@ where
TPerturbationOperator: PerturbationOperator<Chromosome = TInput>,
TBetterThanOperator: BetterThanOperator<TResult>,
{
+ local_search_first_improving_evolving(
+ fit,
+ terminating_condition,
+ perturbation_operator,
+ better_than_operator,
+ &mut IdentityStrategy,
+ initial
+ )
+}
+
+fn local_search_first_improving_evolving<
+ TInput, TResult, TErr, TFit, TTerminatingCondition, TPerturbationOperator, TBetterThanOperator, TEvolutionaryStrategy>(
+ fit: &TFit,
+ terminating_condition: &mut TTerminatingCondition,
+ perturbation_operator: &mut TPerturbationOperator,
+ better_than_operator: &TBetterThanOperator,
+ evolutionary_strategy: &mut TEvolutionaryStrategy,
+ initial: &TInput
+) -> Result<LocalSearchResult<TInput, TResult>, TErr>
+where
+ TResult: Clone,
+ TInput: Clone,
+ TFit: FitnessFunction<In = TInput, Out = TResult, Err = TErr>,
+ TTerminatingCondition: TerminatingCondition<TInput, TResult>,
+ TPerturbationOperator: PerturbationOperator<Chromosome = TInput>,
+ TEvolutionaryStrategy: EvolutionaryStrategy<TResult, TPerturbationOperator>,
+ TBetterThanOperator: BetterThanOperator<TResult>,
+ <TEvolutionaryStrategy as EvolutionaryStrategy<TResult, TPerturbationOperator>>::Err: Debug
+{
let mut best_candidate = LocalSearchCandidate {
pos: initial.clone(),
fit: fit.fit(&initial)?,
@@ 57,7 86,7 @@ where
let perturbed_fit = fit.fit(&perturbed)?;
// Minimize
- if better_than_operator.better_than(&perturbed_fit, &best_candidate.fit) {
+ let better = if better_than_operator.better_than(&perturbed_fit, &best_candidate.fit) {
best_candidate = LocalSearchCandidate {
pos: perturbed.clone(),
fit: perturbed_fit,
@@ 65,7 94,18 @@ where
};
stats.push(best_candidate.clone());
- }
+
+ true
+ } else {
+ false
+ };
+
+ evolutionary_strategy.step(
+ perturbation_operator,
+ better,
+ &stats)
+ // TODO
+ .expect("Evolution failed.");
cycle += 1;
}
@@ 81,7 121,7 @@ where
pub mod tests {
use nalgebra::SVector;
- use crate::{binary_string::{BinaryString, Bounds}, comparison::MinimizingOperator, fitness::{one_max::OneMax, real::Linear, rosenbrock::Rosenbrock, sphere::Sphere, BinaryFitnessWrapper}, local_search::local_search_first_improving, perturbation::{BinaryStringBitPerturbation, BoundedPerturbation, BoundedPerturbationStrategy, PatternPerturbation, RandomDistributionPerturbation}, terminating::{AndTerminatingConditions, EqualTerminatingCondition, NoBetterForCyclesTerminatingCondition}};
+ use crate::{binary_string::{BinaryString, Bounds}, comparison::MinimizingOperator, evolutionary_strategy::OneToFiveStrategy, fitness::{one_max::OneMax, real::Linear, rosenbrock::Rosenbrock, sphere::Sphere, BinaryFitnessWrapper}, local_search::{local_search_first_improving, local_search_first_improving_evolving}, perturbation::{BinaryStringBitPerturbation, BoundedPerturbation, BoundedPerturbationStrategy, PatternPerturbation, RandomDistributionPerturbation}, terminating::{AndTerminatingConditions, EqualTerminatingCondition, NoBetterForCyclesTerminatingCondition}};
#[test]
fn test_local_search_sphere() {
@@ 295,4 335,44 @@ pub mod tests {
optimum
);
}
+
+ #[test]
+ fn test_local_search_linear_onetofive() {
+ let optimum = SVector::<f64, 2>::from_vec(vec![-10.0, 10.0]);
+ let max = SVector::<f64, 2>::from_vec(vec![10.0, 10.0]);
+ let min = -SVector::<f64, 2>::from_vec(vec![10.0, 10.0]);
+
+ let linear = Linear::new(7.0, SVector::<f64, 2>::from_vec(vec![0.2, -0.5]));
+
+ let result = local_search_first_improving_evolving(
+ &linear,
+ &mut
+ AndTerminatingConditions::new(
+ vec![
+ &mut EqualTerminatingCondition::new_remembered(optimum.clone()),
+ &mut NoBetterForCyclesTerminatingCondition::new(100)
+ ]
+ ),
+ &mut BoundedPerturbation::new(
+ RandomDistributionPerturbation::normal(0.5).unwrap(),
+ min,
+ max,
+ BoundedPerturbationStrategy::Retry(10)),
+ &MinimizingOperator::new(),
+ &mut OneToFiveStrategy,
+ &SVector::<f64, 2>::zeros(),
+ ).unwrap();
+
+ println!("{:?}", result);
+
+ assert_eq!(
+ result.best_candidate.fit,
+ -0.0
+ );
+
+ assert_eq!(
+ result.best_candidate.pos,
+ optimum
+ );
+ }
}