use rand::RngCore;
use crate::swarm::Swarm;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BoundaryHandling {
Clamp,
Reflect,
Wrap,
Reinit,
}
pub trait SearchSpace {
type Scalar: Clone + Copy + std::fmt::Debug;
fn dim(&self) -> usize;
fn sample(&self, rng: &mut dyn RngCore) -> Vec<f64>;
fn sample_velocity(&self, rng: &mut dyn RngCore) -> Vec<f64>;
fn clamp(&self, position: &mut [f64]);
fn enforce_bounds(
&self,
position: &mut [f64],
_velocity: &mut [f64],
_handling: BoundaryHandling,
_rng: &mut dyn RngCore,
) {
self.clamp(position);
}
fn decode(&self, raw: &[f64]) -> Vec<Self::Scalar>;
fn span(&self) -> Vec<(f64, f64)> {
Vec::new()
}
}
pub struct UpdateContext<'a> {
pub position: &'a [f64],
pub velocity: &'a [f64],
pub personal_best: &'a [f64],
pub neighbor_best: &'a [f64],
pub neighbor_bests: &'a [&'a [f64]],
pub iteration: usize,
pub max_iterations: usize,
}
pub trait Velocity {
fn update(&self, ctx: &UpdateContext, rng: &mut dyn RngCore) -> Vec<f64>;
fn needs_full_neighborhood(&self) -> bool {
false
}
}
pub trait Topology {
fn neighbors(&self, i: usize, swarm: &Swarm) -> Vec<usize>;
fn best_neighbor(&self, i: usize, swarm: &Swarm) -> usize {
let nb = self.neighbors(i, swarm);
best_among(swarm, &nb, i)
}
}
impl Velocity for Box<dyn Velocity> {
fn update(&self, ctx: &UpdateContext, rng: &mut dyn RngCore) -> Vec<f64> {
(**self).update(ctx, rng)
}
fn needs_full_neighborhood(&self) -> bool {
(**self).needs_full_neighborhood()
}
}
impl Topology for Box<dyn Topology> {
fn neighbors(&self, i: usize, swarm: &Swarm) -> Vec<usize> {
(**self).neighbors(i, swarm)
}
fn best_neighbor(&self, i: usize, swarm: &Swarm) -> usize {
(**self).best_neighbor(i, swarm)
}
}
pub fn best_among(swarm: &Swarm, candidates: &[usize], fallback: usize) -> usize {
candidates
.iter()
.copied()
.min_by(|&a, &b| {
swarm.particles[a]
.best_value
.partial_cmp(&swarm.particles[b].best_value)
.unwrap_or(std::cmp::Ordering::Equal)
})
.unwrap_or(fallback)
}
pub fn global_best_index(swarm: &Swarm) -> usize {
best_among(swarm, &(0..swarm.len()).collect::<Vec<_>>(), 0)
}