1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use crate::solvers::{ObjectiveDirection, ResolutionError, Solution, SolverModel};
use crate::variable::{UnsolvedProblem, VariableDefinition};
use crate::{Constraint, Variable};
use std::marker::PhantomData;
pub fn minilp<F>(to_solve: UnsolvedProblem<F>) -> MiniLpProblem<F> {
let UnsolvedProblem {
objective,
direction,
variables,
} = to_solve;
let mut problem = minilp::Problem::new(match direction {
ObjectiveDirection::Maximisation => minilp::OptimizationDirection::Maximize,
ObjectiveDirection::Minimisation => minilp::OptimizationDirection::Minimize,
});
let variables: Vec<minilp::Variable> = variables
.iter_variables_with_def()
.map(|(var, &VariableDefinition { min, max, .. })| {
let coeff = *objective.linear.coefficients.get(&var).unwrap_or(&0.);
problem.add_var(coeff, (min, max))
})
.collect();
MiniLpProblem {
problem,
variables,
variable_type: PhantomData,
}
}
pub struct MiniLpProblem<F> {
problem: minilp::Problem,
variables: Vec<minilp::Variable>,
variable_type: PhantomData<F>,
}
impl<T> MiniLpProblem<T> {
pub fn as_inner(&self) -> &minilp::Problem {
&self.problem
}
}
impl<T> SolverModel<T> for MiniLpProblem<T> {
type Solution = MiniLpSolution<T>;
type Error = ResolutionError;
fn with(mut self, constraint: Constraint<T>) -> Self {
let coefficients: Vec<(minilp::Variable, f64)> = constraint
.expression
.linear
.coefficients
.iter()
.map(|(var, &coeff)| (self.variables[var.index()], coeff))
.collect();
let op = match constraint.is_equality {
true => minilp::ComparisonOp::Eq,
false => minilp::ComparisonOp::Le,
};
let constant = -constraint.expression.constant;
self.problem.add_constraint(&coefficients, op, constant);
self
}
fn solve(self) -> Result<Self::Solution, Self::Error> {
match self.problem.solve() {
Err(minilp::Error::Unbounded) => Err(ResolutionError::Unbounded),
Err(minilp::Error::Infeasible) => Err(ResolutionError::Infeasible),
Ok(solution) => Ok(MiniLpSolution {
solution,
variables: self.variables,
_variable_type: PhantomData,
}),
}
}
}
pub struct MiniLpSolution<F> {
solution: minilp::Solution,
variables: Vec<minilp::Variable>,
_variable_type: PhantomData<F>,
}
impl<F> MiniLpSolution<F> {
pub fn into_inner(self) -> minilp::Solution {
self.solution
}
}
impl<F> Solution<F> for MiniLpSolution<F> {
fn value(&self, variable: Variable<F>) -> f64 {
self.solution[self.variables[variable.index()]]
}
}
#[cfg(test)]
mod tests {
use super::minilp;
use crate::{variable, variables, Solution, SolverModel};
#[test]
fn can_solve_easy() {
let mut vars = variables!();
let x = vars.add(variable().clamp(0, 2));
let y = vars.add(variable().clamp(1, 3));
let solution = vars
.maximise(x + y)
.using(minilp)
.with(2 * x + y << 4)
.solve()
.unwrap();
assert_eq!((solution.value(x), solution.value(y)), (0.5, 3.))
}
}