simplex 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +31 -5
- data/lib/simplex.rb +14 -4
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64592aedc465c64468c423ca7457e55cf3323801
|
4
|
+
data.tar.gz: 26bb46274ff8e2d27357757e53085a3e34b21812
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5ea39cb79dce8ac5a939b74b89324aa35abd92eed9b2430db0d5f7e9f0b30aad2234028f5defffb471f73a226226971d36984c119d7dc05cb0f2477f4b586a4
|
7
|
+
data.tar.gz: ab7652f11233b742687b7a4975695901d8bc61bea5ba2dfb003e2d4803cede9c5a05a3d11aff2e52788a77ba291d256d8cd360192ab773eae7219e7c4c957f0c
|
data/README.md
CHANGED
@@ -6,15 +6,19 @@ simplex
|
|
6
6
|
|
7
7
|
A naive pure-Ruby implementation of the Simplex algorithm for solving linear programming problems. Solves maximizations in standard form.
|
8
8
|
|
9
|
+
### Changes
|
10
|
+
|
11
|
+
**1.2**: Raises `Simplex::UnboundedProblem` if the problem is unbounded.
|
12
|
+
|
9
13
|
### Why?
|
10
14
|
|
11
15
|
I wrote this because I needed to solve some small allocation problems for a web game I'm writing,
|
12
16
|
and there didn't seem to be any Ruby 2.0 bindings for the "pro" solver libraries,
|
13
17
|
and anyway they are hard to install on Heroku.
|
14
18
|
|
15
|
-
* *Use it for*: small LP problems, when you have trouble loading native or Java solvers,
|
19
|
+
* *Use it for*: small LP problems, with feasible origins, when you have trouble loading native or Java solvers,
|
16
20
|
and when you can accept not that great performance.
|
17
|
-
* *Don't use it for*: large LP problems, when you have access to native solvers, when you need very fast solving time.
|
21
|
+
* *Don't use it for*: large LP problems, problems with infeasible origins,when you have access to native solvers, when you need very fast solving time.
|
18
22
|
|
19
23
|
### Usage
|
20
24
|
|
@@ -29,13 +33,35 @@ To solve the linear programming problem:
|
|
29
33
|
|
30
34
|
Like this:
|
31
35
|
|
32
|
-
|
36
|
+
> simplex = Simplex.new(
|
33
37
|
[1, 1], # coefficients of objective function
|
34
38
|
[ # matrix of inequality coefficients on the lhs ...
|
35
39
|
[ 2, 1],
|
36
40
|
[ 1, 2],
|
37
41
|
],
|
38
42
|
[4, 3] # .. and the rhs of the inequalities
|
39
|
-
)
|
40
|
-
|
43
|
+
)
|
44
|
+
> simplex.solution
|
45
|
+
=> [(5/3), (2/3)]
|
46
|
+
|
47
|
+
You can manually iterate the algorithm, and review the tableau at each step. For instance:
|
48
|
+
|
49
|
+
> simplex = Simplex.new([1, 1], [[2, 1], [1, 2]], [4, 3])
|
50
|
+
> puts simplex.formatted_tableau
|
51
|
+
-1.000 -1.000 0.000 0.000
|
52
|
+
----------------------------------------------
|
53
|
+
*2.000 1.000 1.000 0.000 | 4.000
|
54
|
+
1.000 2.000 0.000 1.000 | 3.000
|
55
|
+
|
56
|
+
> simplex.can_improve?
|
57
|
+
=> true
|
58
|
+
> simplex.pivot
|
59
|
+
=> [0, 3]
|
60
|
+
|
61
|
+
> puts simplex.formatted_tableau
|
62
|
+
0.000 -0.500 0.500 0.000
|
63
|
+
----------------------------------------------
|
64
|
+
1.000 0.500 0.500 0.000 | 2.000
|
65
|
+
0.000 *1.500 -0.500 1.000 | 1.000
|
41
66
|
|
67
|
+
The asterisk indicates what will be the pivot row and column for the next pivot.
|
data/lib/simplex.rb
CHANGED
@@ -7,6 +7,9 @@ end
|
|
7
7
|
class Simplex
|
8
8
|
DEFAULT_MAX_PIVOTS = 10_000
|
9
9
|
|
10
|
+
class UnboundedProblem < StandardError
|
11
|
+
end
|
12
|
+
|
10
13
|
attr_accessor :max_pivots
|
11
14
|
|
12
15
|
def initialize(c, a, b)
|
@@ -79,6 +82,7 @@ class Simplex
|
|
79
82
|
def pivot
|
80
83
|
pivot_column = entering_variable
|
81
84
|
pivot_row = pivot_row(pivot_column)
|
85
|
+
raise UnboundedProblem unless pivot_row
|
82
86
|
leaving_var = basic_variable_in_row(pivot_row)
|
83
87
|
replace_basic_variable(leaving_var => pivot_column)
|
84
88
|
|
@@ -114,7 +118,7 @@ class Simplex
|
|
114
118
|
}.reject { |_, a, b|
|
115
119
|
a == 0
|
116
120
|
}.reject { |_, a, b|
|
117
|
-
(b < 0
|
121
|
+
(b < 0) ^ (a < 0) # negative sign check
|
118
122
|
}
|
119
123
|
row_ix, _, _ = *last_min_by(row_ix_a_and_b) { |_, a, b|
|
120
124
|
Rational(b, a)
|
@@ -137,13 +141,19 @@ class Simplex
|
|
137
141
|
end
|
138
142
|
|
139
143
|
def formatted_tableau
|
140
|
-
|
141
|
-
|
144
|
+
if can_improve?
|
145
|
+
pivot_column = entering_variable
|
146
|
+
pivot_row = pivot_row(pivot_column)
|
147
|
+
else
|
148
|
+
pivot_row = nil
|
149
|
+
end
|
142
150
|
num_cols = @c.size + 1
|
143
151
|
c = formatted_values(@c.to_a)
|
144
152
|
b = formatted_values(@b.to_a)
|
145
153
|
a = @a.to_a.map {|ar| formatted_values(ar.to_a) }
|
146
|
-
|
154
|
+
if pivot_row
|
155
|
+
a[pivot_row][pivot_column] = "*" + a[pivot_row][pivot_column]
|
156
|
+
end
|
147
157
|
max = (c + b + a + ["1234567"]).flatten.map(&:size).max
|
148
158
|
result = []
|
149
159
|
result << c.map {|c| c.rjust(max, " ") }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simplex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Lucraft
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-12-
|
11
|
+
date: 2013-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Naive implementation of the simplex linear programming algorithm in pure
|
14
14
|
Ruby.
|
@@ -39,7 +39,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
39
39
|
version: '0'
|
40
40
|
requirements: []
|
41
41
|
rubyforge_project:
|
42
|
-
rubygems_version: 2.
|
42
|
+
rubygems_version: 2.1.11
|
43
43
|
signing_key:
|
44
44
|
specification_version: 4
|
45
45
|
summary: Simplex linear programming solver
|