metalforge 0.1.1

forge: a deterministic metaheuristic optimization substrate in Rust. Unified Problem/MultiProblem/Anneal traits; DDS, SCE-UA, DE, PSO, NSGA-II and simulated annealing; reproducible by seed; optional Rayon parallelism.
Documentation
//! Optimization results shared by every algorithm.

/// The best point an optimizer found, with its (minimized) objective value.
#[derive(Debug, Clone, PartialEq)]
pub struct Solution {
    /// Best decision vector.
    pub x: Vec<f64>,
    /// Objective value at `x`, in the **minimizing** sense forge uses
    /// internally. If the problem was wrapped in [`Maximize`], negate this to
    /// recover the original value (or use [`Report::best_value_maximized`]).
    ///
    /// [`Maximize`]: crate::problem::Maximize
    pub value: f64,
}

/// A point in a multi-objective search, with its full objective vector (all in
/// the minimizing sense).
#[derive(Debug, Clone, PartialEq)]
pub struct MultiSolution {
    /// Decision vector.
    pub x: Vec<f64>,
    /// Objective values at `x`, length `n_objectives`.
    pub objectives: Vec<f64>,
}

/// The outcome of a multi-objective run: the approximated Pareto front (a set
/// of mutually non-dominated solutions) and the evaluations spent.
#[derive(Debug, Clone, PartialEq)]
pub struct ParetoFront {
    /// Non-dominated solutions found.
    pub solutions: Vec<MultiSolution>,
    /// Objective evaluations performed.
    pub evaluations: usize,
}

impl ParetoFront {
    /// Number of solutions on the front.
    pub fn len(&self) -> usize {
        self.solutions.len()
    }

    /// Whether the front is empty.
    pub fn is_empty(&self) -> bool {
        self.solutions.is_empty()
    }

    /// The objective vectors of every solution on the front.
    pub fn objective_vectors(&self) -> impl Iterator<Item = &[f64]> {
        self.solutions.iter().map(|s| s.objectives.as_slice())
    }
}

/// Why an optimizer stopped.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StopReason {
    /// The evaluation budget was exhausted.
    BudgetExhausted,
    /// The target objective value was reached.
    TargetReached,
}

/// Full outcome of a run: the best [`Solution`], how it stopped, and the number
/// of objective evaluations actually spent.
#[derive(Debug, Clone, PartialEq)]
pub struct Report {
    /// Best solution found.
    pub solution: Solution,
    /// Why the run terminated.
    pub stop: StopReason,
    /// Objective evaluations performed.
    pub evaluations: usize,
}

impl Report {
    /// Best decision vector.
    pub fn best(&self) -> &[f64] {
        &self.solution.x
    }

    /// Best objective in the minimizing sense (as stored).
    pub fn best_value(&self) -> f64 {
        self.solution.value
    }

    /// Best objective in the *maximizing* sense — the negation of
    /// [`Report::best_value`]. Use this when the problem was wrapped in
    /// [`Maximize`].
    ///
    /// [`Maximize`]: crate::problem::Maximize
    pub fn best_value_maximized(&self) -> f64 {
        -self.solution.value
    }
}