Skip to content

Commit 71f7e8f

Browse files
committed
linear_programming: finish simplex implementation
1 parent 16b9fb0 commit 71f7e8f

1 file changed

Lines changed: 137 additions & 9 deletions

File tree

src/linear_programming/mod.rs

Lines changed: 137 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,44 @@
1+
use std::fmt;
2+
use std::usize;
3+
use std::iter;
4+
15
use mtl::array::{Array, ArrayType, concatenate};
26

37

48
/// Simplex solver
59
pub struct Simplex {
610
a: Array<f64>,
711
m: usize,
8-
n: usize
12+
n: usize,
13+
basis: Vec<usize>
14+
}
15+
16+
impl fmt::Display for Simplex {
17+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
18+
let (m, n) = (self.m, self.n);
19+
try!(writeln!(f, "M = {}", m));
20+
try!(writeln!(f, "N = {}", n));
21+
for i in 0 .. m+1 {
22+
for j in 0 .. m+n+1 {
23+
try!(write!(f, "{:7.2}", self.a[[i,j]]));
24+
}
25+
try!(writeln!(f, ""));
26+
}
27+
28+
try!(writeln!(f, "value = {}", self.value()));
29+
for i in 0 .. m {
30+
if self.basis[i] < n {
31+
try!(writeln!(f, "x_{} = {}", self.basis[i], self.a[[i,m+n]]));
32+
}
33+
}
34+
35+
Ok(())
36+
}
937
}
1038

1139

1240
impl Simplex {
41+
#[allow(non_snake_case)]
1342
pub fn new(A: Vec<Vec<f64>>, b: Vec<f64>, c: Vec<f64>) -> Simplex {
1443
let m = b.len(); // M constrains
1544
let n = c.len(); // N variables
@@ -24,15 +53,111 @@ impl Simplex {
2453
let c = Array::from_vec(c).reshape([1, n]);
2554

2655
let ashape = A.shape();
27-
let mut M = concatenate([concatenate([A, Array::eye(ashape[0]), b], 1),
28-
concatenate([c, Array::zeros([1, ashape[0] + 1])], 1)], 0);
56+
let M = concatenate([concatenate([A, Array::eye(ashape[0]), b], 1),
57+
concatenate([c, Array::zeros([1, ashape[0] + 1])], 1)], 0);
2958

30-
Simplex {
59+
let mut ret = Simplex {
3160
a: M,
3261
m: m,
33-
n: n
62+
n: n,
63+
basis: (0..m).map(|i| n+i).collect()
64+
};
65+
ret.solve();
66+
ret
67+
}
68+
69+
/// return optimal objective value
70+
pub fn value(&self) -> f64 {
71+
-self.a[[self.m, self.m+self.n]]
72+
}
73+
74+
/// primal solution vector
75+
pub fn primal(&self) -> Vec<f64> {
76+
let (m, n) = (self.m, self.n);
77+
let mut x = iter::repeat(0.0).take(n).collect::<Vec<f64>>();
78+
for i in 0 .. m {
79+
if self.basis[i] < n {
80+
x[self.basis[i]] = self.a[[i,m+n]];
81+
}
82+
}
83+
x
84+
}
85+
86+
pub fn dual(&self) -> Vec<f64> {
87+
let (m, n) = (self.m, self.n);
88+
let mut y = iter::repeat(0.0).take(m).collect::<Vec<f64>>();
89+
for i in 0 .. m {
90+
y[i] = -self.a[[m,n+1]];
3491
}
92+
y
3593
}
94+
95+
/// Bland's rule
96+
fn bland(&self) -> usize {
97+
let (m, n) = (self.m, self.n);
98+
for j in 0 .. m+n {
99+
if self.a[[m,j]] > 0.0 {
100+
return j;
101+
}
102+
}
103+
usize::MAX // optimal :)
104+
}
105+
106+
fn min_ratio_rule(&self, q: usize) -> usize {
107+
// leaving row
108+
let mut p = usize::MAX;
109+
let (m, n) = (self.m, self.n);
110+
for i in 0 .. self.m {
111+
// skip negative
112+
if self.a[[i,q]] <= 0.0 {
113+
continue;
114+
} else if p == usize::MAX {
115+
p = i
116+
} else if self.a[[i,m+n]] / self.a[[i,q]] < self.a[[p,m+n]] / self.a[[p,q]] {
117+
p = i
118+
}
119+
}
120+
p
121+
}
122+
123+
pub fn pivot(&mut self, p: usize, q: usize) {
124+
let (m, n) = (self.m, self.n);
125+
for i in 0 .. m+1 {
126+
for j in 0 .. m+n+1 {
127+
if i != p && j != q {
128+
self.a[[i,j]] -= self.a[[p,j]] * self.a[[i,q]] / self.a[[p,q]];
129+
}
130+
}
131+
}
132+
133+
// zero out column q
134+
for i in 0 .. m+1 {
135+
if i != p { self.a[[i,q]] = 0.0; }
136+
}
137+
138+
for j in 0 .. m+n+1 {
139+
if j != q { self.a[[p,j]] /= self.a[[p,q]] };
140+
}
141+
142+
self.a[[p,q]] = 1.0;
143+
}
144+
145+
pub fn solve(&mut self) {
146+
loop {
147+
let q = self.bland();
148+
if q == usize::MAX { break }
149+
150+
let p = self.min_ratio_rule(q);
151+
if p == usize::MAX {
152+
panic!("wrong in input question.")
153+
}
154+
155+
self.pivot(p, q);
156+
157+
self.basis[p] = q;
158+
}
159+
}
160+
36161
}
37162

38163

@@ -41,9 +166,9 @@ fn test_simplex_solve() {
41166
/*
42167
maximize: 13 * A + 23 * B
43168
sbject to:
44-
5 * A + 15 * B <= 480
45-
4 * A + 4 * B <= 160
46-
35 * A + 20 * B <= 1190
169+
5 * A + 15 * B <= 480
170+
4 * A + 4 * B <= 160
171+
35 * A + 20 * B <= 1190
47172
*/
48173
let simplex = Simplex::new(
49174
vec![
@@ -53,5 +178,8 @@ fn test_simplex_solve() {
53178
],
54179
vec![480.0, 160.0, 1190.0],
55180
vec![13.0, 23.0]
56-
);
181+
);
182+
println!("solve => \n{}", simplex);
183+
assert_eq!(simplex.value(), 800.0);
184+
57185
}

0 commit comments

Comments
 (0)