Skip to main content

puanrs/
solver.rs

1//! # Simplex solver
2//! 
3//! Beta version of simplex solver for linear and integer linear programs.
4//! 
5
6use itertools::Itertools;
7use linalg::Matrix;
8use crate::polyopt::{Polyhedron, VariableFloat};
9
10use crate::linalg;
11
12/// Data structure for a solution to a linear program.
13#[derive(Default)]
14pub struct Solution {
15    /// Value of the variables at the solution.
16    pub x: Vec<f64>,
17    /// Value of the objective function given `x`.
18    pub z: f64,
19    /// Status of the solution.
20    /// 
21    ///| Code | Description                 |
22    ///|------|-----------------------------|
23    ///| 1    | solution is undefined       |
24    ///| 2    | solution is feasible        |
25    ///| 3    | solution is infeasible      |
26    ///| 4    | no feasible solution exists |
27    ///| 5    | solution is optimal         |
28    ///| 6    | solution is unbounded       |
29    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
38/// Data structure for integer solutions to an integer linear program. (See Solution).
39pub 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/// Data structure for a basic feasible solution.
52#[derive(Default)]
53struct BFS {
54    /// values of the basis variables.
55    x: Vec<f64>,
56    /// Indices of the basis variables.
57    b_vars: Vec<usize>,
58    /// Indices of non-basis variables.
59    n_vars: Vec<usize>,
60    /// Indices of substituted variables.
61    /// Substitutions as x' = upper_bound(x) - x.
62    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/// Data structure for a linear program (LP).
71#[derive(Default)]
72pub struct LinearProgram {
73    /// Polyhedron with constraints on the form $ A \ge b $.
74    pub ge_ph: Polyhedron,
75    /// Polyhedron with constraints on the form $ A = b $.
76    pub eq_ph: Polyhedron,
77    /// Objective function.
78    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/// Data structure for an integer linear program (ILP).
88#[derive(Default)]
89pub struct IntegerLinearProgram {
90    /// Polyhedron with constraints on the form $ A \ge b $.
91    pub ge_ph: Polyhedron,
92    /// Polyhedron with constraints on the form $ A = b $.
93    pub eq_ph: Polyhedron,
94    /// Objective function.
95    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
104/// Data structute for a linear program on standard form.
105struct 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}
116/// Function which converts an LP to an LP on standard form, i.e. introducing slack variables,
117/// adding constraints for lower bounds above zero, substituting variables below zero etc.
118fn convert_lp_to_standard_form(lp: &LinearProgram) -> StandardFormLP {
119    // Handle lower bounds above and below zero
120    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        // Add new constraint to force variable i to be above its lower bound
126        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    // Introduce slack-variables
142    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}
173/// Phase one of the simplex algorithm, finds a basic feasible solution
174fn _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        // No feasible solution exists
216        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
242/// Phase two of the simplex algorithm. Finds an optimal solution to the LP if possible.
243fn _simplex_phase_two(lp: &StandardFormLP, bfs: &BFS) -> (StandardFormLP, BFS) {
244    revised_simplex(lp, bfs)
245}
246
247/// Solves a maximization LP on standard form using the simplex algorithm. 
248fn 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        // Re substitute variables
260        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
288/// Solves a maximization LP using the simplex algorithm
289pub 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
297/// Solves a maximization ILP using the Land-Doig-Dakins algorithm together with the simplex algorithm. 
298pub 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(&current_lp);
308        if current_sol.status_code==4 || current_sol.status_code==3 {
309            // No feasible solution in this area
310           continue
311        } else if current_sol.z < z_lb {
312            // Not possible to find better solution in this area
313           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            // We've found a best solution in this area
316            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    /// Solves a linear program with the revised simplex algorithm. 
376    /// # Example:
377    /// 
378    /// Solve the linear program
379    /// $$ \max \quad -4x_1+-5x_2 $$
380    /// $$ s.t. \quad x_1+4x_2 \geq 4 $$
381    /// $$ \qquad \ 3x_1+2x_2 \geq 6 $$
382    /// $$ \qquad \  x_1, x_2 \geq 0$$
383    /// ```
384    /// use puanrs::polyopt::{Polyhedron, VariableFloat};
385    /// use puanrs::solver::LinearProgram;
386    /// use puanrs::linalg::Matrix;
387    /// let sol = LinearProgram {
388    ///                 ge_ph: Polyhedron {
389    ///                         a: Matrix{val: vec![1.0, 4.0, 3.0, 2.0],
390    ///                             nrows: 2,
391    ///                             ncols: 2
392    ///                         },
393    ///                         b: vec![4.0, 6.0],
394    ///                         variables: vec![ VariableFloat { id: 0, bounds: (0.0,f64::MAX) }, VariableFloat { id: 1, bounds: (0.0,f64::MAX) }],
395    ///                         index: vec![Some(0),Some(1)],
396    ///                 },
397    ///                 eq_ph: Default::default(),
398    ///                 of: vec![-4.0, -5.0],
399    ///             }.solve();
400    /// assert_eq!(sol.z, -9.4);
401    /// assert_eq!(sol.x, vec![1.6000000000000003, 0.5999999999999999]);
402    /// assert_eq!(sol.status_code, 5);
403    /// ```
404    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    /// Solves a linear program with the revised simplex algorithm and produces an integer solution using the Land-Doig-Dakins algorithm. 
414    /// # Example:
415    /// 
416    /// Solve the linear program
417    /// $$ \max \quad -4x_1+-5x_2 $$
418    /// $$ s.t. \quad x_1+4x_2 \geq 4 $$
419    /// $$ \qquad \ 3x_1+2x_2 \geq 6 $$
420    /// $$ \qquad \  x_1, x_2 \geq 0$$
421    /// ```
422    /// use puanrs::solver::IntegerLinearProgram;
423    /// use puanrs::polyopt::{Polyhedron, VariableFloat};
424    /// use puanrs::linalg::Matrix;
425    /// let sol = IntegerLinearProgram {
426    ///                 ge_ph: Polyhedron {
427    ///                         a: Matrix{
428    ///                             val: vec![1.0, 4.0, 3.0, 2.0],
429    ///                             nrows: 2,
430    ///                             ncols: 2
431    ///                         },
432    ///                         b: vec![4.0, 6.0],
433    ///                         variables: vec![ VariableFloat { id:0, bounds: (0.0,f64::MAX) }, VariableFloat { id: 1, bounds: (0.0,f64::MAX) }],
434    ///                         index: vec![Some(0),Some(1)],
435    ///                 },
436    ///                 eq_ph: Default::default(),
437    ///                 of: vec![-4.0, -5.0],
438    ///             }.solve();
439    /// assert_eq!(sol.z, -13);
440    /// assert_eq!(sol.x, vec![2, 1]);
441    /// assert_eq!(sol.status_code, 5);
442    /// ```
443    pub fn solve(&self) -> IntegerSolution {
444        solve_ilp(self)
445    }
446    
447}
448
449/// The revised simplex algorithm
450fn 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    //Initialization
479    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    //Iteration start
498    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            // Problem is unbounded
511            (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    // Unbounded
885    #[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    // Unsolvable
907    #[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    // Not feasible bfs
929    #[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}