summaryrefslogtreecommitdiff
path: root/build/Bonmin/include/coin/OsiUnitTests.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'build/Bonmin/include/coin/OsiUnitTests.hpp')
-rw-r--r--build/Bonmin/include/coin/OsiUnitTests.hpp374
1 files changed, 374 insertions, 0 deletions
diff --git a/build/Bonmin/include/coin/OsiUnitTests.hpp b/build/Bonmin/include/coin/OsiUnitTests.hpp
new file mode 100644
index 0000000..fbb4fc1
--- /dev/null
+++ b/build/Bonmin/include/coin/OsiUnitTests.hpp
@@ -0,0 +1,374 @@
+// Copyright (C) 2010
+// All Rights Reserved.
+// This code is licensed under the terms of the Eclipse Public License (EPL).
+
+/*! \file OsiUnitTests.hpp
+
+ Utility methods for OSI unit tests.
+*/
+
+#ifndef OSISOLVERINTERFACETEST_HPP_
+#define OSISOLVERINTERFACETEST_HPP_
+
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <list>
+#include <map>
+
+class OsiSolverInterface;
+class CoinPackedVectorBase;
+
+/** A function that tests that a lot of problems given in MPS files (mostly the NETLIB problems) solve properly with all the specified solvers.
+ *
+ * The routine creates a vector of NetLib problems (problem name, objective,
+ * various other characteristics), and a vector of solvers to be tested.
+ *
+ * Each solver is run on each problem. The run is deemed successful if the
+ * solver reports the correct problem size after loading and returns the
+ * correct objective value after optimization.
+
+ * If multiple solvers are available, the results are compared pairwise against
+ * the results reported by adjacent solvers in the solver vector. Due to
+ * limitations of the volume solver, it must be the last solver in vecEmptySiP.
+ */
+void OsiSolverInterfaceMpsUnitTest
+ (const std::vector<OsiSolverInterface*> & vecEmptySiP,
+ const std::string& mpsDir);
+
+/** A function that tests the methods in the OsiSolverInterface class.
+ * Some time ago, if this method is compiled with optimization,
+ * the compilation took 10-15 minutes and the machine pages (has 256M core memory!)...
+ */
+void OsiSolverInterfaceCommonUnitTest
+ (const OsiSolverInterface* emptySi,
+ const std::string& mpsDir,
+ const std::string& netlibDir);
+
+/** A function that tests the methods in the OsiColCut class. */
+void OsiColCutUnitTest
+ (const OsiSolverInterface * baseSiP,
+ const std::string & mpsDir);
+
+/** A function that tests the methods in the OsiRowCut class. */
+void OsiRowCutUnitTest
+ (const OsiSolverInterface * baseSiP,
+ const std::string & mpsDir);
+
+/** A function that tests the methods in the OsiRowCutDebugger class. */
+void OsiRowCutDebuggerUnitTest
+ (const OsiSolverInterface * siP,
+ const std::string & mpsDir);
+
+/** A function that tests the methods in the OsiCuts class. */
+void OsiCutsUnitTest();
+
+/// A namespace so we can define a few `global' variables to use during tests.
+namespace OsiUnitTest {
+
+class TestOutcomes;
+
+/*! \brief Verbosity level of unit tests
+
+ 0 (default) for minimal output; larger numbers produce more output
+*/
+extern unsigned int verbosity;
+
+/*! \brief Behaviour on failing a test
+
+ - 0 (= default) continue
+ - 1 press any key to continue
+ - 2 stop with abort()
+*/
+extern unsigned int haltonerror;
+
+/*! \brief Test outcomes
+
+ A global TestOutcomes object to store test outcomes during the run of the unit test
+ for an OSI.
+ */
+extern TestOutcomes outcomes;
+
+/*! \brief Print an error message
+
+ Formatted as "XxxSolverInterface testing issue: message" where Xxx is the string
+ provided as \p solverName.
+
+ Flushes std::cout before printing to std::cerr.
+*/
+void failureMessage(const std::string &solverName,
+ const std::string &message) ;
+/// \overload
+void failureMessage(const OsiSolverInterface &si,
+ const std::string &message) ;
+
+/*! \brief Print an error message, specifying the test name and condition
+
+ Formatted as "XxxSolverInterface testing issue: testname failed: testcond" where
+ Xxx is the OsiStrParam::OsiSolverName parameter of the \p si.
+ Flushes std::cout before printing to std::cerr.
+*/
+void failureMessage(const std::string &solverName,
+ const std::string &testname, const std::string &testcond) ;
+
+/// \overload
+void failureMessage(const OsiSolverInterface &si,
+ const std::string &testname, const std::string &testcond) ;
+
+/*! \brief Print a message.
+
+ Prints the message as given. Flushes std::cout before printing to std::cerr.
+*/
+void testingMessage(const char *const msg) ;
+
+/*! \brief Utility method to check equality
+
+ Tests for equality using CoinRelFltEq with tolerance \p tol. Understands the
+ notion of solver infinity and obtains the value for infinity from the solver
+ interfaces supplied as parameters.
+*/
+bool equivalentVectors(const OsiSolverInterface * si1,
+ const OsiSolverInterface * si2,
+ double tol, const double * v1, const double * v2, int size) ;
+
+/*! \brief Compare two problems for equality
+
+ Compares the problems held in the two solvers: constraint matrix, row and column
+ bounds, column type, and objective. Rows are checked using upper and lower bounds
+ and using sense, bound, and range.
+*/
+bool compareProblems(OsiSolverInterface *osi1, OsiSolverInterface *osi2) ;
+
+/*! \brief Compare a packed vector with an expanded vector
+
+ Checks that all values present in the packed vector are present in the full vector
+ and checks that there are no extra entries in the full vector. Uses CoinRelFltEq
+ with the default tolerance.
+*/
+bool isEquivalent(const CoinPackedVectorBase &pv, int n, const double *fv) ;
+
+/*! \brief Process command line parameters.
+
+ An unrecognised keyword which is not in the \p ignorekeywords map will trigger the
+ help message and a return value of false. For each keyword in \p ignorekeywords, you
+ can specify the number of following parameters that should be ignored.
+
+ This should be replaced with the one of the standard CoinUtils parameter mechanisms.
+ */
+bool processParameters (int argc, const char **argv,
+ std::map<std::string,std::string>& parms,
+ const std::map<std::string,int>& ignorekeywords = std::map<std::string,int>());
+
+/// A single test outcome record.
+class TestOutcome {
+ public:
+ /// Test result
+ typedef enum {
+ NOTE = 0,
+ PASSED = 1,
+ WARNING = 2,
+ ERROR = 3,
+ LAST = 4
+ } SeverityLevel;
+ /// Print strings for SeverityLevel
+ static std::string SeverityLevelName[LAST];
+ /// Name of component under test
+ std::string component;
+ /// Name of test
+ std::string testname;
+ /// Condition being tested
+ std::string testcond;
+ /// Test result
+ SeverityLevel severity;
+ /// Set to true if problem is expected
+ bool expected;
+ /// Name of code file where test executed
+ std::string filename;
+ /// Line number in code file where test executed
+ int linenumber;
+ /// Standard constructor
+ TestOutcome(const std::string& comp, const std::string& tst,
+ const char* cond, SeverityLevel sev,
+ const char* file, int line, bool exp = false)
+ : component(comp),testname(tst),testcond(cond),severity(sev),
+ expected(exp),filename(file),linenumber(line)
+ { }
+ /// Print the test outcome
+ void print() const;
+};
+
+/// Utility class to maintain a list of test outcomes.
+class TestOutcomes : public std::list<TestOutcome> {
+ public:
+ /// Add an outcome to the list
+ void add(std::string comp, std::string tst, const char* cond,
+ TestOutcome::SeverityLevel sev, const char* file, int line,
+ bool exp = false)
+ { push_back(TestOutcome(comp,tst,cond,sev,file,line,exp)); }
+
+ /*! \brief Add an outcome to the list
+
+ Get the component name from the solver interface.
+ */
+ void add(const OsiSolverInterface& si, std::string tst, const char* cond,
+ TestOutcome::SeverityLevel sev, const char* file, int line,
+ bool exp = false);
+ /// Print the list of outcomes
+ void print() const;
+ /*! \brief Count total and expected outcomes at given severity level
+
+ Given a severity level, walk the list of outcomes and count the total number
+ of outcomes at this severity level and the number expected.
+ */
+ void getCountBySeverity(TestOutcome::SeverityLevel sev,
+ int& total, int& expected) const;
+};
+
+/// Convert parameter to a string (stringification)
+#define OSIUNITTEST_QUOTEME_(x) #x
+/// Convert to string with one level of expansion of the parameter
+#define OSIUNITTEST_QUOTEME(x) OSIUNITTEST_QUOTEME_(x)
+
+template <typename Component>
+bool OsiUnitTestAssertSeverityExpected(
+ bool condition, const char * condition_str, const char *filename,
+ int line, const Component& component, const std::string& testname,
+ TestOutcome::SeverityLevel severity, bool expected)
+{
+ if (condition) {
+ OsiUnitTest::outcomes.add(component, testname, condition_str,
+ OsiUnitTest::TestOutcome::PASSED, filename, line, false);
+ if (OsiUnitTest::verbosity >= 2) {
+ std::ostringstream successmsg;
+ successmsg << __FILE__ << ":" << __LINE__ << ": " << testname
+ << " (condition \'" << condition_str << "\') passed.\n";
+ OsiUnitTest::testingMessage(successmsg.str().c_str());
+ }
+ return true;
+ }
+ OsiUnitTest::outcomes.add(component, testname, condition_str,
+ severity, filename, line, expected);
+ OsiUnitTest::failureMessage(component, testname, condition_str);
+ switch (OsiUnitTest::haltonerror) {
+ case 2:
+ { if (severity >= OsiUnitTest::TestOutcome::ERROR ) std::abort(); break; }
+ case 1:
+ { std::cout << std::endl << "press any key to continue..." << std::endl;
+ std::getchar();
+ break ; }
+ default: ;
+ }
+ return false;
+}
+
+/// Add a test outcome to the list held in OsiUnitTest::outcomes
+#define OSIUNITTEST_ADD_OUTCOME(component,testname,testcondition,severity,expected) \
+ OsiUnitTest::outcomes.add(component,testname,testcondition,severity,\
+ __FILE__,__LINE__,expected)
+/*! \brief Test for a condition and record the result
+
+ Test \p condition and record the result in OsiUnitTest::outcomes.
+ If it succeeds, record the result as OsiUnitTest::TestOutcome::PASSED and print
+ a message for OsiUnitTest::verbosity >= 2.
+ If it fails, record the test as failed with \p severity and \p expected and
+ react as specified by OsiUnitTest::haltonerror.
+
+ \p failurecode is executed when failure is not fatal.
+*/
+#define OSIUNITTEST_ASSERT_SEVERITY_EXPECTED(condition,failurecode,component,\
+ testname, severity, expected) \
+{ \
+ if (!OsiUnitTestAssertSeverityExpected(condition, #condition, \
+ __FILE__, __LINE__, component, testname, severity, expected)) { \
+ failurecode; \
+ } \
+}
+
+/*! \brief Perform a test with severity OsiUnitTest::TestOutcome::ERROR, failure not
+ expected.
+*/
+#define OSIUNITTEST_ASSERT_ERROR(condition, failurecode, component, testname) \
+ OSIUNITTEST_ASSERT_SEVERITY_EXPECTED(condition,failurecode,component,testname,\
+ OsiUnitTest::TestOutcome::ERROR,false)
+
+/*! \brief Perform a test with severity OsiUnitTest::TestOutcome::WARNING, failure
+ not expected.
+*/
+#define OSIUNITTEST_ASSERT_WARNING(condition, failurecode, component, testname) \
+ OSIUNITTEST_ASSERT_SEVERITY_EXPECTED(condition,failurecode,component,testname,\
+ OsiUnitTest::TestOutcome::WARNING,false)
+
+/*! \brief Perform a test surrounded by a try/catch block
+
+ \p trycode is executed in a try/catch block; if there's no throw the test is deemed
+ to have succeeded and is recorded in OsiUnitTest::outcomes with status
+ OsiUnitTest::TestOutcome::PASSED. If the \p trycode throws a CoinError, the failure
+ is recorded with status \p severity and \p expected and the value of
+ OsiUnitTest::haltonerror is consulted. If the failure is not fatal, \p catchcode is
+ executed. If any other error is thrown, the failure is recorded as for a CoinError
+ and \p catchcode is executed (haltonerror is not consulted).
+*/
+#define OSIUNITTEST_CATCH_SEVERITY_EXPECTED(trycode, catchcode, component, testname,\
+ severity, expected) \
+{ \
+ try { \
+ trycode; \
+ OSIUNITTEST_ADD_OUTCOME(component,testname,#trycode " did not throw exception",\
+ OsiUnitTest::TestOutcome::PASSED,false); \
+ if (OsiUnitTest::verbosity >= 2) { \
+ std::string successmsg( __FILE__ ":" OSIUNITTEST_QUOTEME(__LINE__) ": "); \
+ successmsg = successmsg + testname; \
+ successmsg = successmsg + " (code \'" #trycode "\') did not throw exception"; \
+ successmsg = successmsg + ".\n" ; \
+ OsiUnitTest::testingMessage(successmsg.c_str()); \
+ } \
+ } catch (CoinError& e) { \
+ std::stringstream errmsg; \
+ errmsg << #trycode " threw CoinError: " << e.message(); \
+ if (e.className().length() > 0) \
+ errmsg << " in " << e.className(); \
+ if (e.methodName().length() > 0) \
+ errmsg << " in " << e.methodName(); \
+ if (e.lineNumber() >= 0) \
+ errmsg << " at " << e.fileName() << ":" << e.lineNumber(); \
+ OSIUNITTEST_ADD_OUTCOME(component,testname,errmsg.str().c_str(),\
+ severity,expected); \
+ OsiUnitTest::failureMessage(component,testname,errmsg.str().c_str()); \
+ switch(OsiUnitTest::haltonerror) { \
+ case 2: \
+ { if (severity >= OsiUnitTest::TestOutcome::ERROR) abort(); break; } \
+ case 1: \
+ { std::cout << std::endl << "press any key to continue..." << std::endl; \
+ getchar(); \
+ break ; } \
+ default: ; \
+ } \
+ catchcode; \
+ } catch (...) { \
+ std::string errmsg; \
+ errmsg = #trycode; \
+ errmsg = errmsg + " threw unknown exception"; \
+ OSIUNITTEST_ADD_OUTCOME(component,testname,errmsg.c_str(),severity,false); \
+ OsiUnitTest::failureMessage(component,testname,errmsg.c_str()); \
+ catchcode; \
+ } \
+}
+
+/*! \brief Perform a try/catch test with severity OsiUnitTest::TestOutcome::ERROR,
+ failure not expected.
+*/
+#define OSIUNITTEST_CATCH_ERROR(trycode, catchcode, component, testname) \
+ OSIUNITTEST_CATCH_SEVERITY_EXPECTED(trycode, catchcode, component, testname, OsiUnitTest::TestOutcome::ERROR, false)
+
+/*! \brief Perform a try/catch test with severity OsiUnitTest::TestOutcome::WARNING,
+ failure not expected.
+*/
+#define OSIUNITTEST_CATCH_WARNING(trycode, catchcode, component, testname) \
+ OSIUNITTEST_CATCH_SEVERITY_EXPECTED(trycode, catchcode, component, testname, OsiUnitTest::TestOutcome::WARNING, false)
+
+} // end namespace OsiUnitTest
+
+#endif /*OSISOLVERINTERFACETEST_HPP_*/