use crate::lp_format::{LpObjective, LpProblem};
use crate::problem::{Problem, StrExpression, Variable};
#[cfg(feature = "cplex")]
use crate::solvers::cplex::Cplex;
use crate::solvers::{CbcSolver, GlpkSolver, GurobiSolver, Solution};
use super::SolverTrait;
#[derive(Debug, Clone)]
pub struct AutoSolver<SOLVER, NEXT>(SOLVER, NEXT);
#[derive(Debug, Clone, Default)]
pub struct NoSolver;
#[cfg(not(feature = "cplex"))]
type Cplex = NoSolver;
pub type AllSolvers = AutoSolver<
GurobiSolver,
AutoSolver<Cplex, AutoSolver<CbcSolver, AutoSolver<GlpkSolver, NoSolver>>>,
>;
impl SolverTrait for NoSolver {
fn run<'a, P: LpProblem<'a>>(&self, _problem: &'a P) -> Result<Solution, String> {
Err("No solver available".to_string())
}
}
impl<A: Default, B: Default> Default for AutoSolver<A, B> {
fn default() -> Self {
AutoSolver(A::default(), B::default())
}
}
impl<SOLVER: Default, NEXT: Default> AutoSolver<SOLVER, NEXT> {
pub fn new() -> Self {
Self::default()
}
pub fn with_solver<NewSolver>(self, solver: NewSolver) -> AutoSolver<NewSolver, Self> {
AutoSolver(solver, self)
}
}
impl<S: SolverTrait, T: SolverTrait> SolverTrait for AutoSolver<S, T> {
fn run<'a, P: LpProblem<'a>>(&self, problem: &'a P) -> Result<Solution, String> {
let works = self
.0
.run(&Problem {
name: "dummy".to_string(),
sense: LpObjective::Minimize,
objective: StrExpression("x".to_string()),
variables: vec![Variable {
name: "x".to_string(),
is_integer: false,
lower_bound: 0.0,
upper_bound: 1.0,
}],
constraints: vec![],
})
.is_ok();
if works {
self.0.run(problem)
} else {
self.1.run(problem)
}
}
}