rglpk 0.1

Sign up to get free protection for your applications and to get access to all the features.
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