mahf 0.1.0

A framework for modular construction and evaluation of metaheuristics.
Documentation
//! State mappings for Simulated Annealing (SA).

use derivative::Derivative;
use eyre::ensure;
use serde::Serialize;

use crate::{
    component::ExecResult,
    components::{
        mapping::{mapping, Mapping},
        Component,
    },
    lens::{AnyLens, ValueLens},
    state::random::Random,
    Problem, State,
};

/// Multiplies the `L::Target` with `alpha`.
///
/// Note that this multiplication is executed on every execution, even within the same iteration.
///
/// This geometric cooling schedule is usually used on the [`Temperature`].
///
/// [`Temperature`]: crate::components::replacement::sa::Temperature
#[derive(Serialize, Derivative)]
#[serde(bound = "")]
#[derivative(Clone(bound = ""))]
pub struct GeometricCooling<L: AnyLens> {
    pub alpha: f64,
    pub lens: L,
}

impl<L: AnyLens> GeometricCooling<L> {
    pub fn from_params(alpha: f64, lens: L) -> ExecResult<Self> {
        ensure!((0.0..1.0).contains(&alpha), "`alpha` must be in [0, 1)");
        Ok(Self { alpha, lens })
    }

    pub fn new<P>(alpha: f64, lens: L) -> ExecResult<Box<dyn Component<P>>>
    where
        P: Problem,
        L: ValueLens<P, f64>,
    {
        Ok(Box::new(Self::from_params(alpha, lens)?))
    }
}

impl<P, L> Mapping<P> for GeometricCooling<L>
where
    P: Problem,
    L: ValueLens<P, f64>,
{
    type Input = f64;
    type Output = f64;

    fn map(&self, value: Self::Input, _rng: &mut Random) -> ExecResult<Self::Output> {
        Ok(value * self.alpha)
    }
}

impl<P, L> Component<P> for GeometricCooling<L>
where
    P: Problem,
    L: ValueLens<P, f64>,
{
    fn execute(&self, problem: &P, state: &mut State<P>) -> ExecResult<()> {
        mapping(self, &self.lens, &self.lens, problem, state)
    }
}