use std::borrow::Cow;
use std::sync::Arc;
use genetic_algorithms::chromosomes::Binary as BinaryChromosome;
use genetic_algorithms::configuration::ProblemSolving;
use genetic_algorithms::eda::{EdaConfiguration, EdaEngine};
use genetic_algorithms::genotypes::Binary as BinaryGene;
use genetic_algorithms::rng;
use genetic_algorithms::traits::LinearChromosome;
use genetic_algorithms::LogObserver;
use rand::Rng;
const CHROMOSOME_LEN: usize = 30;
const BLOCK_SIZE: usize = 5;
const POP_SIZE: usize = 300;
const MAX_GENERATIONS: usize = 500;
const SELECTION_RATIO: f64 = 0.3;
fn trap_fitness(dna: &[BinaryGene]) -> f64 {
dna.chunks(BLOCK_SIZE)
.map(|block| {
let ones = block.iter().filter(|g| g.id == 1).count();
if ones == BLOCK_SIZE {
BLOCK_SIZE as f64
} else {
(BLOCK_SIZE - 1 - ones) as f64
}
})
.sum()
}
fn init_population(n: usize) -> Vec<BinaryChromosome> {
let mut rng = rng::make_rng();
(0..n)
.map(|_| {
let dna: Vec<BinaryGene> = (0..CHROMOSOME_LEN)
.map(|_| {
let v = rng.random::<bool>();
BinaryGene {
id: if v { 1 } else { 0 },
value: v,
}
})
.collect();
let mut c = BinaryChromosome::default();
c.set_dna(Cow::Owned(dna));
c
})
.collect()
}
fn main() {
let _ = env_logger::try_init();
rng::set_seed(Some(42));
let config = EdaConfiguration {
population_size: POP_SIZE,
max_generations: MAX_GENERATIONS,
problem_solving: ProblemSolving::Maximization,
fitness_target: Some(CHROMOSOME_LEN as f64),
selection_ratio: SELECTION_RATIO,
fitness_cache_size: None,
};
let mut engine = EdaEngine::bernoulli(config, init_population, trap_fitness)
.with_observer(Arc::new(LogObserver));
println!("== EDA (UMDA): Deceptive Trap Function ==");
println!(
"chromosome_len={}, block_size={}, blocks={}",
CHROMOSOME_LEN,
BLOCK_SIZE,
CHROMOSOME_LEN / BLOCK_SIZE
);
println!(
"pop={}, max_gen={}, selection_ratio={}",
POP_SIZE, MAX_GENERATIONS, SELECTION_RATIO
);
println!("target=30.0 (all-ones = global maximum)");
println!("---------------------------------------------");
let result = engine.run().expect("engine run should succeed");
let best_dna: String = result
.best
.dna()
.iter()
.map(|g| if g.id == 1 { '1' } else { '0' })
.collect();
println!("Generations: {}", result.generations);
println!("Best fitness: {:.1}", result.best_fitness);
println!("Best DNA: {}", best_dna);
match &result.learned_model {
genetic_algorithms::eda::EdaModel::Bernoulli(probs) => {
let probs_str: Vec<String> = probs.iter().map(|p| format!("{:.2}", p)).collect();
println!("Learned probs: [{}]", probs_str.join(", "));
let converged = probs.iter().filter(|&&p| !(0.1..=0.9).contains(&p)).count();
println!(
"Converged positions (p > 0.9 or p < 0.1): {}/{}",
converged,
probs.len()
);
}
_ => unreachable!("Binary chromosomes always use Bernoulli model"),
}
println!("---------------------------------------------");
if result.best_fitness >= CHROMOSOME_LEN as f64 {
println!("SUCCESS: Found global optimum (all-ones)");
} else {
println!(
"PARTIAL: Best fitness {:.1}/{} (increase generations or population for full convergence)",
result.best_fitness,
CHROMOSOME_LEN
);
}
assert!(
result.best_fitness.is_finite(),
"best_fitness must be finite"
);
}