use std::cell::Cell;
use ndarray::{Array1, Array2, ArrayViewMut1};
use moors::{
RandomGenerator,
algorithms::{AlgorithmBuilderError, AlgorithmError, Nsga2Builder},
duplicates::CloseDuplicatesCleaner,
operators::{
CrossoverOperator, GaussianMutation, MutationOperator, RandomSamplingFloat,
SimulatedBinaryCrossover,
},
};
fn dummy_fitness(genes: &Array2<f64>) -> Array2<f64> {
genes.clone()
}
fn dummy_constraints(genes: &Array2<f64>) -> Array2<f64> {
1.0 - genes.clone()
}
#[derive(Debug)]
struct NoMutation;
impl MutationOperator for NoMutation {
fn mutate<'a>(&self, _individual: ArrayViewMut1<'a, f64>, _rng: &mut impl RandomGenerator) {
}
}
#[derive(Debug)]
struct NoCrossOver;
impl CrossoverOperator for NoCrossOver {
fn crossover(
&self,
parent_a: &Array1<f64>,
parent_b: &Array1<f64>,
_rng: &mut impl RandomGenerator,
) -> (Array1<f64>, Array1<f64>) {
(parent_a.clone(), parent_b.clone())
}
}
#[test]
fn test_empty_mating_finish_algorithm_earlier() {
let mut nsga2 = Nsga2Builder::default()
.fitness_fn(dummy_fitness)
.constraints_fn(dummy_constraints)
.sampler(RandomSamplingFloat::new(2.0, 10.0))
.crossover(NoCrossOver)
.mutation(NoMutation)
.duplicates_cleaner(CloseDuplicatesCleaner::new(1e-8))
.num_vars(10)
.num_iterations(100)
.population_size(10)
.num_offsprings(10)
.build()
.expect("Failed to Build Nsga2");
nsga2.run().expect("Failed to run Nsga2");
assert_eq!(nsga2.context.current_iteration, 0);
}
#[test]
fn test_no_feasible_in_evaluation() {
let counter: Cell<usize> = Cell::new(0);
let constraints_fn = move |genes: &Array2<f64>| -> Array2<f64> {
let idx = counter.get();
counter.set(idx + 1);
let base = dummy_constraints(genes);
if idx == 0 { base } else { -base }
};
let mut nsga2 = Nsga2Builder::default()
.fitness_fn(dummy_fitness)
.constraints_fn(constraints_fn)
.sampler(RandomSamplingFloat::new(2.0, 10.0))
.crossover(SimulatedBinaryCrossover::new(15.0))
.mutation(GaussianMutation::new(0.1, 0.01))
.duplicates_cleaner(CloseDuplicatesCleaner::new(1e-8))
.num_vars(10)
.num_iterations(100)
.population_size(10)
.num_offsprings(10)
.keep_infeasible(false)
.build()
.expect("Failed to Build Nsga2");
let err = match nsga2.run() {
Ok(_) => panic!("Should not be Ok in this"),
Err(e) => e,
};
match err {
AlgorithmError::Evaluator(inner) => {
let msg = inner.to_string();
assert_eq!(msg, "No feasible individuals found in the population.",);
}
other => panic!("Incorrect error raised: {:?}", other),
}
}
#[test]
fn test_no_feasible_in_initialization() {
let constraints_fn = move |genes: &Array2<f64>| -> Array2<f64> { -dummy_constraints(genes) };
let mut nsga2 = Nsga2Builder::default()
.fitness_fn(dummy_fitness)
.constraints_fn(constraints_fn)
.sampler(RandomSamplingFloat::new(2.0, 10.0))
.crossover(SimulatedBinaryCrossover::new(15.0))
.mutation(GaussianMutation::new(0.1, 0.01))
.duplicates_cleaner(CloseDuplicatesCleaner::new(1e-8))
.num_vars(10)
.keep_infeasible(false)
.num_iterations(100)
.population_size(10)
.num_offsprings(10)
.build()
.expect("Failed to Build Nsga2");
let err = match nsga2.run() {
Ok(_) => panic!("Should not be Ok in this"),
Err(e) => e,
};
match err {
AlgorithmError::Initialization(inner) => {
let msg = inner.to_string();
assert_eq!(
msg,
"Error during evaluation at initialization: No feasible individuals found in the population.",
);
}
other => panic!("Incorrect error raised: {:?}", other),
}
}
#[test]
fn test_invalid_params() {
let nsga2 = Nsga2Builder::default()
.fitness_fn(dummy_fitness)
.constraints_fn(dummy_constraints)
.sampler(RandomSamplingFloat::new(2.0, 10.0))
.crossover(SimulatedBinaryCrossover::new(15.0))
.mutation(GaussianMutation::new(0.1, 0.01))
.duplicates_cleaner(CloseDuplicatesCleaner::new(1e-8))
.num_vars(10)
.num_iterations(100)
.population_size(10)
.num_offsprings(10)
.crossover_rate(-1.0);
let err = match nsga2.build() {
Ok(_) => panic!("Should not be Ok in this"),
Err(e) => e,
};
match err {
AlgorithmBuilderError::ValidationError(inner) => {
let msg = inner.to_string();
assert_eq!(msg, "Crossover rate must be between 0 and 1, got -1",);
}
other => panic!("Incorrect error raised: {:?}", other),
}
}
#[test]
fn test_algorithm_population_not_initialized() {
let nsga2 = Nsga2Builder::default()
.fitness_fn(dummy_fitness)
.constraints_fn(dummy_constraints)
.sampler(RandomSamplingFloat::new(2.0, 10.0))
.crossover(SimulatedBinaryCrossover::new(15.0))
.mutation(GaussianMutation::new(0.1, 0.01))
.duplicates_cleaner(CloseDuplicatesCleaner::new(1e-8))
.num_vars(10)
.num_iterations(100)
.population_size(10)
.num_offsprings(10)
.build()
.expect("Failed to Build Nsga2");
assert!(nsga2.population.is_none())
}