lpsolve 5.5.10.i
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/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
|