use crate::binary_string::BinaryString; #[cfg(test)] use crate::binary_string::Bounds; #[cfg(test)] use crate::fitness::one_max::OneMax; #[cfg(test)] use crate::fitness::sphere::Sphere; #[cfg(test)] use crate::terminating::{AndTerminatingConditions, EqualTerminatingCondition, NoBetterForCyclesTerminatingCondition}; #[cfg(test)] use crate::perturbation::BinaryStringBitPerturbation; #[cfg(test)] use crate::comparison:: MinimizingOperator; #[cfg(test)] use crate::fitness::BinaryFitnessWrapper; use crate::fitness::FitnessFunction; use crate::terminating::TerminatingCondition; use crate::perturbation::PerturbationOperator; use crate::comparison::BetterThanOperator; // Functions #[derive(Debug, Clone, PartialEq)] pub struct LocalSearchCandidate where T: Clone { pub fit: T, pub pos: BinaryString, pub cycle: usize } #[derive(Debug, Clone, PartialEq)] pub struct LocalSearchResult where T: Clone { pub best_candidate: LocalSearchCandidate, // How many cycles there were pub cycles: usize, // statistics pub best_candidates: Vec> } 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, TErr> where T: Clone, TFit: FitnessFunction, TTerminatingCondition: TerminatingCondition, TPerturbationOperator: PerturbationOperator, TBetterThanOperator: BetterThanOperator, { let mut best_candidate = LocalSearchCandidate { pos: initial.clone(), fit: fit.fit(&initial)?, cycle: 0 }; let mut stats: Vec> = 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 ); }