From 11d0b171124835e35e754def5853489de83dd187 Mon Sep 17 00:00:00 2001 From: Mizux Seiha Date: Thu, 30 Sep 2021 09:32:43 +0200 Subject: [PATCH] Add Test --- Clp/CMakeLists.txt | 4 + Clp/test/CMakeLists.txt | 34 +++++ Clp/test/ClpTest.cpp | 288 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 326 insertions(+) create mode 100644 Clp/test/CMakeLists.txt create mode 100644 Clp/test/ClpTest.cpp diff --git a/Clp/CMakeLists.txt b/Clp/CMakeLists.txt index d982aa5b3..dae12af9b 100644 --- a/Clp/CMakeLists.txt +++ b/Clp/CMakeLists.txt @@ -246,3 +246,7 @@ install(TARGETS ClpSolver ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/Clp/test/CMakeLists.txt b/Clp/test/CMakeLists.txt new file mode 100644 index 000000000..a5093ec10 --- /dev/null +++ b/Clp/test/CMakeLists.txt @@ -0,0 +1,34 @@ + +add_executable(ClpTest "ClpTest.cpp") +target_include_directories(Clp PUBLIC + $ + $) +target_compile_definitions(ClpTest + PUBLIC HAVE_CONFIG_H + PRIVATE CLP_BUILD COIN_HAS_CLP) +if(CMAKE_VERSION VERSION_LESS "3.8.2") + set_property(TARGET ClpTest PROPERTY CXX_STANDARD 11) + set_property(TARGET ClpTest PROPERTY CXX_STANDARD_REQUIRED ON) +else() + target_compile_features(ClpTest PUBLIC cxx_std_11) +endif() +if(APPLE) + set_target_properties(ClpTest PROPERTIES + INSTALL_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR};@loader_path") +elseif(UNIX) + cmake_path(RELATIVE_PATH CMAKE_INSTALL_FULL_LIBDIR + BASE_DIRECTORY ${CMAKE_INSTALL_FULL_BINDIR} + OUTPUT_VARIABLE libdir_relative_path) + set_target_properties(ClpTest PROPERTIES + INSTALL_RPATH "$ORIGIN/${libdir_relative_path}:$ORIGIN") +endif() +target_link_libraries(ClpTest PRIVATE + Coin::CoinUtils + Coin::Osi + Coin::Clp) +set_target_properties(ClpTest PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}) +add_executable(Coin::ClpTest ALIAS ClpTest) + +add_test(NAME ClpTest COMMAND ClpTest) diff --git a/Clp/test/ClpTest.cpp b/Clp/test/ClpTest.cpp new file mode 100644 index 000000000..53c59d3b4 --- /dev/null +++ b/Clp/test/ClpTest.cpp @@ -0,0 +1,288 @@ +// This is a simple example to create a model by row +#include "ClpSimplex.hpp" +#include "CoinBuild.hpp" +#include "CoinHelperFunctions.hpp" +#include "CoinModel.hpp" +#include "CoinTime.hpp" +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, const char *argv[]) { + std::cout << "coinutils version: " << COINUTILS_VERSION << std::endl; + std::cout << "osi version: " << OSI_VERSION << std::endl; + std::cout << "clp version: " << CLP_VERSION << std::endl; +#if COIN_BIG_INDEX<2 + try { + // Empty model + ClpSimplex model; + + // Objective - just nonzeros + int objIndex[] = {0, 2}; + double objValue[] = {1.0, 4.0}; + // Upper bounds - as dense vector + double upper[] = {2.0, COIN_DBL_MAX, 4.0}; + + // Create space for 3 columns + model.resize(0, 3); + // Fill in + int i; + // Virtuous way + // First objective + for (i = 0; i < 2; i++) + model.setObjectiveCoefficient(objIndex[i], objValue[i]); + // Now bounds (lower will be zero by default but do again) + for (i = 0; i < 3; i++) { + model.setColumnLower(i, 0.0); + model.setColumnUpper(i, upper[i]); + } + /* + We could also have done in non-virtuous way e.g. + double * objective = model.objective(); + and then set directly + */ + // Faster to add rows all at once - but this is easier to show + // Now add row 1 as >= 2.0 + int row1Index[] = {0, 2}; + double row1Value[] = {1.0, 1.0}; + model.addRow(2, row1Index, row1Value, + 2.0, COIN_DBL_MAX); + // Now add row 2 as == 1.0 + int row2Index[] = {0, 1, 2}; + double row2Value[] = {1.0, -5.0, 1.0}; + model.addRow(3, row2Index, row2Value, + 1.0, 1.0); + // solve + model.dual(); + + /* + Adding one row at a time has a significant overhead so let's + try a more complicated but faster way + + First time adding in 10000 rows one by one + */ + model.allSlackBasis(); + ClpSimplex modelSave = model; + double time1 = CoinCpuTime(); + int k; + for (k = 0; k < 10000; k++) { + int row2Index[] = {0, 1, 2}; + double row2Value[] = {1.0, -5.0, 1.0}; + model.addRow(3, row2Index, row2Value, + 1.0, 1.0); + } + printf("Time for 10000 addRow is %g\n", CoinCpuTime() - time1); + model.dual(); + model = modelSave; + // Now use build + CoinBuild buildObject; + time1 = CoinCpuTime(); + for (k = 0; k < 10000; k++) { + int row2Index[] = {0, 1, 2}; + double row2Value[] = {1.0, -5.0, 1.0}; + buildObject.addRow(3, row2Index, row2Value, + 1.0, 1.0); + } + model.addRows(buildObject); + printf("Time for 10000 addRow using CoinBuild is %g\n", CoinCpuTime() - time1); + model.dual(); + model = modelSave; + int del[] = {0, 1, 2}; + model.deleteRows(2, del); + // Now use build +-1 + CoinBuild buildObject2; + time1 = CoinCpuTime(); + for (k = 0; k < 10000; k++) { + int row2Index[] = {0, 1, 2}; + double row2Value[] = {1.0, -1.0, 1.0}; + buildObject2.addRow(3, row2Index, row2Value, + 1.0, 1.0); + } + model.addRows(buildObject2, true); + printf("Time for 10000 addRow using CoinBuild+-1 is %g\n", CoinCpuTime() - time1); + model.dual(); + model = modelSave; + model.deleteRows(2, del); + // Now use build +-1 + CoinModel modelObject2; + time1 = CoinCpuTime(); + for (k = 0; k < 10000; k++) { + int row2Index[] = {0, 1, 2}; + double row2Value[] = {1.0, -1.0, 1.0}; + modelObject2.addRow(3, row2Index, row2Value, + 1.0, 1.0); + } + model.addRows(modelObject2, true); + printf("Time for 10000 addRow using CoinModel+-1 is %g\n", CoinCpuTime() - time1); + model.dual(); + model = ClpSimplex(); + // Now use build +-1 + CoinModel modelObject3; + time1 = CoinCpuTime(); + for (k = 0; k < 10000; k++) { + int row2Index[] = {0, 1, 2}; + double row2Value[] = {1.0, -1.0, 1.0}; + modelObject3.addRow(3, row2Index, row2Value, + 1.0, 1.0); + } + model.loadProblem(modelObject3, true); + printf("Time for 10000 addRow using CoinModel load +-1 is %g\n", CoinCpuTime() - time1); + model.writeMps("xx.mps"); + model.dual(); + model = modelSave; + // Now use model + CoinModel modelObject; + time1 = CoinCpuTime(); + for (k = 0; k < 10000; k++) { + int row2Index[] = {0, 1, 2}; + double row2Value[] = {1.0, -5.0, 1.0}; + modelObject.addRow(3, row2Index, row2Value, + 1.0, 1.0); + } + model.addRows(modelObject); + printf("Time for 10000 addRow using CoinModel is %g\n", CoinCpuTime() - time1); + model.dual(); + model.writeMps("b.mps"); + // Method using least memory - but most complicated + time1 = CoinCpuTime(); + // Assumes we know exact size of model and matrix + // Empty model + ClpSimplex model2; + { + // Create space for 3 columns and 10000 rows + int numberRows = 10000; + int numberColumns = 3; + // This is fully dense - but would not normally be so + int numberElements = numberRows * numberColumns; + // Arrays will be set to default values + model2.resize(numberRows, numberColumns); + double * elements = new double [numberElements]; + CoinBigIndex * starts = new CoinBigIndex [numberColumns+1]; + int * rows = new int [numberElements];; + int * lengths = new int[numberColumns]; + // Now fill in - totally unsafe but .... + // no need as defaults to 0.0 double * columnLower = model2.columnLower(); + double * columnUpper = model2.columnUpper(); + double * objective = model2.objective(); + double * rowLower = model2.rowLower(); + double * rowUpper = model2.rowUpper(); + // Columns - objective was packed + for (k = 0; k < 2; k++) { + int iColumn = objIndex[k]; + objective[iColumn] = objValue[k]; + } + for (k = 0; k < numberColumns; k++) + columnUpper[k] = upper[k]; + // Rows + for (k = 0; k < numberRows; k++) { + rowLower[k] = 1.0; + rowUpper[k] = 1.0; + } + // Now elements + double row2Value[] = {1.0, -5.0, 1.0}; + CoinBigIndex put = 0; + for (k = 0; k < numberColumns; k++) { + starts[k] = put; + lengths[k] = numberRows; + double value = row2Value[k]; + for (int i = 0; i < numberRows; i++) { + rows[put] = i; + elements[put] = value; + put++; + } + } + starts[numberColumns] = put; + // assign to matrix + CoinPackedMatrix * matrix = new CoinPackedMatrix(true, 0.0, 0.0); + matrix->assignMatrix(true, numberRows, numberColumns, numberElements, + elements, rows, starts, lengths); + ClpPackedMatrix * clpMatrix = new ClpPackedMatrix(matrix); + model2.replaceMatrix(clpMatrix, true); + printf("Time for 10000 addRow using hand written code is %g\n", CoinCpuTime() - time1); + // If matrix is really big could switch off creation of row copy + // model2.setSpecialOptions(256); + } + model2.dual(); + model2.writeMps("a.mps"); + // Print column solution + int numberColumns = model.numberColumns(); + + // Alternatively getColSolution() + double * columnPrimal = model.primalColumnSolution(); + // Alternatively getReducedCost() + double * columnDual = model.dualColumnSolution(); + // Alternatively getColLower() + double * columnLower = model.columnLower(); + // Alternatively getColUpper() + double * columnUpper = model.columnUpper(); + // Alternatively getObjCoefficients() + double * columnObjective = model.objective(); + + int iColumn; + + std::cout << " Primal Dual Lower Upper Cost" + << std::endl; + + for (iColumn = 0; iColumn < numberColumns; iColumn++) { + double value; + std::cout << std::setw(6) << iColumn << " "; + value = columnPrimal[iColumn]; + if (fabs(value) < 1.0e5) + std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; + else + std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; + value = columnDual[iColumn]; + if (fabs(value) < 1.0e5) + std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; + else + std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; + value = columnLower[iColumn]; + if (fabs(value) < 1.0e5) + std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; + else + std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; + value = columnUpper[iColumn]; + if (fabs(value) < 1.0e5) + std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; + else + std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; + value = columnObjective[iColumn]; + if (fabs(value) < 1.0e5) + std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; + else + std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; + + std::cout << std::endl; + } + std::cout << "--------------------------------------" << std::endl; + // Test CoinAssert + std::cout << "If Clp compiled without NDEBUG below should give assert, if with NDEBUG or COIN_ASSERT CoinError" << std::endl; + model = modelSave; + model.deleteRows(2, del); + // Deliberate error + model.deleteColumns(1, del + 2); + // Now use build +-1 + CoinBuild buildObject3; + time1 = CoinCpuTime(); + for (k = 0; k < 10000; k++) { + int row2Index[] = {0, 1, 2}; + double row2Value[] = {1.0, -1.0, 1.0}; + buildObject3.addRow(3, row2Index, row2Value, + 1.0, 1.0); + } + model.addRows(buildObject3, true); + } catch (CoinError e) { + e.print(); + if (e.lineNumber() >= 0) + std::cout << "This was from a CoinAssert" << std::endl; + } +#else + printf("addRows not available with COIN_BIG_INDEX=2\n"); +#endif + return 0; +} +