use std::sync::Arc;
use genetic_algorithms::chromosomes::Range as RangeChromosome;
use genetic_algorithms::configuration::ProblemSolving;
use genetic_algorithms::ga::{Ga, TerminationCause};
use genetic_algorithms::genotypes::Range as RangeGenotype;
use genetic_algorithms::initializers::range_random_initialization;
use genetic_algorithms::operations::{Crossover, Mutation, Selection, Survivor};
use genetic_algorithms::population::Population;
use genetic_algorithms::stats::GenerationStats;
use genetic_algorithms::traits::{
ChromosomeT, ConfigurationT, CrossoverConfig, MutationConfig, SelectionConfig, StoppingConfig,
};
use genetic_algorithms::{CompositeObserver, LogObserver};
#[cfg(feature = "observer-metrics")]
use genetic_algorithms::MetricsObserver;
fn main() {
const DIMENSIONS: usize = 5;
const POP_SIZE: usize = 100;
const MAX_GENERATIONS: usize = 500;
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, 5.12)], 0.0_f64)];
let alleles_clone = alleles.clone();
let composite = CompositeObserver::new()
.add(Arc::new(LogObserver));
#[cfg(feature = "observer-metrics")]
let composite = composite.add(Arc::new(MetricsObserver::new("rastrigin")));
let mut ga = Ga::new()
.with_genes_per_chromosome(DIMENSIONS)
.with_population_size(POP_SIZE)
.with_initialization_fn(move |genes_per_chromosome, _, _| {
range_random_initialization(genes_per_chromosome, Some(&alleles_clone), Some(false))
})
.with_fitness_fn(fitness_fn)
.with_selection_method(Selection::Tournament)
.with_crossover_method(Crossover::Uniform)
.with_mutation_method(Mutation::Gaussian)
.with_survivor_method(Survivor::Fitness)
.with_problem_solving(ProblemSolving::Minimization)
.with_max_generations(MAX_GENERATIONS)
.with_observer(Arc::new(composite))
.build()
.expect("Failed to build GA configuration");
println!("== Rastrigin Continuous Optimization ==");
println!(
"Chromosome: {} dimensions, Population: {}, Max generations: {}",
DIMENSIONS, POP_SIZE, MAX_GENERATIONS
);
println!("Operators: Selection=Tournament, Crossover=Uniform, Mutation=Gaussian");
println!("-------------------------------------------------------");
let report_interval = 50;
let result = ga.run_with_callback(
Some(
|gen: &usize,
pop: &Population<RangeChromosome<f64>>,
_stats: &GenerationStats,
_cause: &TerminationCause|
-> std::ops::ControlFlow<()> {
let avg_fitness =
pop.chromosomes.iter().map(|c| c.fitness()).sum::<f64>() / pop.size() as f64;
println!(
"Generation {:4}: best = {:8.4}, avg = {:8.4}",
gen, pop.best_chromosome.fitness, avg_fitness
);
std::ops::ControlFlow::Continue(())
},
),
report_interval,
);
match result {
Ok(population) => {
println!("-------------------------------------------------------");
println!(
"Finished. Best fitness: {:.6}",
population.best_chromosome.fitness
);
if population.best_chromosome.fitness < 1.0 {
println!("Near-optimal solution found!");
} else {
println!("Did not reach optimum. Try increasing generations or population size.");
}
}
Err(e) => {
println!("GA failed: {:?}", e);
}
}
}