simplex 1.0.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 +7 -0
- data/lib/simplex.rb +137 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 607708dc2b1019f3de26f43a8f714d7ba18a1d27
|
4
|
+
data.tar.gz: e05193d59e5237b419560bdb8aa65add6894697e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 57ee4659de8ec4e8660bcc38b412fdd636f300903def27a9b13b1b5baed75a84ead979fb8f7bb84d297dbd17b0c2f8fd0ccfe664463460435a3039ed2b06fc95
|
7
|
+
data.tar.gz: 4915382d169cd3e9743ef3bba31f94ef2c3d89c6862d0849f361689435d1984b3ffeb9b118f8a983ee5d4af24668098452af29cd78a1dcfbbdcf957019963320
|
data/lib/simplex.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'matrix'
|
2
|
+
|
3
|
+
class Matrix
|
4
|
+
def []=(i, j, x)
|
5
|
+
@rows[i][j] = x
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class Vector
|
10
|
+
public :[]=
|
11
|
+
end
|
12
|
+
|
13
|
+
class Simplex
|
14
|
+
DEFAULT_MAX_ITERATIONS = 1_000_000
|
15
|
+
attr_accessor :max_iterations
|
16
|
+
|
17
|
+
def initialize(c, a, b)
|
18
|
+
@max_iterations = DEFAULT_MAX_ITERATIONS
|
19
|
+
# Problem dimensions
|
20
|
+
@num_non_slack_vars = a.first.length
|
21
|
+
@num_constraints = b.length
|
22
|
+
@num_vars = @num_non_slack_vars + @num_constraints
|
23
|
+
@x = Array.new(@num_vars)
|
24
|
+
|
25
|
+
# Set up initial matrix A and vectors b, c
|
26
|
+
@c = Vector[*c.map {|c1| -1*c1 } + [0]*@num_constraints]
|
27
|
+
@a = Matrix[*a.map {|a1| a1.clone + [0]*@num_constraints}]
|
28
|
+
@b = Vector[*b.clone]
|
29
|
+
0.upto(@num_constraints - 1) {|i| @a[i, @num_non_slack_vars + i] = 1 }
|
30
|
+
|
31
|
+
@basic_vars = ((@num_non_slack_vars)...(@num_vars)).to_a
|
32
|
+
|
33
|
+
# set initial solution: all non-slack variables = 0
|
34
|
+
update_solution
|
35
|
+
@solved = false
|
36
|
+
end
|
37
|
+
|
38
|
+
def solve
|
39
|
+
return if @solved
|
40
|
+
i = 0
|
41
|
+
while can_improve? and i < @max_iterations
|
42
|
+
i += 1
|
43
|
+
pivot_column = entering_variable_ix
|
44
|
+
pivot_row = minimum_coefficient_ratio_row_ix(pivot_column)
|
45
|
+
leaving_var = leaving_variable(pivot_row)
|
46
|
+
@basic_vars.delete(leaving_var)
|
47
|
+
|
48
|
+
# update objective
|
49
|
+
c_ratio = Rational(@c[pivot_column], @a[pivot_row, pivot_column])
|
50
|
+
@c = @c - (@a.row(pivot_row)*c_ratio)
|
51
|
+
|
52
|
+
# update pivot row
|
53
|
+
ratio = Rational(1, @a[pivot_row, pivot_column])
|
54
|
+
0.upto(@a.column_count - 1) do |column_ix|
|
55
|
+
@a[pivot_row, column_ix] = ratio * @a[pivot_row, column_ix]
|
56
|
+
end
|
57
|
+
@b[pivot_row] = ratio * @b[pivot_row]
|
58
|
+
|
59
|
+
# update A and B
|
60
|
+
0.upto(@a.row_count - 1) do |row_ix|
|
61
|
+
next if row_ix == pivot_row
|
62
|
+
ratio = @a[row_ix, pivot_column]
|
63
|
+
0.upto(@a.column_count - 1) do |column_ix|
|
64
|
+
@a[row_ix, column_ix] = @a[row_ix, column_ix] - ratio*@a[pivot_row, column_ix]
|
65
|
+
end
|
66
|
+
@b[row_ix] = @b[row_ix] - ratio*@b[pivot_row]
|
67
|
+
end
|
68
|
+
|
69
|
+
@basic_vars << pivot_column
|
70
|
+
@basic_vars.sort!
|
71
|
+
update_solution
|
72
|
+
end
|
73
|
+
@solved = true
|
74
|
+
end
|
75
|
+
|
76
|
+
def update_solution
|
77
|
+
0.upto(@num_vars - 1) {|i| @x[i] = 0 }
|
78
|
+
@basic_vars.each do |basic_var|
|
79
|
+
row_coeff_1 = nil
|
80
|
+
0.upto(@a.row_count - 1) do |row_ix|
|
81
|
+
coeff = @a[row_ix, basic_var]
|
82
|
+
if coeff == 1
|
83
|
+
if row_coeff_1 == nil
|
84
|
+
row_coeff_1 = row_ix
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
@x[basic_var] = @b[row_coeff_1]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def solution
|
93
|
+
solve
|
94
|
+
@x.to_a[0...@num_non_slack_vars]
|
95
|
+
end
|
96
|
+
|
97
|
+
def can_improve?
|
98
|
+
!!entering_variable_ix
|
99
|
+
end
|
100
|
+
|
101
|
+
def entering_variable_ix
|
102
|
+
current_min_value = nil
|
103
|
+
current_min_index = nil
|
104
|
+
@c.each_with_index do |v, i|
|
105
|
+
if v < 0
|
106
|
+
if current_min_value == nil || v <= current_min_value
|
107
|
+
current_min_value = v
|
108
|
+
current_min_index = i
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
current_min_index
|
113
|
+
end
|
114
|
+
|
115
|
+
def leaving_variable(pivot_row)
|
116
|
+
0.upto(@a.column_count - 1) do |column_ix|
|
117
|
+
if @a[pivot_row, column_ix] == 1 and @basic_vars.include?(column_ix)
|
118
|
+
return column_ix
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def minimum_coefficient_ratio_row_ix(column_ix)
|
124
|
+
current_min_value = nil
|
125
|
+
current_min_index = nil
|
126
|
+
0.upto(@a.row_count - 1) do |row_ix|
|
127
|
+
next if @a[row_ix, column_ix] == 0
|
128
|
+
ratio = Rational(@b[row_ix], @a[row_ix, column_ix])
|
129
|
+
if ratio > 0 && (!current_min_value || ratio < current_min_value)
|
130
|
+
current_min_value = ratio
|
131
|
+
current_min_index = row_ix
|
132
|
+
end
|
133
|
+
end
|
134
|
+
return current_min_index
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simplex
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Lucraft
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-09-15 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Naive implementation of the simplex linear programming algorithm in pure
|
14
|
+
Ruby.
|
15
|
+
email: dan@fluentradical.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/simplex.rb
|
21
|
+
homepage:
|
22
|
+
licenses: []
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubyforge_project:
|
40
|
+
rubygems_version: 2.0.6
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: Simplex linear programming solver
|
44
|
+
test_files: []
|