use crate::binary_string::{BinaryString, Bounds};
use crate::fitness::one_max::OneMax;
use crate::fitness::sphere::Sphere;
use crate::terminating::{AndTerminatingConditions, EqualTerminatingCondition, NoBetterForCyclesTerminatingCondition, TerminatingCondition};
use crate::perturbation::{BinaryStringBitPerturbation, PerturbationOperator};
use crate::comparison::{BetterThanOperator, MinimizingOperator};
use crate::fitness::{FitnessFunction, BinaryFitnessWrapper};
// Functions
#[derive(Debug, Clone, PartialEq)]
pub struct LocalSearchCandidate<T>
where T: Clone
{
pub fit: T,
pub pos: BinaryString,
pub cycle: usize
}
#[derive(Debug, Clone, PartialEq)]
pub struct LocalSearchResult<T>
where T: Clone
{
pub best_candidate: LocalSearchCandidate<T>,
// How many cycles there were
pub cycles: usize,
// statistics
pub best_candidates: Vec<LocalSearchCandidate<T>>
}
fn local_search_first_improving<
T, TErr, TFit, TTerminatingCondition, TPerturbationOperator, TBetterThanOperator>(
fit: &TFit,
terminating_condition: &mut TTerminatingCondition,
perturbation_operator: &mut TPerturbationOperator,
better_than_operator: &TBetterThanOperator,
initial: &BinaryString
) -> Result<LocalSearchResult<T>, TErr>
where
T: Clone,
TFit: FitnessFunction<In = BinaryString, Out = T, Err = TErr>,
TTerminatingCondition: TerminatingCondition<T>,
TPerturbationOperator: PerturbationOperator<Chromosome = BinaryString>,
TBetterThanOperator: BetterThanOperator<T>,
{
let mut best_candidate = LocalSearchCandidate {
pos: initial.clone(),
fit: fit.fit(&initial)?,
cycle: 0
};
let mut stats: Vec<LocalSearchCandidate<T>> = vec![];
let mut cycle: usize = 0;
while !terminating_condition.should_terminate(&best_candidate, &stats, cycle) {
let perturbed = perturbation_operator.perturb(&best_candidate.pos);
let perturbed_fit = fit.fit(&perturbed)?;
// Minimize
if better_than_operator.better_than(&perturbed_fit, &best_candidate.fit) {
best_candidate = LocalSearchCandidate {
pos: perturbed.clone(),
fit: perturbed_fit,
cycle
};
stats.push(best_candidate.clone());
}
cycle += 1;
}
Ok(LocalSearchResult {
best_candidate,
best_candidates: stats,
cycles: cycle
})
}
#[test]
fn test_local_search_sphere() {
let optimum = BinaryString::new(vec![0, 0, 1, 0, 0,
0, 0, 1, 0, 0]);
let bounds = vec![Bounds::new(0.0, 31.0), Bounds::new(0.0, 31.0)];
let optimum_real = optimum.to_real(&bounds).unwrap();
let sphere = Sphere::new(optimum_real);
let sphere_wrapped = BinaryFitnessWrapper::new(sphere, bounds);
let result = local_search_first_improving(
&sphere_wrapped,
&mut
AndTerminatingConditions::new(
vec![
&mut EqualTerminatingCondition::new_remembered(optimum.clone()),
&mut NoBetterForCyclesTerminatingCondition::new(100)
]
),
&mut BinaryStringBitPerturbation::new(0.3),
&MinimizingOperator::new(),
&BinaryString::new(vec![1; 10]),
).unwrap();
println!("{:?}", result);
assert_eq!(
result.best_candidate.fit,
0.0
);
assert_eq!(
result.best_candidate.pos,
optimum
);
}
#[test]
fn test_local_search_one_max() {
let one_max = OneMax::new();
let optimum = BinaryString::new(vec![0; 10]);
let result = local_search_first_improving(
&one_max,
&mut
AndTerminatingConditions::new(
vec![
&mut EqualTerminatingCondition::new_remembered(optimum.clone()),
&mut NoBetterForCyclesTerminatingCondition::new(100)
]
),
&mut BinaryStringBitPerturbation::new(0.3),
&MinimizingOperator::new(),
&BinaryString::new(vec![1; 10]),
).unwrap();
println!("{:?}", result);
assert_eq!(
result.best_candidate.fit,
0
);
assert_eq!(
result.best_candidate.pos,
optimum
);
}