use std::sync::Arc;
use genetic_algorithms::chromosomes::Range as RangeChromosome;
use genetic_algorithms::configuration::{GaConfiguration, ProblemSolving};
use genetic_algorithms::genotypes::Range as RangeGenotype;
use genetic_algorithms::initializers::range_random_initialization;
use genetic_algorithms::island::configuration::IslandConfiguration;
use genetic_algorithms::island::topology::MigrationTopology;
use genetic_algorithms::island::IslandGa;
use genetic_algorithms::operations::{Crossover, Mutation, Selection, Survivor};
use genetic_algorithms::traits::ChromosomeT;
use genetic_algorithms::{CompositeObserver, IslandGaObserver, LogObserver};
#[cfg(feature = "observer-metrics")]
use genetic_algorithms::MetricsObserver;
fn main() {
const DIMENSIONS: usize = 20;
const POP_SIZE_PER_ISLAND: usize = 50;
const MAX_GENERATIONS: usize = 200;
const NUM_ISLANDS: usize = 4;
const MIGRATION_INTERVAL: usize = 10;
const MIGRATION_COUNT: usize = 2;
let fitness_fn = |dna: &[RangeGenotype<f64>]| -> f64 {
let a = 10.0;
let n = dna.len() as f64;
a * n
+ dna.iter()
.map(|g| g.value.powi(2) - a * (2.0 * std::f64::consts::PI * g.value).cos())
.sum::<f64>()
};
let alleles = vec![RangeGenotype::new(0, vec![(-5.12_f64, 5.12_f64)], 0.0_f64)];
let alleles_clone = alleles.clone();
let island_config = IslandConfiguration::new()
.with_num_islands(NUM_ISLANDS)
.with_migration_interval(MIGRATION_INTERVAL)
.with_migration_count(MIGRATION_COUNT)
.with_topology(MigrationTopology::Ring);
let mutation_probs = [0.01_f64, 0.05, 0.10, 0.20];
let ga_configs: Vec<GaConfiguration> = mutation_probs
.iter()
.map(|&prob| {
let mut cfg = GaConfiguration::default();
cfg.limit_configuration.population_size = POP_SIZE_PER_ISLAND;
cfg.limit_configuration.genes_per_chromosome = DIMENSIONS;
cfg.limit_configuration.problem_solving = ProblemSolving::Minimization;
cfg.limit_configuration.max_generations = MAX_GENERATIONS;
cfg.mutation_configuration.probability_max = Some(prob);
cfg.mutation_configuration.method = Mutation::Gaussian;
cfg.crossover_configuration.method = Crossover::Uniform;
cfg.selection_configuration.method = Selection::Tournament;
cfg.survivor = Survivor::Fitness;
cfg
})
.collect();
let composite = CompositeObserver::new()
.add(Arc::new(LogObserver));
#[cfg(feature = "observer-metrics")]
let composite = composite.add(Arc::new(MetricsObserver::new("island_model")));
println!("== Island Model: Rastrigin {}D Minimization ==", DIMENSIONS);
println!(
"Islands: {}, Population per island: {}, Total population: {}",
NUM_ISLANDS,
POP_SIZE_PER_ISLAND,
NUM_ISLANDS * POP_SIZE_PER_ISLAND
);
println!(
"Topology: Ring, Migration: every {} gens, {} migrants",
MIGRATION_INTERVAL, MIGRATION_COUNT
);
println!(
"Mutation probs per island: {:?}",
mutation_probs
);
println!("Max generations: {}", MAX_GENERATIONS);
println!("-------------------------------------------------------");
let mut island_ga =
IslandGa::<RangeChromosome<f64>>::with_heterogeneous_configs(island_config, ga_configs)
.with_alleles(alleles)
.with_initialization_fn(move |n, _, _| {
range_random_initialization(n, Some(&alleles_clone), Some(true))
})
.with_fitness_fn(fitness_fn)
.with_observer(Arc::new(composite) as Arc<dyn IslandGaObserver<RangeChromosome<f64>> + Send + Sync>)
.build()
.expect("Failed to build island GA");
match island_ga.run() {
Ok(best) => {
println!("-------------------------------------------------------");
println!("Best fitness: {:.6}", best.fitness());
let first_five: Vec<f64> = best.dna()[0..5].iter().map(|g| g.value).collect();
println!("Best solution (first 5 dims): {:?}", first_five);
if best.fitness() < 50.0 {
println!("Good convergence for 20D Rastrigin!");
} else {
println!("Try increasing generations or population size.");
}
}
Err(e) => {
println!("Island GA failed: {:?}", e);
std::process::exit(1);
}
}
}