1 | /* $Id: unitTest.cpp 1668 2011-06-13 16:32:06Z forrest $ */ |
---|
2 | // Copyright (C) 2002, International Business Machines |
---|
3 | // Corporation and others. All Rights Reserved. |
---|
4 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
---|
5 | |
---|
6 | // Test individual classes or groups of classes |
---|
7 | |
---|
8 | #include "CbcConfig.h" |
---|
9 | #include "CoinPragma.hpp" |
---|
10 | |
---|
11 | #include <cstdlib> |
---|
12 | #include <cassert> |
---|
13 | #include <vector> |
---|
14 | #include <iostream> |
---|
15 | #include <cstdio> |
---|
16 | |
---|
17 | #include "CoinHelperFunctions.hpp" |
---|
18 | #include "CoinFileIO.hpp" |
---|
19 | |
---|
20 | #ifdef COIN_HAS_CBC |
---|
21 | #include "OsiCbcSolverInterface.hpp" |
---|
22 | #endif |
---|
23 | #ifdef COIN_HAS_OSL |
---|
24 | #include "OsiOslSolverInterface.hpp" |
---|
25 | #endif |
---|
26 | #ifdef COIN_HAS_SPX |
---|
27 | #include "OsiSpxSolverInterface.hpp" |
---|
28 | #endif |
---|
29 | #ifdef COIN_HAS_DYLP |
---|
30 | #include "OsiDylpSolverInterface.hpp" |
---|
31 | #endif |
---|
32 | #ifdef COIN_HAS_GLPK |
---|
33 | #include "OsiGlpkSolverInterface.hpp" |
---|
34 | #endif |
---|
35 | #ifdef COIN_HAS_CLP |
---|
36 | #include "OsiClpSolverInterface.hpp" |
---|
37 | #endif |
---|
38 | #ifdef NDEBUG |
---|
39 | #undef NDEBUG |
---|
40 | #endif |
---|
41 | |
---|
42 | #include "CoinTime.hpp" |
---|
43 | // Function Prototypes. Function definitions is in this file. |
---|
44 | void testingMessage( const char * const msg ); |
---|
45 | |
---|
46 | #ifdef COIN_HAS_CBC |
---|
47 | void CbcMiplibTest (const std::vector<OsiCbcSolverInterface*> & vecEmptySiP, |
---|
48 | const std::string & mpsDir) |
---|
49 | { |
---|
50 | int i ; |
---|
51 | unsigned int m ; |
---|
52 | // See if files exist |
---|
53 | FILE * fp; |
---|
54 | bool doTest = false; |
---|
55 | std::string test1 = mpsDir + "p0033"; |
---|
56 | fp = fopen(test1.c_str(), "r"); |
---|
57 | if (fp) { |
---|
58 | doTest = true; |
---|
59 | fclose(fp); |
---|
60 | } |
---|
61 | if (!doTest && CoinFileInput::haveGzipSupport()) |
---|
62 | { |
---|
63 | test1 += ".gz"; |
---|
64 | fp = fopen(test1.c_str(), "r"); |
---|
65 | if (fp) { |
---|
66 | doTest = true; |
---|
67 | fclose(fp); |
---|
68 | } |
---|
69 | } |
---|
70 | if (!doTest) |
---|
71 | return; |
---|
72 | /* |
---|
73 | Vectors to hold test problem names and characteristics. The objective value |
---|
74 | after optimization (objValue) must agree to the specified tolerance |
---|
75 | (objValueTol). |
---|
76 | */ |
---|
77 | std::vector<std::string> mpsName ; |
---|
78 | std::vector<int> nRows ; |
---|
79 | std::vector<int> nCols ; |
---|
80 | std::vector<double> objValueC ; |
---|
81 | std::vector<double> objValue ; |
---|
82 | std::vector<int> strategy ; |
---|
83 | /* |
---|
84 | And a macro to make the vector creation marginally readable. |
---|
85 | */ |
---|
86 | #define PUSH_MPS(zz_mpsName_zz,\ |
---|
87 | zz_nRows_zz,zz_nCols_zz,zz_objValue_zz,zz_objValueC_zz, \ |
---|
88 | zz_strategy_zz) \ |
---|
89 | mpsName.push_back(zz_mpsName_zz) ; \ |
---|
90 | nRows.push_back(zz_nRows_zz) ; \ |
---|
91 | nCols.push_back(zz_nCols_zz) ; \ |
---|
92 | objValueC.push_back(zz_objValueC_zz) ; \ |
---|
93 | strategy.push_back(zz_strategy_zz) ; \ |
---|
94 | objValue.push_back(zz_objValue_zz) ; |
---|
95 | |
---|
96 | /* |
---|
97 | Load up the problem vector. Note that the row counts here include the |
---|
98 | objective function. |
---|
99 | |
---|
100 | Set HOWMANY to 0 for no test, 1 for some, 2 for many, 3 for all. |
---|
101 | */ |
---|
102 | #define HOWMANY 1 |
---|
103 | #if HOWMANY |
---|
104 | #if HOWMANY>1 |
---|
105 | PUSH_MPS("10teams", 230, 2025, 924, 917, 7) |
---|
106 | #endif |
---|
107 | PUSH_MPS("air03", 124, 10757, 340160, 338864.25, 7) |
---|
108 | #if HOWMANY==3 |
---|
109 | PUSH_MPS("air04", 823, 8904, 56137, 55535.436, 8) |
---|
110 | PUSH_MPS("air05", 426, 7195, 26374, 25877.609, 8) |
---|
111 | #endif |
---|
112 | // PUSH_MPS("arki001",1048,1388,7580813.0459,7579599.80787,7) |
---|
113 | PUSH_MPS("bell3a", 123, 133, 878430.32, 862578.64, 7) |
---|
114 | #if HOWMANY>1 |
---|
115 | PUSH_MPS("bell5", 91, 104, 8966406.49, 8608417.95, 7) |
---|
116 | #endif |
---|
117 | PUSH_MPS("blend2", 274, 353, 7.598985, 6.9156751140, 7) |
---|
118 | #if HOWMANY>1 |
---|
119 | PUSH_MPS("cap6000", 2176, 6000, -2451377, -2451537.325, 7) |
---|
120 | #endif |
---|
121 | // PUSH_MPS("dano3mip",3202,13873,728.1111,576.23162474,7) |
---|
122 | // PUSH_MPS("danoint",664,521,65.67,62.637280418,7) |
---|
123 | PUSH_MPS("dcmulti", 290, 548, 188182, 183975.5397, 7) |
---|
124 | PUSH_MPS("dsbmip", 1182, 1886, -305.19817501, -305.19817501, 7) |
---|
125 | PUSH_MPS("egout", 98, 141, 568.101, 149.589, 7) |
---|
126 | PUSH_MPS("enigma", 21, 100, 0.0, 0.0, 7) |
---|
127 | #if HOWMANY==3 |
---|
128 | PUSH_MPS("fast0507", 507, 63009, 174, 172.14556668, 7) |
---|
129 | #endif |
---|
130 | PUSH_MPS("fiber", 363, 1298, 405935.18000, 156082.51759, 7) |
---|
131 | #if HOWMANY>1 |
---|
132 | PUSH_MPS("fixnet6", 478, 878, 3983, 1200.88, 7) |
---|
133 | #endif |
---|
134 | PUSH_MPS("flugpl", 18, 18, 1201500, 1167185.7, 7) |
---|
135 | PUSH_MPS("gen", 780, 870, 112313, 112130.0, 7) |
---|
136 | #if HOWMANY>1 |
---|
137 | PUSH_MPS("gesa2", 1392, 1224, 25779856.372, 25476489.678, 7) |
---|
138 | PUSH_MPS("gesa2_o", 1248, 1224, 25779856.372, 25476489.678, 7) |
---|
139 | #endif |
---|
140 | PUSH_MPS("gesa3", 1368, 1152, 27991042.648, 27833632.451, 7) |
---|
141 | PUSH_MPS("gesa3_o", 1224, 1152, 27991042.648, 27833632.451, 7) |
---|
142 | PUSH_MPS("gt2", 29, 188, 21166.000, 13460.233074, 7) |
---|
143 | #if HOWMANY==3 |
---|
144 | PUSH_MPS("harp2", 112, 2993, -73899798.00, -74353341.502, 7) |
---|
145 | #endif |
---|
146 | PUSH_MPS("khb05250", 101, 1350, 106940226, 95919464.0, 7) |
---|
147 | #if HOWMANY>1 |
---|
148 | PUSH_MPS("l152lav", 97, 1989, 4722, 4656.36, 7) |
---|
149 | #endif |
---|
150 | PUSH_MPS("lseu", 28, 89, 1120, 834.68, 7) |
---|
151 | PUSH_MPS("misc03", 96, 160, 3360, 1910., 7) |
---|
152 | PUSH_MPS("misc06", 820, 1808, 12850.8607, 12841.6, 7) |
---|
153 | #if HOWMANY>1 |
---|
154 | PUSH_MPS("misc07", 212, 260, 2810, 1415.0, 7) |
---|
155 | PUSH_MPS("mitre", 2054, 10724, 115155, 114740.5184, 7) |
---|
156 | #endif |
---|
157 | PUSH_MPS("mod008", 6, 319, 307, 290.9, 7) |
---|
158 | PUSH_MPS("mod010", 146, 2655, 6548, 6532.08, 7) |
---|
159 | #if HOWMANY==3 |
---|
160 | PUSH_MPS("mod011", 4480, 10958, -54558535, -62121982.55, 7) |
---|
161 | PUSH_MPS("modglob", 291, 422, 20740508, 20430947., 7) |
---|
162 | PUSH_MPS("noswot", 182, 128, -43, -43.0, 7) |
---|
163 | #endif |
---|
164 | #if HOWMANY>1 |
---|
165 | PUSH_MPS("nw04", 36, 87482, 16862, 16310.66667, 7) |
---|
166 | #endif |
---|
167 | PUSH_MPS("p0033", 16, 33, 3089, 2520.57, 7) |
---|
168 | PUSH_MPS("p0201", 133, 201, 7615, 6875.0, 7) |
---|
169 | PUSH_MPS("p0282", 241, 282, 258411, 176867.50, 7) |
---|
170 | PUSH_MPS("p0548", 176, 548, 8691, 315.29, 7) |
---|
171 | PUSH_MPS("p2756", 755, 2756, 3124, 2688.75, 7) |
---|
172 | #if HOWMANY==3 |
---|
173 | PUSH_MPS("pk1", 45, 86, 11.0, 0.0, 7) |
---|
174 | #endif |
---|
175 | #if HOWMANY>1 |
---|
176 | PUSH_MPS("pp08a", 136, 240, 7350.0, 2748.3452381, 7) |
---|
177 | PUSH_MPS("pp08aCUTS", 246, 240, 7350.0, 5480.6061563, 7) |
---|
178 | #endif |
---|
179 | #if HOWMANY==3 |
---|
180 | PUSH_MPS("qiu", 1192, 840, -132.873137, -931.638857, 7) |
---|
181 | #endif |
---|
182 | PUSH_MPS("qnet1", 503, 1541, 16029.692681, 14274.102667, 7) |
---|
183 | PUSH_MPS("qnet1_o", 456, 1541, 16029.692681, 12095.571667, 7) |
---|
184 | PUSH_MPS("rentacar", 6803, 9557, 30356761, 28806137.644, 7) |
---|
185 | PUSH_MPS("rgn", 24, 180, 82.1999, 48.7999, 7) |
---|
186 | #if HOWMANY==3 |
---|
187 | PUSH_MPS("rout", 291, 556, 1077.56, 981.86428571, 7) |
---|
188 | PUSH_MPS("set1ch", 492, 712, 54537.75, 32007.73, 7) |
---|
189 | #endif |
---|
190 | // PUSH_MPS("seymour",4944,1372,423,403.84647413,7) |
---|
191 | PUSH_MPS("stein27", 118, 27, 18, 13.0, 7) |
---|
192 | #if HOWMANY>1 |
---|
193 | PUSH_MPS("stein45", 331, 45, 30, 22.0, 7) |
---|
194 | #endif |
---|
195 | PUSH_MPS("vpm1", 234, 378, 20, 15.4167, 7) |
---|
196 | PUSH_MPS("vpm2", 234, 378, 13.75, 9.8892645972, 7) |
---|
197 | #endif |
---|
198 | #undef PUSH_MPS |
---|
199 | |
---|
200 | /* |
---|
201 | Create a vector of solver interfaces that we can use to run the test |
---|
202 | problems. The strategy is to create a fresh clone of the `empty' solvers |
---|
203 | from vecEmptySiP for each problem, then proceed in stages: read the MPS |
---|
204 | file, solve the problem, check the solution. If there are multiple |
---|
205 | solvers in vecSiP, the results of each solver are compared with its |
---|
206 | neighbors in the vector. |
---|
207 | */ |
---|
208 | int numberSolvers = vecEmptySiP.size(); |
---|
209 | std::vector<OsiSolverInterface*> vecSiP(numberSolvers) ; |
---|
210 | |
---|
211 | // Create vector to store a name for each solver interface |
---|
212 | // and a count on the number of problems the solver interface solved. |
---|
213 | std::vector<std::string> siName; |
---|
214 | std::vector<int> numProbSolved; |
---|
215 | std::vector<double> timeTaken; |
---|
216 | for ( i = 0; i < numberSolvers; i++ ) { |
---|
217 | std::string name; |
---|
218 | vecEmptySiP[i]->getStrParam(OsiSolverName, name); |
---|
219 | siName.push_back(name); |
---|
220 | numProbSolved.push_back(0); |
---|
221 | timeTaken.push_back(0.0); |
---|
222 | } |
---|
223 | |
---|
224 | /* |
---|
225 | Open the main loops. Outer loop steps through MPS problems, inner loop |
---|
226 | steps through solvers. |
---|
227 | */ |
---|
228 | for (m = 0 ; m < mpsName.size() ; m++) { |
---|
229 | std::cerr << " processing mps file: " << mpsName[m] |
---|
230 | << " (" << m + 1 << " out of " << mpsName.size() << ")" |
---|
231 | << std::endl ; |
---|
232 | for (i = vecSiP.size() - 1 ; i >= 0 ; --i) { |
---|
233 | vecSiP[i] = vecEmptySiP[i]->clone() ; |
---|
234 | /* |
---|
235 | Stage 1: Read the MPS file into the solver interface. |
---|
236 | |
---|
237 | As a basic check, make sure the size of the constraint matrix is correct. |
---|
238 | */ |
---|
239 | |
---|
240 | std::string fn = mpsDir + mpsName[m] ; |
---|
241 | vecSiP[i]->readMps(fn.c_str(), "") ; |
---|
242 | |
---|
243 | vecSiP[i]->setObjSense(1.0) ; |
---|
244 | |
---|
245 | int nr = vecSiP[i]->getNumRows() ; |
---|
246 | int nc = vecSiP[i]->getNumCols() ; |
---|
247 | assert(nr == nRows[m]) ; |
---|
248 | assert(nc == nCols[m]) ; |
---|
249 | /* |
---|
250 | Stage 2: Call the solver to get a solution for the LP relaxation. |
---|
251 | */ |
---|
252 | double startTime = CoinCpuTime(); |
---|
253 | OsiCbcSolverInterface * integerSolver = |
---|
254 | dynamic_cast<OsiCbcSolverInterface *>(vecSiP[i]) ; |
---|
255 | assert(integerSolver); |
---|
256 | integerSolver->initialSolve(); |
---|
257 | /* |
---|
258 | Stage 3: Call the solver to perform branch and cut. |
---|
259 | |
---|
260 | We call each solver, then check the return code and objective. |
---|
261 | Limits are 50000 nodes and one hour of time. |
---|
262 | */ |
---|
263 | |
---|
264 | integerSolver->setMaximumNodes(50000); |
---|
265 | integerSolver->setMaximumSeconds(60*60); |
---|
266 | integerSolver->getModelPtr()->messageHandler()->setLogLevel(1) ; |
---|
267 | integerSolver->branchAndBound(); |
---|
268 | |
---|
269 | double timeOfSolution = CoinCpuTime() - startTime; |
---|
270 | if (!integerSolver->status()) { |
---|
271 | double soln = integerSolver->getObjValue(); |
---|
272 | CoinRelFltEq eq(1.0e-3) ; |
---|
273 | if (eq(soln, objValue[m])) { |
---|
274 | std::cerr |
---|
275 | << siName[i] << " " |
---|
276 | << soln << " = " << objValue[m] << " ; okay"; |
---|
277 | numProbSolved[i]++; |
---|
278 | } else { |
---|
279 | std::cerr << siName[i] << " " << soln << " != " << objValue[m] << "; error=" ; |
---|
280 | std::cerr << fabs(objValue[m] - soln); |
---|
281 | } |
---|
282 | } else { |
---|
283 | std::cerr << "error; too many nodes" ; |
---|
284 | } |
---|
285 | std::cerr << " - took " << timeOfSolution << " seconds." << std::endl; |
---|
286 | timeTaken[i] += timeOfSolution; |
---|
287 | delete integerSolver; |
---|
288 | } |
---|
289 | } |
---|
290 | |
---|
291 | const int siName_size = siName.size(); |
---|
292 | for ( i = 0; i < siName_size; i++ ) { |
---|
293 | std::cerr |
---|
294 | << siName[i] |
---|
295 | << " solved " |
---|
296 | << numProbSolved[i] |
---|
297 | << " out of " |
---|
298 | << objValue.size() |
---|
299 | << " and took " |
---|
300 | << timeTaken[i] |
---|
301 | << " seconds." |
---|
302 | << std::endl; |
---|
303 | } |
---|
304 | } |
---|
305 | #endif // COIN_HAS_CBC |
---|
306 | |
---|
307 | //---------------------------------------------------------------- |
---|
308 | // unitTest [-miplibDir=V2] |
---|
309 | // |
---|
310 | // where: |
---|
311 | // -miplibDir: directory containing miplib files |
---|
312 | // Default value V2="./examples/miplib3" |
---|
313 | // |
---|
314 | // All parameters are optional. |
---|
315 | //---------------------------------------------------------------- |
---|
316 | |
---|
317 | int mainTest (int argc, const char *argv[]) |
---|
318 | { |
---|
319 | int i; |
---|
320 | |
---|
321 | |
---|
322 | // define valid parameter keywords |
---|
323 | std::set<std::string> definedKeyWords; |
---|
324 | definedKeyWords.insert("-miplibDir"); |
---|
325 | |
---|
326 | // Create a map of parameter keys and associated data |
---|
327 | std::map<std::string, std::string> parms; |
---|
328 | for ( i = 1; i < argc; i++ ) { |
---|
329 | std::string parm(argv[i]); |
---|
330 | std::string key, value; |
---|
331 | unsigned int eqPos = parm.find('='); |
---|
332 | |
---|
333 | // Does parm contain and '=' |
---|
334 | if ( eqPos == std::string::npos ) { |
---|
335 | //Parm does not contain '=' |
---|
336 | key = parm; |
---|
337 | } else { |
---|
338 | key = parm.substr(0, eqPos); |
---|
339 | value = parm.substr(eqPos + 1); |
---|
340 | } |
---|
341 | |
---|
342 | // Is specifed key valid? |
---|
343 | if ( definedKeyWords.find(key) == definedKeyWords.end() ) { |
---|
344 | // invalid key word. |
---|
345 | // Write help text |
---|
346 | std::cerr << "Undefined parameter \"" << key << "\".\n"; |
---|
347 | std::cerr << "Correct usage: \n"; |
---|
348 | std::cerr << " unitTest [-miplibDir=V2] \n"; |
---|
349 | std::cerr << " where:\n"; |
---|
350 | std::cerr << " -miplibDir: directory containing miplib files\n"; |
---|
351 | std::cerr << " Default value V2=\"./Data/miplib3\"\n"; |
---|
352 | return 1; |
---|
353 | } |
---|
354 | parms[key] = value; |
---|
355 | } |
---|
356 | |
---|
357 | const char dirsep = CoinFindDirSeparator(); |
---|
358 | |
---|
359 | // Set directory containing miplib data files. |
---|
360 | std::string miplibDir; |
---|
361 | if (parms.find("-miplibDir") != parms.end()) |
---|
362 | miplibDir = parms["-miplibDir"] + dirsep; |
---|
363 | else |
---|
364 | miplibDir = dirsep == '/' ? "./Data/miplib3/" : ".\\Data\\miplib3\\"; |
---|
365 | #ifdef COIN_HAS_CBC |
---|
366 | |
---|
367 | { |
---|
368 | // Create vector of solver interfaces |
---|
369 | std::vector<OsiCbcSolverInterface*> vecSi; |
---|
370 | CbcStrategyDefault strategy(0); |
---|
371 | # if COIN_HAS_OSL |
---|
372 | OsiSolverInterface * oslSi = new OsiOslSolverInterface; |
---|
373 | vecSi.push_back(new OsiCbcSolverInterface(oslSi, &strategy)); |
---|
374 | #endif |
---|
375 | # if COIN_HAS_SPX |
---|
376 | OsiSolverInterface * spxSi = new OsiSpxSolverInterface; |
---|
377 | vecSi.push_back(new OsiCbcSolverInterface(spxSi, &strategy)); |
---|
378 | #endif |
---|
379 | # if COIN_HAS_CLP |
---|
380 | OsiSolverInterface *clpSi = new OsiClpSolverInterface ; |
---|
381 | /* Quiet, already! */ |
---|
382 | clpSi->setHintParam(OsiDoReducePrint, true, OsiHintDo) ; |
---|
383 | vecSi.push_back(new OsiCbcSolverInterface(clpSi, &strategy)); |
---|
384 | #endif |
---|
385 | # if COIN_HAS_DYLP |
---|
386 | OsiSolverInterface * dylpSi = new OsiDylpSolverInterface; |
---|
387 | vecSi.push_back(new OsiCbcSolverInterface(dylpSi, &strategy)); |
---|
388 | #endif |
---|
389 | # if COIN_HAS_GLPK |
---|
390 | OsiSolverInterface * glpkSi = new OsiGlpkSolverInterface; |
---|
391 | vecSi.push_back(new OsiCbcSolverInterface(glpkSi, &strategy)); |
---|
392 | #endif |
---|
393 | |
---|
394 | testingMessage( "Testing some miplib stuff\n" ); |
---|
395 | CbcMiplibTest(vecSi, miplibDir); |
---|
396 | |
---|
397 | unsigned int i; |
---|
398 | for (i = 0; i < vecSi.size(); i++) |
---|
399 | delete vecSi[i]; |
---|
400 | } |
---|
401 | #else // COIN_HAS_CBC |
---|
402 | std::cerr |
---|
403 | << "cbc has been built without OsiCbc support. To enable the -miplib\n" |
---|
404 | << "option, you must enable libOsiCbc in Makefile.location, then\n" |
---|
405 | << "execute the command `make clean cbc' to rebuild the cbc program." |
---|
406 | << std::endl ; |
---|
407 | #endif // COIN_HAS_CBC |
---|
408 | testingMessage( "All tests completed successfully\n" ); |
---|
409 | return 0; |
---|
410 | } |
---|
411 | |
---|
412 | |
---|
413 | // Display message on stdout and stderr |
---|
414 | void testingMessage( const char * const msg ) |
---|
415 | { |
---|
416 | std::cerr << msg << std::endl ; |
---|
417 | // std::cout << msg << std::endl ; |
---|
418 | } |
---|
419 | |
---|