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
121
122
123
124
125
126
127
128
129
/*!
Linear programming library that provides primal and dual simplex solvers. Both solvers are currently working for a small set of test problems. This library is an *early work-in-progress*.

## Examples

Here is example code that sets up a linear program, and then solves it with both the primal and dual simplex solvers.

First we setup the problem


```
use ellp::*;

let mut prob = Problem::new();

let x1 = prob
    .add_var(2., Bound::TwoSided(-1., 1.), Some("x1".to_string()))
    .unwrap();

let x2 = prob
    .add_var(10., Bound::Upper(6.), Some("x2".to_string()))
    .unwrap();

let x3 = prob
    .add_var(0., Bound::Lower(0.), Some("x3".to_string()))
    .unwrap();

let x4 = prob
    .add_var(1., Bound::Fixed(0.), Some("x4".to_string()))
    .unwrap();

let x5 = prob
    .add_var(0., Bound::Free, Some("x5".to_string()))
    .unwrap();

prob.add_constraint(vec![(x1, 2.5), (x2, 3.5)], ConstraintOp::Gte, 5.)
    .unwrap();

prob.add_constraint(vec![(x2, 2.5), (x1, 4.5)], ConstraintOp::Lte, 1.)
    .unwrap();

prob.add_constraint(vec![(x3, -1.), (x4, -3.), (x5, -4.)], ConstraintOp::Eq, 2.)
    .unwrap();

println!("{}", prob);

let primal_solver = PrimalSimplexSolver::default();
let dual_solver = DualSimplexSolver::default();

let primal_result = primal_solver.solve(prob.clone()).unwrap();
let dual_result = dual_solver.solve(prob).unwrap();

if let SolverResult::Optimal(sol) = primal_result {
    println!("primal obj: {}", sol.obj());
    println!("primal opt point: {}", sol.x());
} else {
    panic!("should have an optimal point");
}

if let SolverResult::Optimal(sol) = dual_result {
    println!("dual obj: {}", sol.obj());
    println!("dual opt point: {}", sol.x());
} else {
    panic!("should have an optimal point");
}
```

The output is
```console
minimize
+ 2 x1 + 10 x2 + 1 x4

subject to
+ 2.5 x1 + 3.5 x2 ≥ 5
+ 2.5 x2 + 4.5 x1 ≤ 1
- 1 x3 - 3 x4 - 4 x5 = 2

with the bounds
-1 ≤ x1 ≤ 1
x2 ≤ 6
x3 ≥ 0
x4 = 0
x5 free

primal obj: 19.157894736842103
primal opt point:
  ┌                     ┐
  │ -0.9473684210526313 │
  │  2.1052631578947367 │
  │                   0 │
  │                   0 │
  │                -0.5 │
  └                     ┘

dual obj: 19.157894736842103
dual opt point:
  ┌                     ┐
  │ -0.9473684210526313 │
  │  2.1052631578947367 │
  │                   0 │
  │                   0 │
  │                -0.5 │
  └                     ┘
```

If the problem is infeasible or unbounded, then `solve` will return [`SolverResult::Infeasible`] or [`SolverResult::Unbounded`], respectively.
*/

mod error;
pub mod problem;
pub mod solver;
mod solvers;
mod standard_form;
mod util;

#[cfg(feature = "mps")]
mod parse_mps;

#[cfg(feature = "mps")]
pub use parse_mps::parse_mps;

#[cfg(feature = "mps")]
pub use parse_mps::MpsParsingError;

pub use crate::error::EllPError;
pub use crate::problem::{Bound, Constraint, ConstraintOp, Problem, Variable};
pub use crate::solver::{EllPResult, SolverResult};
pub use crate::solvers::dual::dual_simplex_solver::DualSimplexSolver;
pub use crate::solvers::primal::primal_simplex_solver::PrimalSimplexSolver;