use crate::core::{ArgminFloat, Problem, Solver, State};
use num_traits::{Float, FromPrimitive};
use std::cmp::Ordering;
use std::fmt;
#[derive(Clone)]
pub struct OptimizationResult<O, S, I> {
pub problem: Problem<O>,
pub solver: S,
pub state: I,
}
impl<O, S, I> OptimizationResult<O, S, I> {
pub fn new(problem: Problem<O>, solver: S, state: I) -> Self {
OptimizationResult {
problem,
solver,
state,
}
}
pub fn problem(&self) -> &Problem<O> {
&self.problem
}
pub fn solver(&self) -> &S {
&self.solver
}
pub fn state(&self) -> &I {
&self.state
}
}
impl<O, S, I> std::fmt::Display for OptimizationResult<O, S, I>
where
I: State,
I::Param: fmt::Debug,
S: Solver<O, I>,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
writeln!(f, "OptimizationResult:")?;
writeln!(f, " Solver: {}", self.solver.name())?;
writeln!(
f,
" param (best): {}",
if let Some(best_param) = self.state.get_best_param() {
format!("{best_param:?}")
} else {
String::from("None")
}
)?;
writeln!(f, " cost (best): {}", self.state.get_best_cost())?;
writeln!(f, " iters (best): {}", self.state.get_last_best_iter())?;
writeln!(f, " iters (total): {}", self.state.get_iter())?;
writeln!(
f,
" termination: {}",
self.state.get_termination_status()
)?;
if let Some(time) = self.state.get_time() {
writeln!(f, " time: {time:?}")?;
}
Ok(())
}
}
impl<O, S, I: State> PartialEq for OptimizationResult<O, S, I>
where
I::Float: ArgminFloat,
{
fn eq(&self, other: &OptimizationResult<O, S, I>) -> bool {
(self.state.get_best_cost() - other.state.get_best_cost()).abs() < I::Float::epsilon()
}
}
impl<O, S, I: State> Eq for OptimizationResult<O, S, I> {}
impl<O, S, I: State> Ord for OptimizationResult<O, S, I> {
fn cmp(&self, other: &OptimizationResult<O, S, I>) -> Ordering {
let t = self.state.get_best_cost() - other.state.get_best_cost();
if t.abs() < I::Float::epsilon() {
Ordering::Equal
} else if t > I::Float::from_f64(0.0).unwrap() {
Ordering::Greater
} else {
Ordering::Less
}
}
}
impl<O, S, I: State> PartialOrd for OptimizationResult<O, S, I> {
fn partial_cmp(&self, other: &OptimizationResult<O, S, I>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::{
test_utils::{TestProblem, TestSolver},
IterState,
};
send_sync_test!(
optimizationresult,
OptimizationResult<TestProblem, TestSolver, IterState<(), (), (), (), (), f64>>
);
}