use rand::{Rng, RngCore};
use crate::traits::{UpdateContext, Velocity};
#[derive(Debug, Clone)]
pub struct InertiaVelocity {
pub w: f64,
pub c1: f64,
pub c2: f64,
pub w_end: Option<f64>,
}
impl InertiaVelocity {
pub fn new(w: f64, c1: f64, c2: f64) -> Self {
Self {
w,
c1,
c2,
w_end: None,
}
}
pub fn with_decay(mut self, w_end: f64) -> Self {
self.w_end = Some(w_end);
self
}
fn current_w(&self, iter: usize, max_iter: usize) -> f64 {
match self.w_end {
Some(w_end) if max_iter > 1 => {
let t = iter as f64 / (max_iter - 1) as f64;
self.w + (w_end - self.w) * t
}
_ => self.w,
}
}
}
impl Velocity for InertiaVelocity {
fn update(&self, ctx: &UpdateContext, rng: &mut dyn RngCore) -> Vec<f64> {
let w = self.current_w(ctx.iteration, ctx.max_iterations);
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(w * ctx.velocity[d] + cognitive + social);
}
new_v
}
}