~ruther/ctu-fee-eoa

4d86e224ee6811a86789797d55f82582a61d9d79 — Rutherther a month ago b999449
feat: add possibility to evolve strategy during evolution_algorithm
2 files changed, 65 insertions(+), 23 deletions(-)

M codes/eoa_lib/src/evolution.rs
M codes/tsp_hw01/src/main.rs
M codes/eoa_lib/src/evolution.rs => codes/eoa_lib/src/evolution.rs +43 -12
@@ 28,19 28,38 @@ pub struct EvolutionResult<TInput, TResult> {
    pub iterations: usize
}

pub fn evolution_algorithm<TChromosome: Clone, TResult: Clone, const DParents: usize>(
pub fn evolution_algorithm
    <TChromosome: Clone,
     TResult: Clone,
     const DParents: usize,
     TSelection: Selection<TChromosome, TResult>,
     TPairing: Pairing<DParents, Chromosome = TChromosome, Out = TResult>,
     TCrossover: Crossover<DParents, Chromosome = TChromosome, Out = TResult>,
     TReplacement: Replacement<TChromosome, TResult>,
     TPerturbation: PerturbationOperator<Chromosome = TChromosome>>(
    initial_population: Population<TChromosome>,
    parents_count: usize,
    fitness: &impl FitnessFunction<In = TChromosome, Out = TResult>,
    selection: &impl Selection<TChromosome, TResult>,
    pairing: &impl Pairing<DParents, Chromosome = TChromosome, Out = TResult>,
    crossover: &impl Crossover<DParents, Chromosome = TChromosome, Out = TResult>,
    perturbation: &impl PerturbationOperator<Chromosome = TChromosome>,
    replacement: &impl Replacement<TChromosome, TResult>,
    selection: &mut TSelection,
    pairing: &mut TPairing,
    crossover: &mut TCrossover,
    perturbation: &mut TPerturbation,
    replacement: &mut TReplacement,
    better_than: &impl BetterThanOperator<TResult>,
    // TODO: termination condition
    iterations: usize,
    rng: &mut dyn RngCore,
    mut evolution: impl FnMut(
        usize,
        &EvolutionStats<TChromosome, TResult>,
        &EvaluatedPopulation<TChromosome, TResult>,

        &mut TSelection,
        &mut TPairing,
        &mut TCrossover,
        &mut TPerturbation,
        &mut TReplacement
    )
) -> Result<EvolutionResult<TChromosome, TResult>, Box<dyn Error>> {
    let mut current_population = initial_population.evaluate(fitness)?;



@@ 84,6 103,17 @@ pub fn evolution_algorithm<TChromosome: Clone, TResult: Clone, const DParents: u

        // Replace
        current_population = replacement.replace(current_population, evaluated_offsprings, better_than, rng);

        evolution(
            iteration,
            &stats,
            &current_population,
            selection,
            pairing,
            crossover,
            perturbation,
            replacement
        );
    }

    let best_candidate = last_best_candidate.evaluated_chromosome.clone();


@@ 124,10 154,10 @@ pub mod tests {
            population,
            50,
            &one_max,
            &TournamentSelection::new(5, 0.8),
            &AdjacentPairing::new(),
            &BinaryOnePointCrossover::new(),
            &CombinedPerturbation::new(
            &mut TournamentSelection::new(5, 0.8),
            &mut AdjacentPairing::new(),
            &mut BinaryOnePointCrossover::new(),
            &mut CombinedPerturbation::new(
                vec![
                    Box::new(MutationPerturbation::new(
                        Box::new(BinaryStringSingleBitPerturbation::new()),


@@ 137,10 167,11 @@ pub mod tests {
                        0.3))
                ]
            ),
            &BestReplacement::new(),
            &mut BestReplacement::new(),
            &MinimizingOperator,
            1000,
            &mut rng
            &mut rng,
            |_, _, _, _, _, _, _, _| ()
        ).unwrap();

        assert_eq!(

M codes/tsp_hw01/src/main.rs => codes/tsp_hw01/src/main.rs +22 -11
@@ 93,16 93,16 @@ fn run_evolution_algorithm(instance: &TSPInstance<Dyn>, 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<Dyn>, 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