/* Install the name information from a CoinModel object. CoinModel does not maintain a name for the objective function (in fact, it has no concept of objective function). */ void OsiSolverInterface::setRowColNames (CoinModel &mod) { int nameDiscipline,m,n ; /* Determine how we're handling names. It's possible that the underlying solver has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that case, we want to default to auto names */ bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; if (recognisesOsiNames == false) { nameDiscipline = 0 ; } /* Whatever happens, we're about to clean out the current name vectors. Decide on an appropriate size and call reallocRowColNames to adjust capacity. */ if (nameDiscipline == 0) { m = 0 ; n = 0 ; } else { m = mod.rowNames()->numberItems() ; n = mod.columnNames()->numberItems() ; } reallocRowColNames(rowNames_,m,colNames_,n) ; /* If name discipline is auto, we're done already. Otherwise, load 'em up. As best I can see, there's no guarantee that we'll have names for all rows and columns, so we need to pay attention. */ if (nameDiscipline != 0) { int maxRowNdx=-1, maxColNdx=-1 ; const char *const *names = mod.rowNames()->names() ; rowNames_.resize(m) ; for (int i = 0 ; i < m ; i++) { std::string nme = names[i] ; if (nme.length() == 0) { if (nameDiscipline == 2) { nme = dfltRowColName('r',i) ; } } if (nme.length() > 0) { maxRowNdx = i ; } rowNames_[i] = nme ; } rowNames_.resize(maxRowNdx+1) ; names = mod.columnNames()->names() ; colNames_.resize(n) ; for (int j = 0 ; j < n ; j++) { std::string nme = names[j] ; if (nme.length() == 0) { if (nameDiscipline == 2) { nme = dfltRowColName('c',j) ; } } if (nme.length() > 0) { maxColNdx = j ; } colNames_[j] = nme ; } colNames_.resize(maxColNdx+1) ; } /* And we're done. */ return ; }
// nothing to inherit from GC really ColoredGraph solve(const Graph& gr) override { CoinModel coinModel; for (auto i = 0; i < gr.nodeCount(); ++i) { coinModel.addCol(0, nullptr, nullptr, 0, gr.nodeCount()-1, 1, nullptr, true); } OsiClpSolverInterface solver; solver.loadFromCoinModel(coinModel); CbcModel model(solver); model.setLogLevel(0); model.passInEventHandler(make_unique<GC_LP_EventHandler>(recoveryPath).get()); if (use_heuristic) { GC_LP_Heuristic heuristic; model.addHeuristic(&heuristic); } AddRules(model, gr); if (use_parallel) { model.setNumberThreads(std::thread::hardware_concurrency()); } if (max_seconds != 0) model.setMaximumSeconds(max_seconds); model.initialSolve(); model.branchAndBound(); if (model.maximumSecondsReached()) Println(cout, "max seconds reached"); if (model.isSecondsLimitReached()) Println(cout, "seconds limit reached"); seconds_passed_ = model.getCurrentSeconds(); iterations_passed_ = model.getIterationCount(); const double *solution = model.bestSolution(); if (solution == nullptr) { vector<Color> colors(gr.nodeCount()); iota(colors.begin(), colors.end(), 0); return {gr, colors}; } return ColoredGraph(gr, {solution, solution+gr.nodeCount()}); }
int main(int argc, const char *argv[]) { 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 << setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnDual[iColumn]; if (fabs(value) < 1.0e5) std::cout << setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnLower[iColumn]; if (fabs(value) < 1.0e5) std::cout << setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnUpper[iColumn]; if (fabs(value) < 1.0e5) std::cout << setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnObjective[iColumn]; if (fabs(value) < 1.0e5) std::cout << setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << setiosflags(std::ios::scientific) << std::setw(14) << value; std::cout << std::endl; } std::cout << "--------------------------------------" << std::endl; // Test CoinAssert std::cout << "If Clp compiled with -g below should give assert, if with -O1 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; } return 0; }
//-------------------------------------------------------------------------- // test solution methods. void OsiCbcSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir) { { CoinRelFltEq eq; OsiCbcSolverInterface m; std::string fn = mpsDir+"exmip1"; m.readMps(fn.c_str(),"mps"); { OsiCbcSolverInterface im; OSIUNITTEST_ASSERT_ERROR(im.getNumCols() == 0, {}, "cbc", "default constructor"); OSIUNITTEST_ASSERT_ERROR(im.getModelPtr() != NULL, {}, "cbc", "default constructor"); } // Test copy constructor and assignment operator { OsiCbcSolverInterface lhs; { OsiCbcSolverInterface im(m); OsiCbcSolverInterface imC1(im); OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != im.getModelPtr(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getNumCols() == im.getNumCols(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getNumRows() == im.getNumRows(), {}, "cbc", "copy constructor"); OsiCbcSolverInterface imC2(im); OSIUNITTEST_ASSERT_ERROR(imC2.getModelPtr() != im.getModelPtr(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC2.getNumCols() == im.getNumCols(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC2.getNumRows() == im.getNumRows(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != imC2.getModelPtr(), {}, "cbc", "copy constructor"); lhs = imC2; } // Test that lhs has correct values even though rhs has gone out of scope OSIUNITTEST_ASSERT_ERROR(lhs.getModelPtr() != m.getModelPtr(), {}, "cbc", "assignment operator"); OSIUNITTEST_ASSERT_ERROR(lhs.getNumCols() == m.getNumCols(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(lhs.getNumRows() == m.getNumRows(), {}, "cbc", "copy constructor"); } // Test clone { OsiCbcSolverInterface cbcSi(m); OsiSolverInterface * siPtr = &cbcSi; OsiSolverInterface * siClone = siPtr->clone(); OsiCbcSolverInterface * cbcClone = dynamic_cast<OsiCbcSolverInterface*>(siClone); OSIUNITTEST_ASSERT_ERROR(cbcClone != NULL, {}, "cbc", "clone"); OSIUNITTEST_ASSERT_ERROR(cbcClone->getModelPtr() != cbcSi.getModelPtr(), {}, "cbc", "clone"); OSIUNITTEST_ASSERT_ERROR(cbcClone->getNumRows() == cbcSi.getNumRows(), {}, "cbc", "clone"); OSIUNITTEST_ASSERT_ERROR(cbcClone->getNumCols() == m.getNumCols(), {}, "cbc", "clone"); delete siClone; } // test infinity { OsiCbcSolverInterface si; OSIUNITTEST_ASSERT_ERROR(si.getInfinity() == OsiCbcInfinity, {}, "cbc", "infinity"); } // Test some catches if (!OsiCbcHasNDEBUG()) { OsiCbcSolverInterface solver; try { solver.setObjCoeff(0,0.0); OSIUNITTEST_ADD_OUTCOME("cbc", "setObjCoeff on empty model", "should throw exception", OsiUnitTest::TestOutcome::ERROR, false); } catch (CoinError e) { if (OsiUnitTest::verbosity >= 1) std::cout<<"Correct throw from setObjCoeff on empty model"<<std::endl; } std::string fn = mpsDir+"exmip1"; solver.readMps(fn.c_str(),"mps"); OSIUNITTEST_CATCH_ERROR(solver.setObjCoeff(0,0.0), {}, "cbc", "setObjCoeff on nonempty model"); try { int index[]={0,20}; double value[]={0.0,0.0,0.0,0.0}; solver.setColSetBounds(index,index+2,value); OSIUNITTEST_ADD_OUTCOME("cbc", "setColSetBounds on cols not in model", "should throw exception", OsiUnitTest::TestOutcome::ERROR, false); } catch (CoinError e) { if (OsiUnitTest::verbosity >= 1) std::cout<<"Correct throw from setObjCoeff on empty model"<<std::endl; } } { OsiCbcSolverInterface cbcSi(m); int nc = cbcSi.getNumCols(); int nr = cbcSi.getNumRows(); const double * cl = cbcSi.getColLower(); const double * cu = cbcSi.getColUpper(); const double * rl = cbcSi.getRowLower(); const double * ru = cbcSi.getRowUpper(); OSIUNITTEST_ASSERT_ERROR(nc == 8, return, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(nr == 5, return, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cl[0],2.5), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cl[1],0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cu[1],4.1), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cu[2],1.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(rl[0],2.5), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(rl[4],3.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(ru[1],2.1), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(ru[4],15.), {}, "cbc", "read and copy exmip1"); const double * cs = cbcSi.getColSolution(); OSIUNITTEST_ASSERT_ERROR(eq(cs[0],2.5), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cs[7],0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(!eq(cl[3],1.2345), {}, "cbc", "set col lower"); cbcSi.setColLower( 3, 1.2345 ); OSIUNITTEST_ASSERT_ERROR( eq(cbcSi.getColLower()[3],1.2345), {}, "cbc", "set col lower"); OSIUNITTEST_ASSERT_ERROR(!eq(cbcSi.getColUpper()[4],10.2345), {}, "cbc", "set col upper"); cbcSi.setColUpper( 4, 10.2345 ); OSIUNITTEST_ASSERT_ERROR( eq(cbcSi.getColUpper()[4],10.2345), {}, "cbc", "set col upper"); // LH: Objective will depend on how underlying solver constructs and maintains initial solution double objValue = cbcSi.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,3.5) || eq(objValue,10.5), {}, "cbc", "getObjValue() before solve"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[0], 1.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[1], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[2], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[3], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[4], 2.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[5], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[6], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[7],-1.0), {}, "cbc", "read and copy exmip1"); } // Test matrixByRow method { const OsiCbcSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim() == 5, return, "cbc", "getMatrixByRow: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getMinorDim() == 8, return, "cbc", "getMatrixByRow: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "cbc", "getMatrixByRow: num elements"); OSIUNITTEST_ASSERT_ERROR(smP->getSizeVectorStarts() == 6, return, "cbc", "getMatrixByRow: num elements"); #ifdef OSICBC_TEST_MTX_STRUCTURE CoinRelFltEq eq; const double * ev = smP->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[0], 3.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[1], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[2], -2.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[3], -1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[4], -1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[5], 2.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[6], 1.1), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[7], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[8], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[9], 2.8), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10], -1.2), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "getMatrixByRow: elements"); const int * mi = smP->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "getMatrixByRow: vector starts"); const int * ei = smP->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "getMatrixByRow: indices"); #else // OSICBC_TEST_MTX_STRUCTURE CoinPackedMatrix exmip1Mtx ; exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*smP), {}, "cbc", "getMatrixByRow") ; #endif // OSICBC_TEST_MTX_STRUCTURE } // Test adding several cuts, and handling of a coefficient of infinity // in the constraint matrix. { OsiCbcSolverInterface fim; std::string fn = mpsDir+"exmip1"; fim.readMps(fn.c_str(),"mps"); // exmip1.mps has 2 integer variables with index 2 & 3 fim.initialSolve(); OsiRowCut cuts[3]; // Generate one ineffective cut plus two trivial cuts int c; int nc = fim.getNumCols(); int *inx = new int[nc]; for (c=0;c<nc;c++) inx[c]=c; double *el = new double[nc]; for (c=0;c<nc;c++) el[c]=1.0e-50+((double)c)*((double)c); cuts[0].setRow(nc,inx,el); cuts[0].setLb(-100.); cuts[0].setUb(500.); cuts[0].setEffectiveness(22); el[4]=0.0; // to get inf later for (c=2;c<4;c++) { el[0]=1.0; inx[0]=c; cuts[c-1].setRow(1,inx,el); cuts[c-1].setLb(1.); cuts[c-1].setUb(100.); cuts[c-1].setEffectiveness(c); } fim.writeMps("x1.mps"); fim.applyRowCuts(3,cuts); fim.writeMps("x2.mps"); // resolve - should get message about zero elements fim.resolve(); fim.writeMps("x3.mps"); // check integer solution const double * cs = fim.getColSolution(); CoinRelFltEq eq; OSIUNITTEST_ASSERT_ERROR(eq(cs[2], 1.0), {}, "cbc", "add cuts"); OSIUNITTEST_ASSERT_ERROR(eq(cs[3], 1.0), {}, "cbc", "add cuts"); // check will find invalid matrix el[0]=1.0/el[4]; inx[0]=0; cuts[0].setRow(nc,inx,el); cuts[0].setLb(-100.); cuts[0].setUb(500.); cuts[0].setEffectiveness(22); fim.applyRowCut(cuts[0]); // resolve - should get message about zero elements fim.resolve(); OSIUNITTEST_ASSERT_WARNING(fim.isAbandoned(), {}, "cbc", "add cuts"); delete[]el; delete[]inx; } // Test matrixByCol method { const OsiCbcSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByCol(); OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim() == 8, return, "cbc", "getMatrixByCol: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getMinorDim() == 5, return, "cbc", "getMatrixByCol: minor dim"); OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "cbc", "getMatrixByCol: number of elements"); OSIUNITTEST_ASSERT_ERROR(smP->getSizeVectorStarts() == 9, return, "cbc", "getMatrixByCol: vector starts size"); #ifdef OSICBC_TEST_MTX_STRUCTURE CoinRelFltEq eq; const double * ev = smP->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 5.6), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 2.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 1.1), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6],-2.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 2.8), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8],-1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11],-1.2), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12],-1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "getMatrixByCol: elements"); const CoinBigIndex * mi = smP->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 2, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 4, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 6, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 8, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 10, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[6] == 11, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[7] == 12, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[8] == 14, {}, "cbc", "getMatrixByCol: vector starts"); const int * ei = smP->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 1, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 3, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 4, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 2, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 3, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 4, {}, "cbc", "getMatrixByCol: indices"); #else // OSICBC_TEST_MTX_STRUCTURE CoinPackedMatrix &exmip1Mtx = BuildExmip1Mtx() ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*smP), {}, "cbc", "getMatrixByCol"); #endif // OSICBC_TEST_MTX_STRUCTURE } //-------------- // Test rowsense, rhs, rowrange, matrixByRow, solver assignment { OsiCbcSolverInterface lhs; { OsiCbcSolverInterface siC1(m); const char * siC1rs = siC1.getRowSense(); OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "cbc", "row sense"); const double * siC1rhs = siC1.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "cbc", "right hand side"); const double * siC1rr = siC1.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "cbc", "row range"); const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(siC1mbr != NULL, {}, "cbc", "matrix by row"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMajorDim() == 5, return, "cbc", "matrix by row: major dim"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMinorDim() == 8, return, "cbc", "matrix by row: major dim"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getNumElements() == 14, return, "cbc", "matrix by row: num elements"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getSizeVectorStarts() == 6, return, "cbc", "matrix by row: num elements"); #ifdef OSICBC_TEST_MTX_STRUCTURE const double * ev = siC1mbr->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "matrix by row: elements"); const CoinBigIndex * mi = siC1mbr->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "matrix by row: vector starts"); const int * ei = siC1mbr->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "matrix by row: indices"); #else // OSICBC_TEST_MTX_STRUCTURE CoinPackedMatrix exmip1Mtx ; exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*siC1mbr), {}, "cbc", "matrix by row"); #endif // OSICBC_TEST_MTX_STRUCTURE OSIUNITTEST_ASSERT_WARNING(siC1rs == siC1.getRowSense(), {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_WARNING(siC1rhs == siC1.getRightHandSide(), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_WARNING(siC1rr == siC1.getRowRange(), {}, "cbc", "row range"); // Change CBC Model by adding free row OsiRowCut rc; rc.setLb(-COIN_DBL_MAX); rc.setUb( COIN_DBL_MAX); OsiCuts cuts; cuts.insert(rc); siC1.applyCuts(cuts); siC1rs = siC1.getRowSense(); OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[5] == 'N', {}, "cbc", "row sense after adding row"); siC1rhs = siC1.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[5],0.0), {}, "cbc", "right hand side after adding row"); siC1rr = siC1.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[5],0.0), {}, "cbc", "row range after adding row"); lhs = siC1; } // Test that lhs has correct values even though siC1 has gone out of scope const char * lhsrs = lhs.getRowSense(); OSIUNITTEST_ASSERT_ERROR(lhsrs[0] == 'G', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[1] == 'L', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[2] == 'E', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[3] == 'R', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[4] == 'R', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[5] == 'N', {}, "cbc", "row sense after assignment"); const double * lhsrhs = lhs.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[0],2.5), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[1],2.1), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[2],4.0), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[3],5.0), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[4],15.), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[5],0.0), {}, "cbc", "right hand side after assignment"); const double *lhsrr = lhs.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[0],0.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[1],0.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[2],0.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[3],5.0-1.8), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[4],15.0-3.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[5],0.0), {}, "cbc", "row range after assignment"); const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(lhsmbr != NULL, {}, "cbc", "matrix by row after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsmbr->getMajorDim() == 6, return, "cbc", "matrix by row after assignment: major dim"); OSIUNITTEST_ASSERT_ERROR(lhsmbr->getNumElements() == 14, return, "cbc", "matrix by row after assignment: num elements"); #ifdef OSICBC_TEST_MTX_STRUCTURE const double * ev = lhsmbr->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "matrix by row after assignment: elements"); const CoinBigIndex * mi = lhsmbr->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "matrix by row after assignment: vector starts"); const int * ei = lhsmbr->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "matrix by row after assignment: indices"); #else // OSICBC_TEST_MTX_STRUCTURE /* This admittedly looks bogus, but it's the equivalent operation on the matrix for inserting a cut of the form -Inf <= +Inf (i.e., a cut with no coefficients). */ CoinPackedMatrix exmip1Mtx ; exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ; CoinPackedVector freeRow ; exmip1Mtx.appendRow(freeRow) ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*lhsmbr), {}, "cbc", "matrix by row after assignment"); #endif // OSICBC_TEST_MTX_STRUCTURE } } // Test add/delete columns { OsiCbcSolverInterface m; std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); double inf = m.getInfinity(); CoinPackedVector c0; c0.insert(0, 4); c0.insert(1, 1); m.addCol(c0, 0, inf, 3); m.initialSolve(); double objValue = m.getObjValue(); CoinRelFltEq eq(1.0e-2); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "cbc", "objvalue after adding col"); // Try deleting first column that's nonbasic at lower bound (0). int * d = new int[1]; CoinWarmStartBasis *cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ; OSIUNITTEST_ASSERT_ERROR(cwsb != NULL, {}, "cbc", "get warmstart basis"); CoinWarmStartBasis::Status stati ; int iCol ; for (iCol = 0 ; iCol < cwsb->getNumStructural() ; iCol++) { stati = cwsb->getStructStatus(iCol) ; if (stati == CoinWarmStartBasis::atLowerBound) break ; } d[0]=iCol; m.deleteCols(1,d); delete [] d; delete cwsb; d=NULL; m.resolve(); objValue = m.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "clp", "objvalue after deleting first col"); // Try deleting column we added. If basic, go to initialSolve as deleting // basic variable trashes basis required for warm start. iCol = m.getNumCols()-1; cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ; stati = cwsb->getStructStatus(iCol) ; delete cwsb; m.deleteCols(1,&iCol); if (stati == CoinWarmStartBasis::basic) { m.initialSolve() ; } else { m.resolve(); } objValue = m.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "clp", "objvalue after deleting added col"); } // Build a model { OsiCbcSolverInterface model; std::string fn = mpsDir+"p0033"; model.readMps(fn.c_str(),"mps"); // Point to data int numberRows = model.getNumRows(); const double * rowLower = model.getRowLower(); const double * rowUpper = model.getRowUpper(); int numberColumns = model.getNumCols(); const double * columnLower = model.getColLower(); const double * columnUpper = model.getColUpper(); const double * columnObjective = model.getObjCoefficients(); // get row copy CoinPackedMatrix rowCopy = *model.getMatrixByRow(); const int * column = rowCopy.getIndices(); const int * rowLength = rowCopy.getVectorLengths(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); const double * element = rowCopy.getElements(); // solve model.initialSolve(); // Now build new model CoinModel build; // Row bounds int iRow; for (iRow=0;iRow<numberRows;iRow++) { build.setRowBounds(iRow,rowLower[iRow],rowUpper[iRow]); } // Column bounds and objective int iColumn; for (iColumn=0;iColumn<numberColumns;iColumn++) { build.setColumnLower(iColumn,columnLower[iColumn]); build.setColumnUpper(iColumn,columnUpper[iColumn]); build.setObjective(iColumn,columnObjective[iColumn]); } // Adds elements one by one by row (backwards by row) for (iRow=numberRows-1;iRow>=0;iRow--) { int start = rowStart[iRow]; for (int j=start;j<start+rowLength[iRow];j++) build(iRow,column[j],element[j]); } // Now create Model OsiCbcSolverInterface model2; model2.loadFromCoinModel(build); model2.initialSolve(); // Save - should be continuous model2.writeMps("continuous"); int * whichInteger = new int[numberColumns]; for (iColumn=0;iColumn<numberColumns;iColumn++) whichInteger[iColumn]=iColumn; // mark as integer model2.setInteger(whichInteger,numberColumns); delete [] whichInteger; // save - should be integer model2.writeMps("integer"); // Now do with strings attached // Save build to show how to go over rows CoinModel saveBuild = build; build = CoinModel(); // Column bounds for (iColumn=0;iColumn<numberColumns;iColumn++) { build.setColumnLower(iColumn,columnLower[iColumn]); build.setColumnUpper(iColumn,columnUpper[iColumn]); } // Objective - half the columns as is and half with multiplier of "1.0+multiplier" // Pick up from saveBuild (for no reason at all) for (iColumn=0;iColumn<numberColumns;iColumn++) { double value = saveBuild.objective(iColumn); if (iColumn*2<numberColumns) { build.setObjective(iColumn,columnObjective[iColumn]); } else { // create as string char temp[100]; sprintf(temp,"%g + abs(%g*multiplier)",value,value); build.setObjective(iColumn,temp); } } // It then adds rows one by one but for half the rows sets their values // with multiplier of "1.0+1.5*multiplier" for (iRow=0;iRow<numberRows;iRow++) { if (iRow*2<numberRows) { // add row in simple way int start = rowStart[iRow]; build.addRow(rowLength[iRow],column+start,element+start, rowLower[iRow],rowUpper[iRow]); } else { // As we have to add one by one let's get from saveBuild CoinModelLink triple=saveBuild.firstInRow(iRow); while (triple.column()>=0) { int iColumn = triple.column(); if (iColumn*2<numberColumns) { // just value as normal build(iRow,triple.column(),triple.value()); } else { // create as string char temp[100]; sprintf(temp,"%g + (1.5*%g*multiplier)",triple.value(), triple.value()); build(iRow,iColumn,temp); } triple=saveBuild.next(triple); } // but remember to do rhs build.setRowLower(iRow,rowLower[iRow]); build.setRowUpper(iRow,rowUpper[iRow]); } } // If small switch on error printing if (numberColumns<50) build.setLogLevel(1); // should fail as we never set multiplier OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build) != 0, {}, "cbc", "build model with missing multipliers"); build.associateElement("multiplier",0.0); OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build) == 0, {}, "cbc", "build model"); model2.initialSolve(); // It then loops with multiplier going from 0.0 to 2.0 in increments of 0.1 for (double multiplier=0.0;multiplier<2.0;multiplier+= 0.1) { build.associateElement("multiplier",multiplier); OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build,true) == 0, {}, "cbc", "build model with increasing multiplier"); model2.resolve(); } } // branch and bound { OsiCbcSolverInterface m; std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); m.initialSolve(); //m.messageHandler()->setLogLevel(0); m.getModelPtr()->messageHandler()->setLogLevel(0); m.branchAndBound(); } // branch and bound using CbcModel!!!!!!! { OsiCbcSolverInterface mm; OsiCbcSolverInterface m(&mm); std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); m.initialSolve(); m.branchAndBound(); } // Do common solverInterface testing { OsiCbcSolverInterface m; OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } { OsiCbcSolverInterface mm; OsiCbcSolverInterface m(&mm); OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } }
//-------------------------------------------------------------------------- // Test building a model void CoinModelUnitTest(const std::string & mpsDir, const std::string & netlibDir, const std::string & testModel) { // Get a model CoinMpsIO m; std::string fn = mpsDir+"exmip1"; int numErr = m.readMps(fn.c_str(),"mps"); assert( numErr== 0 ); int numberRows = m.getNumRows(); int numberColumns = m.getNumCols(); // Build by row from scratch { CoinPackedMatrix matrixByRow = * m.getMatrixByRow(); const double * element = matrixByRow.getElements(); const int * column = matrixByRow.getIndices(); const CoinBigIndex * rowStart = matrixByRow.getVectorStarts(); const int * rowLength = matrixByRow.getVectorLengths(); const double * rowLower = m.getRowLower(); const double * rowUpper = m.getRowUpper(); const double * columnLower = m.getColLower(); const double * columnUpper = m.getColUpper(); const double * objective = m.getObjCoefficients(); int i; CoinModel temp; for (i=0; i<numberRows; i++) { temp.addRow(rowLength[i],column+rowStart[i], element+rowStart[i],rowLower[i],rowUpper[i],m.rowName(i)); } // Now do column part for (i=0; i<numberColumns; i++) { temp.setColumnBounds(i,columnLower[i],columnUpper[i]); temp.setColumnObjective(i,objective[i]); if (m.isInteger(i)) temp.setColumnIsInteger(i,true);; } // write out temp.writeMps("byRow.mps"); } // Build by column from scratch and save CoinModel model; { CoinPackedMatrix matrixByColumn = * m.getMatrixByCol(); const double * element = matrixByColumn.getElements(); const int * row = matrixByColumn.getIndices(); const CoinBigIndex * columnStart = matrixByColumn.getVectorStarts(); const int * columnLength = matrixByColumn.getVectorLengths(); const double * rowLower = m.getRowLower(); const double * rowUpper = m.getRowUpper(); const double * columnLower = m.getColLower(); const double * columnUpper = m.getColUpper(); const double * objective = m.getObjCoefficients(); int i; for (i=0; i<numberColumns; i++) { model.addColumn(columnLength[i],row+columnStart[i], element+columnStart[i],columnLower[i],columnUpper[i], objective[i],m.columnName(i),m.isInteger(i)); } // Now do row part for (i=0; i<numberRows; i++) { model.setRowBounds(i,rowLower[i],rowUpper[i]); } // write out model.writeMps("byColumn.mps"); } // model was created by column - play around { CoinModel temp; int i; for (i=numberRows-1; i>=0; i--) temp.setRowLower(i,model.getRowLower(i)); for (i=0; i<numberColumns; i++) { temp.setColumnUpper(i,model.getColumnUpper(i)); temp.setColumnName(i,model.getColumnName(i)); } for (i=numberColumns-1; i>=0; i--) { temp.setColumnLower(i,model.getColumnLower(i)); temp.setColumnObjective(i,model.getColumnObjective(i)); temp.setColumnIsInteger(i,model.getColumnIsInteger(i)); } for (i=0; i<numberRows; i++) { temp.setRowUpper(i,model.getRowUpper(i)); temp.setRowName(i,model.getRowName(i)); } // Now elements for (i=0; i<numberRows; i++) { CoinModelLink triple=model.firstInRow(i); while (triple.column()>=0) { temp(i,triple.column(),triple.value()); triple=model.next(triple); } } // and by column for (i=numberColumns-1; i>=0; i--) { CoinModelLink triple=model.lastInColumn(i); while (triple.row()>=0) { assert (triple.value()==temp(triple.row(),i)); temp(triple.row(),i,triple.value()); triple=model.previous(triple); } } // check equal model.setLogLevel(1); assert (!model.differentModel(temp,false)); } // Try creating model with strings { CoinModel temp; int i; for (i=numberRows-1; i>=0; i--) { double value = model.getRowLower(i); if (value==-1.0) temp.setRowLower(i,"minusOne"); else if (value==1.0) temp.setRowLower(i,"sqrt(plusOne)"); else if (value==4.0) temp.setRowLower(i,"abs(4*plusOne)"); else temp.setRowLower(i,value); } for (i=0; i<numberColumns; i++) { double value; value = model.getColumnUpper(i); if (value==-1.0) temp.setColumnUpper(i,"minusOne"); else if (value==1.0) temp.setColumnUpper(i,"plusOne"); else temp.setColumnUpper(i,value); temp.setColumnName(i,model.getColumnName(i)); } for (i=numberColumns-1; i>=0; i--) { temp.setColumnLower(i,model.getColumnLower(i)); temp.setColumnObjective(i,model.getColumnObjective(i)); temp.setColumnIsInteger(i,model.getColumnIsInteger(i)); } for (i=0; i<numberRows; i++) { double value = model.getRowUpper(i); if (value==-1.0) temp.setRowUpper(i,"minusOne"); else if (value==1.0) temp.setRowUpper(i,"plusOne"); else temp.setRowUpper(i,value); temp.setRowName(i,model.getRowName(i)); } // Now elements for (i=0; i<numberRows; i++) { CoinModelLink triple=model.firstInRow(i); while (triple.column()>=0) { double value = triple.value(); if (value==-1.0) temp(i,triple.column(),"minusOne"); else if (value==1.0) temp(i,triple.column(),"plusOne"); else if (value==-2.0) temp(i,triple.column(),"minusOne-1.0"); else if (value==2.0) temp(i,triple.column(),"plusOne+1.0+minusOne+(2.0-plusOne)"); else temp(i,triple.column(),value); triple=model.next(triple); } } temp.associateElement("minusOne",-1.0); temp.associateElement("plusOne",1.0); temp.setProblemName("fromStrings"); temp.writeMps("string.mps"); // check equal model.setLogLevel(1); assert (!model.differentModel(temp,false)); } // Test with various ways of generating { /* Get a model. Try first with netlibDir, fall back to mpsDir (sampleDir) if that fails. */ CoinMpsIO m; std::string fn = netlibDir+testModel; double time1 = CoinCpuTime(); int numErr = m.readMps(fn.c_str(),""); if (numErr != 0) { std::cout << "Could not read " << testModel << " in " << netlibDir << "; falling back to " << mpsDir << "." << std::endl ; fn = mpsDir+testModel ; numErr = m.readMps(fn.c_str(),"") ; if (numErr != 0) { std::cout << "Could not read " << testModel << "; skipping test." << std::endl ; } } if (numErr == 0) { std::cout << "Time for readMps is " << (CoinCpuTime()-time1) << " seconds." << std::endl ; int numberRows = m.getNumRows(); int numberColumns = m.getNumCols(); // Build model CoinModel model; CoinPackedMatrix matrixByRow = * m.getMatrixByRow(); const double * element = matrixByRow.getElements(); const int * column = matrixByRow.getIndices(); const CoinBigIndex * rowStart = matrixByRow.getVectorStarts(); const int * rowLength = matrixByRow.getVectorLengths(); const double * rowLower = m.getRowLower(); const double * rowUpper = m.getRowUpper(); const double * columnLower = m.getColLower(); const double * columnUpper = m.getColUpper(); const double * objective = m.getObjCoefficients(); int i; for (i=0; i<numberRows; i++) { model.addRow(rowLength[i],column+rowStart[i], element+rowStart[i],rowLower[i],rowUpper[i],m.rowName(i)); } // Now do column part for (i=0; i<numberColumns; i++) { model.setColumnBounds(i,columnLower[i],columnUpper[i]); model.setColumnObjective(i,objective[i]); model.setColumnName(i,m.columnName(i)); if (m.isInteger(i)) model.setColumnIsInteger(i,true);; } // Test CoinSeedRandom(11111); time1 = 0.0; int nPass=50; for (i=0; i<nPass; i++) { double random = CoinDrand48(); int iSeed = (int) (random*1000000); //iSeed = 776151; CoinSeedRandom(iSeed); std::cout << "before pass " << i << " with seed of " << iSeed << std::endl ; buildRandom(model,CoinDrand48(),time1,i); model.validateLinks(); } std::cout << "Time for " << nPass << " CoinModel passes is " << time1 << " seconds\n" << std::endl ; } } }
/* Build a model in some interesting way Nine blocks defined by 4 random numbers If next random number <0.4 addRow next possible If <0.8 addColumn if possible Otherwise do by element For each one use random <0.5 to add rim at same time At end fill in rim at random */ void buildRandom(CoinModel & baseModel, double random, double & timeIt, int iPass) { CoinModel model; int numberRows = baseModel.numberRows(); int numberColumns = baseModel.numberColumns(); int numberElements = baseModel.numberElements(); // Row numbers and column numbers int lastRow[4]; int lastColumn[4]; int i; lastRow[0]=0; lastColumn[0]=0; lastRow[3]=numberRows; lastColumn[3]=numberColumns; for ( i=1; i<3; i++) { int size; size = (int) ((0.25*random+0.2)*numberRows); random = CoinDrand48(); lastRow[i]=lastRow[i-1]+size; size = (int) ((0.25*random+0.2)*numberColumns); random = CoinDrand48(); lastColumn[i]=lastColumn[i-1]+size; } // whether block done 0 row first char block[9]= {0,0,0,0,0,0,0,0,0}; // whether rowRim done char rowDone[3]= {0,0,0}; // whether columnRim done char columnDone[3]= {0,0,0}; // Save array for deleting elements CoinModelTriple * dTriple = new CoinModelTriple[numberElements]; numberElements=0; double time1 = CoinCpuTime(); for (int jBlock=0; jBlock<9; jBlock++) { int iType=-1; int iBlock=-1; if (random<0.4) { // trying addRow int j; for (j=0; j<3; j++) { int k; for (k=0; k<3; k++) { if (block[3*j+k]) break; //already taken } if (k==3) { // can do but decide which one iBlock = 3*j + (int) (CoinDrand48()*0.3); iType=0; break; } } } if (iType==-1&&random<0.8) { // trying addRow int j; for (j=0; j<3; j++) { int k; for (k=0; k<3; k++) { if (block[j+3*k]) break; //already taken } if (k==3) { // can do but decide which one iBlock = j + 3*((int) (CoinDrand48()*0.3)); iType=1; break; } } } if (iType==-1) { iType=2; int j; for (j=0; j<9; j++) { if (!block[j]) { iBlock=j; break; } } } random=CoinDrand48(); assert (iBlock>=0&&iBlock<9); assert (iType>=0); assert (!block[iBlock]); block[iBlock]=static_cast<char>(1+iType); int jRow = iBlock/3; int jColumn = iBlock%3; bool doRow = (CoinDrand48()<0.5)&&!rowDone[jRow]; bool doColumn = (CoinDrand48()<0.5&&!columnDone[jColumn]); if (!iType) { // addRow int * column = new int[lastColumn[jColumn+1]-lastColumn[jColumn]]; double * element = new double[lastColumn[jColumn+1]-lastColumn[jColumn]]; for (i=lastRow[jRow]; i<lastRow[jRow+1]; i++) { int n=0; CoinModelLink triple=baseModel.firstInRow(i); while (triple.column()>=0) { if (triple.column()>=lastColumn[jColumn]&&triple.column()<lastColumn[jColumn+1]) { column[n]=triple.column(); element[n++]=triple.value(); } triple=baseModel.next(triple); } assert (i>=model.numberRows()); if (i>model.numberRows()) { assert (i==lastRow[jRow]); std::cout << "need to fill in rows" << std::endl ; for (int k=0; k<jRow; k++) { int start = CoinMax(lastRow[k],model.numberRows()); int end = lastRow[k+1]; bool doBounds = rowDone[k]!=0; for (int j=start; j<end; j++) { if (doBounds) model.addRow(0,NULL,NULL,baseModel.rowLower(j), baseModel.rowUpper(j),baseModel.rowName(j)); else model.addRow(0,NULL,NULL); } } } if (doRow) model.addRow(n,column,element,baseModel.rowLower(i), baseModel.rowUpper(i),baseModel.rowName(i)); else model.addRow(n,column,element); } if (doRow) { rowDone[jRow]=1; } delete [] column; delete [] element; } else if (iType==1) { // addColumn int * row = new int[lastRow[jRow+1]-lastRow[jRow]]; double * element = new double[lastRow[jRow+1]-lastRow[jRow]]; for (i=lastColumn[jColumn]; i<lastColumn[jColumn+1]; i++) { int n=0; CoinModelLink triple=baseModel.firstInColumn(i); while (triple.row()>=0) { if (triple.row()>=lastRow[jRow]&&triple.row()<lastRow[jRow+1]) { row[n]=triple.row(); element[n++]=triple.value(); } triple=baseModel.next(triple); } assert (i>=model.numberColumns()); if (i>model.numberColumns()) { assert (i==lastColumn[jColumn]); std::cout << "need to fill in columns" << std::endl ; for (int k=0; k<jColumn; k++) { int start = CoinMax(lastColumn[k],model.numberColumns()); int end = lastColumn[k+1]; bool doBounds = columnDone[k]!=0; for (int j=start; j<end; j++) { if (doBounds) model.addColumn(0,NULL,NULL,baseModel.columnLower(j), baseModel.columnUpper(j),baseModel.objective(j), baseModel.columnName(j),baseModel.isInteger(j)); else model.addColumn(0,NULL,NULL); } } } if (doColumn) model.addColumn(n,row,element,baseModel.columnLower(i), baseModel.columnUpper(i),baseModel.objective(i), baseModel.columnName(i),baseModel.isInteger(i)); else model.addColumn(n,row,element); } if (doColumn) { columnDone[jColumn]=1; } delete [] row; delete [] element; } else { // addElement // Which way round ? if (CoinDrand48()<0.5) { // rim first if (doRow) { for (i=lastRow[jRow]; i<lastRow[jRow+1]; i++) { model.setRowLower(i,baseModel.getRowLower(i)); model.setRowUpper(i,baseModel.getRowUpper(i)); model.setRowName(i,baseModel.getRowName(i)); } rowDone[jRow]=1; } if (doColumn) { for (i=lastColumn[jColumn]; i<lastColumn[jColumn+1]; i++) { model.setColumnLower(i,baseModel.getColumnLower(i)); model.setColumnUpper(i,baseModel.getColumnUpper(i)); model.setColumnName(i,baseModel.getColumnName(i)); model.setColumnObjective(i,baseModel.getColumnObjective(i)); model.setColumnIsInteger(i,baseModel.getColumnIsInteger(i)); } columnDone[jColumn]=1; } if (CoinDrand48()<0.3) { // by row for (i=lastRow[jRow]; i<lastRow[jRow+1]; i++) { CoinModelLink triple=baseModel.firstInRow(i); while (triple.column()>=0) { int iColumn = triple.column(); if (iColumn>=lastColumn[jColumn]&&iColumn<lastColumn[jColumn+1]) model(i,triple.column(),triple.value()); triple=baseModel.next(triple); } } } else if (CoinDrand48()<0.6) { // by column for (i=lastColumn[jColumn]; i<lastColumn[jColumn+1]; i++) { CoinModelLink triple=baseModel.firstInColumn(i); while (triple.row()>=0) { int iRow = triple.row(); if (iRow>=lastRow[jRow]&&iRow<lastRow[jRow+1]) model(triple.row(),i,triple.value()); triple=baseModel.next(triple); } } } else { // scan through backwards const CoinModelTriple * elements = baseModel.elements(); for (i=baseModel.numberElements()-1; i>=0; i--) { int iRow = (int) rowInTriple(elements[i]); int iColumn = elements[i].column; if (iRow>=lastRow[jRow]&&iRow<lastRow[jRow+1]&& iColumn>=lastColumn[jColumn]&&iColumn<lastColumn[jColumn+1]) model(iRow,iColumn,elements[i].value); } } } else { // elements first if (CoinDrand48()<0.3) { // by row for (i=lastRow[jRow]; i<lastRow[jRow+1]; i++) { CoinModelLink triple=baseModel.firstInRow(i); while (triple.column()>=0) { int iColumn = triple.column(); if (iColumn>=lastColumn[jColumn]&&iColumn<lastColumn[jColumn+1]) model(i,triple.column(),triple.value()); triple=baseModel.next(triple); } } } else if (CoinDrand48()<0.6) { // by column for (i=lastColumn[jColumn]; i<lastColumn[jColumn+1]; i++) { CoinModelLink triple=baseModel.firstInColumn(i); while (triple.row()>=0) { int iRow = triple.row(); if (iRow>=lastRow[jRow]&&iRow<lastRow[jRow+1]) model(triple.row(),i,triple.value()); triple=baseModel.next(triple); } } } else { // scan through backwards const CoinModelTriple * elements = baseModel.elements(); for (i=baseModel.numberElements()-1; i>=0; i--) { int iRow = (int) rowInTriple(elements[i]); int iColumn = elements[i].column; if (iRow>=lastRow[jRow]&&iRow<lastRow[jRow+1]&& iColumn>=lastColumn[jColumn]&&iColumn<lastColumn[jColumn+1]) model(iRow,iColumn,elements[i].value); } } if (doRow) { for (i=lastRow[jRow]; i<lastRow[jRow+1]; i++) { model.setRowLower(i,baseModel.getRowLower(i)); model.setRowUpper(i,baseModel.getRowUpper(i)); model.setRowName(i,baseModel.getRowName(i)); } rowDone[jRow]=1; } if (doColumn) { for (i=lastColumn[jColumn]; i<lastColumn[jColumn+1]; i++) { model.setColumnLower(i,baseModel.getColumnLower(i)); model.setColumnUpper(i,baseModel.getColumnUpper(i)); model.setColumnName(i,baseModel.getColumnName(i)); model.setColumnObjective(i,baseModel.getColumnObjective(i)); model.setColumnIsInteger(i,baseModel.getColumnIsInteger(i)); } columnDone[jColumn]=1; } } } // Mess up be deleting some elements if (CoinDrand48()<0.3&&iPass>10) { double random2=CoinDrand48(); double randomDelete = 0.2 + 0.5*random2; // fraction to delete //model.validateLinks(); if (random2<0.2) { // delete some rows for (int j=lastRow[jRow]; j<lastRow[jRow+1]; j++) { //model.validateLinks(); if (CoinDrand48()<randomDelete) { // save and delete double rowLower = model.rowLower(j); double rowUpper = model.rowUpper(j); char * rowName = CoinStrdup(model.rowName(j)); CoinModelLink triple=model.firstInRow(j); while (triple.column()>=0) { int iColumn = triple.column(); assert (j==triple.row()); setRowInTriple(dTriple[numberElements],j); dTriple[numberElements].column=iColumn; dTriple[numberElements].value = triple.value(); numberElements++; triple=model.next(triple); } model.deleteRow(j); if (rowDone[jRow]) { // put back rim model.setRowLower(j,rowLower); model.setRowUpper(j,rowUpper); model.setRowName(j,rowName); } free(rowName); } } } else if (random2<0.4) { // delete some columns for (int j=lastColumn[jColumn]; j<lastColumn[jColumn+1]; j++) { //model.validateLinks(); if (CoinDrand48()<randomDelete) { // save and delete double columnLower = model.columnLower(j); double columnUpper = model.columnUpper(j); double objective = model.objective(j); bool integer = model.isInteger(j)!=0; char * columnName = CoinStrdup(model.columnName(j)); CoinModelLink triple=model.firstInColumn(j); while (triple.column()>=0) { int iRow = triple.row(); assert (j==triple.column()); dTriple[numberElements].column = j; setRowInTriple(dTriple[numberElements],iRow); dTriple[numberElements].value = triple.value(); numberElements++; triple=model.next(triple); } model.deleteColumn(j); if (columnDone[jColumn]) { // put back rim model.setColumnLower(j,columnLower); model.setColumnUpper(j,columnUpper); model.setObjective(j,objective); model.setIsInteger(j,integer); model.setColumnName(j,columnName); } free(columnName); } } } else { // delete some elements //model.validateLinks(); const CoinModelTriple * elements = baseModel.elements(); for (i=0; i<model.numberElements(); i++) { int iRow = (int) rowInTriple(elements[i]); int iColumn = elements[i].column; if (iRow>=lastRow[jRow]&&iRow<lastRow[jRow+1]&& iColumn>=lastColumn[jColumn]&&iColumn<lastColumn[jColumn+1]) { if (CoinDrand48()<randomDelete) { dTriple[numberElements].column = iColumn; setRowInTriple(dTriple[numberElements],iRow); dTriple[numberElements].value = elements[i].value; int position = model.deleteElement(iRow,iColumn); if (position>=0) numberElements++; } } } } } } // Do rim if necessary for (int k=0; k<3; k++) { if (!rowDone[k]) { for (i=lastRow[k]; i<lastRow[k+1]; i++) { model.setRowLower(i,baseModel.getRowLower(i)); model.setRowUpper(i,baseModel.getRowUpper(i)); model.setRowName(i,baseModel.getRowName(i)); } } if (!columnDone[k]) { for (i=lastColumn[k]; i<lastColumn[k+1]; i++) { model.setColumnLower(i,baseModel.getColumnLower(i)); model.setColumnUpper(i,baseModel.getColumnUpper(i)); model.setColumnName(i,baseModel.getColumnName(i)); model.setColumnObjective(i,baseModel.getColumnObjective(i)); model.setColumnIsInteger(i,baseModel.getColumnIsInteger(i)); } } } // Put back any elements for (i=0; i<numberElements; i++) { model(rowInTriple(dTriple[i]),dTriple[i].column,dTriple[i].value); } delete [] dTriple; timeIt += CoinCpuTime()-time1; model.setLogLevel(1); assert (!model.differentModel(baseModel,false)); }
int main(int argc, const char *argv[]) { // Empty model ClpSimplex model; std::string mpsFileName; if (argc >= 2) mpsFileName = argv[1]; else { #if defined(NETLIBDIR) mpsFileName = NETLIBDIR "/25fv47.mps"; #else fprintf(stderr, "Do not know where to find netlib MPS files.\n"); exit(1); #endif } int status = model.readMps(mpsFileName.c_str(), true); if (status) { fprintf(stderr, "Bad readMps %s\n", mpsFileName.c_str()); fprintf(stdout, "Bad readMps %s\n", mpsFileName.c_str()); exit(1); } // Point to data int numberRows = model.numberRows(); const double * rowLower = model.rowLower(); const double * rowUpper = model.rowUpper(); int numberColumns = model.numberColumns(); const double * columnLower = model.columnLower(); const double * columnUpper = model.columnUpper(); const double * columnObjective = model.objective(); CoinPackedMatrix * matrix = model.matrix(); // get row copy CoinPackedMatrix rowCopy = *matrix; rowCopy.reverseOrdering(); const int * column = rowCopy.getIndices(); const int * rowLength = rowCopy.getVectorLengths(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); const double * element = rowCopy.getElements(); //const int * row = matrix->getIndices(); //const int * columnLength = matrix->getVectorLengths(); //const CoinBigIndex * columnStart = matrix->getVectorStarts(); //const double * elementByColumn = matrix->getElements(); // solve model.dual(); // Now build new model CoinModel build; double time1 = CoinCpuTime(); // Row bounds int iRow; for (iRow = 0; iRow < numberRows; iRow++) { build.setRowBounds(iRow, rowLower[iRow], rowUpper[iRow]); // optional name build.setRowName(iRow, model.rowName(iRow).c_str()); } // Column bounds and objective int iColumn; for (iColumn = 0; iColumn < numberColumns; iColumn++) { build.setColumnLower(iColumn, columnLower[iColumn]); build.setColumnUpper(iColumn, columnUpper[iColumn]); build.setObjective(iColumn, columnObjective[iColumn]); // optional name build.setColumnName(iColumn, model.columnName(iColumn).c_str()); } // Adds elements one by one by row (backwards by row) for (iRow = numberRows - 1; iRow >= 0; iRow--) { int start = rowStart[iRow]; for (int j = start; j < start + rowLength[iRow]; j++) build(iRow, column[j], element[j]); } double time2 = CoinCpuTime(); // Now create clpsimplex ClpSimplex model2; model2.loadProblem(build); double time3 = CoinCpuTime(); printf("Time for build using CoinModel is %g (%g for loadproblem)\n", time3 - time1, time3 - time2); model2.dual(); // Now do with strings attached // Save build to show how to go over rows CoinModel saveBuild = build; build = CoinModel(); time1 = CoinCpuTime(); // Column bounds for (iColumn = 0; iColumn < numberColumns; iColumn++) { build.setColumnLower(iColumn, columnLower[iColumn]); build.setColumnUpper(iColumn, columnUpper[iColumn]); } // Objective - half the columns as is and half with multiplier of "1.0+multiplier" // Pick up from saveBuild (for no reason at all) for (iColumn = 0; iColumn < numberColumns; iColumn++) { double value = saveBuild.objective(iColumn); if (iColumn * 2 < numberColumns) { build.setObjective(iColumn, columnObjective[iColumn]); } else { // create as string char temp[100]; sprintf(temp, "%g + abs(%g*multiplier)", value, value); build.setObjective(iColumn, temp); } } // It then adds rows one by one but for half the rows sets their values // with multiplier of "1.0+1.5*multiplier" for (iRow = 0; iRow < numberRows; iRow++) { if (iRow * 2 < numberRows) { // add row in simple way int start = rowStart[iRow]; build.addRow(rowLength[iRow], column + start, element + start, rowLower[iRow], rowUpper[iRow]); } else { // As we have to add one by one let's get from saveBuild CoinModelLink triple = saveBuild.firstInRow(iRow); while (triple.column() >= 0) { int iColumn = triple.column(); if (iColumn * 2 < numberColumns) { // just value as normal build(iRow, triple.column(), triple.value()); } else { // create as string char temp[100]; sprintf(temp, "%g + (1.5*%g*multiplier)", triple.value(), triple.value()); build(iRow, iColumn, temp); } triple = saveBuild.next(triple); } // but remember to do rhs build.setRowLower(iRow, rowLower[iRow]); build.setRowUpper(iRow, rowUpper[iRow]); } } time2 = CoinCpuTime(); // Now create ClpSimplex // If small switch on error printing if (numberColumns < 50) build.setLogLevel(1); int numberErrors = model2.loadProblem(build); // should fail as we never set multiplier assert(numberErrors); time3 = CoinCpuTime() - time2; // subtract out unsuccessful times time1 += time3; time2 += time3; build.associateElement("multiplier", 0.0); numberErrors = model2.loadProblem(build); assert(!numberErrors); time3 = CoinCpuTime(); printf("Time for build using CoinModel is %g (%g for successful loadproblem)\n", time3 - time1, time3 - time2); build.writeMps("zero.mps"); // It then loops with multiplier going from 0.0 to 2.0 in increments of 0.1 for (double multiplier = 0.0; multiplier < 2.0; multiplier += 0.1) { build.associateElement("multiplier", multiplier); numberErrors = model2.loadProblem(build, true); assert(!numberErrors); model2.dual(); } return 0; }
int main(int argc, const char *argv[]) { { // Empty model ClpSimplex model; // Bounds on rows - as dense vector double lower[] = {2.0, 1.0}; double upper[] = {COIN_DBL_MAX, 1.0}; // Create space for 2 rows model.resize(2, 0); // Fill in int i; // Now row bounds for (i = 0; i < 2; i++) { model.setRowLower(i, lower[i]); model.setRowUpper(i, upper[i]); } // Now add column 1 int column1Index[] = {0, 1}; double column1Value[] = {1.0, 1.0}; model.addColumn(2, column1Index, column1Value, 0.0, 2, 1.0); // Now add column 2 int column2Index[] = {1}; double column2Value[] = { -5.0}; model.addColumn(1, column2Index, column2Value, 0.0, COIN_DBL_MAX, 0.0); // Now add column 3 int column3Index[] = {0, 1}; double column3Value[] = {1.0, 1.0}; model.addColumn(2, column3Index, column3Value, 0.0, 4.0, 4.0); // solve model.dual(); /* Adding one column at a time has a significant overhead so let's try a more complicated but faster way First time adding in 10000 columns one by one */ model.allSlackBasis(); ClpSimplex modelSave = model; double time1 = CoinCpuTime(); int k; for (k = 0; k < 10000; k++) { int column2Index[] = {0, 1}; double column2Value[] = {1.0, -5.0}; model.addColumn(2, column2Index, column2Value, 0.0, 1.0, 10000.0); } printf("Time for 10000 addColumn is %g\n", CoinCpuTime() - time1); model.dual(); model = modelSave; // Now use build CoinBuild buildObject; time1 = CoinCpuTime(); for (k = 0; k < 100000; k++) { int column2Index[] = {0, 1}; double column2Value[] = {1.0, -5.0}; buildObject.addColumn(2, column2Index, column2Value, 0.0, 1.0, 10000.0); } model.addColumns(buildObject); printf("Time for 100000 addColumn using CoinBuild is %g\n", CoinCpuTime() - time1); model.dual(); model = modelSave; // Now use build +-1 int del[] = {0, 1, 2}; model.deleteColumns(3, del); CoinBuild buildObject2; time1 = CoinCpuTime(); for (k = 0; k < 10000; k++) { int column2Index[] = {0, 1}; double column2Value[] = {1.0, 1.0, -1.0}; int bias = k & 1; buildObject2.addColumn(2, column2Index, column2Value + bias, 0.0, 1.0, 10000.0); } model.addColumns(buildObject2, true); printf("Time for 10000 addColumn using CoinBuild+-1 is %g\n", CoinCpuTime() - time1); model.dual(); model = modelSave; // Now use build +-1 model.deleteColumns(3, del); CoinModel modelObject2; time1 = CoinCpuTime(); for (k = 0; k < 10000; k++) { int column2Index[] = {0, 1}; double column2Value[] = {1.0, 1.0, -1.0}; int bias = k & 1; modelObject2.addColumn(2, column2Index, column2Value + bias, 0.0, 1.0, 10000.0); } model.addColumns(modelObject2, true); printf("Time for 10000 addColumn using CoinModel+-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 < 100000; k++) { int column2Index[] = {0, 1}; double column2Value[] = {1.0, -5.0}; modelObject.addColumn(2, column2Index, column2Value, 0.0, 1.0, 10000.0); } model.addColumns(modelObject); printf("Time for 100000 addColumn using CoinModel is %g\n", CoinCpuTime() - time1); model.dual(); // Print column solution Just first 3 columns int numberColumns = model.numberColumns(); numberColumns = CoinMin(3, 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; } { // Now copy a model ClpSimplex model; int status; if (argc < 2) { #if defined(SAMPLEDIR) status = model.readMps(SAMPLEDIR "/p0033.mps", true); #else fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); #endif } else status = model.readMps(argv[1]); if (status) { printf("errors on input\n"); exit(77); } model.initialSolve(); int numberRows = model.numberRows(); int numberColumns = model.numberColumns(); const double * rowLower = model.rowLower(); const double * rowUpper = model.rowUpper(); // Start off model2 ClpSimplex model2; model2.addRows(numberRows, rowLower, rowUpper, NULL); // Build object CoinBuild buildObject; // Add columns const double * columnLower = model.columnLower(); const double * columnUpper = model.columnUpper(); const double * objective = model.objective(); CoinPackedMatrix * matrix = model.matrix(); const int * row = matrix->getIndices(); const int * columnLength = matrix->getVectorLengths(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const double * elementByColumn = matrix->getElements(); for (int iColumn = 0; iColumn < numberColumns; iColumn++) { CoinBigIndex start = columnStart[iColumn]; buildObject.addColumn(columnLength[iColumn], row + start, elementByColumn + start, columnLower[iColumn], columnUpper[iColumn], objective[iColumn]); } // add in model2.addColumns(buildObject); model2.initialSolve(); } { // and again ClpSimplex model; int status; if (argc < 2) { #if defined(SAMPLEDIR) status = model.readMps(SAMPLEDIR "/p0033.mps", true); #else fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); #endif } else status = model.readMps(argv[1]); if (status) { printf("errors on input\n"); exit(77); } model.initialSolve(); int numberRows = model.numberRows(); int numberColumns = model.numberColumns(); const double * rowLower = model.rowLower(); const double * rowUpper = model.rowUpper(); // Build object CoinModel buildObject; for (int iRow = 0; iRow < numberRows; iRow++) buildObject.setRowBounds(iRow, rowLower[iRow], rowUpper[iRow]); // Add columns const double * columnLower = model.columnLower(); const double * columnUpper = model.columnUpper(); const double * objective = model.objective(); CoinPackedMatrix * matrix = model.matrix(); const int * row = matrix->getIndices(); const int * columnLength = matrix->getVectorLengths(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const double * elementByColumn = matrix->getElements(); for (int iColumn = 0; iColumn < numberColumns; iColumn++) { CoinBigIndex start = columnStart[iColumn]; buildObject.addColumn(columnLength[iColumn], row + start, elementByColumn + start, columnLower[iColumn], columnUpper[iColumn], objective[iColumn]); } // add in ClpSimplex model2; model2.loadProblem(buildObject); model2.initialSolve(); } return 0; }
int main (int argc, const char *argv[]) { // Get data std::string fileName = "./sudoku_sample.csv"; if (argc>=2) fileName = argv[1]; FILE * fp = fopen(fileName.c_str(),"r"); if (!fp) { printf("Unable to open file %s\n",fileName.c_str()); exit(0); } #define MAX_SIZE 16 int valueOffset=1; double lo[MAX_SIZE*MAX_SIZE],up[MAX_SIZE*MAX_SIZE]; char line[80]; int row,column; /*************************************** Read .csv file and see if 9 or 16 Su Doku ***************************************/ int size=9; for (row=0;row<size;row++) { fgets(line,80,fp); // Get size of sudoku puzzle (9 or 16) if (!row) { int get=0; size=1; while (line[get]>=32) { if (line[get]==',') size++; get++; } assert (size==9||size==16); printf("Solving Su Doku of size %d\n",size); if (size==16) valueOffset=0; } int get=0; for (column=0;column<size;column++) { lo[size*row+column]=valueOffset; up[size*row+column]=valueOffset-1+size; if (line[get]!=','&&line[get]>=32) { // skip blanks if (line[get]==' ') { get++; continue; } int value = line[get]-'0'; if (size==9) { assert (value>=1&&value<=9); } else { assert (size==16); if (value<0||value>9) { if (line[get]=='"') { get++; value = 10 + line[get]-'A'; if (value<10||value>15) { value = 10 + line[get]-'a'; } get++; } else { value = 10 + line[get]-'A'; if (value<10||value>15) { value = 10 + line[get]-'a'; } } } assert (value>=0&&value<=15); } lo[size*row+column]=value; up[size*row+column]=value; get++; } get++; } } int block_size = (int) sqrt ((double) size); /*************************************** Now build rules for all different 3*9 or 3*16 sets of variables Number variables by row*size+column ***************************************/ int starts[3*MAX_SIZE+1]; int which[3*MAX_SIZE*MAX_SIZE]; int put=0; int set=0; starts[0]=0; // By row for (row=0;row<size;row++) { for (column=0;column<size;column++) which[put++]=row*size+column; starts[set+1]=put; set++; } // By column for (column=0;column<size;column++) { for (row=0;row<size;row++) which[put++]=row*size+column; starts[set+1]=put; set++; } // By box for (row=0;row<size;row+=block_size) { for (column=0;column<size;column+=block_size) { for (int row2=row;row2<row+block_size;row2++) { for (int column2=column;column2<column+block_size;column2++) which[put++]=row2*size+column2; } starts[set+1]=put; set++; } } OsiClpSolverInterface solver1; /*************************************** Create model Set variables to be general integer variables although priorities probably mean that it won't matter ***************************************/ CoinModel build; // Columns char name[4]; for (row=0;row<size;row++) { for (column=0;column<size;column++) { if (row<10) { if (column<10) sprintf(name,"X%d%d",row,column); else sprintf(name,"X%d%c",row,'A'+(column-10)); } else { if (column<10) sprintf(name,"X%c%d",'A'+(row-10),column); else sprintf(name,"X%c%c",'A'+(row-10),'A'+(column-10)); } double value = CoinDrand48()*100.0; build.addColumn(0,NULL,NULL,lo[size*row+column], up[size*row+column], value, name,true); } } /*************************************** Now add in extra variables for N way branching ***************************************/ for (row=0;row<size;row++) { for (column=0;column<size;column++) { int iColumn = size*row+column; double value = lo[iColumn]; if (value<up[iColumn]) { for (int i=0;i<size;i++) build.addColumn(0,NULL,NULL,0.0,1.0,0.0); } else { // fixed // obviously could do better if we missed out variables int which = ((int) value) - valueOffset; for (int i=0;i<size;i++) { if (i!=which) build.addColumn(0,NULL,NULL,0.0,0.0,0.0); else build.addColumn(0,NULL,NULL,0.0,1.0,0.0); } } } } /*************************************** Now rows ***************************************/ double values[]={1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0}; int indices[MAX_SIZE+1]; double rhs = size==9 ? 45.0 : 120.0; for (row=0;row<3*size;row++) { int iStart = starts[row]; for (column=0;column<size;column++) indices[column]=which[column+iStart]; build.addRow(size,indices,values,rhs,rhs); } double values2[MAX_SIZE+1]; values2[0]=-1.0; for (row=0;row<size;row++) values2[row+1]=row+valueOffset; // Now add rows for extra variables for (row=0;row<size;row++) { for (column=0;column<size;column++) { int iColumn = row*size+column; int base = size*size + iColumn*size; indices[0]=iColumn; for (int i=0;i<size;i++) indices[i+1]=base+i; build.addRow(size+1,indices,values2,0.0,0.0); } } solver1.loadFromCoinModel(build); build.writeMps("xx.mps"); double time1 = CoinCpuTime(); solver1.initialSolve(); CbcModel model(solver1); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); model.solver()->setHintParam(OsiDoScale,false,OsiHintTry); /*************************************** Add in All different cut generator and All different branching So we will have integers then cut branching then N way branching in reverse priority order ***************************************/ // Cut generator CglAllDifferent allDifferent(3*size,starts,which); model.addCutGenerator(&allDifferent,-99,"allDifferent"); model.cutGenerator(0)->setWhatDepth(5); CbcObject ** objects = new CbcObject * [4*size*size]; int nObj=0; for (row=0;row<3*size;row++) { int iStart = starts[row]; objects[row]= new CbcBranchAllDifferent(&model,size,which+iStart); objects[row]->setPriority(2000+nObj); // do after rest satisfied nObj++; } /*************************************** Add in N way branching and while we are at it add in cuts ***************************************/ CglStored stored; for (row=0;row<size;row++) { for (column=0;column<size;column++) { int iColumn = row*size+column; int base = size*size + iColumn*size; int i; for ( i=0;i<size;i++) indices[i]=base+i; CbcNWay * obj = new CbcNWay(&model,size,indices,nObj); int seq[200]; int newUpper[200]; memset(newUpper,0,sizeof(newUpper)); for (i=0;i<size;i++) { int state=9999; int one=1; int nFix=1; // Fix real variable seq[0]=iColumn; newUpper[0]=valueOffset+i; int kColumn = base+i; int j; // same row for (j=0;j<size;j++) { int jColumn = row*size+j; int jjColumn = size*size+jColumn*size+i; if (jjColumn!=kColumn) { seq[nFix++]=jjColumn; // must be zero } } // same column for (j=0;j<size;j++) { int jColumn = j*size+column; int jjColumn = size*size+jColumn*size+i; if (jjColumn!=kColumn) { seq[nFix++]=jjColumn; // must be zero } } // same block int kRow = row/block_size; kRow *= block_size; int kCol = column/block_size; kCol *= block_size; for (j=kRow;j<kRow+block_size;j++) { for (int jc=kCol;jc<kCol+block_size;jc++) { int jColumn = j*size+jc; int jjColumn = size*size+jColumn*size+i; if (jjColumn!=kColumn) { seq[nFix++]=jjColumn; // must be zero } } } // seem to need following? const int * upperAddress = newUpper; const int * seqAddress = seq; CbcFixVariable fix(1,&state,&one,&upperAddress,&seqAddress,&nFix,&upperAddress,&seqAddress); obj->setConsequence(indices[i],fix); // Now do as cuts for (int kk=1;kk<nFix;kk++) { int jColumn = seq[kk]; int cutInd[2]; cutInd[0]=kColumn; if (jColumn>kColumn) { cutInd[1]=jColumn; stored.addCut(-COIN_DBL_MAX,1.0,2,cutInd,values); } } } objects[nObj]= obj; objects[nObj]->setPriority(nObj); nObj++; } } model.addObjects(nObj,objects); for (row=0;row<nObj;row++) delete objects[row]; delete [] objects; model.messageHandler()->setLogLevel(1); model.addCutGenerator(&stored,1,"stored"); // Say we want timings int numberGenerators = model.numberCutGenerators(); int iGenerator; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); generator->setTiming(true); } // Set this to get all solutions (all ones in newspapers should only have one) //model.setCutoffIncrement(-1.0e6); /*************************************** Do branch and bound ***************************************/ // Do complete search model.branchAndBound(); std::cout<<"took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; /*************************************** Print solution and check it is feasible We could modify output so could be imported by spreadsheet ***************************************/ if (model.getMinimizationObjValue()<1.0e50) { const double * solution = model.bestSolution(); int put=0; for (row=0;row<size;row++) { for (column=0;column<size;column++) { int value = (int) floor(solution[row*size+column]+0.5); assert (value>=lo[put]&&value<=up[put]); // save for later test lo[put++]=value; printf("%d ",value); } printf("\n"); } // check valid bool valid=true; // By row for (row=0;row<size;row++) { put=0; for (column=0;column<size;column++) which[put++]=row*size+column; assert (put==size); int i; for (i=0;i<put;i++) which[i]=(int) lo[which[i]]; std::sort(which,which+put); int last = valueOffset-1; for (i=0;i<put;i++) { int value=which[i]; if (value!=last+1) valid=false; last=value; } } // By column for (column=0;column<size;column++) { put=0; for (row=0;row<size;row++) which[put++]=row*size+column; assert (put==size); int i; for (i=0;i<put;i++) which[i]=(int) lo[which[i]]; std::sort(which,which+put); int last = valueOffset-1; for (i=0;i<put;i++) { int value=which[i]; if (value!=last+1) valid=false; last=value; } } // By box for (row=0;row<size;row+=block_size) { for (column=0;column<size;column+=block_size) { put=0; for (int row2=row;row2<row+block_size;row2++) { for (int column2=column;column2<column+block_size;column2++) which[put++]=row2*size+column2; } assert (put==size); int i; for (i=0;i<put;i++) which[i]=(int) lo[which[i]]; std::sort(which,which+put); int last = valueOffset-1; for (i=0;i<put;i++) { int value=which[i]; if (value!=last+1) valid=false; last=value; } } } if (valid) { printf("solution is valid\n"); } else { printf("solution is not valid\n"); abort(); } } return 0; }
int main (int argc, const char *argv[]) { OsiClpSolverInterface solver1; /* We are going to treat x1 and x2 as integer and x3 and x4 as a set. We define two new variables y1 == x1*x4 and y2 == x2*x3. We define a variable z == x1*x4/x2*x3 so y2*z == y1 (we will treat y2 as a set) Then we have objective - minimize w1 + w2 where w1 - w2 = 1.0/6.931 - z The model would be a lot smaller if we had column generation. */ // Create model CoinModel build; // Keep values of all variables for reporting purposes even if not necessary /* z is first, then x then y1,y2 then w1,w2 then y1 stuff, y2 stuff and finally y2 -> z stuff. For rows same but 2 per y then rest of z stuff */ int loInt=12; int hiInt=60; int ybaseA=5, ybaseB=9, ylen=hiInt-loInt+1; int base = ybaseB+2*2*ylen; int yylen = hiInt*hiInt-loInt*loInt+1; int zbase = 10; int i; // Do single variables double value[] ={1.0,1.0}; int row[2]; /* z - obviously we can't choose bounds too tight but we need bounds so choose 20% off as obviously feasible. fastest way to solve would be too run for a few seconds to get tighter bounds then re-formulate and solve. */ double loose=0.2; double loZ = (1-loose)*(1.0/6.931), hiZ = (1+loose)*(1.0/6.931); row[0]=0; // for reporting row[1]=zbase+1; // for real use build.addColumn(2,row,value,loZ, hiZ, 0.0); // x for (i=0;i<4;i++) { row[0]=i+1; build.addColumn(1,row,value,loInt, hiInt,0.0); // we don't need to say x2, x3 integer but won't hurt build.setInteger(i+1); } // y for (i=0;i<2;i++) { // y from x*x, and convexity row[0]=ybaseA+2*i; if (i==0) row[1]=zbase+2; // yb*z == ya else row[1]=zbase-1; // to feed into z build.addColumn(2,row,value,loInt*loInt, hiInt*hiInt,0.0); // we don't need to say integer but won't hurt build.setInteger(ybaseA+i); } // skip z convexity put w in final equation row[0]=zbase+1; build.addColumn(1,row,value,0.0,1.0,1.0); value[0]=-1.0; build.addColumn(1,row,value,0.0,1.0,1.0); // Do columns so we know where each is for (i=ybaseB;i<base+(2*yylen);i++) build.setColumnBounds(i,0.0,1.0); // Now do rows // z definition build.setRowBounds(0,0.0,0.0); for (i=0;i<yylen;i++) { // l build.setElement(0,base+2*i,-loZ); // u build.setElement(0,base+2*i+1,-hiZ); } // x for (i=0;i<2;i++) { int iVarRow = 1+i; int iSetRow = 4-i; // as it is x1*x4 and x2*x3 build.setRowBounds(iVarRow,0.0,0.0); build.setRowBounds(iSetRow,0.0,0.0); int j; int base2 = ybaseB + 2*ylen*i; for (j=0;j<ylen;j++) { // l build.setElement(iVarRow,base2+2*j,-loInt); build.setElement(iSetRow,base2+2*j,-loInt-j); // u build.setElement(iVarRow,base2+2*j+1,-hiInt); build.setElement(iSetRow,base2+2*j+1,-loInt-j); } } // y for (i=0;i<2;i++) { int iRow = 5+2*i; int iConvex = iRow+1; build.setRowBounds(iRow,0.0,0.0); build.setRowBounds(iConvex,1.0,1.0); int j; int base2 = ybaseB + 2*ylen*i; for (j=0;j<ylen;j++) { // l build.setElement(iRow,base2+2*j,-loInt*(j+loInt)); build.setElement(iConvex,base2+2*j,1.0); // u build.setElement(iRow,base2+2*j+1,-hiInt*(j+loInt)); build.setElement(iConvex,base2+2*j+1,1.0); } } // row that feeds into z and convexity build.setRowBounds(zbase-1,0.0,0.0); build.setRowBounds(zbase,1.0,1.0); for (i=0;i<yylen;i++) { // l build.setElement(zbase-1,base+2*i,-(i+loInt*loInt)); build.setElement(zbase,base+2*i,1.0); // u build.setElement(zbase-1,base+2*i+1,-(i+loInt*loInt)); build.setElement(zbase,base+2*i+1,1.0); } // and real equation rhs build.setRowBounds(zbase+1,1.0/6.931,1.0/6.931); // z*y build.setRowBounds(zbase+2,0.0,0.0); for (i=0;i<yylen;i++) { // l build.setElement(zbase+2,base+2*i,-(i+loInt*loInt)*loZ); // u build.setElement(zbase+2,base+2*i+1,-(i+loInt*loInt)*hiZ); } // And finally two more rows to break symmetry build.setRowBounds(zbase+3,-COIN_DBL_MAX,0.0); build.setElement(zbase+3,1,1.0); build.setElement(zbase+3,4,-1.0); build.setRowBounds(zbase+4,-COIN_DBL_MAX,0.0); build.setElement(zbase+4,2,1.0); build.setElement(zbase+4,3,-1.0); solver1.loadFromCoinModel(build); // To make CbcBranchLink simpler assume that all variables with same i are consecutive double time1 = CoinCpuTime(); solver1.initialSolve(); solver1.writeMps("bad"); CbcModel model(solver1); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); model.solver()->setHintParam(OsiDoScale,false,OsiHintTry); CbcObject ** objects = new CbcObject * [3]; /* Format is number in sets, number in each link, first variable in matrix) and then a weight for each in set to say where to branch. In this case use NULL to say 0,1,2 ... Finally a set number as ID. */ objects[0]=new CbcLink(&model,ylen,2,ybaseB,NULL,0); objects[0]->setPriority(10); objects[1]=new CbcLink(&model,ylen,2,ybaseB+2*ylen,NULL,0); objects[1]->setPriority(20); objects[2]=new CbcLink(&model,yylen,2,base,NULL,0); objects[2]->setPriority(1); model.addObjects(3,objects); for (i=0;i<3;i++) delete objects[i]; delete [] objects; model.messageHandler()->setLogLevel(1); // Do complete search model.setDblParam(CbcModel::CbcMaximumSeconds,1200.0); model.setDblParam(CbcModel::CbcCutoffIncrement,1.0e-8); model.branchAndBound(); std::cout<<"took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; if (model.getMinimizationObjValue()<1.0e50) { const double * solution = model.bestSolution(); int numberColumns = model.solver()->getNumCols(); double x1=solution[1]; double x2=solution[2]; double x3=solution[3]; double x4=solution[4]; printf("Optimal solution %g %g %g %g\n",x1,x2,x3,x4); for (int iColumn=0;iColumn<numberColumns;iColumn++) { double value=solution[iColumn]; if (fabs(value)>1.0e-7) std::cout<<iColumn<<" "<<value<<std::endl; } } return 0; }
//----------------------------------------------------------------------------- void CbcSolver2::resolve() { int numberColumns = modelPtr_->numberColumns(); if ((count_<10&&algorithm_==2)||!algorithm_) { OsiClpSolverInterface::resolve(); if (modelPtr_->status()==0) { count_++; double * solution = modelPtr_->primalColumnSolution(); int i; for (i=0;i<numberColumns;i++) { if (solution[i]>1.0e-6||modelPtr_->getStatus(i)==ClpSimplex::basic) { node_[i]=CoinMax(count_,node_[i]); howMany_[i]++; } } } else { if (!algorithm_==2) printf("infeasible early on\n"); } } else { // use counts int numberRows=modelPtr_->numberRows(); int * whichRow = new int[numberRows]; int * whichColumn = new int [numberColumns]; int i; const double * lower = modelPtr_->columnLower(); const double * upper = modelPtr_->columnUpper(); const double * rowUpper = modelPtr_->rowUpper(); bool equality=false; for (i=0;i<numberRows;i++) { if (rowUpper[i]==1.0) { equality=true; break; } } setBasis(basis_,modelPtr_); int nNewCol=0; // Column copy //const double * element = modelPtr_->matrix()->getElements(); const int * row = modelPtr_->matrix()->getIndices(); const CoinBigIndex * columnStart = modelPtr_->matrix()->getVectorStarts(); const int * columnLength = modelPtr_->matrix()->getVectorLengths(); int * rowActivity = new int[numberRows]; memset(rowActivity,0,numberRows*sizeof(int)); int * rowActivity2 = new int[numberRows]; memset(rowActivity2,0,numberRows*sizeof(int)); char * mark = new char[numberColumns]; memset(mark,0,numberColumns); // Get rows which are satisfied for (i=0;i<numberColumns;i++) { if (lower[i]>0.0) { CoinBigIndex j; for (j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; rowActivity2[iRow] ++; } } else if (!upper[i]) { mark[i]=2; // no good } } // If equality - check not infeasible if (equality) { bool feasible=true; for (i=0;i<numberRows;i++) { if (rowActivity2[i]>1) { feasible=false; break; } } if (!feasible) { delete [] rowActivity; delete [] rowActivity2; modelPtr_->setProblemStatus(1); delete [] whichRow; delete [] whichColumn; delete [] mark; printf("infeasible by inspection (over)\n"); return; } } int nNoGood=0; for (i=0;i<numberColumns;i++) { if (mark[i]==2) { nNoGood++; continue; } bool choose; if (algorithm_==1) choose = true; else choose = (node_[i]>count_-memory_&&node_[i]>0); bool any; if (equality) { // See if forced to be zero CoinBigIndex j; any=true; for (j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; if (rowActivity2[iRow]) any=false; // can't be in } } else { // See if not useful CoinBigIndex j; any=false; for (j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; if (!rowActivity2[iRow]) any=true; // useful } } if (!any&&!lower[i]) { choose=false; // and say can't be useful mark[i]=2; nNoGood++; } if (strategy_&&modelPtr_->getColumnStatus(i)==ClpSimplex::basic) choose=true; if (choose||lower[i]>0.0) { mark[i]=1; whichColumn[nNewCol++]=i; CoinBigIndex j; double value = upper[i]; if (value) { for (j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; rowActivity[iRow] ++; } } } } // If equality add in slacks CoinModel build; if (equality) { int row=0; for (i=0;i<numberRows;i++) { // put in all rows if wanted if(strategy_) rowActivity2[i]=0; if (!rowActivity2[i]) { double element=1.0; build.addColumn(1,&row,&element,0.0,1.0,1.0e8); // large cost row++; } } } int nOK=0; int nNewRow=0; for (i=0;i<numberRows;i++) { if (rowActivity[i]) nOK++; if (!rowActivity2[i]) whichRow[nNewRow++]=i; // not satisfied else modelPtr_->setRowStatus(i,ClpSimplex::basic); // make slack basic } if (nOK<numberRows) { for (i=0;i<numberColumns;i++) { if (!mark[i]) { CoinBigIndex j; int good=0; for (j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; if (!rowActivity[iRow]) { rowActivity[iRow] ++; good++; } } if (good) { nOK+=good; whichColumn[nNewCol++]=i; } } } } delete [] rowActivity; delete [] rowActivity2; if (nOK<numberRows) { modelPtr_->setProblemStatus(1); delete [] whichRow; delete [] whichColumn; delete [] mark; printf("infeasible by inspection\n"); return; } bool allIn=false; if (nNewCol+nNoGood+numberRows>numberColumns) { // add in all allIn=true; for (i=0;i<numberColumns;i++) { if (!mark[i]) { whichColumn[nNewCol++]=i; } } } ClpSimplex * temp = new ClpSimplex(modelPtr_,nNewRow,whichRow,nNewCol,whichColumn); if (equality) temp->addColumns(build); temp->setLogLevel(1); printf("small has %d rows and %d columns (%d impossible to help) %s\n", nNewRow,nNewCol,nNoGood,allIn ? "all in" : ""); temp->setSpecialOptions(128+512); temp->setDualObjectiveLimit(1.0e50); temp->dual(); assert (!temp->status()); double * solution = modelPtr_->primalColumnSolution(); const double * solution2 = temp->primalColumnSolution(); memset(solution,0,numberColumns*sizeof(double)); for (i=0;i<nNewCol;i++) { int iColumn = whichColumn[i]; solution[iColumn]=solution2[i]; modelPtr_->setStatus(iColumn,temp->getStatus(i)); } double * rowSolution = modelPtr_->primalRowSolution(); const double * rowSolution2 = temp->primalRowSolution(); double * dual = modelPtr_->dualRowSolution(); const double * dual2 = temp->dualRowSolution(); memset(dual,0,numberRows*sizeof(double)); for (i=0;i<nNewRow;i++) { int iRow=whichRow[i]; modelPtr_->setRowStatus(iRow,temp->getRowStatus(i)); rowSolution[iRow]=rowSolution2[i]; dual[iRow]=dual2[i]; } // See if optimal double * dj = modelPtr_->dualColumnSolution(); // get reduced cost for large problem // this assumes minimization memcpy(dj,modelPtr_->objective(),numberColumns*sizeof(double)); modelPtr_->transposeTimes(-1.0,dual,dj); modelPtr_->setObjectiveValue(temp->objectiveValue()); modelPtr_->setProblemStatus(0); int nBad=0; for (i=0;i<numberColumns;i++) { if (modelPtr_->getStatus(i)==ClpSimplex::atLowerBound &&upper[i]>lower[i]&&dj[i]<-1.0e-5) nBad++; } //modelPtr_->writeMps("bada.mps"); //temp->writeMps("badb.mps"); delete temp; if (nBad&&!allIn) { assert (algorithm_==2); //printf("%d bad\n",nBad); timesBad_++; // just non mark==2 int nAdded=0; for (i=0;i<numberColumns;i++) { if (!mark[i]) { whichColumn[nNewCol++]=i; nAdded++; } } assert (nAdded); { temp = new ClpSimplex(modelPtr_,nNewRow,whichRow,nNewCol,whichColumn); if (equality) temp->addColumns(build); temp->setLogLevel(2); temp->setSpecialOptions(128+512); temp->setDualObjectiveLimit(1.0e50); temp->primal(1); assert (!temp->status()); double * solution = modelPtr_->primalColumnSolution(); const double * solution2 = temp->primalColumnSolution(); memset(solution,0,numberColumns*sizeof(double)); for (i=0;i<nNewCol;i++) { int iColumn = whichColumn[i]; solution[iColumn]=solution2[i]; modelPtr_->setStatus(iColumn,temp->getStatus(i)); } double * rowSolution = modelPtr_->primalRowSolution(); const double * rowSolution2 = temp->primalRowSolution(); double * dual = modelPtr_->dualRowSolution(); const double * dual2 = temp->dualRowSolution(); memset(dual,0,numberRows*sizeof(double)); for (i=0;i<nNewRow;i++) { int iRow=whichRow[i]; modelPtr_->setRowStatus(iRow,temp->getRowStatus(i)); rowSolution[iRow]=rowSolution2[i]; dual[iRow]=dual2[i]; } modelPtr_->setObjectiveValue(temp->objectiveValue()); modelPtr_->setProblemStatus(0); iterationsBad_ += temp->numberIterations(); printf("clean %d\n",temp->numberIterations()); delete temp; } } delete [] mark; delete [] whichRow; delete [] whichColumn; basis_ = getBasis(modelPtr_); modelPtr_->setSpecialOptions(0); count_++; if ((count_%100)==0&&algorithm_==2) printf("count %d, bad %d - iterations %d\n",count_,timesBad_,iterationsBad_); for (i=0;i<numberColumns;i++) { if (solution[i]>1.0e-6||modelPtr_->getStatus(i)==ClpSimplex::basic) { node_[i]=CoinMax(count_,node_[i]); howMany_[i]++; } } if (modelPtr_->objectiveValue()>=modelPtr_->dualObjectiveLimit()) modelPtr_->setProblemStatus(1); } }
OsiSolverInterface * expandKnapsack(CoinModel & model, int * whichColumn, int * knapsackStart, int * knapsackRow, int &numberKnapsack, CglStored & stored, int logLevel, int fixedPriority, int SOSPriority, CoinModel & tightenedModel) { int maxTotal = numberKnapsack; // load from coin model OsiSolverLink *si = new OsiSolverLink(); OsiSolverInterface * finalModel = NULL; si->setDefaultMeshSize(0.001); // need some relative granularity si->setDefaultBound(100.0); si->setDefaultMeshSize(0.01); si->setDefaultBound(100000.0); si->setIntegerPriority(1000); si->setBiLinearPriority(10000); si->load(model, true, logLevel); // get priorities const int * priorities = model.priorities(); int numberColumns = model.numberColumns(); if (priorities) { OsiObject ** objects = si->objects(); int numberObjects = si->numberObjects(); for (int iObj = 0; iObj < numberObjects; iObj++) { int iColumn = objects[iObj]->columnNumber(); if (iColumn >= 0 && iColumn < numberColumns) { #ifndef NDEBUG OsiSimpleInteger * obj = dynamic_cast <OsiSimpleInteger *>(objects[iObj]) ; #endif assert (obj); int iPriority = priorities[iColumn]; if (iPriority > 0) objects[iObj]->setPriority(iPriority); } } if (fixedPriority > 0) { si->setFixedPriority(fixedPriority); } if (SOSPriority < 0) SOSPriority = 100000; } CoinModel coinModel = *si->coinModel(); assert(coinModel.numberRows() > 0); tightenedModel = coinModel; int numberRows = coinModel.numberRows(); // Mark variables int * whichKnapsack = new int [numberColumns]; int iRow, iColumn; for (iColumn = 0; iColumn < numberColumns; iColumn++) whichKnapsack[iColumn] = -1; int kRow; bool badModel = false; // analyze if (logLevel > 1) { for (iRow = 0; iRow < numberRows; iRow++) { /* Just obvious one at first positive non unit coefficients all integer positive rowUpper for now - linear (but further down in code may use nonlinear) column bounds should be tight */ //double lower = coinModel.getRowLower(iRow); double upper = coinModel.getRowUpper(iRow); if (upper < 1.0e10) { CoinModelLink triple = coinModel.firstInRow(iRow); bool possible = true; int n = 0; int n1 = 0; while (triple.column() >= 0) { int iColumn = triple.column(); const char * el = coinModel.getElementAsString(iRow, iColumn); if (!strcmp("Numeric", el)) { if (coinModel.columnLower(iColumn) == coinModel.columnUpper(iColumn)) { triple = coinModel.next(triple); continue; // fixed } double value = coinModel.getElement(iRow, iColumn); if (value < 0.0) { possible = false; } else { n++; if (value == 1.0) n1++; if (coinModel.columnLower(iColumn) < 0.0) possible = false; if (!coinModel.isInteger(iColumn)) possible = false; if (whichKnapsack[iColumn] >= 0) possible = false; } } else { possible = false; // non linear } triple = coinModel.next(triple); } if (n - n1 > 1 && possible) { double lower = coinModel.getRowLower(iRow); double upper = coinModel.getRowUpper(iRow); CoinModelLink triple = coinModel.firstInRow(iRow); while (triple.column() >= 0) { int iColumn = triple.column(); lower -= coinModel.columnLower(iColumn) * triple.value(); upper -= coinModel.columnLower(iColumn) * triple.value(); triple = coinModel.next(triple); } printf("%d is possible %g <=", iRow, lower); // print triple = coinModel.firstInRow(iRow); while (triple.column() >= 0) { int iColumn = triple.column(); if (coinModel.columnLower(iColumn) != coinModel.columnUpper(iColumn)) printf(" (%d,el %g up %g)", iColumn, triple.value(), coinModel.columnUpper(iColumn) - coinModel.columnLower(iColumn)); triple = coinModel.next(triple); } printf(" <= %g\n", upper); } } } } numberKnapsack = 0; for (kRow = 0; kRow < numberRows; kRow++) { iRow = kRow; /* Just obvious one at first positive non unit coefficients all integer positive rowUpper for now - linear (but further down in code may use nonlinear) column bounds should be tight */ //double lower = coinModel.getRowLower(iRow); double upper = coinModel.getRowUpper(iRow); if (upper < 1.0e10) { CoinModelLink triple = coinModel.firstInRow(iRow); bool possible = true; int n = 0; int n1 = 0; while (triple.column() >= 0) { int iColumn = triple.column(); const char * el = coinModel.getElementAsString(iRow, iColumn); if (!strcmp("Numeric", el)) { if (coinModel.columnLower(iColumn) == coinModel.columnUpper(iColumn)) { triple = coinModel.next(triple); continue; // fixed } double value = coinModel.getElement(iRow, iColumn); if (value < 0.0) { possible = false; } else { n++; if (value == 1.0) n1++; if (coinModel.columnLower(iColumn) < 0.0) possible = false; if (!coinModel.isInteger(iColumn)) possible = false; if (whichKnapsack[iColumn] >= 0) possible = false; } } else { possible = false; // non linear } triple = coinModel.next(triple); } if (n - n1 > 1 && possible) { // try CoinModelLink triple = coinModel.firstInRow(iRow); while (triple.column() >= 0) { int iColumn = triple.column(); if (coinModel.columnLower(iColumn) != coinModel.columnUpper(iColumn)) whichKnapsack[iColumn] = numberKnapsack; triple = coinModel.next(triple); } knapsackRow[numberKnapsack++] = iRow; } } } if (logLevel > 0) printf("%d out of %d candidate rows are possible\n", numberKnapsack, numberRows); // Check whether we can get rid of nonlinearities /* mark rows -2 in knapsack and other variables -1 not involved n only in knapsack n */ int * markRow = new int [numberRows]; for (iRow = 0; iRow < numberRows; iRow++) markRow[iRow] = -1; int canDo = 1; // OK and linear for (iColumn = 0; iColumn < numberColumns; iColumn++) { CoinModelLink triple = coinModel.firstInColumn(iColumn); int iKnapsack = whichKnapsack[iColumn]; bool linear = true; // See if quadratic objective const char * expr = coinModel.getColumnObjectiveAsString(iColumn); if (strcmp(expr, "Numeric")) { linear = false; } while (triple.row() >= 0) { int iRow = triple.row(); if (iKnapsack >= 0) { if (markRow[iRow] == -1) { markRow[iRow] = iKnapsack; } else if (markRow[iRow] != iKnapsack) { markRow[iRow] = -2; } } const char * expr = coinModel.getElementAsString(iRow, iColumn); if (strcmp(expr, "Numeric")) { linear = false; } triple = coinModel.next(triple); } if (!linear) { if (whichKnapsack[iColumn] < 0) { canDo = 0; break; } else { canDo = 2; } } } int * markKnapsack = NULL; double * coefficient = NULL; double * linear = NULL; int * whichRow = NULL; int * lookupRow = NULL; badModel = (canDo == 0); if (numberKnapsack && canDo) { /* double check - OK if no nonlinear nonlinear only on columns in knapsack nonlinear only on columns in knapsack * ONE other - same for all in knapsack AND that is only row connected to knapsack (theoretically could split knapsack if two other and small numbers) also ONE could be ONE expression - not just a variable */ int iKnapsack; markKnapsack = new int [numberKnapsack]; coefficient = new double [numberKnapsack]; linear = new double [numberColumns]; for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) markKnapsack[iKnapsack] = -1; if (canDo == 2) { for (iRow = -1; iRow < numberRows; iRow++) { int numberOdd; CoinPackedMatrix * row = coinModel.quadraticRow(iRow, linear, numberOdd); if (row) { // see if valid const double * element = row->getElements(); const int * column = row->getIndices(); const CoinBigIndex * columnStart = row->getVectorStarts(); const int * columnLength = row->getVectorLengths(); int numberLook = row->getNumCols(); for (int i = 0; i < numberLook; i++) { int iKnapsack = whichKnapsack[i]; if (iKnapsack < 0) { // might be able to swap - but for now can't have knapsack in for (int j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iColumn = column[j]; if (whichKnapsack[iColumn] >= 0) { canDo = 0; // no good badModel = true; break; } } } else { // OK if in same knapsack - or maybe just one int marked = markKnapsack[iKnapsack]; for (int j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iColumn = column[j]; if (whichKnapsack[iColumn] != iKnapsack && whichKnapsack[iColumn] >= 0) { canDo = 0; // no good badModel = true; break; } else if (marked == -1) { markKnapsack[iKnapsack] = iColumn; marked = iColumn; coefficient[iKnapsack] = element[j]; coinModel.associateElement(coinModel.columnName(iColumn), 1.0); } else if (marked != iColumn) { badModel = true; canDo = 0; // no good break; } else { // could manage with different coefficients - but for now ... assert(coefficient[iKnapsack] == element[j]); } } } } delete row; } } } if (canDo) { // for any rows which are cuts whichRow = new int [numberRows]; lookupRow = new int [numberRows]; bool someNonlinear = false; double maxCoefficient = 1.0; for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) { if (markKnapsack[iKnapsack] >= 0) { someNonlinear = true; int iColumn = markKnapsack[iKnapsack]; maxCoefficient = CoinMax(maxCoefficient, fabs(coefficient[iKnapsack] * coinModel.columnUpper(iColumn))); } } if (someNonlinear) { // associate all columns to stop possible error messages for (iColumn = 0; iColumn < numberColumns; iColumn++) { coinModel.associateElement(coinModel.columnName(iColumn), 1.0); } } ClpSimplex tempModel; tempModel.loadProblem(coinModel); // Create final model - first without knapsacks int nCol = 0; int nRow = 0; for (iRow = 0; iRow < numberRows; iRow++) { if (markRow[iRow] < 0) { lookupRow[iRow] = nRow; whichRow[nRow++] = iRow; } else { lookupRow[iRow] = -1; } } for (iColumn = 0; iColumn < numberColumns; iColumn++) { if (whichKnapsack[iColumn] < 0) whichColumn[nCol++] = iColumn; } ClpSimplex finalModelX(&tempModel, nRow, whichRow, nCol, whichColumn, false, false, false); OsiClpSolverInterface finalModelY(&finalModelX, true); finalModel = finalModelY.clone(); finalModelY.releaseClp(); // Put back priorities const int * priorities = model.priorities(); if (priorities) { finalModel->findIntegers(false); OsiObject ** objects = finalModel->objects(); int numberObjects = finalModel->numberObjects(); for (int iObj = 0; iObj < numberObjects; iObj++) { int iColumn = objects[iObj]->columnNumber(); if (iColumn >= 0 && iColumn < nCol) { #ifndef NDEBUG OsiSimpleInteger * obj = dynamic_cast <OsiSimpleInteger *>(objects[iObj]) ; #endif assert (obj); int iPriority = priorities[whichColumn[iColumn]]; if (iPriority > 0) objects[iObj]->setPriority(iPriority); } } } for (iRow = 0; iRow < numberRows; iRow++) { whichRow[iRow] = iRow; } int numberOther = finalModel->getNumCols(); int nLargest = 0; int nelLargest = 0; int nTotal = 0; for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) { iRow = knapsackRow[iKnapsack]; int nCreate = maxTotal; int nelCreate = coinModel.expandKnapsack(iRow, nCreate, NULL, NULL, NULL, NULL); if (nelCreate < 0) badModel = true; nTotal += nCreate; nLargest = CoinMax(nLargest, nCreate); nelLargest = CoinMax(nelLargest, nelCreate); } if (nTotal > maxTotal) badModel = true; if (!badModel) { // Now arrays for building nelLargest = CoinMax(nelLargest, nLargest) + 1; double * buildObj = new double [nLargest]; double * buildElement = new double [nelLargest]; int * buildStart = new int[nLargest+1]; int * buildRow = new int[nelLargest]; // alow for integers in knapsacks OsiObject ** object = new OsiObject * [numberKnapsack+nTotal]; int nSOS = 0; int nObj = numberKnapsack; for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) { knapsackStart[iKnapsack] = finalModel->getNumCols(); iRow = knapsackRow[iKnapsack]; int nCreate = 10000; coinModel.expandKnapsack(iRow, nCreate, buildObj, buildStart, buildRow, buildElement); // Redo row numbers for (iColumn = 0; iColumn < nCreate; iColumn++) { for (int j = buildStart[iColumn]; j < buildStart[iColumn+1]; j++) { int jRow = buildRow[j]; jRow = lookupRow[jRow]; assert (jRow >= 0 && jRow < nRow); buildRow[j] = jRow; } } finalModel->addCols(nCreate, buildStart, buildRow, buildElement, NULL, NULL, buildObj); int numberFinal = finalModel->getNumCols(); for (iColumn = numberOther; iColumn < numberFinal; iColumn++) { if (markKnapsack[iKnapsack] < 0) { finalModel->setColUpper(iColumn, maxCoefficient); finalModel->setInteger(iColumn); } else { finalModel->setColUpper(iColumn, maxCoefficient + 1.0); finalModel->setInteger(iColumn); } OsiSimpleInteger * sosObject = new OsiSimpleInteger(finalModel, iColumn); sosObject->setPriority(1000000); object[nObj++] = sosObject; buildRow[iColumn-numberOther] = iColumn; buildElement[iColumn-numberOther] = 1.0; } if (markKnapsack[iKnapsack] < 0) { // convexity row finalModel->addRow(numberFinal - numberOther, buildRow, buildElement, 1.0, 1.0); } else { int iColumn = markKnapsack[iKnapsack]; int n = numberFinal - numberOther; buildRow[n] = iColumn; buildElement[n++] = -fabs(coefficient[iKnapsack]); // convexity row (sort of) finalModel->addRow(n, buildRow, buildElement, 0.0, 0.0); OsiSOS * sosObject = new OsiSOS(finalModel, n - 1, buildRow, NULL, 1); sosObject->setPriority(iKnapsack + SOSPriority); // Say not integral even if is (switch off heuristics) sosObject->setIntegerValued(false); object[nSOS++] = sosObject; } numberOther = numberFinal; } finalModel->addObjects(nObj, object); for (iKnapsack = 0; iKnapsack < nObj; iKnapsack++) delete object[iKnapsack]; delete [] object; // Can we move any rows to cuts const int * cutMarker = coinModel.cutMarker(); if (cutMarker && 0) { printf("AMPL CUTS OFF until global cuts fixed\n"); cutMarker = NULL; } if (cutMarker) { // Row copy const CoinPackedMatrix * matrixByRow = finalModel->getMatrixByRow(); const double * elementByRow = matrixByRow->getElements(); const int * column = matrixByRow->getIndices(); const CoinBigIndex * rowStart = matrixByRow->getVectorStarts(); const int * rowLength = matrixByRow->getVectorLengths(); const double * rowLower = finalModel->getRowLower(); const double * rowUpper = finalModel->getRowUpper(); int nDelete = 0; for (iRow = 0; iRow < numberRows; iRow++) { if (cutMarker[iRow] && lookupRow[iRow] >= 0) { int jRow = lookupRow[iRow]; whichRow[nDelete++] = jRow; int start = rowStart[jRow]; stored.addCut(rowLower[jRow], rowUpper[jRow], rowLength[jRow], column + start, elementByRow + start); } } finalModel->deleteRows(nDelete, whichRow); } knapsackStart[numberKnapsack] = finalModel->getNumCols(); delete [] buildObj; delete [] buildElement; delete [] buildStart; delete [] buildRow; finalModel->writeMps("full"); } } } delete [] whichKnapsack; delete [] markRow; delete [] markKnapsack; delete [] coefficient; delete [] linear; delete [] whichRow; delete [] lookupRow; delete si; si = NULL; if (!badModel && finalModel) { finalModel->setDblParam(OsiObjOffset, coinModel.objectiveOffset()); return finalModel; } else { delete finalModel; printf("can't make knapsacks - did you set fixedPriority (extra1)\n"); return NULL; } }