1use oximo_core::{Model, ModelKind, SosType};
2
3use crate::result::SolverResult;
4use crate::status::SolverError;
5
6pub trait Solver {
20 type Options;
23
24 fn name(&self) -> &str;
25
26 fn supports(&self, kind: ModelKind) -> bool;
27
28 fn supports_sos(&self, _sos_type: SosType) -> bool {
30 false
31 }
32
33 fn supports_indicators(&self) -> bool {
35 false
36 }
37
38 fn supports_model(&self, model: &Model) -> bool {
40 self.supports(model.kind())
41 && model
42 .sos_constraints()
43 .iter()
44 .filter(|constraint| constraint.active)
45 .all(|constraint| self.supports_sos(constraint.sos_type))
46 && (!model.has_active_indicator_constraints() || self.supports_indicators())
47 }
48
49 fn solve(&mut self, model: &Model, opts: &Self::Options) -> Result<SolverResult, SolverError>;
55}
56
57#[cfg(test)]
58mod tests {
59 use oximo_core::{SosType, constraint, variable};
60
61 use super::*;
62
63 #[derive(Debug)]
64 struct NoSos;
65
66 impl Solver for NoSos {
67 type Options = ();
68
69 fn name(&self) -> &str {
70 "no-sos"
71 }
72
73 fn supports(&self, kind: ModelKind) -> bool {
74 matches!(kind, ModelKind::LP | ModelKind::MILP)
75 }
76
77 fn solve(&mut self, _model: &Model, _opts: &()) -> Result<SolverResult, SolverError> {
78 unreachable!("capability test solver is never solved")
79 }
80 }
81
82 #[derive(Debug)]
83 struct NativeSos;
84
85 impl Solver for NativeSos {
86 type Options = ();
87
88 fn name(&self) -> &str {
89 "native-sos"
90 }
91
92 fn supports(&self, kind: ModelKind) -> bool {
93 matches!(kind, ModelKind::LP | ModelKind::MILP)
94 }
95
96 fn supports_sos(&self, _sos_type: SosType) -> bool {
97 true
98 }
99
100 fn solve(&mut self, _model: &Model, _opts: &()) -> Result<SolverResult, SolverError> {
101 unreachable!("capability test solver is never solved")
102 }
103 }
104
105 fn sos_model() -> Model {
106 let m = Model::new("capabilities");
107 variable!(m, x);
108 variable!(m, y);
109 constraint!(m, bound, x + y <= 1.0);
110 m.add_sos_constraint("choice", SosType::Sos1, [(x, 1.0), (y, 2.0)]);
111 m
112 }
113
114 #[test]
115 fn supports_model_checks_native_sos_capability() {
116 let model = sos_model();
117 assert!(!NoSos.supports_model(&model));
118 assert!(NativeSos.supports_model(&model));
119
120 let transformed = model
121 .to_reformulated_sos_model(
122 oximo_core::SosReformulationOptions::default().with_fallback_big_m(100.0),
123 )
124 .unwrap();
125 assert!(NoSos.supports_model(&transformed));
126 assert!(NativeSos.supports_model(&transformed));
127 }
128}