rglpk 0.1

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/glpk.rb ADDED
@@ -0,0 +1,320 @@
1
+ require 'rglpk.so'
2
+
3
+ module GLPK
4
+
5
+ Rglpk.constants.each do |c|
6
+ v = Rglpk.const_get(c)
7
+ self.const_set(c,v) if v.kind_of? Numeric
8
+ end
9
+ TypeConstants =[GLP_FR, GLP_LO, GLP_UP, GLP_DB, GLP_FX]
10
+
11
+ class RowColArray < Array
12
+ def [](i)
13
+ super(i-1)
14
+ end
15
+ def []=(i,n)
16
+ super(i-1,n)
17
+ end
18
+ def fix_idx
19
+ self.each_with_index do |rc,i|
20
+ if rc.respond_to?(:i)
21
+ rc.i = i+1
22
+ else
23
+ rc.j = i+1
24
+ end
25
+ end
26
+ end
27
+ end
28
+ class RowArray < RowColArray
29
+ def [](i)
30
+ if i.kind_of?(Numeric)
31
+ super(i)
32
+ elsif i.kind_of?(String)
33
+ raise RuntimeError if self[1].nil?
34
+ idx = Rglpk.glp_find_row(self[1].p.lp,i)
35
+ raise ArgumentError if idx == 0
36
+ super(idx)
37
+ else
38
+ raise ArgumentError
39
+ end
40
+ end
41
+ def []=(i,n)
42
+ raise ArgumentError unless n.is_a?(GLPK::Row)
43
+ super
44
+ end
45
+ end
46
+ class ColArray < RowColArray
47
+ def [](i)
48
+ if i.kind_of?(Numeric)
49
+ super(i)
50
+ elsif i.kind_of?(String)
51
+ raise RuntimeError if self[1].nil?
52
+ idx = Rglpk.glp_find_col(self[1].p.lp,i)
53
+ raise ArgumentError if idx == 0
54
+ super(idx)
55
+ else
56
+ raise ArgumentError
57
+ end
58
+ end
59
+ def []=(i,n)
60
+ raise ArgumentError unless n.is_a?(GLPK::Col)
61
+ super
62
+ end
63
+ end
64
+
65
+ class Problem
66
+
67
+ attr_accessor :rows, :cols, :obj, :lp
68
+
69
+ def initialize
70
+ @lp = Rglpk.glp_create_prob
71
+ @obj = GLPK::ObjectiveFunction.new(self)
72
+ @rows = GLPK::RowArray.new
73
+ @cols = GLPK::ColArray.new
74
+ Rglpk.glp_create_index(@lp)
75
+ @status = nil
76
+ end
77
+
78
+ def name=(n)
79
+ Rglpk.glp_set_prob_name(@lp,n)
80
+ end
81
+ def name
82
+ Rglpk.glp_get_prob_name(@lp)
83
+ end
84
+
85
+ def nz
86
+ Rglpk.glp_get_num_nz(@lp)
87
+ end
88
+
89
+ def add_rows(n)
90
+ Rglpk.glp_add_rows(@lp,n)
91
+ s = @rows.size
92
+ n.times{|i| @rows << GLPK::Row.new(self,s+i+1)}
93
+ @rows
94
+ end
95
+ def add_cols(n)
96
+ Rglpk.glp_add_cols(@lp,n)
97
+ s = @cols.size
98
+ n.times{|i| @cols << GLPK::Column.new(self,s+i+1)}
99
+ @cols
100
+ end
101
+
102
+ def del_rows(a)
103
+ #ensure the array of rows tro delete is sorted and unique
104
+ a = a.sort.uniq
105
+
106
+ r = Rglpk.new_intArray(a.size+1)
107
+ a.each_with_index{|n,i| Rglpk.intArray_setitem(r,i+1,n)}
108
+ Rglpk.glp_del_rows(@lp,a.size,r)
109
+
110
+ a.each do |n|
111
+ @rows.delete_at(n)
112
+ a.each_with_index do |nn,i|
113
+ a[i] -= 1
114
+ end
115
+ end
116
+ @rows.fix_idx
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 = Rglpk.new_intArray(a.size+1)
125
+ a.each_with_index{|n,i| Rglpk.intArray_setitem(r,i+1,n)}
126
+ Rglpk.glp_del_cols(@lp,a.size,r)
127
+
128
+ a.each do |n|
129
+ @cols.delete_at(n)
130
+ a.each_with_index do |nn,i|
131
+ a[i] -= 1
132
+ end
133
+ end
134
+ @cols.fix_idx
135
+ a
136
+ end
137
+
138
+ def set_matrix(v)
139
+
140
+ nr = Rglpk.glp_get_num_rows(@lp)
141
+ nc = Rglpk.glp_get_num_cols(@lp)
142
+
143
+ ia = Rglpk.new_intArray(v.size+1)
144
+ ja = Rglpk.new_intArray(v.size+1)
145
+ ar = Rglpk.new_doubleArray(v.size+1)
146
+
147
+ v.each_with_index do |x,y|
148
+ rn = (y+nr) / nc
149
+ cn = (y % nc) + 1
150
+
151
+ Rglpk.intArray_setitem(ia,y+1,rn) # 1,1,2,2
152
+ Rglpk.intArray_setitem(ja,y+1,cn) # 1,2,1,2
153
+ Rglpk.doubleArray_setitem(ar,y+1,x)
154
+ end
155
+
156
+ Rglpk.glp_load_matrix(@lp,v.size,ia,ja,ar)
157
+
158
+ end
159
+
160
+ def simplex(options)
161
+
162
+ parm = Rglpk::Glp_smcp.new
163
+ Rglpk.glp_init_smcp(parm)
164
+
165
+ #Default to errors only temrinal output
166
+ parm.msg_lev = GLPK::GLP_MSG_ERR
167
+
168
+ #set options
169
+ options.each do |k,v|
170
+ begin
171
+ parm.send("#{k}=".to_sym,v)
172
+ rescue NoMethodError
173
+ raise ArgumentError, "Unrecognised option: #{k}"
174
+ end
175
+ end
176
+
177
+ Rglpk.glp_simplex(@lp,parm)
178
+ end
179
+
180
+ def status
181
+ Rglpk.glp_get_status(@lp)
182
+ end
183
+
184
+ end
185
+
186
+ class Row
187
+ attr_accessor :i, :p
188
+ def initialize(problem,i)
189
+ @p = problem
190
+ @i = i
191
+ end
192
+ def name=(n)
193
+ Rglpk.glp_set_row_name(@p.lp,@i,n)
194
+ end
195
+ def name
196
+ Rglpk.glp_get_row_name(@p.lp,@i)
197
+ end
198
+ def set_bounds(type,lb,ub)
199
+ raise ArgumentError unless GLPK::TypeConstants.include?(type)
200
+ lb = 0.0 if lb.nil?
201
+ ub = 0.0 if ub.nil?
202
+ Rglpk.glp_set_row_bnds(@p.lp,@i,type,lb.to_f,ub.to_f)
203
+ end
204
+ def bounds
205
+ t = Rglpk.glp_get_row_type(@p.lp,@i)
206
+ lb = Rglpk.glp_get_row_lb(@p.lp,@i)
207
+ ub = Rglpk.glp_get_row_ub(@p.lp,@i)
208
+
209
+ lb = (t == GLPK::GLP_FR or t == GLPK::GLP_UP) ? nil : lb
210
+ ub = (t == GLPK::GLP_FR or t == GLPK::GLP_LO) ? nil : ub
211
+
212
+ [t,lb,ub]
213
+ end
214
+ def set(v)
215
+ raise RuntimeError unless v.size == @p.cols.size
216
+ ind = Rglpk.new_intArray(v.size+1)
217
+ val = Rglpk.new_doubleArray(v.size+1)
218
+
219
+ 1.upto(v.size){|x| Rglpk.intArray_setitem(ind,x,x)}
220
+ v.each_with_index{|x,y| Rglpk.doubleArray_setitem(val,y+1,x)}
221
+
222
+ Rglpk.glp_set_mat_row(@p.lp,@i,v.size,ind,val)
223
+ end
224
+ def get
225
+ ind = Rglpk.new_intArray(@p.cols.size+1)
226
+ val = Rglpk.new_doubleArray(@p.cols.size+1)
227
+ len = Rglpk.glp_get_mat_row(@p.lp,@i,ind,val)
228
+ row = Array.new(@p.cols.size,0)
229
+ len.times do |i|
230
+ v = Rglpk.doubleArray_getitem(val,i+1)
231
+ j = Rglpk.intArray_getitem(ind,i+1)
232
+ row[j-1] = v
233
+ end
234
+ return row
235
+ end
236
+ end
237
+ class Column
238
+ attr_accessor :j, :p
239
+ def initialize(problem,i)
240
+ @p = problem
241
+ @j = i
242
+ end
243
+ def name=(n)
244
+ Rglpk.glp_set_col_name(@p.lp,@j,n)
245
+ end
246
+ def name
247
+ Rglpk.glp_get_col_name(@p.lp,@j)
248
+ end
249
+ def set_bounds(type,lb,ub)
250
+ raise ArgumentError unless GLPK::TypeConstants.include?(type)
251
+ lb = 0.0 if lb.nil?
252
+ ub = 0.0 if ub.nil?
253
+ Rglpk.glp_set_col_bnds(@p.lp,@j,type,lb,ub)
254
+ end
255
+ def bounds
256
+ t = Rglpk.glp_get_col_type(@p.lp,@j)
257
+ lb = Rglpk.glp_get_col_lb(@p.lp,@j)
258
+ ub = Rglpk.glp_get_col_ub(@p.lp,@j)
259
+
260
+ lb = (t == GLPK::GLP_FR or t == GLPK::GLP_UP) ? nil : lb
261
+ ub = (t == GLPK::GLP_FR or t == GLPK::GLP_LO) ? nil : ub
262
+
263
+ [t,lb,ub]
264
+ end
265
+ def set(v)
266
+ raise RuntimeError unless v.size == @p.rows.size
267
+ ind = Rglpk.new_intArray(v.size+1)
268
+ val = Rglpk.new_doubleArray(v.size+1)
269
+
270
+ 1.upto(v.size){|x| Rglpk.intArray_setitem(ind,x,x)}
271
+ v.each_with_index{|x,y| Rglpk.doubleArray_setitem(val,y+1,x)}
272
+
273
+ Rglpk.glp_set_mat_col(@p.lp,@j,v.size,ind,val)
274
+ end
275
+ def get
276
+ ind = Rglpk.new_intArray(@p.rows.size+1)
277
+ val = Rglpk.new_doubleArray(@p.rows.size+1)
278
+ len = Rglpk.glp_get_mat_col(@p.lp,@j,ind,val)
279
+ col = Array.new(@p.rows.size,0)
280
+ len.times do |i|
281
+ v = Rglpk.doubleArray_getitem(val,i+1)
282
+ j = Rglpk.intArray_getitem(ind,i+1)
283
+ col[j-1] = v
284
+ end
285
+ return col
286
+ end
287
+ end
288
+
289
+ class ObjectiveFunction
290
+ def initialize(problem)
291
+ @p = problem
292
+ end
293
+ def name=(n)
294
+ Rglpk.glp_set_obj_name(@p.lp,n)
295
+ end
296
+ def name
297
+ Rglpk.glp_get_obj_name(@p.lp)
298
+ end
299
+ def dir=(d)
300
+ raise ArgumentError if d != GLPK::GLP_MIN and d != GLPK::GLP_MAX
301
+ Rglpk.glp_set_obj_dir(@p.lp,d)
302
+ end
303
+ def dir
304
+ Rglpk.glp_get_obj_dir(@p.lp)
305
+ end
306
+ def set_coef(j,coef)
307
+ Rglpk.glp_set_obj_coef(@p.lp,j,coef)
308
+ end
309
+ def coefs=(a)
310
+ @p.cols.each{|c| Rglpk.glp_set_obj_coef(@p.lp,c.j,a[c.j-1])}
311
+ a
312
+ end
313
+ def coefs
314
+ @p.cols.map{|c| Rglpk.glp_get_obj_coef(@p.lp,c.j)}
315
+ end
316
+ def get
317
+ Rglpk.glp_get_obj_val(@p.lp)
318
+ end
319
+ end
320
+ end
data/swig/Makefile.in ADDED
@@ -0,0 +1,4 @@
1
+ rglpk.c: glpk.i
2
+ @SWIG@ -I/usr/local/include -ruby -w801 -o $@ $?
3
+ wrap: rglpk.c
4
+ cp $? ../ext/$?
data/swig/configure.in ADDED
@@ -0,0 +1,4 @@
1
+ AC_INIT(glpk.i)
2
+ AC_CHECK_HEADERS_ONCE(glpk.h)
3
+ AC_PATH_PROG([SWIG], [swig])
4
+ AC_OUTPUT(Makefile)
data/swig/glpk.i ADDED
@@ -0,0 +1,40 @@
1
+ /*
2
+ * == Author
3
+ * Nigel Galloway
4
+ *
5
+ * == Copyright
6
+ *Copyright (C) 2007 Nigel Galloway
7
+ *
8
+ * Contributor(s):
9
+ * Alex Gutteridge
10
+ *
11
+ *This library is free software; you can redistribute it and/or
12
+ *modify it under the terms of the GNU Lesser General Public
13
+ *License as published by the Free Software Foundation; either
14
+ *version 2.1 of the License, or (at your option) any later version.
15
+ *
16
+ *This library is distributed in the hope that it will be useful,
17
+ *but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
+ *Lesser General Public License for more details.
20
+ *
21
+ *You should have received a copy of the GNU Lesser General Public
22
+ *License along with this library; if not, write to the Free Software
23
+ *Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
+ */
25
+
26
+ %module rglpk
27
+
28
+ %{
29
+ #include "glpk.h"
30
+ %}
31
+
32
+ %include "carrays.i"
33
+
34
+ %array_functions(int, intArray)
35
+ %array_functions(double, doubleArray)
36
+
37
+ %include "glpk.h"
38
+
39
+
40
+
data/test/test_all.rb ADDED
@@ -0,0 +1,188 @@
1
+ require 'test/unit'
2
+ require 'glpk'
3
+
4
+ class TestGLPK < Test::Unit::TestCase
5
+
6
+ def test_create
7
+ assert_instance_of GLPK::Problem, GLPK::Problem.new
8
+ end
9
+
10
+ def test_name
11
+ p = GLPK::Problem.new
12
+ p.name = 'test'
13
+ assert_equal 'test', p.name
14
+ end
15
+
16
+ def test_obj_fun_name
17
+ p = GLPK::Problem.new
18
+ p.obj.name = 'test'
19
+ assert_equal 'test', p.obj.name
20
+ end
21
+
22
+ def test_obj_fun_dir
23
+ p = GLPK::Problem.new
24
+ p.obj.dir = GLPK::GLP_MIN
25
+ assert_equal GLPK::GLP_MIN, p.obj.dir
26
+ p.obj.dir = GLPK::GLP_MAX
27
+ assert_equal GLPK::GLP_MAX, p.obj.dir
28
+ assert_raise(ArgumentError){p.obj.dir = 3}
29
+ end
30
+
31
+ def test_add_rows
32
+ p = GLPK::Problem.new
33
+ p.add_rows(2)
34
+ assert_equal 2, p.rows.length
35
+ p.add_rows(2)
36
+ assert_equal 4, p.rows.length
37
+ end
38
+
39
+ def test_add_cols
40
+ p = GLPK::Problem.new
41
+ p.add_cols(2)
42
+ assert_equal 2, p.cols.length
43
+ p.add_cols(2)
44
+ assert_equal 4, p.cols.length
45
+ end
46
+
47
+ def test_set_row_name
48
+ p = GLPK::Problem.new
49
+ p.add_rows(10)
50
+ p.rows[1].name = 'test'
51
+ assert_equal 'test', p.rows[1].name
52
+ assert_nil p.rows[2].name
53
+ end
54
+
55
+ def test_set_col_name
56
+ p = GLPK::Problem.new
57
+ p.add_cols(2)
58
+ p.cols[1].name = 'test'
59
+ assert_equal 'test', p.cols[1].name
60
+ assert_nil p.cols[2].name
61
+ end
62
+
63
+ def test_set_row_bounds
64
+ p = GLPK::Problem.new
65
+ p.add_rows(2)
66
+ p.rows[1].set_bounds(GLPK::GLP_FR,nil,nil)
67
+ assert_equal [GLPK::GLP_FR, nil, nil], p.rows[1].bounds
68
+ end
69
+
70
+ def test_set_col_bounds
71
+ p = GLPK::Problem.new
72
+ p.add_cols(2)
73
+ p.cols[1].set_bounds(GLPK::GLP_FR,nil,nil)
74
+ assert_equal [GLPK::GLP_FR, nil, nil], p.cols[1].bounds
75
+ end
76
+
77
+ def test_obj_coef
78
+ p = GLPK::Problem.new
79
+ p.add_cols(2)
80
+ p.obj.set_coef(1,2)
81
+ assert_equal [2,0], p.obj.coefs
82
+ p.obj.coefs = [1,2]
83
+ assert_equal [1,2], p.obj.coefs
84
+ end
85
+
86
+ def test_set_row
87
+ p = GLPK::Problem.new
88
+ p.add_rows(2)
89
+ assert_raise(RuntimeError){p.rows[1].set([1,2])}
90
+ p.add_cols(2)
91
+ p.rows[1].set([1,2])
92
+ assert_equal [1,2], p.rows[1].get
93
+ end
94
+
95
+ def test_set_col
96
+ p = GLPK::Problem.new
97
+ p.add_cols(2)
98
+ assert_raise(RuntimeError){p.cols[1].set([1,2])}
99
+ p.add_rows(2)
100
+ p.cols[1].set([1,2])
101
+ assert_equal [1,2], p.cols[1].get
102
+ end
103
+
104
+ def test_set_mat
105
+ p = GLPK::Problem.new
106
+ p.add_cols(2)
107
+ p.add_rows(2)
108
+ p.set_matrix([1,2,3,4])
109
+ assert_equal [1,2], p.rows[1].get
110
+ assert_equal [3,4], p.rows[2].get
111
+ assert_equal [1,3], p.cols[1].get
112
+ assert_equal [2,4], p.cols[2].get
113
+ end
114
+
115
+ def test_del_row
116
+ p = GLPK::Problem.new
117
+ p.add_cols(2)
118
+ p.add_rows(2)
119
+ p.set_matrix([1,2,3,4])
120
+ assert_equal [1,2], p.rows[1].get
121
+ p.del_rows([1])
122
+ assert_equal [3,4], p.rows[1].get
123
+ assert_equal [3], p.cols[1].get
124
+ end
125
+
126
+ def test_del_col
127
+ p = GLPK::Problem.new
128
+ p.add_cols(2)
129
+ p.add_rows(2)
130
+ p.set_matrix([1,2,3,4])
131
+ assert_equal [1,3], p.cols[1].get
132
+ p.del_cols([1])
133
+ assert_equal [2,4], p.cols[1].get
134
+ assert_equal [2], p.rows[1].get
135
+ end
136
+
137
+ def test_nz
138
+ p = GLPK::Problem.new
139
+ p.add_cols(2)
140
+ p.add_rows(2)
141
+ p.set_matrix([1,2,3,4])
142
+ assert_equal 4, p.nz
143
+ end
144
+
145
+ def test_row_get_by_name
146
+ p = GLPK::Problem.new
147
+ assert_raises(RuntimeError){ p.rows['test'] }
148
+ p.add_cols(2)
149
+ p.add_rows(2)
150
+ p.set_matrix([1,2,3,4])
151
+ assert_raises(ArgumentError){ p.rows['test'] }
152
+ p.rows[1].name = 'test'
153
+ assert_equal [1,2], p.rows['test'].get
154
+ end
155
+
156
+ def test_col_get_by_name
157
+ p = GLPK::Problem.new
158
+ assert_raises(RuntimeError){ p.cols['test'] }
159
+ p.add_cols(2)
160
+ p.add_rows(2)
161
+ p.set_matrix([1,2,3,4])
162
+ assert_raises(ArgumentError){ p.cols['test'] }
163
+ p.cols[1].name = 'test'
164
+ assert_equal [1,3], p.cols['test'].get
165
+ end
166
+
167
+ def test_solve
168
+ p = GLPK::Problem.new
169
+ assert_raises(RuntimeError){ p.cols['test'] }
170
+ p.add_cols(2)
171
+ p.add_rows(2)
172
+ p.set_matrix([1,2,3,4])
173
+ p.simplex({:msg_lev => 1})
174
+ end
175
+
176
+ class D < GLPK::Problem
177
+ attr_accessor :species
178
+ def initialize
179
+ @species = []
180
+ super
181
+ end
182
+ end
183
+
184
+ def test_derived
185
+ D.new.add_rows(10)
186
+ end
187
+
188
+ end