From 4d86e224ee6811a86789797d55f82582a61d9d79 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Fri, 31 Oct 2025 15:56:02 +0100 Subject: [PATCH] feat: add possibility to evolve strategy during evolution_algorithm --- codes/eoa_lib/src/evolution.rs | 55 ++++++++++++++++++++++++++-------- codes/tsp_hw01/src/main.rs | 33 +++++++++++++------- 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/codes/eoa_lib/src/evolution.rs b/codes/eoa_lib/src/evolution.rs index bf2e9c0fc6e4afd0b97e438725e99476b3e6b605..6b52d3278b26e7b6d47280a1c52be581105be5d4 100644 --- a/codes/eoa_lib/src/evolution.rs +++ b/codes/eoa_lib/src/evolution.rs @@ -28,19 +28,38 @@ pub struct EvolutionResult { pub iterations: usize } -pub fn evolution_algorithm( +pub fn evolution_algorithm + , + TPairing: Pairing, + TCrossover: Crossover, + TReplacement: Replacement, + TPerturbation: PerturbationOperator>( initial_population: Population, parents_count: usize, fitness: &impl FitnessFunction, - selection: &impl Selection, - pairing: &impl Pairing, - crossover: &impl Crossover, - perturbation: &impl PerturbationOperator, - replacement: &impl Replacement, + selection: &mut TSelection, + pairing: &mut TPairing, + crossover: &mut TCrossover, + perturbation: &mut TPerturbation, + replacement: &mut TReplacement, better_than: &impl BetterThanOperator, // TODO: termination condition iterations: usize, rng: &mut dyn RngCore, + mut evolution: impl FnMut( + usize, + &EvolutionStats, + &EvaluatedPopulation, + + &mut TSelection, + &mut TPairing, + &mut TCrossover, + &mut TPerturbation, + &mut TReplacement + ) ) -> Result, Box> { let mut current_population = initial_population.evaluate(fitness)?; @@ -84,6 +103,17 @@ pub fn evolution_algorithm, optimal_cost: f64, base_ // Create combined perturbation with two mutations wrapped in MutationPerturbation let swap_mutation = MutationPerturbation::new(Box::new(SwapPerturbation::new()), 0.5); let reverse_mutation = MutationPerturbation::new(Box::new(ReverseSubsequencePerturbation::new()), 0.5); - let combined_perturbation = CombinedPerturbation::new(vec![ + let mut combined_perturbation = CombinedPerturbation::new(vec![ Box::new(swap_mutation), Box::new(reverse_mutation), ]); // Set up other components - let crossover = EdgeRecombinationCrossover::new(); - let selection = TournamentSelection::new(5, 0.8); - let replacement = BestReplacement::new(); - let pairing = AdjacentPairing::new(); + let mut crossover = EdgeRecombinationCrossover::new(); + let mut selection = TournamentSelection::new(5, 0.8); + let mut replacement = BestReplacement::new(); + let mut pairing = AdjacentPairing::new(); let better_than_operator = MinimizingOperator::new(); // Create initial population @@ -116,18 +116,29 @@ fn run_evolution_algorithm(instance: &TSPInstance, optimal_cost: f64, base_ // Run evolution algorithm let parents_count = 250; - let result = evolution_algorithm::<_, _, 2>( + let result = evolution_algorithm( initial_population.clone(), parents_count, instance, - &selection, - &pairing, - &crossover, - &combined_perturbation, - &replacement, + &mut selection, + &mut pairing, + &mut crossover, + &mut combined_perturbation, + &mut replacement, &better_than_operator, 5000, // max iterations &mut rng, + |iteration, stats, _, _, _, _, perturbation, _| { + let iters_till_end = 5000 - iteration + 1; + let iters_since_better = + iteration - stats.best_candidates.last().map(|c| c.iteration).unwrap_or(0); + MutationPerturbation::apply_to_mutations( + perturbation, + &mut |p| { + p.probability = (0.5 * (1.0 + (iters_since_better as f64 / iters_till_end as f64))).min(1.0); + } + ); + } )?; // Plot the best solution