use super::*;
use rand::prelude::*;
use std::{collections::HashSet, hash::Hash};
mod mutation;
pub use mutation::*;
mod crossover;
pub use crossover::*;
mod selection;
pub use selection::*;
#[inline]
pub fn compare_fitness<I: Individual>(a: &I, b: &I) -> std::cmp::Ordering {
a.fitness()
.partial_cmp(&b.fitness())
.unwrap_or(std::cmp::Ordering::Equal)
}
#[inline]
pub fn random_pair<R: Rng>(n: usize, rng: &mut R) -> (usize, usize) {
assert!(n >= 2);
let p1 = rng.gen_range(0..n);
let mut p2 = rng.gen_range(0..n - 1);
if p2 >= p1 {
p2 += 1;
}
(p1, p2)
}
#[inline]
pub fn random_range<R: Rng>(n: usize, rng: &mut R) -> std::ops::Range<usize> {
assert!(n != 0);
bounded_random_range(n, 1, n, rng)
}
#[inline]
pub fn bounded_random_range<R: Rng>(
n: usize,
min_len: usize,
max_len: usize,
rng: &mut R,
) -> std::ops::Range<usize> {
let length = rng.gen_range(min_len..=max_len);
let start = rng.gen_range(0..=(n - length));
let end = start + length;
start..end
}
pub fn common_neighbors<G>(genome1: &[G], genome2: &[G]) -> Vec<(G, G)>
where
G: Copy + PartialOrd + Eq + Hash,
{
if genome1.len() < 2 || genome2.len() <= 2 {
return Vec::new();
}
let (genome1, genome2) = if genome1.len() <= genome2.len() {
(genome1, genome2)
} else {
(genome2, genome1)
};
let mut neighbors1 = Vec::with_capacity(genome1.len());
let mut neighbors2 = HashSet::with_capacity(genome2.len());
let neighbor = |a: &G, b: &G| if a < b { (*a, *b) } else { (*b, *a) };
neighbors1.extend(
genome1
.windows(2)
.map(|w| neighbor(&w[0], &w[1]))
.chain(std::iter::once(neighbor(
genome1.last().unwrap(),
genome1.first().unwrap(),
))),
);
neighbors2.extend(
genome2
.windows(2)
.map(|w| neighbor(&w[0], &w[1]))
.chain(std::iter::once(neighbor(
genome2.last().unwrap(),
genome2.first().unwrap(),
))),
);
neighbors1.retain(|neighbor| neighbors2.contains(neighbor));
neighbors1
}
pub fn common_partitions<G>(genome1: &[G], genome2: &[G]) -> Vec<Vec<G>>
where
G: Copy + PartialOrd + Eq + Hash,
{
let mut partitions = Vec::with_capacity(genome1.len());
let mut visited = HashSet::with_capacity(genome1.len());
let common_neighbors = common_neighbors(genome1, genome2);
for &node in genome1.iter() {
if visited.contains(&node) {
continue;
}
let mut partition = Vec::with_capacity(common_neighbors.len());
partition.push(node);
visited.insert(node);
while let Some(next_node) = partition.last().and_then(|&last| {
common_neighbors.iter().find_map(|&(a, b)| {
if a == last && !visited.contains(&b) {
Some(b)
} else if b == last && !visited.contains(&a) {
Some(a)
} else {
None
}
})
}) {
partition.push(next_node);
visited.insert(next_node);
}
partitions.push(partition);
}
partitions
}