| 160 | } |
| 161 | |
| 162 | pub fn solve_exact( |
| 163 | schema: &DecisionSchema, |
| 164 | objective: &dyn IntegerObjective, |
| 165 | ) -> Result<OptimizationResult, CombinatorialOptimizationError> { |
| 166 | schema.validate()?; |
| 167 | let values = schema |
| 168 | .variables |
| 169 | .iter() |
| 170 | .copied() |
| 171 | .map(IntegerVariable::values) |
| 172 | .collect::<Result<Vec<_>, _>>()?; |
| 173 | if values.iter().any(Vec::is_empty) { |
| 174 | return Err(CombinatorialOptimizationError::EmptyDomain); |
| 175 | } |
| 176 | |
| 177 | let mut current = vec![0_i64; schema.variables.len()]; |
| 178 | let mut best_decision: Option<Vec<i64>> = None; |
| 179 | let mut best_objective = 0.0; |
| 180 | let mut evaluated = 0usize; |
| 181 | |
| 182 | enumerate_decisions(&values, 0, &mut current, &mut |decision| { |
| 183 | let value = objective.evaluate(decision)?; |
| 184 | if !value.is_finite() { |
| 185 | return Err(CombinatorialOptimizationError::ObjectiveNotFinite); |
| 186 | } |
| 187 | if best_decision.is_none() || is_better(value, best_objective, objective.sense()) { |
| 188 | best_decision = Some(decision.to_vec()); |
| 189 | best_objective = value; |
| 190 | } |
| 191 | evaluated = evaluated.saturating_add(1); |
| 192 | Ok(()) |
| 193 | })?; |
| 194 | |
| 195 | let best_decision = best_decision.ok_or(CombinatorialOptimizationError::NoFeasibleSolution)?; |
| 196 | Ok(OptimizationResult { best_decision, best_objective, evaluated_candidates: evaluated }) |
| 197 | } |
| 198 | |
| 199 | pub fn solve_with_adapter( |
| 200 | schema: &DecisionSchema, |