swarmkit 0.1.0

Composable particle swarm optimization with nested searches
Documentation
//! Test-only fixtures shared by `gbest_tests`. `#[cfg(test)]` keeps them
//! out of the published crate.

use crate::{Boundary, Contextful, FieldwiseClamp, ParticleInit};
use rand::{Rng, RngExt as _};
use std::ops::{Add, Mul, Sub};

#[derive(Copy, Clone, Default, Debug, PartialEq, PartialOrd)]
pub struct Vector2f {
    pub x: f64,
    pub y: f64,
}

impl Vector2f {
    pub const fn new(x: f64, y: f64) -> Self {
        Self { x, y }
    }
}

impl FieldwiseClamp for Vector2f {
    fn clamp(&self, min: Self, max: Self) -> Self {
        Self::new(self.x.clamp(min.x, max.x), self.y.clamp(min.y, max.y))
    }
}

impl Add for Vector2f {
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Self::new(self.x + rhs.x, self.y + rhs.y)
    }
}

impl Sub for Vector2f {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self {
        Self::new(self.x - rhs.x, self.y - rhs.y)
    }
}

impl Mul<f64> for Vector2f {
    type Output = Self;
    fn mul(self, rhs: f64) -> Self {
        Self::new(self.x * rhs, self.y * rhs)
    }
}

#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Bounds {
    pub min: Vector2f,
    pub max: Vector2f,
}

#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct RectBoundary {
    pub bounds: Bounds,
}

impl Contextful for RectBoundary {
    type TContext = ();
}

impl Boundary for RectBoundary {
    type T = Vector2f;
    fn handle(&self, pos: Vector2f) -> Vector2f {
        pos.clamp(self.bounds.min, self.bounds.max)
    }
}

pub struct RandomInit {
    pub particle_count: usize,
    pub bounds: Bounds,
}

impl ParticleInit for RandomInit {
    type T = Vector2f;

    fn init_pos<R: Rng>(&self, rng: &mut R) -> Vec<Vector2f> {
        (0..self.particle_count)
            .map(|_| sample(&self.bounds, rng))
            .collect()
    }

    fn init_vel<R: Rng>(&self, rng: &mut R) -> Vec<Vector2f> {
        (0..self.particle_count)
            .map(|_| sample(&self.bounds, rng) * 0.5)
            .collect()
    }
}

fn sample<R: Rng>(b: &Bounds, rng: &mut R) -> Vector2f {
    Vector2f::new(
        rng.random_range(b.min.x..b.max.x),
        rng.random_range(b.min.y..b.max.y),
    )
}