use genetic_algorithms::fitness::cache::{hash_dna, FitnessCache};
use genetic_algorithms::genotypes::Binary as BinaryGene;
use genetic_algorithms::traits::GeneT;
#[test]
fn cache_new_is_empty() {
let cache = FitnessCache::new(10);
assert!(cache.is_empty());
assert_eq!(cache.len(), 0);
assert_eq!(cache.hits(), 0);
assert_eq!(cache.misses(), 0);
}
#[test]
fn cache_put_and_get() {
let mut cache = FitnessCache::new(10);
cache.put(42, 3.5);
assert_eq!(cache.len(), 1);
let result = cache.get(42);
assert_eq!(result, Some(3.5));
assert_eq!(cache.hits(), 1);
assert_eq!(cache.misses(), 0);
}
#[test]
fn cache_miss_increments_counter() {
let mut cache = FitnessCache::new(10);
let result = cache.get(99);
assert_eq!(result, None);
assert_eq!(cache.misses(), 1);
assert_eq!(cache.hits(), 0);
}
#[test]
fn cache_evicts_lru_when_full() {
let mut cache = FitnessCache::new(3);
cache.put(1, 1.0);
cache.put(2, 2.0);
cache.put(3, 3.0);
assert_eq!(cache.len(), 3);
cache.put(4, 4.0);
assert_eq!(cache.len(), 3);
assert_eq!(cache.get(1), None); assert_eq!(cache.get(4), Some(4.0)); }
#[test]
fn cache_access_updates_lru_order() {
let mut cache = FitnessCache::new(3);
cache.put(1, 1.0);
cache.put(2, 2.0);
cache.put(3, 3.0);
cache.get(1);
cache.put(4, 4.0);
assert_eq!(cache.get(1), Some(1.0)); assert_eq!(cache.get(2), None); }
#[test]
fn cache_update_existing_key() {
let mut cache = FitnessCache::new(10);
cache.put(1, 1.0);
cache.put(1, 2.0);
assert_eq!(cache.get(1), Some(2.0));
assert_eq!(cache.len(), 1); }
#[test]
fn cache_capacity_one() {
let mut cache = FitnessCache::new(1);
cache.put(1, 1.0);
cache.put(2, 2.0);
assert_eq!(cache.len(), 1);
assert_eq!(cache.get(1), None);
assert_eq!(cache.get(2), Some(2.0));
}
#[test]
fn hash_dna_identical_produces_same_hash() {
let dna1: Vec<BinaryGene> = vec![
{ let mut g = <BinaryGene as Default>::default(); g.set_id(1); g.value = true; g },
{ let mut g = <BinaryGene as Default>::default(); g.set_id(2); g.value = false; g },
];
let dna2 = dna1.clone();
assert_eq!(hash_dna(&dna1), hash_dna(&dna2));
}
#[test]
fn hash_dna_different_produces_different_hash() {
let dna1: Vec<BinaryGene> = vec![
{ let mut g = <BinaryGene as Default>::default(); g.set_id(1); g.value = true; g },
];
let dna2: Vec<BinaryGene> = vec![
{ let mut g = <BinaryGene as Default>::default(); g.set_id(1); g.value = false; g },
];
assert_ne!(hash_dna(&dna1), hash_dna(&dna2));
}
#[test]
fn hash_dna_different_ids_produces_different_hash() {
let dna1: Vec<BinaryGene> = vec![
{ let mut g = <BinaryGene as Default>::default(); g.set_id(1); g },
];
let dna2: Vec<BinaryGene> = vec![
{ let mut g = <BinaryGene as Default>::default(); g.set_id(2); g },
];
assert_ne!(hash_dna(&dna1), hash_dna(&dna2));
}
#[test]
fn hash_dna_empty_is_consistent() {
let dna: Vec<BinaryGene> = vec![];
assert_eq!(hash_dna(&dna), hash_dna(&dna));
}
#[test]
fn hash_dna_range_f64_identical() {
use genetic_algorithms::genotypes::Range as RangeGene;
let dna1 = vec![RangeGene::new(0, vec![(0.0, 10.0)], 5.5)];
let dna2 = vec![RangeGene::new(0, vec![(0.0, 10.0)], 5.5)];
assert_eq!(hash_dna(&dna1), hash_dna(&dna2));
}
#[test]
fn hash_dna_range_f64_different_values() {
use genetic_algorithms::genotypes::Range as RangeGene;
let dna1 = vec![RangeGene::new(0, vec![(0.0, 10.0)], 5.5)];
let dna2 = vec![RangeGene::new(0, vec![(0.0, 10.0)], 7.3)];
assert_ne!(hash_dna(&dna1), hash_dna(&dna2));
}
#[test]
fn ga_with_fitness_cache_builds_successfully() {
use genetic_algorithms::chromosomes::Binary;
use genetic_algorithms::ga::Ga;
use genetic_algorithms::initializers::binary_random_initialization;
use genetic_algorithms::operations::{Crossover, Mutation, Selection, Survivor};
use genetic_algorithms::configuration::ProblemSolving;
use genetic_algorithms::traits::{ConfigurationT, CrossoverConfig, MutationConfig, SelectionConfig, StoppingConfig};
let ga = Ga::<Binary>::new()
.with_population_size(20)
.with_genes_per_chromosome(4)
.with_fitness_fn(|dna: &[BinaryGene]| dna.iter().filter(|g| g.value).count() as f64)
.with_initialization_fn(|n, _, _| binary_random_initialization(n, None, None))
.with_selection_method(Selection::Tournament)
.with_crossover_method(Crossover::Uniform)
.with_mutation_method(Mutation::BitFlip)
.with_problem_solving(ProblemSolving::Maximization)
.with_survivor_method(Survivor::Fitness)
.with_max_generations(10)
.with_fitness_cache_size(100)
.build();
assert!(ga.is_ok());
}
#[test]
fn ga_with_fitness_cache_runs_correctly() {
use genetic_algorithms::chromosomes::Binary;
use genetic_algorithms::ga::Ga;
use genetic_algorithms::initializers::binary_random_initialization;
use genetic_algorithms::operations::{Crossover, Mutation, Selection, Survivor};
use genetic_algorithms::configuration::ProblemSolving;
use genetic_algorithms::traits::{ConfigurationT, CrossoverConfig, MutationConfig, SelectionConfig, StoppingConfig};
let mut ga = Ga::<Binary>::new()
.with_population_size(20)
.with_genes_per_chromosome(4)
.with_fitness_fn(|dna: &[BinaryGene]| dna.iter().filter(|g| g.value).count() as f64)
.with_initialization_fn(|n, _, _| binary_random_initialization(n, None, None))
.with_selection_method(Selection::Tournament)
.with_crossover_method(Crossover::Uniform)
.with_mutation_method(Mutation::BitFlip)
.with_problem_solving(ProblemSolving::Maximization)
.with_survivor_method(Survivor::Fitness)
.with_max_generations(10)
.with_fitness_cache_size(200)
.build()
.unwrap();
let result = ga.run();
assert!(result.is_ok());
let pop = result.unwrap();
assert!(pop.size() > 0);
}
#[test]
fn ga_with_fitness_cache_range_chromosome() {
use genetic_algorithms::chromosomes::Range as RangeChromosome;
use genetic_algorithms::genotypes::Range as RangeGene;
use genetic_algorithms::ga::Ga;
use genetic_algorithms::initializers::range_random_initialization;
use genetic_algorithms::operations::{Crossover, Mutation, Selection, Survivor};
use genetic_algorithms::configuration::ProblemSolving;
use genetic_algorithms::traits::{ConfigurationT, CrossoverConfig, MutationConfig, SelectionConfig, StoppingConfig};
let alleles = vec![RangeGene::new(0, vec![(0.0, 10.0)], 0.0)];
let alleles_clone = alleles.clone();
let mut ga = Ga::<RangeChromosome<f64>>::new()
.with_population_size(20)
.with_genes_per_chromosome(3)
.with_alleles(alleles)
.with_fitness_fn(|dna: &[RangeGene<f64>]| {
dna.iter().map(|g| g.value).sum::<f64>()
})
.with_initialization_fn(move |n, _, _| {
range_random_initialization(n, Some(&alleles_clone), Some(false))
})
.with_selection_method(Selection::Tournament)
.with_crossover_method(Crossover::Uniform)
.with_mutation_method(Mutation::Value)
.with_problem_solving(ProblemSolving::Maximization)
.with_survivor_method(Survivor::Fitness)
.with_max_generations(10)
.with_fitness_cache_size(200)
.build()
.unwrap();
let result = ga.run();
assert!(result.is_ok());
}