use rand::{Rng, RngCore};
use crate::traits::{UpdateContext, Velocity};
#[derive(Debug, Clone)]
pub struct ConstrictionVelocity {
pub c1: f64,
pub c2: f64,
chi: f64,
}
impl ConstrictionVelocity {
pub fn new(c1: f64, c2: f64) -> Self {
let phi = c1 + c2;
assert!(phi > 4.0, "constriction requires c1 + c2 > 4 (got {phi})");
let chi = 2.0 / (2.0 - phi - (phi * phi - 4.0 * phi).sqrt()).abs();
Self { c1, c2, chi }
}
pub fn chi(&self) -> f64 {
self.chi
}
}
impl Default for ConstrictionVelocity {
fn default() -> Self {
Self::new(2.05, 2.05)
}
}
impl Velocity for ConstrictionVelocity {
fn update(&self, ctx: &UpdateContext, rng: &mut dyn RngCore) -> Vec<f64> {
let dim = ctx.position.len();
let mut new_v = Vec::with_capacity(dim);
for d in 0..dim {
let r1: f64 = rng.gen();
let r2: f64 = rng.gen();
let cognitive = self.c1 * r1 * (ctx.personal_best[d] - ctx.position[d]);
let social = self.c2 * r2 * (ctx.neighbor_best[d] - ctx.position[d]);
new_v.push(self.chi * (ctx.velocity[d] + cognitive + social));
}
new_v
}
}