ellp

Linear programming library that provides primal and dual simplex solvers

4 releases

 0.2.0 Dec 26, 2022 Jun 26, 2021 Jun 11, 2021 Jun 10, 2021

#564 in Math

95KB
2.5K SLoC

ellp

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.

``````use ellp::*;

let mut prob = Problem::new();

let x1 = prob
.unwrap();

let x2 = prob
.unwrap();

let x3 = prob
.unwrap();

let x4 = prob
.unwrap();

let x5 = prob
.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

``````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.

Development priorities

• clean up the code, add proper logging
• performance improvements (LU factorization update, steepest edge)
• add benchmarks and test problems, and document how to run them (and how to run all tests)
• switch to sparse matrices (perhaps make it optional)
• make a binary that solves problems given by mps files

Various notes

• problems in MPS format taken from https://netlib.org/lp/
• can run them with `cargo test --features benchmarks`

~3.5MB
~75K SLoC