use std::collections::HashMap;
use std::fmt::Display;
use crate::solution::{RealBounds, Solution};
use crate::utils::random::Random;
pub trait Operator {
fn name(&self) -> &str;
}
pub trait MutationOperator<T, Q = f64>: Operator
where
T: Clone,
Q: Clone,
{
fn execute(
&self,
solution: &mut Solution<T, Q>,
probability: f64,
bounds: Option<&RealBounds>,
rng: &mut Random,
);
}
pub trait NeighborhoodOperator<T, Q = f64>: Operator
where
T: Clone,
Q: Clone,
{
fn neighborhood_size(&self, solution: &Solution<T, Q>) -> Option<usize> {
let _ = solution;
None
}
fn random_neighbor(
&self,
solution: &Solution<T, Q>,
bounds: Option<&RealBounds>,
rng: &mut Random,
) -> Solution<T, Q>;
fn all_neighbors(
&self,
solution: &Solution<T, Q>,
bounds: Option<&RealBounds>,
) -> Option<Vec<Solution<T, Q>>> {
let _ = (solution, bounds);
None
}
}
pub trait CrossoverOperator<T, Q = f64>: Operator
where
T: Clone,
Q: Clone,
{
fn execute(
&self,
parent1: &Solution<T, Q>,
parent2: &Solution<T, Q>,
bounds: Option<&RealBounds>,
rng: &mut Random,
) -> Vec<Solution<T, Q>>;
fn execute_several(
&self,
parents: Vec<Solution<T, Q>>,
bounds: Option<&RealBounds>,
_rng: &mut Random,
) -> Vec<Solution<T, Q>> {
let _ = bounds;
let mut offspring_result = vec![];
for i in 1..parents.len() {
offspring_result.push(parents[i].clone());
}
offspring_result
}
fn number_of_offspring(&self) -> usize {
2
}
}
pub trait SelectionOperator<T, Q = f64>: Operator
where
T: Clone,
Q: Clone,
{
fn execute<'a>(
&self,
population: &'a [Solution<T, Q>],
rng: &mut Random,
dominates: &dyn Fn(&Solution<T, Q>, &Solution<T, Q>) -> bool,
) -> &'a Solution<T, Q>;
fn select_many<'a>(
&self,
population: &'a [Solution<T, Q>],
count: usize,
rng: &mut Random,
dominates: fn(&Solution<T, Q>, &Solution<T, Q>) -> bool,
) -> Vec<&'a Solution<T, Q>> {
(0..count)
.map(|_| self.execute(population, rng, &dominates))
.collect()
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct SolutionTabuMemory;
impl SolutionTabuMemory {
pub const fn new() -> Self {
Self
}
}
impl Operator for SolutionTabuMemory {
fn name(&self) -> &str {
"SolutionTabuMemory"
}
}
pub trait TabuMemoryOperator<T, Q = f64>: Operator
where
T: Clone + Display,
Q: Clone + Display,
{
fn signature(&self, solution: &Solution<T, Q>) -> String {
solution.encode()
}
fn initialize_memory(
&self,
initial_solution: &Solution<T, Q>,
iteration: usize,
tabu_tenure: usize,
) -> HashMap<String, usize> {
let mut memory = HashMap::new();
self.remember(&mut memory, initial_solution, iteration, tabu_tenure);
memory
}
fn purge_expired(&self, tabu_memory: &mut HashMap<String, usize>, iteration: usize) {
tabu_memory.retain(|_, expiry| *expiry > iteration);
}
fn is_tabu(
&self,
tabu_memory: &HashMap<String, usize>,
candidate: &Solution<T, Q>,
iteration: usize,
) -> bool {
tabu_memory
.get(&self.signature(candidate))
.is_some_and(|expiry| *expiry > iteration)
}
fn remember(
&self,
tabu_memory: &mut HashMap<String, usize>,
solution: &Solution<T, Q>,
iteration: usize,
tabu_tenure: usize,
) {
tabu_memory.insert(self.signature(solution), iteration + tabu_tenure);
}
}
impl<T, Q> TabuMemoryOperator<T, Q> for SolutionTabuMemory
where
T: Clone + Display,
Q: Clone + Display,
{
}