//-------------------------------------------------------------------------- void OsiCpxSolverInterfaceUnitTest( const std::string & mpsDir, const std::string & netlibDir ) { // Test default constructor { OsiCpxSolverInterface m; assert( m.obj_==NULL ); assert( m.collower_==NULL ); assert( m.colupper_==NULL ); assert( m.coltype_==NULL ); assert( m.rowsense_==NULL ); assert( m.rhs_==NULL ); assert( m.rowrange_==NULL ); assert( m.rowlower_==NULL ); assert( m.rowupper_==NULL ); assert( m.colsol_==NULL ); assert( m.rowsol_==NULL ); assert( m.matrixByRow_==NULL ); assert( m.matrixByCol_==NULL ); assert( m.coltype_==NULL ); assert( m.coltypesize_==0 ); assert( m.getApplicationData() == NULL ); int i=2346; m.setApplicationData(&i); assert( *((int *)(m.getApplicationData())) == i ); } { CoinRelFltEq eq; OsiCpxSolverInterface m; std::string fn = mpsDir+"exmip1"; m.readMps(fn.c_str(),"mps"); int ad = 13579; m.setApplicationData(&ad); assert( *((int *)(m.getApplicationData())) == ad ); { assert( m.getNumCols()==8 ); const CoinPackedMatrix * colCopy = m.getMatrixByCol(); assert( colCopy->getNumCols() == 8 ); assert( colCopy->getMajorDim() == 8 ); assert( colCopy->getNumRows() == 5 ); assert( colCopy->getMinorDim() == 5 ); assert (colCopy->getVectorLengths()[7] == 2 ); CoinPackedMatrix revColCopy; revColCopy.reverseOrderedCopyOf(*colCopy); CoinPackedMatrix rev2ColCopy; rev2ColCopy.reverseOrderedCopyOf(revColCopy); assert( rev2ColCopy.getNumCols() == 8 ); assert( rev2ColCopy.getMajorDim() == 8 ); assert( rev2ColCopy.getNumRows() == 5 ); assert( rev2ColCopy.getMinorDim() == 5 ); assert( rev2ColCopy.getVectorLengths()[7] == 2 ); } { OsiCpxSolverInterface im; assert( im.getNumCols() == 0 ); } // Test copy constructor and assignment operator { OsiCpxSolverInterface lhs; { assert( *((int *)(m.getApplicationData())) == ad ); OsiCpxSolverInterface im(m); assert( *((int *)(im.getApplicationData())) == ad ); OsiCpxSolverInterface imC1(im); assert( imC1.lp_ != im.lp_ ); assert( imC1.getNumCols() == im.getNumCols() ); assert( imC1.getNumRows() == im.getNumRows() ); assert( *((int *)(imC1.getApplicationData())) == ad ); //im.setModelPtr(m); OsiCpxSolverInterface imC2(im); assert( imC2.lp_ != im.lp_ ); assert( imC2.getNumCols() == im.getNumCols() ); assert( imC2.getNumRows() == im.getNumRows() ); assert( *((int *)(imC2.getApplicationData())) == ad ); assert( imC2.lp_ != imC1.lp_ ); lhs=imC2; } // Test that lhs has correct values even though rhs has gone out of scope assert( lhs.lp_ != m.lp_ ); assert( lhs.getNumCols() == m.getNumCols() ); assert( lhs.getNumRows() == m.getNumRows() ); assert( *((int *)(lhs.getApplicationData())) == ad ); } // Test clone { OsiCpxSolverInterface cplexSi(m); OsiSolverInterface * siPtr = &cplexSi; OsiSolverInterface * siClone = siPtr->clone(); OsiCpxSolverInterface * cplexClone = dynamic_cast<OsiCpxSolverInterface*>(siClone); assert( cplexClone != NULL ); assert( cplexClone->lp_ != cplexSi.lp_ ); assert( cplexClone->getNumRows() == cplexSi.getNumRows() ); assert( cplexClone->getNumCols() == m.getNumCols() ); assert( *((int *)(cplexClone->getApplicationData())) == ad ); delete siClone; } // test infinity { OsiCpxSolverInterface si; assert( eq( si.getInfinity(), CPX_INFBOUND ) ); } // Test setting solution { OsiCpxSolverInterface m1(m); int i; double * cs = new double[m1.getNumCols()]; for ( i = 0; i < m1.getNumCols(); i++ ) cs[i] = i + .5; m1.setColSolution(cs); for ( i = 0; i < m1.getNumCols(); i++ ) assert(m1.getColSolution()[i] == i + .5); double * rs = new double[m1.getNumRows()]; for ( i = 0; i < m1.getNumRows(); i++ ) rs[i] = i - .5; m1.setRowPrice(rs); for ( i = 0; i < m1.getNumRows(); i++ ) assert(m1.getRowPrice()[i] == i - .5); delete [] cs; delete [] rs; } // Test fraction Indices { OsiCpxSolverInterface fim; std::string fn = mpsDir+"exmip1"; fim.readMps(fn.c_str(),"mps"); //fim.setModelPtr(m); // exmip1.mps has 2 integer variables with index 2 & 3 assert( fim.isContinuous(0) ); assert( fim.isContinuous(1) ); assert( !fim.isContinuous(2) ); assert( !fim.isContinuous(3) ); assert( fim.isContinuous(4) ); assert( !fim.isInteger(0) ); assert( !fim.isInteger(1) ); assert( fim.isInteger(2) ); assert( fim.isInteger(3) ); assert( !fim.isInteger(4) ); assert( !fim.isBinary(0) ); assert( !fim.isBinary(1) ); assert( fim.isBinary(2) ); assert( fim.isBinary(3) ); assert( !fim.isBinary(4) ); assert( !fim.isIntegerNonBinary(0) ); assert( !fim.isIntegerNonBinary(1) ); assert( !fim.isIntegerNonBinary(2) ); assert( !fim.isIntegerNonBinary(3) ); assert( !fim.isIntegerNonBinary(4) ); // Test fractionalIndices { // Set a solution vector double * cs = new double[fim.getNumCols()]; for ( int i = 0; i < fim.getNumCols(); cs[i++] = 0.0 ); cs[2] = 2.9; cs[3] = 3.0; fim.setColSolution(cs); OsiVectorInt fi = fim.getFractionalIndices(); assert( fi.size() == 1 ); assert( fi[0]==2 ); // Set integer variables very close to integer values cs[2] = 5 + .00001/2.; cs[3] = 8 - .00001/2.; fim.setColSolution(cs); fi = fim.getFractionalIndices(1e-5); assert( fi.size() == 0 ); // Set integer variables close, but beyond tolerances cs[2] = 5 + .00001*2.; cs[3] = 8 - .00001*2.; fim.setColSolution(cs); fi = fim.getFractionalIndices(1e-5); assert( fi.size() == 2 ); assert( fi[0]==2 ); assert( fi[1]==3 ); delete [] cs; } // Change data so column 2 & 3 are integerNonBinary fim.setColUpper(2, 5); fim.setColUpper(3, 6.0); assert( !fim.isBinary(0) ); assert( !fim.isBinary(1) ); assert( !fim.isBinary(2) ); assert( !fim.isBinary(3) ); assert( !fim.isBinary(4) ); assert( !fim.isIntegerNonBinary(0) ); assert( !fim.isIntegerNonBinary(1) ); assert( fim.isIntegerNonBinary(2) ); assert( fim.isIntegerNonBinary(3) ); assert( !fim.isIntegerNonBinary(4) ); } // Test apply cuts method { OsiCpxSolverInterface im(m); OsiCuts cuts; // Generate some cuts { // Get number of rows and columns in model int nr=im.getNumRows(); int nc=im.getNumCols(); assert( nr == 5 ); assert( nc == 8 ); // Generate a valid row cut from thin air int c; { 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]=((double)c)*((double)c); OsiRowCut rc; rc.setRow(nc,inx,el); rc.setLb(-100.); rc.setUb(100.); rc.setEffectiveness(22); cuts.insert(rc); delete[]el; delete[]inx; } // Generate valid col cut from thin air { const double * cplexColLB = im.getColLower(); const double * cplexColUB = im.getColUpper(); int *inx = new int[nc]; for (c=0;c<nc;c++) inx[c]=c; double *lb = new double[nc]; double *ub = new double[nc]; for (c=0;c<nc;c++) lb[c]=cplexColLB[c]+0.001; for (c=0;c<nc;c++) ub[c]=cplexColUB[c]-0.001; OsiColCut cc; cc.setLbs(nc,inx,lb); cc.setUbs(nc,inx,ub); cuts.insert(cc); delete [] ub; delete [] lb; delete [] inx; } { // Generate a row and column cut which have are ineffective OsiRowCut * rcP= new OsiRowCut; rcP->setEffectiveness(-1.); cuts.insert(rcP); assert(rcP==NULL); OsiColCut * ccP= new OsiColCut; ccP->setEffectiveness(-12.); cuts.insert(ccP); assert(ccP==NULL); } { //Generate inconsistent Row cut OsiRowCut rc; const int ne=1; int inx[ne]={-10}; double el[ne]={2.5}; rc.setRow(ne,inx,el); rc.setLb(3.); rc.setUb(4.); assert(!rc.consistent()); cuts.insert(rc); } { //Generate inconsistent col cut OsiColCut cc; const int ne=1; int inx[ne]={-10}; double el[ne]={2.5}; cc.setUbs(ne,inx,el); assert(!cc.consistent()); cuts.insert(cc); } { // Generate row cut which is inconsistent for model m OsiRowCut rc; const int ne=1; int inx[ne]={10}; double el[ne]={2.5}; rc.setRow(ne,inx,el); assert(rc.consistent()); assert(!rc.consistent(im)); cuts.insert(rc); } { // Generate col cut which is inconsistent for model m OsiColCut cc; const int ne=1; int inx[ne]={30}; double el[ne]={2.0}; cc.setLbs(ne,inx,el); assert(cc.consistent()); assert(!cc.consistent(im)); cuts.insert(cc); } { // Generate col cut which is infeasible OsiColCut cc; const int ne=1; int inx[ne]={0}; double el[ne]={2.0}; cc.setUbs(ne,inx,el); cc.setEffectiveness(1000.); assert(cc.consistent()); assert(cc.consistent(im)); assert(cc.infeasible(im)); cuts.insert(cc); } } assert(cuts.sizeRowCuts()==4); assert(cuts.sizeColCuts()==5); OsiSolverInterface::ApplyCutsReturnCode rc = im.applyCuts(cuts); assert( rc.getNumIneffective() == 2 ); assert( rc.getNumApplied() == 2 ); assert( rc.getNumInfeasible() == 1 ); assert( rc.getNumInconsistentWrtIntegerModel() == 2 ); assert( rc.getNumInconsistent() == 2 ); assert( cuts.sizeCuts() == rc.getNumIneffective() + rc.getNumApplied() + rc.getNumInfeasible() + rc.getNumInconsistentWrtIntegerModel() + rc.getNumInconsistent() ); } { OsiCpxSolverInterface cplexSi(m); int nc = cplexSi.getNumCols(); int nr = cplexSi.getNumRows(); const double * cl = cplexSi.getColLower(); const double * cu = cplexSi.getColUpper(); const double * rl = cplexSi.getRowLower(); const double * ru = cplexSi.getRowUpper(); assert( nc == 8 ); assert( nr == 5 ); assert( eq(cl[0],2.5) ); assert( eq(cl[1],0.0) ); assert( eq(cu[1],4.1) ); assert( eq(cu[2],1.0) ); assert( eq(rl[0],2.5) ); assert( eq(rl[4],3.0) ); assert( eq(ru[1],2.1) ); assert( eq(ru[4],15.0) ); double newCs[8] = {1., 2., 3., 4., 5., 6., 7., 8.}; cplexSi.setColSolution(newCs); const double * cs = cplexSi.getColSolution(); assert( eq(cs[0],1.0) ); assert( eq(cs[7],8.0) ); { OsiCpxSolverInterface solnSi(cplexSi); const double * cs = solnSi.getColSolution(); assert( eq(cs[0],1.0) ); assert( eq(cs[7],8.0) ); } assert( !eq(cl[3],1.2345) ); cplexSi.setColLower( 3, 1.2345 ); assert( eq(cplexSi.getColLower()[3],1.2345) ); assert( !eq(cu[4],10.2345) ); cplexSi.setColUpper( 4, 10.2345 ); assert( eq(cplexSi.getColUpper()[4],10.2345) ); assert( eq(cplexSi.getObjValue(),0.0) ); assert( eq( cplexSi.getObjCoefficients()[0], 1.0) ); assert( eq( cplexSi.getObjCoefficients()[1], 0.0) ); assert( eq( cplexSi.getObjCoefficients()[2], 0.0) ); assert( eq( cplexSi.getObjCoefficients()[3], 0.0) ); assert( eq( cplexSi.getObjCoefficients()[4], 2.0) ); assert( eq( cplexSi.getObjCoefficients()[5], 0.0) ); assert( eq( cplexSi.getObjCoefficients()[6], 0.0) ); assert( eq( cplexSi.getObjCoefficients()[7], -1.0) ); } // Test getMatrixByRow method { const OsiCpxSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByRow(); //const CoinPackedMatrix * osmP = dynamic_cast(const OsiCpxPackedMatrix*)(smP); //assert( osmP!=NULL ); CoinRelFltEq eq; const double * ev = smP->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = smP->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = smP->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7] == 2 ); assert( ei[8] == 5 ); assert( ei[9] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); assert( smP->getMajorDim() == 5 ); assert( smP->getNumElements() == 14 ); } //-------------- // Test rowsense, rhs, rowrange, getMatrixByRow { OsiCpxSolverInterface lhs; { #if 0 assert( m.obj_==NULL ); assert( m.collower_==NULL ); assert( m.colupper_==NULL ); assert( m.rowrange_==NULL ); assert( m.rowsense_==NULL ); assert( m.rhs_==NULL ); assert( m.rowlower_==NULL ); assert( m.rowupper_==NULL ); assert( m.colsol_==NULL ); assert( m.rowsol_==NULL ); assert( m.getMatrixByRow_==NULL ); #endif OsiCpxSolverInterface siC1(m); assert( siC1.obj_==NULL ); assert( siC1.collower_==NULL ); assert( siC1.colupper_==NULL ); // assert( siC1.coltype_==NULL ); assert( siC1.rowrange_==NULL ); assert( siC1.rowsense_==NULL ); assert( siC1.rhs_==NULL ); assert( siC1.rowlower_==NULL ); assert( siC1.rowupper_==NULL ); assert( siC1.colsol_!=NULL ); assert( siC1.rowsol_!=NULL ); assert( siC1.matrixByRow_==NULL ); const char * siC1rs = siC1.getRowSense(); assert( siC1rs[0]=='G' ); assert( siC1rs[1]=='L' ); assert( siC1rs[2]=='E' ); assert( siC1rs[3]=='R' ); assert( siC1rs[4]=='R' ); const double * siC1rhs = siC1.getRightHandSide(); assert( eq(siC1rhs[0],2.5) ); assert( eq(siC1rhs[1],2.1) ); assert( eq(siC1rhs[2],4.0) ); assert( eq(siC1rhs[3],5.0) ); assert( eq(siC1rhs[4],15.) ); const double * siC1rr = siC1.getRowRange(); assert( eq(siC1rr[0],0.0) ); assert( eq(siC1rr[1],0.0) ); assert( eq(siC1rr[2],0.0) ); assert( eq(siC1rr[3],5.0-1.8) ); assert( eq(siC1rr[4],15.0-3.0) ); const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow(); assert( siC1mbr != NULL ); const double * ev = siC1mbr->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = siC1mbr->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = siC1mbr->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7] == 2 ); assert( ei[8] == 5 ); assert( ei[9] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); assert( siC1mbr->getMajorDim() == 5 ); assert( siC1mbr->getNumElements() == 14 ); assert( siC1rs == siC1.getRowSense() ); assert( siC1rhs == siC1.getRightHandSide() ); assert( siC1rr == siC1.getRowRange() ); // Change CPLEX 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); // Since model was changed, test that cached // data is now freed. assert( siC1.obj_==NULL ); assert( siC1.collower_==NULL ); assert( siC1.colupper_==NULL ); // assert( siC1.coltype_==NULL ); assert( siC1.rowrange_==NULL ); assert( siC1.rowsense_==NULL ); assert( siC1.rhs_==NULL ); assert( siC1.rowlower_==NULL ); assert( siC1.rowupper_==NULL ); assert( siC1.colsol_==NULL ); assert( siC1.rowsol_==NULL ); assert( siC1.matrixByRow_==NULL ); siC1rs = siC1.getRowSense(); siC1rhs = siC1.getRightHandSide(); siC1rr = siC1.getRowRange(); assert( siC1rs[0]=='G' ); assert( siC1rs[1]=='L' ); assert( siC1rs[2]=='E' ); assert( siC1rs[3]=='R' ); assert( siC1rs[4]=='R' ); assert( siC1rs[5]=='N' ); assert( eq(siC1rhs[0],2.5) ); assert( eq(siC1rhs[1],2.1) ); assert( eq(siC1rhs[2],4.0) ); assert( eq(siC1rhs[3],5.0) ); assert( eq(siC1rhs[4],15.) ); assert( eq(siC1rhs[5],0.0) ); assert( eq(siC1rr[0],0.0) ); assert( eq(siC1rr[1],0.0) ); assert( eq(siC1rr[2],0.0) ); assert( eq(siC1rr[3],5.0-1.8) ); assert( eq(siC1rr[4],15.0-3.0) ); assert( eq(siC1rr[5],0.0) ); lhs=siC1; } // Test that lhs has correct values even though siC1 has gone out of scope assert( lhs.obj_==NULL ); assert( lhs.collower_==NULL ); assert( lhs.colupper_==NULL ); // assert( lhs.coltype_==NULL ); assert( lhs.rowrange_==NULL ); assert( lhs.rowsense_==NULL ); assert( lhs.rhs_==NULL ); assert( lhs.rowlower_==NULL ); assert( lhs.rowupper_==NULL ); assert( lhs.colsol_!=NULL ); assert( lhs.rowsol_!=NULL ); assert( lhs.matrixByRow_==NULL ); const char * lhsrs = lhs.getRowSense(); assert( lhsrs[0]=='G' ); assert( lhsrs[1]=='L' ); assert( lhsrs[2]=='E' ); assert( lhsrs[3]=='R' ); assert( lhsrs[4]=='R' ); assert( lhsrs[5]=='N' ); const double * lhsrhs = lhs.getRightHandSide(); assert( eq(lhsrhs[0],2.5) ); assert( eq(lhsrhs[1],2.1) ); assert( eq(lhsrhs[2],4.0) ); assert( eq(lhsrhs[3],5.0) ); assert( eq(lhsrhs[4],15.) ); assert( eq(lhsrhs[5],0.0) ); const double *lhsrr = lhs.getRowRange(); assert( eq(lhsrr[0],0.0) ); assert( eq(lhsrr[1],0.0) ); assert( eq(lhsrr[2],0.0) ); assert( eq(lhsrr[3],5.0-1.8) ); assert( eq(lhsrr[4],15.0-3.0) ); assert( eq(lhsrr[5],0.0) ); const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow(); assert( lhsmbr != NULL ); const double * ev = lhsmbr->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = lhsmbr->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = lhsmbr->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7] == 2 ); assert( ei[8] == 5 ); assert( ei[9] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); int md = lhsmbr->getMajorDim(); assert( md == 6 ); assert( lhsmbr->getNumElements() == 14 ); } } // Do common solverInterface testing by calling the // base class testing method. { OsiCpxSolverInterface m; OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } }
void CouenneCutGenerator::generateCuts (const OsiSolverInterface &si, OsiCuts &cs, const CglTreeInfo info) #if CGL_VERSION_MAJOR == 0 && CGL_VERSION_MINOR <= 57 const #endif { // check if out of time or if an infeasibility cut (iis of type 0) // was added as a result of, e.g., pruning on BT. If so, no need to // run this. if (isWiped (cs) || (CoinCpuTime () > problem_ -> getMaxCpuTime ())) return; #ifdef FM_TRACE_OPTSOL double currCutOff = problem_->getCutOff(); double bestVal = 1e50; CouenneRecordBestSol *rs = problem_->getRecordBestSol(); if(rs->getHasSol()) { bestVal = rs->getVal(); } if(currCutOff > bestVal) { //problem_ -> setCutOff (bestVal - 1e-6); // FIXME: don't add numerical constants problem_ -> setCutOff (bestVal); int indObj = problem_->Obj(0)->Body()->Index(); if (indObj >= 0) { OsiColCut *objCut = new OsiColCut; objCut->setUbs(1, &indObj, &bestVal); cs.insert(objCut); delete objCut; } } #endif #ifdef FM_PRINT_INFO if((BabPtr_ != NULL) && (info.level >= 0) && (info.pass == 0) && (BabPtr_->model().getNodeCount() > lastPrintLine)) { printLineInfo(); lastPrintLine += 1; } #endif const int infeasible = 1; int nInitCuts = cs.sizeRowCuts (); CouNumber *&realOpt = problem_ -> bestSol (), *saveOptimum = realOpt; if (!firstcall_ && realOpt) { // have a debug optimal solution. Check if current bounds // contain it, otherwise pretend it does not exist CouNumber *opt = realOpt; const CouNumber *sol = si.getColSolution (), *lb = si.getColLower (), *ub = si.getColUpper (); int objind = problem_ -> Obj (0) -> Body () -> Index (); for (int j=0, i=problem_ -> nVars (); i--; j++, opt++, lb++, ub++) if ((j != objind) && ((*opt < *lb - COUENNE_EPS * (1 + CoinMin (fabs (*opt), fabs (*lb)))) || (*opt > *ub + COUENNE_EPS * (1 + CoinMin (fabs (*opt), fabs (*ub)))))) { jnlst_ -> Printf (J_VECTOR, J_CONVEXIFYING, "out of bounds, ignore x%d = %g [%g,%g] opt = %g\n", problem_ -> nVars () - i - 1, *sol, *lb, *ub, *opt); // optimal point is not in current bounding box, // pretend realOpt is NULL until we return from this procedure realOpt = NULL; break; } } /*static int count = 0; char fname [20]; sprintf (fname, "relax_%d", count++); si.writeLp (fname); printf ("writing %s\n", fname);*/ jnlst_ -> Printf (J_DETAILED, J_CONVEXIFYING, "generateCuts: level = %d, pass = %d, intree = %d\n", info.level, info.pass, info.inTree); Bonmin::BabInfo * babInfo = dynamic_cast <Bonmin::BabInfo *> (si.getAuxiliaryInfo ()); if (babInfo) babInfo -> setFeasibleNode (); double now = CoinCpuTime (); int ncols = problem_ -> nVars (); // This vector contains variables whose bounds have changed due to // branching, reduced cost fixing, or bound tightening below. To be // used with malloc/realloc/free t_chg_bounds *chg_bds = new t_chg_bounds [ncols]; /*for (int i=0; i < ncols; i++) if (problem_ -> Var (i) -> Multiplicity () <= 0) { chg_bds [i].setLower (t_chg_bounds::UNCHANGED); chg_bds [i].setUpper (t_chg_bounds::UNCHANGED); }*/ problem_ -> installCutOff (); // install upper bound if (firstcall_) { // First convexification ////////////////////////////////////// // OsiSolverInterface is empty yet, no information can be obtained // on variables or bounds -- and none is needed since our // constructor populated *problem_ with variables and bounds. We // only need to update the auxiliary variables and bounds with // their current value. for (int i=0; i < ncols; i++) if (problem_ -> Var (i) -> Multiplicity () > 0) { chg_bds [i].setLower (t_chg_bounds::CHANGED); chg_bds [i].setUpper (t_chg_bounds::CHANGED); } // start with FBBT, should take advantage of cutoff found by NLP // run AFTER initial FBBT... if (problem_ -> doFBBT () && (! (problem_ -> boundTightening (chg_bds, babInfo)))) jnlst_ -> Printf (J_STRONGWARNING, J_CONVEXIFYING, "Couenne: WARNING, first convexification is infeasible\n"); // For each auxiliary variable replacing the original (nonlinear) // constraints, check if corresponding bounds are violated, and // add cut to cs int nnlc = problem_ -> nCons (); for (int i=0; i<nnlc; i++) { if (CoinCpuTime () > problem_ -> getMaxCpuTime ()) break; // for each constraint CouenneConstraint *con = problem_ -> Con (i); // (which has an aux as its body) int objindex = con -> Body () -> Index (); if ((objindex >= 0) && ((con -> Body () -> Type () == AUX) || (con -> Body () -> Type () == VAR))) { // get the auxiliary that is at the lhs exprVar *conaux = problem_ -> Var (objindex); if (conaux && (conaux -> Type () == AUX) && (conaux -> Image ()) && (conaux -> Image () -> Linearity () <= LINEAR)) { // reduce density of problem by adding w >= l rather than // ax + b >= l for any linear auxiliary defined as w := ax+b double lb = (*(con -> Lb ())) (), ub = (*(con -> Ub ())) (); OsiColCut newBound; if (lb > -COUENNE_INFINITY) newBound.setLbs (1, &objindex, &lb); if (ub < COUENNE_INFINITY) newBound.setUbs (1, &objindex, &ub); cs.insert (newBound); // the auxiliary w of constraint w <= b is associated with a // linear expression w = ax: add constraint ax <= b /*conaux -> Image () -> generateCuts (conaux, si, cs, this, chg_bds, conaux -> Index (), (*(con -> Lb ())) (), (*(con -> Ub ())) ());*/ // take it from the list of the variables to be linearized // // DO NOT decrease multiplicity. Even if it is a linear // term, its bounds can still be used in implied bounds // // Are we sure? That will happen only if its multiplicity is // nonzero, for otherwise this aux is only used here, and is // useless elsewhere // //conaux -> decreaseMult (); // !!! } // also, add constraint w <= b // not now, do it later // // if there exists violation, add constraint // CouNumber l = con -> Lb () -> Value (), // u = con -> Ub () -> Value (); // // tighten bounds in Couenne's problem representation // problem_ -> Lb (index) = CoinMax (l, problem_ -> Lb (index)); // problem_ -> Ub (index) = CoinMin (u, problem_ -> Ub (index)); } else { // body is more than just a variable, but it should be // linear. If so, generate equivalent linear cut assert (false); // TODO } } if (jnlst_ -> ProduceOutput (J_ITERSUMMARY, J_CONVEXIFYING)) { if (cs.sizeRowCuts ()) { jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne: %d constraint row cuts\n", cs.sizeRowCuts ()); for (int i=0; i<cs.sizeRowCuts (); i++) cs.rowCutPtr (i) -> print (); } if (cs.sizeColCuts ()) { jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne: %d constraint col cuts\n", cs.sizeColCuts ()); for (int i=0; i<cs.sizeColCuts (); i++) cs.colCutPtr (i) -> print (); } } } else { // use new optimum as lower bound for variable associated w/objective int indobj = problem_ -> Obj (0) -> Body () -> Index (); // transmit solution from OsiSolverInterface to problem problem_ -> domain () -> push (&si, &cs); if (indobj >= 0) { // Use current value of objvalue's x as a lower bound for bound // tightening double lp_bound = problem_ -> domain () -> x (indobj); //if (problem_ -> Obj (0) -> Sense () == MINIMIZE) {if (lp_bound > problem_ -> Lb (indobj)) problem_ -> Lb (indobj) = lp_bound;} //else {if (lp_bound < problem_ -> Ub (indobj)) problem_ -> Ub (indobj) = lp_bound;} } updateBranchInfo (si, problem_, chg_bds, info); // info.depth >= 0 || info.pass >= 0 } // restore constraint bounds before tightening and cut generation for (int i = problem_ -> nCons (); i--;) { // for each constraint CouenneConstraint *con = problem_ -> Con (i); // (which has an aux as its body) int objindex = con -> Body () -> Index (); if ((objindex >= 0) && ((con -> Body () -> Type () == AUX) || (con -> Body () -> Type () == VAR))) { // if there exists violation, add constraint CouNumber l = con -> Lb () -> Value (), u = con -> Ub () -> Value (); // tighten bounds in Couenne's problem representation problem_ -> Lb (objindex) = CoinMax (l, problem_ -> Lb (objindex)); problem_ -> Ub (objindex) = CoinMin (u, problem_ -> Ub (objindex)); } } problem_ -> installCutOff (); // install upper bound fictitiousBound (cs, problem_, false); // install finite lower bound, if currently -inf int *changed = NULL, nchanged; // Bound tightening /////////////////////////////////////////// // do bound tightening only at first pass of cutting plane in a node // of BB tree (info.pass == 0) or if first call (creation of RLT, // info.pass == -1) try { // Before bound tightening, compute symmetry group. After bound // tightening is done, we can apply further tightening using orbit // information. #ifdef COIN_HAS_NTY // ChangeBounds (psi -> getColLower (), // psi -> getColUpper (), // psi -> getNumCols ()); if (problem_ -> orbitalBranching ()) problem_ -> Compute_Symmetry (); #endif // Bound tightening //////////////////////////////////// /*printf ("== BT ================\n"); for (int i = 0; i < problem_ -> nVars (); i++) if (problem_ -> Var (i) -> Multiplicity () > 0) printf ("%4d %+20.8g [%+20.8g,%+20.8g]\n", i, problem_ -> X (i), problem_ -> Lb (i), problem_ -> Ub (i)); printf("=============================\n");*/ // Reduced Cost BT -- to be done first to use rcost correctly if (!firstcall_ && // have a linearization already problem_ -> doRCBT () && // authorized to do reduced cost tightening problem_ -> redCostBT (&si, chg_bds) && // some variables were tightened with reduced cost !(problem_ -> btCore (chg_bds))) // in this case, do another round of FBBT throw infeasible; // FBBT if (problem_ -> doFBBT () && //(info.pass <= 0) && // do it in subsequent rounds too (! (problem_ -> boundTightening (chg_bds, babInfo)))) throw infeasible; // OBBT if (!firstcall_ && // no obbt if first call (there is no LP to work with) problem_ -> obbt (this, si, cs, info, babInfo, chg_bds) < 0) throw infeasible; // Bound tightening done ///////////////////////////// if ((problem_ -> doFBBT () || problem_ -> doOBBT () || problem_ -> doABT ()) && (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING))) { jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== after bt =============\n"); for (int i = 0; i < problem_ -> nVars (); i++) if (problem_ -> Var (i) -> Multiplicity () > 0) jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i, problem_ -> X (i), problem_ -> Lb (i), problem_ -> Ub (i)); jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n"); } // Use orbit info to tighten bounds #ifdef COIN_HAS_NTY // TODO: when independent bound tightener, can get original bounds // through si.getCol{Low,Upp}er() if (problem_ -> orbitalBranching () && !firstcall_) { CouNumber *lb = problem_ -> Lb (), *ub = problem_ -> Ub (); std::vector<std::vector<int> > *new_orbits = problem_ -> getNtyInfo () -> getOrbits(); for (int i=0, ii = problem_ -> getNtyInfo () -> getNumOrbits (); ii--; i++){ CouNumber ll = -COUENNE_INFINITY, uu = COUENNE_INFINITY; std::vector <int> orbit = (*new_orbits)[i]; if (orbit.size () <= 1) continue; // not much to do when only one variable in this orbit if (jnlst_ -> ProduceOutput (J_VECTOR, J_BOUNDTIGHTENING)) { printf ("orbit bounds: "); fflush (stdout); for(int j = 0; j < orbit.size (); j++) { printf ("x_%d [%g,%g] ", orbit[j], lb [orbit [j]], ub [orbit [j]]); fflush (stdout); } printf ("\n"); } for (int j = 0; j < orbit.size (); j++) { int indOrb = orbit [j]; if (indOrb < problem_ -> nVars ()) { if (lb [indOrb] > ll) ll = lb [indOrb]; if (ub [indOrb] < uu) uu = ub [indOrb]; } } jnlst_ -> Printf (J_VECTOR, J_BOUNDTIGHTENING, " --> new common lower bounds: [%g,--]\n", ll); for(int j = 0; j < orbit.size (); j++) { int indOrb = orbit [j]; if (indOrb < problem_ -> nVars ()){ lb [indOrb] = ll; ub [indOrb] = uu; } } } delete new_orbits; } #endif // Generate convexification cuts ////////////////////////////// sparse2dense (ncols, chg_bds, changed, nchanged); double *nlpSol = NULL; //-------------------------------------------- if (true) { if (babInfo) nlpSol = const_cast <double *> (babInfo -> nlpSolution ()); // Aggressive Bound Tightening //////////////////////////////// int logAbtLev = problem_ -> logAbtLev (); if (problem_ -> doABT () && // flag is checked, AND ((logAbtLev != 0) || // (parameter is nonzero OR (info.level == 0)) && // we are at root node), AND (info.pass == 0) && // at first round of cuts, AND ((logAbtLev < 0) || // (logAbtLev = -1, OR (info.level <= logAbtLev) || // depth is lower than COU_OBBT_CUTOFF_LEVEL, OR (CoinDrand48 () < // probability inversely proportional to the level) pow (2., (double) logAbtLev - (info.level + 1))))) { jnlst_ -> Printf(J_VECTOR, J_BOUNDTIGHTENING," performing ABT\n"); if (! (problem_ -> aggressiveBT (nlp_, chg_bds, info, babInfo))) throw infeasible; sparse2dense (ncols, chg_bds, changed, nchanged); } // obtain solution just found by nlp solver // Auxiliaries should be correct. solution should be the one found // at the node even if not as good as the best known. // save violation flag and disregard it while adding cut at NLP // point (which are not violated by the current, NLP, solution) bool save_av = addviolated_; addviolated_ = false; // save values problem_ -> domain () -> push (problem_ -> nVars (), problem_ -> domain () -> x (), problem_ -> domain () -> lb (), problem_ -> domain () -> ub (), false); // fill originals with nlp values if (nlpSol) { CoinCopyN (nlpSol, problem_ -> nOrigVars (), problem_ -> domain () -> x ()); //problem_ -> initAuxs (); problem_ -> getAuxs (problem_ -> domain () -> x ()); } if (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING)) { jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== genrowcuts on NLP =============\n"); for (int i = 0; i < problem_ -> nVars (); i++) if (problem_ -> Var (i) -> Multiplicity () > 0) jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i, problem_ -> X (i), problem_ -> Lb (i), problem_ -> Ub (i)); jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n"); } problem_ -> domain () -> current () -> isNlp () = true; genRowCuts (si, cs, nchanged, changed, chg_bds); // add cuts problem_ -> domain () -> pop (); // restore point addviolated_ = save_av; // restore previous value // if (!firstcall_) // keep solution if called from extractLinearRelaxation() if (babInfo) babInfo -> setHasNlpSolution (false); // reset it after use //AW HERE } else { if (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING)) { jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== genrowcuts on LP =============\n"); for (int i = 0; i < problem_ -> nVars (); i++) if (problem_ -> Var (i) -> Multiplicity () > 0) jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i, problem_ -> X (i), problem_ -> Lb (i), problem_ -> Ub (i)); jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n"); } genRowCuts (si, cs, nchanged, changed, chg_bds); } // change tightened bounds through OsiCuts if (nchanged) genColCuts (si, cs, nchanged, changed); if (firstcall_ && (cs.sizeRowCuts () >= 1)) jnlst_->Printf(J_ITERSUMMARY, J_CONVEXIFYING, "Couenne: %d initial row cuts\n", cs.sizeRowCuts ()); if (realOpt && // this is a good time to check if we have cut the optimal solution isOptimumCut (realOpt, cs, problem_)) jnlst_->Printf(J_ITERSUMMARY, J_CONVEXIFYING, "Warning: Optimal solution was cut\n"); } catch (int exception) { if ((exception == infeasible) && (!firstcall_)) { jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING, "Couenne: Infeasible node\n"); WipeMakeInfeas (cs); } if (babInfo) // set infeasibility to true in order to skip NLP heuristic babInfo -> setInfeasibleNode (); } delete [] chg_bds; if (changed) free (changed); if (firstcall_) { jnlst_ -> Printf (J_SUMMARY, J_CONVEXIFYING, "Couenne: %d cuts (%d row, %d col) for linearization\n", cs.sizeRowCuts () + cs.sizeColCuts (), cs.sizeRowCuts (), cs.sizeColCuts ()); fictitiousBound (cs, problem_, true); firstcall_ = false; ntotalcuts_ = nrootcuts_ = cs.sizeRowCuts (); } else { problem_ -> domain () -> pop (); ntotalcuts_ += (cs.sizeRowCuts () - nInitCuts); if (saveOptimum) realOpt = saveOptimum; // restore debug optimum } septime_ += CoinCpuTime () - now; if (jnlst_ -> ProduceOutput (J_ITERSUMMARY, J_CONVEXIFYING)) { if (cs.sizeColCuts ()) { jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne col cuts:\n"); for (int i=0; i<cs.sizeColCuts (); i++) cs.colCutPtr (i) -> print (); } } if (!(info.inTree)) rootTime_ = CoinCpuTime (); }
//-------------------------------------------------------------------------- void OsiColCutUnitTest(const OsiSolverInterface *baseSiP, const std::string &mpsDir) { // Test default constructor { OsiColCut r; OSIUNITTEST_ASSERT_ERROR(r.lbs_.getIndices() == NULL, {}, "osicolcut", "default constructor"); OSIUNITTEST_ASSERT_ERROR(r.lbs_.getElements() == NULL, {}, "osicolcut", "default constructor"); OSIUNITTEST_ASSERT_ERROR(r.lbs_.getNumElements() == 0, {}, "osicolcut", "default constructor"); OSIUNITTEST_ASSERT_ERROR(r.lbs().getNumElements() == 0, {}, "osicolcut", "default constructor"); OSIUNITTEST_ASSERT_ERROR(r.ubs_.getIndices() == NULL, {}, "osicolcut", "default constructor"); OSIUNITTEST_ASSERT_ERROR(r.ubs_.getElements() == NULL, {}, "osicolcut", "default constructor"); OSIUNITTEST_ASSERT_ERROR(r.ubs_.getNumElements() == 0, {}, "osicolcut", "default constructor"); OSIUNITTEST_ASSERT_ERROR(r.ubs().getNumElements() == 0, {}, "osicolcut", "default constructor"); } // Test set and get methods const int ne = 4; int inx[ne] = { 1, 3, 4, 7 }; double el[ne] = { 1.2, 3.4, 5.6, 7.8 }; const int ne3 = 0; int *inx3 = NULL; double *el3 = NULL; { OsiColCut r; // Test setting/getting bounds r.setLbs(ne, inx, el); r.setEffectiveness(222.); OSIUNITTEST_ASSERT_ERROR(r.lbs().getNumElements() == ne, return, "osicolcut", "setting bounds"); bool bounds_ok = true; for (int i = 0; i < ne; i++) { bounds_ok &= r.lbs().getIndices()[i] == inx[i]; bounds_ok &= r.lbs().getElements()[i] == el[i]; } OSIUNITTEST_ASSERT_ERROR(bounds_ok, {}, "osicolcut", "setting bounds"); OSIUNITTEST_ASSERT_ERROR(r.effectiveness() == 222.0, {}, "osicolcut", "setting bounds"); r.setUbs(ne3, inx3, el3); OSIUNITTEST_ASSERT_ERROR(r.ubs().getNumElements() == 0, {}, "osicolcut", "setting bounds"); OSIUNITTEST_ASSERT_ERROR(r.ubs().getIndices() == NULL, {}, "osicolcut", "setting bounds"); OSIUNITTEST_ASSERT_ERROR(r.ubs().getElements() == NULL, {}, "osicolcut", "setting bounds"); } // Test copy constructor and assignment operator { OsiColCut rhs; { OsiColCut r; OsiColCut rC1(r); OSIUNITTEST_ASSERT_ERROR(rC1.lbs().getNumElements() == r.lbs().getNumElements(), {}, "osicolcut", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(rC1.ubs().getNumElements() == r.ubs().getNumElements(), {}, "osicolcut", "copy constructor"); r.setLbs(ne, inx, el); r.setUbs(ne, inx, el); r.setEffectiveness(121.); OSIUNITTEST_ASSERT_ERROR(rC1.lbs().getNumElements() != r.lbs().getNumElements(), {}, "osicolcut", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(rC1.ubs().getNumElements() != r.lbs().getNumElements(), {}, "osicolcut", "copy constructor"); OsiColCut rC2(r); OSIUNITTEST_ASSERT_ERROR(rC2.lbs().getNumElements() == r.lbs().getNumElements(), {}, "osicolcut", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(rC2.ubs().getNumElements() == r.ubs().getNumElements(), {}, "osicolcut", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(rC2.lbs().getNumElements() == ne, return, "osicolcut", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(rC2.ubs().getNumElements() == ne, return, "osicolcut", "copy constructor"); bool bounds_ok = true; for (int i = 0; i < ne; i++) { bounds_ok &= rC2.lbs().getIndices()[i] == inx[i]; bounds_ok &= rC2.lbs().getElements()[i] == el[i]; bounds_ok &= rC2.ubs().getIndices()[i] == inx[i]; bounds_ok &= rC2.ubs().getElements()[i] == el[i]; } OSIUNITTEST_ASSERT_ERROR(bounds_ok, {}, "osicolcut", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(rC2.effectiveness() == 121.0, {}, "osicolcut", "copy constructor"); rhs = rC2; } // Test that rhs has correct values even though lhs has gone out of scope OSIUNITTEST_ASSERT_ERROR(rhs.lbs().getNumElements() == ne, return, "osicolcut", "assignment operator"); OSIUNITTEST_ASSERT_ERROR(rhs.ubs().getNumElements() == ne, return, "osicolcut", "assignment operator"); bool bounds_ok = true; for (int i = 0; i < ne; i++) { bounds_ok &= rhs.lbs().getIndices()[i] == inx[i]; bounds_ok &= rhs.lbs().getElements()[i] == el[i]; bounds_ok &= rhs.ubs().getIndices()[i] == inx[i]; bounds_ok &= rhs.ubs().getElements()[i] == el[i]; } OSIUNITTEST_ASSERT_ERROR(bounds_ok, {}, "osicolcut", "assignment operator"); OSIUNITTEST_ASSERT_ERROR(rhs.effectiveness() == 121.0, {}, "osicolcut", "assignment operator"); } // Test setting bounds with packed vector and operator== { const int ne1 = 4; int inx1[ne] = { 1, 3, 4, 7 }; double el1[ne] = { 1.2, 3.4, 5.6, 7.8 }; const int ne2 = 2; int inx2[ne2] = { 1, 3 }; double el2[ne2] = { 1.2, 3.4 }; CoinPackedVector v1, v2; v1.setVector(ne1, inx1, el1); v2.setVector(ne2, inx2, el2); OsiColCut c1, c2; OSIUNITTEST_ASSERT_ERROR(c1 == c2, {}, "osicolcut", "setting bounds with packed vector and operator =="); OSIUNITTEST_ASSERT_ERROR(!(c1 != c2), {}, "osicolcut", "setting bounds with packed vector and operator !="); c1.setLbs(v1); OSIUNITTEST_ASSERT_ERROR(c1 != c2, {}, "osicolcut", "setting bounds with packed vector and operator !="); OSIUNITTEST_ASSERT_ERROR(!(c1 == c2), {}, "osicolcut", "setting bounds with packed vector and operator =="); OSIUNITTEST_ASSERT_ERROR(c1.lbs() == v1, {}, "osicolcut", "setting bounds with packed vector and operator !="); c1.setUbs(v2); OSIUNITTEST_ASSERT_ERROR(c1.ubs() == v2, {}, "osicolcut", "setting bounds with packed vector and operator !="); c1.setEffectiveness(3.); OSIUNITTEST_ASSERT_ERROR(c1.effectiveness() == 3.0, {}, "osicolcut", "setting bounds with packed vector and operator !="); { OsiColCut c3(c1); OSIUNITTEST_ASSERT_ERROR(c3 == c1, {}, "osicolcut", "operator =="); OSIUNITTEST_ASSERT_ERROR(!(c3 != c1), {}, "osicolcut", "operator !="); } { OsiColCut c3(c1); c3.setLbs(v2); OSIUNITTEST_ASSERT_ERROR(c3 != c1, {}, "osicolcut", "operator !="); OSIUNITTEST_ASSERT_ERROR(!(c3 == c1), {}, "osicolcut", "operator =="); } { OsiColCut c3(c1); c3.setUbs(v1); OSIUNITTEST_ASSERT_ERROR(c3 != c1, {}, "osicolcut", "operator !="); OSIUNITTEST_ASSERT_ERROR(!(c3 == c1), {}, "osicolcut", "operator =="); } { OsiColCut c3(c1); c3.setEffectiveness(5.); OSIUNITTEST_ASSERT_ERROR(c3 != c1, {}, "osicolcut", "operator !="); OSIUNITTEST_ASSERT_ERROR(!(c3 == c1), {}, "osicolcut", "operator =="); } } // internal consistency { const int ne = 1; int inx[ne] = { -3 }; double el[ne] = { 1.2 }; OsiColCut r; r.setLbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(!r.consistent(), {}, "osicolcut", "consistent"); } { const int ne = 1; int inx[ne] = { -3 }; double el[ne] = { 1.2 }; OsiColCut r; r.setUbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(!r.consistent(), {}, "osicolcut", "consistent"); } { const int ne = 1; int inx[ne] = { 100 }; double el[ne] = { 1.2 }; const int ne1 = 2; int inx1[ne1] = { 50, 100 }; double el1[ne1] = { 100., 100. }; OsiColCut r; r.setUbs(ne, inx, el); r.setLbs(ne1, inx1, el1); OSIUNITTEST_ASSERT_ERROR(r.consistent(), {}, "osicolcut", "consistent"); OsiSolverInterface *imP = baseSiP->clone(); assert(imP != NULL); std::string fn = mpsDir + "exmip1"; imP->readMps(fn.c_str(), "mps"); OSIUNITTEST_ASSERT_ERROR(!r.consistent(*imP), {}, "osicolcut", "consistent"); delete imP; } { const int ne = 1; int inx[ne] = { 100 }; double el[ne] = { 1.2 }; const int ne1 = 2; int inx1[ne1] = { 50, 100 }; double el1[ne1] = { 100., 1. }; OsiColCut r; r.setUbs(ne, inx, el); r.setLbs(ne1, inx1, el1); OSIUNITTEST_ASSERT_ERROR(r.consistent(), {}, "osicolcut", "consistent"); } { // Test consistent(IntegerModel) method. OsiSolverInterface *imP = baseSiP->clone(); assert(imP != NULL); std::string fn = mpsDir + "exmip1"; imP->readMps(fn.c_str(), "mps"); OsiColCut cut; const int ne = 1; int inx[ne] = { 20 }; double el[ne] = { 0.25 }; cut.setLbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(!cut.consistent(*imP), {}, "osicolcut", "consistent(IntegerModel)"); cut.setLbs(0, NULL, NULL); cut.setUbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(!cut.consistent(*imP), {}, "osicolcut", "consistent(IntegerModel)"); inx[0] = 4; cut.setLbs(ne, inx, el); cut.setUbs(0, NULL, NULL); OSIUNITTEST_ASSERT_ERROR(cut.consistent(*imP), {}, "osicolcut", "consistent(IntegerModel)"); el[0] = 4.5; cut.setLbs(0, NULL, NULL); cut.setUbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(cut.consistent(*imP), {}, "osicolcut", "consistent(IntegerModel)"); cut.setLbs(ne, inx, el); cut.setUbs(0, NULL, NULL); OSIUNITTEST_ASSERT_ERROR(cut.consistent(*imP), {}, "osicolcut", "consistent(IntegerModel)"); OSIUNITTEST_ASSERT_ERROR(cut.infeasible(*imP), {}, "osicolcut", "infeasible(IntegerModel)"); el[0] = 3.0; cut.setLbs(ne, inx, el); cut.setUbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(cut.consistent(*imP), {}, "osicolcut", "consistent(IntegerModel)"); delete imP; } { //Test infeasible(im) method // Test consistent(IntegerModel) method. OsiSolverInterface *imP = baseSiP->clone(); assert(imP != NULL); std::string fn = mpsDir + "exmip1"; imP->readMps(fn.c_str(), "mps"); OsiColCut cut; const int ne = 1; int inx[ne] = { 4 }; double el[ne] = { 4.5 }; cut.setLbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(cut.infeasible(*imP), {}, "osicolcut", "infeasible(IntegerModel)"); el[0] = 0.25; cut.setLbs(0, NULL, NULL); cut.setUbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(cut.infeasible(*imP), {}, "osicolcut", "infeasible(IntegerModel)"); el[0] = 3.0; cut.setLbs(ne, inx, el); cut.setUbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(!cut.infeasible(*imP), {}, "osicolcut", "infeasible(IntegerModel)"); delete imP; } { //Test violation double solution[] = { 1.0 }; OsiColCut cut; const int ne = 1; int inx[ne] = { 0 }; double el[ne] = { 4.5 }; cut.setLbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(cut.violated(solution), {}, "osicolcut", "violated"); el[0] = 0.25; cut.setLbs(0, NULL, NULL); cut.setUbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(cut.violated(solution), {}, "osicolcut", "violated"); el[0] = 1.0; cut.setLbs(ne, inx, el); cut.setUbs(ne, inx, el); OSIUNITTEST_ASSERT_ERROR(!cut.violated(solution), {}, "osicolcut", "violated"); } }
//----------------------------------------------------------------------- // Test XPRESS-MP solution methods. void OsiXprSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir) { #if 0 // Test to at least see if licence managment is working { int iret = initlz(NULL, 0); if ( iret != 0 ) getipv(N_ERRNO, &iret); assert(iret == 0); } #endif // Test default constructor { assert( OsiXprSolverInterface::getNumInstances()==0 ); OsiXprSolverInterface m; // assert( m.xprSaved_ == false ); // assert( m.xprMatrixId_ = -1 ); assert( m.xprProbname_ == "" ); assert( m.matrixByRow_ == NULL ); assert( m.colupper_ == NULL ); assert( m.collower_ == NULL ); assert( m.rowupper_ == NULL ); assert( m.rowlower_ == NULL ); assert( m.rowsense_ == NULL ); assert( m.rhs_ == NULL ); assert( m.rowrange_ == NULL ); assert( m.colsol_ == NULL ); assert( m.rowprice_ == NULL ); assert( m.ivarind_ == NULL ); assert( m.ivartype_ == NULL ); assert( m.vartype_ == NULL ); assert( OsiXprSolverInterface::getNumInstances() == 1 ); // assert( OsiXprSolverInterface::xprCurrentProblem_ == NULL ); assert( m.getApplicationData() == NULL ); int i = 2346; m.setApplicationData(&i); assert( *((int *)(m.getApplicationData())) == i ); } assert( OsiXprSolverInterface::getNumInstances() == 0 ); { CoinRelFltEq eq; OsiXprSolverInterface m; assert( OsiXprSolverInterface::getNumInstances() == 1 ); std::string fn = mpsDir+"exmip1"; m.readMps(fn.c_str()); // assert( OsiXprSolverInterface::xprCurrentProblem_ == &m ); // This assert fails on windows because fn is mixed case and xprProbname_is uppercase. //assert( m.xprProbname_ == fn ); int ad = 13579; m.setApplicationData(&ad); assert( *((int *)(m.getApplicationData())) == ad ); { OsiXprSolverInterface im; // assert( im.modelPtr_==NULL ); assert( im.getNumCols() == 0 ); // assert( im.modelPtr()!=NULL ); // assert( im.mutableModelPtr()!=NULL ); // assert( im.modelPtr() == im.mutableModelPtr() ); } // Test copy constructor and assignment operator { OsiXprSolverInterface lhs; { assert( *((int *)(m.getApplicationData())) == ad ); OsiXprSolverInterface im(m); assert( *((int *)(im.getApplicationData())) == ad ); OsiXprSolverInterface imC1(im); // assert( imC1.mutableModelPtr()!=im.mutableModelPtr() ); // assert( imC1.modelPtr()!=im.modelPtr() ); assert( imC1.getNumCols() == im.getNumCols() ); assert( imC1.getNumRows() == im.getNumRows() ); assert( *((int *)(imC1.getApplicationData())) == ad ); //im.setModelPtr(m); OsiXprSolverInterface imC2(im); // assert( imC2.mutableModelPtr()!=im.mutableModelPtr() ); // assert( imC2.modelPtr()!=im.modelPtr() ); assert( imC2.getNumCols() == im.getNumCols() ); assert( imC2.getNumRows() == im.getNumRows() ); assert( *((int *)(imC2.getApplicationData())) == ad ); // assert( imC2.mutableModelPtr()!=imC1.mutableModelPtr() ); // assert( imC2.modelPtr()!=imC1.modelPtr() ); lhs=imC2; } // Test that lhs has correct values even though rhs has gone out of scope // assert( lhs.mutableModelPtr() != m.mutableModelPtr() ); // assert( lhs.modelPtr() != m.modelPtr() ); assert( lhs.getNumCols() == m.getNumCols() ); assert( lhs.getNumRows() == m.getNumRows() ); assert( *((int *)(lhs.getApplicationData())) == ad ); } // Test clone { OsiXprSolverInterface xprSi(m); OsiSolverInterface * siPtr = &xprSi; OsiSolverInterface * siClone = siPtr->clone(); OsiXprSolverInterface * xprClone = dynamic_cast<OsiXprSolverInterface*>(siClone); assert( xprClone != NULL ); // assert( xprClone->modelPtr() != xprSi.modelPtr() ); // assert( xprClone->modelPtr() != m.modelPtr() ); assert( xprClone->getNumRows() == xprSi.getNumRows() ); assert( xprClone->getNumCols() == m.getNumCols() ); assert( *((int *)(xprClone->getApplicationData())) == ad ); delete siClone; } // Test infinity { OsiXprSolverInterface si; assert( eq(si.getInfinity(), XPRS_PLUSINFINITY) ); } // Test setting solution { OsiXprSolverInterface m1(m); int i; double * cs = new double[m1.getNumCols()]; for ( i = 0; i < m1.getNumCols(); i++ ) cs[i] = i + .5; m1.setColSolution(cs); for ( i = 0; i < m1.getNumCols(); i++ ) assert(m1.getColSolution()[i] == i + .5); double * rs = new double[m1.getNumRows()]; for ( i = 0; i < m1.getNumRows(); i++ ) rs[i] = i - .5; m1.setRowPrice(rs); for ( i = 0; i < m1.getNumRows(); i++ ) assert(m1.getRowPrice()[i] == i - .5); delete [] cs; delete [] rs; } // Test fraction Indices { OsiXprSolverInterface fim; std::string fn = mpsDir+"exmip1"; fim.readMps(fn.c_str()); //fim.setModelPtr(m); // exmip1.mps has 2 integer variables with index 2 & 3 assert( fim.isContinuous(0) ); assert( fim.isContinuous(1) ); assert( !fim.isContinuous(2) ); assert( !fim.isContinuous(3) ); assert( fim.isContinuous(4) ); assert( !fim.isInteger(0) ); assert( !fim.isInteger(1) ); assert( fim.isInteger(2) ); assert( fim.isInteger(3) ); assert( !fim.isInteger(4) ); // XPRESS-MP incorrectly treats unbounded integer variables as // general integers instead of binary (as in MPSX standard) assert( !fim.isBinary(0) ); assert( !fim.isBinary(1) ); assert( fim.isBinary(2) ); assert( fim.isBinary(3) ); assert( !fim.isBinary(4) ); assert( !fim.isIntegerNonBinary(0) ); assert( !fim.isIntegerNonBinary(1) ); assert( !fim.isIntegerNonBinary(2) ); assert( !fim.isIntegerNonBinary(3) ); assert( !fim.isIntegerNonBinary(4) ); // Test fractionalIndices { // Set a solution vector double * cs = new double[fim.getNumCols()]; for ( int i = 0; i < fim.getNumCols(); cs[i++] = 0.0 ); cs[2] = 2.9; cs[3] = 3.0; fim.setColSolution(cs); OsiVectorInt fi = fim.getFractionalIndices(); assert( fi.size() == 1 ); assert( fi[0]==2 ); // Set integer variables very close to integer values cs[2] = 5 + .00001/2.; cs[3] = 8 - .00001/2.; fim.setColSolution(cs); fi = fim.getFractionalIndices(1e-5); assert( fi.size() == 0 ); // Set integer variables close, but beyond tolerances cs[2] = 5 + .00001*2.; cs[3] = 8 - .00001*2.; fim.setColSolution(cs); fi = fim.getFractionalIndices(1e-5); assert( fi.size() == 2 ); assert( fi[0]==2 ); assert( fi[1]==3 ); delete [] cs; } // Change data so column 2 & 3 are integerNonBinary fim.setColUpper(2, 5); fim.setColUpper(3, 6.0); assert( !fim.isBinary(0) ); assert( !fim.isBinary(1) ); assert( !fim.isBinary(2) ); assert( !fim.isBinary(3) ); assert( !fim.isBinary(4) ); assert( !fim.isIntegerNonBinary(0) ); assert( !fim.isIntegerNonBinary(1) ); assert( fim.isIntegerNonBinary(2) ); assert( fim.isIntegerNonBinary(3) ); assert( !fim.isIntegerNonBinary(4) ); } // Test apply cut method { OsiXprSolverInterface im(m); OsiCuts cuts; // Generate some cuts //cg.generateCuts(im,cuts); { // Get number of rows and columns in model int nr=im.getNumRows(); int nc=im.getNumCols(); assert ( nr == 5 ); assert ( nc == 8 ); // Generate a valid row cut from thin air int c; { 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]=((double)c)*((double)c); OsiRowCut rc; rc.setRow(nc,inx,el); rc.setLb(-100.); rc.setUb(100.); rc.setEffectiveness(22); cuts.insert(rc); delete[]el; delete[]inx; } // Generate valid col cut from thin air { const double * xprColLB = im.getColLower(); const double * xprColUB = im.getColUpper(); int *inx = new int[nc]; for (c=0;c<nc;c++) inx[c]=c; double *lb = new double[nc]; double *ub = new double[nc]; for (c=0;c<nc;c++) lb[c]=xprColLB[c]+0.001; for (c=0;c<nc;c++) ub[c]=xprColUB[c]-0.001; OsiColCut cc; cc.setLbs(nc,inx,lb); cc.setUbs(nc,inx,ub); cuts.insert(cc); delete [] ub; delete [] lb; delete [] inx; } { // Generate a row and column cut which have are ineffective OsiRowCut * rcP= new OsiRowCut; rcP->setEffectiveness(-1.); cuts.insert(rcP); assert(rcP==NULL); OsiColCut * ccP= new OsiColCut; ccP->setEffectiveness(-12.); cuts.insert(ccP); assert(ccP==NULL); } { //Generate inconsistent Row cut OsiRowCut rc; const int ne=1; int inx[ne]={-10}; double el[ne]={2.5}; rc.setRow(ne,inx,el); rc.setLb(3.); rc.setUb(4.); assert(!rc.consistent()); cuts.insert(rc); } { //Generate inconsistent col cut OsiColCut cc; const int ne=1; int inx[ne]={-10}; double el[ne]={2.5}; cc.setUbs(ne,inx,el); assert(!cc.consistent()); cuts.insert(cc); } { // Generate row cut which is inconsistent for model m OsiRowCut rc; const int ne=1; int inx[ne]={10}; double el[ne]={2.5}; rc.setRow(ne,inx,el); assert(rc.consistent()); assert(!rc.consistent(im)); cuts.insert(rc); } { // Generate col cut which is inconsistent for model m OsiColCut cc; const int ne=1; int inx[ne]={30}; double el[ne]={2.0}; cc.setLbs(ne,inx,el); assert(cc.consistent()); assert(!cc.consistent(im)); cuts.insert(cc); } { // Generate col cut which is infeasible OsiColCut cc; const int ne=1; int inx[ne]={0}; double el[ne]={2.0}; cc.setUbs(ne,inx,el); cc.setEffectiveness(1000.); assert(cc.consistent()); assert(cc.consistent(im)); assert(cc.infeasible(im)); cuts.insert(cc); } } assert(cuts.sizeRowCuts()==4); assert(cuts.sizeColCuts()==5); OsiSolverInterface::ApplyCutsReturnCode rc = im.applyCuts(cuts); assert( rc.getNumIneffective() == 2 ); assert( rc.getNumApplied() == 2 ); assert( rc.getNumInfeasible() == 1 ); assert( rc.getNumInconsistentWrtIntegerModel() == 2 ); assert( rc.getNumInconsistent() == 2 ); assert( cuts.sizeCuts() == rc.getNumIneffective() + rc.getNumApplied() + rc.getNumInfeasible() + rc.getNumInconsistentWrtIntegerModel() + rc.getNumInconsistent() ); } { OsiXprSolverInterface xprSi(m); int nc = xprSi.getNumCols(); int nr = xprSi.getNumRows(); assert( nc == 8 ); assert( nr == 5 ); assert( eq(xprSi.getColLower()[0],2.5) ); assert( eq(xprSi.getColLower()[1],0.0) ); assert( eq(xprSi.getColUpper()[1],4.1) ); assert( eq(xprSi.getRowLower()[0],2.5) ); assert( eq(xprSi.getRowLower()[4],3.0) ); assert( eq(xprSi.getRowUpper()[1],2.1) ); assert( eq(xprSi.getRowUpper()[4],15.0) ); // const double * cs = xprSi.getColSolution(); // assert( eq(cs[0],2.5) ); // assert( eq(cs[7],0.0) ); assert( !eq(xprSi.getColLower()[3],1.2345) ); xprSi.setColLower( 3, 1.2345 ); assert( eq(xprSi.getColLower()[3],1.2345) ); assert( !eq(xprSi.getColUpper()[4],10.2345) ); xprSi.setColUpper( 4, 10.2345 ); assert( eq(xprSi.getColUpper()[4],10.2345) ); //assert( eq(xprSi.getObjValue(),0.0) ); assert( eq( xprSi.getObjCoefficients()[0], 1.0) ); assert( eq( xprSi.getObjCoefficients()[1], 0.0) ); assert( eq( xprSi.getObjCoefficients()[2], 0.0) ); assert( eq( xprSi.getObjCoefficients()[3], 0.0) ); assert( eq( xprSi.getObjCoefficients()[4], 2.0) ); assert( eq( xprSi.getObjCoefficients()[5], 0.0) ); assert( eq( xprSi.getObjCoefficients()[6], 0.0) ); assert( eq( xprSi.getObjCoefficients()[7], -1.0) ); } // Test matrixByRow method { const OsiXprSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByRow(); CoinRelFltEq eq; const double * ev = smP->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = smP->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = smP->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7] == 2 ); assert( ei[8] == 5 ); assert( ei[9] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); assert( smP->getMajorDim() == 5 ); assert( smP->getMinorDim() == 8 ); assert( smP->getNumElements() == 14 ); assert( smP->getSizeVectorStarts()==6 ); } //-------------- // Test rowsense, rhs, rowrange, matrixByRow { OsiXprSolverInterface lhs; { assert( m.rowrange_==NULL ); assert( m.rowsense_==NULL ); assert( m.rhs_==NULL ); OsiXprSolverInterface siC1(m); assert( siC1.rowrange_==NULL ); assert( siC1.rowsense_==NULL ); assert( siC1.rhs_==NULL ); const char * siC1rs = siC1.getRowSense(); assert( siC1rs[0] == 'G' ); assert( siC1rs[1] == 'L' ); assert( siC1rs[2] == 'E' ); assert( siC1rs[3] == 'R' ); assert( siC1rs[4] == 'R' ); const double * siC1rhs = siC1.getRightHandSide(); assert( eq(siC1rhs[0], 2.5) ); assert( eq(siC1rhs[1], 2.1) ); assert( eq(siC1rhs[2], 4.0) ); assert( eq(siC1rhs[3], 5.0) ); assert( eq(siC1rhs[4], 15.0) ); const double * siC1rr = siC1.getRowRange(); assert( eq(siC1rr[0], 0.0) ); assert( eq(siC1rr[1], 0.0) ); assert( eq(siC1rr[2], 0.0) ); assert( eq(siC1rr[3], 5.0 - 1.8) ); assert( eq(siC1rr[4], 15.0 - 3.0) ); const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow(); assert( siC1mbr != NULL ); const double * ev = siC1mbr->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = siC1mbr->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = siC1mbr->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7 ] == 2 ); assert( ei[8 ] == 5 ); assert( ei[9 ] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); assert( siC1mbr->getMajorDim() == 5 ); assert( siC1mbr->getMinorDim() == 8 ); assert( siC1mbr->getNumElements() == 14 ); assert( siC1mbr->getSizeVectorStarts()==6 ); assert( siC1rs == siC1.getRowSense() ); assert( siC1rhs == siC1.getRightHandSide() ); assert( siC1rr == siC1.getRowRange() ); // Change XPRESS 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); // Since model was changed, test that cached // data is now freed. assert( siC1.rowrange_ == NULL ); assert( siC1.rowsense_ == NULL ); assert( siC1.rhs_ == NULL ); assert( siC1.matrixByRow_ == NULL ); siC1rs = siC1.getRowSense(); assert( siC1rs[0] == 'G' ); assert( siC1rs[1] == 'L' ); assert( siC1rs[2] == 'E' ); assert( siC1rs[3] == 'R' ); assert( siC1rs[4] == 'R' ); assert( siC1rs[5] == 'N' ); siC1rhs = siC1.getRightHandSide(); assert( eq(siC1rhs[0],2.5) ); assert( eq(siC1rhs[1],2.1) ); assert( eq(siC1rhs[2],4.0) ); assert( eq(siC1rhs[3],5.0) ); assert( eq(siC1rhs[4],15.0) ); assert( eq(siC1rhs[5],0.0) ); siC1rr = siC1.getRowRange(); assert( eq(siC1rr[0], 0.0) ); assert( eq(siC1rr[1], 0.0) ); assert( eq(siC1rr[2], 0.0) ); assert( eq(siC1rr[3], 5.0 - 1.8) ); assert( eq(siC1rr[4], 15.0 - 3.0) ); assert( eq(siC1rr[5], 0.0) ); lhs=siC1; } // Test that lhs has correct values even though siC1 has gone out of scope assert( lhs.rowrange_ == NULL ); assert( lhs.rowsense_ == NULL ); assert( lhs.rhs_ == NULL ); assert( lhs.matrixByRow_ == NULL ); const char * lhsrs = lhs.getRowSense(); assert( lhsrs[0] == 'G' ); assert( lhsrs[1] == 'L' ); assert( lhsrs[2] == 'E' ); assert( lhsrs[3] == 'R' ); assert( lhsrs[4] == 'R' ); assert( lhsrs[5] == 'N' ); const double * lhsrhs = lhs.getRightHandSide(); assert( eq(lhsrhs[0], 2.5) ); assert( eq(lhsrhs[1], 2.1) ); assert( eq(lhsrhs[2], 4.0) ); assert( eq(lhsrhs[3], 5.0) ); assert( eq(lhsrhs[4], 15.0) ); assert( eq(lhsrhs[5], 0.0) ); const double *lhsrr = lhs.getRowRange(); assert( eq(lhsrr[0], 0.0) ); assert( eq(lhsrr[1], 0.0) ); assert( eq(lhsrr[2], 0.0) ); assert( eq(lhsrr[3], 5.0 - 1.8) ); assert( eq(lhsrr[4], 15.0 - 3.0) ); assert( eq(lhsrr[5], 0.0) ); const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow(); assert( lhsmbr != NULL ); const double * ev = lhsmbr->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = lhsmbr->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = lhsmbr->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7] == 2 ); assert( ei[8] == 5 ); assert( ei[9] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); assert( lhsmbr->getMajorDim() == 6 ); assert( lhsmbr->getMinorDim() == 8 ); assert( lhsmbr->getNumElements() == 14 ); assert( lhsmbr->getSizeVectorStarts()==7 ); } //-------------- // Test load problem { OsiXprSolverInterface base(m); base.initialSolve(); assert(m.getNumRows() == base.getNumRows()); OsiXprSolverInterface si1,si2,si3,si4; si1.loadProblem( *base.getMatrixByCol(), base.getColLower(),base.getColUpper(),base.getObjCoefficients(), base.getRowSense(),base.getRightHandSide(),base.getRowRange()); si1.initialSolve(); assert(eq(base.getObjValue(), si1.getObjValue())); assert(m.getNumRows() == si1.getNumRows()); si2.loadProblem( *base.getMatrixByRow(), base.getColLower(),base.getColUpper(),base.getObjCoefficients(), base.getRowSense(),base.getRightHandSide(),base.getRowRange()); si2.initialSolve(); assert(eq(base.getObjValue(), si2.getObjValue())); assert(m.getNumRows() == si2.getNumRows()); si3.loadProblem( *base.getMatrixByCol(), base.getColLower(),base.getColUpper(),base.getObjCoefficients(), base.getRowLower(),base.getRowUpper() ); si3.initialSolve(); assert(eq(base.getObjValue(), si3.getObjValue())); assert(m.getNumRows() == si3.getNumRows()); si4.loadProblem( *base.getMatrixByCol(), base.getColLower(),base.getColUpper(),base.getObjCoefficients(), base.getRowLower(),base.getRowUpper() ); si4.initialSolve(); assert(eq(base.getObjValue(), si4.getObjValue())); assert(m.getNumRows() == si4.getNumRows()); base.initialSolve(); si1.initialSolve(); si2.initialSolve(); si3.initialSolve(); si4.initialSolve(); // Create an indices vector assert(base.getNumCols()<10); assert(base.getNumRows()<10); int indices[10]; int i; for (i=0; i<10; i++) indices[i]=i; // Test collower CoinPackedVector basePv,pv; basePv.setVector(base.getNumCols(),indices,base.getColLower()); pv.setVector( si1.getNumCols(),indices, si1.getColLower()); assert(basePv.isEquivalent(pv)); pv.setVector( si2.getNumCols(),indices, si2.getColLower()); assert(basePv.isEquivalent(pv)); pv.setVector( si3.getNumCols(),indices, si3.getColLower()); assert(basePv.isEquivalent(pv)); pv.setVector( si4.getNumCols(),indices, si4.getColLower()); assert(basePv.isEquivalent(pv)); // Test colupper basePv.setVector(base.getNumCols(),indices,base.getColUpper()); pv.setVector( si1.getNumCols(),indices, si1.getColUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si2.getNumCols(),indices, si2.getColUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si3.getNumCols(),indices, si3.getColUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si4.getNumCols(),indices, si4.getColUpper()); assert(basePv.isEquivalent(pv)); // Test getObjCoefficients basePv.setVector(base.getNumCols(),indices,base.getObjCoefficients()); pv.setVector( si1.getNumCols(),indices, si1.getObjCoefficients()); assert(basePv.isEquivalent(pv)); pv.setVector( si2.getNumCols(),indices, si2.getObjCoefficients()); assert(basePv.isEquivalent(pv)); pv.setVector( si3.getNumCols(),indices, si3.getObjCoefficients()); assert(basePv.isEquivalent(pv)); pv.setVector( si4.getNumCols(),indices, si4.getObjCoefficients()); assert(basePv.isEquivalent(pv)); // Test rowlower basePv.setVector(base.getNumRows(),indices,base.getRowLower()); pv.setVector( si1.getNumRows(),indices, si1.getRowLower()); assert( eq(base.getRowLower()[3],si1.getRowLower()[3]) ); assert(basePv.isEquivalent(pv)); pv.setVector( si2.getNumRows(),indices, si2.getRowLower()); assert(basePv.isEquivalent(pv)); pv.setVector( si3.getNumRows(),indices, si3.getRowLower()); assert(basePv.isEquivalent(pv)); pv.setVector( si4.getNumRows(),indices, si4.getRowLower()); assert(basePv.isEquivalent(pv)); // Test rowupper basePv.setVector(base.getNumRows(),indices,base.getRowUpper()); pv.setVector( si1.getNumRows(),indices, si1.getRowUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si2.getNumRows(),indices, si2.getRowUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si3.getNumRows(),indices, si3.getRowUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si4.getNumRows(),indices, si4.getRowUpper()); assert(basePv.isEquivalent(pv)); // Test Constraint Matrix assert( base.getMatrixByCol()->isEquivalent(*si1.getMatrixByCol()) ); assert( base.getMatrixByRow()->isEquivalent(*si1.getMatrixByRow()) ); assert( base.getMatrixByCol()->isEquivalent(*si2.getMatrixByCol()) ); assert( base.getMatrixByRow()->isEquivalent(*si2.getMatrixByRow()) ); assert( base.getMatrixByCol()->isEquivalent(*si3.getMatrixByCol()) ); assert( base.getMatrixByRow()->isEquivalent(*si3.getMatrixByRow()) ); assert( base.getMatrixByCol()->isEquivalent(*si4.getMatrixByCol()) ); assert( base.getMatrixByRow()->isEquivalent(*si4.getMatrixByRow()) ); // Test Objective Value assert( eq(base.getObjValue(),si1.getObjValue()) ); assert( eq(base.getObjValue(),si2.getObjValue()) ); assert( eq(base.getObjValue(),si3.getObjValue()) ); assert( eq(base.getObjValue(),si4.getObjValue()) ); } //-------------- assert(OsiXprSolverInterface::getNumInstances()==1); } assert(OsiXprSolverInterface::getNumInstances()==0); // Do common solverInterface testing by calling the // base class testing method. { OsiXprSolverInterface m; OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } }
//------------------------------------------------------------------- // Generate cuts //------------------------------------------------------------------- void CglAllDifferent::generateCuts(const OsiSolverInterface & si, OsiCuts & cs, const CglTreeInfo ) const { #ifndef NDEBUG int nCols=si.getNumCols(); #endif int i; const double * lower = si.getColLower(); const double * upper = si.getColUpper(); #ifdef CGL_DEBUG const OsiRowCutDebugger * debugger = si.getRowCutDebugger(); if (debugger&&debugger->onOptimalPath(si)) { printf("On optimal path %d\n",nPath); nPath++; int nCols=si.getNumCols(); const double * solution = si.getColSolution(); const double * optimal = debugger->optimalSolution(); const double * objective = si.getObjCoefficients(); double objval1=0.0,objval2=0.0; for (i=0;i<nCols;i++) { #if CGL_DEBUG>1 printf("%d %g %g %g %g\n",i,lower[i],solution[i],upper[i],optimal[i]); #endif objval1 += solution[i]*objective[i]; objval2 += optimal[i]*objective[i]; assert(optimal[i]>=lower[i]&&optimal[i]<=upper[i]); } printf("current obj %g, integer %g\n",objval1,objval2); } #endif int * lo = new int[numberDifferent_]; int * up = new int[numberDifferent_]; for (i=0;i<numberDifferent_;i++) { int iColumn = originalWhich_[i]; assert (iColumn<nCols); lo[i] = static_cast<int> (lower[iColumn]); assert (floor(lower[iColumn]+0.5)==lower[iColumn]); up[i] = static_cast<int> (upper[iColumn]); assert (floor(upper[iColumn]+0.5)==upper[iColumn]); assert (up[i]>=lo[i]); } // We are going to assume we can just have one big 2d array! // Could save by going to bits // also could skip sets where all are fixed // could do some of above by separate first pass // once a variable fixed - can take out of list // so need to redo complete stuff (including temp which_) every big pass int offset = COIN_INT_MAX; int maxValue = -COIN_INT_MAX; int numberLook=0; // copies //int * which = new int [numberTotal]; //int * start = new int [numberSets_+1]; for (i=0;i<numberSets_;i++) { for (int j=start_[i];j<start_[i+1];j++) { int k=which_[j]; offset = CoinMin(offset,lo[k]); maxValue = CoinMax(maxValue,up[k]); } numberLook++; int gap = maxValue-offset+1; double size = static_cast<double> (gap) * numberDifferent_; if (size>1.0e7) { if (logLevel_) printf("Only looking at %d sets\n",numberLook); break; } } // Which sets a variable is in int * back = new int [start_[numberSets_]]; int * backStart = new int[numberDifferent_+1]; memset(backStart,0,(numberDifferent_+1)*sizeof(int)); int numberTotal = start_[numberLook]; for (i=0;i<numberTotal;i++) { int k=which_[i]; // note +1 backStart[k+1]++; } int n=0; for (i=0;i<numberDifferent_;i++) { int nThis = backStart[i+1]; backStart[i+1]=n; n+= nThis; } // at end all backStart correct! for (i=0;i<numberLook;i++) { for (int j=start_[i];j<start_[i+1];j++) { int k=which_[j]; // note +1 int iPut = backStart[k+1]; back[iPut]=i; backStart[k+1]=iPut+1; } } // value is possible for variable k if possible[k*gap+value] is nonzero int gap = maxValue-offset+1; char * possible = new char[gap*numberDifferent_]; memset(possible,0,gap*numberDifferent_); // initialize int numberFixed=0; int * alreadyFixed = new int[numberDifferent_]; for (i=0;i<numberDifferent_;i++) { alreadyFixed[i]=-1; int startV = i*gap + lo[i] - offset; int n = up[i]-lo[i]+1; memset(possible+startV,1,n); } for (i=0;i<numberDifferent_;i++) { int n = up[i]-lo[i]+1; if (n==1) { int fixedAt = lo[i]-offset; numberFixed++; alreadyFixed[i]=fixedAt; // take out of all others for (int j=backStart[i];j<backStart[i+1];j++) { int iSet = back[j]; for (int jj=start_[iSet];jj<start_[iSet+1];jj++) { int k=which_[jj]; if (k!=i) { // impossible possible[k*gap+fixedAt]=0; } } } } } bool finished=false; //int numberTightened=0; bool infeasible=false; // space to see which values possible int * check = new int[gap]; unsigned int * bitmap = new unsigned int[numberDifferent_]; int * stack = new int[numberDifferent_+1]; int * first = new int[numberDifferent_+1]; // just for valgrind etc memset(stack,0,(numberDifferent_+1)*sizeof(int)); memset(first,0,(numberDifferent_+1)*sizeof(int)); // do one set at a time while (!finished) { finished=true; int fixed=numberFixed; for (i=0;i<numberLook;i++) { memset(check,0,gap*sizeof(int)); for (int j=start_[i];j<start_[i+1];j++) { int k=which_[j]; if (alreadyFixed[k]>=0) { if (check[alreadyFixed[k]]==0) { check[alreadyFixed[k]]=1; continue; } else { // infeasible infeasible=true; i=numberLook; break; } } char * allowed = possible + k*gap; int n=0; for (int jj=0;jj<gap;jj++) { if (allowed[jj]) { n++; check[jj]++; } } if (n<2) { if (n==1) { // fix int fixedAt = -1; for (int jj=0;jj<gap;jj++) { if (allowed[jj]) { fixedAt=jj; break; } } numberFixed++; alreadyFixed[k]=fixedAt; check[fixedAt]=1; // take out of all others for (int j=backStart[k];j<backStart[k+1];j++) { int iSet = back[j]; for (int jj=start_[iSet];jj<start_[iSet+1];jj++) { int kk=which_[jj]; if (kk!=k) { // impossible possible[kk*gap+fixedAt]=0; } } } } else { // infeasible infeasible=true; j=numberTotal; i=numberLook; break; } } } // now check set // If number covered < number in set infeasible if (gap<30&&!infeasible) { int n=start_[i+1]-start_[i]; memset(bitmap,0,n*sizeof(unsigned int)); int j; int * which = which_+start_[i]; unsigned int covered=0; bool good=true; for (j=0;j<n;j++) { int k=which[j]; char * allowed = possible + k*gap; int jj; for (jj=0;jj<gap;jj++) if (allowed[jj]) break; assert (jj<gap); first[j]=jj; unsigned int iBit = 1<<jj; if ((covered&iBit)==0) { stack[j]=jj; covered |= iBit; } else { // can't jj++; for (;jj<gap;jj++) { iBit = iBit << 1; if (allowed[jj]&&(covered&iBit)==0) break; } if (jj<gap) { stack[j]=jj; covered |= iBit; } else { good = false; break; } } } int nStack=j; // just do first for rest for (;j<n;j++) { int k=which[j]; char * allowed = possible + k*gap; int jj; for (jj=0;jj<gap;jj++) if (allowed[jj]) break; assert (jj<gap); first[j]=jj; } int kLook=0; while (nStack) { nStack--; if (good) { #if 0 printf("con %d = ",i); for (j=0;j<n;j++) printf("%d ",stack[j]+1); printf("\n"); #endif // bug - kLook >= 0 kLook=0; for (j=kLook;j<n;j++) { int iBit = 1 << stack[j]; bitmap[j] |= iBit; } } kLook=nStack; int jj=stack[nStack]; unsigned int iBit = 1<<jj; covered &= ~iBit; { unsigned int kBit=0; for (int k=0;k<nStack;k++) { int kk=stack[k]; kBit |= 1<<kk; } assert (covered==kBit); } jj++; stack[nStack]=jj; while (nStack<n) { int k=which[nStack]; char * allowed = possible + k*gap; for (;jj<gap;jj++) { iBit = 1 << jj; if (allowed[jj]&&(covered&iBit)==0) break; } if (jj<gap) { stack[nStack]=jj; covered |= iBit; nStack++; stack[nStack]=first[nStack]; jj = first[nStack]; good=true; } else { good = false; break; } } } int nnFix=0; // Now see if we can fix any for (j=0;j<n;j++) { int k=which[j]; unsigned int mapped = bitmap[j]; char * allowed = possible + k*gap; unsigned int iBit=1; for (int jj=0;jj<gap;jj++) { if ((mapped&iBit)==0) { if (allowed[jj]) { if (!nnFix) printf("for con %d x ",i); nnFix++; printf("%d not %d ",j,jj+1); allowed[jj]=0; finished=false; } } iBit = iBit << 1; } } if (nnFix) printf("\n"); } } if (numberFixed>fixed) finished=false; // try again } // Could try two sets if (infeasible) { // create infeasible cut OsiRowCut rc; rc.setLb(COIN_DBL_MAX); rc.setUb(0.0); cs.insert(rc); } else { // check to see if can tighten bounds CoinPackedVector lbs; CoinPackedVector ubs; int nTightened=0; for (i=0;i<numberDifferent_;i++) { int iColumn = originalWhich_[i]; char * allowed = possible+i*gap; int firstLo=-1; int lastUp=-1; for (int jj=0;jj<gap;jj++) { if (allowed[jj]) { if (firstLo<0) firstLo=jj; lastUp = jj; } } if (firstLo+offset>lo[i]) { lbs.insert(iColumn,static_cast<double> (firstLo+offset)); nTightened++; } if (lastUp+offset<up[i]) { ubs.insert(iColumn,static_cast<double> (lastUp+offset)); nTightened++; } } if (nTightened) { OsiColCut cc; cc.setUbs(ubs); cc.setLbs(lbs); cc.setEffectiveness(100.0); cs.insert(cc); } } //delete [] which; //delete [] start; delete [] first; delete [] stack; delete [] bitmap; delete [] check; delete [] alreadyFixed; delete [] back; delete [] backStart; delete [] possible; delete [] lo; delete [] up; }