swarmkit 0.1.0

Composable particle swarm optimization with nested searches
Documentation
//! Traits for producing initial particle swarms.
//!
//! [`ParticleInit`] is the standalone case. [`ParticleInitDependent`] is
//! for inner searches inside [`crate::NestedMover`], where the init seeds
//! around the outer particle's current position.

use crate::{Group, Particle, Unit};
use rand::Rng;

/// Initializes an inner swarm seeded around the outer particle's position.
pub trait ParticleInitDependent {
    /// Outer-search unit.
    type TIn: Unit;
    /// Inner-search unit being produced.
    type TOut: Unit;

    /// One initial position per particle.
    fn init_pos<R: Rng>(&self, rng: &mut R, p: Self::TIn) -> Vec<Self::TOut>;
    /// One initial velocity per particle.
    fn init_vel<R: Rng>(&self, rng: &mut R, p: Self::TIn) -> Vec<Self::TOut>;

    /// Zip `init_pos` and `init_vel` into a [`Group`] with `f64::MIN`
    /// fitness; the inner searcher's first fitness pass overwrites it.
    fn init_dep<R: Rng>(&self, rng: &mut R, p: Self::TIn) -> Group<Self::TOut> {
        let positions = self.init_pos(rng, p);
        let velocities = self.init_vel(rng, p);
        debug_assert_eq!(
            positions.len(),
            velocities.len(),
            "init_pos and init_vel must produce equal-length vectors",
        );
        let mut group = Group::<Self::TOut>::with_capacity(positions.len());
        for (pos, vel) in positions.into_iter().zip(velocities) {
            group.push(Particle {
                pos,
                vel,
                fit: f64::MIN,
                best_pos: pos,
                best_fit: f64::MIN,
            });
        }
        group
    }
}

/// Initializes a standalone swarm.
pub trait ParticleInit {
    /// The particle unit.
    type T: Unit;

    /// One initial position per particle.
    fn init_pos<R: Rng>(&self, rng: &mut R) -> Vec<Self::T>;
    /// One initial velocity per particle.
    fn init_vel<R: Rng>(&self, rng: &mut R) -> Vec<Self::T>;

    /// Zip `init_pos` and `init_vel` into a [`Group`] with `f64::MIN`
    /// fitness; the searcher's first fitness pass overwrites it.
    fn init<R: Rng>(&self, rng: &mut R) -> Group<Self::T> {
        let positions = self.init_pos(rng);
        let velocities = self.init_vel(rng);
        debug_assert_eq!(
            positions.len(),
            velocities.len(),
            "init_pos and init_vel must produce equal-length vectors",
        );
        let mut group = Group::<Self::T>::with_capacity(positions.len());
        for (pos, vel) in positions.into_iter().zip(velocities) {
            group.push(Particle {
                pos,
                vel,
                fit: f64::MIN,
                best_pos: pos,
                best_fit: f64::MIN,
            });
        }
        group
    }
}