use genetic_algorithm::strategy::hill_climb::prelude::*;
const TARGET_SCORE: isize = (59.0 / PRECISION) as isize;
const PRECISION: f32 = 1e-5;
#[derive(Clone, Debug)]
struct MILPFitness;
impl Fitness for MILPFitness {
type Genotype = MultiRangeGenotype<f32>;
fn calculate_for_chromosome(
&mut self,
chromosome: &FitnessChromosome<Self>,
_genotype: &FitnessGenotype<Self>,
) -> Option<FitnessValue> {
let x1 = chromosome.genes[0];
let x2 = chromosome.genes[1].floor();
if x1 + 2.0 * x2 >= -14.0 && -4.0 * x1 - x2 <= -33.0 && 2.0 * x1 + x2 <= 20.0 {
let score = 8.0 * x1 + x2;
Some((score / PRECISION) as isize)
} else {
None
}
}
}
fn main() {
env_logger::init();
let genotype = MultiRangeGenotype::builder()
.with_allele_ranges(vec![(-10.0..=10.0), (0.0..=10.0)])
.with_mutation_types(vec![
MutationType::StepScaled(vec![0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001]),
MutationType::StepScaled(vec![0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001]),
])
.build()
.unwrap();
println!("genotype: {}", genotype);
let hill_climb_builder = HillClimb::builder()
.with_genotype(genotype)
.with_variant(HillClimbVariant::SteepestAscent)
.with_max_stale_generations(2)
.with_target_fitness_score(TARGET_SCORE)
.with_fitness_ordering(FitnessOrdering::Minimize)
.with_fitness(MILPFitness);
for _ in 0..10 {
let now = std::time::Instant::now();
let (hill_climb, _) = hill_climb_builder.clone().call_repeatedly(1000).unwrap();
let duration = now.elapsed();
if let Some((best_genes, fitness_score)) = hill_climb.best_genes_and_fitness_score() {
let x1 = best_genes[0];
let x2 = best_genes[1].floor();
let result = 8.0 * x1 + x2;
println!(
"x1: {:.5}, x2: {} => {:.5} (fitness score: {:>3}, best_iteration: {:>3}, best_generation: {:>5}, duration: {:?}, scale_index: {:?})",
x1, x2 as u8, result, fitness_score, hill_climb.state.current_iteration, hill_climb.best_generation(), duration, hill_climb.genotype.current_scale_index()
);
} else {
println!(
"invalid solution with fitness score: none, duration {:?}",
duration
);
}
}
}