rglpk 0.1.1 → 0.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.
- data/.gitignore +17 -0
- data/ChangeLog.md +13 -0
- data/README.md +99 -0
- data/Rakefile +69 -0
- data/VERSION +1 -0
- data/ext/extconf.rb +1 -1
- data/ext/{rglpk.c → glpk_wrapper.c} +9979 -4362
- data/lib/rglpk.rb +378 -0
- data/rglpk.gemspec +67 -0
- data/swig/Makefile.in +2 -2
- data/swig/glpk.i +2 -1
- data/test/helper.rb +3 -0
- data/test/test_all.rb +5 -187
- data/test/test_basic.rb +186 -0
- data/test/test_brief_example.rb +56 -0
- data/test/test_problem_kind.rb +81 -0
- metadata +55 -25
- data/History.txt +0 -7
- data/Manifest.txt +0 -12
- data/README.txt +0 -45
- data/Rakefile.rb +0 -50
- data/lib/glpk.rb +0 -320
data/lib/rglpk.rb
ADDED
@@ -0,0 +1,378 @@
|
|
1
|
+
require 'glpk_wrapper'
|
2
|
+
|
3
|
+
module Rglpk
|
4
|
+
Glpk_wrapper.constants.each do |c|
|
5
|
+
v = Glpk_wrapper.const_get(c)
|
6
|
+
self.const_set(c, v) if v.kind_of? Numeric
|
7
|
+
end
|
8
|
+
TypeConstants = [GLP_FR, GLP_LO, GLP_UP, GLP_DB, GLP_FX]
|
9
|
+
|
10
|
+
class RowColArray
|
11
|
+
include Enumerable
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@array = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def size
|
18
|
+
@array.size
|
19
|
+
end
|
20
|
+
|
21
|
+
def each(&block)
|
22
|
+
@array.each(&block)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def [](i)
|
27
|
+
if i.kind_of?(Numeric)
|
28
|
+
@array[i]
|
29
|
+
elsif i.kind_of?(String)
|
30
|
+
raise RuntimeError if self[1].nil?
|
31
|
+
idx = Glpk_wrapper.send(glp_find_method, self[1].p.lp, i)
|
32
|
+
raise ArgumentError if idx == 0
|
33
|
+
@array[idx - 1]
|
34
|
+
else
|
35
|
+
raise ArgumentError
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def push(rc)
|
42
|
+
@array << rc
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete_at(index)
|
46
|
+
@array.delete_at(index)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class RowArray < RowColArray
|
51
|
+
protected
|
52
|
+
def glp_find_method
|
53
|
+
:glp_find_row
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class ColArray < RowColArray
|
58
|
+
protected
|
59
|
+
def glp_find_method
|
60
|
+
:glp_find_col
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Problem
|
65
|
+
attr_accessor :rows, :cols, :obj, :lp
|
66
|
+
|
67
|
+
def initialize
|
68
|
+
@lp = Glpk_wrapper.glp_create_prob
|
69
|
+
@obj = ObjectiveFunction.new(self)
|
70
|
+
@rows = RowArray.new
|
71
|
+
@cols = ColArray.new
|
72
|
+
Glpk_wrapper.glp_create_index(@lp)
|
73
|
+
@status = nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def name=(n)
|
77
|
+
Glpk_wrapper.glp_set_prob_name(@lp, n)
|
78
|
+
end
|
79
|
+
|
80
|
+
def name
|
81
|
+
Glpk_wrapper.glp_get_prob_name(@lp)
|
82
|
+
end
|
83
|
+
|
84
|
+
def nz
|
85
|
+
Glpk_wrapper.glp_get_num_nz(@lp)
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_rows(n)
|
89
|
+
Glpk_wrapper.glp_add_rows(@lp, n)
|
90
|
+
s = @rows.size
|
91
|
+
n.times{|i| @rows.send(:push, Row.new(self, s + i + 1))}
|
92
|
+
@rows
|
93
|
+
end
|
94
|
+
|
95
|
+
def add_cols(n)
|
96
|
+
Glpk_wrapper.glp_add_cols(@lp, n)
|
97
|
+
s = @cols.size
|
98
|
+
n.times{|i| @cols.send(:push, Column.new(self, s + i + 1))}
|
99
|
+
@cols
|
100
|
+
end
|
101
|
+
|
102
|
+
def del_rows(a)
|
103
|
+
# Ensure the array of rows to delete is sorted and unique.
|
104
|
+
a = a.sort.uniq
|
105
|
+
|
106
|
+
r = Glpk_wrapper.new_intArray(a.size + 1)
|
107
|
+
a.each_with_index{|n, i| Glpk_wrapper.intArray_setitem(r, i + 1, n)}
|
108
|
+
Glpk_wrapper.glp_del_rows(@lp, a.size, r)
|
109
|
+
|
110
|
+
a.each do |n|
|
111
|
+
@rows.send(:delete_at, n)
|
112
|
+
a.each_with_index do |nn, i|
|
113
|
+
a[i] -= 1
|
114
|
+
end
|
115
|
+
end
|
116
|
+
@rows.each_with_index{|r, i| r.i = i + 1}
|
117
|
+
a
|
118
|
+
end
|
119
|
+
|
120
|
+
def del_cols(a)
|
121
|
+
# Ensure the array of rows tro delete is sorted and unique.
|
122
|
+
a = a.sort.uniq
|
123
|
+
|
124
|
+
r = Glpk_wrapper.new_intArray(a.size + 1)
|
125
|
+
a.each_with_index{|n, i| Glpk_wrapper.intArray_setitem(r, i + 1, n)}
|
126
|
+
Glpk_wrapper.glp_del_cols(@lp, a.size, r)
|
127
|
+
|
128
|
+
a.each do |n|
|
129
|
+
@cols.send(:delete_at, n)
|
130
|
+
a.each_with_index do |nn, i|
|
131
|
+
a[i] -= 1
|
132
|
+
end
|
133
|
+
end
|
134
|
+
@cols.each_with_index{|c, i| c.j = i + 1}
|
135
|
+
a
|
136
|
+
end
|
137
|
+
|
138
|
+
def set_matrix(v)
|
139
|
+
nc = Glpk_wrapper.glp_get_num_cols(@lp)
|
140
|
+
|
141
|
+
ia = Glpk_wrapper.new_intArray(v.size + 1)
|
142
|
+
ja = Glpk_wrapper.new_intArray(v.size + 1)
|
143
|
+
ar = Glpk_wrapper.new_doubleArray(v.size + 1)
|
144
|
+
|
145
|
+
v.each_with_index do |x, y|
|
146
|
+
rn = (y + nc) / nc
|
147
|
+
cn = (y % nc) + 1
|
148
|
+
|
149
|
+
Glpk_wrapper.intArray_setitem(ia, y + 1, rn)
|
150
|
+
Glpk_wrapper.intArray_setitem(ja, y + 1, cn)
|
151
|
+
Glpk_wrapper.doubleArray_setitem(ar, y + 1, x)
|
152
|
+
end
|
153
|
+
|
154
|
+
Glpk_wrapper.glp_load_matrix(@lp, v.size, ia, ja, ar)
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
def apply_options_to_parm(options, parm)
|
160
|
+
options.each do |k, v|
|
161
|
+
begin
|
162
|
+
parm.send("#{k}=".to_sym, v)
|
163
|
+
rescue NoMethodError
|
164
|
+
raise ArgumentError, "Unrecognised option: #{k}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
public
|
170
|
+
|
171
|
+
def simplex(options = {})
|
172
|
+
parm = Glpk_wrapper::Glp_smcp.new
|
173
|
+
Glpk_wrapper.glp_init_smcp(parm)
|
174
|
+
|
175
|
+
# Default to errors only temrinal output.
|
176
|
+
parm.msg_lev = GLP_MSG_ERR
|
177
|
+
|
178
|
+
apply_options_to_parm(options, parm)
|
179
|
+
Glpk_wrapper.glp_simplex(@lp, parm)
|
180
|
+
end
|
181
|
+
|
182
|
+
def mip(options = {})
|
183
|
+
parm = Glpk_wrapper::Glp_iocp.new
|
184
|
+
Glpk_wrapper.glp_init_iocp(parm)
|
185
|
+
|
186
|
+
# Default to errors only temrinal output.
|
187
|
+
parm.msg_lev = GLP_MSG_ERR
|
188
|
+
|
189
|
+
apply_options_to_parm(options, parm)
|
190
|
+
Glpk_wrapper.glp_intopt(@lp, parm)
|
191
|
+
end
|
192
|
+
|
193
|
+
def status
|
194
|
+
Glpk_wrapper.glp_get_status(@lp)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
class Row
|
199
|
+
attr_accessor :i, :p
|
200
|
+
|
201
|
+
def initialize(problem, i)
|
202
|
+
@p = problem
|
203
|
+
@i = i
|
204
|
+
end
|
205
|
+
|
206
|
+
def name=(n)
|
207
|
+
Glpk_wrapper.glp_set_row_name(@p.lp, @i, n)
|
208
|
+
end
|
209
|
+
|
210
|
+
def name
|
211
|
+
Glpk_wrapper.glp_get_row_name(@p.lp, @i)
|
212
|
+
end
|
213
|
+
|
214
|
+
def set_bounds(type, lb, ub)
|
215
|
+
raise ArgumentError unless TypeConstants.include?(type)
|
216
|
+
lb = 0.0 if lb.nil?
|
217
|
+
ub = 0.0 if ub.nil?
|
218
|
+
Glpk_wrapper.glp_set_row_bnds(@p.lp, @i, type, lb.to_f, ub.to_f)
|
219
|
+
end
|
220
|
+
|
221
|
+
def bounds
|
222
|
+
t = Glpk_wrapper.glp_get_row_type(@p.lp, @i)
|
223
|
+
lb = Glpk_wrapper.glp_get_row_lb(@p.lp, @i)
|
224
|
+
ub = Glpk_wrapper.glp_get_row_ub(@p.lp, @i)
|
225
|
+
|
226
|
+
lb = (t == GLP_FR or t == GLP_UP) ? nil : lb
|
227
|
+
ub = (t == GLP_FR or t == GLP_LO) ? nil : ub
|
228
|
+
|
229
|
+
[t, lb, ub]
|
230
|
+
end
|
231
|
+
|
232
|
+
def set(v)
|
233
|
+
raise RuntimeError unless v.size == @p.cols.size
|
234
|
+
ind = Glpk_wrapper.new_intArray(v.size + 1)
|
235
|
+
val = Glpk_wrapper.new_doubleArray(v.size + 1)
|
236
|
+
|
237
|
+
1.upto(v.size){|x| Glpk_wrapper.intArray_setitem(ind, x, x)}
|
238
|
+
v.each_with_index{|x, y|
|
239
|
+
Glpk_wrapper.doubleArray_setitem(val, y + 1, x)}
|
240
|
+
|
241
|
+
Glpk_wrapper.glp_set_mat_row(@p.lp, @i, v.size, ind, val)
|
242
|
+
end
|
243
|
+
|
244
|
+
def get
|
245
|
+
ind = Glpk_wrapper.new_intArray(@p.cols.size + 1)
|
246
|
+
val = Glpk_wrapper.new_doubleArray(@p.cols.size + 1)
|
247
|
+
len = Glpk_wrapper.glp_get_mat_row(@p.lp, @i, ind, val)
|
248
|
+
row = Array.new(@p.cols.size, 0)
|
249
|
+
len.times do |i|
|
250
|
+
v = Glpk_wrapper.doubleArray_getitem(val, i + 1)
|
251
|
+
j = Glpk_wrapper.intArray_getitem(ind, i + 1)
|
252
|
+
row[j - 1] = v
|
253
|
+
end
|
254
|
+
row
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
class Column
|
259
|
+
attr_accessor :j, :p
|
260
|
+
|
261
|
+
def initialize(problem, i)
|
262
|
+
@p = problem
|
263
|
+
@j = i
|
264
|
+
end
|
265
|
+
|
266
|
+
def name=(n)
|
267
|
+
Glpk_wrapper.glp_set_col_name(@p.lp, @j, n)
|
268
|
+
end
|
269
|
+
|
270
|
+
def name
|
271
|
+
Glpk_wrapper.glp_get_col_name(@p.lp, @j)
|
272
|
+
end
|
273
|
+
|
274
|
+
def kind=(kind)
|
275
|
+
Glpk_wrapper.glp_set_col_kind(@p.lp, j, kind)
|
276
|
+
end
|
277
|
+
|
278
|
+
def kind
|
279
|
+
Glpk_wrapper.glp_get_col_kind(@p.lp, @j)
|
280
|
+
end
|
281
|
+
|
282
|
+
def set_bounds(type, lb, ub)
|
283
|
+
raise ArgumentError unless TypeConstants.include?(type)
|
284
|
+
lb = 0.0 if lb.nil?
|
285
|
+
ub = 0.0 if ub.nil?
|
286
|
+
Glpk_wrapper.glp_set_col_bnds(@p.lp, @j, type, lb, ub)
|
287
|
+
end
|
288
|
+
|
289
|
+
def bounds
|
290
|
+
t = Glpk_wrapper.glp_get_col_type(@p.lp, @j)
|
291
|
+
lb = Glpk_wrapper.glp_get_col_lb(@p.lp, @j)
|
292
|
+
ub = Glpk_wrapper.glp_get_col_ub(@p.lp, @j)
|
293
|
+
|
294
|
+
lb = (t == GLP_FR or t == GLP_UP) ? nil : lb
|
295
|
+
ub = (t == GLP_FR or t == GLP_LO) ? nil : ub
|
296
|
+
|
297
|
+
[t, lb, ub]
|
298
|
+
end
|
299
|
+
|
300
|
+
def set(v)
|
301
|
+
raise RuntimeError unless v.size == @p.rows.size
|
302
|
+
ind = Glpk_wrapper.new_intArray(v.size + 1)
|
303
|
+
val = Glpk_wrapper.new_doubleArray(v.size + 1)
|
304
|
+
|
305
|
+
1.upto(v.size){|x| Glpk_wrapper.intArray_setitem(ind, x, x)}
|
306
|
+
v.each_with_index{|x, y|
|
307
|
+
Glpk_wrapper.doubleArray_setitem(val, y + 1, x)}
|
308
|
+
|
309
|
+
Glpk_wrapper.glp_set_mat_col(@p.lp, @j, v.size, ind, val)
|
310
|
+
end
|
311
|
+
|
312
|
+
def get
|
313
|
+
ind = Glpk_wrapper.new_intArray(@p.rows.size + 1)
|
314
|
+
val = Glpk_wrapper.new_doubleArray(@p.rows.size + 1)
|
315
|
+
len = Glpk_wrapper.glp_get_mat_col(@p.lp, @j, ind, val)
|
316
|
+
col = Array.new(@p.rows.size, 0)
|
317
|
+
len.times do |i|
|
318
|
+
v = Glpk_wrapper.doubleArray_getitem(val, i + 1)
|
319
|
+
j = Glpk_wrapper.intArray_getitem(ind, i + 1)
|
320
|
+
col[j - 1] = v
|
321
|
+
end
|
322
|
+
col
|
323
|
+
end
|
324
|
+
|
325
|
+
def get_prim
|
326
|
+
Glpk_wrapper.glp_get_col_prim(@p.lp, @j)
|
327
|
+
end
|
328
|
+
|
329
|
+
def mip_val
|
330
|
+
Glpk_wrapper.glp_mip_col_val(@p.lp, @j)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
class ObjectiveFunction
|
335
|
+
|
336
|
+
def initialize(problem)
|
337
|
+
@p = problem
|
338
|
+
end
|
339
|
+
|
340
|
+
def name=(n)
|
341
|
+
Glpk_wrapper.glp_set_obj_name(@p.lp, n)
|
342
|
+
end
|
343
|
+
|
344
|
+
def name
|
345
|
+
Glpk_wrapper.glp_get_obj_name(@p.lp)
|
346
|
+
end
|
347
|
+
|
348
|
+
def dir=(d)
|
349
|
+
raise ArgumentError if d != GLP_MIN and d != GLP_MAX
|
350
|
+
Glpk_wrapper.glp_set_obj_dir(@p.lp, d)
|
351
|
+
end
|
352
|
+
|
353
|
+
def dir
|
354
|
+
Glpk_wrapper.glp_get_obj_dir(@p.lp)
|
355
|
+
end
|
356
|
+
|
357
|
+
def set_coef(j, coef)
|
358
|
+
Glpk_wrapper.glp_set_obj_coef(@p.lp, j, coef)
|
359
|
+
end
|
360
|
+
|
361
|
+
def coefs=(a)
|
362
|
+
@p.cols.each{|c| Glpk_wrapper.glp_set_obj_coef(@p.lp, c.j, a[c.j - 1])}
|
363
|
+
a
|
364
|
+
end
|
365
|
+
|
366
|
+
def coefs
|
367
|
+
@p.cols.map{|c| Glpk_wrapper.glp_get_obj_coef(@p.lp, c.j)}
|
368
|
+
end
|
369
|
+
|
370
|
+
def get
|
371
|
+
Glpk_wrapper.glp_get_obj_val(@p.lp)
|
372
|
+
end
|
373
|
+
|
374
|
+
def mip
|
375
|
+
Glpk_wrapper.glp_mip_obj_val(@p.lp)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
data/rglpk.gemspec
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{rglpk}
|
8
|
+
s.version = "0.2.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Alex Gutteridge", "William Taysom"]
|
12
|
+
s.date = %q{2010-10-13}
|
13
|
+
s.description = %q{Rglpk is a package providing a Ruby wrapper to the [GNU GLPK](http://www.gnu.org/software/glpk/) library. The GLPK (GNU Linear Programming Kit) package is intended for solving large-scale linear programming (LP), mixed integer programming (MIP), and other related problems.
|
14
|
+
|
15
|
+
Rglpk (pronounced as "wriggle-pick") is currently in alpha status and the API should be considered subject to change. Rglpk uses [Swig](http://www.swig.org/) to initially wrap the C GLPK library (using a Swig wrapper originally developed by Nigel Galloway) and then a pure Ruby library to wrap the Swig code in a more friendly OO-style.
|
16
|
+
|
17
|
+
All bug reports, feature requests and patches are welcome. Please email alexg (at) kuicr.kyoto-u.ac.jp or use the [rubyforge forums](http://rubyforge.org/forum/?group_id=3943).}
|
18
|
+
s.email = ["alexg@kuicr.kyoto-u.ac.jp", "wtaysom@gmail.com"]
|
19
|
+
s.extensions = ["ext/extconf.rb", "ext/extconf.rb"]
|
20
|
+
s.extra_rdoc_files = [
|
21
|
+
"ChangeLog.md",
|
22
|
+
"README.md"
|
23
|
+
]
|
24
|
+
s.files = [
|
25
|
+
".gitignore",
|
26
|
+
"ChangeLog.md",
|
27
|
+
"License.txt",
|
28
|
+
"README.md",
|
29
|
+
"Rakefile",
|
30
|
+
"VERSION",
|
31
|
+
"ext/extconf.rb",
|
32
|
+
"ext/glpk_wrapper.c",
|
33
|
+
"lib/rglpk.rb",
|
34
|
+
"rglpk.gemspec",
|
35
|
+
"swig/Makefile.in",
|
36
|
+
"swig/configure.in",
|
37
|
+
"swig/glpk.i",
|
38
|
+
"test/helper.rb",
|
39
|
+
"test/test_all.rb",
|
40
|
+
"test/test_basic.rb",
|
41
|
+
"test/test_brief_example.rb",
|
42
|
+
"test/test_problem_kind.rb"
|
43
|
+
]
|
44
|
+
s.homepage = %q{http://rglpk.rubyforge.org/}
|
45
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
46
|
+
s.require_paths = ["lib", "ext", "ext"]
|
47
|
+
s.rubygems_version = %q{1.3.7}
|
48
|
+
s.summary = %q{Rglpk is a package providing a Ruby wrapper to the [GNU GLPK](http://www.gnu.org/software/glpk/) library. The GLPK (GNU Linear Programming Kit) package is intended for solving large-scale linear programming (LP), mixed integer programming (MIP), and other related problems.}
|
49
|
+
s.test_files = [
|
50
|
+
"test/helper.rb",
|
51
|
+
"test/test_all.rb",
|
52
|
+
"test/test_basic.rb",
|
53
|
+
"test/test_brief_example.rb",
|
54
|
+
"test/test_problem_kind.rb"
|
55
|
+
]
|
56
|
+
|
57
|
+
if s.respond_to? :specification_version then
|
58
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
59
|
+
s.specification_version = 3
|
60
|
+
|
61
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
62
|
+
else
|
63
|
+
end
|
64
|
+
else
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
data/swig/Makefile.in
CHANGED