use std::collections::HashMap;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use crate::variable::UnsolvedProblem;
use crate::Constraint;
use crate::{constraint::ConstraintReference, IntoAffineExpression, Variable};
#[cfg(feature = "coin_cbc")]
#[cfg_attr(docsrs, doc(cfg(feature = "coin_cbc")))]
pub mod coin_cbc;
#[cfg(feature = "minilp")]
#[cfg_attr(docsrs, doc(cfg(feature = "minilp")))]
pub mod minilp;
#[cfg(feature = "lpsolve")]
#[cfg_attr(docsrs, doc(cfg(feature = "lpsolve")))]
pub mod lpsolve;
#[cfg(feature = "highs")]
#[cfg_attr(docsrs, doc(cfg(feature = "highs")))]
pub mod highs;
#[cfg(feature = "lp-solvers")]
#[cfg_attr(docsrs, doc(cfg(feature = "lp-solvers")))]
pub mod lp_solvers;
pub trait Solver {
type Model: SolverModel;
fn create_model(&mut self, problem: UnsolvedProblem) -> Self::Model;
}
pub trait StaticSolver: Solver + 'static {}
impl<T> StaticSolver for T where T: Solver + 'static {}
impl<SOLVER, MODEL> Solver for SOLVER
where
SOLVER: FnMut(UnsolvedProblem) -> MODEL,
MODEL: SolverModel,
{
type Model = MODEL;
fn create_model(&mut self, pb: UnsolvedProblem) -> Self::Model {
self(pb)
}
}
#[derive(Eq, PartialEq, Clone, Copy)]
pub enum ObjectiveDirection {
Maximisation,
Minimisation,
}
#[derive(Debug, PartialEq, Clone)]
pub enum ResolutionError {
Unbounded,
Infeasible,
Other(&'static str),
Str(String),
}
impl Display for ResolutionError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ResolutionError::Unbounded =>
write!(f, "Unbounded: The objective can be made infinitely large without violating any constraints."),
ResolutionError::Infeasible =>
write!(f, "Infeasible: The problem contains contradictory constraints. No solution exists."),
ResolutionError::Other(s) =>
write!(f, "An unexpected error occurred while running the optimizer: {}.", s),
ResolutionError::Str(s) =>
write!(f, "An unexpected error occurred while running the optimizer: {}.", s)
}
}
}
impl From<String> for ResolutionError {
fn from(s: String) -> Self {
ResolutionError::Str(s)
}
}
impl Error for ResolutionError {}
pub trait SolverModel {
type Solution: Solution;
type Error: std::error::Error;
fn with(mut self, constraint: Constraint) -> Self
where
Self: Sized,
{
self.add_constraint(constraint);
self
}
fn solve(self) -> Result<Self::Solution, Self::Error>;
fn add_constraint(&mut self, c: Constraint) -> ConstraintReference;
}
pub trait Solution {
fn value(&self, variable: Variable) -> f64;
fn eval<E: IntoAffineExpression>(&self, expr: E) -> f64
where
Self: Sized,
{
expr.eval_with(self)
}
}
impl<N: Into<f64> + Clone> Solution for HashMap<Variable, N> {
fn value(&self, variable: Variable) -> f64 {
self[&variable].clone().into()
}
}
pub trait DualValues {
fn dual(&self, c: ConstraintReference) -> f64;
}
pub trait SolutionWithDual<'a> {
type Dual: DualValues;
fn compute_dual(&'a mut self) -> Self::Dual;
}
#[allow(clippy::upper_case_acronyms)]
pub trait ModelWithSOS1 {
fn add_sos1<I: IntoAffineExpression>(&mut self, variables_and_weights: I);
fn with_sos1<I: IntoAffineExpression>(mut self, variables_and_weights: I) -> Self
where
Self: Sized,
{
self.add_sos1(variables_and_weights);
self
}
}