/** scale the cut passed as argument*/ void scale(OsiRowCut &cut) { double rhs = fabs(cut.lb()); CoinPackedVector row; row.reserve(cut.row().getNumElements()); for (int i = 0 ; i < cut.row().getNumElements() ; i++) { row.insert(cut.row().getIndices()[i], cut.row().getElements()[i]/rhs); } cut.setLb(cut.lb()/rhs); cut.setRow(row); }
/* Returns 0 unchanged 1 strengthened 2 weakened 3 deleted */ int CbcCutSubsetModifier::modify(const OsiSolverInterface * /*solver*/, OsiRowCut & cut) { int n = cut.row().getNumElements(); if (!n) return 0; const int * column = cut.row().getIndices(); //const double * element = cut.row().getElements(); int returnCode = 0; for (int i = 0; i < n; i++) { if (column[i] >= firstOdd_) { returnCode = 3; break; } } #ifdef COIN_DETAIL if (!returnCode) { const double * element = cut.row().getElements(); printf("%g <= ", cut.lb()); for (int i = 0; i < n; i++) { printf("%g*x%d ", element[i], column[i]); } printf("<= %g\n", cut.ub()); } #endif //return 3; return returnCode; }
//---------------------------------------------------------------- // == operator //------------------------------------------------------------------- bool OsiRowCut::operator==(const OsiRowCut& rhs) const { if ( this->OsiCut::operator!=(rhs) ) return false; if ( row() != rhs.row() ) return false; if ( lb() != rhs.lb() ) return false; if ( ub() != rhs.ub() ) return false; return true; }
/** scale the cut passed as argument using provided normalization factor*/ void scale(OsiRowCut &cut, double norma) { assert(norma >0.); CoinPackedVector row; row.reserve(cut.row().getNumElements()); for (int i = 0 ; i < cut.row().getNumElements() ; i++) { row.insert(cut.row().getIndices()[i], cut.row().getElements()[i]/norma); } cut.setLb(cut.lb()/norma); cut.setRow(row); }
void OsiTestSolverInterface::applyRowCut(const OsiRowCut& rc) { const int rownum = getNumRows(); const double lb = rc.lb(); const double ub = rc.ub(); rowRimResize_(rownum + 1); rowprice_[rownum] = 0.0; rowlower_[rownum] = lb; rowupper_[rownum] = ub; convertBoundToSense(lb, ub, rowsense_[rownum], rhs_[rownum], rowrange_[rownum]); updateRowMatrix_(); rowMatrix_.appendRow(rc.row()); colMatrixCurrent_ = false; }
/* Insert a row cut unless it is a duplicate (CoinRelFltEq)*/ void OsiCuts::insertIfNotDuplicate( OsiRowCut & rc , CoinRelFltEq treatAsSame) { double newLb = rc.lb(); double newUb = rc.ub(); CoinPackedVector vector = rc.row(); int numberElements =vector.getNumElements(); int * newIndices = vector.getIndices(); double * newElements = vector.getElements(); CoinSort_2(newIndices,newIndices+numberElements,newElements); bool notDuplicate=true; int numberRowCuts = sizeRowCuts(); for ( int i =0; i<numberRowCuts;i++) { const OsiRowCut * cutPtr = rowCutPtr(i); if (cutPtr->row().getNumElements()!=numberElements) continue; if (!treatAsSame(cutPtr->lb(),newLb)) continue; if (!treatAsSame(cutPtr->ub(),newUb)) continue; const CoinPackedVector * thisVector = &(cutPtr->row()); const int * indices = thisVector->getIndices(); const double * elements = thisVector->getElements(); int j; for(j=0;j<numberElements;j++) { if (indices[j]!=newIndices[j]) break; if (!treatAsSame(elements[j],newElements[j])) break; } if (j==numberElements) { notDuplicate=false; break; } } if (notDuplicate) { OsiRowCut * newCutPtr = new OsiRowCut(); newCutPtr->setLb(newLb); newCutPtr->setUb(newUb); newCutPtr->setRow(vector); rowCutPtrs_.push_back(newCutPtr); } }
/** Clean an OsiCut \return 1 if min violation is too small \return 2 if small coefficient can not be removed \return 3 if dynamic is too big \return 4 if too many non zero element*/ int Validator::cleanCut(OsiRowCut & aCut, const double * solCut, const OsiSolverInterface &si, const CglParam& par, const double * origColLower, const double * origColUpper) const { /** Compute fill-in in si */ int numcols = si.getNumCols(); const double * colLower = (origColLower) ? origColLower : si.getColLower(); const double * colUpper = (origColUpper) ? origColUpper : si.getColUpper(); int maxNnz = static_cast<int> (maxFillIn_ * static_cast<double> (numcols)); double rhs = aCut.lb(); assert (aCut.ub()> 1e50); CoinPackedVector *vec = const_cast<CoinPackedVector *>(&aCut.row()); int * indices = vec->getIndices(); double * elems = vec->getElements(); int n = vec->getNumElements(); /** First compute violation if it is too small exit */ double violation = aCut.violated(solCut); if (violation < minViolation_) return 1; /** Now relax get dynamic and remove tiny elements */ int offset = 0; rhs -= 1e-8; double smallest = 1e100; double biggest = 0; for (int i = 0 ; i < n ; i++) { double val = fabs(elems[i]); if (val <= par.getEPS()) //try to remove coef { if (val>0 && val<1e-20) { offset++; continue; throw; } if (val==0) { offset++; continue; } int & iCol = indices[i]; if (elems[i]>0. && colUpper[iCol] < 10000.) { offset++; rhs -= elems[i] * colUpper[iCol]; elems[i]=0; } else if (elems[i]<0. && colLower[iCol] > -10000.) { offset++; rhs -= elems[i] * colLower[iCol]; elems[i]=0.; } else { #ifdef DEBUG std::cout<<"Small coefficient : "<<elems[i]<<" bounds : ["<<colLower[iCol]<<", "<<colUpper[iCol]<<std::endl; #endif numRejected_[SmallCoefficient]++; return SmallCoefficient; } } else //Not a small coefficient keep it { smallest = std::min(val,smallest); biggest = std::max (val,biggest); if (biggest > maxRatio_ * smallest) { #ifdef DEBUG std::cout<<"Whaooo "<<biggest/smallest<<std::endl; #endif numRejected_[BigDynamic]++; return BigDynamic; } if (offset) //if offset is zero current values are ok otherwise translate { int i2 = i - offset; indices[i2] = indices[i]; elems[i2] = elems[i]; } } } if ((n - offset) > maxNnz) { numRejected_[DenseCut] ++; return DenseCut; } if (offset == n) { numRejected_[EmptyCut]++; return EmptyCut; } if (offset) vec->truncate(n - offset); indices = vec->getIndices(); elems = vec->getElements(); n = vec->getNumElements(); aCut.setLb(rhs); violation = aCut.violated(solCut); if (violation < minViolation_) { numRejected_[SmallViolation]++; return SmallViolation; } return NoneAccepted; }
/**Clean cut 2, different algorithm. First check the dynamic of the cut if < maxRatio scale to a biggest coef of 1 otherwise scale it so that biggest coeff is 1 and try removing tinys ( < 1/maxRatio) either succeed or fail */ int Validator::cleanCut2(OsiRowCut & aCut, const double * solCut, const OsiSolverInterface &si, const CglParam &/* par */, const double * origColLower, const double * origColUpper) const { /** Compute fill-in in si */ int numcols = si.getNumCols(); // int numrows = si.getNumRows(); const double * colLower = (origColLower) ? origColLower : si.getColLower(); const double * colUpper = (origColUpper) ? origColUpper : si.getColUpper(); int maxNnz = static_cast<int> ( maxFillIn_ * static_cast<double> (numcols)); double rhs = aCut.lb(); assert (aCut.ub()> 1e50); CoinPackedVector *vec = const_cast<CoinPackedVector *>(&aCut.row()); // vec->sortIncrIndex(); int * indices = vec->getIndices(); double * elems = vec->getElements(); int n = vec->getNumElements(); if (n==0) { numRejected_[EmptyCut]++; return EmptyCut; } /** First compute violation if it is too small exit */ double violation = aCut.violated(solCut); if (violation < minViolation_) return 1; /** Now relax get dynamic and remove tiny elements */ int offset = 0; rhs -= 1e-10; double smallest = fabs(rhs); double biggest = smallest; double veryTiny = 1e-20; for (int i = 0 ; i < n ; i++) { double val = fabs(elems[i]); if (val > veryTiny) //tiny should be very very small { smallest = std::min(val,smallest); biggest = std::max (val,biggest); } } if (biggest > 1e9) { #ifdef DEBUG std::cout<<"Whaooo "<<biggest/smallest<<std::endl; #endif numRejected_[BigDynamic]++; return BigDynamic; } //rescale the cut so that biggest is 1e1. double toBeBiggest = rhsScale_; rhs *= (toBeBiggest / biggest); toBeBiggest /= biggest; for (int i = 0 ; i < n ; i++) { elems[i] *= toBeBiggest; } if (biggest > maxRatio_ * smallest) //we have to remove some small coefficients { double myTiny = biggest * toBeBiggest / maxRatio_; veryTiny *= toBeBiggest ; for (int i = 0 ; i < n ; i++) { double val = fabs(elems[i]); if (val < myTiny) { if (val< veryTiny) { offset++; continue; } int & iCol = indices[i]; if (elems[i]>0. && colUpper[iCol] < 1000.) { offset++; rhs -= elems[i] * colUpper[iCol]; elems[i]=0; } else if (elems[i]<0. && colLower[iCol] > -1000.) { offset++; rhs -= elems[i] * colLower[iCol]; elems[i]=0.; } else { numRejected_[SmallCoefficient]++; return SmallCoefficient; } } else //Not a small coefficient keep it { if (offset) //if offset is zero current values are ok { int i2 = i - offset; indices[i2] = indices[i]; elems[i2] = elems[i]; } } } } if ((n - offset) > maxNnz) { numRejected_[DenseCut] ++; return DenseCut; } if (offset) vec->truncate(n - offset); if (vec->getNumElements() == 0 ) { numRejected_[EmptyCut]++; return EmptyCut; } /** recheck violation */ aCut.setLb(rhs); violation = aCut.violated(solCut); if (violation < minViolation_) { numRejected_[SmallViolation]++; return SmallViolation; } assert(fabs(rhs)<1e09); return NoneAccepted; }
//-------------------------------------------------------------------------- // test the simple rounding cut generators methods. void CglSimpleRoundingUnitTest( const OsiSolverInterface * baseSiP, const std::string mpsDir ) { // Test default constructor { CglSimpleRounding cg; } // Test copy & assignment { CglSimpleRounding rhs; { CglSimpleRounding cg; CglSimpleRounding cgC(cg); rhs=cg; } } // Test gcd and gcdn { CglSimpleRounding cg; int v = cg.gcd(122,356); assert(v==2); v=cg.gcd(356,122); assert(v==2); v=cg.gcd(54,67); assert(v==1); v=cg.gcd(67,54); assert(v==1); v=cg.gcd(485,485); assert(v==485); v=cg.gcd(17*13,17*23); assert( v==17); v=cg.gcd(17*13*5,17*23); assert( v==17); v=cg.gcd(17*13*23,17*23); assert(v==17*23); int a[4] = {12, 20, 32, 400}; v= cg.gcdv(4,a); assert(v== 4); int b[4] = {782, 4692, 51, 2754}; v= cg.gcdv(4,b); assert(v== 17); int c[4] = {50, 40, 30, 10}; v= cg.gcdv(4,c); assert(v== 10); } // Test generate cuts method on exmip1.5.mps { CglSimpleRounding cg; OsiSolverInterface * siP = baseSiP->clone(); std::string fn = mpsDir+"exmip1.5.mps"; siP->readMps(fn.c_str(),""); OsiCuts cuts; cg.generateCuts(*siP,cuts); // there should be 3 cuts int nRowCuts = cuts.sizeRowCuts(); assert(nRowCuts==3); // get the last "sr"=simple rounding cut that was derived OsiRowCut srRowCut2 = cuts.rowCut(2); CoinPackedVector srRowCutPV2 = srRowCut2.row(); // this is what the last cut should look like: i.e. the "solution" const int solSize = 2; int solCols[solSize]={2,3}; double solCoefs[solSize]={5.0, 4.0}; OsiRowCut solRowCut; solRowCut.setRow(solSize,solCols,solCoefs); solRowCut.setLb(-COIN_DBL_MAX); solRowCut.setUb(2.0); // Test for equality between the derived cut and the solution cut // Note: testing two OsiRowCuts are equal invokes testing two // CoinPackedVectors are equal which invokes testing two doubles // are equal. Usually not a good idea to test that two doubles are equal, // but in this cut the "doubles" represent integer values. Also allow that // different solvers have different orderings in packed vectors, which may // not match the ordering defined for solRowCut. assert(srRowCut2.OsiCut::operator==(solRowCut)) ; assert(srRowCut2.row().isEquivalent(solRowCut.row())) ; assert(srRowCut2.lb() == solRowCut.lb()) ; assert(srRowCut2.ub() == solRowCut.ub()) ; delete siP; } // Test generate cuts method on p0033 { CglSimpleRounding cg; OsiSolverInterface * siP = baseSiP->clone(); std::string fn = mpsDir+"p0033"; siP->readMps(fn.c_str(),"mps"); OsiCuts cuts; cg.generateCuts(*siP,cuts); // p0033 is the optimal solution to p0033 int objIndices[14] = { 0, 6, 7, 9, 13, 17, 18, 22, 24, 25, 26, 27, 28, 29 }; CoinPackedVector p0033(14,objIndices,1.0); // test that none of the generated cuts // chops off the optimal solution int nRowCuts = cuts.sizeRowCuts(); OsiRowCut rcut; CoinPackedVector rpv; int i; for (i=0; i<nRowCuts; i++){ rcut = cuts.rowCut(i); rpv = rcut.row(); double p0033Sum = (rpv*p0033).sum(); double rcutub = rcut.ub(); assert (p0033Sum <= rcutub); } // test that the cuts improve the // lp objective function value siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("Final LP min=%f\n\n",lpRelaxAfter); #endif assert( lpRelaxBefore < lpRelaxAfter ); delete siP; } }
//-------------------------------------------------------------------------- // test EKKsolution methods. void CglProbingUnitTest( const OsiSolverInterface * baseSiP, const std::string mpsDir ) { # ifdef CGL_DEBUG int i ; // define just once # endif CoinRelFltEq eq(0.000001); // Test default constructor { CglProbing aGenerator; } // Test copy & assignment { CglProbing rhs; { CglProbing bGenerator; CglProbing cGenerator(bGenerator); rhs=bGenerator; } } { OsiCuts osicuts; CglProbing test1; OsiSolverInterface * siP = baseSiP->clone(); int nColCuts; int nRowCuts; std::string fn = mpsDir+"p0033"; siP->readMps(fn.c_str(),"mps"); siP->initialSolve(); // just unsatisfied variables test1.generateCuts(*siP,osicuts); nColCuts = osicuts.sizeColCuts(); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" probing cuts"<<std::endl; { std::cout<<"there are "<<nColCuts<<" probing column cuts"<<std::endl; #ifdef CGL_DEBUG const double * lo = siP->getColLower(); const double * up = siP->getColUpper(); for (i=0; i<nColCuts; i++){ OsiColCut ccut; CoinPackedVector cpv; ccut = osicuts.colCut(i); cpv = ccut.lbs(); int n = cpv.getNumElements(); int j; const int * indices = cpv.getIndices(); double* elements = cpv.getElements(); for (j=0;j<n;j++) { int icol=indices[j]; if (elements[j]>lo[icol]) std::cout<<"Can increase lb on "<<icol<<" from "<<lo[icol]<< " to "<<elements[j]<<std::endl; } cpv = ccut.ubs(); n = cpv.getNumElements(); indices = cpv.getIndices(); elements = cpv.getElements(); for (j=0;j<n;j++) { int icol=indices[j]; if (elements[j]<up[icol]) std::cout<<"Can decrease ub on "<<icol<<" from "<<up[icol]<< " to "<<elements[j]<<std::endl; } } #endif } #ifdef CGL_DEBUG for (i=0; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; const double * colsol = siP->getColSolution(); rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; double lb=rcut.lb(); double ub=rcut.ub(); for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } } #endif if (nRowCuts==1) { CoinPackedVector check; int index[] = {6,32}; double el[] = {1,1}; check.setVector(2,index,el); // sort Elements in increasing order CoinPackedVector rpv=osicuts.rowCut(0).row(); assert (rpv.getNumElements()==2); rpv.sortIncrIndex(); assert (check==rpv); assert (osicuts.rowCut(0).lb()==1.0); } // now all variables osicuts=OsiCuts(); test1.setMode(2); test1.setRowCuts(3); test1.generateCuts(*siP,osicuts); nColCuts = osicuts.sizeColCuts(); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" probing cuts"<<std::endl; { std::cout<<"there are "<<nColCuts<<" probing column cuts"<<std::endl; #ifdef CGL_DEBUG const double * lo = siP->getColLower(); const double * up = siP->getColUpper(); for (i=0; i<nColCuts; i++){ OsiColCut ccut; CoinPackedVector cpv; ccut = osicuts.colCut(i); cpv = ccut.lbs(); int n = cpv.getNumElements(); int j; const int * indices = cpv.getIndices(); double* elements = cpv.getElements(); for (j=0;j<n;j++) { int icol=indices[j]; if (elements[j]>lo[icol]) std::cout<<"Can increase lb on "<<icol<<" from "<<lo[icol]<< " to "<<elements[j]<<std::endl; } cpv = ccut.ubs(); n = cpv.getNumElements(); indices = cpv.getIndices(); elements = cpv.getElements(); for (j=0;j<n;j++) { int icol=indices[j]; if (elements[j]<up[icol]) std::cout<<"Can decrease ub on "<<icol<<" from "<<up[icol]<< " to "<<elements[j]<<std::endl; } } #endif } #ifdef CGL_DEBUG for (i=0; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; const double * colsol = siP->getColSolution(); rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; double lb=rcut.lb(); double ub=rcut.ub(); for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } } #endif assert (osicuts.sizeRowCuts()>=4); delete siP; } }
//-------------------------------------------------------------------------- // ** At present this does not use any solver void CglGomoryUnitTest( const OsiSolverInterface * baseSiP, const std::string mpsDir ) { CoinRelFltEq eq(0.000001); // Test default constructor { CglGomory aGenerator; assert (aGenerator.getLimit()==50); assert (aGenerator.getAway()==0.05); } // Test copy & assignment etc { CglGomory rhs; { CglGomory bGenerator; bGenerator.setLimit(99); bGenerator.setAway(0.2); CglGomory cGenerator(bGenerator); rhs=bGenerator; assert (rhs.getLimit()==99); assert (rhs.getAway()==0.2); } } // Test explicit form - all integer (pg 125 Wolsey) if (1) { OsiCuts osicuts; CglGomory test1; int i; int nOldCuts=0,nRowCuts; // matrix data //deliberate hiccup of 2 between 0 and 1 CoinBigIndex start[5]={0,4,7,8,9}; int length[5]={2,3,1,1,1}; int rows[11]={0,2,-1,-1,0,1,2,0,1,2}; double elements[11]={7.0,2.0,1.0e10,1.0e10,-2.0,1.0,-2.0,1,1,1}; CoinPackedMatrix matrix(true,3,5,8,elements,rows,start,length); // rim data (objective not used just yet) double rowLower[5]={14.0,3.0,3.0,1.0e10,1.0e10}; double rowUpper[5]={14.0,3.0,3.0,-1.0e10,-1.0e10}; double colLower[7]={0.0,0.0,0.0,0.0,0.0,0.0,0.0}; double colUpper[7]={100.0,100.0,100.0,100.0,100.0,100.0,100.0}; // integer char intVar[7]={2,2,2,2,2,2,2}; // basis 1 int rowBasis1[3]={-1,-1,-1}; int colBasis1[5]={1,1,-1,-1,1}; CoinWarmStartBasis warm; warm.setSize(5,3); for (i=0;i<3;i++) { if (rowBasis1[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<5;i++) { if (colBasis1[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 1 double colsol1[5]={20.0/7.0,3.0,0.0,0.0,23.0/7.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol1, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==2); // cuts always <= int testCut=0; // test first cut as stronger double rhs=-6.0; double testCut1[5]={0.0,0.0,-1.0,-2.0,0.0}; double * cut = testCut1; double * colsol = colsol1; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==2); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut // explicit slack matrix.setDimensions(-1,6); rpv.insert(5,1.0*7.0); // to get cut in book rowLower[3]=ub; rowUpper[3]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 2 int rowBasis2[4]={-1,-1,-1,-1}; int colBasis2[6]={1,1,1,1,-1,-1}; warm.setSize(6,4); for (i=0;i<4;i++) { if (rowBasis2[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<6;i++) { if (colBasis2[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 2 double colsol2[6]={2.0,0.5,1.0,2.5,0.0,0.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol2, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts-nOldCuts==2); // cuts always <= testCut=0; // test first cut as stronger rhs=-1.0; double testCut2[6]={0.0,0.0,0.0,0.0,-1.0,0.0}; cut = testCut2; colsol = colsol2; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==1); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut // explicit slack matrix.setDimensions(-1,7); rpv.insert(6,1.0); rowLower[4]=ub; rowUpper[4]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 3 int rowBasis3[5]={-1,-1,-1,-1,-1}; int colBasis3[7]={1,1,1,1,1,-1,-1}; warm.setSize(7,5); for (i=0;i<5;i++) { if (rowBasis3[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<7;i++) { if (colBasis3[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 3 double colsol3[7]={2.0,1.0,2.0,2.0,1.0,0.0,0.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol3, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==nOldCuts); } // Test explicit form - this time with x4 flipped if (1) { OsiCuts osicuts; CglGomory test1; int i; int nOldCuts=0,nRowCuts; // matrix data //deliberate hiccup of 2 between 0 and 1 CoinBigIndex start[5]={0,4,7,8,9}; int length[5]={2,3,1,1,1}; int rows[11]={0,2,-1,-1,0,1,2,0,1,2}; double elements[11]={7.0,2.0,1.0e10,1.0e10,-2.0,1.0,-2.0,1,-1,1}; CoinPackedMatrix matrix(true,3,5,8,elements,rows,start,length); // rim data (objective not used just yet) double rowLower[5]={14.0,-5.0,3.0,1.0e10,1.0e10}; double rowUpper[5]={14.0,-5.0,3.0,-1.0e10,-1.0e10}; double colLower[7]={0.0,0.0,0.0,0.0,0.0,0.0,0.0}; double colUpper[7]={100.0,100.0,100.0,8.0,100.0,100.0,100.0}; // integer char intVar[7]={2,2,2,2,2,2,2}; // basis 1 int rowBasis1[3]={-1,-1,-1}; int colBasis1[5]={1,1,-1,-1,1}; CoinWarmStartBasis warm; warm.setSize(5,3); for (i=0;i<3;i++) { if (rowBasis1[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<5;i++) { if (colBasis1[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 1 double colsol1[5]={20.0/7.0,3.0,0.0,8.0,23.0/7.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol1, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==2); // cuts always <= int testCut=0; // test first cut as stronger double rhs=10.0; double testCut1[5]={0.0,0.0,-1.0,2.0,0.0}; double * cut = testCut1; double * colsol = colsol1; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==2); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut // explicit slack matrix.setDimensions(-1,6); rpv.insert(5,1.0*7.0); // to get cut in book rowLower[3]=ub; rowUpper[3]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 2 int rowBasis2[4]={-1,-1,-1,-1}; int colBasis2[6]={1,1,1,1,-1,-1}; warm.setSize(6,4); for (i=0;i<4;i++) { if (rowBasis2[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<6;i++) { if (colBasis2[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 2 double colsol2[6]={2.0,0.5,1.0,5.5,0.0,0.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol2, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts-nOldCuts==2); // cuts always <= testCut=0; // test first cut as stronger rhs=-1.0; double testCut2[6]={0.0,0.0,0.0,0.0,-1.0,0.0}; cut = testCut2; colsol = colsol2; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==1); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut // explicit slack matrix.setDimensions(-1,7); rpv.insert(6,1.0); rowLower[4]=ub; rowUpper[4]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 3 int rowBasis3[5]={-1,-1,-1,-1,-1}; int colBasis3[7]={1,1,1,1,1,-1,-1}; warm.setSize(7,5); for (i=0;i<5;i++) { if (rowBasis3[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<7;i++) { if (colBasis3[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 3 double colsol3[7]={2.0,1.0,2.0,6.0,1.0,0.0,0.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol3, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==nOldCuts); } // Test with slacks if (1) { OsiCuts osicuts; CglGomory test1; int i; int nOldCuts=0,nRowCuts; // matrix data //deliberate hiccup of 2 between 0 and 1 CoinBigIndex start[5]={0,4}; int length[5]={2,3}; int rows[11]={0,2,-1,-1,0,1,2}; double elements[11]={7.0,2.0,1.0e10,1.0e10,-2.0,1.0,-2.0}; CoinPackedMatrix matrix(true,3,2,5,elements,rows,start,length); // rim data (objective not used just yet) double rowLower[5]={-1.0e10,-1.0e10,-1.0e10,1.0e10,1.0e10}; double rowUpper[5]={14.0,3.0,3.0,-1.0e10,-1.0e10}; double colLower[2]={0.0,0.0}; double colUpper[2]={100.0,100.0}; // integer char intVar[2]={2,2}; // basis 1 int rowBasis1[3]={-1,-1,1}; int colBasis1[2]={1,1}; CoinWarmStartBasis warm; warm.setSize(2,3); for (i=0;i<3;i++) { if (rowBasis1[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<2;i++) { if (colBasis1[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 1 double colsol1[2]={20.0/7.0,3.0}; test1.generateCuts(NULL, osicuts, matrix, /* objective,*/ colsol1, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==1); // cuts always <= int testCut=0; // test first cut as stronger double rhs=2.0; double testCut1[2]={1.0,0.0}; double * cut = testCut1; double * colsol = colsol1; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==1); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut rowLower[3]=-1.0e100; rowUpper[3]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 2 int rowBasis2[4]={1,1,-1,-1}; int colBasis2[2]={1,1}; warm.setSize(2,4); for (i=0;i<4;i++) { if (rowBasis2[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<2;i++) { if (colBasis2[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 2 double colsol2[2]={2.0,0.5}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol2, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts-nOldCuts==1); // cuts always <= testCut=0; // test first cut as stronger rhs=1.0; double testCut2[2]={1.0,-1.0}; cut = testCut2; colsol = colsol2; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==2); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut rowLower[4]=-1.0e100; rowUpper[4]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 3 int rowBasis3[5]={1,1,1,-1,-1}; int colBasis3[2]={1,1}; warm.setSize(2,5); for (i=0;i<5;i++) { if (rowBasis3[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<2;i++) { if (colBasis3[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 3 double colsol3[2]={2.0,1.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol3, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==nOldCuts); } // swap some rows to G if (1) { OsiCuts osicuts; CglGomory test1; int i; int nOldCuts=0,nRowCuts; // matrix data //deliberate hiccup of 2 between 0 and 1 CoinBigIndex start[5]={0,4}; int length[5]={2,3}; int rows[11]={0,2,-1,-1,0,1,2}; double elements[11]={-7.0,-2.0,1.0e10,1.0e10,+2.0,1.0,+2.0}; CoinPackedMatrix matrix(true,3,2,5,elements,rows,start,length); // rim data (objective not used just yet) double rowUpper[5]={1.0e10,3.0,1.0e10,-1.0e10,-1.0e10}; double rowLower[5]={-14.0,-1.0e10,-3.0,1.0e10,1.0e10}; double colLower[2]={0.0,0.0}; double colUpper[2]={100.0,100.0}; // integer char intVar[2]={2,2}; // basis 1 int rowBasis1[3]={-1,-1,1}; int colBasis1[2]={1,1}; CoinWarmStartBasis warm; warm.setSize(2,3); for (i=0;i<3;i++) { if (rowBasis1[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<2;i++) { if (colBasis1[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 1 double colsol1[2]={20.0/7.0,3.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol1, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==1); // cuts always <= int testCut=0; // test first cut as stronger double rhs=2.0; double testCut1[2]={1.0,0.0}; double * cut = testCut1; double * colsol = colsol1; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==1); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut rowLower[3]=-1.0e100; rowUpper[3]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 2 int rowBasis2[4]={1,1,-1,-1}; int colBasis2[2]={1,1}; warm.setSize(2,4); for (i=0;i<4;i++) { if (rowBasis2[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<2;i++) { if (colBasis2[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 2 double colsol2[2]={2.0,0.5}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol2, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts-nOldCuts==1); // cuts always <= testCut=0; // test first cut as stronger rhs=1.0; double testCut2[2]={1.0,-1.0}; cut = testCut2; colsol = colsol2; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==2); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut rowLower[4]=-1.0e100; rowUpper[4]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 3 int rowBasis3[5]={1,1,1,-1,-1}; int colBasis3[2]={1,1}; warm.setSize(2,5); for (i=0;i<5;i++) { if (rowBasis3[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<2;i++) { if (colBasis3[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 3 double colsol3[2]={2.0,1.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol3, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==nOldCuts); } // NOW mixed integer gomory cuts // Test explicit form - (pg 130 Wolsey) // Some arrays left same size as previously although not used in full if (1) { OsiCuts osicuts; CglGomory test1; int i; int nOldCuts=0,nRowCuts; // matrix data //deliberate hiccup of 2 between 0 and 1 CoinBigIndex start[5]={0,4,7,8,9}; int length[5]={2,3,1,1,1}; int rows[11]={0,2,-1,-1,0,1,2,0,1,2}; double elements[11]={7.0,2.0,1.0e10,1.0e10,-2.0,1.0,-2.0,1,1,1}; CoinPackedMatrix matrix(true,3,5,8,elements,rows,start,length); // rim data (objective not used just yet) double rowLower[5]={14.0,3.0,3.0,1.0e10,1.0e10}; double rowUpper[5]={14.0,3.0,3.0,-1.0e10,-1.0e10}; double colLower[7]={0.0,0.0,0.0,0.0,0.0,0.0,0.0}; double colUpper[7]={100.0,100.0,100.0,100.0,100.0,100.0,100.0}; // integer char intVar[7]={2,0,0,0,0,0,0}; // basis 1 int rowBasis1[3]={-1,-1,-1}; int colBasis1[5]={1,1,-1,-1,1}; CoinWarmStartBasis warm; warm.setSize(5,3); for (i=0;i<3;i++) { if (rowBasis1[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<5;i++) { if (colBasis1[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 1 double colsol1[5]={20.0/7.0,3.0,0.0,0.0,23.0/7.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol1, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==1); // cuts always <= int testCut=0; // test first cut as stronger double rhs=-6.0/7.0; double testCut1[5]={0.0,0.0,-1.0/7.0,-2.0/7.0,0.0}; double * cut = testCut1; double * colsol = colsol1; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==2); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut // explicit slack matrix.setDimensions(-1,6); rpv.insert(5,1.0); // to get cut in book rowLower[3]=ub; rowUpper[3]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 2 int rowBasis2[4]={-1,-1,-1,-1}; int colBasis2[6]={1,1,1,1,-1,-1}; warm.setSize(6,4); for (i=0;i<4;i++) { if (rowBasis2[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<6;i++) { if (colBasis2[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 2 double colsol2[6]={2.0,0.5,1.0,2.5,0.0,0.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol2, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==nOldCuts); } // Test explicit form - this time with x4 flipped if (1) { OsiCuts osicuts; CglGomory test1; int i; int nOldCuts=0,nRowCuts; // matrix data //deliberate hiccup of 2 between 0 and 1 CoinBigIndex start[5]={0,4,7,8,9}; int length[5]={2,3,1,1,1}; int rows[11]={0,2,-1,-1,0,1,2,0,1,2}; double elements[11]={7.0,2.0,1.0e10,1.0e10,-2.0,1.0,-2.0,1,-1,1}; CoinPackedMatrix matrix(true,3,5,8,elements,rows,start,length); // rim data (objective not used just yet) double rowLower[5]={14.0,-5.0,3.0,1.0e10,1.0e10}; double rowUpper[5]={14.0,-5.0,3.0,-1.0e10,-1.0e10}; double colLower[7]={0.0,0.0,0.0,0.0,0.0,0.0,0.0}; double colUpper[7]={100.0,100.0,100.0,8.0,100.0,100.0,100.0}; // integer char intVar[7]={2,0,0,0,0,0,0}; // basis 1 int rowBasis1[3]={-1,-1,-1}; int colBasis1[5]={1,1,-1,-1,1}; CoinWarmStartBasis warm; warm.setSize(5,3); for (i=0;i<3;i++) { if (rowBasis1[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<5;i++) { if (colBasis1[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 1 double colsol1[5]={20.0/7.0,3.0,0.0,8.0,23.0/7.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol1, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==1); // cuts always <= int testCut=0; double rhs=10.0/7.0; double testCut1[5]={0.0,0.0,-1.0/7.0,2.0/7.0,0.0}; double * cut = testCut1; double * colsol = colsol1; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==2); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut // explicit slack matrix.setDimensions(-1,6); rpv.insert(5,1.0); // to get cut in book rowLower[3]=ub; rowUpper[3]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 2 int rowBasis2[4]={-1,-1,-1,-1}; int colBasis2[6]={1,1,1,1,-1,-1}; warm.setSize(6,4); for (i=0;i<4;i++) { if (rowBasis2[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<6;i++) { if (colBasis2[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 2 double colsol2[6]={2.0,0.5,1.0,5.5,0.0,0.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol2, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==nOldCuts); } // Test with slacks if (1) { OsiCuts osicuts; CglGomory test1; int i; int nOldCuts=0,nRowCuts; // matrix data //deliberate hiccup of 2 between 0 and 1 CoinBigIndex start[5]={0,4}; int length[5]={2,3}; int rows[11]={0,2,-1,-1,0,1,2}; double elements[11]={7.0,2.0,1.0e10,1.0e10,-2.0,1.0,-2.0}; CoinPackedMatrix matrix(true,3,2,5,elements,rows,start,length); // rim data (objective not used just yet) double rowLower[5]={-1.0e10,-1.0e10,-1.0e10,1.0e10,1.0e10}; double rowUpper[5]={14.0,3.0,3.0,-1.0e10,-1.0e10}; double colLower[2]={0.0,0.0}; double colUpper[2]={100.0,100.0}; // integer char intVar[2]={2,0}; // basis 1 int rowBasis1[3]={-1,-1,1}; int colBasis1[2]={1,1}; CoinWarmStartBasis warm; warm.setSize(2,3); for (i=0;i<3;i++) { if (rowBasis1[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<2;i++) { if (colBasis1[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 1 double colsol1[2]={20.0/7.0,3.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol1, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==1); // cuts always <= int testCut=0; // test first cut as stronger double rhs=2.0; double testCut1[2]={1.0,0.0}; double * cut = testCut1; double * colsol = colsol1; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==1); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut rowLower[3]=-1.0e100; rowUpper[3]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 2 int rowBasis2[4]={1,1,-1,-1}; int colBasis2[2]={1,1}; warm.setSize(2,4); for (i=0;i<4;i++) { if (rowBasis2[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<2;i++) { if (colBasis2[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 2 double colsol2[2]={2.0,0.5}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol2, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==nOldCuts); } // swap some rows to G if (1) { OsiCuts osicuts; CglGomory test1; int i; int nOldCuts=0,nRowCuts; // matrix data //deliberate hiccup of 2 between 0 and 1 CoinBigIndex start[5]={0,4}; int length[5]={2,3}; int rows[11]={0,2,-1,-1,0,1,2}; double elements[11]={-7.0,-2.0,1.0e10,1.0e10,+2.0,1.0,+2.0}; CoinPackedMatrix matrix(true,3,2,5,elements,rows,start,length); // rim data (objective not used just yet) double rowUpper[5]={1.0e10,3.0,1.0e10,-1.0e10,-1.0e10}; double rowLower[5]={-14.0,-1.0e10,-3.0,1.0e10,1.0e10}; double colLower[2]={0.0,0.0}; double colUpper[2]={100.0,100.0}; // integer char intVar[2]={2,0}; // basis 1 int rowBasis1[3]={-1,-1,1}; int colBasis1[2]={1,1}; CoinWarmStartBasis warm; warm.setSize(2,3); for (i=0;i<3;i++) { if (rowBasis1[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<2;i++) { if (colBasis1[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 1 double colsol1[2]={20.0/7.0,3.0}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol1, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==1); // cuts always <= int testCut=0; // test first cut as stronger double rhs=2.0; double testCut1[2]={1.0,0.0}; double * cut = testCut1; double * colsol = colsol1; for (i=nOldCuts; i<nRowCuts; i++){ OsiRowCut rcut; CoinPackedVector rpv; rcut = osicuts.rowCut(i); rpv = rcut.row(); const int n = rpv.getNumElements(); const int * indices = rpv.getIndices(); double* elements = rpv.getElements(); double sum2=0.0; int k=0; for (k=0; k<n; k++){ int column=indices[k]; sum2 += colsol[column]*elements[k]; } double ub=rcut.ub(); #ifdef CGL_DEBUG double lb=rcut.lb(); if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) { std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl; for (k=0; k<n; k++){ int column=indices[k]; std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<< colsol[column]<<") "; } std::cout <<std::endl; } #endif if (i-nOldCuts==testCut) { assert( eq(rhs,ub)); assert(n==1); for (k=0; k<n; k++){ int column=indices[k]; assert (eq(cut[column],elements[k])); } // add cut rowLower[3]=-1.0e100; rowUpper[3]=ub; matrix.appendRow(rpv); } } nOldCuts=nRowCuts; // basis 2 int rowBasis2[4]={1,1,-1,-1}; int colBasis2[2]={1,1}; warm.setSize(2,4); for (i=0;i<4;i++) { if (rowBasis2[i]<0) { warm.setArtifStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setArtifStatus(i,CoinWarmStartBasis::basic); } } for (i=0;i<2;i++) { if (colBasis2[i]<0) { warm.setStructStatus(i,CoinWarmStartBasis::atLowerBound); } else { warm.setStructStatus(i,CoinWarmStartBasis::basic); } } // solution 2 double colsol2[2]={2.0,0.5}; test1.generateCuts(NULL, osicuts, matrix, /*objective,*/ colsol2, colLower, colUpper, rowLower, rowUpper, intVar, &warm); nRowCuts = osicuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" gomory cuts"<<std::endl; assert (nRowCuts==nOldCuts); } // Miplib3 problem p0033 if (1) { // Setup OsiSolverInterface * siP = baseSiP->clone(); std::string fn(mpsDir+"p0033"); siP->readMps(fn.c_str(),"mps"); siP->activateRowCutDebugger("p0033"); CglGomory test; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); std::cout<<"Initial LP value: "<<lpRelaxBefore<<std::endl; assert( eq(lpRelaxBefore, 2520.5717391304347) ); // Fails with OsiCpx, OsiXpr: /********** double mycs[] = {0, 1, 0, 0, -2.0837010502455788e-19, 1, 0, 0, 1, 0.021739130434782594, 0.35652173913043478, -6.7220534694101275e-18, 5.3125906451789717e-18, 1, 0, 1.9298798670241979e-17, 0, 0, 0, 7.8875708048320448e-18, 0.5, 0, 0.85999999999999999, 1, 1, 0.57999999999999996, 1, 0, 1, 0, 0.25, 0, 0.67500000000000004}; siP->setColSolution(mycs); ****/ OsiCuts cuts; // Test generateCuts method test.generateCuts(*siP,cuts); int nRowCuts = cuts.sizeRowCuts(); std::cout<<"There are "<<nRowCuts<<" Gomory cuts"<<std::endl; assert(cuts.sizeRowCuts() > 0); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); std::cout<<"LP value with cuts: "<<lpRelaxAfter<<std::endl; //assert( eq(lpRelaxAfter, 2592.1908295194507) ); assert( lpRelaxAfter> 2550.0 ); assert( lpRelaxBefore < lpRelaxAfter ); assert(lpRelaxAfter < 3089.1); delete siP; } }
SCIP_RETCODE SCIPconshdlrBenders::sepaBenders( SCIP * scip, SCIP_CONSHDLR * conshdlr, SCIP_SOL * sol, whereFrom where, SCIP_RESULT * result) { OsiCuts cs; /**< Benders cut placeholder */ SCIP_Real * vals = NULL; /**< current solution */ #if 1 if (scip_checkpriority_ < 0) { /** consider incumbent solutions only */ double primObj = SCIPgetPrimalbound(scip); double currObj = SCIPgetSolOrigObj(scip, sol); if (SCIPisLT(scip, primObj, currObj)) { DSPdebugMessage(" -> primObj %e currObj %e\n", primObj, currObj); return SCIP_OKAY; } } #endif /** allocate memory */ SCIP_CALL(SCIPallocMemoryArray(scip, &vals, nvars_)); /** get current solution */ SCIP_CALL(SCIPgetSolVals(scip, sol, nvars_, vars_, vals)); /** TODO The following filter does not work, meaning that it provides suboptimal solution. * I do not know the reason. */ #if 0 double maxviol = 1.e-10; for (int j = 0; j < nvars_ - naux_; ++j) { SCIP_VARTYPE vartype = SCIPvarGetType(vars_[j]); if (vartype == SCIP_VARTYPE_CONTINUOUS) continue; double viol = 0.5 - fabs(vals[j] - floor(vals[j]) - 0.5); if (viol > maxviol) maxviol = viol; } DSPdebugMessage("maximum violation %e\n", maxviol); if (where != from_scip_check && where != from_scip_enfolp && where != from_scip_enfops && maxviol > 1.e-7) { printf("where %d maxviol %e\n", where, maxviol); /** free memory */ SCIPfreeMemoryArray(scip, &vals); return SCIP_OKAY; } #endif #ifdef DSP_DEBUG2 double minvals = COIN_DBL_MAX; double maxvals = -COIN_DBL_MAX; double sumvals = 0.; double ssvals = 0.; //printf("nvars_ %d naux_ %d nAuxvars_ %d\n", nvars_, naux_, tss_->nAuxvars_); for (int j = 0; j < nvars_ - naux_; ++j) { // if (vals[j] < 0 || vals[j] > 1) // printf("solution %d has value %e.\n", j, vals[j]); sumvals += vals[j]; ssvals += vals[j] * vals[j]; minvals = minvals > vals[j] ? vals[j] : minvals; maxvals = maxvals < vals[j] ? vals[j] : maxvals; } DSPdebugMessage("solution: min %e max %e avg %e sum %e two-norm %e\n", minvals, maxvals, sumvals / nvars_, sumvals, sqrt(ssvals)); #endif #define SCAN_GLOBAL_CUT_POOL #ifdef SCAN_GLOBAL_CUT_POOL if (SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPgetStage(scip) == SCIP_STAGE_SOLVED || SCIPgetStage(scip) == SCIP_STAGE_EXITSOLVE) { bool addedPoolCut = false; int numPoolCuts = SCIPgetNPoolCuts(scip); int numCutsToScan = 100; SCIP_CUT ** poolcuts = SCIPgetPoolCuts(scip); for (int i = numPoolCuts - 1; i >= 0; --i) { if (i < 0) break; if (numCutsToScan == 0) break; /** retrieve row */ SCIP_ROW * poolcutrow = SCIPcutGetRow(poolcuts[i]); /** benders? */ if (strcmp(SCIProwGetName(poolcutrow), "benders") != 0) continue; /** counter */ numCutsToScan--; if (SCIPgetCutEfficacy(scip, sol, poolcutrow) > 1.e-6) { if (where == from_scip_sepalp || where == from_scip_sepasol || where == from_scip_enfolp) { /** add cut */ SCIP_Bool infeasible; SCIP_CALL(SCIPaddCut(scip, sol, poolcutrow, FALSE, /**< force cut */ &infeasible)); if (infeasible) *result = SCIP_CUTOFF; else //if (*result != SCIP_CUTOFF) *result = SCIP_SEPARATED; } else *result = SCIP_INFEASIBLE; addedPoolCut = true; break; } } if (addedPoolCut) { DSPdebugMessage("Added pool cut\n"); /** free memory */ SCIPfreeMemoryArray(scip, &vals); return SCIP_OKAY; } } #endif /** generate Benders cuts */ assert(tss_); tss_->generateCuts(nvars_, vals, &cs); /** If found Benders cuts */ for (int i = 0; i < cs.sizeCuts(); ++i) { /** get cut pointer */ OsiRowCut * rc = cs.rowCutPtr(i); if (!rc) continue; const CoinPackedVector cutrow = rc->row(); if (cutrow.getNumElements() == 0) continue; /** is optimality cut? */ bool isOptimalityCut = false; for (int j = nvars_ - naux_; j < nvars_; ++j) { if (cutrow.getMaxIndex() == j) { isOptimalityCut = true; break; } } double efficacy = rc->violated(vals) / cutrow.twoNorm(); SCIP_Bool isEfficacious = efficacy > 1.e-6; #define KK_TEST #ifdef KK_TEST if (SCIPgetStage(scip) == SCIP_STAGE_INITSOLVE || SCIPgetStage(scip) == SCIP_STAGE_SOLVING) { /** create empty row */ SCIP_ROW * row = NULL; SCIP_CALL(SCIPcreateEmptyRowCons(scip, &row, conshdlr, "benders", rc->lb(), SCIPinfinity(scip), FALSE, /**< is row local? */ FALSE, /**< is row modifiable? */ FALSE /**< is row removable? can this be TRUE? */)); /** cache the row extension and only flush them if the cut gets added */ SCIP_CALL(SCIPcacheRowExtensions(scip, row)); /** collect all non-zero coefficients */ for (int j = 0; j < cutrow.getNumElements(); ++j) SCIP_CALL(SCIPaddVarToRow(scip, row, vars_[cutrow.getIndices()[j]], cutrow.getElements()[j])); DSPdebugMessage("found Benders (%s) cut: act=%f, lhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n", isOptimalityCut ? "opti" : "feas", SCIPgetRowLPActivity(scip, row), SCIProwGetLhs(row), SCIProwGetNorm(row), SCIPgetCutEfficacy(scip, sol, row), SCIPgetRowMinCoef(scip, row), SCIPgetRowMaxCoef(scip, row), SCIPgetRowMaxCoef(scip, row)/SCIPgetRowMinCoef(scip, row)); /** flush all changes before adding cut */ SCIP_CALL(SCIPflushRowExtensions(scip, row)); DSPdebugMessage("efficacy %e isEfficatious %d\n", efficacy, isEfficacious); if (isEfficacious) { if (where == from_scip_sepalp || where == from_scip_sepasol || where == from_scip_enfolp) { /** add cut */ SCIP_Bool infeasible; SCIP_CALL(SCIPaddCut(scip, sol, row, FALSE, /**< force cut */ &infeasible)); if (infeasible) *result = SCIP_CUTOFF; else //if (*result != SCIP_CUTOFF) *result = SCIP_SEPARATED; } else *result = SCIP_INFEASIBLE; } /** add cut to global pool */ SCIP_CALL(SCIPaddPoolCut(scip, row)); DSPdebugMessage("number of cuts in global cut pool: %d\n", SCIPgetNPoolCuts(scip)); /** release the row */ SCIP_CALL(SCIPreleaseRow(scip, &row)); } else if (isEfficacious && where != from_scip_sepalp && where != from_scip_sepasol && where != from_scip_enfolp) *result = SCIP_INFEASIBLE; #else if (where == from_scip_sepalp || where == from_scip_sepasol || where == from_scip_enfolp) { /** create empty row */ SCIP_ROW * row = NULL; SCIP_CALL(SCIPcreateEmptyRowCons(scip, &row, conshdlr, "benders", rc->lb(), SCIPinfinity(scip), FALSE, /**< is row local? */ FALSE, /**< is row modifiable? */ FALSE /**< is row removable? can this be TRUE? */)); /** cache the row extension and only flush them if the cut gets added */ SCIP_CALL(SCIPcacheRowExtensions(scip, row)); /** collect all non-zero coefficients */ for (int j = 0; j < cutrow.getNumElements(); ++j) SCIP_CALL(SCIPaddVarToRow(scip, row, vars_[cutrow.getIndices()[j]], cutrow.getElements()[j])); DSPdebugMessage("found Benders (%s) cut: act=%f, lhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n", isOptimalityCut ? "opti" : "feas", SCIPgetRowLPActivity(scip, row), SCIProwGetLhs(row), SCIProwGetNorm(row), SCIPgetCutEfficacy(scip, NULL, row), SCIPgetRowMinCoef(scip, row), SCIPgetRowMaxCoef(scip, row), SCIPgetRowMaxCoef(scip, row)/SCIPgetRowMinCoef(scip, row)); /** flush all changes before adding cut */ SCIP_CALL(SCIPflushRowExtensions(scip, row)); /** is cut efficacious? */ if (isOptimalityCut) { efficacy = SCIPgetCutEfficacy(scip, sol, row); isEfficacious = SCIPisCutEfficacious(scip, sol, row); } else { efficacy = rc->violated(vals); isEfficacious = efficacy > 1.e-6; } if (isEfficacious) { /** add cut */ SCIP_Bool infeasible; SCIP_CALL(SCIPaddCut(scip, sol, row, FALSE, /**< force cut */ &infeasible)); if (infeasible) *result = SCIP_CUTOFF; else if (*result != SCIP_CUTOFF) *result = SCIP_SEPARATED; } /** add cut to global pool */ SCIP_CALL(SCIPaddPoolCut(scip, row)); /** release the row */ SCIP_CALL(SCIPreleaseRow(scip, &row)); } else { if (isOptimalityCut) { efficacy = rc->violated(vals) / cutrow.twoNorm(); isEfficacious = efficacy > 0.05; } else { efficacy = rc->violated(vals); isEfficacious = efficacy > 1.e-6; } DSPdebugMessage("%s efficacy %e\n", isOptimalityCut ? "Opti" : "Feas", efficacy); if (isEfficacious == TRUE) *result = SCIP_INFEASIBLE; } #endif } /** free memory */ SCIPfreeMemoryArray(scip, &vals); return SCIP_OKAY; }
void CglLandPUnitTest( OsiSolverInterface * si, const std::string &mpsDir) { CoinRelFltEq eq(1e-05); // Test default constructor { CglLandP aGenerator; assert(aGenerator.parameter().pivotLimit==20); assert(aGenerator.parameter().maxCutPerRound==5000); assert(aGenerator.parameter().failedPivotLimit==1); assert(aGenerator.parameter().degeneratePivotLimit==0); assert(eq(aGenerator.parameter().pivotTol, 1e-04)); assert(eq(aGenerator.parameter().away, 5e-04)); assert(eq(aGenerator.parameter().timeLimit, COIN_DBL_MAX)); assert(eq(aGenerator.parameter().singleCutTimeLimit, COIN_DBL_MAX)); assert(aGenerator.parameter().useTableauRow==true); assert(aGenerator.parameter().modularize==false); assert(aGenerator.parameter().strengthen==true); assert(aGenerator.parameter().perturb==true); assert(aGenerator.parameter().pivotSelection==CglLandP::mostNegativeRc); } // Test copy constructor { CglLandP a; { CglLandP b; b.parameter().pivotLimit = 100; b.parameter().maxCutPerRound = 100; b.parameter().failedPivotLimit = 10; b.parameter().degeneratePivotLimit = 10; b.parameter().pivotTol = 1e-07; b.parameter().away = 1e-10; b.parameter().timeLimit = 120; b.parameter().singleCutTimeLimit = 15; b.parameter().useTableauRow = true; b.parameter().modularize = true; b.parameter().strengthen = false; b.parameter().perturb = false; b.parameter().pivotSelection=CglLandP::bestPivot; //Test Copy CglLandP c(b); assert(c.parameter().pivotLimit == 100); assert(c.parameter().maxCutPerRound == 100); assert(c.parameter().failedPivotLimit == 10); assert(c.parameter().degeneratePivotLimit == 10); assert(c.parameter().pivotTol == 1e-07); assert(c.parameter().away == 1e-10); assert(c.parameter().timeLimit == 120); assert(c.parameter().singleCutTimeLimit == 15); assert(c.parameter().useTableauRow == true); assert(c.parameter().modularize == true); assert(c.parameter().strengthen == false); assert(c.parameter().perturb == false); assert(c.parameter().pivotSelection == CglLandP::bestPivot); a=b; assert(a.parameter().pivotLimit == 100); assert(a.parameter().maxCutPerRound == 100); assert(a.parameter().failedPivotLimit == 10); assert(a.parameter().degeneratePivotLimit == 10); assert(a.parameter().pivotTol == 1e-07); assert(a.parameter().away == 1e-10); assert(a.parameter().timeLimit == 120); assert(a.parameter().singleCutTimeLimit == 15); assert(a.parameter().useTableauRow == true); assert(a.parameter().modularize == true); assert(a.parameter().strengthen == false); assert(a.parameter().perturb == false); assert(a.parameter().pivotSelection == CglLandP::bestPivot); } } { // Maximize 2 x2 // s.t. // 2x1 + 2x2 <= 3 // -2x1 + 2x2 <= 1 // 7x1 + 4x2 <= 8 // -7x1 + 4x2 <= 1 // x1, x2 >= 0 and x1, x2 integer // Slacks are s1, s2, s3, s4 //Test that problem is correct // Optimal Basis is x1, x2, s3, s4 with tableau // x1 0.25 s1 -0.25 s2 = 0.5 // x2 0.25 s1 0.25 s2 = 1 // -2.75 s1 0.75 s2 s3 = 0.5 // 0.75 s1 -2.75 s2 s4 = 0.5 // z= -0.25 s1 -0.25 s2 = -1 // Gomory cut from variable x1 is x2 <= 0.5 // Can be improved by first pivoting s2 in and s4 out, then s1 in and s3 out // to x2 <= 0.25 { int start[2] = {0,4}; int length[2] = {4,4}; int rows[8] = {0,1,2,3,0,1,2,3}; double elements[8] = {2.0,-2.0,7.0,-7.0,2.0,2.0,4.0,4.0}; CoinPackedMatrix columnCopy(true,4,2,8,elements,rows,start,length); double rowLower[4]={-COIN_DBL_MAX,-COIN_DBL_MAX, -COIN_DBL_MAX,-COIN_DBL_MAX}; double rowUpper[4]={3.,1.,8.,1.}; double colLower[2]={0.0,0.0}; double colUpper[2]={1.0,1.0}; double obj[2]={-1,-1}; int intVar[2]={0,1}; OsiSolverInterface * siP = si->clone(); siP->loadProblem(columnCopy, colLower, colUpper, obj, rowLower, rowUpper); siP->setInteger(intVar,2); CglLandP test; test.setLogLevel(2); test.parameter().sepSpace = CglLandP::Full; siP->resolve(); // Test generateCuts method { OsiCuts cuts; test.generateCuts(*siP,cuts); cuts.printCuts(); assert(cuts.sizeRowCuts()==1); OsiRowCut aCut = cuts.rowCut(0); assert(eq(aCut.lb(), -.0714286)); CoinPackedVector row = aCut.row(); if (row.getNumElements() == 1) { assert(row.getIndices()[0]==1); assert(eq(row.getElements()[0], -4*.0714286)); } else if (row.getNumElements() == 2) { assert(row.getIndices()[0]==0); assert(eq(row.getElements()[0], 0.)); assert(row.getIndices()[1]==1); assert(eq(row.getElements()[1], -1)); } OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); } if (0) { OsiCuts cuts; test.generateCuts(*siP,cuts); cuts.printCuts(); assert(cuts.sizeRowCuts()==1); OsiRowCut aCut = cuts.rowCut(0); CoinPackedVector row = aCut.row(); if (row.getNumElements() == 1) { assert(row.getIndices()[0]==1); assert(eq(row.getElements()[0], -1)); } else if (row.getNumElements() == 2) { assert(row.getIndices()[0]==0); assert(eq(row.getElements()[0], 0.)); assert(row.getIndices()[1]==1); assert(eq(row.getElements()[1], -1)); } assert(eq(aCut.lb(), 0.)); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); } delete siP; } } if (1) //Test on p0033 { // Setup OsiSolverInterface * siP = si->clone(); std::string fn(mpsDir+"p0033"); siP->readMps(fn.c_str(),"mps"); siP->activateRowCutDebugger("p0033"); CglLandP test; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, 2520.5717391304347) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif OsiCuts cuts; // Test generateCuts method test.generateCuts(*siP,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); //assert( eq(lpRelaxAfter, 2592.1908295194507) ); std::cout<<"Relaxation after "<<lpRelaxAfter<<std::endl; assert( lpRelaxAfter> 2840. ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore < lpRelaxAfter ); delete siP; } if (1) //test again with modularization { // Setup OsiSolverInterface * siP = si->clone(); std::string fn(mpsDir+"p0033"); siP->readMps(fn.c_str(),"mps"); siP->activateRowCutDebugger("p0033"); CglLandP test; test.parameter().modularize = true; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, 2520.5717391304347) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif OsiCuts cuts; // Test generateCuts method test.generateCuts(*siP,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); //assert( eq(lpRelaxAfter, 2592.1908295194507) ); std::cout<<"Relaxation after "<<lpRelaxAfter<<std::endl; assert( lpRelaxAfter> 2840. ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore < lpRelaxAfter ); delete siP; } if (1) //test again with alternate pivoting rule { // Setup OsiSolverInterface * siP = si->clone(); std::string fn(mpsDir+"p0033"); siP->readMps(fn.c_str(),"mps"); siP->activateRowCutDebugger("p0033"); CglLandP test; test.parameter().pivotSelection = CglLandP::bestPivot; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, 2520.5717391304347) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif OsiCuts cuts; // Test generateCuts method test.generateCuts(*siP,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); //assert( eq(lpRelaxAfter, 2592.1908295194507) ); std::cout<<"Relaxation after "<<lpRelaxAfter<<std::endl; assert( lpRelaxAfter> 2840. ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore < lpRelaxAfter ); delete siP; } if (1) //Finally test code in documentation { // Setup OsiSolverInterface * siP = si->clone(); std::string fn(mpsDir+"p0033"); siP->readMps(fn.c_str(),"mps"); siP->activateRowCutDebugger("p0033"); CglLandP landpGen; landpGen.parameter().timeLimit = 10.; landpGen.parameter().pivotLimit = 2; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, 2520.5717391304347) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif OsiCuts cuts; // Test generateCuts method landpGen.generateCuts(*siP, cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); //assert( eq(lpRelaxAfter, 2592.1908295194507) ); std::cout<<"Relaxation after "<<lpRelaxAfter<<std::endl; assert( lpRelaxAfter> 2840. ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore < lpRelaxAfter ); delete siP; } }
//-------------------------------------------------------------------------- void CglKnapsackCoverUnitTest( const OsiSolverInterface * baseSiP, const std::string mpsDir ) { int i; CoinRelFltEq eq(0.000001); // Test default constructor { CglKnapsackCover kccGenerator; } // Test copy & assignment { CglKnapsackCover rhs; { CglKnapsackCover kccGenerator; CglKnapsackCover cgC(kccGenerator); rhs=kccGenerator; } } // test exactSolveKnapsack { CglKnapsackCover kccg; const int n=7; double c=50; double p[n] = {70,20,39,37,7,5,10}; double w[n] = {31, 10, 20, 19, 4, 3, 6}; double z; int x[n]; int exactsol = kccg.exactSolveKnapsack(n, c, p, w, z, x); assert(exactsol==1); assert (z == 107); assert (x[0]==1); assert (x[1]==0); assert (x[2]==0); assert (x[3]==1); assert (x[4]==0); assert (x[5]==0); assert (x[6]==0); } /* // Testcase /u/rlh/osl2/mps/scOneInt.mps // Model has 3 continous, 2 binary, and 1 general // integer variable. { OsiSolverInterface * siP = baseSiP->clone(); int * complement=NULL; double * xstar=NULL; siP->readMps("../Mps/scOneInt","mps"); CglKnapsackCover kccg; int nCols=siP->getNumCols(); // Test the siP methods for detecting // variable type int numCont=0, numBinary=0, numIntNonBinary=0, numInt=0; for (int thisCol=0; thisCol<nCols; thisCol++) { if ( siP->isContinuous(thisCol) ) numCont++; if ( siP->isBinary(thisCol) ) numBinary++; if ( siP->isIntegerNonBinary(thisCol) ) numIntNonBinary++; if ( siP->isInteger(thisCol) ) numInt++; } assert(numCont==3); assert(numBinary==2); assert(numIntNonBinary==1); assert(numInt==3); // Test initializeCutGenerator siP->initialSolve(); assert(xstar !=NULL); for (i=0; i<nCols; i++){ assert(complement[i]==0); } int nRows=siP->getNumRows(); for (i=0; i<nRows; i++){ int vectorsize = siP->getMatrixByRow()->vectorSize(i); assert(vectorsize==2); } kccg.cleanUpCutGenerator(complement,xstar); delete siP; } */ // Testcase /u/rlh/osl2/mps/tp3.mps // Models has 3 cols, 3 rows // Row 0 yields a knapsack, others do not. { // setup OsiSolverInterface * siP = baseSiP->clone(); std::string fn(mpsDir+"tp3"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); OsiCuts cs; CoinPackedVector krow; double b=0; int nCols=siP->getNumCols(); int * complement=new int [nCols]; double * xstar=new double [nCols]; CglKnapsackCover kccg; // solve LP relaxation // a "must" before calling initialization siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); std::cout<<"Initial LP value: "<<lpRelaxBefore<<std::endl; assert( eq(siP->getObjValue(), 97.185) ); double mycs[] = {.627, .667558333333, .038}; siP->setColSolution(mycs); const double *colsol = siP->getColSolution(); int k; for (k=0; k<nCols; k++){ xstar[k]=colsol[k]; complement[k]=0; } // test deriveAKnapsack int rind = ( siP->getRowSense()[0] == 'N' ) ? 1 : 0; const CoinShallowPackedVector reqdBySunCC = siP->getMatrixByRow()->getVector(rind) ; int deriveaknap = kccg.deriveAKnapsack(*siP, cs, krow,b,complement,xstar,rind,reqdBySunCC); assert(deriveaknap ==1); assert(complement[0]==0); assert(complement[1]==1); assert(complement[2]==1); int inx[3] = {0,1,2}; double el[3] = {161, 120, 68}; CoinPackedVector r; r.setVector(3,inx,el); assert (krow == r); //assert (b == 183.0); ????? but x1 and x2 at 1 is valid // test findGreedyCover CoinPackedVector cover,remainder; #if 0 int findgreedy = kccg.findGreedyCover( 0, krow, b, xstar, cover, remainder ); assert( findgreedy == 1 ); int coveri = cover.getNumElements(); assert( cover.getNumElements() == 2); coveri = cover.getIndices()[0]; assert( cover.getIndices()[0] == 0); assert( cover.getIndices()[1] == 1); assert( cover.getElements()[0] == 161.0); assert( cover.getElements()[1] == 120.0); assert( remainder.getNumElements() == 1); assert( remainder.getIndices()[0] == 2); assert( remainder.getElements()[0] == 68.0); // test liftCoverCut CoinPackedVector cut; double * rowupper = ekk_rowupper(model); double cutRhs = cover.getNumElements() - 1.0; kccg.liftCoverCut(b, krow.getNumElements(), cover, remainder, cut); assert ( cut.getNumElements() == 3 ); assert ( cut.getIndices()[0] == 0 ); assert ( cut.getIndices()[1] == 1 ); assert ( cut.getIndices()[2] == 2 ); assert( cut.getElements()[0] == 1 ); assert( cut.getElements()[1] == 1 ); assert( eq(cut.getElements()[2], 0.087719) ); // test liftAndUncomplementAndAdd OsiCuts cuts; kccg.liftAndUncomplementAndAdd(*siP.getRowUpper()[0],krow,b,complement,0, cover,remainder,cuts); int sizerowcuts = cuts.sizeRowCuts(); assert ( sizerowcuts== 1 ); OsiRowCut testRowCut = cuts.rowCut(0); CoinPackedVector testRowPV = testRowCut.row(); OsiRowCut sampleRowCut; const int sampleSize = 3; int sampleCols[sampleSize]={0,1,2}; double sampleElems[sampleSize]={1.0,-1.0,-0.087719}; sampleRowCut.setRow(sampleSize,sampleCols,sampleElems); sampleRowCut.setLb(-DBL_MAX); sampleRowCut.setUb(-0.087719); bool equiv = testRowPV.equivalent(sampleRowCut.row(),CoinRelFltEq(1.0e-05) ); assert ( equiv ); #endif // test find PseudoJohnAndEllisCover cover.setVector(0,NULL, NULL); remainder.setVector(0,NULL,NULL); rind = ( siP->getRowSense()[0] == 'N' ) ? 1 : 0; int findPJE = kccg.findPseudoJohnAndEllisCover( rind, krow, b, xstar, cover, remainder ); assert( findPJE == 1 ); assert ( cover.getIndices()[0] == 0 ); assert ( cover.getIndices()[1] == 2 ); assert ( cover.getElements()[0] == 161 ); assert ( cover.getElements()[1] == 68 ); assert ( remainder.getIndices()[0] == 1 ); assert ( remainder.getElements()[0] == 120 ); OsiCuts cuts; kccg.liftAndUncomplementAndAdd((*siP).getRowUpper()[rind],krow,b, complement, rind, cover,remainder,cuts); assert (cuts.sizeRowCuts() == 1 ); OsiRowCut testRowCut = cuts.rowCut(0); CoinPackedVector testRowPV = testRowCut.row(); const int sampleSize = 3; int sampleCols[sampleSize]={0,1,2}; double sampleElems[sampleSize]={1.0, -1.0, -1.0}; OsiRowCut sampleRowCut; sampleRowCut.setRow(sampleSize,sampleCols,sampleElems); sampleRowCut.setLb(-COIN_DBL_MAX); sampleRowCut.setUb(-1.0); // test for 'close enough' assert( testRowPV.isEquivalent(sampleRowCut.row(),CoinRelFltEq(1.0e-05) ) ); // Reset complement & test next row for (i=0; i<nCols; i++){ complement[i]=0; } rind++; const CoinShallowPackedVector reqdBySunCC2 = siP->getMatrixByRow()->getVector(rind) ; deriveaknap = kccg.deriveAKnapsack(*siP,cuts,krow,b,complement,xstar,rind,reqdBySunCC2); assert(deriveaknap==0); // Reset complement & test next row for (i=0; i<nCols; i++){ complement[i]=0; } const CoinShallowPackedVector reqdBySunCC3 = siP->getMatrixByRow()->getVector(2) ; deriveaknap = kccg.deriveAKnapsack(*siP,cuts,krow,b,complement,xstar,2, reqdBySunCC3); assert(deriveaknap == 0); // Clean up delete [] complement; delete [] xstar; delete siP; } #if 0 // Testcase /u/rlh/osl2/mps/tp4.mps // Models has 6 cols, 1 knapsack row and // 3 rows explicily bounding variables // Row 0 yields a knapsack cover cut // using findGreedyCover which moves the // LP objective function value. { // Setup EKKContext * env=ekk_initializeContext(); EKKModel * model = ekk_newModel(env,""); OsiSolverInterface si(model); ekk_importModel(model, "tp4.mps"); CglKnapsackCover kccg; kccg.ekk_validateIntType(si); // Solve the LP relaxation of the model and // print out ofv for sake of comparison ekk_allSlackBasis(model); ekk_crash(model,1); ekk_primalSimplex(model,1); double lpRelaxBefore=ekk_getRobjvalue(model); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif // Determine if lp sol is ip optimal // Note: no ekk_function to do this int nCols=ekk_getInumcols(model); double * optLpSol = ekk_colsol(model); int ipOpt = 1; i=0; while (i++<nCols && ipOpt){ if(optLpSol[i] < 1.0-1.0e-08 && optLpSol[i]> 1.0e-08) ipOpt = 0; } if (ipOpt){ #ifdef CGL_DEBUG printf("Lp solution is within ip optimality tolerance\n"); #endif } else { OsiSolverInterface iModel(model); OsiCuts cuts; // Test generateCuts method kccg.generateCuts(iModel,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = iModel.applyCuts(cuts); ekk_mergeBlocks(model,1); ekk_dualSimplex(model); double lpRelaxAfter=ekk_getRobjvalue(model); #ifdef CGL_DEBUG printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore < lpRelaxAfter ); // This may need to be updated as other // minimal cover finders are added assert( cuts.sizeRowCuts() == 1 ); OsiRowCut testRowCut = cuts.rowCut(0); CoinPackedVector testRowPV = testRowCut.row(); OsiRowCut sampleRowCut; const int sampleSize = 6; int sampleCols[sampleSize]={0,1,2,3,4,5}; double sampleElems[sampleSize]={1.0,1.0,1.0,1.0,0.5, 2.0}; sampleRowCut.setRow(sampleSize,sampleCols,sampleElems); sampleRowCut.setLb(-DBL_MAX); sampleRowCut.setUb(3.0); bool equiv = testRowPV.equivalent(sampleRowCut.row(),CoinRelFltEq(1.0e-05) ); assert( testRowPV.equivalent(sampleRowCut.row(),CoinRelFltEq(1.0e-05) ) ); } // Exit out of OSL ekk_deleteModel(model); ekk_endContext(env); } #endif // Testcase /u/rlh/osl2/mps/tp5.mps // Models has 6 cols, 1 knapsack row and // 3 rows explicily bounding variables // Row 0 yields a knapsack cover cut // using findGreedyCover which moves the // LP objective function value. { // Setup OsiSolverInterface * siP = baseSiP->clone(); std::string fn(mpsDir+"tp5"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); CglKnapsackCover kccg; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, -51.66666666667) ); double mycs[] = {.8999999999, .899999999999, .89999999999, 1.110223e-16, .5166666666667, 0}; siP->setColSolution(mycs); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif // Determine if lp sol is 0/1 optimal int nCols=siP->getNumCols(); const double * optLpSol = siP->getColSolution(); bool ipOpt = true; i=0; while (i++<nCols && ipOpt){ if(optLpSol[i] > kccg.epsilon_ && optLpSol[i] < kccg.onetol_) ipOpt = false; } if (ipOpt){ #ifdef CGL_DEBUG printf("Lp solution is within ip optimality tolerance\n"); #endif } else { // set up OsiCuts cuts; CoinPackedVector krow; double b=0.0; int * complement=new int[nCols]; double * xstar=new double[nCols]; // initialize cut generator const double *colsol = siP->getColSolution(); for (i=0; i<nCols; i++){ xstar[i]=colsol[i]; complement[i]=0; } int row = ( siP->getRowSense()[0] == 'N' ) ? 1 : 0; // transform row into canonical knapsack form const CoinShallowPackedVector reqdBySunCC = siP->getMatrixByRow()->getVector(row) ; if (kccg.deriveAKnapsack(*siP, cuts, krow, b, complement, xstar, row,reqdBySunCC)){ CoinPackedVector cover, remainder; // apply greedy logic to detect violated minimal cover inequalities if (kccg.findGreedyCover(row, krow, b, xstar, cover, remainder) == 1){ // lift, uncomplements, and add cut to cut set kccg.liftAndUncomplementAndAdd((*siP).getRowUpper()[row],krow, b, complement, row, cover, remainder, cuts); } // reset optimal column solution (xstar) information in OSL const double * rowupper = siP->getRowUpper(); int k; if (fabs(b-rowupper[row]) > 1.0e-05) { for(k=0; k<krow.getNumElements(); k++) { if (complement[krow.getIndices()[k]]){ xstar[krow.getIndices()[k]]= 1.0-xstar[krow.getIndices()[k]]; complement[krow.getIndices()[k]]=0; } } } // clean up delete [] complement; delete [] xstar; } // apply the cuts OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); assert( eq(lpRelaxAfter, -30.0) ); #ifdef CGL_DEBUG printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif // test that expected cut was detected assert( lpRelaxBefore < lpRelaxAfter ); assert( cuts.sizeRowCuts() == 1 ); OsiRowCut testRowCut = cuts.rowCut(0); CoinPackedVector testRowPV = testRowCut.row(); OsiRowCut sampleRowCut; const int sampleSize = 6; int sampleCols[sampleSize]={0,1,2,3,4,5}; double sampleElems[sampleSize]={1.0,1.0,1.0,0.25,1.0,2.0}; sampleRowCut.setRow(sampleSize,sampleCols,sampleElems); sampleRowCut.setLb(-COIN_DBL_MAX); sampleRowCut.setUb(3.0); assert(testRowPV.isEquivalent(sampleRowCut.row(),CoinRelFltEq(1.0e-05))); } delete siP; } // Testcase /u/rlh/osl2/mps/p0033 // Miplib3 problem p0033 // Test that no cuts chop off the optimal solution { // Setup OsiSolverInterface * siP = baseSiP->clone(); std::string fn(mpsDir+"p0033"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); int nCols=siP->getNumCols(); CglKnapsackCover kccg; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, 2520.5717391304347) ); double mycs[] = {0, 1, 0, 0, -2.0837010502455788e-19, 1, 0, 0, 1, 0.021739130434782594, 0.35652173913043478, -6.7220534694101275e-18, 5.3125906451789717e-18, 1, 0, 1.9298798670241979e-17, 0, 0, 0, 7.8875708048320448e-18, 0.5, 0, 0.85999999999999999, 1, 1, 0.57999999999999996, 1, 0, 1, 0, 0.25, 0, 0.67500000000000004}; siP->setColSolution(mycs); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif OsiCuts cuts; // Test generateCuts method kccg.generateCuts(*siP,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); assert( eq(lpRelaxAfter, 2829.0597826086955) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore < lpRelaxAfter ); // the CoinPackedVector p0033 is the optimal // IP solution to the miplib problem p0033 int objIndices[14] = { 0, 6, 7, 9, 13, 17, 18, 22, 24, 25, 26, 27, 28, 29 }; CoinPackedVector p0033(14,objIndices,1.0); // Sanity check const double * objective=siP->getObjCoefficients(); double ofv =0 ; int r; for (r=0; r<nCols; r++){ ofv=ofv + p0033[r]*objective[r]; } CoinRelFltEq eq; assert( eq(ofv,3089.0) ); int nRowCuts = cuts.sizeRowCuts(); OsiRowCut rcut; CoinPackedVector rpv; for (i=0; i<nRowCuts; i++){ rcut = cuts.rowCut(i); rpv = rcut.row(); double p0033Sum = (rpv*p0033).sum(); assert (p0033Sum <= rcut.ub() ); } delete siP; } // if a debug file is there then look at it { FILE * fp = fopen("knapsack.debug","r"); if (fp) { int ncol,nel; double up; int x = fscanf(fp,"%d %d %lg",&ncol,&nel,&up); if (x<=0) throw("bad fscanf"); printf("%d columns, %d elements, upper %g\n",ncol,nel,up); double * sol1 = new double[nel]; double * el1 = new double[nel]; int * col1 = new int[nel]; CoinBigIndex * start = new CoinBigIndex [ncol+1]; memset(start,0,ncol*sizeof(CoinBigIndex )); int * row = new int[nel]; int i; for (i=0;i<nel;i++) { x=fscanf(fp,"%d %lg %lg",col1+i,el1+i,sol1+i); if (x<=0) throw("bad fscanf"); printf("[%d, e=%g, v=%g] ",col1[i],el1[i],sol1[i]); start[col1[i]]=1; row[i]=0; } printf("\n"); // Setup OsiSolverInterface * siP = baseSiP->clone(); double lo=-1.0e30; double * upper = new double[ncol]; start[ncol]=nel; int last=0; for (i=0;i<ncol;i++) { upper[i]=1.0; int marked=start[i]; start[i]=last; if (marked) last++; } siP->loadProblem(ncol,1,start,row,el1,NULL,upper,NULL,&lo,&up); // use upper for solution memset(upper,0,ncol*sizeof(double)); for (i=0;i<nel;i++) { int icol=col1[i]; upper[icol]=sol1[i]; siP->setInteger(icol); } siP->setColSolution(upper); delete [] sol1; delete [] el1; delete [] col1; delete [] start; delete [] row; delete [] upper; CglKnapsackCover kccg; OsiCuts cuts; // Test generateCuts method kccg.generateCuts(*siP,cuts); // print out and compare to known cuts int numberCuts = cuts.sizeRowCuts(); if (numberCuts) { for (i=0;i<numberCuts;i++) { OsiRowCut * thisCut = cuts.rowCutPtr(i); int n=thisCut->row().getNumElements(); printf("Cut %d has %d entries, rhs %g %g =>",i,n,thisCut->lb(), thisCut->ub()); int j; const int * index = thisCut->row().getIndices(); const double * element = thisCut->row().getElements(); for (j=0;j<n;j++) { printf(" (%d,%g)",index[j],element[j]); } printf("\n"); } } fclose(fp); } } // Testcase /u/rlh/osl2/mps/p0201 // Miplib3 problem p0282 // Test that no cuts chop off the optimal ip solution { // Setup OsiSolverInterface * siP = baseSiP->clone(); std::string fn(mpsDir+"p0201"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); const int nCols=siP->getNumCols(); CglKnapsackCover kccg; // Solve the LP relaxation of the model and // print out ofv for sake of comparisn siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, 6875.) ); double mycs[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; siP->setColSolution(mycs); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif OsiCuts cuts; // Test generateCuts method kccg.generateCuts(*siP,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); assert( eq(lpRelaxAfter, 7125) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore < lpRelaxAfter ); // Optimal IP solution to p0201 int objIndices[22] = { 8, 10, 21, 38, 39, 56, 60, 74, 79, 92, 94, 110, 111, 128, 132, 146, 151,164, 166, 182,183, 200 }; CoinPackedVector p0201(22,objIndices,1.0); // Sanity check const double * objective=siP->getObjCoefficients(); double ofv =0 ; int r; for (r=0; r<nCols; r++){ ofv=ofv + p0201[r]*objective[r]; } CoinRelFltEq eq; assert( eq(ofv,7615.0) ); //printf("p0201 optimal ofv = %g\n",ofv); int nRowCuts = cuts.sizeRowCuts(); OsiRowCut rcut; CoinPackedVector rpv; for (i=0; i<nRowCuts; i++){ rcut = cuts.rowCut(i); rpv = rcut.row(); double p0201Sum = (rpv*p0201).sum(); assert (p0201Sum <= rcut.ub() ); } delete siP; } // see if I get the same covers that N&W get { OsiSolverInterface * siP=baseSiP->clone(); std::string fn(mpsDir+"nw460"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); CglKnapsackCover kccg; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, -225.68951787852194) ); double mycs[] = {0.7099213482046447, 0, 0.34185802225477174, 1, 1, 0, 1, 1, 0}; siP->setColSolution(mycs); OsiCuts cuts; // Test generateCuts method kccg.generateCuts(*siP,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); assert( eq(lpRelaxAfter, -176) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif #ifdef MJS assert( lpRelaxBefore < lpRelaxAfter ); #endif int nRowCuts = cuts.sizeRowCuts(); OsiRowCut rcut; CoinPackedVector rpv; for (i=0; i<nRowCuts; i++){ rcut = cuts.rowCut(i); rpv = rcut.row(); int j; printf("Row cut number %i has rhs = %g\n",i,rcut.ub()); for (j=0; j<rpv.getNumElements(); j++){ printf("index %i, element %g\n", rpv.getIndices()[j], rpv.getElements()[j]); } printf("\n"); } delete siP; } // Debugging: try "exmip1.mps" { // Setup OsiSolverInterface * siP = baseSiP->clone(); std::string fn(mpsDir+"exmip1"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); CglKnapsackCover kccg; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, 3.2368421052631575) ); double mycs[] = {2.5, 0, 0, 0.6428571428571429, 0.5, 4, 0, 0.26315789473684253}; siP->setColSolution(mycs); // Test generateCuts method OsiCuts cuts; kccg.generateCuts(*siP,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); assert( eq(lpRelaxAfter, 3.2368421052631575) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore <= lpRelaxAfter ); delete siP; } #ifdef CGL_DEBUG // See what findLPMostViolatedMinCover for knapsack with 2 elements does { int nCols = 2; int row = 1; CoinPackedVector krow; double e[2] = {5,10}; int ii[2] = {0,1}; krow.setVector(nCols,ii,e); double b=11; double xstar[2] = {.2,.9}; CoinPackedVector cover; CoinPackedVector remainder; CglKnapsackCover kccg; kccg.findLPMostViolatedMinCover(nCols, row, krow, b, xstar, cover, remainder); printf("num in cover = %i\n",cover.getNumElements()); int j; for (j=0; j<cover.getNumElements(); j++){ printf(" index %i element % g\n", cover.getIndices()[j], cover.getElements()[j]); } } #endif #ifdef CGL_DEBUG // see what findLPMostViolatedMinCover does { int nCols = 5; int row = 1; CoinPackedVector krow; double e[5] = {1,1,1,1,10}; int ii[5] = {0,1,2,3,4}; krow.setVector(nCols,ii,e); double b=11; double xstar[5] = {.9,.9,1,1,.1}; CoinPackedVector cover; CoinPackedVector remainder; CglKnapsackCover kccg; kccg.findLPMostViolatedMinCover(nCols, row, krow, b, xstar, cover, remainder); printf("num in cover = %i\n",cover.getNumElements()); int j; for (j=0; j<cover.getNumElements(); j++){ printf(" index %i element % g\n", cover.getIndices()[j], cover.getElements()[j]); } } #endif }