1 | // $Id$ |
---|
2 | // Copyright (C) 2000, 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 | #include "CoinPragma.hpp" |
---|
7 | |
---|
8 | #include "OsiConfig.h" |
---|
9 | |
---|
10 | #ifdef NDEBUG |
---|
11 | #undef NDEBUG |
---|
12 | #endif |
---|
13 | |
---|
14 | #include <cassert> |
---|
15 | #include <cstdio> |
---|
16 | #include <iostream> |
---|
17 | #include <map> |
---|
18 | |
---|
19 | #include "OsiUnitTests.hpp" |
---|
20 | #include "OsiRowCutDebugger.hpp" |
---|
21 | |
---|
22 | #include "CoinError.hpp" |
---|
23 | |
---|
24 | #include "OsiCbcSolverInterface.hpp" |
---|
25 | |
---|
26 | namespace { |
---|
27 | |
---|
28 | // Display message on stdout and stderr. Flush cout buffer before printing the |
---|
29 | // message, so that output comes out in order in spite of buffered cout. |
---|
30 | |
---|
31 | void testingMessage( const char * const msg ) |
---|
32 | { |
---|
33 | std::cout.flush() ; |
---|
34 | std::cerr <<msg; |
---|
35 | //cout <<endl <<"*****************************************" |
---|
36 | // <<endl <<msg <<endl; |
---|
37 | } |
---|
38 | |
---|
39 | |
---|
40 | /* |
---|
41 | Utility routine to process command line parameters. An unrecognised parameter |
---|
42 | will trigger the help message and a return value of false. |
---|
43 | |
---|
44 | This should be replaced with the one of the standard CoinUtils parameter |
---|
45 | mechanisms. |
---|
46 | */ |
---|
47 | bool processParameters (int argc, const char **argv, |
---|
48 | std::map<std::string,std::string> &parms) |
---|
49 | |
---|
50 | { |
---|
51 | assert(argc >= 1); |
---|
52 | assert(argv != NULL); |
---|
53 | /* |
---|
54 | Initialise the parameter keywords. |
---|
55 | */ |
---|
56 | std::set<std::string> definedKeyWords; |
---|
57 | definedKeyWords.insert("-cerr2cout"); |
---|
58 | definedKeyWords.insert("-mpsDir"); |
---|
59 | definedKeyWords.insert("-netlibDir"); |
---|
60 | definedKeyWords.insert("-testOsiSolverInterface"); |
---|
61 | definedKeyWords.insert("-nobuf"); |
---|
62 | /* |
---|
63 | Set default values for data directories. |
---|
64 | */ |
---|
65 | std::string dirsep(1,CoinFindDirSeparator()) ; |
---|
66 | std::string upOne = ".."+dirsep ; |
---|
67 | std::string pathTmp ; |
---|
68 | /* |
---|
69 | Establish likely defaults for the Sample and Miplib directories. |
---|
70 | */ |
---|
71 | # ifdef SAMPLEDIR |
---|
72 | pathTmp = SAMPLEDIR ; |
---|
73 | # else |
---|
74 | pathTmp = upOne+upOne+"Data"+dirsep+"Sample" ; |
---|
75 | # endif |
---|
76 | parms["-mpsDir"] = pathTmp ; |
---|
77 | # ifdef NETLIBDIR |
---|
78 | pathTmp = NETLIBDIR ; |
---|
79 | # else |
---|
80 | pathTmp = upOne+upOne+"Data"+dirsep+"Netlib" ; |
---|
81 | # endif |
---|
82 | parms["-netlibDir"] = pathTmp ; |
---|
83 | /* |
---|
84 | Read the command line parameters and fill a map of parameter keys and |
---|
85 | associated data. The parser allows for parameters which are only a keyword, |
---|
86 | or parameters of the form keyword=value (no spaces). |
---|
87 | */ |
---|
88 | for (int i = 1 ; i < argc ; i++) |
---|
89 | { std::string parm(argv[i]) ; |
---|
90 | std::string key,value ; |
---|
91 | std::string::size_type eqPos = parm.find('='); |
---|
92 | |
---|
93 | if (eqPos == std::string::npos) |
---|
94 | { key = parm ; } |
---|
95 | else |
---|
96 | { key = parm.substr(0,eqPos) ; |
---|
97 | value = parm.substr(eqPos+1) ; } |
---|
98 | /* |
---|
99 | Is the specifed key valid? |
---|
100 | */ |
---|
101 | if (definedKeyWords.find(key) == definedKeyWords.end()) |
---|
102 | { std::cerr << "Undefined parameter \"" << key << "\"." << std::endl ; |
---|
103 | std::cerr |
---|
104 | << "Usage: " << argv[0] |
---|
105 | << " [-nobuf] [-mpsDir=V1] [-netlibDir=V2] " |
---|
106 | << "[-testOsiSolverInterface] " << std::endl ; |
---|
107 | std::cerr << " where:" << std::endl ; |
---|
108 | std::cerr |
---|
109 | << " " |
---|
110 | << "-cerr2cout: redirect cerr to cout; sometimes useful." << std::endl |
---|
111 | << "\t" << "to synchronise cout & cerr." << std::endl ; |
---|
112 | std::cerr |
---|
113 | << " " |
---|
114 | << "-mpsDir: directory containing mps test files." << std::endl |
---|
115 | << "\t" << "Default value V1=\"../../Data/Sample\"" << std::endl ; |
---|
116 | std::cerr |
---|
117 | << " " |
---|
118 | << "-netlibDir: directory containing netlib files." << std::endl |
---|
119 | << "\t" << "Default value V2=\"../../Data/Netlib\"" << std::endl ; |
---|
120 | std::cerr |
---|
121 | << " " |
---|
122 | << "-testOsiSolverInterface: " |
---|
123 | << "run each OSI on the netlib problem set." << std::endl |
---|
124 | << "\t" |
---|
125 | << "Default is to not run the netlib problem set." << std::endl ; |
---|
126 | std::cerr |
---|
127 | << " " |
---|
128 | << "-nobuf: use unbuffered output." << std::endl |
---|
129 | << "\t" << "Default is buffered output." << std::endl ; |
---|
130 | |
---|
131 | return (false) ; } |
---|
132 | /* |
---|
133 | Valid keyword; stash the value for later reference. |
---|
134 | */ |
---|
135 | parms[key]=value ; } |
---|
136 | /* |
---|
137 | Tack the directory separator onto the data directories so we don't have to |
---|
138 | worry about it later. |
---|
139 | */ |
---|
140 | parms["-mpsDir"] += dirsep ; |
---|
141 | parms["-netlibDir"] += dirsep ; |
---|
142 | /* |
---|
143 | Did the user request unbuffered i/o? It seems we need to go after this |
---|
144 | through stdio --- using pubsetbuf(0,0) on the C++ streams has no |
---|
145 | discernible affect. Nor, for that matter, did setting the unitbuf flag on |
---|
146 | the streams. Why? At a guess, sync_with_stdio connects the streams to the |
---|
147 | stdio buffers, and the C++ side isn't programmed to change them? |
---|
148 | */ |
---|
149 | if (parms.find("-nobuf") != parms.end()) |
---|
150 | { // std::streambuf *coutBuf, *cerrBuf ; |
---|
151 | // coutBuf = std::cout.rdbuf() ; |
---|
152 | // coutBuf->pubsetbuf(0,0) ; |
---|
153 | // cerrBuf = std::cerr.rdbuf() ; |
---|
154 | // cerrBuf->pubsetbuf(0,0) ; |
---|
155 | setbuf(stderr,0) ; |
---|
156 | setbuf(stdout,0) ; } |
---|
157 | /* |
---|
158 | Did the user request a redirect for cerr? This must occur before any i/o is |
---|
159 | performed. |
---|
160 | */ |
---|
161 | if (parms.find("-cerr2cout") != parms.end()) |
---|
162 | { std::cerr.rdbuf(std::cout.rdbuf()) ; } |
---|
163 | |
---|
164 | return (true) ; } |
---|
165 | |
---|
166 | |
---|
167 | } // end file-local namespace |
---|
168 | |
---|
169 | |
---|
170 | |
---|
171 | //---------------------------------------------------------------- |
---|
172 | // unitTest [-nobuf] [-mpsDir=V1] [-netlibDir=V2] [-testOsiSolverInterface] |
---|
173 | // |
---|
174 | // where: |
---|
175 | // -nobuf: remove buffering on cout (stdout); useful to keep cout and cerr |
---|
176 | // messages synchronised when redirecting output to a file or pipe. |
---|
177 | // -mpsDir: directory containing mps test files |
---|
178 | // Default value V1="../../Data/Sample" |
---|
179 | // -netlibDir: directory containing netlib files |
---|
180 | // Default value V2="../../Data/Netlib" |
---|
181 | // -testOsiSolverInterface |
---|
182 | // If specified, then OsiSolveInterface::unitTest |
---|
183 | // is skipped over and not run. |
---|
184 | // |
---|
185 | // All parameters are optional. |
---|
186 | //---------------------------------------------------------------- |
---|
187 | |
---|
188 | int main (int argc, const char *argv[]) |
---|
189 | |
---|
190 | { int totalErrCnt = 0; |
---|
191 | |
---|
192 | /* |
---|
193 | Start off with various bits of initialisation that don't really belong |
---|
194 | anywhere else. |
---|
195 | |
---|
196 | First off, synchronise C++ stream i/o with C stdio. This makes debugging |
---|
197 | output a bit more comprehensible. It still suffers from interleave of cout |
---|
198 | (stdout) and cerr (stderr), but -nobuf deals with that. |
---|
199 | */ |
---|
200 | std::ios::sync_with_stdio() ; |
---|
201 | /* |
---|
202 | Suppress an popup window that Windows shows in response to a crash. See |
---|
203 | note at head of file. |
---|
204 | */ |
---|
205 | WindowsErrorPopupBlocker(); |
---|
206 | /* |
---|
207 | Process command line parameters. |
---|
208 | */ |
---|
209 | std::map<std::string,std::string> parms ; |
---|
210 | |
---|
211 | if (processParameters(argc,argv,parms) == false) |
---|
212 | { return (1) ; } |
---|
213 | |
---|
214 | std::string mpsDir = parms["-mpsDir"] ; |
---|
215 | std::string netlibDir = parms["-netlibDir"] ; |
---|
216 | |
---|
217 | try { |
---|
218 | /* |
---|
219 | Test Osi{Row,Col}Cut routines. |
---|
220 | */ |
---|
221 | { |
---|
222 | OsiCbcSolverInterface cbcSi; |
---|
223 | testingMessage( "Testing OsiRowCut with OsiCbcSolverInterface\n" ); |
---|
224 | OsiRowCutUnitTest(&cbcSi,mpsDir); |
---|
225 | } |
---|
226 | { |
---|
227 | OsiCbcSolverInterface cbcSi; |
---|
228 | testingMessage( "Testing OsiColCut with OsiCbcSolverInterface\n" ); |
---|
229 | OsiColCutUnitTest(&cbcSi,mpsDir); |
---|
230 | } |
---|
231 | { |
---|
232 | OsiCbcSolverInterface cbcSi; |
---|
233 | testingMessage( "Testing OsiRowCutDebugger with OsiCbcSolverInterface\n" ); |
---|
234 | OsiRowCutDebuggerUnitTest(&cbcSi,mpsDir); |
---|
235 | } |
---|
236 | |
---|
237 | /* |
---|
238 | Run the OsiXXX class test. It's up to the OsiCbc implementor |
---|
239 | to decide whether or not to run OsiSolverInterfaceCommonUnitTest. Arguably |
---|
240 | this should be required. |
---|
241 | */ |
---|
242 | testingMessage( "Testing OsiCbcSolverInterface\n" ); |
---|
243 | OsiCbcSolverInterfaceUnitTest(mpsDir,netlibDir); |
---|
244 | |
---|
245 | /* |
---|
246 | We have run the specialised unit test. Check now to see if we need to |
---|
247 | run through the Netlib problems. |
---|
248 | */ |
---|
249 | if (parms.find("-testOsiSolverInterface") != parms.end()) |
---|
250 | { |
---|
251 | // Create vector of solver interfaces |
---|
252 | std::vector<OsiSolverInterface*> vecSi(1, new OsiCbcSolverInterface); |
---|
253 | |
---|
254 | testingMessage( "Testing OsiSolverInterface on Netlib problems.\n" ); |
---|
255 | OsiSolverInterfaceMpsUnitTest(vecSi,netlibDir); |
---|
256 | |
---|
257 | delete vecSi[0]; |
---|
258 | } |
---|
259 | else { |
---|
260 | testingMessage( "***Skipped Testing of OsiCbcSolverInterface on Netlib problems***\n" ); |
---|
261 | testingMessage( "***use -testOsiSolverInterface to run them.***\n" ); |
---|
262 | } |
---|
263 | } catch (CoinError& error) { |
---|
264 | std::cout.flush(); |
---|
265 | std::cerr << "Caught CoinError exception: "; |
---|
266 | error.print(true); |
---|
267 | totalErrCnt += 1; |
---|
268 | } |
---|
269 | /* |
---|
270 | We're done. Report on the results. |
---|
271 | */ |
---|
272 | if (totalErrCnt) |
---|
273 | { std::cout.flush() ; |
---|
274 | std::cerr |
---|
275 | << "Tests completed with " << totalErrCnt << " errors." << std::endl ; |
---|
276 | } else |
---|
277 | { testingMessage("All tests completed successfully\n") ; } |
---|
278 | return totalErrCnt; |
---|
279 | } |
---|