use serde::{Deserialize, Serialize};
use super::{Budget, SearchSpace};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OptimizationResult<S> {
pub solution: S,
pub objective_value: f64,
pub evaluations: usize,
pub iterations: usize,
pub history: Vec<f64>,
pub termination: TerminationReason,
}
impl<S> OptimizationResult<S> {
#[must_use]
pub fn new(
solution: S,
objective_value: f64,
evaluations: usize,
iterations: usize,
history: Vec<f64>,
termination: TerminationReason,
) -> Self {
Self {
solution,
objective_value,
evaluations,
iterations,
history,
termination,
}
}
#[must_use]
pub const fn converged(&self) -> bool {
matches!(self.termination, TerminationReason::Converged)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TerminationReason {
Converged,
BudgetExhausted,
MaxIterations,
UserTerminated,
NumericalError,
}
pub trait PerturbativeMetaheuristic {
type Solution: Clone;
fn optimize<F>(
&mut self,
objective: &F,
space: &SearchSpace,
budget: Budget,
) -> OptimizationResult<Self::Solution>
where
F: Fn(&[f64]) -> f64;
fn best(&self) -> Option<&Self::Solution>;
fn history(&self) -> &[f64];
fn reset(&mut self);
}
#[allow(dead_code, unreachable_pub)]
pub trait ConstructiveMetaheuristic {
type Solution: Clone;
type Component;
fn construct_solution(&self, space: &SearchSpace, rng: &mut impl rand::Rng) -> Self::Solution;
fn update_state(&mut self, solutions: &[(Self::Solution, f64)]);
fn optimize<F>(
&mut self,
objective: &F,
space: &SearchSpace,
budget: Budget,
) -> OptimizationResult<Self::Solution>
where
F: Fn(&Self::Solution) -> f64;
fn reset(&mut self);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_optimization_result_converged() {
let result: OptimizationResult<Vec<f64>> = OptimizationResult::new(
vec![1.0, 2.0],
0.5,
1000,
100,
vec![10.0, 5.0, 1.0, 0.5],
TerminationReason::Converged,
);
assert!(result.converged());
assert_eq!(result.evaluations, 1000);
assert_eq!(result.iterations, 100);
}
#[test]
fn test_optimization_result_budget_exhausted() {
let result: OptimizationResult<Vec<f64>> = OptimizationResult::new(
vec![1.0, 2.0],
0.5,
10000,
100,
vec![10.0, 5.0, 1.0, 0.5],
TerminationReason::BudgetExhausted,
);
assert!(!result.converged());
}
#[test]
fn test_termination_reason_equality() {
assert_eq!(TerminationReason::Converged, TerminationReason::Converged);
assert_ne!(
TerminationReason::Converged,
TerminationReason::BudgetExhausted
);
}
}