use oximo_core::{Model, ModelKind, SosType};
use crate::result::SolverResult;
use crate::status::SolverError;
pub trait Solver {
type Options;
fn name(&self) -> &str;
fn supports(&self, kind: ModelKind) -> bool;
fn supports_sos(&self, _sos_type: SosType) -> bool {
false
}
fn supports_indicators(&self) -> bool {
false
}
fn supports_model(&self, model: &Model) -> bool {
self.supports(model.kind())
&& model
.sos_constraints()
.iter()
.filter(|constraint| constraint.active)
.all(|constraint| self.supports_sos(constraint.sos_type))
&& (!model.has_active_indicator_constraints() || self.supports_indicators())
}
fn solve(&mut self, model: &Model, opts: &Self::Options) -> Result<SolverResult, SolverError>;
}
#[cfg(test)]
mod tests {
use oximo_core::{SosType, constraint, variable};
use super::*;
#[derive(Debug)]
struct NoSos;
impl Solver for NoSos {
type Options = ();
fn name(&self) -> &str {
"no-sos"
}
fn supports(&self, kind: ModelKind) -> bool {
matches!(kind, ModelKind::LP | ModelKind::MILP)
}
fn solve(&mut self, _model: &Model, _opts: &()) -> Result<SolverResult, SolverError> {
unreachable!("capability test solver is never solved")
}
}
#[derive(Debug)]
struct NativeSos;
impl Solver for NativeSos {
type Options = ();
fn name(&self) -> &str {
"native-sos"
}
fn supports(&self, kind: ModelKind) -> bool {
matches!(kind, ModelKind::LP | ModelKind::MILP)
}
fn supports_sos(&self, _sos_type: SosType) -> bool {
true
}
fn solve(&mut self, _model: &Model, _opts: &()) -> Result<SolverResult, SolverError> {
unreachable!("capability test solver is never solved")
}
}
fn sos_model() -> Model {
let m = Model::new("capabilities");
variable!(m, x);
variable!(m, y);
constraint!(m, bound, x + y <= 1.0);
m.add_sos_constraint("choice", SosType::Sos1, [(x, 1.0), (y, 2.0)]);
m
}
#[test]
fn supports_model_checks_native_sos_capability() {
let model = sos_model();
assert!(!NoSos.supports_model(&model));
assert!(NativeSos.supports_model(&model));
let transformed = model
.to_reformulated_sos_model(
oximo_core::SosReformulationOptions::default().with_fallback_big_m(100.0),
)
.unwrap();
assert!(NoSos.supports_model(&transformed));
assert!(NativeSos.supports_model(&transformed));
}
}