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
/*!
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 dual;
mod error;
mod primal;
pub mod problem;
pub mod solver;
mod standard_form;
mod util;

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