problemreductions/solvers/
resolver.rs1use super::registry::CompiledIlpPipeline;
4use super::registry::{solver_capability_registry, CustomizedSolverRegistration, ExactProblemKey};
5use crate::registry::LoadedDynProblem;
6use serde::Serialize;
7
8#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
10pub enum SolverRequest {
11 #[default]
12 Default,
13 Customized,
14 Ilp,
15 BruteForce,
16}
17
18#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
20#[serde(tag = "kind", rename_all = "kebab-case")]
21pub enum SolverExecution {
22 Customized { implementation: &'static str },
23 Ilp { reduction_path: Vec<String> },
24 BruteForce,
25}
26
27#[derive(Clone, Debug, PartialEq, Eq)]
29pub struct SolveResult {
30 pub solver: SolverExecution,
31 pub outcome: SolveOutcome,
32}
33
34#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
36#[serde(tag = "status", rename_all = "snake_case")]
37pub enum SolveOutcome {
38 Optimal {
41 solution: serde_json::Value,
42 evaluation: String,
43 },
44 Infeasible,
46}
47
48fn problem_key(problem: &LoadedDynProblem) -> ExactProblemKey {
49 ExactProblemKey::new(problem.problem_name(), problem.variant_map())
50}
51
52fn solve_customized(
53 problem: &LoadedDynProblem,
54 registration: &'static CustomizedSolverRegistration,
55) -> Result<SolveResult, super::SolveError> {
56 let outcome = match (registration.solve_fn)(problem.as_any())? {
57 Some(solution) => SolveOutcome::Optimal {
58 evaluation: problem.evaluate_dyn(&solution)?,
59 solution,
60 },
61 None => SolveOutcome::Infeasible,
62 };
63 Ok(SolveResult {
64 solver: SolverExecution::Customized {
65 implementation: registration.implementation,
66 },
67 outcome,
68 })
69}
70
71fn solve_ilp(
72 problem: &LoadedDynProblem,
73 pipeline: &CompiledIlpPipeline,
74) -> Result<SolveResult, super::SolveError> {
75 let outcome = match pipeline.solve(problem.as_any(), &super::ILPSolver::new()) {
76 Ok(solution) => SolveOutcome::Optimal {
77 evaluation: problem.evaluate_dyn(&solution)?,
78 solution,
79 },
80 Err(super::ILPSolveError::Infeasible) => SolveOutcome::Infeasible,
81 Err(source) => {
82 return Err(super::SolveError::IlpSolve {
83 problem: problem_key(problem).label(),
84 source,
85 });
86 }
87 };
88 Ok(SolveResult {
89 solver: SolverExecution::Ilp {
90 reduction_path: pipeline.path_labels(),
91 },
92 outcome,
93 })
94}
95
96fn solve_brute_force(
97 problem: &LoadedDynProblem,
98 registration: &'static super::BruteForceRegistration,
99) -> Result<SolveResult, super::SolveError> {
100 let outcome = match (registration.solve_fn)(problem.as_any())? {
101 Some((solution, evaluation)) => SolveOutcome::Optimal {
102 solution,
103 evaluation,
104 },
105 None => SolveOutcome::Infeasible,
106 };
107 Ok(SolveResult {
108 solver: SolverExecution::BruteForce,
109 outcome,
110 })
111}
112
113pub fn solve(
118 problem: &LoadedDynProblem,
119 request: SolverRequest,
120) -> Result<SolveResult, super::SolveError> {
121 let registry = solver_capability_registry().map_err(super::SolveError::InvalidRegistry)?;
122 let key = problem_key(problem);
123 let capabilities = registry.lookup(&key);
124
125 match request {
126 SolverRequest::BruteForce => solve_brute_force(
127 problem,
128 capabilities
129 .brute_force
130 .ok_or_else(|| super::SolveError::MissingRegistration(key.label()))?,
131 ),
132 SolverRequest::Customized => {
133 let registration = capabilities
134 .customized
135 .ok_or_else(|| super::SolveError::MissingCustomizedCapability(key.label()))?;
136 solve_customized(problem, registration)
137 }
138 SolverRequest::Ilp => {
139 let pipeline = capabilities
140 .ilp
141 .ok_or_else(|| super::SolveError::MissingIlpCapability(key.label()))?;
142 solve_ilp(problem, pipeline)
143 }
144 SolverRequest::Default => {
145 if let Some(customized) = capabilities.customized {
146 return solve_customized(problem, customized);
147 }
148 if let Some(pipeline) = capabilities.ilp {
149 return solve_ilp(problem, pipeline);
150 }
151 solve_brute_force(
152 problem,
153 capabilities
154 .brute_force
155 .ok_or_else(|| super::SolveError::MissingRegistration(key.label()))?,
156 )
157 }
158 }
159}
160
161#[cfg(test)]
162#[path = "../unit_tests/solvers/resolver.rs"]
163mod tests;