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, GaussianParams, Mutation, Selection, Survivor};
use genetic_algorithms::traits::{ChromosomeT, LinearChromosome};
#[cfg(feature = "observer-metrics")]
use genetic_algorithms::MetricsObserver;
use genetic_algorithms::{CompositeObserver, IslandGaObserver, LogObserver};
use std::sync::Arc;
fn main() {
let _ = env_logger::try_init();
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);
use genetic_algorithms::traits::{
ConfigurationT, CrossoverConfig, MutationConfig, SelectionConfig, StoppingConfig,
};
use genetic_algorithms::ChromosomeLength;
let mutation_probs = [0.01_f64, 0.05, 0.10, 0.20];
let ga_configs: Vec<GaConfiguration> = mutation_probs
.iter()
.map(|&prob| {
GaConfiguration::default()
.with_population_size(POP_SIZE_PER_ISLAND)
.with_chromosome_length(ChromosomeLength::Fixed(DIMENSIONS))
.with_problem_solving(ProblemSolving::Minimization)
.with_max_generations(MAX_GENERATIONS)
.with_mutation_probability_max(prob)
.with_mutation_method(Mutation::Gaussian(GaussianParams { sigma: None }))
.with_crossover_method(Crossover::Uniform)
.with_selection_method(Selection::Tournament)
.with_survivor_method(Survivor::Fitness)
})
.collect();
let composite = CompositeObserver::new().register(Arc::new(LogObserver));
#[cfg(feature = "observer-metrics")]
let composite = composite.register(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))
})
.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);
}
}
}