simplex 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -5
  3. data/lib/simplex.rb +14 -4
  4. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 653a4166c7a16f592147416d42e2a9e69aebc01d
4
- data.tar.gz: a023d7fd81dd5bb510ae19c6508415fdc9ab9935
3
+ metadata.gz: 64592aedc465c64468c423ca7457e55cf3323801
4
+ data.tar.gz: 26bb46274ff8e2d27357757e53085a3e34b21812
5
5
  SHA512:
6
- metadata.gz: df013865a60100ab6056ef9df8699e2f729aa8e9778650fc33e401cfddcf3100307548c72d273c606f37ea1d7b7e7b463f6d347dd279a7bc31999cabd69633de
7
- data.tar.gz: 9e77d9f2623751bd64c8370b1477c9cce6bc54a8ee7adb2a9c506935db613f4d1fe68108ef0c227772acc78ff8455c70ba5d4786a088cd16bb16102954b0ebed
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
- result = Simplex.new(
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
- ).solution
40
- # => [(5/3), (2/3)]
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.
@@ -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 or a < 0) and !(b < 0 and a < 0) # negative sign check
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
- pivot_column = entering_variable
141
- pivot_row = pivot_row(pivot_column)
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
- a[pivot_row][pivot_column] = "*" + a[pivot_row][pivot_column]
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.1.0
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-20 00:00:00.000000000 Z
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.0.14
42
+ rubygems_version: 2.1.11
43
43
  signing_key:
44
44
  specification_version: 4
45
45
  summary: Simplex linear programming solver