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/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
@@ -1,4 +1,4 @@
1
- rglpk.c: glpk.i
1
+ glpk_wrapper.c: glpk.i
2
2
  @SWIG@ -I/usr/local/include -ruby -w801 -o $@ $?
3
- wrap: rglpk.c
3
+ wrap: glpk_wrapper.c
4
4
  cp $? ../ext/$?