lpsolve 5.5.10.i
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +78 -0
- data/VERSION +1 -0
- data/doc/Doxyfile +1127 -0
- data/doc/run_doxygen +107 -0
- data/doc/typos.txt +29 -0
- data/example/boilerplate.rb +8 -0
- data/example/demo.rb +223 -0
- data/example/lp.lp +9 -0
- data/example/lp.mps +25 -0
- data/example/model.lp +8 -0
- data/example/model.mps +16 -0
- data/example/rubydemo.rb +215 -0
- data/ext/Makefile +187 -0
- data/ext/extconf.rb +11 -0
- data/ext/lpconsts.c +174 -0
- data/ext/lpsolve.c +2915 -0
- data/test/Rakefile +8 -0
- data/test/lp_model.right +24 -0
- data/test/lpsolve.right +60 -0
- data/test/mps_model.right +24 -0
- data/test/test_lpsolve.rb +530 -0
- metadata +96 -0
data/test/Rakefile
ADDED
data/test/lp_model.right
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
Model name: 'LP model' - run #1
|
3
|
+
Objective: Maximize(R0)
|
4
|
+
|
5
|
+
SUBMITTED
|
6
|
+
Model size: 3 constraints, 2 variables, 6 non-zeros.
|
7
|
+
Sets: 0 GUB, 0 SOS.
|
8
|
+
|
9
|
+
Using DUAL simplex for phase 1 and PRIMAL simplex for phase 2.
|
10
|
+
The primal and dual simplex pricing strategy set to 'Devex'.
|
11
|
+
|
12
|
+
|
13
|
+
Optimal solution 6315.625 after 2 iter.
|
14
|
+
|
15
|
+
Excellent numeric accuracy ||*|| = 0
|
16
|
+
|
17
|
+
MEMO: lp_solve version 5.5.0.10 for 32 bit OS, with 64 bit REAL variables.
|
18
|
+
In the total iteration count 2, 0 (0.0%) were bound flips.
|
19
|
+
There were 0 refactorizations, 0 triggered by time and 0 by density.
|
20
|
+
... on average 2.0 major pivots per refactorization.
|
21
|
+
The largest [LUSOL v2.2.1.0] fact(B) had 4 NZ entries, 1.0x largest basis.
|
22
|
+
The constraint matrix inf-norm is 210, with a dynamic range of 210.
|
23
|
+
Time to load data was 0.001 seconds, presolve used 0.000 seconds,
|
24
|
+
... 0.001 seconds in simplex solver, in total 0.002 seconds.
|
data/test/lpsolve.right
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
print_str() test
|
2
|
+
Model name:
|
3
|
+
C1 C2 C3 C4
|
4
|
+
Minimize 0 0 0 0
|
5
|
+
R1 3 2 2 1 <= 4
|
6
|
+
Type Real Real Real Real
|
7
|
+
upbo Inf Inf Inf Inf
|
8
|
+
lowbo 0 0 0 0
|
9
|
+
Model name:
|
10
|
+
C1 C2 C3 C4
|
11
|
+
Minimize 0 0 0 0
|
12
|
+
R1 3 2 2 1 <= 4
|
13
|
+
R2 0 4 3 1 >= 3
|
14
|
+
Type Real Real Real Real
|
15
|
+
upbo Inf Inf Inf Inf
|
16
|
+
lowbo 0 0 0 0
|
17
|
+
Model name:
|
18
|
+
C1 C2 C3 C4
|
19
|
+
Minimize:
|
20
|
+
2 3 -2 3
|
21
|
+
|
22
|
+
Subject to:
|
23
|
+
R1 3 2 2 1 <= 4
|
24
|
+
R2 4 3 1 >= 3
|
25
|
+
|
26
|
+
Type Real Real Real Real
|
27
|
+
upbo Inf Inf Inf Inf
|
28
|
+
lowbo 0 0 0 0
|
29
|
+
SOS false false false false
|
30
|
+
|
31
|
+
Value of objective function: -4
|
32
|
+
|
33
|
+
Actual values of the variables:
|
34
|
+
Column 1 0
|
35
|
+
C2 0
|
36
|
+
C3 2
|
37
|
+
C4 0
|
38
|
+
|
39
|
+
Actual values of the variables:
|
40
|
+
C3 2
|
41
|
+
|
42
|
+
Actual values of the constraints:
|
43
|
+
Row 1 4
|
44
|
+
R2 6
|
45
|
+
|
46
|
+
Objective function limits:
|
47
|
+
From Till FromValue
|
48
|
+
Column 1 -3 1e+30 0.6666667
|
49
|
+
C2 -2 1e+30 2
|
50
|
+
C3 -1e+30 0.0 -1e+30
|
51
|
+
C4 -1 1e+30 4
|
52
|
+
|
53
|
+
Dual values with from - till limits:
|
54
|
+
Dual value From Till
|
55
|
+
Row 1 -1 2 1e+30
|
56
|
+
R2 0 -1e+30 1e+30
|
57
|
+
Column 1 5 -1e+30 0.6666667
|
58
|
+
C2 5 -3 2
|
59
|
+
C3 0 -1e+30 1e+30
|
60
|
+
C4 4 -1e+30 4
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
Model name: 'MPS model' - run #1
|
3
|
+
Objective: Minimize(R0)
|
4
|
+
|
5
|
+
SUBMITTED
|
6
|
+
Model size: 3 constraints, 2 variables, 6 non-zeros.
|
7
|
+
Sets: 0 GUB, 0 SOS.
|
8
|
+
|
9
|
+
Using DUAL simplex for phase 1 and PRIMAL simplex for phase 2.
|
10
|
+
The primal and dual simplex pricing strategy set to 'Devex'.
|
11
|
+
|
12
|
+
|
13
|
+
Optimal solution 0 after 0 iter.
|
14
|
+
|
15
|
+
Excellent numeric accuracy ||*|| = 0
|
16
|
+
|
17
|
+
MEMO: lp_solve version 5.5.0.10 for 32 bit OS, with 64 bit REAL variables.
|
18
|
+
In the total iteration count 0, 0 (100.0%) were bound flips.
|
19
|
+
There were 0 refactorizations, 0 triggered by time and 0 by density.
|
20
|
+
... on average 0.0 major pivots per refactorization.
|
21
|
+
The largest [LUSOL v2.2.1.0] fact(B) had 4 NZ entries, 1.0x largest basis.
|
22
|
+
The constraint matrix inf-norm is 210, with a dynamic range of 210.
|
23
|
+
Time to load data was 0.001 seconds, presolve used 0.000 seconds,
|
24
|
+
... 0.000 seconds in simplex solver, in total 0.001 seconds.
|
@@ -0,0 +1,530 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# $Id: test_lpsolve.rb,v 1.13 2007/03/28 11:48:01 rocky Exp $
|
3
|
+
require 'test/unit'
|
4
|
+
require 'rubygems'
|
5
|
+
|
6
|
+
# require 'ruby-debug' ; Debugger.start
|
7
|
+
|
8
|
+
Mypath = File.expand_path(File.dirname(__FILE__))
|
9
|
+
old_dir = File.expand_path(Dir.pwd)
|
10
|
+
if old_dir != Mypath
|
11
|
+
Dir.chdir(Mypath)
|
12
|
+
end
|
13
|
+
require Mypath + '/../ext/lpsolve.so'
|
14
|
+
|
15
|
+
def compare_files(file_correct, file_check_against, max_line=0, filter=nil)
|
16
|
+
check_against = File.new(file_check_against)
|
17
|
+
got_lines = check_against.readlines
|
18
|
+
correct = File.new(file_correct)
|
19
|
+
correct_lines = correct.readlines
|
20
|
+
filter.call(got_lines, correct_lines) if filter
|
21
|
+
|
22
|
+
correct_lines.each_with_index do |line, lineno|
|
23
|
+
begin
|
24
|
+
break if max_line > 0 && lineno >= max_line - 1
|
25
|
+
if got_lines[lineno] != correct_lines[lineno]
|
26
|
+
puts "At line #{lineno}, we expected:"
|
27
|
+
puts correct_lines[lineno]
|
28
|
+
puts 'but got:'
|
29
|
+
puts got_lines[lineno]
|
30
|
+
return false
|
31
|
+
end
|
32
|
+
rescue EOFError
|
33
|
+
return false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
if correct_lines.size != got_lines.size
|
37
|
+
puts('difference in number of lines: ' +
|
38
|
+
"#{correct_lines.size} vs. #{got_lines.size}")
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
|
44
|
+
class TestLPSolve < Test::Unit::TestCase
|
45
|
+
def setup
|
46
|
+
@lp = LPSolve.new(0, 4)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_basic
|
50
|
+
assert_equal(Object, LPSolve.superclass)
|
51
|
+
assert_equal(LPSolve, @lp.class)
|
52
|
+
|
53
|
+
assert_equal(4, @lp.version.length)
|
54
|
+
@lp.print_lp()
|
55
|
+
|
56
|
+
[
|
57
|
+
# Constraint relations
|
58
|
+
[0, 'FR'], [1, 'LE'], [2, 'GE'], [3, 'EQ'],
|
59
|
+
|
60
|
+
# Verbosity constant
|
61
|
+
[0, 'NEUTRAL'], [1, 'CRITICAL'], [2, 'SEVERE'],
|
62
|
+
[3, 'IMPORTANT'], [4, 'NORMAL'], [5, 'DETAILED'],
|
63
|
+
[6, 'FULL'],
|
64
|
+
|
65
|
+
# Scaling constants
|
66
|
+
|
67
|
+
[0, 'SCALE_NONE'], [1, 'SCALE_EXTREME'], [2, 'SCALE_RANGE'],
|
68
|
+
[3, 'SCALE_MEAN'], [4, 'SCALE_GEOMETRIC'],
|
69
|
+
[7, 'SCALE_CURTISREID'],
|
70
|
+
|
71
|
+
# Simplex types
|
72
|
+
[ 5, 'SIMPLEX_PRIMAL_PRIMAL'],
|
73
|
+
[ 6, 'SIMPLEX_DUAL_PRIMAL'],
|
74
|
+
[ 9, 'SIMPLEX_PRIMAL_DUAL'],
|
75
|
+
[10, 'SIMPLEX_DUAL_DUAL'],
|
76
|
+
|
77
|
+
# Solve types
|
78
|
+
[-2, 'NOMEMORY'], [ 0, 'OPTIMAL'], [ 1, 'SUBOPTIMAL'],
|
79
|
+
[ 2, 'INFEASIBLE'], [ 3, 'UNBOUNDED'], [ 4, 'DEGENERATE'],
|
80
|
+
[ 5, 'NUMFAILURE'], [ 6, 'USERABORT'], [ 7, 'TIMEOUT'],
|
81
|
+
[ 9, 'PRESOLVED'], [10, 'PROCFAIL'], [11, 'PROCBREAK'],
|
82
|
+
[12, 'FEASFOUND'], [13, 'NOFEASFOUND']
|
83
|
+
].each do |val, sym|
|
84
|
+
assert_equal(val, eval('LPSolve::' + sym))
|
85
|
+
end
|
86
|
+
|
87
|
+
# Brand-and-bound rules
|
88
|
+
[
|
89
|
+
[ 0, 'NODE_FIRSTSELECT'],
|
90
|
+
[ 1, 'NODE_GAPSELECT'],
|
91
|
+
[ 2, 'NODE_RANGESELECT'],
|
92
|
+
[ 3, 'NODE_FRACTIONSELECT'],
|
93
|
+
[ 4, 'NODE_PSEUDOCOSTSELECT'],
|
94
|
+
[ 5, 'NODE_PSEUDONONINTSELECT'],
|
95
|
+
[ 6, 'NODE_PSEUDORATIOSELECT'],
|
96
|
+
[ 7, 'NODE_USERSELECT'],
|
97
|
+
[ 8, 'NODE_WEIGHTREVERSEMODE'],
|
98
|
+
[ 16, 'NODE_BRANCHREVERSEMODE'],
|
99
|
+
[ 32, 'NODE_GREEDYMODE'],
|
100
|
+
[ 64, 'NODE_PSEUDOCOSTMODE'],
|
101
|
+
[ 128, 'NODE_DEPTHFIRSTMODE'],
|
102
|
+
[ 256, 'NODE_RANDOMIZEMODE'],
|
103
|
+
[1024, 'NODE_DYNAMICMODE'],
|
104
|
+
[2048, 'NODE_RESTARTMODE'],
|
105
|
+
[4096, 'NODE_BREADTHFIRSTMODE'],
|
106
|
+
[8192, 'NODE_AUTOORDER']
|
107
|
+
].each do |val, sym|
|
108
|
+
assert_equal(val, eval('LPSolve::' + sym))
|
109
|
+
@lp.bb_rule = val
|
110
|
+
assert_equal(val, @lp.bb_rule)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_constraint
|
115
|
+
@lp.set_outputfile('lpsolve.out')
|
116
|
+
@lp.print_str("print_str() test\n")
|
117
|
+
assert(@lp.str_add_constraint("3 2 2 1", LPSolve::LE, 4),
|
118
|
+
"Error in adding <= constraint")
|
119
|
+
@lp.print_lp()
|
120
|
+
assert(@lp.str_add_constraint("0 4 3 1", LPSolve::GE, 3),
|
121
|
+
"Error in adding >= constraint")
|
122
|
+
@lp.print_lp()
|
123
|
+
assert true
|
124
|
+
puts "Setting the objective function: 2 3 -2 3"
|
125
|
+
assert(@lp.str_set_obj_fn("2 3 -2 3"),
|
126
|
+
"Error in setting objective function")
|
127
|
+
@lp.verbose = LPSolve::IMPORTANT
|
128
|
+
@lp.print()
|
129
|
+
solution = @lp.solve
|
130
|
+
assert_equal(0, solution)
|
131
|
+
assert_equal(0, @lp.status)
|
132
|
+
assert_equal("OPTIMAL solution", @lp.get_statustext(@lp.status))
|
133
|
+
@lp.lp_name = "Test model"
|
134
|
+
@lp.set_col_name(1, "Column 1")
|
135
|
+
@lp.set_row_name(1, "Row 1")
|
136
|
+
@lp.print_objective
|
137
|
+
@lp.print_solution(1)
|
138
|
+
@lp.print_solution(-1)
|
139
|
+
@lp.print_constraints(1)
|
140
|
+
@lp.print_duals()
|
141
|
+
assert @lp.set_mat(2,1,0.5)
|
142
|
+
assert_equal(2.0 , @lp.get_mat(1, 2))
|
143
|
+
assert_equal(-4.0 , @lp.objective)
|
144
|
+
assert_equal(-4.0 , @lp.get_var_primalresult(0))
|
145
|
+
assert_equal(4.0, @lp.get_var_primalresult(1))
|
146
|
+
assert_in_delta(6.0, @lp.get_var_primalresult(2), 0.001)
|
147
|
+
assert_in_delta(5.0, @lp.get_var_dualresult(3), 0.001)
|
148
|
+
assert_in_delta(5.0, @lp.get_var_dualresult(4), 0.001)
|
149
|
+
assert_equal(0.0, @lp.get_var_dualresult(5))
|
150
|
+
assert_equal(0, @lp.get_var_primalresult(3))
|
151
|
+
assert_equal(0, @lp.get_var_primalresult(4))
|
152
|
+
assert_equal(2.0, @lp.get_var_primalresult(5))
|
153
|
+
assert_equal(1, @lp.get_solutioncount)
|
154
|
+
assert_equal(1, @lp.solutioncount)
|
155
|
+
@lp = nil
|
156
|
+
filter = Proc.new{|got_lines, correct_lines|
|
157
|
+
[got_lines[49]].flatten.each do |s|
|
158
|
+
s.sub!(/-1e[+]30\s+.*\s+-1e[+]30/, "-1e+30\t\t0.0\t\t-1e+30")
|
159
|
+
end
|
160
|
+
}
|
161
|
+
assert compare_files('lpsolve.right', 'lpsolve.out', 0, filter)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Check set_col_name(), get_col_name(), and get_origcol_name()
|
165
|
+
def test_col_name
|
166
|
+
# Test Invalid parameter type, should be a string.
|
167
|
+
assert_equal(nil, @lp.set_col_name(1, true))
|
168
|
+
|
169
|
+
col_name="column test name"
|
170
|
+
assert_equal(nil, @lp.set_col_name([1], col_name),
|
171
|
+
"Column name must be an int")
|
172
|
+
assert_equal(nil, @lp.set_col_name(1, [1]),
|
173
|
+
"Column name must be an int")
|
174
|
+
assert @lp.set_col_name(1, col_name)
|
175
|
+
assert_equal(col_name, @lp.get_col_name(1))
|
176
|
+
assert_equal(col_name, @lp.get_origcol_name(1))
|
177
|
+
assert_equal(nil, @lp.get_col_name(100))
|
178
|
+
assert_equal(nil, @lp.get_col_name("A"))
|
179
|
+
assert_equal(1, @lp.get_col_num(col_name))
|
180
|
+
end
|
181
|
+
|
182
|
+
# Check get_Nrows(), get_Ncolumns(), get_Norig_rows(), get_Norig_columns()
|
183
|
+
# Check reading an MPS and the solution.
|
184
|
+
def test_Ncols_rows
|
185
|
+
# Test Invalid parameter type, should be a string.
|
186
|
+
assert_equal(4, @lp.Ncolumns)
|
187
|
+
assert_equal(4, @lp.Norig_columns)
|
188
|
+
assert_equal(0, @lp.Nrows)
|
189
|
+
assert_equal(0, @lp.Norig_rows)
|
190
|
+
@lp = LPSolve.read_MPS("../example/model.mps", LPSolve::NORMAL)
|
191
|
+
assert_equal(nil, @lp.add_SOS("bad", 1, 1, []))
|
192
|
+
presolve = LPSolve::PRESOLVE_COLS +
|
193
|
+
LPSolve::PRESOLVE_LINDEP +
|
194
|
+
LPSolve::PRESOLVE_SOS +
|
195
|
+
LPSolve::PRESOLVE_REDUCEMIP +
|
196
|
+
LPSolve::PRESOLVE_KNAPSACK
|
197
|
+
@lp.presolve = [presolve, presolve]
|
198
|
+
@lp.solve()
|
199
|
+
assert_equal(0, @lp.status)
|
200
|
+
assert_equal(2, @lp.Ncolumns)
|
201
|
+
assert_equal(2, @lp.Norig_columns)
|
202
|
+
assert_equal(3, @lp.Nrows)
|
203
|
+
assert_equal(3, @lp.Norig_rows)
|
204
|
+
assert_equal(0.0, @lp.get_objective())
|
205
|
+
assert_equal(1, @lp.solutioncount())
|
206
|
+
end
|
207
|
+
|
208
|
+
# Check set_col_name(), get_col_name(), and get_origcol_name()
|
209
|
+
def test_nonzeros
|
210
|
+
# Test Invalid parameter type, should be a string.
|
211
|
+
assert_equal(0, @lp.nonzeros,
|
212
|
+
"Initially there are 0 nonzero entries - everything is zero")
|
213
|
+
assert_equal(0, @lp.get_nonzeros,
|
214
|
+
"Initially there are 0 nonzero entries - everything is zero")
|
215
|
+
assert(@lp.str_add_constraint("0 4 3 1", LPSolve::GE, 3),
|
216
|
+
"Error in adding <= constraint")
|
217
|
+
assert_equal(3, @lp.nonzeros,
|
218
|
+
"We just set 3 entries to be non-zero")
|
219
|
+
end
|
220
|
+
|
221
|
+
# Check get_Nrows(), get_Ncolumns(), get_Norig_rows(), get_Norig_columns()
|
222
|
+
# Check set/get_timeout
|
223
|
+
def test_get_timeout
|
224
|
+
assert_equal Float, @lp.get_timeout().class
|
225
|
+
@lp.set_timeout 10.0
|
226
|
+
assert_equal(10.0, @lp.get_timeout())
|
227
|
+
end
|
228
|
+
|
229
|
+
# Check get_bb_depthlimit set_bb_depthlimit
|
230
|
+
def test_get_bb_depthlimit
|
231
|
+
@lp.bb_depthlimit = 10
|
232
|
+
assert_equal(10, @lp.bb_depthlimit)
|
233
|
+
@lp.set_bb_depthlimit(-5)
|
234
|
+
assert_equal(-5, @lp.get_bb_depthlimit)
|
235
|
+
end
|
236
|
+
|
237
|
+
# Check get_bb_depthlimit set_bb_depthlimit
|
238
|
+
def test_set_mip_gap
|
239
|
+
@lp.set_mip_gap(true, 10)
|
240
|
+
assert_equal(10, @lp.get_mip_gap(true))
|
241
|
+
@lp.set_mip_gap(false, 1.0)
|
242
|
+
assert_equal(1.0, @lp.get_mip_gap(false))
|
243
|
+
end
|
244
|
+
|
245
|
+
# Check set_*variable* types
|
246
|
+
def test_vartype
|
247
|
+
[:set_binary, :set_int, :set_semicont].each do |fn|
|
248
|
+
assert(@lp.send(fn, 1, true),
|
249
|
+
"Should have been able to set variable type (#{fn}) for " +
|
250
|
+
"column 1")
|
251
|
+
|
252
|
+
assert(@lp.send(fn, 1, false),
|
253
|
+
"Should have been able to unset variable type (#{fn}) for " +
|
254
|
+
"column 1")
|
255
|
+
|
256
|
+
assert(@lp.send(fn, 1, nil),
|
257
|
+
"Should have been able to unset variable type (#{fn}) via " +
|
258
|
+
"nil for column 1")
|
259
|
+
|
260
|
+
assert(!@lp.send(fn, 100, false),
|
261
|
+
"Should not have been able to set variable type (#{fn}) " +
|
262
|
+
"since column number is too large")
|
263
|
+
|
264
|
+
assert(!@lp.send(fn, 1, "not a boolean parameter"),
|
265
|
+
"Should not gotten an error on (#{fn}) " +
|
266
|
+
"because parameter 2 is not boolean or nil")
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# Check set_debug() and is_debug() and accessor functions to them.
|
271
|
+
def test_debug
|
272
|
+
assert_equal(false, eval("@lp.set_debug(5)")) # bad value
|
273
|
+
assert_equal(false, eval("@lp.set_debug('true')")) # bad value
|
274
|
+
assert eval("@lp.debug = true")
|
275
|
+
assert @lp.is_debug
|
276
|
+
assert @lp.debug?
|
277
|
+
@lp.set_debug(false)
|
278
|
+
assert_equal(@lp.is_debug, false)
|
279
|
+
end
|
280
|
+
|
281
|
+
# Check our deallocation routine doesn't mess
|
282
|
+
# things up across a garbage collection
|
283
|
+
def test_gc
|
284
|
+
@lp = LPSolve.new(0, 4)
|
285
|
+
GC.enable
|
286
|
+
GC.start
|
287
|
+
assert_equal(LPSolve, @lp.class)
|
288
|
+
end
|
289
|
+
|
290
|
+
# Check set_row_name(), set_orig_row_name() and get_row_name()
|
291
|
+
# and corresponding accessor functions
|
292
|
+
def test_lp_name
|
293
|
+
assert_equal(String, @lp.lp_name.class) # accessor function
|
294
|
+
assert @lp.set_lp_name("Test model")
|
295
|
+
assert_equal("Test model", @lp.get_lp_name())
|
296
|
+
@lp.lp_name = "Test 2"
|
297
|
+
assert_equal("Test 2", @lp.lp_name())
|
298
|
+
end
|
299
|
+
|
300
|
+
# Check set_mat(), get_mat(), set_add_rowmode(), str_add_constraint()
|
301
|
+
def test_mat
|
302
|
+
assert_equal(nil , @lp.get_mat(1.01, 2), "Row number should be int")
|
303
|
+
assert_equal(nil , @lp.get_mat(1, "a"), "Col number should be int")
|
304
|
+
assert_equal(0.0 , @lp.get_mat(1, 2))
|
305
|
+
assert_equal(nil, @lp.set_add_rowmode(1), "Parameter should be a boolean")
|
306
|
+
assert_equal(true, @lp.set_add_rowmode(true),
|
307
|
+
"The default should have been false")
|
308
|
+
assert_equal(false, @lp.set_add_rowmode(true),
|
309
|
+
"We should have just set rowmode to true")
|
310
|
+
assert_equal(nil, @lp.add_constraintex(nil, [],
|
311
|
+
LPSolve::LE, 3),
|
312
|
+
"add_constraintex")
|
313
|
+
assert_equal(nil, @lp.add_constraintex(nil,
|
314
|
+
[[1, 3], [2, 2], ["a", 2], [4, 1]],
|
315
|
+
LPSolve::LE, 3),
|
316
|
+
"add_constraintex")
|
317
|
+
assert_equal(1, @lp.add_constraintex("Row1",
|
318
|
+
[[1, 3], [2, 2], [3, 2], [4, 1]],
|
319
|
+
LPSolve::LE, 4),
|
320
|
+
"add_constraintex")
|
321
|
+
assert(@lp.str_add_constraint("0 4 3 1", LPSolve::GE, 3),
|
322
|
+
"Error in adding <= constraint")
|
323
|
+
assert_equal(nil, @lp.set_obj_fnex("bad"))
|
324
|
+
assert(@lp.set_obj_fnex([[1, 2], [2, 3], [3, -2], [4, 3]]),
|
325
|
+
"Error in setting objective function via set_obj_fnex")
|
326
|
+
assert(@lp.set_add_rowmode(false),
|
327
|
+
"Rowmode should have been set true and is now false")
|
328
|
+
assert @lp.set_mat(2,1,0.5)
|
329
|
+
assert_equal(2.0 , @lp.get_mat(1, 2))
|
330
|
+
end
|
331
|
+
|
332
|
+
# Check our deallocation routine doesn't mess
|
333
|
+
# things up across a garbage collection
|
334
|
+
def test_putlogfunc
|
335
|
+
@lp.put_logfunc("puts")
|
336
|
+
end
|
337
|
+
|
338
|
+
# Check read_LP()
|
339
|
+
def test_read_LP
|
340
|
+
# Check invalid parameter type. Should be a string.
|
341
|
+
assert_equal(nil, LPSolve.read_LP(TRUE, LPSolve::IMPORTANT, "LP model"))
|
342
|
+
assert_equal(nil, LPSolve.read_LP("model.lp", LPSolve::IMPORTANT, 5.0))
|
343
|
+
|
344
|
+
lp = LPSolve.read_LP("../example/model.lp", LPSolve::IMPORTANT, "LP model")
|
345
|
+
assert_equal(LPSolve, lp.class)
|
346
|
+
lp.set_outputfile("lp_model.out")
|
347
|
+
lp.set_verbose(LPSolve::NORMAL)
|
348
|
+
lp.solve
|
349
|
+
|
350
|
+
assert_in_delta(lp.time_total,
|
351
|
+
lp.time_load + lp.time_presolve + lp.time_simplex,
|
352
|
+
0.01)
|
353
|
+
assert(lp.time_total >= lp.time_elapsed,
|
354
|
+
("total time %g should be larger than elapsed time %g" %
|
355
|
+
[lp.time_total, lp.time_elapsed]))
|
356
|
+
|
357
|
+
filter = Proc.new{|got_lines, correct_lines|
|
358
|
+
[got_lines[14]].flatten.each do |s|
|
359
|
+
s.sub!(/\|\|[*]\|\| = .+/, '||*|| = 0') if s
|
360
|
+
end
|
361
|
+
[got_lines[49]].flatten.each do |s|
|
362
|
+
s.sub!(/-1e[+]30\s+.*\s+-1e[+]30/, "-1e+30\t\t0.0\t\t-1e+30") if s
|
363
|
+
end
|
364
|
+
}
|
365
|
+
assert compare_files("lp_model.right", "lp_model.out", 23, filter)
|
366
|
+
assert_in_delta(21.875, lp.variables[0], 0.0001)
|
367
|
+
assert_in_delta(53.125, lp.variables[1], 0.0001)
|
368
|
+
assert_equal([143.0, 120.0, 110.0, 1.0], lp.get_column(1))
|
369
|
+
assert_equal(nil, lp.get_column(0))
|
370
|
+
assert_in_delta(60.0, lp.get_column(2)[0], 0.0001)
|
371
|
+
assert_in_delta(210.0, lp.get_column(2)[1], 0.0001)
|
372
|
+
assert_equal(0, lp.get_lowbo(1))
|
373
|
+
assert_equal(lp.infinite, lp.get_upbo(1))
|
374
|
+
assert(lp.set_bounds(1, -1, 200.1))
|
375
|
+
assert_equal(false, lp.set_bounds(0, -1, 200.1))
|
376
|
+
assert_equal(200.1, lp.get_upbo(1))
|
377
|
+
assert_equal(-1, lp.get_lowbo(1))
|
378
|
+
assert lp.maxim?
|
379
|
+
end
|
380
|
+
|
381
|
+
# Check read_MPS()
|
382
|
+
def test_read_MPS
|
383
|
+
# Check invalid parameter type. Should be a string.
|
384
|
+
assert_equal(nil, LPSolve.read_MPS(5, LPSolve::IMPORTANT))
|
385
|
+
|
386
|
+
lp = LPSolve.read_MPS("../example/model.mps", LPSolve::IMPORTANT)
|
387
|
+
assert_equal(LPSolve, lp.class)
|
388
|
+
lp.set_outputfile("mps_model.out")
|
389
|
+
lp.set_verbose(LPSolve::NORMAL)
|
390
|
+
lp.set_lp_name("MPS model")
|
391
|
+
lp.solve
|
392
|
+
assert compare_files("mps_model.right", "mps_model.out", 23)
|
393
|
+
assert_in_delta(0.0, lp.variables[0], 0.0001)
|
394
|
+
assert_in_delta(0.0, lp.variables[1], 0.0001)
|
395
|
+
assert_equal([143.0, 120.0, 110.0, 1.0], lp.get_column(1))
|
396
|
+
assert_equal(nil, lp.get_column(0))
|
397
|
+
assert_in_delta(60.0, lp.get_column(2)[0], 0.0001)
|
398
|
+
assert_in_delta(210.0, lp.get_column(2)[1], 0.0001)
|
399
|
+
assert_equal(0, lp.get_lowbo(1))
|
400
|
+
assert(lp.set_lowbo(1, 1))
|
401
|
+
assert_equal(1, lp.get_lowbo(1))
|
402
|
+
assert_equal(lp.infinite, lp.get_upbo(1))
|
403
|
+
|
404
|
+
assert(lp.set_upbo(1, 100))
|
405
|
+
assert_equal(100, lp.get_upbo(1))
|
406
|
+
assert(lp.write_lp("foo.lp"))
|
407
|
+
assert(lp.write_mps("foo.mps"))
|
408
|
+
## FIXME
|
409
|
+
# assert(lp.write_mps(nil))
|
410
|
+
# assert(lp.write_mps())
|
411
|
+
end
|
412
|
+
|
413
|
+
# Check set_row_name(), set_orig_row_name() and get_row_name()
|
414
|
+
def test_row_name
|
415
|
+
# Test Invalid parameter type, should be a string.
|
416
|
+
assert_equal(false, @lp.set_row_name(1, true))
|
417
|
+
|
418
|
+
assert @lp.set_row_name(1, "row test name")
|
419
|
+
assert_equal("row test name", @lp.get_row_name(1))
|
420
|
+
assert_equal("row test name", @lp.get_origrow_name(1))
|
421
|
+
assert_equal(nil, @lp.get_origrow_name([1]))
|
422
|
+
assert_equal(@lp.get_row_name(100), nil)
|
423
|
+
assert_equal(@lp.get_row_name("a"), nil)
|
424
|
+
end
|
425
|
+
|
426
|
+
# Check set_rh() and set_rh_range
|
427
|
+
def test_set_rh
|
428
|
+
# Test Invalid parameter type, should be a string.
|
429
|
+
assert(@lp.str_set_obj_fn("1 0 0 0"),
|
430
|
+
"Error in setting objective function via set_obj_fnex")
|
431
|
+
assert_equal(nil, @lp.set_rh(0, 6.0),
|
432
|
+
"Should get false on set_rh because row hasn't been set yet")
|
433
|
+
assert_equal(false, @lp.set_rh_range(1, 2.0),
|
434
|
+
"Should get false on _set_rh - row not set yet")
|
435
|
+
@lp.add_constraintex("ROW1", [[1, 1.0]], LPSolve::GE, 5.0)
|
436
|
+
@lp.set_rh(1, 6.0) # Reset above range from 5 to 6.
|
437
|
+
assert @lp.set_rh_range(1, 2.0) # Set lower bound to 6.0 - 2.0
|
438
|
+
assert(@lp.set_maxim, "Should have been able to maximize")
|
439
|
+
assert_equal(0, @lp.solve())
|
440
|
+
# FIXME: test solution
|
441
|
+
assert(@lp.set_minim, "Should have been able to minimmize")
|
442
|
+
assert_equal(0, @lp.solve())
|
443
|
+
# FIXME: test solution
|
444
|
+
end
|
445
|
+
|
446
|
+
# Check set_scaling(), get_scaling()
|
447
|
+
def test_scaling
|
448
|
+
scalemodes = [LPSolve::SCALE_NONE,
|
449
|
+
LPSolve::SCALE_EXTREME,
|
450
|
+
LPSolve::SCALE_RANGE,
|
451
|
+
LPSolve::SCALE_MEAN,
|
452
|
+
LPSolve::SCALE_GEOMETRIC,
|
453
|
+
LPSolve::SCALE_CURTISREID]
|
454
|
+
for scalemode in scalemodes do
|
455
|
+
@lp.set_scaling(scalemode)
|
456
|
+
assert_equal(scalemode, @lp.get_scaling())
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
# Check set_simplextype(), get_simplextype()
|
461
|
+
def test_simplextype
|
462
|
+
simplextypes = [
|
463
|
+
LPSolve::SIMPLEX_PRIMAL_PRIMAL,
|
464
|
+
LPSolve::SIMPLEX_DUAL_PRIMAL,
|
465
|
+
LPSolve::SIMPLEX_PRIMAL_DUAL,
|
466
|
+
LPSolve::SIMPLEX_DUAL_DUAL
|
467
|
+
]
|
468
|
+
assert_equal LPSolve::SIMPLEX_DUAL_PRIMAL, @lp.simplextype
|
469
|
+
for simplextype in simplextypes do
|
470
|
+
@lp.set_simplextype(simplextype)
|
471
|
+
assert_equal(simplextype, @lp.get_simplextype())
|
472
|
+
end
|
473
|
+
for simplextype in simplextypes do
|
474
|
+
@lp.simplextype = simplextype
|
475
|
+
assert_equal(simplextype, @lp.simplextype)
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
# Check set_debug() and is_debug()
|
480
|
+
def test_verbose
|
481
|
+
assert_equal(Fixnum, @lp.get_verbose.class)
|
482
|
+
@lp.set_verbose(LPSolve::CRITICAL)
|
483
|
+
assert_equal LPSolve::CRITICAL, @lp.verbose
|
484
|
+
@lp.verbose = LPSolve::NORMAL
|
485
|
+
end
|
486
|
+
|
487
|
+
def test_solutioncount_limit
|
488
|
+
@lp = LPSolve.new(0, 4)
|
489
|
+
assert_equal(0, @lp.solutioncount,
|
490
|
+
"Haven't solved anything yet so solutioncount should be 0.")
|
491
|
+
assert_equal(1, @lp.solutionlimit,
|
492
|
+
"The default solution limit should be 1.")
|
493
|
+
assert_equal(17445, @lp.bb_rule,
|
494
|
+
"This is the default bb_rule mask. Have defaults changed? ")
|
495
|
+
@lp.solutionlimit = 3
|
496
|
+
assert_equal(3, @lp.get_solutionlimit,
|
497
|
+
"We just previously set the solution limit to 3.")
|
498
|
+
@lp.set_lp_name("Four equal solutions")
|
499
|
+
@lp.set_add_rowmode(true)
|
500
|
+
|
501
|
+
# Maximize:
|
502
|
+
@lp.set_obj_fnex([[1, 100], [2, 100], [3, 100], [4, 100]])
|
503
|
+
|
504
|
+
@lp.add_constraintex("Only two", [[1, 1], [2, 1], [3, 1], [4, 1]],
|
505
|
+
LPSolve::LE, 2)
|
506
|
+
@lp.add_SOS("SOS 1 or 2", 1, 1, [[1, 0], [2, 1]])
|
507
|
+
@lp.add_SOS("SOS 3 or 4", 1, 1, [[3, 0], [4, 1]])
|
508
|
+
@lp.set_binary(1, true)
|
509
|
+
@lp.set_binary(2, true)
|
510
|
+
@lp.set_binary(3, true)
|
511
|
+
@lp.set_binary(4, true)
|
512
|
+
@lp.set_add_rowmode(false)
|
513
|
+
assert(@lp.set_maxim, "Should have been able to maximize")
|
514
|
+
assert_equal(0, @lp.solve)
|
515
|
+
end
|
516
|
+
|
517
|
+
def test_status
|
518
|
+
@lp = LPSolve.new(0, 1)
|
519
|
+
assert_equal("LPSolve method solve() not performed yet.",
|
520
|
+
@lp.get_statustext)
|
521
|
+
assert_equal(0, @lp.solve())
|
522
|
+
assert_equal("OPTIMAL solution", @lp.get_statustext)
|
523
|
+
assert @lp.str_add_constraint("1", LPSolve::EQ, 4)
|
524
|
+
assert @lp.str_add_constraint("2", LPSolve::EQ, 2)
|
525
|
+
assert_equal(2, @lp.solve())
|
526
|
+
assert_equal(2, @lp.status)
|
527
|
+
assert_equal("Model is primal INFEASIBLE", @lp.statustext)
|
528
|
+
end
|
529
|
+
|
530
|
+
end
|