1use itertools::Itertools;
7use linalg::Matrix;
8use crate::polyopt::{Polyhedron, VariableFloat};
9
10use crate::linalg;
11
12#[derive(Default)]
14pub struct Solution {
15 pub x: Vec<f64>,
17 pub z: f64,
19 pub status_code: usize
30}
31
32impl Clone for Solution {
33 fn clone(&self) -> Self {
34 return Solution { x: self.x.clone(), z: self.z, status_code: self.status_code}
35 }
36}
37
38pub struct IntegerSolution {
40 pub x: Vec<i64>,
41 pub z: i64,
42 pub status_code: usize
43}
44
45impl Clone for IntegerSolution {
46 fn clone(&self) -> Self {
47 return IntegerSolution { x: self.x.clone(), z: self.z, status_code: self.status_code}
48 }
49}
50
51#[derive(Default)]
53struct BFS {
54 x: Vec<f64>,
56 b_vars: Vec<usize>,
58 n_vars: Vec<usize>,
60 sub_vars: Vec<usize>
63}
64
65impl Clone for BFS {
66 fn clone(&self) -> Self {
67 return BFS { x: self.x.clone(), b_vars: self.b_vars.clone(), n_vars: self.n_vars.clone(), sub_vars: self.sub_vars.clone()}
68 }
69}
70#[derive(Default)]
72pub struct LinearProgram {
73 pub ge_ph: Polyhedron,
75 pub eq_ph: Polyhedron,
77 pub of: Vec<f64>
79}
80
81impl Clone for LinearProgram {
82 fn clone(&self) -> Self {
83 return LinearProgram { ge_ph: self.ge_ph.clone(), eq_ph: self.eq_ph.clone(), of: self.of.clone()}
84 }
85}
86
87#[derive(Default)]
89pub struct IntegerLinearProgram {
90 pub ge_ph: Polyhedron,
92 pub eq_ph: Polyhedron,
94 pub of: Vec<f64>
96}
97
98impl Clone for IntegerLinearProgram {
99 fn clone(&self) -> Self {
100 return IntegerLinearProgram { ge_ph: self.ge_ph.clone(), eq_ph: self.eq_ph.clone(), of: self.of.clone()}
101 }
102}
103
104struct StandardFormLP{
106 eq_ph: Polyhedron,
107 of: Vec<f64>
108}
109
110impl Clone for StandardFormLP {
111 fn clone(&self) -> Self {
112 return StandardFormLP { eq_ph: self.eq_ph.clone(), of: self.of.clone() }
113 }
114
115}
116fn convert_lp_to_standard_form(lp: &LinearProgram) -> StandardFormLP {
119 let mut new_a = lp.ge_ph.a.clone();
121 let mut new_b = lp.ge_ph.b.to_vec();
122 let mut new_bounds = lp.ge_ph.bounds();
123 let mut new_of = lp.of.to_vec();
124 for i in 0..new_a.ncols {
125 if new_bounds[i].0 > 0.0 {
127 let mut tmp = vec![0.0; new_a.ncols];
128 tmp[i] = 1.0;
129 new_a.val.extend(tmp);
130 new_a.nrows = new_a.nrows+1;
131 new_b.push(new_bounds[i].0);
132 new_bounds[i].0 = 0.0;
133 }
134 if new_bounds[i].0 < 0.0 {
135 let tmp_a = new_a.val.to_vec();
136 new_a = new_a.insert_column(new_a.ncols, tmp_a.iter().skip(i).step_by(new_a.ncols).map(|e| -e).collect());
137 new_of.push(-new_of[i]);
138 new_bounds.push((f64::max(0.0, -new_bounds[i].1), -new_bounds[i].0));
139 }
140 }
141 for i in 0..new_a.nrows {
143 let mut tmp = vec![0.0; new_a.nrows];
144 if new_b[i] <= 0.0 {
145 tmp[i] = 1.0;
146 for j in 0..new_a.ncols{
147 new_a.val[i*new_a.ncols+j] = -new_a.val[i*new_a.ncols+j];
148 }
149 new_b[i] = -new_b[i];
150 } else {
151 tmp[i] = -1.0;
152 }
153 new_a = new_a.insert_column( new_a.ncols, tmp);
154 new_bounds.push((0.0, f64::MAX));
155 new_of.push(0.);
156 }
157
158 let n_rows = new_a.nrows;
159 return StandardFormLP {
160 eq_ph: Polyhedron{
161 a: new_a,
162 b: new_b.to_vec(),
163 variables: new_bounds.iter().map(|b| VariableFloat { id: 0, bounds: *b}).collect(),
164 index: (0..n_rows).map(|x| Some(x as u32)).collect(),
165 },
166 of: new_of.to_vec()
167 }
168}
169
170fn convert_ilp_to_standard_form(lp: &IntegerLinearProgram) -> StandardFormLP {
171 convert_lp_to_standard_form(&LinearProgram{ge_ph: lp.ge_ph.clone(), eq_ph: lp.eq_ph.clone(), of: lp.of.clone()})
172}
173fn _simplex_phase_one(lp: &StandardFormLP) -> (StandardFormLP, BFS) {
175 let mut origo_is_bfs = true;
176 let mut new_a: Matrix = lp.eq_ph.a.clone();
177 let mut art_var_cnt = 0;
178 let mut new_bounds = lp.eq_ph.bounds();
179 let mut new_of = vec![0.0; lp.eq_ph.a.ncols];
180 let updated_lp: StandardFormLP;
181 let mut new_bfs: BFS;
182 let mut b_vars: Vec<usize> = Vec::with_capacity(lp.eq_ph.a.nrows);
183 let mut n_vars: Vec<usize> = (0..lp.eq_ph.a.ncols - lp.eq_ph.a.nrows).collect();
184
185 let lp_eq_ph_bounds = lp.eq_ph.bounds();
186 for i in 0..lp.eq_ph.a.nrows {
187 if lp.eq_ph.a.val[i*lp.eq_ph.a.ncols + lp.eq_ph.a.ncols - lp.eq_ph.a.nrows+i] < 0.0 && lp.eq_ph.b[i] > 0.0 || lp.eq_ph.b[i] < lp_eq_ph_bounds[lp.eq_ph.a.ncols - lp.eq_ph.a.nrows+i].0 || lp.eq_ph.b[i] > lp_eq_ph_bounds[lp.eq_ph.a.ncols - lp.eq_ph.a.nrows+i].1 {
188 origo_is_bfs = false;
189 let mut tmp = vec![0.0; lp.eq_ph.a.nrows];
190 tmp[i] = 1.0;
191 new_a = new_a.insert_column(new_a.ncols, tmp);
192 b_vars.push(lp.eq_ph.a.ncols + art_var_cnt);
193 art_var_cnt = art_var_cnt + 1;
194 new_bounds.push((0.0, f64::MAX));
195 new_of.push(-1.0);
196 n_vars.push(lp.eq_ph.a.ncols - lp.eq_ph.a.nrows + i);
197 } else {
198 b_vars.push(lp.eq_ph.a.ncols - lp.eq_ph.a.nrows + i);
199 }
200 }
201 if origo_is_bfs {
202 return (lp.clone(), BFS {x: lp.eq_ph.b.clone(), b_vars: (new_a.ncols-new_a.nrows..new_a.ncols).collect(), n_vars: (0..new_a.ncols-new_a.nrows).collect(), sub_vars: Default::default()});
203 } else {
204 (updated_lp, new_bfs) = revised_simplex(
205 &StandardFormLP{ eq_ph: Polyhedron { a: new_a.clone(), b: lp.eq_ph.b.clone(), variables: new_bounds.iter().map(|b| VariableFloat {id: 0, bounds: *b}).collect(), index: lp.eq_ph.index.clone() },
206 of: new_of.clone()},
207 &BFS{
208 x: lp.eq_ph.b.clone(),
209 b_vars, n_vars, sub_vars: Default::default()
210 });
211 }
212 new_bfs.x = new_bfs.x.iter().map(|x| if (x%1.0) < 0.00001 {x.floor()} else if x%1.0>0.99999 {x.ceil()} else {*x}).collect();
213 let res = Matrix {val: new_bfs.x.clone(), nrows: 1, ncols: new_bfs.x.len()}.dot(&Matrix{val: new_of.clone(), ncols: new_of.len(), nrows: 1}.get_columns(&new_bfs.b_vars).transpose());
214 if res.val[0] < 0.0 - 0.0000001 {
215 return (lp.clone(), Default::default());
217 } else {
218 let mut b_vars = new_bfs.b_vars.clone();
219 let mut n_vars = new_bfs.n_vars.clone();
220 let mut b_inv = linalg::identity_matrix(b_vars.len());
221 let mut a = updated_lp.eq_ph.a.clone();
222 for index in 0..b_vars.len(){
223 if b_vars[index] >= lp.eq_ph.a.ncols {
224 let incoming_variable = n_vars.iter().find_or_first(|x| **x < lp.eq_ph.a.ncols).unwrap();
225 let b_inv_n_j = b_inv.dot(&Matrix { val : a.val.iter().skip(*incoming_variable).step_by(a.ncols).copied().collect(), ncols: 1, nrows: a.nrows});
226 let mut e = linalg::identity_matrix(b_vars.len());
227 e.val = e.update_column(index, &Matrix{val: (b_inv_n_j.val).iter().map(|x| -x).collect(), nrows: b_inv_n_j.nrows, ncols: b_inv_n_j.ncols}.divide(&Matrix{val: vec![(b_inv_n_j.val)[index]], ncols: 1, nrows:1}).val).val;
228 e.val[index*e.ncols + index] = if b_inv_n_j.val[index] != 0. {1./b_inv_n_j.val[index]} else {f64::MAX};
229 b_inv = e.dot(&b_inv);
230 b_vars[index] = *incoming_variable;
231 n_vars = n_vars.iter().filter(|x| **x != *incoming_variable).map(|x| *x).collect();
232 }
233 }
234 a = b_inv.dot(&a);
235 let b = b_inv.dot(&Matrix{val: updated_lp.eq_ph.b.to_vec(), ncols: 1, nrows: updated_lp.eq_ph.b.len()});
236
237 return (StandardFormLP{ eq_ph: Polyhedron{ a: a.get_columns(&(0..lp.eq_ph.a.ncols).collect()), b: b.val.to_vec(), variables: updated_lp.eq_ph.bounds()[0..lp.eq_ph.a.ncols].iter().map(|b| VariableFloat {id: 0, bounds: *b}).collect(), index: updated_lp.eq_ph.index.clone()}, of: lp.of.clone()},
238 BFS { x: b.val.to_vec(), b_vars: b_vars, n_vars: n_vars.into_iter().filter(|x| *x < lp.eq_ph.a.ncols).collect::<Vec<usize>>(), sub_vars: new_bfs.sub_vars})
239 }
240}
241
242fn _simplex_phase_two(lp: &StandardFormLP, bfs: &BFS) -> (StandardFormLP, BFS) {
244 revised_simplex(lp, bfs)
245}
246
247fn solve_standard_form_lp(lp: &StandardFormLP, bfs: Option<&BFS>) -> Solution {
249 let mut _bfs: BFS;
250 let mut _lp = lp.clone();
251 let sol: Solution;
252 if bfs.is_none() {
253 (_lp, _bfs) = _simplex_phase_one(&lp);
254 } else {
255 _bfs = bfs.unwrap().clone();
256 }
257 if _bfs.x.len() > 0 {
258 (_lp, _bfs) = _simplex_phase_two(&_lp, &_bfs);
259 let mut x = vec![0.0; _lp.eq_ph.a.ncols];
261 for i in 0.._bfs.b_vars.len(){
262 x[_bfs.b_vars[i]] = _bfs.x[i];
263 }
264 let lp_eq_ph_bounds = lp.eq_ph.bounds();
265 for i in 0.._bfs.sub_vars.len(){
266 x[_bfs.sub_vars[i]] = lp_eq_ph_bounds[_bfs.sub_vars[i]].1 - x[_bfs.sub_vars[i]];
267 }
268 let z = lp.of.iter().zip(x.iter()).map(|(x, y)| x*y).sum();
269 let status_code: usize;
270 if _bfs.x.len() < 1 {
271 status_code = 1;
272 } else if x.iter().any(|x| *x >= f64::MAX){
273 status_code = 6;
274 } else {
275 status_code = 5;
276 }
277 sol = Solution { x, z, status_code };
278 } else {
279 sol = Solution{
280 x: Default::default(),
281 z: Default::default(),
282 status_code: 4
283 };
284 }
285 sol
286}
287
288pub fn solve_lp(lp: &LinearProgram) -> Solution {
290 let mut sol = solve_standard_form_lp(&lp.convert_to_standard_form(), None);
291 if sol.x.len() > lp.ge_ph.a.ncols {
292 sol.x = sol.x[..lp.ge_ph.a.ncols].to_vec()
293 }
294 Solution { x: sol.x, z: sol.z, status_code: sol.status_code}
295}
296
297pub fn solve_ilp(lp: &IntegerLinearProgram) -> IntegerSolution {
299 let mut z_lb: f64 = f64::MIN;
300 let mut current_best_sol: Solution = Default::default();
301 let mut nodes_to_explore = vec![LinearProgram{ge_ph: lp.ge_ph.clone(), eq_ph: lp.eq_ph.clone(), of: lp.of.to_vec()}];
302 let mut explored_nodes: Vec<Vec<(f64, f64)>> = vec![];
303 let mut current_lp: LinearProgram;
304 let mut current_sol: Solution;
305 while nodes_to_explore.len() > 0 {
306 current_lp = nodes_to_explore.pop().expect("No LinearProgram in vector");
307 current_sol = LinearProgram::solve(¤t_lp);
308 if current_sol.status_code==4 || current_sol.status_code==3 {
309 continue
311 } else if current_sol.z < z_lb {
312 continue
314 } else if current_sol.x.iter().position(|x| (x%1.0) > 0.0000001 && (x%1.0) < 0.9999999).is_none() || current_sol.x.iter().position(|x| (x%1.0) > 0.0000001 && (x%1.0) < 0.999999).unwrap() >= current_lp.ge_ph.a.ncols {
315 z_lb = current_sol.z;
317 current_best_sol = current_sol;
318 } else {
319 let first_non_int = current_sol.x.iter().position(|x| (x%1.0) > 0.0000001 && (x%1.0) < 0.9999999).unwrap();
320
321 let mut bounds1 = current_lp.ge_ph.bounds().to_vec();
322 bounds1[first_non_int].1 = f64::floor(current_sol.x[first_non_int]);
323 let mut node_explored = false;
324 for i in 0..explored_nodes.len(){
325 node_explored = true;
326 for j in 0..explored_nodes[i].len(){
327 if j < bounds1.len() && !(explored_nodes[i][j].0 == bounds1[j].0 && explored_nodes[i][j].1 == bounds1[j].1) {
328 node_explored = false;
329 continue;
330 }
331 }
332 if node_explored {
333 break;
334 }
335 }
336 if !node_explored{
337 explored_nodes.push(bounds1.to_vec());
338 nodes_to_explore.push(LinearProgram{ge_ph: Polyhedron{ a: current_lp.ge_ph.a.clone(), b: current_lp.ge_ph.b.to_vec(), variables: bounds1.iter().map(|b| VariableFloat {id: 0, bounds: *b}).collect(), index: current_lp.ge_ph.index.clone()},
339 eq_ph: Polyhedron{ a: current_lp.eq_ph.a.clone(), b: current_lp.eq_ph.b.to_vec(), variables: bounds1.iter().map(|b| VariableFloat {id: 0, bounds: *b}).collect(), index: current_lp.eq_ph.index.clone()},
340 of: current_lp.of.to_vec()});
341 }
342 let mut node_explored = false;
343 let mut bounds2 = current_lp.ge_ph.bounds();
344 bounds2[first_non_int].0 = f64::ceil(current_sol.x[first_non_int]);
345 for i in 0..explored_nodes.len(){
346 node_explored = true;
347 for j in 0..explored_nodes[i].len(){
348 if j < bounds2.len() && !(explored_nodes[i][j].0 == bounds2[j].0 && explored_nodes[i][j].1 == bounds2[j].1) {
349 node_explored = false;
350 continue;
351 }
352 }
353 if node_explored {
354 break;
355 }
356 }
357 if !node_explored{
358 explored_nodes.push(bounds2.to_vec());
359 nodes_to_explore.push(LinearProgram{ge_ph: Polyhedron{ a: current_lp.ge_ph.a.clone(), b: current_lp.ge_ph.b.to_vec(), variables: bounds2.iter().map(|b| VariableFloat {id: 0, bounds: *b}).collect(), index: current_lp.ge_ph.index.clone()},
360 eq_ph: Polyhedron{ a: current_lp.eq_ph.a.clone(), b: current_lp.eq_ph.b.to_vec(), variables: bounds2.iter().map(|b| VariableFloat {id: 0, bounds: *b}).collect(), index: current_lp.eq_ph.index.clone()},
361 of: current_lp.of.to_vec()});
362 }
363 }
364 }
365 let mut res: Vec<i64> = current_best_sol.x.iter().map(|x| *x as i64).collect();
366 if res.len() > lp.ge_ph.a.ncols {
367 res = res[..lp.ge_ph.a.ncols].to_vec()
368 }
369 return IntegerSolution { z: z_lb as i64, x: res, status_code: current_best_sol.status_code};
370}
371impl LinearProgram {
372 fn convert_to_standard_form(&self) -> StandardFormLP {
373 convert_lp_to_standard_form(self)
374 }
375 pub fn solve(&self) -> Solution {
405 solve_lp(self)
406 }
407}
408
409impl IntegerLinearProgram {
410 fn convert_to_standard_form(&self) -> StandardFormLP {
411 convert_ilp_to_standard_form(self)
412 }
413 pub fn solve(&self) -> IntegerSolution {
444 solve_ilp(self)
445 }
446
447}
448
449fn revised_simplex(lp: &StandardFormLP, bfs: &BFS) -> (StandardFormLP, BFS) {
451 fn _update_constraint_column(b_inv_n_j: &Matrix, index: usize, b_inv: &Matrix, b_vars: &Vec<usize>) -> Matrix {
452 let mut e = linalg::identity_matrix(b_vars.len());
453 e.val = e.update_column(index, &Matrix{val: (b_inv_n_j.val).iter().map(|x| -x).collect(), nrows: b_inv_n_j.nrows, ncols: b_inv_n_j.ncols}.divide(&Matrix{val: vec![(b_inv_n_j.val)[index]], ncols: 1, nrows:1}).val).val;
454 e.val[index*e.ncols + index] = if b_inv_n_j.val[index] != 0. {1./b_inv_n_j.val[index]} else {f64::MAX};
455 e.dot(&b_inv)
456 }
457 fn _update_basis(b_vars: &Vec<usize>, n_vars: &Vec<usize>, incoming: usize, outgoing: usize) -> (Vec<usize>, Vec<usize>) {
458 let _tmp = b_vars[outgoing];
459 let mut b_vars_new = b_vars.to_vec();
460 let mut n_vars_new = n_vars.to_vec();
461 b_vars_new[outgoing] = n_vars[incoming];
462 n_vars_new[incoming] = _tmp;
463 (b_vars_new, n_vars_new)
464 }
465 fn _perform_ub_substitution(a_eq: &Matrix, b_eq: &Vec<f64>, c: &Vec<f64>, variable: &usize, limit: &f64, substituted_vars: &Vec<usize>) -> (Matrix, Vec<f64>, Vec<f64>, Vec<usize>){
466 let mut b = Vec::with_capacity(b_eq.len());
467 for i in 0..b_eq.len() {
468 b.push(b_eq[i] - limit*a_eq.val[i*a_eq.ncols+variable]);
469 }
470 let a = a_eq.val.iter().enumerate().map(|x| if x.0%a_eq.ncols == *variable {-*x.1} else {*x.1}).collect();
471 let mut c_new = c.to_vec();
472 c_new[*variable] = -c[*variable];
473 let mut sub_vars = substituted_vars.to_vec();
474 sub_vars.push(*variable);
475 return (Matrix{val: a, ncols: a_eq.ncols, nrows: a_eq.nrows}, b, c_new, sub_vars)
476 }
477
478 let mut b_vars = bfs.b_vars.clone();
480 let mut n_vars = bfs.n_vars.clone();
481 let mut c_new = lp.of.clone();
482 let mut sub_vars = bfs.sub_vars.clone();
483 for i in 0..sub_vars.len(){
484 c_new[sub_vars[i]] = -c_new[sub_vars[i]];
485 }
486 let mut x_b = Matrix{val: bfs.x.clone(), ncols: 1, nrows: b_vars.len()};
487 let mut b_inv = linalg::identity_matrix(b_vars.len());
488 let mut c_tilde_n: Vec<f64> = Vec::with_capacity(n_vars.len());
489 let mut a = lp.eq_ph.a.clone();
490 let mut b = lp.eq_ph.b.clone();
491 for i in 0..n_vars.len(){
492 c_tilde_n.push(lp.of[n_vars[i]] - Matrix{val: b_vars.iter().map(|i| lp.of[*i]).collect(),
493 ncols: b_vars.len(),
494 nrows: 1}.dot(&b_inv).dot(&linalg::get_columns(&a, &n_vars)).val[i]);
495 }
496 let mut b_inv_tilde: Matrix;
497 let lp_eq_ph_bounds = lp.eq_ph.bounds();
499 while c_tilde_n.iter().any(|x| *x > 0.0) {
500 let c_tilde_n_max = c_tilde_n.iter().cloned().fold(0./0., f64::max);
501 let incoming_variable_index = c_tilde_n.iter().position(|&x| x == c_tilde_n_max).unwrap();
502 let incoming_variable = n_vars[incoming_variable_index];
503 let b_inv_n_j = b_inv.dot(&Matrix { val : a.val.iter().skip(incoming_variable).step_by(a.ncols).copied().collect(), ncols: 1, nrows: a.nrows});
504 let mut _t1 = x_b.ge_divide(&b_inv_n_j);
505 let t1 = _t1.val.iter().cloned().fold(0.0/0.0, f64::min);
506 let t2 = lp_eq_ph_bounds[incoming_variable].1;
507 let _t3 = linalg::get_columns(&Matrix{val: lp_eq_ph_bounds.iter().map(|x| x.1).collect(), nrows:1, ncols: lp_eq_ph_bounds.len()}, &b_vars).subtract(&x_b.transpose()).ge_divide(&Matrix{ val: b_inv_n_j.val.iter().map(|x| -x).collect(), ncols: b_inv_n_j.ncols, nrows: b_inv_n_j.nrows}.transpose());
508 let t3 = _t3.val.iter().cloned().fold(0.0/0.0, f64::min);
509 if f64::min(f64::min(t1, t2), t3) == f64::MAX {
510 (b_vars, n_vars) = _update_basis(&b_vars, &n_vars, incoming_variable_index, 0);
512 x_b.val[0] = f64::MAX;
513 break;
514 } else if t3 < t1 && t3 < t2 {
515 let mut outgoing_variable = 0;
516 for i in 0.._t3.val.len(){
517 if _t3.val[i] == t3 && b_vars[i] > outgoing_variable {
518 outgoing_variable = b_vars[i];
519 }
520 }
521 let outgoing_variable_index = b_vars.iter().position(|&x| x==outgoing_variable).unwrap();
522 (a, b, c_new, sub_vars) = _perform_ub_substitution(&a.clone(), &b.to_vec(), &c_new.to_vec(), &outgoing_variable, &lp_eq_ph_bounds[outgoing_variable].1, &sub_vars);
523 b_inv_tilde = _update_constraint_column(&b_inv_n_j, outgoing_variable_index, &b_inv, &b_vars);
524 (b_vars, n_vars) = _update_basis(&b_vars, &n_vars, incoming_variable_index, outgoing_variable_index);
525 } else if t2 < t1 {
526 (a, b, c_new, sub_vars) = _perform_ub_substitution(&a.clone(), &b.to_vec(), &c_new.to_vec(), &incoming_variable, &lp_eq_ph_bounds[incoming_variable].1, &sub_vars);
527 b_inv_tilde = b_inv.clone();
528 } else {
529 let outgoing_variable: Option<usize> = _t1.val.iter().enumerate().filter(|(_, &r)| r == t1).map(|(index, _)| *b_vars.get(index).expect("did not find index")).max();
530 let outgoing_variable_index = b_vars.iter().position(|&x| x==outgoing_variable.unwrap()).unwrap();
531 b_inv_tilde = _update_constraint_column(&b_inv_n_j, outgoing_variable_index, &b_inv, &b_vars);
532 (b_vars, n_vars) = _update_basis(&b_vars, &n_vars, incoming_variable_index, outgoing_variable_index);
533 }
534 b_inv = b_inv_tilde.clone();
535 for i in 0..n_vars.len(){
536 c_tilde_n[i] = c_new[n_vars[i]] - Matrix{val: b_vars.iter().map(|j| c_new[*j]).collect(),
537 ncols: b_vars.len(),
538 nrows: 1}.dot(&b_inv_tilde).dot(&linalg::get_columns(&a, &n_vars)).val[i];
539 }
540 x_b = b_inv.dot(&Matrix{val: b.to_vec(), ncols: 1, nrows: b.len()});
541 }
542
543 let a_new = b_inv.dot(&a);
544
545 return (StandardFormLP{ eq_ph: Polyhedron {a: a_new, b: x_b.val.to_vec(), variables: lp.eq_ph.variables.clone(), index: lp.eq_ph.index.clone()}, of: lp.of.clone()},
546 BFS { x: x_b.val, b_vars, n_vars, sub_vars})
547}
548
549#[cfg(test)]
550mod tests {
551 use super::*;
552 #[test]
553 fn test_solver_1(){
554 let lp: IntegerLinearProgram = IntegerLinearProgram {
555 ge_ph: Polyhedron {
556 a: Matrix{val: vec![1.0, 1.0, 0.0, 0.0, 1.0, 1.0],
557 nrows: 2,
558 ncols: 3},
559 b: vec![1.0, 1.0],
560 variables: vec![
561 VariableFloat { id: 0, bounds: (0.0,1.0)},
562 VariableFloat { id: 0, bounds: (0.0,1.0)},
563 VariableFloat { id: 0, bounds: (0.0,1.0)}
564 ],
565 index: (0..2).map(|x| Some(x as u32)).collect(),
566 },
567 eq_ph: Default::default(),
568 of: vec![1.0,1.0,1.0]
569 };
570 let sol = lp.solve();
571 assert_eq!(sol.z, 3);
572 assert_eq!(sol.x, vec![1, 1, 1]);
573 }
574 #[test]
575 fn test_solver_2(){
576 let lp: IntegerLinearProgram = IntegerLinearProgram {
577 ge_ph: Polyhedron {
578 a: Matrix{val: vec![-2.0, -1.0, -1.0, -1.0, -1.0, 0.0],
579 nrows: 3,
580 ncols: 2},
581 b: vec![-100.0, -80.0, -40.0],
582 variables: vec![
583 VariableFloat { id: 0, bounds: (0.0,f64::MAX) },
584 VariableFloat { id: 0, bounds: (0.0,f64::MAX) },
585 ],
586 index: (0..3).map(|x| Some(x as u32)).collect(),
587 },
588 eq_ph: Default::default(),
589 of: vec![30.0,20.0]
590 };
591 let sol = lp.solve();
592 assert_eq!(sol.z, 1800);
593 assert_eq!(sol.x, vec![20, 60]);
594 }
595 #[test]
596 fn test_solver_3(){
597 let lp: IntegerLinearProgram = IntegerLinearProgram {
598 ge_ph: Polyhedron {
599 a: Matrix{val: vec![-2.0, -1.0, -1.0, -1.0],
600 nrows: 2,
601 ncols: 2},
602 b: vec![-100.0, -80.0],
603 variables: vec![
604 VariableFloat { id: 0, bounds: (0.0,40.0) },
605 VariableFloat { id: 0, bounds: (0.0,30.0) }
606 ],
607 index: (0..2).map(|x| Some(x as u32)).collect(),
608 },
609 eq_ph: Default::default(),
610 of: vec![30.0,20.0]
611 };
612 let sol = lp.solve();
613 assert_eq!(sol.z, 1650);
614 assert_eq!(sol.x, vec![35, 30]);
615 }
616 #[test]
617 fn test_solver_4(){
618 let lp: IntegerLinearProgram = IntegerLinearProgram {
619 ge_ph: Polyhedron {
620 a: Matrix{val: vec![2.0, -1.0, -1.0, -2.0, -1.0, 0.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0],
621 nrows: 4,
622 ncols: 3},
623 b: vec![1.0, -5.0, 1.0, -1.0],
624 variables: vec![
625 VariableFloat { id: 0, bounds: (0.0,f64::MAX) },
626 VariableFloat { id: 0, bounds: (0.0,f64::MAX) },
627 VariableFloat { id: 0, bounds: (0.0,f64::MAX) }
628 ],
629 index: (0..4).map(|x| Some(x as u32)).collect(),
630 },
631 eq_ph: Default::default(),
632 of: vec![-2.0,-1.0, -1.0]
633 };
634 let sol = lp.solve();
635 assert_eq!(sol.z, -3);
636 assert_eq!(sol.x, vec![1, 0, 1]);
637 }
638 #[test]
639 fn test_solver_5(){
640 let lp: IntegerLinearProgram = IntegerLinearProgram {
641 ge_ph: Polyhedron {
642 a: Matrix{val: vec![-1.0, 1.0, -2.0, 1.0, 0.0, -1.0],
643 nrows: 3,
644 ncols: 2},
645 b: vec![-2.0, -4.0, -2.0],
646 variables: vec![
647 VariableFloat { id: 0, bounds: (0.0,f64::MAX)},
648 VariableFloat { id: 0, bounds: (0.0,f64::MAX)}
649 ],
650 index: (0..3).map(|x| Some(x as u32)).collect(),
651 },
652 eq_ph: Default::default(),
653 of: vec![1.0, 1.0]
654 };
655 let sol = lp.solve();
656 assert_eq!(sol.z, 5);
657 assert_eq!(sol.x, vec![3, 2]);
658 }
659
660 #[test]
661 fn test_solver_6(){
662 let lp: IntegerLinearProgram = IntegerLinearProgram {
663 ge_ph: Polyhedron {
664 a: Matrix{val: vec![-5.0, -4.0],
665 nrows: 1,
666 ncols: 2},
667 b: vec![-21.0],
668 variables: vec![
669 VariableFloat { id: 0, bounds: (0.0,f64::MAX)},
670 VariableFloat { id: 0, bounds: (0.0,f64::MAX)}
671 ],
672 index: (0..1).map(|x| Some(x as u32)).collect(),
673 },
674 eq_ph: Default::default(),
675 of: vec![5.0, 2.0]
676 };
677 let sol = lp.solve();
678 assert_eq!(sol.z, 20);
679 assert_eq!(sol.x, vec![4, 0]);
680 }
681
682 #[test]
683 fn test_solver_7(){
684 let lp: IntegerLinearProgram = IntegerLinearProgram {
685 ge_ph: Polyhedron {
686 a: Matrix{val: vec![-4.0, -2.0, -2.0, -3.0],
687 nrows: 1,
688 ncols: 4},
689 b: vec![-7.0],
690 variables: vec![
691 VariableFloat { id: 0, bounds: (0.0,1.0)},
692 VariableFloat { id: 0, bounds: (0.0,1.0)},
693 VariableFloat { id: 0, bounds: (0.0,1.0)},
694 VariableFloat { id: 0, bounds: (0.0,1.0)}
695 ],
696 index: (0..1).map(|x| Some(x as u32)).collect(),
697 },
698 eq_ph: Default::default(),
699 of: vec![7.0, 3.0, 2.0, 2.0]
700 };
701 let sol = lp.solve();
702 assert_eq!(sol.z, 10);
703 assert_eq!(sol.x, vec![1,1,0,0]);
704 }
705
706 #[test]
707 fn test_solver_8(){
708 let lp: IntegerLinearProgram = IntegerLinearProgram {
709 ge_ph: Polyhedron {
710 a: Matrix{val: vec![1.0, 4.0, 3.0, 2.0],
711 nrows: 2,
712 ncols: 2},
713 b: vec![4.0, 6.0],
714 variables: vec![
715 VariableFloat { id: 0, bounds: (0.0,f64::MAX)},
716 VariableFloat { id: 0, bounds: (0.0,f64::MAX)}
717 ],
718 index: (0..2).map(|x| Some(x as u32)).collect(),
719 },
720 eq_ph: Default::default(),
721 of: vec![-4.0, -5.0]
722 };
723 let sol = lp.solve();
724 assert_eq!(sol.z, -13);
725 assert_eq!(sol.x, vec![2,1]);
726 }
727 #[test]
728 fn test_solver_9(){
729 let lp: IntegerLinearProgram = IntegerLinearProgram {
730 ge_ph: Polyhedron {
731 a: Matrix{val: vec![4.0, -3.0, -3.0, -2.0],
732 nrows: 2,
733 ncols: 2},
734 b: vec![-6.0, -18.0],
735 variables: vec![
736 VariableFloat { id: 0, bounds: (0.0,f64::MAX)},
737 VariableFloat { id: 0, bounds: (0.0,f64::MAX)}
738 ],
739 index: (0..2).map(|x| Some(x as u32)).collect(),
740 },
741 eq_ph: Default::default(),
742 of: vec![1.0, 5.0]
743 };
744 let sol = lp.solve();
745 assert_eq!(sol.z, 23);
746 assert_eq!(sol.x, vec![3,4]);
747 }
748 #[test]
749 fn test_solver_10(){
750 let lp: IntegerLinearProgram = IntegerLinearProgram {
751 ge_ph: Polyhedron {
752 a: Matrix{val: vec![-5.0, -7.0, -1.0, 0.0, 0.0, -1.0],
753 nrows: 3,
754 ncols: 2},
755 b: vec![-35.0, -3.0, -4.0],
756 variables: vec![
757 VariableFloat { id: 0, bounds: (0.0,f64::MAX)},
758 VariableFloat { id: 0, bounds: (0.0,f64::MAX)}
759 ],
760 index: (0..3).map(|x| Some(x as u32)).collect(),
761 },
762 eq_ph: Default::default(),
763 of: vec![5.0, 6.0]
764 };
765 let sol = lp.solve();
766 assert_eq!(sol.z, 29);
767 assert_eq!(sol.x, vec![1,4]);
768 }
769 #[test]
770 fn test_solver_11(){
771 let lp: IntegerLinearProgram = IntegerLinearProgram {
772 ge_ph: Polyhedron {
773 a: Matrix{val: vec![-4.0, -2.0, -3.0, -1.0],
774 nrows: 1,
775 ncols: 4},
776 b: vec![-7.0],
777 variables: vec![
778 VariableFloat { id: 0, bounds: (0.0,f64::MAX)},
779 VariableFloat { id: 0, bounds: (0.0,f64::MAX)},
780 VariableFloat { id: 0, bounds: (0.0,f64::MAX)},
781 VariableFloat { id: 0, bounds: (0.0,f64::MAX)}
782 ],
783 index: (0..1).map(|x| Some(x as u32)).collect(),
784 },
785 eq_ph: Default::default(),
786 of: vec![18.0, 8.0, 4.0, 2.0]
787 };
788 let sol = lp.solve();
789 assert_eq!(sol.z, 28);
790 assert_eq!(sol.x, vec![1, 1, 0, 1]);
791 }
792 #[test]
793 fn test_solver_12(){
794 let lp: IntegerLinearProgram = IntegerLinearProgram {
795 ge_ph: Polyhedron {
796 a: Matrix{val: vec![-6.0, -10.0, -15.0, -10.0],
797 nrows: 1,
798 ncols: 4},
799 b: vec![-36.0],
800 variables: vec![
801 VariableFloat { id: 0, bounds: (0.0,f64::MAX)},
802 VariableFloat { id: 0, bounds: (0.0,f64::MAX)},
803 VariableFloat { id: 0, bounds: (0.0,f64::MAX)},
804 VariableFloat { id: 0, bounds: (0.0,f64::MAX)}
805 ],
806 index: (0..1).map(|x| Some(x as u32)).collect(),
807 },
808 eq_ph: Default::default(),
809 of: vec![5.0, 10.0, 10.0, 16.0]
810 };
811 let sol = lp.solve();
812 assert_eq!(sol.z, 53);
813 assert_eq!(sol.x, vec![1, 0, 0, 3]);
814 }
815 #[test]
816 fn test_solver_13(){
817 let lp: IntegerLinearProgram = IntegerLinearProgram {
818 ge_ph: Polyhedron {
819 a: Matrix{val: vec![-2.0, -3.0, -3.0],
820 nrows: 1,
821 ncols: 3},
822 b: vec![-9.0],
823 variables: vec![
824 VariableFloat { id: 0, bounds: (0.0,2.0)},
825 VariableFloat { id: 0, bounds: (0.0,2.0)},
826 VariableFloat { id: 0, bounds: (0.0,2.0)}
827 ],
828 index: (0..1).map(|x| Some(x as u32)).collect(),
829 },
830 eq_ph: Default::default(),
831 of: vec![5.0, 6.0, 7.0]
832 };
833 let sol = lp.solve();
834 assert_eq!(sol.z, 20);
835 assert_eq!(sol.x, vec![0, 1, 2]);
836 }
837 #[test]
838 fn test_solver_14(){
839 let lp: IntegerLinearProgram = IntegerLinearProgram {
840 ge_ph: Polyhedron {
841 a: Matrix{val: vec![-1.0, -2.0, -1.0, 0.0, 0.0, -2.0, -4.0, -3.0, -7.0, -3.0],
842 nrows: 2,
843 ncols: 5},
844 b: vec![-2.0, -13.0],
845 variables: vec![
846 VariableFloat { id: 0, bounds: (0.0,1.0)},
847 VariableFloat { id: 0, bounds: (0.0,1.0)},
848 VariableFloat { id: 0, bounds: (0.0,1.0)},
849 VariableFloat { id: 0, bounds: (0.0,1.0)},
850 VariableFloat { id: 0, bounds: (0.0,1.0)}
851 ],
852 index: (0..2).map(|x| Some(x as u32)).collect(),
853 },
854 eq_ph: Default::default(),
855 of: vec![5.0, 7.0, 6.0, 4.0, 5.0]
856 };
857 let sol = lp.solve();
858 assert_eq!(sol.z, 16);
859 assert_eq!(sol.x, vec![1, 0, 1, 0, 1]);
860 }
861 #[test]
862 fn test_solver_15(){
863 let lp: IntegerLinearProgram = IntegerLinearProgram {
864 ge_ph: Polyhedron {
865 a: Matrix{val: vec![-2.0, -1.0, -2.0, -1.0],
866 nrows: 1,
867 ncols: 4},
868 b: vec![-4.0],
869 variables: vec![
870 VariableFloat { id: 0, bounds: (0.0,1.0)},
871 VariableFloat { id: 0, bounds: (0.0,1.0)},
872 VariableFloat { id: 0, bounds: (0.0,1.0)},
873 VariableFloat { id: 0, bounds: (0.0,1.0)}
874 ],
875 index: (0..1).map(|x| Some(x as u32)).collect(),
876 },
877 eq_ph: Default::default(),
878 of: vec![5.0, 8.0, 4.0, 6.0]
879 };
880 let sol = lp.solve();
881 assert_eq!(sol.z, 19);
882 assert_eq!(sol.x, vec![1, 1, 0, 1]);
883 }
884 #[test]
886 fn test_solver_16(){
887 let lp: IntegerLinearProgram = IntegerLinearProgram {
888 ge_ph: Polyhedron {
889 a: Matrix{val: vec![0.0, -1.0],
890 nrows: 1,
891 ncols: 2},
892 b: vec![-3.0],
893 variables: vec![
894 VariableFloat { id: 0, bounds: (0.0, f64::MAX)},
895 VariableFloat { id: 0, bounds: (0.0, f64::MAX)}
896 ],
897 index: (0..1).map(|x| Some(x as u32)).collect(),
898 },
899 eq_ph: Default::default(),
900 of: vec![1.0, 1.0]
901 };
902 let sol = lp.solve();
903 assert_eq!(sol.z, i64::MAX);
904 assert_eq!(sol.x, vec![i64::MAX, 0]);
905 }
906 #[test]
908 fn test_solver_17(){
909 let lp: IntegerLinearProgram = IntegerLinearProgram {
910 ge_ph: Polyhedron {
911 a: Matrix{val: vec![-1.0, -1.0, 1.0, -1.0, 0.0, 1.0],
912 nrows: 3,
913 ncols: 2},
914 b: vec![-1.0, 0.0, 2.0],
915 variables: vec![
916 VariableFloat { id: 0, bounds: (0.0, f64::MAX)},
917 VariableFloat { id: 0, bounds: (0.0, f64::MAX)}
918 ],
919 index: (0..3).map(|x| Some(x as u32)).collect(),
920 },
921 eq_ph: Default::default(),
922 of: vec![1.0, 1.0]
923 };
924 let sol = lp.solve();
925 assert_eq!(sol.z, -f64::MAX as i64);
926 assert_eq!(sol.x, vec![]);
927 }
928 #[test]
930 fn test_solver_18(){
931 let lp: IntegerLinearProgram = IntegerLinearProgram {
932 ge_ph: Polyhedron {
933 a: Matrix{val: vec![1.0, 1.0, 0.0, 0.0, 1.0, 1.0],
934 nrows: 2,
935 ncols: 3},
936 b: vec![1.0, 1.0],
937 variables: vec![
938 VariableFloat { id: 0, bounds: (0.0,1.0)},
939 VariableFloat { id: 0, bounds: (0.0,1.0)},
940 VariableFloat { id: 0, bounds: (0.0,1.0)}
941 ],
942 index: (0..2).map(|x| Some(x as u32)).collect(),
943 },
944 eq_ph: Default::default(),
945 of: vec![1.0,1.0,1.0]
946 };
947 let sol = lp.solve();
948 assert_eq!(sol.z, 3);
949 assert_eq!(sol.x, vec![1, 1, 1]);
950 }
951 #[test]
952 fn test_solver_19(){
953 let lp: IntegerLinearProgram = IntegerLinearProgram{
954 ge_ph: Polyhedron { a: Matrix { val: vec![ 1., 1., 0., 0., 0., 0., 0., -2., 0., 0., 1., 1., -1., 0., -1., -1., 0., 0.],
955 nrows: 3, ncols: 6},
956 b: vec![1.0, 0.0, -2.0],
957 variables: vec![
958 VariableFloat{id: 0, bounds:(0.0, 1.0)},
959 VariableFloat{id: 0, bounds:(0.0, 1.0)},
960 VariableFloat{id: 0, bounds:(0.0, 1.0)},
961 VariableFloat{id: 0, bounds:(0.0, 1.0)},
962 VariableFloat{id: 0, bounds:(0.0, 1.0)},
963 VariableFloat{id: 0, bounds:(0.0, 1.0)}],
964 index: (0..5).map(|x| Some(x as u32)).collect(),
965 },
966 eq_ph: Default::default(),
967 of: vec![0.0, 1.0, 1.0, 1.0, 0.0, 0.0]
968 };
969 let sol = lp.solve();
970 assert_eq!(sol.z, 3);
971 assert_eq!(sol.x, vec![0, 1, 1, 1, 1, 1]);
972 }
973 #[test]
974 fn test_solver_20(){
975 let solution: IntegerSolution = IntegerLinearProgram {
976 ge_ph: Polyhedron {
977 a: Matrix {
978 val: vec![1.0, 1.0],
979 ncols: 2,
980 nrows: 1
981 },
982 b: vec![2.0],
983 index: vec![Some(0)],
984 variables: vec![
985 VariableFloat { id: 1, bounds: (0.0, 1.0) },
986 VariableFloat { id: 2, bounds: (0.0, 1.0) },
987 ]
988 },
989 eq_ph: Default::default(),
990 of: vec![1.0, 0.0]
991 }.solve();
992 assert_eq!(solution.x, vec![1,1]);
993 assert_eq!(solution.z, 1);
994 assert_eq!(solution.status_code, 5);
995 }
996 #[test]
997 fn test_solver_21(){
998 let solution: IntegerSolution = IntegerLinearProgram {
999 ge_ph: Polyhedron {
1000 a: Matrix {
1001 val: vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 1., 0., 0., 0.,
1002 -1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,-5., 0., 0., 0.,
1003 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0.,-6., 0., 1., 1., 0., 1., 1., 0.,
1004 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.,-1., 0.,
1005 0.,-1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,-1., 0., 0., 0., 0., 0., 0.,
1006 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.,-1., 0., 0.,
1007 0., 0., 0., 0., 0., 0., 0.,-1., 0., 0., 0., 0., 0., 0., 0.,-1., 0., 0., 0., 0., 0., 0., 0., 0.,
1008 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.,-1., 0., 0., 0., 0.,
1009 0., 0., 0.,-1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,-1., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
1010 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,-1., 0., 0., 0., 0., 1.,
1011 0., 0., 0., 0., 0., 0., 0., 0.,-1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,-1.,
1012 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,-1., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
1013 0., 0., 0., 0., 0., 0.,-1., 0., 0., 0., 0., 0., 0.,-1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
1014 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,-1., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
1015 0., 0.,-1., 0., 0., 0., 0., 0., 0., 0., 0., 0.,-1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
1016 ncols: 24,
1017 nrows: 15
1018 },
1019 b: vec![2.,-10., 0., 0.,-1., 0.,-1., 0.,-1., 0.,-1., 0.,-1., 0.,-1.],
1020 index: vec![Some(0)],
1021 variables: vec![
1022 VariableFloat { id: 1, bounds: (0.0, 1.0) },
1023 VariableFloat { id: 2, bounds: (0.0, 1.0) },
1024 VariableFloat { id: 3, bounds: (0.0, 1.0) },
1025 VariableFloat { id: 4, bounds: (0.0, 1.0) },
1026 VariableFloat { id: 5, bounds: (0.0, 1.0) },
1027 VariableFloat { id: 6, bounds: (0.0, 1.0) },
1028 VariableFloat { id: 7, bounds: (0.0, 1.0) },
1029 VariableFloat { id: 8, bounds: (0.0, 1.0) },
1030 VariableFloat { id: 9, bounds: (0.0, 1.0) },
1031 VariableFloat { id: 10, bounds: (0.0, 1.0) },
1032 VariableFloat { id: 11, bounds: (0.0, 1.0) },
1033 VariableFloat { id: 12, bounds: (0.0, 1.0) },
1034 VariableFloat { id: 13, bounds: (0.0, 1.0) },
1035 VariableFloat { id: 14, bounds: (0.0, 1.0) },
1036 VariableFloat { id: 15, bounds: (0.0, 1.0) },
1037 VariableFloat { id: 16, bounds: (0.0, 1.0) },
1038 VariableFloat { id: 17, bounds: (0.0, 1.0) },
1039 VariableFloat { id: 18, bounds: (0.0, 1.0) },
1040 VariableFloat { id: 19, bounds: (0.0, 1.0) },
1041 VariableFloat { id: 20, bounds: (0.0, 1.0) },
1042 VariableFloat { id: 21, bounds: (0.0, 1.0) },
1043 VariableFloat { id: 22, bounds: (0.0, 1.0) },
1044 VariableFloat { id: 23, bounds: (0.0, 1.0) },
1045 VariableFloat { id: 24, bounds: (0.0, 1.0) },
1046 ]
1047 }, eq_ph: Default::default(),
1048 of: vec![10., 10., 10., 10., 10., 10., 10., 10., 10., 10., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.] }.solve();
1049 assert_eq!(solution.x, vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1])
1050 }
1051}