/* 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; }
// Add a row cut from elements void CglStored::addCut(double lb, double ub, int size, const int * colIndices, const double * elements) { OsiRowCut rc; rc.setRow(size,colIndices,elements,false); rc.setLb(lb); rc.setUb(ub); cuts_.insert(rc); }
// Add a row cut from a packed vector void CglStored::addCut(double lb, double ub, const CoinPackedVector & vector) { OsiRowCut rc; rc.setRow(vector); rc.mutableRow().setTestForDuplicateIndex(false); rc.setLb(lb); rc.setUb(ub); cuts_.insert(rc); }
//------------------------------------------------------------------- // Constructor from file //------------------------------------------------------------------- CglStored::CglStored (const char * fileName) : CglCutGenerator(), requiredViolation_(1.0e-5), probingInfo_(NULL), numberColumns_(0), bestSolution_(NULL), bounds_(NULL) { FILE * fp = fopen(fileName,"rb"); if (fp) { #ifndef NDEBUG size_t numberRead; #endif int maxInCut=0; int * index = NULL; double * coefficient = NULL; double rhs[2]; int n=0; while (n>=0) { #ifndef NDEBUG numberRead = fread(&n,sizeof(int),1,fp); assert (numberRead==1); #else fread(&n,sizeof(int),1,fp); #endif if (n<0) break; if (n>maxInCut) { maxInCut=n; delete [] index; delete [] coefficient; index = new int [maxInCut]; coefficient = new double [maxInCut]; } #ifndef NDEBUG numberRead = fread(rhs,sizeof(double),2,fp); assert (numberRead==2); #else fread(rhs,sizeof(double),2,fp); #endif fread(index,sizeof(int),n,fp); fread(coefficient,sizeof(double),n,fp); OsiRowCut rc; rc.setRow(n,index,coefficient,false); rc.setLb(rhs[0]); rc.setUb(rhs[1]); cuts_.insert(rc); } delete [] index; delete [] coefficient; fclose(fp); } }
void CglClique::recordClique(const int len, int* indices, OsiCuts& cs) { /* transform relative indices into user indices and order them */ for (int j = len - 1; j >= 0; j--) indices[j] = sp_orig_col_ind[indices[j]]; std::sort(indices, indices + len); OsiRowCut rowcut; double* coef = new double[len]; std::fill(coef, coef + len, 1.0); rowcut.setRow(len, indices, coef); rowcut.setUb(1.0); CoinAbsFltEq equal(1.0e-12); cs.insertIfNotDuplicate(rowcut,equal); delete[] coef; }
QuadRow::QuadRow(const OsiRowCut &cut): c_(0), a_(cut.row()), Q_() { initialize(); }
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; }
/** 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); }
OsiRowCut * BlisConstraint::createOsiRowCut() { double lower = CoinMax(getLbHard(), getLbSoft()); double upper = CoinMin(getUbHard(), getUbSoft()); OsiRowCut * cut = new OsiRowCut; if (!cut) { /* Out of memory. */ throw CoinError("Out of Memory", "Blis_constraintToOsiCut", "NONE"); } assert(size_ > 0); cut->setLb(lower); cut->setUb(upper); cut->setRow(size_, indices_, values_); return cut; }
/** 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); }
// approximate the cone around given point. // If given point is in interior do nothing. // if it is on the boundry add support // We do not expect it to be infeasible for now. This may change in future // in case of infeasibility we will just call separate routine. // feas of given solution: // Note that the numerical accuracy of the input sol // depends on the underlying solver that created sol, and // its accuracy level set. // current strategy: // the point we are given is not very close to the boundry // do a computationally cheap projection of the point to te boundry // and generate cuts that support cone. // For now we just increase leadin var and project the point to the boundry. void LorentzCone::approximate(double const * sol, OsiCuts * cuts) { // todo(aykut) improve accuracy of given solution // we do nothing for this for now. // coef array, [2x1, -2x2, -2x3, ... -2xn] double * coef = new double[size_]; double * p = new double[size_]; for (int i=0; i<size_; ++i) { p[i] = sol[members_[i]]; } // 2. compute coefficient from given solution if (type()==LORENTZ) { // cone is in canonical form for (int i=1; i<size_; ++i) { coef[i] = 2.0*p[i]; } coef[0] = -2.0*p[0]; } else if (type()==RLORENTZ) { // map solution from RLORENTZ space to LORENTZ space, find the projection // on LORENTZ, project this point to RLORENTZ and generate cut // cone is a rotated cone // generate cut from xbar coef[0] = -2.0*p[1]; coef[1] = -2.0*p[0]; for (int i=2; i<size_; ++i) { coef[i] = 2.0*p[i]; } } // rhs is allways 0.0 OsiRowCut * cut = new OsiRowCut(); cut->setRow(size_, members_, coef); cuts->insert(*cut); delete[] coef; delete[] p; delete cut; }
CbcBranchingObject * CbcBranchAllDifferent::createCbcBranch(OsiSolverInterface * /*solver*/ , const OsiBranchingInformation * /*info*/, int /*way*/) { // by default way must be -1 //assert (way==-1); const double * solution = model_->testSolution(); double * values = new double[numberInSet_]; int * which = new int[numberInSet_]; int i; for (i = 0; i < numberInSet_; i++) { int iColumn = which_[i]; values[i] = solution[iColumn]; which[i] = iColumn; } CoinSort_2(values, values + numberInSet_, which); double last = -1.0; double closest = 1.0; int worst = -1; for (i = 0; i < numberInSet_; i++) { if (values[i] - last < closest) { closest = values[i] - last; worst = i - 1; } last = values[i]; } assert (closest <= 0.99999); OsiRowCut down; down.setLb(-COIN_DBL_MAX); down.setUb(-1.0); int pair[2]; double elements[] = {1.0, -1.0}; pair[0] = which[worst]; pair[1] = which[worst+1]; delete [] values; delete [] which; down.setRow(2, pair, elements); // up is same - just with rhs changed OsiRowCut up = down; up.setLb(1.0); up.setUb(COIN_DBL_MAX); // Say is not a fix type branch CbcCutBranchingObject * newObject = new CbcCutBranchingObject(model_, down, up, false); if (model_->messageHandler()->logLevel() > 1) printf("creating cut in CbcBranchCut\n"); return newObject; }
/* 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); } }
//-------------------------------------------------------------------------- // 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; } }
/** 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; }
//------------------------------------------------------------------- // Given the model data, a row of the model, and a LP solution, // this function tries to generate a violated lifted simple generalized // flow cover. //------------------------------------------------------------------- bool CglFlowCover::generateOneFlowCut( const OsiSolverInterface & si, const int rowLen, int* ind, double* coef, char sense, double rhs, OsiRowCut& flowCut, double& violation ) const { bool generated = false; const double* xlp = si.getColSolution(); const int numCols = si.getNumCols(); double* up = new double [rowLen]; double* x = new double [rowLen]; double* y = new double [rowLen]; CglFlowColType* sign = new CglFlowColType [rowLen]; int i, j; double value, LB, UB; CglFlowVLB VLB; CglFlowVUB VUB; static int count=0; ++count; CGLFLOW_DEBUG=false; doLift=true; // Get integer types const char * columnType = si.getColType (); for (i = 0; i < rowLen; ++i) { if ( xlp[ind[i]] - floor(xlp[ind[i]]) > EPSILON_ && ceil(xlp[ind[i]]) - xlp[ind[i]] > EPSILON_ ) break; } if (i == rowLen) { delete [] sign; delete [] up; delete [] x; delete [] y; return generated; } //------------------------------------------------------------------------- if (sense == 'G') flipRow(rowLen, coef, rhs); // flips everything, // but the sense if(CGLFLOW_DEBUG) { std::cout << "***************************" << std::endl; std::cout << "Generate Flow cover -- initial constraint, converted to L sense..." << std::endl; std::cout << "Rhs = " << rhs << std::endl; std::cout << "coef [var_index]" << " -- " << "xlp[var_index]" << '\t' << "vub_coef[vub_index] vub_lp_value OR var_index_col_ub" << std::endl; for(int iD = 0; iD < rowLen; ++iD) { VUB = getVubs(ind[iD]); std::cout << std::setw(5) << coef[iD] << "[" << std::setw(5) << ind[iD] << "] -- " << std::setw(20) << xlp[ind[iD]] << '\t'; if (VUB.getVar() != UNDEFINED_) { std::cout << std::setw(20) << VUB.getVal() << "[" << std::setw(5) << VUB.getVar() << "]" << std::setw(20) << xlp[VUB.getVar()] << std::endl; } else std::cout << std::setw(20) << si.getColUpper()[ind[iD]] << " " << std::setw(20) << 1.0 << std::endl; } } //------------------------------------------------------------------------- // Generate conservation inequality and capacity equalities from // the given row. for (i = 0; i < rowLen; ++i) { VLB = getVlbs(ind[i]); LB = ( VLB.getVar() != UNDEFINED_ ) ? VLB.getVal() : si.getColLower()[ind[i]]; VUB = getVubs(ind[i]); UB = ( VUB.getVar() != UNDEFINED_ ) ? VUB.getVal() : si.getColUpper()[ind[i]]; if (LB < -EPSILON_) { // Only consider rows whose variables are all delete [] sign; // non-negative (LB>= 0). delete [] up; delete [] x; delete [] y; return generated; } if ( columnType[ind[i]]==1 ) { // Binary variable value = coef[i]; if (value > EPSILON_) sign[i] = CGLFLOW_COL_BINPOS; else { sign[i] = CGLFLOW_COL_BINNEG; value = -value; } up[i] = value; x[i] = xlp[ind[i]]; y[i] = value * x[i]; } else { value = coef[i]; if (value > EPSILON_) sign[i] = CGLFLOW_COL_CONTPOS; else { sign[i] = CGLFLOW_COL_CONTNEG; value = -value; } up[i] = value* UB; x[i] = (VUB.getVar() != UNDEFINED_) ? xlp[VUB.getVar()] : 1.0; y[i] = value * xlp[ind[i]]; } } //------------------------------------------------------------------------- // Find a initial cover (C+, C-) in (N+, N-) double knapRHS = rhs; double tempSum = 0.0; double tempMin = INFTY_; CglFlowColCut * candidate = new CglFlowColCut [rowLen]; CglFlowColCut * label = new CglFlowColCut [rowLen]; double* ratio = new double [rowLen]; int t = -1; for (i = 0; i < rowLen; ++i) { candidate[i] = label[i] = CGLFLOW_COL_OUTCUT; ratio[i] = INFTY_; switch(sign[i]) { case CGLFLOW_COL_CONTPOS: case CGLFLOW_COL_BINPOS: if( y[i] > EPSILON_ ) { ratio[i] = (1.0 - x[i]) / up[i]; if( y[i] > up[i] * x[i] - EPSILON_ ) { // Violated candidate[i] = CGLFLOW_COL_PRIME; tempSum += up[i]; } else { candidate[i] = CGLFLOW_COL_SECONDARY; } } break; case CGLFLOW_COL_CONTNEG: case CGLFLOW_COL_BINNEG: if( up[i] > ( (1.0 - EPSILON_) * INFTY_ ) ) { // UB is infty label[i] = CGLFLOW_COL_INCUT; } else { knapRHS += up[i]; if( y[i] < up[i] ) { candidate[i] = CGLFLOW_COL_PRIME; ratio[i] = x[i] / up[i]; tempSum += up[i]; } } break; } } double diff, tempD, lambda; int xID = -1; if (knapRHS >1.0e10) { if(CGLFLOW_DEBUG) { std::cout << "knapsack RHS too large. RETURN." << std::endl; } delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; return generated; } while (tempSum < knapRHS + EPSILON_) { // Not a cover yet diff = INFTY_; for (i = 0; i < rowLen; ++i) { if (candidate[i] == CGLFLOW_COL_SECONDARY) { tempD = up[i] * x[i] - y[i]; if (tempD < diff - EPSILON_) { diff = tempD; xID = i; } } } if( diff > (1.0 - EPSILON_) * INFTY_ ) { // NO cover exits. delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; return generated; } else { tempSum += up[xID]; candidate[xID] = CGLFLOW_COL_PRIME; } } // Solve the knapsack problem to get an initial cover tempSum = 0.0; for (i = 0; i < rowLen; ++i) { if (candidate[i] == CGLFLOW_COL_PRIME && ratio[i] < EPSILON_) { //Zero ratio label[i] = CGLFLOW_COL_INCUT; tempSum += up[i]; } } while (tempSum < knapRHS + EPSILON_) { tempMin = INFTY_; xID=-1; for (i = 0; i < rowLen; i++) { // Search the col with minimum ratio if (candidate[i] == CGLFLOW_COL_PRIME && label[i] == 0 && ratio[i] < tempMin) { tempMin = ratio[i]; xID = i; } } if (xID>=0) { label[xID] = CGLFLOW_COL_INCUT; tempSum += up[xID]; } else { if(CGLFLOW_DEBUG) { std::cout << "knapsack RHS too large B. RETURN." << std::endl; } delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; return generated; } } // Reduce to a minimal cover for (i = 0; i < rowLen; ++i) { if (label[i] == CGLFLOW_COL_INCUT && ratio[i] > EPSILON_) { if (tempSum - up[i] > knapRHS + EPSILON_) { label[i] = CGLFLOW_COL_OUTCUT; tempSum -= up[i]; } } } for (i = 0; i < rowLen; ++i) { if (label[i] == CGLFLOW_COL_INCUT && ratio[i] < EPSILON_) { if (tempSum - up[i] > knapRHS + EPSILON_) { label[i] = CGLFLOW_COL_OUTCUT; tempSum -= up[i]; } } } // Due to the way to handle N- for(i = 0; i < rowLen; ++i) { if( sign[i] < 0 ) label[i] = label[i]==CGLFLOW_COL_OUTCUT?CGLFLOW_COL_INCUT:CGLFLOW_COL_OUTCUT; } // No cover, no cut. bool emptyCover = true; for (i = 0; i < rowLen; ++i) { if (label[i] == CGLFLOW_COL_INCUT) { emptyCover = false; break; } } if (emptyCover) { if(CGLFLOW_DEBUG) { std::cout << "No cover. RETURN." << std::endl; } delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; return generated; } lambda = tempSum - knapRHS; if(CGLFLOW_DEBUG) { double sum_mj_Cplus = 0.0; double sum_mj_Cminus= 0.0; // double checkLambda; // variable not used anywhere (LL) // print out the knapsack variables std::cout << "Knapsack Cover: C+" << std::endl; for (i = 0; i < rowLen; ++i) { if ( label[i] == CGLFLOW_COL_INCUT && sign[i] > 0 ) { std::cout << ind[i] << '\t' << up[i] << std::endl; sum_mj_Cplus += up[i]; } } std::cout << "Knapsack Cover: C-" << std::endl; for (i = 0; i < rowLen; ++i) { if ( label[i] == CGLFLOW_COL_INCUT && sign[i] < 0 ) { std::cout << ind[i] << '\t' << up[i] << std::endl; sum_mj_Cminus += up[i]; } } // rlh: verified "lambda" is lambda in the paper. // lambda = (sum coefficients in C+) - (sum of VUB // coefficients in C-) - rhs-orig-constraint std::cout << "lambda = " << lambda << std::endl; } //------------------------------------------------------------------------- // Generate a violated SGFC int numCMinus = 0; int numPlusPlus = 0; double* rho = new double [rowLen]; double* xCoef = new double [rowLen]; double* yCoef = new double [rowLen]; double cutRHS = rhs; double temp = 0.0; double sum = 0.0; double minPlsM = INFTY_; double minNegM = INFTY_; for(i = 0; i < rowLen; ++i) { rho[i] = 0.0; xCoef[i] = 0.0; yCoef[i] = 0.0; } // Project out variables in C- // d^' = d + sum_{i in C^-} m_i. Now cutRHS = d^' for (i = 0; i < rowLen; ++i) { if ( label[i] == CGLFLOW_COL_INCUT && sign[i] < 0 ) { cutRHS += up[i]; ++numCMinus; } } // (1) Compute the coefficients of the simple generalized flow cover // (2) Compute minPlsM, minNegM and sum // // sum = sum_{i in C+\C++} m_i + sum_{i in L--} m_i = m. Page 15. // minPlsM = min_{i in C++} m_i // minNegM = min_{i in L-} m_i temp = cutRHS; for (i = 0; i < rowLen; ++i) { if (label[i] == CGLFLOW_COL_INCUT && sign[i] > 0) { // C+ yCoef[i] = 1.0; if ( up[i] > lambda + EPSILON_ ) { // C++ ++numPlusPlus; xCoef[i] = lambda - up[i]; cutRHS += xCoef[i]; if( up[i] < minPlsM ) { minPlsM = up[i]; } } else { // C+\C++ xCoef[i] = 0.0; // rlh: is this necesarry? (xCoef initialized to zero) sum += up[i]; } } if (label[i] != CGLFLOW_COL_INCUT && sign[i] < 0) { // N-\C- temp += up[i]; if ( up[i] > lambda) { // L- if(CGLFLOW_DEBUG) { std::cout << "Variable " << ind[i] << " is in L-" << std::endl; } yCoef[i] = 0.0; xCoef[i] = -lambda; label[i] = CGLFLOW_COL_INLMIN; if ( up[i] < minNegM ) { minNegM = up[i]; } } else { // L-- if(CGLFLOW_DEBUG) { std::cout << "Variable " << ind[i] << " is in L-- " << std::endl; } yCoef[i] = -1.0; xCoef[i] = 0.0; // rlh: is this necesarry? (xCoef initialized to zero) label[i] = CGLFLOW_COL_INLMINMIN; sum += up[i]; } } } // Sort the upper bounds (m_i) of variables in C++ and L-. int ix; int index = 0; double temp1 = 0.0; double* mt = new double [rowLen]; double* M = new double [rowLen + 1]; // order to look at variables int * order = new int [rowLen]; int nLook=0; for (int i = 0; i < rowLen; ++i) { if ( (label[i] == CGLFLOW_COL_INCUT && sign[i] > 0) || label[i] == CGLFLOW_COL_INLMIN ) { // C+ || L- // possible M[nLook]=-up[i]; order[nLook++]=i; } } CoinSort_2(M,M+nLook,order); int kLook=0; while (kLook<nLook) { ix = UNDEFINED_; i = order[kLook]; kLook++; if ( (label[i] == CGLFLOW_COL_INCUT && sign[i] > 0) || label[i] == CGLFLOW_COL_INLMIN ) { // C+ || L- if ( up[i] > lambda ) { // C++ || L-(up[i] > lambda) ix = i; } } if( ix == UNDEFINED_ ) break; mt[index++] = up[ix]; // Record m_i in C++ and L-(not all) in descending order. if( label[ix] == CGLFLOW_COL_INLMIN ) label[ix] = CGLFLOW_COL_INLMINDONE; else label[ix] = CGLFLOW_COL_INCUTDONE; } //printf("mins %g %g\n",minNegM,minPlsM); if( index == 0 || numPlusPlus == 0) { // No column in C++ and L-(not all). RETURN. if(CGLFLOW_DEBUG) { std::cout << "index = 0. RETURN." << std::endl; } delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; delete [] rho; delete [] xCoef; delete [] yCoef; delete [] mt; delete [] M; delete [] order; return generated; } for ( i = 0; i < rowLen; i++ ) { switch( label[i] ) { case CGLFLOW_COL_INCUTDONE: label[i] = CGLFLOW_COL_INCUT; break; case CGLFLOW_COL_INLMIN: case CGLFLOW_COL_INLMINDONE: case CGLFLOW_COL_INLMINMIN: label[i] = CGLFLOW_COL_OUTCUT; break; case CGLFLOW_COL_INCUT: case CGLFLOW_COL_OUTCUT: case CGLFLOW_COL_PRIME: case CGLFLOW_COL_SECONDARY: break; } } temp1 = temp; /* Get t */ t = 0; for ( i = 0; i < index; ++i ) { if ( mt[i] < minPlsM ) { t = i; break; } } if (i == index) { t = index; } /* Compute M_i */ M[0] = 0.0; for ( i = 1; i <= index; ++i ) { M[i] = M[(i-1)] + mt[(i-1)]; if(CGLFLOW_DEBUG) { std::cout << "t = " << t << std::endl; std::cout << "mt[" << std::setw(5) << (i-1) << "]=" << std::setw(2) << ", M[" << std::setw(5) << i << "]=" << std::setw(20) << M[i] << std::endl; } } // Exit if very big M if (M[index]>1.0e30) { // rlh: should test for huge col UB earler // no sense doing all this work in that case. if(CGLFLOW_DEBUG) { std::cout << "M[index]>1.0e30. RETURN." << std::endl; delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; delete [] rho; delete [] xCoef; delete [] yCoef; delete [] mt; delete [] M; delete [] order; return generated; } } /* Get ml */ double ml = CoinMin(sum, lambda); if(CGLFLOW_DEBUG) { // sum = sum_{i in C+\C++} m_i + sum_{i in L--} m_i = m. Page 15. std::cout << "ml = CoinMin(m, lambda) = CoinMin(" << sum << ", " << lambda << ") =" << ml << std::endl; } /* rho_i = max[0, m_i - (minPlsM - lamda) - ml */ if (t < index ) { /* rho exits only for t <= index-1 */ value = (minPlsM - lambda) + ml; for (i = t; i < index; ++i) { rho[i] = CoinMax(0.0, mt[i] - value); if(CGLFLOW_DEBUG) { std::cout << "rho[" << std::setw(5) << i << "]=" << std::setw(20) << rho[i] << std::endl; } } } // Calculate the violation violation = -cutRHS; for ( i = 0; i < rowLen; ++i ) { #ifdef CGLFLOW_DEBUG2 if(CGLFLOW_DEBUG) { std::cout << "i = " << i << " ind = " << ind[i] << " sign = " << sign[i] << " coef = " << coef[i] << " x = " << x[i] << " xCoef = " << xCoef[i] << " y = " << y[i] << " yCoef = " << yCoef[i] << " up = " << up[i] << " label = " << label[i] << std::endl; } #endif violation += y[i] * yCoef[i] + x[i] * xCoef[i]; } if(CGLFLOW_DEBUG) { std::cout << "violation = " << violation << std::endl; } // double violationBeforeLift=violation; // variable not used anywhere (LL) if(doLift && fabs(violation) > TOLERANCE_ ) { // LIFTING double estY, estX; double movement = 0.0; double dPrimePrime = temp + cutRHS; bool lifted = false; for( i = 0; i < rowLen; ++i ) { if ( (label[i] != CGLFLOW_COL_INCUT) && (sign[i] > 0) ) {/* N+\C+*/ lifted = liftPlus(estY, estX, index, up[i], lambda, y[i], x[i], dPrimePrime, M); xCoef[i] = -estX; yCoef[i] = estY; if(CGLFLOW_DEBUG) { if (lifted) { printf("Success: Lifted col %i (up_i=%f,yCoef[i]=%f,xCoef[i]=%f) in N+\\C+\n", ind[i], up[i], yCoef[i], xCoef[i]); } else { printf("Failed to Lift col %i (m_i=%f) in N+\\C+\n", ind[i], up[i]); } } } if (label[i] == CGLFLOW_COL_INCUT && sign[i] < 0) { /* C- */ liftMinus(movement, t, index, up[i], dPrimePrime, lambda, ml, M, rho); if(movement > EPSILON_) { if(CGLFLOW_DEBUG) { printf("Success: Lifted col %i in C-, movement=%f\n", ind[i], movement); } lifted = true; xCoef[i] = -movement; cutRHS -= movement; } else { if(CGLFLOW_DEBUG) { printf("Failed to Lift col %i in C-, g=%f\n", ind[i], movement); } } } } } //------------------------------------------------------------------- // Calculate the violation violation = -cutRHS; for ( i = 0; i < rowLen; ++i ) { #ifdef CGLFLOW_DEBUG2 if(CGLFLOW_DEBUG) { std::cout << "i = " << i << " ind = " << ind[i] << " sign = " << sign[i] << " coef = " << coef[i] << " x = " << x[i] << " xCoef = " << xCoef[i] << " y = " << y[i] << " yCoef = " << yCoef[i] << " up = " << up[i] << " label = " << label[i] << std::endl; } #endif violation += y[i] * yCoef[i] + x[i] * xCoef[i]; } if(CGLFLOW_DEBUG) { std::cout << "violation = " << violation << std::endl; } int cutLen = 0; char cutSense = 'L'; int* cutInd = 0; double* cutCoef = 0; // If violated, transform the inequality back to original system if ( violation > TOLERANCE_ ) { cutLen = 0; cutSense = 'L'; cutInd = new int [numCols]; cutCoef = new double [numCols]; for ( i = 0; i < rowLen; ++i ) { VUB = getVubs(ind[i]); if ( ( sign[i] == CGLFLOW_COL_CONTPOS ) || ( sign[i] == CGLFLOW_COL_CONTNEG ) ) { if ( fabs( yCoef[i] ) > EPSILON_ ) { if ( sign[i] == CGLFLOW_COL_CONTPOS ) cutCoef[cutLen] = coef[i] * yCoef[i]; else cutCoef[cutLen] = -coef[i] * yCoef[i]; cutInd[cutLen++] = ind[i]; } if ( fabs( xCoef[i] ) > EPSILON_ ) { if ( VUB.getVar() != UNDEFINED_ ) { cutCoef[cutLen] = xCoef[i]; cutInd[cutLen++] = VUB.getVar(); } else cutRHS -= xCoef[i]; } } if ( ( sign[i] == CGLFLOW_COL_BINPOS ) || ( sign[i] == CGLFLOW_COL_BINNEG ) ) { if (fabs(yCoef[i]) > EPSILON_ || fabs(xCoef[i]) > EPSILON_) { if (sign[i] == CGLFLOW_COL_BINPOS) cutCoef[cutLen] = coef[i] * yCoef[i] + xCoef[i]; else cutCoef[cutLen] = -coef[i] * yCoef[i] + xCoef[i]; cutInd[cutLen++] = ind[i]; } } } for ( i = 0; i < cutLen; ++i ) { for ( j = 0; j < i; j++ ) { if ( cutInd[j] == cutInd[i] ) { /* Duplicate*/ cutCoef[j] += cutCoef[i]; cutInd[i] = -1; } } } for ( j = 0, i = 0; i < cutLen; ++i ) { if ( ( cutInd[i] == -1 ) || ( fabs( cutCoef[i]) < EPSILON_ ) ){ /* Small coeff*/ } else { cutCoef[j] = cutCoef[i]; cutInd[j] = cutInd[i]; j++; } } cutLen = j; // Skip if no elements ? - bug somewhere assert (cutLen); // Recheck the violation. violation = 0.0; for (i = 0; i < cutLen; ++i) violation += cutCoef[i] * xlp[cutInd[i]]; violation -= cutRHS; if ( violation > TOLERANCE_ ) { flowCut.setRow(cutLen, cutInd, cutCoef); flowCut.setLb(-1.0 * si.getInfinity()); flowCut.setUb(cutRHS); flowCut.setEffectiveness(violation); generated = true; if(CGLFLOW_DEBUG) { std::cout << "generateOneFlowCover(): Found a cut" << std::endl; } } else { if(CGLFLOW_DEBUG) { std::cout << "generateOneFlowCover(): Lost a cut" << std::endl; } } } //------------------------------------------------------------------------- delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; delete [] rho; delete [] xCoef; delete [] yCoef; delete [] mt; delete [] M; delete [] order; delete [] cutInd; delete [] cutCoef; return generated; }
// Generate cuts void CglFakeClique::generateCuts(const OsiSolverInterface& si, OsiCuts & cs, const CglTreeInfo info) { if (fakeSolver_) { assert (si.getNumCols()==fakeSolver_->getNumCols()); fakeSolver_->setColLower(si.getColLower()); const double * solution = si.getColSolution(); fakeSolver_->setColSolution(solution); fakeSolver_->setColUpper(si.getColUpper()); // get and set branch and bound cutoff double cutoff; si.getDblParam(OsiDualObjectiveLimit,cutoff); fakeSolver_->setDblParam(OsiDualObjectiveLimit,COIN_DBL_MAX); #ifdef COIN_HAS_CLP OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (fakeSolver_); if (clpSolver) { // fix up fake solver const ClpSimplex * siSimplex = clpSolver->getModelPtr(); // need to set djs memcpy(siSimplex->primalColumnSolution(), si.getReducedCost(),si.getNumCols()*sizeof(double)); fakeSolver_->setDblParam(OsiDualObjectiveLimit,cutoff); } #endif const CoinPackedMatrix * matrixByRow = si.getMatrixByRow(); const double * elementByRow = matrixByRow->getElements(); const int * column = matrixByRow->getIndices(); const CoinBigIndex * rowStart = matrixByRow->getVectorStarts(); const int * rowLength = matrixByRow->getVectorLengths(); const double * rowUpper = si.getRowUpper(); const double * rowLower = si.getRowLower(); // Scan all rows looking for possibles int numberRows = si.getNumRows(); double tolerance = 1.0e-3; for (int iRow=0;iRow<numberRows;iRow++) { CoinBigIndex start = rowStart[iRow]; CoinBigIndex end = start + rowLength[iRow]; double upRhs = rowUpper[iRow]; double loRhs = rowLower[iRow]; double sum = 0.0; for (CoinBigIndex j=start;j<end;j++) { int iColumn=column[j]; double value = elementByRow[j]; sum += solution[iColumn]*value; } if (sum<loRhs-tolerance||sum>upRhs+tolerance) { // add as cut OsiRowCut rc; rc.setLb(loRhs); rc.setUb(upRhs); rc.setRow(end-start,column+start,elementByRow+start,false); CoinAbsFltEq equal(1.0e-12); cs.insertIfNotDuplicate(rc,equal); } } CglClique::generateCuts(*fakeSolver_,cs,info); if (probing_) { probing_->generateCuts(*fakeSolver_,cs,info); } } else { // just use real solver CglClique::generateCuts(si,cs,info); } }
/**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 solution methods. void OsiCbcSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir) { { CoinRelFltEq eq; OsiCbcSolverInterface m; std::string fn = mpsDir+"exmip1"; m.readMps(fn.c_str(),"mps"); { OsiCbcSolverInterface im; OSIUNITTEST_ASSERT_ERROR(im.getNumCols() == 0, {}, "cbc", "default constructor"); OSIUNITTEST_ASSERT_ERROR(im.getModelPtr() != NULL, {}, "cbc", "default constructor"); } // Test copy constructor and assignment operator { OsiCbcSolverInterface lhs; { OsiCbcSolverInterface im(m); OsiCbcSolverInterface imC1(im); OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != im.getModelPtr(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getNumCols() == im.getNumCols(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getNumRows() == im.getNumRows(), {}, "cbc", "copy constructor"); OsiCbcSolverInterface imC2(im); OSIUNITTEST_ASSERT_ERROR(imC2.getModelPtr() != im.getModelPtr(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC2.getNumCols() == im.getNumCols(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC2.getNumRows() == im.getNumRows(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != imC2.getModelPtr(), {}, "cbc", "copy constructor"); lhs = imC2; } // Test that lhs has correct values even though rhs has gone out of scope OSIUNITTEST_ASSERT_ERROR(lhs.getModelPtr() != m.getModelPtr(), {}, "cbc", "assignment operator"); OSIUNITTEST_ASSERT_ERROR(lhs.getNumCols() == m.getNumCols(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(lhs.getNumRows() == m.getNumRows(), {}, "cbc", "copy constructor"); } // Test clone { OsiCbcSolverInterface cbcSi(m); OsiSolverInterface * siPtr = &cbcSi; OsiSolverInterface * siClone = siPtr->clone(); OsiCbcSolverInterface * cbcClone = dynamic_cast<OsiCbcSolverInterface*>(siClone); OSIUNITTEST_ASSERT_ERROR(cbcClone != NULL, {}, "cbc", "clone"); OSIUNITTEST_ASSERT_ERROR(cbcClone->getModelPtr() != cbcSi.getModelPtr(), {}, "cbc", "clone"); OSIUNITTEST_ASSERT_ERROR(cbcClone->getNumRows() == cbcSi.getNumRows(), {}, "cbc", "clone"); OSIUNITTEST_ASSERT_ERROR(cbcClone->getNumCols() == m.getNumCols(), {}, "cbc", "clone"); delete siClone; } // test infinity { OsiCbcSolverInterface si; OSIUNITTEST_ASSERT_ERROR(si.getInfinity() == OsiCbcInfinity, {}, "cbc", "infinity"); } // Test some catches if (!OsiCbcHasNDEBUG()) { OsiCbcSolverInterface solver; try { solver.setObjCoeff(0,0.0); OSIUNITTEST_ADD_OUTCOME("cbc", "setObjCoeff on empty model", "should throw exception", OsiUnitTest::TestOutcome::ERROR, false); } catch (CoinError e) { if (OsiUnitTest::verbosity >= 1) std::cout<<"Correct throw from setObjCoeff on empty model"<<std::endl; } std::string fn = mpsDir+"exmip1"; solver.readMps(fn.c_str(),"mps"); OSIUNITTEST_CATCH_ERROR(solver.setObjCoeff(0,0.0), {}, "cbc", "setObjCoeff on nonempty model"); try { int index[]={0,20}; double value[]={0.0,0.0,0.0,0.0}; solver.setColSetBounds(index,index+2,value); OSIUNITTEST_ADD_OUTCOME("cbc", "setColSetBounds on cols not in model", "should throw exception", OsiUnitTest::TestOutcome::ERROR, false); } catch (CoinError e) { if (OsiUnitTest::verbosity >= 1) std::cout<<"Correct throw from setObjCoeff on empty model"<<std::endl; } } { OsiCbcSolverInterface cbcSi(m); int nc = cbcSi.getNumCols(); int nr = cbcSi.getNumRows(); const double * cl = cbcSi.getColLower(); const double * cu = cbcSi.getColUpper(); const double * rl = cbcSi.getRowLower(); const double * ru = cbcSi.getRowUpper(); OSIUNITTEST_ASSERT_ERROR(nc == 8, return, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(nr == 5, return, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cl[0],2.5), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cl[1],0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cu[1],4.1), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cu[2],1.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(rl[0],2.5), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(rl[4],3.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(ru[1],2.1), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(ru[4],15.), {}, "cbc", "read and copy exmip1"); const double * cs = cbcSi.getColSolution(); OSIUNITTEST_ASSERT_ERROR(eq(cs[0],2.5), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cs[7],0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(!eq(cl[3],1.2345), {}, "cbc", "set col lower"); cbcSi.setColLower( 3, 1.2345 ); OSIUNITTEST_ASSERT_ERROR( eq(cbcSi.getColLower()[3],1.2345), {}, "cbc", "set col lower"); OSIUNITTEST_ASSERT_ERROR(!eq(cbcSi.getColUpper()[4],10.2345), {}, "cbc", "set col upper"); cbcSi.setColUpper( 4, 10.2345 ); OSIUNITTEST_ASSERT_ERROR( eq(cbcSi.getColUpper()[4],10.2345), {}, "cbc", "set col upper"); // LH: Objective will depend on how underlying solver constructs and maintains initial solution double objValue = cbcSi.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,3.5) || eq(objValue,10.5), {}, "cbc", "getObjValue() before solve"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[0], 1.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[1], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[2], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[3], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[4], 2.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[5], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[6], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[7],-1.0), {}, "cbc", "read and copy exmip1"); } // Test matrixByRow method { const OsiCbcSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim() == 5, return, "cbc", "getMatrixByRow: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getMinorDim() == 8, return, "cbc", "getMatrixByRow: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "cbc", "getMatrixByRow: num elements"); OSIUNITTEST_ASSERT_ERROR(smP->getSizeVectorStarts() == 6, return, "cbc", "getMatrixByRow: num elements"); #ifdef OSICBC_TEST_MTX_STRUCTURE CoinRelFltEq eq; const double * ev = smP->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[0], 3.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[1], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[2], -2.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[3], -1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[4], -1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[5], 2.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[6], 1.1), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[7], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[8], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[9], 2.8), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10], -1.2), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "getMatrixByRow: elements"); const int * mi = smP->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "getMatrixByRow: vector starts"); const int * ei = smP->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "getMatrixByRow: indices"); #else // OSICBC_TEST_MTX_STRUCTURE CoinPackedMatrix exmip1Mtx ; exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*smP), {}, "cbc", "getMatrixByRow") ; #endif // OSICBC_TEST_MTX_STRUCTURE } // Test adding several cuts, and handling of a coefficient of infinity // in the constraint matrix. { OsiCbcSolverInterface fim; std::string fn = mpsDir+"exmip1"; fim.readMps(fn.c_str(),"mps"); // exmip1.mps has 2 integer variables with index 2 & 3 fim.initialSolve(); OsiRowCut cuts[3]; // Generate one ineffective cut plus two trivial cuts int c; int nc = fim.getNumCols(); int *inx = new int[nc]; for (c=0;c<nc;c++) inx[c]=c; double *el = new double[nc]; for (c=0;c<nc;c++) el[c]=1.0e-50+((double)c)*((double)c); cuts[0].setRow(nc,inx,el); cuts[0].setLb(-100.); cuts[0].setUb(500.); cuts[0].setEffectiveness(22); el[4]=0.0; // to get inf later for (c=2;c<4;c++) { el[0]=1.0; inx[0]=c; cuts[c-1].setRow(1,inx,el); cuts[c-1].setLb(1.); cuts[c-1].setUb(100.); cuts[c-1].setEffectiveness(c); } fim.writeMps("x1.mps"); fim.applyRowCuts(3,cuts); fim.writeMps("x2.mps"); // resolve - should get message about zero elements fim.resolve(); fim.writeMps("x3.mps"); // check integer solution const double * cs = fim.getColSolution(); CoinRelFltEq eq; OSIUNITTEST_ASSERT_ERROR(eq(cs[2], 1.0), {}, "cbc", "add cuts"); OSIUNITTEST_ASSERT_ERROR(eq(cs[3], 1.0), {}, "cbc", "add cuts"); // check will find invalid matrix el[0]=1.0/el[4]; inx[0]=0; cuts[0].setRow(nc,inx,el); cuts[0].setLb(-100.); cuts[0].setUb(500.); cuts[0].setEffectiveness(22); fim.applyRowCut(cuts[0]); // resolve - should get message about zero elements fim.resolve(); OSIUNITTEST_ASSERT_WARNING(fim.isAbandoned(), {}, "cbc", "add cuts"); delete[]el; delete[]inx; } // Test matrixByCol method { const OsiCbcSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByCol(); OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim() == 8, return, "cbc", "getMatrixByCol: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getMinorDim() == 5, return, "cbc", "getMatrixByCol: minor dim"); OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "cbc", "getMatrixByCol: number of elements"); OSIUNITTEST_ASSERT_ERROR(smP->getSizeVectorStarts() == 9, return, "cbc", "getMatrixByCol: vector starts size"); #ifdef OSICBC_TEST_MTX_STRUCTURE CoinRelFltEq eq; const double * ev = smP->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 5.6), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 2.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 1.1), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6],-2.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 2.8), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8],-1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11],-1.2), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12],-1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "getMatrixByCol: elements"); const CoinBigIndex * mi = smP->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 2, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 4, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 6, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 8, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 10, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[6] == 11, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[7] == 12, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[8] == 14, {}, "cbc", "getMatrixByCol: vector starts"); const int * ei = smP->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 1, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 3, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 4, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 2, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 3, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 4, {}, "cbc", "getMatrixByCol: indices"); #else // OSICBC_TEST_MTX_STRUCTURE CoinPackedMatrix &exmip1Mtx = BuildExmip1Mtx() ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*smP), {}, "cbc", "getMatrixByCol"); #endif // OSICBC_TEST_MTX_STRUCTURE } //-------------- // Test rowsense, rhs, rowrange, matrixByRow, solver assignment { OsiCbcSolverInterface lhs; { OsiCbcSolverInterface siC1(m); const char * siC1rs = siC1.getRowSense(); OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "cbc", "row sense"); const double * siC1rhs = siC1.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "cbc", "right hand side"); const double * siC1rr = siC1.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "cbc", "row range"); const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(siC1mbr != NULL, {}, "cbc", "matrix by row"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMajorDim() == 5, return, "cbc", "matrix by row: major dim"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMinorDim() == 8, return, "cbc", "matrix by row: major dim"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getNumElements() == 14, return, "cbc", "matrix by row: num elements"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getSizeVectorStarts() == 6, return, "cbc", "matrix by row: num elements"); #ifdef OSICBC_TEST_MTX_STRUCTURE const double * ev = siC1mbr->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "matrix by row: elements"); const CoinBigIndex * mi = siC1mbr->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "matrix by row: vector starts"); const int * ei = siC1mbr->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "matrix by row: indices"); #else // OSICBC_TEST_MTX_STRUCTURE CoinPackedMatrix exmip1Mtx ; exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*siC1mbr), {}, "cbc", "matrix by row"); #endif // OSICBC_TEST_MTX_STRUCTURE OSIUNITTEST_ASSERT_WARNING(siC1rs == siC1.getRowSense(), {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_WARNING(siC1rhs == siC1.getRightHandSide(), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_WARNING(siC1rr == siC1.getRowRange(), {}, "cbc", "row range"); // Change CBC Model by adding free row OsiRowCut rc; rc.setLb(-COIN_DBL_MAX); rc.setUb( COIN_DBL_MAX); OsiCuts cuts; cuts.insert(rc); siC1.applyCuts(cuts); siC1rs = siC1.getRowSense(); OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[5] == 'N', {}, "cbc", "row sense after adding row"); siC1rhs = siC1.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[5],0.0), {}, "cbc", "right hand side after adding row"); siC1rr = siC1.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[5],0.0), {}, "cbc", "row range after adding row"); lhs = siC1; } // Test that lhs has correct values even though siC1 has gone out of scope const char * lhsrs = lhs.getRowSense(); OSIUNITTEST_ASSERT_ERROR(lhsrs[0] == 'G', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[1] == 'L', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[2] == 'E', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[3] == 'R', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[4] == 'R', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[5] == 'N', {}, "cbc", "row sense after assignment"); const double * lhsrhs = lhs.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[0],2.5), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[1],2.1), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[2],4.0), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[3],5.0), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[4],15.), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[5],0.0), {}, "cbc", "right hand side after assignment"); const double *lhsrr = lhs.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[0],0.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[1],0.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[2],0.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[3],5.0-1.8), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[4],15.0-3.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[5],0.0), {}, "cbc", "row range after assignment"); const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(lhsmbr != NULL, {}, "cbc", "matrix by row after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsmbr->getMajorDim() == 6, return, "cbc", "matrix by row after assignment: major dim"); OSIUNITTEST_ASSERT_ERROR(lhsmbr->getNumElements() == 14, return, "cbc", "matrix by row after assignment: num elements"); #ifdef OSICBC_TEST_MTX_STRUCTURE const double * ev = lhsmbr->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "matrix by row after assignment: elements"); const CoinBigIndex * mi = lhsmbr->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "matrix by row after assignment: vector starts"); const int * ei = lhsmbr->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "matrix by row after assignment: indices"); #else // OSICBC_TEST_MTX_STRUCTURE /* This admittedly looks bogus, but it's the equivalent operation on the matrix for inserting a cut of the form -Inf <= +Inf (i.e., a cut with no coefficients). */ CoinPackedMatrix exmip1Mtx ; exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ; CoinPackedVector freeRow ; exmip1Mtx.appendRow(freeRow) ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*lhsmbr), {}, "cbc", "matrix by row after assignment"); #endif // OSICBC_TEST_MTX_STRUCTURE } } // Test add/delete columns { OsiCbcSolverInterface m; std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); double inf = m.getInfinity(); CoinPackedVector c0; c0.insert(0, 4); c0.insert(1, 1); m.addCol(c0, 0, inf, 3); m.initialSolve(); double objValue = m.getObjValue(); CoinRelFltEq eq(1.0e-2); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "cbc", "objvalue after adding col"); // Try deleting first column that's nonbasic at lower bound (0). int * d = new int[1]; CoinWarmStartBasis *cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ; OSIUNITTEST_ASSERT_ERROR(cwsb != NULL, {}, "cbc", "get warmstart basis"); CoinWarmStartBasis::Status stati ; int iCol ; for (iCol = 0 ; iCol < cwsb->getNumStructural() ; iCol++) { stati = cwsb->getStructStatus(iCol) ; if (stati == CoinWarmStartBasis::atLowerBound) break ; } d[0]=iCol; m.deleteCols(1,d); delete [] d; delete cwsb; d=NULL; m.resolve(); objValue = m.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "clp", "objvalue after deleting first col"); // Try deleting column we added. If basic, go to initialSolve as deleting // basic variable trashes basis required for warm start. iCol = m.getNumCols()-1; cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ; stati = cwsb->getStructStatus(iCol) ; delete cwsb; m.deleteCols(1,&iCol); if (stati == CoinWarmStartBasis::basic) { m.initialSolve() ; } else { m.resolve(); } objValue = m.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "clp", "objvalue after deleting added col"); } // Build a model { OsiCbcSolverInterface model; std::string fn = mpsDir+"p0033"; model.readMps(fn.c_str(),"mps"); // Point to data int numberRows = model.getNumRows(); const double * rowLower = model.getRowLower(); const double * rowUpper = model.getRowUpper(); int numberColumns = model.getNumCols(); const double * columnLower = model.getColLower(); const double * columnUpper = model.getColUpper(); const double * columnObjective = model.getObjCoefficients(); // get row copy CoinPackedMatrix rowCopy = *model.getMatrixByRow(); const int * column = rowCopy.getIndices(); const int * rowLength = rowCopy.getVectorLengths(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); const double * element = rowCopy.getElements(); // solve model.initialSolve(); // Now build new model CoinModel build; // Row bounds int iRow; for (iRow=0;iRow<numberRows;iRow++) { build.setRowBounds(iRow,rowLower[iRow],rowUpper[iRow]); } // Column bounds and objective int iColumn; for (iColumn=0;iColumn<numberColumns;iColumn++) { build.setColumnLower(iColumn,columnLower[iColumn]); build.setColumnUpper(iColumn,columnUpper[iColumn]); build.setObjective(iColumn,columnObjective[iColumn]); } // Adds elements one by one by row (backwards by row) for (iRow=numberRows-1;iRow>=0;iRow--) { int start = rowStart[iRow]; for (int j=start;j<start+rowLength[iRow];j++) build(iRow,column[j],element[j]); } // Now create Model OsiCbcSolverInterface model2; model2.loadFromCoinModel(build); model2.initialSolve(); // Save - should be continuous model2.writeMps("continuous"); int * whichInteger = new int[numberColumns]; for (iColumn=0;iColumn<numberColumns;iColumn++) whichInteger[iColumn]=iColumn; // mark as integer model2.setInteger(whichInteger,numberColumns); delete [] whichInteger; // save - should be integer model2.writeMps("integer"); // Now do with strings attached // Save build to show how to go over rows CoinModel saveBuild = build; build = CoinModel(); // Column bounds for (iColumn=0;iColumn<numberColumns;iColumn++) { build.setColumnLower(iColumn,columnLower[iColumn]); build.setColumnUpper(iColumn,columnUpper[iColumn]); } // Objective - half the columns as is and half with multiplier of "1.0+multiplier" // Pick up from saveBuild (for no reason at all) for (iColumn=0;iColumn<numberColumns;iColumn++) { double value = saveBuild.objective(iColumn); if (iColumn*2<numberColumns) { build.setObjective(iColumn,columnObjective[iColumn]); } else { // create as string char temp[100]; sprintf(temp,"%g + abs(%g*multiplier)",value,value); build.setObjective(iColumn,temp); } } // It then adds rows one by one but for half the rows sets their values // with multiplier of "1.0+1.5*multiplier" for (iRow=0;iRow<numberRows;iRow++) { if (iRow*2<numberRows) { // add row in simple way int start = rowStart[iRow]; build.addRow(rowLength[iRow],column+start,element+start, rowLower[iRow],rowUpper[iRow]); } else { // As we have to add one by one let's get from saveBuild CoinModelLink triple=saveBuild.firstInRow(iRow); while (triple.column()>=0) { int iColumn = triple.column(); if (iColumn*2<numberColumns) { // just value as normal build(iRow,triple.column(),triple.value()); } else { // create as string char temp[100]; sprintf(temp,"%g + (1.5*%g*multiplier)",triple.value(), triple.value()); build(iRow,iColumn,temp); } triple=saveBuild.next(triple); } // but remember to do rhs build.setRowLower(iRow,rowLower[iRow]); build.setRowUpper(iRow,rowUpper[iRow]); } } // If small switch on error printing if (numberColumns<50) build.setLogLevel(1); // should fail as we never set multiplier OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build) != 0, {}, "cbc", "build model with missing multipliers"); build.associateElement("multiplier",0.0); OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build) == 0, {}, "cbc", "build model"); model2.initialSolve(); // It then loops with multiplier going from 0.0 to 2.0 in increments of 0.1 for (double multiplier=0.0;multiplier<2.0;multiplier+= 0.1) { build.associateElement("multiplier",multiplier); OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build,true) == 0, {}, "cbc", "build model with increasing multiplier"); model2.resolve(); } } // branch and bound { OsiCbcSolverInterface m; std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); m.initialSolve(); //m.messageHandler()->setLogLevel(0); m.getModelPtr()->messageHandler()->setLogLevel(0); m.branchAndBound(); } // branch and bound using CbcModel!!!!!!! { OsiCbcSolverInterface mm; OsiCbcSolverInterface m(&mm); std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); m.initialSolve(); m.branchAndBound(); } // Do common solverInterface testing { OsiCbcSolverInterface m; OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } { OsiCbcSolverInterface mm; OsiCbcSolverInterface m(&mm); OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } }
void CglLandP::generateCuts(const OsiSolverInterface & si, OsiCuts & cs, const CglTreeInfo info ) { if ((info.pass == 0) && !info.inTree) { numrows_ = si.getNumRows(); } // scanExtraCuts(cs, si.getColSolution()); Parameters params = params_; params.rhsWeight = numrows_ + 2; handler_->message(CUT_GAP, messages_)<<info.pass<<si.getObjValue() <<CoinMessageEol; if (info.inTree) //put lower pivot limit { params.pivotLimit = std::min(params.pivotLimit, params.pivotLimitInTree); params.countMistakenRc = true; } if (params.timeLimit < 0) { params.pivotLimit = 0; } assert(si.basisIsAvailable()); #ifdef APPEND_ROW OsiSolverInterface * t_si = si.clone(); if (params.modularize) { int new_idx = si.getNumCols(); int v_idx[1] = {new_idx}; double v_val[1] = {-1}; CoinPackedVector v(1, v_idx, v_val, false); t_si->addCol(CoinPackedVector(), 0, 1, 0); t_si->setInteger(new_idx); t_si->addRow(v,0, 0); t_si->resolve(); } #else const OsiSolverInterface * t_si = &si; #endif cached_.getData(*t_si); CglLandPSimplex landpSi(*t_si, cached_, params, validator_); if (params.generateExtraCuts == CglLandP::AllViolatedMigs) { landpSi.genThisBasisMigs(cached_, params); } landpSi.setLogLevel(handler_->logLevel()); int nCut = 0; std::vector<int> indices; getSortedFractionalIndices(indices,cached_, params); #ifndef NDEBUG int numrows = si.getNumRows(); #endif #ifdef DO_STAT //Get informations on current optimum { OsiSolverInterface * gapTester = si.clone(); gapTester->resolve(); roundsStats_.analyseOptimalBasis(gapTester,info.pass, numrows_); delete gapTester; } #endif params_.timeLimit += CoinCpuTime(); CoinRelFltEq eq(1e-04); for (unsigned int i = 0; i < indices.size() && nCut < params.maxCutPerRound && nCut < cached_.nBasics_ ; i++) { //Check for time limit int iRow = indices[i]; assert(iRow < numrows); OsiRowCut cut; int code=1; OsiSolverInterface * ncSi = NULL; if (params.pivotLimit != 0) { ncSi = t_si->clone(); landpSi.setSi(ncSi); ncSi->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX); ncSi->messageHandler()->setLogLevel(0); } int generated = 0; if (params.pivotLimit == 0) { generated = landpSi.generateMig(iRow, cut, params); } else { generated = landpSi.optimize(iRow, cut, cached_, params); if (params.generateExtraCuts == CglLandP::AllViolatedMigs) { landpSi.genThisBasisMigs(cached_, params); } landpSi.resetSolver(cached_.basis_); } code = 0; if (generated) code = validator_(cut, cached_.colsol_, si, params, originalColLower_, originalColUpper_); if (!generated || code) { if (params.pivotLimit !=0) { handler_->message(LAP_CUT_FAILED_DO_MIG, messages_)<<validator_.failureString(code)<<CoinMessageEol; landpSi.freeSi(); OsiSolverInterface * ncSi = t_si->clone(); landpSi.setSi(ncSi); params.pivotLimit = 0; if (landpSi.optimize(iRow, cut, cached_, params)) { code = validator_(cut, cached_.colsol_, si, params, originalColLower_, originalColUpper_); } params.pivotLimit = params_.pivotLimit; } } if (params.pivotLimit != 0) { landpSi.freeSi(); } if (code) { handler_->message(CUT_REJECTED, messages_)<< validator_.failureString(code)<<CoinMessageEol; } else { if (canLift_) { cut.setGloballyValid(true); } cs.insertIfNotDuplicate(cut, eq); //cs.insert(cut); { //std::cout<<"Violation "<<cut.violated(cached_.colsol_)<<std::endl; nCut++; } } } Cuts& extra = landpSi.extraCuts(); for (int i = 0 ; i < cached_.nNonBasics_; i++) { OsiRowCut * cut = extra.rowCut(i); if (cut == NULL) continue; int code = validator_(*cut, cached_.colsol_, si, params, originalColLower_, originalColUpper_); if (code) { handler_->message(LAP_CUT_FAILED_DO_MIG, messages_) <<validator_.failureString(code)<<CoinMessageEol; } else { cs.insertIfNotDuplicate(*cut, eq); { nCut++; } } delete cut; } landpSi.outPivInfo(nCut); params_.timeLimit -= CoinCpuTime(); cached_.clean(); #ifdef APPEND_ROW assert(t_si != &si); delete t_si; #endif }
void exprQuad::quadCuts (expression *w, OsiCuts &cs, const CouenneCutGenerator *cg){ #ifdef DEBUG std::cout<<"Expression has "<< lcoeff_.size () <<" linear terms and " << nqterms_ <<" quadratic terms." << std::endl; printf ("Q:"); for (sparseQ::iterator row = matrix_.begin (); row != matrix_.end (); ++row) { int xind = row -> first -> Index (); for (sparseQcol::iterator col = row -> second.begin (); col != row -> second.end (); ++col) printf (" <%d,%d,%g>", xind, col -> first -> Index (), col -> second); } printf ("\nb:"); for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el) //for (int i=0; i < nlterms_; i++) printf (" <%d,%g>", el -> first -> Index (), el -> second);//index_ [i], coeff_ [i]); if (c0_) printf ("; <c0 = %g>", c0_); printf ("\nBounds: var val lb ub eigval scaled\n"); int index = 0; for (std::map <exprVar *, std::pair <CouNumber, CouNumber> >::iterator i = bounds_.begin (); i != bounds_.end (); ++i, index++) { printf ("%3d:\t", index); i -> first -> print (); printf ("\t"); printf (" %8g [%8g, %8g]", (*(i -> first)) (), i -> second.first, i -> second.second); CouNumber lb = cg -> Problem () -> Lb (i -> first -> Index ()), ub = cg -> Problem () -> Ub (i -> first -> Index ()); if ((eigen_.size () > 0) && (fabs (ub-lb) > COUENNE_EPS)) printf (" --> %8g %8g", eigen_.begin () -> first, eigen_.begin () -> first / (ub-lb)); printf ("\n"); } #endif // Get on which side constraint is violated to get the good lambda CouNumber varVal = (*w) (), exprVal = (*this) (), lambda = (eigen_.size () == 0) ? 0. : (varVal < exprVal) ? CoinMin (0., eigen_.begin () -> first) : // Use under-estimator CoinMax (0., eigen_.rbegin () -> first), // Use over-estimator convVal = 0.; enum auxSign sign = cg -> Problem () -> Var (w -> Index ()) -> sign (); // if this is a "semi"-auxiliary, check if necessary to separate if ((sign == expression::AUX_GEQ && varVal > exprVal) || (sign == expression::AUX_LEQ && varVal < exprVal)) return; const CouenneProblem& problem = *(cg -> Problem ()); const int numcols = problem.nVars (); const double *colsol = problem.X (), // current solution *lower = problem.Lb (), // lower bound *upper = problem.Ub (); // upper // compute lower or upper convexification and check if it contains // the current point if (fabs (lambda) > COUENNE_EPS) { convVal = exprVal; // there is a convexification, check if out of current point for (std::map <exprVar *, std::pair <CouNumber, CouNumber> >::iterator i = bounds_.begin (); i != bounds_.end (); ++i) { int ind = i -> first -> Index (); CouNumber xi = colsol [ind], lb = lower [ind], ub = upper [ind], delta = ub-lb; if (fabs (delta) > COUENNE_EPS) convVal += lambda * (xi-lb) * (ub-xi) / (delta * delta); } if (varVal < exprVal) {if (convVal < varVal) return;} else {if (convVal > varVal) return;} } #ifdef DEBUG std::cout << "Point to cut: "; for (int i = 0 ; i < numcols ; i++) std::cout << colsol [i] << ", "; printf (" (w,f(x),c) = (%g,%g,%g) -- lambda = %g\n", (*w) (), exprVal, convVal, lambda); #endif // Initialize by copying $a$ into a dense vector and computing Q x^* double *Qxs = new double [numcols], // sparse coefficient vector, $Qx^*$ a0 = -c0_; // constant term CoinFillN (Qxs, numcols, 0.); // Compute 2 * Q x^*. for (sparseQ::iterator row = matrix_.begin (); row != matrix_.end (); ++row) { int qi = row -> first -> Index (); for (sparseQcol::iterator col = row -> second.begin (); col != row -> second.end (); ++col) { int qj = col -> first -> Index (); CouNumber qc = col -> second, xi = colsol [qi], xj = colsol [qj]; if (qi != qj) { Qxs [qi] += qc * xj; // contribution of element $q_{ij}$ to (Qx)_i Qxs [qj] += qc * xi; // $q_{ij}$ (Qx)_j a0 += 2 * qc * xi * xj; } else { /* if (fabs (lambda) > COUENNE_EPS) { CouNumber lb = lower [qi], ub = upper [qi], delta = ub-lb; if (fabs (delta) > COUENNE_EPS) qc -= lambda / (delta*delta); } */ // elements on the diagonal are not halved upon reading a0 += qc * xi * xi; Qxs [qi] += 2 * qc * xi; } } } #ifdef DEBUG printf ("2Qx = ("); for (int i = 0; i < numcols; i++) printf ("%g ", Qxs [i]); printf (")\n"); #endif // Add a to it. for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el) Qxs [el -> first -> Index ()] += el -> second; //coeff_ [i]; // multiply Qx^* by x^*^T again and store the result for the lower // bound into constant term /* for (int i=0; i < numcols; i++){ a0 -= 0.5 * Qxs [i] * colsol [i]; // Qxs [i] *= 2; } */ // And myself Qxs [w -> Index ()] -= 1; #ifdef DEBUG printf ("2Qx = ("); for(int i = 0; i < numcols; i++) printf ("%g ", Qxs [i]); printf (")[%g]\n",a0); #endif //a0 -= exprVal; if (fabs (lambda) > COUENNE_EPS) // Now the part which depends on lambda, if there is one for (std::map <exprVar *, std::pair <CouNumber, CouNumber> >::iterator i = bounds_.begin (); i != bounds_.end (); ++i) { int ind = i -> first -> Index (); CouNumber xi = colsol [ind], lb = lower [ind], ub = upper [ind], delta = ub-lb; if (fabs (delta) > COUENNE_EPS) { CouNumber normlambda = lambda / (delta*delta), coeff = normlambda * (lb + ub - 2. * xi); a0 += normlambda * (lb*ub - xi*xi); //a0 += coeff * xi - normlambda * (xi - lb) * (ub - xi); //a0 += normlambda * lb * ub; Qxs [ind] += coeff; //Qxs [ind] += normlambda * (lb + ub); }// else coeff = 0.; // a0 += lambda [k] * lower [ind] * upper [ind]; // a0 -= lambda [k] * colsol [ind] * colsol [ind]; //Qxs [ind] -= lambda [k] * (colsol [ind]) * 2; } // Count the number of non-zeroes int nnz = 0; for (int i=0; i < numcols ; i++) if (fabs (Qxs [i]) > COUENNE_EPS) nnz++; #ifdef DEBUG printf ("2Qx = (");for(int i=0;i<numcols;i++)printf("%g ",Qxs[i]);printf (")[%g], %d nz\n",a0,nnz); #endif // Pack the vector into a CoinPackedVector and generate the cut. CoinPackedVector a (false); a.reserve (nnz); #ifdef DEBUG CouNumber lhs = 0, lhsc = 0, *optimum = cg -> Problem () -> bestSol (), *current = cg -> Problem () -> X (); #endif for (int i=0; i < numcols; i++) if (fabs (Qxs [i]) > 1.0e-21) { // why 1.0e-21? Look at CoinPackedMatrix.cpp:2188 // compute violation #ifdef DEBUG if (optimum) { printf ("%+g * %g ", Qxs [i], optimum [i]); lhs += Qxs [i] * optimum [i]; } lhsc += Qxs [i] * current [i]; #endif a.insert (i, Qxs [i]); } OsiRowCut cut; cut.setRow (a); delete [] Qxs; if (varVal < exprVal) { //(lambda == dCoeffLo_) { cut.setUb (a0); #ifdef DEBUG if (optimum && (lhs - a0 > COUENNE_EPS)) { printf ("cut violates optimal solution: %g > %g\n", lhs, a0); cut.print (); } if (lhsc < a0 + COUENNE_EPS){ printf ("cut (+) is not cutting: "); cut.print (); } #endif // cut.setLb(-COUENNE_INFINITY); } else { cut.setLb (a0); #ifdef DEBUG if (optimum && (lhs - a0 < -COUENNE_EPS)) { printf ("cut violates optimal solution: %g < %g\n", lhs, a0); cut.print (); } if (lhsc > a0 - COUENNE_EPS){ printf ("cut (-) is not cutting: "); cut.print (); } #endif // cut.setUb(COUENNE_INFINITY); } cs.insert (cut); }
void CglOddHole::generateCuts(const OsiRowCutDebugger * /*debugger*/, const CoinPackedMatrix & rowCopy, const double * solution, const double * dj, OsiCuts & cs, const int * suitableRow, const int * fixedColumn, const CglTreeInfo info, bool packed) { CoinPackedMatrix columnCopy = rowCopy; columnCopy.reverseOrdering(); // Get basic problem information int nRows=columnCopy.getNumRows(); int nCols=columnCopy.getNumCols(); const int * column = rowCopy.getIndices(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); const int * rowLength = rowCopy.getVectorLengths(); const int * row = columnCopy.getIndices(); const CoinBigIndex * columnStart = columnCopy.getVectorStarts(); const int * columnLength = columnCopy.getVectorLengths(); // we need only look at suitable rows and variables with unsatisfied 0-1 // lookup from true row to compressed matrix int * mrow = new int[nRows]; // lookup from true column to compressed int * lookup = new int[nCols]; // number of columns in compressed matrix int nSmall=0; int i; //do lookup from true sequence to compressed int n=0; for (i=0;i<nRows;i++) { if (suitableRow[i]>0) { mrow[i]=n++; } else { mrow[i]=-1; } } for (i=0;i<nCols;i++) { if (!fixedColumn[i]) { lookup[i]=nSmall++; } else { lookup[i]=-1; } } int nSmall2=2*nSmall; // we don't know how big matrix will be #define MAXELS 50000 int maxels=MAXELS; //How do I do reallocs in C++? // 1.0 - value x(i) - value x(j) for each node pair (or reverse if cover) double * cost = reinterpret_cast<double *> (malloc(maxels*sizeof(double))); // arc i.e. j which can be reached from i int * to= reinterpret_cast<int *> (malloc(maxels*sizeof(int))); //original row for each arc int * rowfound=reinterpret_cast<int *> (malloc(maxels*sizeof(int))); // start of each column int * starts=new int[2*nSmall+1]; starts[0]=0; // useful array for marking if already connected int * mark =new int[nSmall2]; memset(mark,0,nSmall2*sizeof(int)); n=0; //number of elements in matrix for (i=0;i<nCols;i++) { int icol=lookup[i]; if (icol>=0) { // column in compressed matrix int k; double dd=1.0000001-solution[i]; mark[icol]=1; // reallocate if matrix reached size limit if (n+nCols>maxels) { maxels*=2; cost=reinterpret_cast<double *> (realloc(cost,maxels*sizeof(double))); to=reinterpret_cast<int *> (realloc(to,maxels*sizeof(int))); rowfound=reinterpret_cast<int *> (realloc(rowfound,maxels*sizeof(int))); } // get all other connected variables for (k=columnStart[i];k<columnStart[i]+columnLength[i];k++) { int irow=row[k]; int jrow=mrow[irow]; // but only if row in compressed matrix if (jrow>=0) { int j; for (j=rowStart[irow];j<rowStart[irow]+rowLength[irow];j++) { int jcol=column[j]; int kcol=lookup[jcol]; if (kcol>=0&&!mark[kcol]) { cost[n]=dd-solution[jcol]; to[n]=kcol; rowfound[n++]=irow;//original row mark[kcol]=1; } } } } starts[icol+1]=n; // zero out markers for next column mark[icol]=0; for (k=starts[icol];k<starts[icol+1];k++) { int ito=to[k]; if (ito<0||ito>=nSmall) abort(); mark[to[k]]=0; } } } //if cover then change sign - otherwise make sure positive if (packed) { for (i=0;i<n;i++) { if (cost[i]<1.0e-10) { cost[i]=1.0e-10; } } } else { for (i=0;i<n;i++) { cost[i]=-cost[i]; if (cost[i]<1.0e-10) { cost[i]=1.0e-10; } } } // we are going to double size if (2*n>maxels) { maxels=2*n; cost=reinterpret_cast<double *> (realloc(cost,maxels*sizeof(double))); to=reinterpret_cast<int *> (realloc(to,maxels*sizeof(int))); rowfound=reinterpret_cast<int *> (realloc(rowfound,maxels*sizeof(int))); } /* copy and make bipartite*/ for (i=0;i<nSmall;i++) { int k,j=i+nSmall; for (k=starts[i];k<starts[i+1];k++) { int ito=to[k]; to[n]=ito; to[k]=ito+nSmall; cost[n]=cost[k]; rowfound[n++]=rowfound[k];; } starts[j+1]=n; } //random numbers to winnow out duplicate cuts double * check = new double[nCols]; if (info.randomNumberGenerator) { const CoinThreadRandom * randomGenerator = info.randomNumberGenerator; for (i=0;i<nCols;i++) { check[i]=randomGenerator->randomDouble(); } } else { CoinSeedRandom(13579); for (i=0;i<nCols;i++) { check[i]=CoinDrand48(); // NOT on a thread by thread basis } } // Shortest path algorithm from Dijkstra - is there a better one? typedef struct { double cost; //cost to starting node int back; //previous node } Path; typedef struct { double cost; //cost to starting node int node; //node } Item; Item * stack = new Item [nSmall2]; Path * path = new Path [nSmall2]; // arrays below are used only if looks promising // allocate here // we don't know how many cuts will be generated int ncuts=0; int maxcuts=1000; double * hash = reinterpret_cast<double *> (malloc(maxcuts*sizeof(double))); // to clean (should not be needed) int * clean = new int[nSmall2]; int * candidate = new int[CoinMax(nSmall2,nCols)]; double * element = new double[nCols]; // in case we want to sort double_double_int_triple * sortit = new double_double_int_triple [nCols]; memset(mark,0,nSmall2*sizeof(int)); int * countcol = new int[nCols]; memset(countcol,0,nCols*sizeof(int)); int bias = packed ? 0 : 1; //amount to add before halving // If nSmall large then should do a randomized subset // Improvement 1 int icol; for (icol=0;icol<nSmall;icol++) { int j; int jcol=icol+nSmall; int istack=1; for (j=0;j<nSmall2;j++) { path[j].cost=1.0e70; path[j].back=nSmall2+1; } path[icol].cost=0.0; path[icol].back=-1; stack[0].cost=0.0; stack[0].node=icol; mark[icol]=1; while(istack) { Item thisItem=stack[--istack]; double thisCost=thisItem.cost; int inode=thisItem.node; int k; mark[inode]=0; //say available for further work // See if sorting every so many would help (and which way)? // Improvement 2 for (k=starts[inode];k<starts[inode+1];k++) { int jnode=to[k]; if (!mark[jnode]&&thisCost+cost[k]<path[jnode].cost-1.0e-12) { path[jnode].cost=thisCost+cost[k]; path[jnode].back=inode; // add to stack stack[istack].cost=path[jnode].cost; stack[istack++].node=jnode; mark[jnode]=1; #ifdef CGL_DEBUG assert (istack<=nSmall2); #endif } } } bool good=(path[jcol].cost<0.9999); if (good) { /* try */ int ii; int nrow2=0; int nclean=0; double sum=0; #ifdef CGL_DEBUG printf("** %d ",jcol-nSmall); #endif ii=1; candidate[0]=jcol; while(jcol!=icol) { int jjcol; jcol=path[jcol].back; if (jcol>=nSmall) { jjcol=jcol-nSmall; } else { jjcol=jcol; } #ifdef CGL_DEBUG printf(" %d",jjcol); #endif if (mark[jjcol]) { // good=false; // probably means this is from another cycle (will have been found) // one of cycles must be zero cost // printf("variable already on chain!\n"); } else { mark[jjcol]=1; clean[nclean++]=jjcol; candidate[ii++]=jcol; #ifdef CGL_DEBUG assert (ii<=nSmall2); #endif } } #ifdef CGL_DEBUG printf("\n"); #endif for (j=0;j<nclean;j++) { int k=clean[j]; mark[k]=0; } if (good) { int k; for (k=ii-1;k>0;k--) { int jk,kk=candidate[k]; int ix=0; for (jk=starts[kk];jk<starts[kk+1];jk++) { int ito=to[jk]; if (ito==candidate[k-1]) { ix=1; // back to original row mrow[nrow2++]=rowfound[jk]; break; } } if (!ix) { good=false; } } if ((nrow2&1)!=1) { good=false; } if (good) { int nincut=0; for (k=0;k<nrow2;k++) { int j,irow=mrow[k]; for (j=rowStart[irow];j<rowStart[irow]+rowLength[irow];j++) { int icol=column[j]; if (!countcol[icol]) candidate[nincut++]=icol; countcol[icol]++; } } #ifdef CGL_DEBUG printf("true constraint %d",nrow2); #endif nrow2=nrow2>>1; double rhs=nrow2; if (!packed) rhs++; // +1 for cover ii=0; for (k=0;k<nincut;k++) { int jcol=candidate[k]; if (countcol[jcol]) { #ifdef CGL_DEBUG printf(" %d %d",jcol,countcol[jcol]); #endif int ihalf=(countcol[jcol]+bias)>>1; if (ihalf) { element[ii]=ihalf; sum+=solution[jcol]*element[ii]; /*printf("%d %g %g\n",jcol,element[ii],sumall[jcol]);*/ candidate[ii++]=jcol; } countcol[jcol]=0; } } #ifdef CGL_DEBUG printf("\n"); #endif OsiRowCut rc; double violation=0.0; if (packed) { violation = sum-rhs; rc.setLb(-COIN_DBL_MAX); rc.setUb(rhs); } else { // other way for cover violation = rhs-sum; rc.setUb(COIN_DBL_MAX); rc.setLb(rhs); } if (violation<minimumViolation_) { #ifdef CGL_DEBUG printf("why no cut\n"); #endif good=false; } else { if (static_cast<double> (ii) * minimumViolationPer_>violation|| ii>maximumEntries_) { #ifdef CGL_DEBUG printf("why no cut\n"); #endif if (packed) { // sort and see if we can get down to length // relax by taking out ones with solution 0.0 nincut=ii; for (k=0;k<nincut;k++) { int jcol=candidate[k]; double value = fabs(dj[jcol]); if (solution[jcol]) value = -solution[jcol]; sortit[k].dj=value; sortit[k].element=element[k]; sortit[k].sequence=jcol; } // sort std::sort(sortit,sortit+nincut,double_double_int_triple_compare()); nincut = CoinMin(nincut,maximumEntries_); sum=0.0; for (k=0;k<nincut;k++) { int jcol=sortit[k].sequence; candidate[k]=jcol; element[k]=sortit[k].element; sum+=solution[jcol]*element[k]; } violation = sum-rhs; ii=nincut; if (violation<minimumViolation_) { good=false; } } else { good=false; } } } if (good) { //this assumes not many cuts int j; #if 0 double value=0.0; for (j=0;j<ii;j++) { int icol=candidate[j]; value += check[icol]*element[j]; } #else CoinPackedVector candidatePv(ii,candidate,element); candidatePv.sortIncrIndex(); double value = candidatePv.dotProduct(check); #endif for (j=0;j<ncuts;j++) { if (value==hash[j]) { //could check equality - quicker just to assume break; } } if (j==ncuts) { //new if (ncuts==maxcuts) { maxcuts *= 2; hash = reinterpret_cast<double *> (realloc(hash,maxcuts*sizeof(double))); } hash[ncuts++]=value; rc.setRow(ii,candidate,element); #ifdef CGL_DEBUG printf("sum %g rhs %g %d\n",sum,rhs,ii); if (debugger) assert(!debugger->invalidCut(rc)); #endif cs.insert(rc); } } } /* end of adding cut */ } } } delete [] countcol; delete [] element; delete [] candidate; delete [] sortit; delete [] clean; delete [] path; delete [] stack; free(hash); delete [] check; delete [] mark; delete [] starts; delete [] lookup; delete [] mrow; free(rowfound); free(to); free(cost); }
//------------------------------------------------------------------- // Generate Stored cuts //------------------------------------------------------------------- void CglStored::generateCuts(const OsiSolverInterface & si, OsiCuts & cs, const CglTreeInfo /*info*/) const { // Get basic problem information const double * solution = si.getColSolution(); int numberRowCuts = cuts_.sizeRowCuts(); for (int i=0;i<numberRowCuts;i++) { const OsiRowCut * rowCutPointer = cuts_.rowCutPtr(i); double violation = rowCutPointer->violated(solution); if (violation>=requiredViolation_) cs.insert(*rowCutPointer); } if (probingInfo_) { int number01 = probingInfo_->numberIntegers(); const cliqueEntry * entry = probingInfo_->fixEntries(); const int * toZero = probingInfo_->toZero(); const int * toOne = probingInfo_->toOne(); const int * integerVariable = probingInfo_->integerVariable(); const double * lower = si.getColLower(); const double * upper = si.getColUpper(); OsiRowCut cut; int column[2]; double element[2]; for (int i=0;i<number01;i++) { int iColumn=integerVariable[i]; if (upper[iColumn]==lower[iColumn]) continue; double value1 = solution[iColumn]; for (int j=toZero[i];j<toOne[i];j++) { int jColumn=sequenceInCliqueEntry(entry[j]); if (jColumn<number01) { jColumn=integerVariable[jColumn]; assert (jColumn>=0); double value2 = solution[jColumn]; if (oneFixesInCliqueEntry(entry[j])) { double violation = 1.0-value1-value2; if (violation>requiredViolation_) { //printf("XXX can do %d + %d >=1\n",iColumn,jColumn); cut.setLb(1.0); cut.setUb(COIN_DBL_MAX); column[0]=iColumn; element[0]=1.0; column[1]=jColumn; element[1]= 1.0; cut.setEffectiveness(violation); cut.setRow(2,column,element,false); cs.insert(cut); } } else { double violation = value2-value1; if (violation>requiredViolation_) { //printf("XXX can do %d >= %d\n",iColumn,jColumn); cut.setLb(0.0); cut.setUb(COIN_DBL_MAX); column[0]=iColumn; element[0]=1.0; column[1]=jColumn; element[1]= -1.0; cut.setEffectiveness(violation); cut.setRow(2,column,element,false); cs.insert(cut); } } } else { jColumn -= number01; // not 0-1 double value2 = solution[jColumn]; double lowerValue = lower[jColumn]; double upperValue = upper[jColumn]; if (oneFixesInCliqueEntry(entry[j])) { double violation = upperValue-value1*(upperValue-lowerValue)-value2; if (violation>requiredViolation_) { //printf("XXX can do %g*%d + %d >=%g\n",(upperValue-lowerValue),iColumn,jColumn,upperValue); cut.setLb(upperValue); cut.setUb(COIN_DBL_MAX); column[0]=iColumn; element[0]=upperValue-lowerValue; column[1]=jColumn; element[1]= 1.0; cut.setEffectiveness(violation); cut.setRow(2,column,element,false); cs.insert(cut); } } else { double violation = value2-value1*(upperValue-lowerValue)-lowerValue; if (violation>requiredViolation_) { //printf("XXX can do %g*%d >= %d -%g\n",(upperValue-lowerValue),iColumn,jColumn,lowerValue); cut.setLb(-lowerValue); cut.setUb(COIN_DBL_MAX); column[0]=iColumn; element[0]=upperValue-lowerValue; column[1]=jColumn; element[1]= -1.0; cut.setEffectiveness(violation); cut.setRow(2,column,element,false); cs.insert(cut); } } } } for (int j=toOne[i];j<toZero[i+1];j++) { int jColumn=sequenceInCliqueEntry(entry[j]); if (jColumn<number01) { jColumn=integerVariable[jColumn]; assert (jColumn>=0); double value2 = solution[jColumn]; if (oneFixesInCliqueEntry(entry[j])) { double violation = value1-value2; if (violation>requiredViolation_) { //printf("XXX can do %d <= %d\n",iColumn,jColumn); cut.setLb(-COIN_DBL_MAX); cut.setUb(0.0); column[0]=iColumn; element[0]=1.0; column[1]=jColumn; element[1]= -1.0; cut.setEffectiveness(violation); cut.setRow(2,column,element,false); cs.insert(cut); } } else { double violation = value1+value2-1.0; if (violation>requiredViolation_) { //printf("XXX can do %d + %d <=1\n",iColumn,jColumn); cut.setLb(-COIN_DBL_MAX); cut.setUb(1.0); column[0]=iColumn; element[0]=1.0; column[1]=jColumn; element[1]= 1.0; cut.setEffectiveness(violation); cut.setRow(2,column,element,false); cs.insert(cut); } } } else { jColumn -= number01; // not 0-1 double value2 = solution[jColumn]; double lowerValue = lower[jColumn]; double upperValue = upper[jColumn]; if (oneFixesInCliqueEntry(entry[j])) { double violation = lowerValue +(upperValue-lowerValue)*value1-value2; if (violation>requiredViolation_) { //printf("XXX can do %g*%d <= %d -%g\n",(upperValue-lowerValue),iColumn,jColumn,lowerValue); cut.setLb(-COIN_DBL_MAX); cut.setUb(-lowerValue); column[0]=iColumn; element[0]=upperValue-lowerValue; column[1]=jColumn; element[1]= -1.0; cut.setEffectiveness(violation); cut.setRow(2,column,element,false); cs.insert(cut); } } else { double violation = (upperValue-lowerValue)*value1+value2-upperValue; if (violation>requiredViolation_) { //printf("XXX can do %g*%d + %d <=%g\n",(upperValue-lowerValue),iColumn,jColumn,upperValue); cut.setLb(-COIN_DBL_MAX); cut.setUb(upperValue); column[0]=iColumn; element[0]=upperValue-lowerValue; column[1]=jColumn; element[1]= 1.0; cut.setEffectiveness(violation); cut.setRow(2,column,element,false); cs.insert(cut); } } } } } } }
void OsiSpxSolverInterfaceUnitTest( const std::string & mpsDir, const std::string & netlibDir ) { // Test default constructor { OsiSpxSolverInterface m; OSIUNITTEST_ASSERT_ERROR(m.soplex_ != NULL, {}, "SoPlex", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.getNumCols() == 0, {}, "SoPlex", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.rowsense_ == NULL, {}, "SoPlex", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.rhs_ == NULL, {}, "SoPlex", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.rowrange_ == NULL, {}, "SoPlex", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.colsol_ == NULL, {}, "SoPlex", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.rowsol_ == NULL, {}, "SoPlex", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.matrixByRow_ == NULL, {}, "SoPlex", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.matrixByCol_ == NULL, {}, "SoPlex", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.getApplicationData() == NULL, {}, "SoPlex", "default constructor"); int i=2346; m.setApplicationData(&i); OSIUNITTEST_ASSERT_ERROR(*((int *)(m.getApplicationData())) == i, {}, "SoPlex", "set application data"); } { CoinRelFltEq eq; OsiSpxSolverInterface m; std::string fn = mpsDir+"exmip1"; m.readMps(fn.c_str(),"mps"); // int ad = 13579; // m.setApplicationData(&ad); // OSIUNITTEST_ASSERT_ERROR(*((int *)(m.getApplicationData())) == ad, {}, "SoPlex", "set application data"); { const CoinPackedMatrix * colCopy = m.getMatrixByCol(); OSIUNITTEST_ASSERT_ERROR(colCopy->getNumCols() == 8, {}, "SoPlex", "exmip1 matrix"); OSIUNITTEST_ASSERT_ERROR(colCopy->getMajorDim() == 8, {}, "SoPlex", "exmip1 matrix"); OSIUNITTEST_ASSERT_ERROR(colCopy->getNumRows() == 5, {}, "SoPlex", "exmip1 matrix"); OSIUNITTEST_ASSERT_ERROR(colCopy->getMinorDim() == 5, {}, "SoPlex", "exmip1 matrix"); OSIUNITTEST_ASSERT_ERROR(colCopy->getVectorLengths()[7] == 2, {}, "SoPlex", "exmip1 matrix"); CoinPackedMatrix revColCopy; revColCopy.reverseOrderedCopyOf(*colCopy); CoinPackedMatrix rev2ColCopy; rev2ColCopy.reverseOrderedCopyOf(revColCopy); OSIUNITTEST_ASSERT_ERROR(rev2ColCopy.getNumCols() == 8, {}, "SoPlex", "twice reverse matrix copy"); OSIUNITTEST_ASSERT_ERROR(rev2ColCopy.getMajorDim() == 8, {}, "SoPlex", "twice reverse matrix copy"); OSIUNITTEST_ASSERT_ERROR(rev2ColCopy.getNumRows() == 5, {}, "SoPlex", "twice reverse matrix copy"); OSIUNITTEST_ASSERT_ERROR(rev2ColCopy.getMinorDim() == 5, {}, "SoPlex", "twice reverse matrix copy"); OSIUNITTEST_ASSERT_ERROR(rev2ColCopy.getVectorLengths()[7] == 2, {}, "SoPlex", "twice reverse matrix copy"); } // Test copy constructor and assignment operator { OsiSpxSolverInterface lhs; { OsiSpxSolverInterface im(m); OsiSpxSolverInterface imC1(im); OsiSpxSolverInterface imC2(im); lhs = imC2; } // Test that lhs has correct values even though rhs has gone out of scope OSIUNITTEST_ASSERT_ERROR(lhs.getNumCols() == m.getNumCols(), {}, "SoPlex", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(lhs.getNumRows() == m.getNumRows(), {}, "SoPlex", "copy constructor"); } // Test clone { OsiSpxSolverInterface soplexSi(m); OsiSolverInterface * siPtr = &soplexSi; OsiSolverInterface * siClone = siPtr->clone(); OsiSpxSolverInterface * soplexClone = dynamic_cast<OsiSpxSolverInterface*>(siClone); OSIUNITTEST_ASSERT_ERROR(soplexClone != NULL, {}, "SoPlex", "clone"); OSIUNITTEST_ASSERT_ERROR(soplexClone->getNumRows() == soplexSi.getNumRows(), {}, "SoPlex", "clone"); OSIUNITTEST_ASSERT_ERROR(soplexClone->getNumCols() == m.getNumCols(), {}, "SoPlex", "clone"); delete siClone; } // test infinity { OsiSpxSolverInterface si; OSIUNITTEST_ASSERT_ERROR(si.getInfinity() == soplex::infinity, {}, "SoPlex", "value for infinity"); } { OsiSpxSolverInterface soplexSi(m); int nc = soplexSi.getNumCols(); int nr = soplexSi.getNumRows(); const double * cl = soplexSi.getColLower(); const double * cu = soplexSi.getColUpper(); const double * rl = soplexSi.getRowLower(); const double * ru = soplexSi.getRowUpper(); OSIUNITTEST_ASSERT_ERROR(nc == 8, return, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(nr == 5, return, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cl[0],2.5), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cl[1],0.0), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cu[1],4.1), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cu[2],1.0), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(rl[0],2.5), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(rl[4],3.0), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(ru[1],2.1), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(ru[4],15.), {}, "SoPlex", "read and copy exmip1"); double newCs[8] = {1., 2., 3., 4., 5., 6., 7., 8.}; soplexSi.setColSolution(newCs); const double * cs = soplexSi.getColSolution(); OSIUNITTEST_ASSERT_ERROR(eq(cs[0],1.0), {}, "SoPlex", "set col solution"); OSIUNITTEST_ASSERT_ERROR(eq(cs[7],8.0), {}, "SoPlex", "set col solution"); { OsiSpxSolverInterface solnSi(soplexSi); const double * cs = solnSi.getColSolution(); OSIUNITTEST_ASSERT_ERROR(eq(cs[0],1.0), {}, "SoPlex", "set col solution and copy"); OSIUNITTEST_ASSERT_ERROR(eq(cs[7],8.0), {}, "SoPlex", "set col solution and copy"); } OSIUNITTEST_ASSERT_ERROR(!eq(cl[3],1.2345), {}, "SoPlex", "set col lower"); soplexSi.setColLower( 3, 1.2345 ); OSIUNITTEST_ASSERT_ERROR( eq(cl[3],1.2345), {}, "SoPlex", "set col lower"); OSIUNITTEST_ASSERT_ERROR(!eq(cu[4],10.2345), {}, "SoPlex", "set col upper"); soplexSi.setColUpper( 4, 10.2345 ); OSIUNITTEST_ASSERT_ERROR( eq(cu[4],10.2345), {}, "SoPlex", "set col upper"); OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[0], 1.0), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[1], 0.0), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[2], 0.0), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[3], 0.0), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[4], 2.0), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[5], 0.0), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[6], 0.0), {}, "SoPlex", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[7],-1.0), {}, "SoPlex", "read and copy exmip1"); } // Test getMatrixByRow method { const OsiSpxSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim() == 5, return, "SoPlex", "getMatrixByRow: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "SoPlex", "getMatrixByRow: num elements"); CoinRelFltEq eq; const double * ev = smP->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[0], 3.0), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[1], 1.0), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[2], -2.0), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[3], -1.0), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[4], -1.0), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[5], 2.0), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[6], 1.1), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[7], 1.0), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[8], 1.0), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[9], 2.8), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10], -1.2), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "SoPlex", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "SoPlex", "getMatrixByRow: elements"); const int * mi = smP->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "SoPlex", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "SoPlex", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "SoPlex", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "SoPlex", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "SoPlex", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "SoPlex", "getMatrixByRow: vector starts"); const int * ei = smP->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "SoPlex", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "SoPlex", "getMatrixByRow: indices"); } //-------------- // Test rowsense, rhs, rowrange, getMatrixByRow { OsiSpxSolverInterface lhs; { OsiSpxSolverInterface siC1(m); OSIUNITTEST_ASSERT_WARNING(siC1.rowrange_ == NULL, {}, "SoPlex", "row range"); OSIUNITTEST_ASSERT_WARNING(siC1.rowsense_ == NULL, {}, "SoPlex", "row sense"); OSIUNITTEST_ASSERT_WARNING(siC1.rhs_ == NULL, {}, "SoPlex", "right hand side"); OSIUNITTEST_ASSERT_WARNING(siC1.matrixByRow_ == NULL, {}, "SoPlex", "matrix by row"); OSIUNITTEST_ASSERT_WARNING(siC1.colsol_ == NULL, {}, "SoPlex", "col solution"); OSIUNITTEST_ASSERT_WARNING(siC1.rowsol_ == NULL, {}, "SoPlex", "row solution"); const char * siC1rs = siC1.getRowSense(); OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "SoPlex", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "SoPlex", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "SoPlex", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "SoPlex", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "SoPlex", "row sense"); const double * siC1rhs = siC1.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "SoPlex", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "SoPlex", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "SoPlex", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "SoPlex", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "SoPlex", "right hand side"); const double * siC1rr = siC1.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "SoPlex", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "SoPlex", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "SoPlex", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "SoPlex", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "SoPlex", "row range"); const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(siC1mbr != NULL, {}, "SoPlex", "matrix by row"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMajorDim() == 5, return, "SoPlex", "matrix by row: major dim"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getNumElements() == 14, return, "SoPlex", "matrix by row: num elements"); const double * ev = siC1mbr->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "SoPlex", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "SoPlex", "matrix by row: elements"); const CoinBigIndex * mi = siC1mbr->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "SoPlex", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "SoPlex", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "SoPlex", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "SoPlex", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "SoPlex", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "SoPlex", "matrix by row: vector starts"); const int * ei = siC1mbr->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "SoPlex", "matrix by row: indices"); OSIUNITTEST_ASSERT_WARNING(siC1rs == siC1.getRowSense(), {}, "SoPlex", "row sense"); OSIUNITTEST_ASSERT_WARNING(siC1rhs == siC1.getRightHandSide(), {}, "SoPlex", "right hand side"); OSIUNITTEST_ASSERT_WARNING(siC1rr == siC1.getRowRange(), {}, "SoPlex", "row range"); // Change SOPLEX 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. OSIUNITTEST_ASSERT_ERROR(siC1.rowrange_ == NULL, {}, "SoPlex", "free cached data after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1.rowsense_ == NULL, {}, "SoPlex", "free cached data after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1.rhs_ == NULL, {}, "SoPlex", "free cached data after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1.matrixByRow_ == NULL, {}, "SoPlex", "free cached data after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1.matrixByCol_ == NULL, {}, "SoPlex", "free cached data after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1.colsol_ == NULL, {}, "SoPlex", "free cached data after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1.rowsol_ == NULL, {}, "SoPlex", "free cached data after adding row"); siC1rs = siC1.getRowSense(); OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "SoPlex", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "SoPlex", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "SoPlex", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "SoPlex", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "SoPlex", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[5] == 'N', {}, "SoPlex", "row sense after adding row"); siC1rhs = siC1.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "SoPlex", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "SoPlex", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "SoPlex", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "SoPlex", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "SoPlex", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[5],0.0), {}, "SoPlex", "right hand side after adding row"); siC1rr = siC1.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "SoPlex", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "SoPlex", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "SoPlex", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "SoPlex", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "SoPlex", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[5],0.0), {}, "SoPlex", "row range after adding row"); lhs = siC1; } // Test that lhs has correct values even though siC1 has gone out of scope OSIUNITTEST_ASSERT_ERROR(lhs.rowrange_ == NULL, {}, "SoPlex", "freed origin after assignment"); OSIUNITTEST_ASSERT_ERROR(lhs.rowsense_ == NULL, {}, "SoPlex", "freed origin after assignment"); OSIUNITTEST_ASSERT_ERROR(lhs.rhs_ == NULL, {}, "SoPlex", "freed origin after assignment"); OSIUNITTEST_ASSERT_ERROR(lhs.matrixByRow_ == NULL, {}, "SoPlex", "freed origin after assignment"); OSIUNITTEST_ASSERT_ERROR(lhs.matrixByCol_ == NULL, {}, "SoPlex", "freed origin after assignment"); OSIUNITTEST_ASSERT_ERROR(lhs.colsol_ == NULL, {}, "SoPlex", "freed origin after assignment"); OSIUNITTEST_ASSERT_ERROR(lhs.rowsol_ == NULL, {}, "SoPlex", "freed origin after assignment"); const char * lhsrs = lhs.getRowSense(); OSIUNITTEST_ASSERT_ERROR(lhsrs[0] == 'G', {}, "SoPlex", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[1] == 'L', {}, "SoPlex", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[2] == 'E', {}, "SoPlex", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[3] == 'R', {}, "SoPlex", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[4] == 'R', {}, "SoPlex", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[5] == 'N', {}, "SoPlex", "row sense after assignment"); const double * lhsrhs = lhs.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[0],2.5), {}, "SoPlex", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[1],2.1), {}, "SoPlex", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[2],4.0), {}, "SoPlex", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[3],5.0), {}, "SoPlex", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[4],15.), {}, "SoPlex", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[5],0.0), {}, "SoPlex", "right hand side after assignment"); const double *lhsrr = lhs.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[0],0.0), {}, "SoPlex", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[1],0.0), {}, "SoPlex", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[2],0.0), {}, "SoPlex", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[3],5.0-1.8), {}, "SoPlex", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[4],15.0-3.0), {}, "SoPlex", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[5],0.0), {}, "SoPlex", "row range after assignment"); const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(lhsmbr != NULL, {}, "SoPlex", "matrix by row after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsmbr->getMajorDim() == 6, return, "SoPlex", "matrix by row after assignment: major dim"); OSIUNITTEST_ASSERT_ERROR(lhsmbr->getNumElements() == 14, return, "SoPlex", "matrix by row after assignment: num elements"); const double * ev = lhsmbr->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "SoPlex", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "SoPlex", "matrix by row after assignment: elements"); const CoinBigIndex * mi = lhsmbr->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "SoPlex", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "SoPlex", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "SoPlex", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "SoPlex", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "SoPlex", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "SoPlex", "matrix by row after assignment: vector starts"); const int * ei = lhsmbr->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "SoPlex", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "SoPlex", "matrix by row after assignment: indices"); } //-------------- } // Do common solverInterface testing by calling the // base class testing method. { OsiSpxSolverInterface m; OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } }
//-------------------------------------------------------------------------- // 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; } }
//----------------------------------------------------------------------------- // Generate Lift-and-Project cuts //------------------------------------------------------------------- void CglLiftAndProject::generateCuts(const OsiSolverInterface& si, OsiCuts& cs, const CglTreeInfo /*info*/) { // Assumes the mixed 0-1 problem // // min {cx: <Atilde,x> >= btilde} // // is in canonical form with all bounds, // including x_t>=0, -x_t>=-1 for x_t binary, // explicitly stated in the constraint matrix. // See ~/COIN/Examples/Cgl2/cgl2.cpp // for a general purpose "convert" function. // Reference [BCC]: Balas, Ceria, and Corneujols, // "A lift-and-project cutting plane algorithm // for mixed 0-1 program", Math Prog 58, (1993) // 295-324. // This implementation uses Normalization 1. // Given canonical problem and // the lp-relaxation solution, x, // the LAP cut generator attempts to construct // a cut for every x_j such that 0<x_j<1 // [BCC:307] // x_j is the strictly fractional binary variable // the cut is generated from int j = 0; // Get basic problem information // let Atilde be an m by n matrix const int m = si.getNumRows(); const int n = si.getNumCols(); const double * x = si.getColSolution(); // Remember - Atildes may have gaps.. const CoinPackedMatrix * Atilde = si.getMatrixByRow(); const double * AtildeElements = Atilde->getElements(); const int * AtildeIndices = Atilde->getIndices(); const CoinBigIndex * AtildeStarts = Atilde->getVectorStarts(); const int * AtildeLengths = Atilde->getVectorLengths(); const int AtildeFullSize = AtildeStarts[m]; const double * btilde = si.getRowLower(); // Set up memory for system (10) [BCC:307] // (the problem over the norm intersected // with the polar cone) // // min <<x^T,Atilde^T>,u> + x_ju_0 // s.t. // <B,w> = (0,...,0,beta_,beta)^T // w is nonneg for all but the // last two entries, which are free. // where // w = (u,v,v_0,u_0)in BCC notation // u and v are m-vectors; u,v >=0 // v_0 and u_0 are free-scalars, and // // B = Atilde^T -Atilde^T -e_j e_j // btilde^T e_0^T 0 0 // e_0^T btilde^T 1 0 // ^T indicates Transpose // e_0 is a (AtildeNCols x 1) vector of all zeros // e_j is e_0 with a 1 in the jth position // Storing B in column order. B is a (n+2 x 2m+2) matrix // But need to allow for possible gaps in Atilde. // At each iteration, only need to change 2 cols and objfunc // Sane design of OsiSolverInterface does not permit mucking // with matrix. // Because we must delete and add cols to alter matrix, // and we can only add columns on the end of the matrix // put the v_0 and u_0 columns on the end. // rather than as described in [BCC] // Initially allocating B with space for v_0 and u_O cols // but not populating, for efficiency. // B without u_0 and v_0 is a (n+2 x 2m) size matrix. int twoM = 2*m; int BNumRows = n+2; int BNumCols = twoM+2; int BFullSize = 2*AtildeFullSize+twoM+3; double * BElements = new double[BFullSize]; int * BIndices = new int[BFullSize]; CoinBigIndex * BStarts = new CoinBigIndex [BNumCols+1]; int * BLengths = new int[BNumCols]; int i, ij, k=0; int nPlus1=n+1; int offset = AtildeStarts[m]+m; for (i=0; i<m; i++){ for (ij=AtildeStarts[i];ij<AtildeStarts[i]+AtildeLengths[i];ij++){ BElements[k]=AtildeElements[ij]; BElements[k+offset]=-AtildeElements[ij]; BIndices[k]= AtildeIndices[ij]; BIndices[k+offset]= AtildeIndices[ij]; k++; } BElements[k]=btilde[i]; BElements[k+offset]=btilde[i]; BIndices[k]=n; BIndices[k+offset]=nPlus1; BStarts[i]= AtildeStarts[i]+i; BStarts[i+m]=offset+BStarts[i];// = AtildeStarts[m]+m+AtildeStarts[i]+i BLengths[i]= AtildeLengths[i]+1; BLengths[i+m]= AtildeLengths[i]+1; k++; } BStarts[twoM]=BStarts[twoM-1]+BLengths[twoM-1]; // Cols that will be deleted each iteration int BNumColsLessOne=BNumCols-1; int BNumColsLessTwo=BNumCols-2; const int delCols[2] = {BNumColsLessOne, BNumColsLessTwo}; // Set lower bound on u and v // u_0, v_0 will be reset as free const double solverINFINITY = si.getInfinity(); double * BColLowers = new double[BNumCols]; double * BColUppers = new double[BNumCols]; CoinFillN(BColLowers,BNumCols,0.0); CoinFillN(BColUppers,BNumCols,solverINFINITY); // Set row lowers and uppers. // The rhs is zero, for but the last two rows. // For these the rhs is beta_ double * BRowLowers = new double[BNumRows]; double * BRowUppers = new double[BNumRows]; CoinFillN(BRowLowers,BNumRows,0.0); CoinFillN(BRowUppers,BNumRows,0.0); BRowLowers[BNumRows-2]=beta_; BRowUppers[BNumRows-2]=beta_; BRowLowers[BNumRows-1]=beta_; BRowUppers[BNumRows-1]=beta_; // Calculate base objective <<x^T,Atilde^T>,u> // Note: at each iteration coefficient u_0 // changes to <x^T,e_j> // w=(u,v,beta,v_0,u_0) size 2m+3 // So, BOjective[2m+2]=x[j] double * BObjective= new double[BNumCols]; double * Atildex = new double[m]; CoinFillN(BObjective,BNumCols,0.0); Atilde->times(x,Atildex); // Atildex is size m, x is size n CoinDisjointCopyN(Atildex,m,BObjective); // Number of cols and size of Elements vector // in B without the v_0 and u_0 cols int BFullSizeLessThree = BFullSize-3; // Load B matrix into a column orders CoinPackedMatrix CoinPackedMatrix * BMatrix = new CoinPackedMatrix(true, BNumRows, BNumColsLessTwo, BFullSizeLessThree, BElements,BIndices, BStarts,BLengths); // Assign problem into a solver interface // Note: coneSi will cleanup the memory itself OsiSolverInterface * coneSi = si.clone(false); coneSi->assignProblem (BMatrix, BColLowers, BColUppers, BObjective, BRowLowers, BRowUppers); // Problem sense should default to "min" by default, // but just to be virtuous... coneSi->setObjSense(1.0); // The plot outline from here on down: // coneSi has been assigned B without the u_0 and v_0 columns // Calculate base objective <<x^T,Atilde^T>,u> // bool haveWarmStart = false; // For (j=0; j<n, j++) // if (!isBinary(x_j) || x_j<=0 || x_j>=1) continue; // // IMPROVEME: if(haveWarmStart) check if j attractive // add {-e_j,0,-1} matrix column for v_0 // add {e_j,0,0} matrix column for u_0 // objective coefficient for u_0 is x_j // if (haveWarmStart) // set warmstart info // solve min{objw:Bw=0; w>=0,except v_0, u_0 free} // if (bounded) // get warmstart info // haveWarmStart=true; // ustar = optimal u solution // ustar_0 = optimal u_0 solution // alpha^T= <ustar^T,Atilde> -ustar_0e_j^T // (double check <alpha^T,x> >= beta_ should be violated) // add <alpha^T,x> >= beta_ to cutset // endif // delete column for u_0 // this deletes all column info. // delete column for v_0 // endFor // clean up memory // return 0; int * nVectorIndices = new int[n]; CoinIotaN(nVectorIndices, n, 0); bool haveWarmStart = false; bool equalObj1, equalObj2; CoinRelFltEq eq; double v_0Elements[2] = {-1,1}; double u_0Elements[1] = {1}; CoinWarmStart * warmStart = 0; double * ustar = new double[m]; CoinFillN(ustar, m, 0.0); double* alpha = new double[n]; CoinFillN(alpha, n, 0.0); for (j=0;j<n;j++){ if (!si.isBinary(j)) continue; // Better to ask coneSi? No! // coneSi has no binInfo. equalObj1=eq(x[j],0); equalObj2=eq(x[j],1); if (equalObj1 || equalObj2) continue; // IMPROVEME: if (haveWarmStart) check if j attractive; // AskLL:wanted to declare u_0 and v_0 packedVec outside loop // and setIndices, but didn't see a method to do that(?) // (Could "insert". Seems inefficient) int v_0Indices[2]={j,nPlus1}; int u_0Indices[1]={j}; // CoinPackedVector v_0(2,v_0Indices,v_0Elements,false); CoinPackedVector u_0(1,u_0Indices,u_0Elements,false); #if CGL_DEBUG const CoinPackedMatrix *see1 = coneSi->getMatrixByRow(); #endif coneSi->addCol(v_0,-solverINFINITY,solverINFINITY,0); coneSi->addCol(u_0,-solverINFINITY,solverINFINITY,x[j]); if(haveWarmStart) { coneSi->setWarmStart(warmStart); coneSi->resolve(); } else { #if CGL_DEBUG const CoinPackedMatrix *see2 = coneSi->getMatrixByRow(); #endif coneSi->initialSolve(); } if(coneSi->isProvenOptimal()){ warmStart = coneSi->getWarmStart(); haveWarmStart=true; const double * wstar = coneSi->getColSolution(); CoinDisjointCopyN(wstar, m, ustar); Atilde->transposeTimes(ustar,alpha); alpha[j]+=wstar[BNumCols-1]; #if debug int p; double sum; for(p=0;p<n;p++)sum+=alpha[p]*x[p]; if (sum<=beta_){ throw CoinError("Cut not violated", "cutGeneration", "CglLiftAndProject"); } #endif // add <alpha^T,x> >= beta_ to cutset OsiRowCut rc; rc.setRow(n,nVectorIndices,alpha); rc.setLb(beta_); rc.setUb(solverINFINITY); cs.insert(rc); } // delete col for u_o and v_0 coneSi->deleteCols(2,delCols); // clean up memory } // clean up delete [] alpha; delete [] ustar; delete [] nVectorIndices; // BMatrix, BColLowers,BColUppers, BObjective, BRowLowers, BRowUppers // are all freed by OsiSolverInterface destructor (?) delete [] BLengths; delete [] BStarts; delete [] BIndices; delete [] BElements; }
/** Get an inner-approximation constraint obtained by drawing a chord linking the two given points x and x2. * This only applies to nonlinear constraints featuring univariate functions (f(x) <= y).**/ bool HeuristicInnerApproximation::getMyInnerApproximation(Bonmin::OsiTMINLPInterface &si, OsiCuts &cs, int ind, const double * x, const double * x2) { int n, m, nnz_jac_g, nnz_h_lag; Ipopt::TNLP::IndexStyleEnum index_style; Bonmin::TMINLP2TNLP * problem = si.problem(); problem->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style); double infty = si.getInfinity(); CoinPackedVector cut; double lb = -infty; double ub = 0; double g = 0; double g2 = 0; double diff = 0; double a = 0; problem->eval_gi(n, x, 1, ind, g); problem->eval_gi(n, x2, 1, ind, g2); Bonmin::vector<int> jCol(n); int nnz; problem->eval_grad_gi(n, x2, 0, ind, nnz, jCol(), NULL); Bonmin::vector<double> jValues(nnz); problem->eval_grad_gi(n, x2, 0, ind, nnz, NULL, jValues()); bool add = false; //printf("const %i nnz %i\n", ind, nnz); for (int i = 0; i < nnz; i++) { const int &colIdx = jCol[i]; if(index_style == Ipopt::TNLP::FORTRAN_STYLE) jCol[i]--; diff = x[colIdx] - x2[colIdx]; if (fabs(diff) >= 1e-8) { a = (g - g2) / diff; cut.insert(colIdx, a); ub = (a * x[colIdx] - g) - fabs(a * x[colIdx] - g)*1e-6; //printf("const %i col %i p[col] %g pp[col] %g g %g g2 %g diff %g\n",ind, colIdx, x[colIdx], x2[colIdx], g, g2, diff); add = true; } else { cut.insert(colIdx, jValues[i]); //printf("const %i col %i val %g\n",ind, colIdx, jValues[i]); } } if (add) { OsiRowCut newCut; newCut.setGloballyValidAsInteger(1); newCut.setLb(lb); //********* Perspective Extension ********// int binary_id = 0; // index corresponding to the binary variable activating the corresponding constraint const int* ids = problem->get_const_xtra_id(); // vector of indices corresponding to the binary variable activating the corresponding constraint // Get the index of the corresponding indicator binary variable binary_id = (ids == NULL) ? -1 : ids[ind]; if(binary_id>0) {// If this hyperplane is a linearization of a disjunctive constraint, we link its righthand side to the corresponding indicator binary variable cut.insert(binary_id, -ub); // ∂x ≤ ub => ∂x - ub*z ≤ 0 newCut.setUb(0); } else newCut.setUb(ub); //********* Perspective Extension ********// newCut.setRow(cut); cs.insert(newCut); //newCut.print(); return true; } return false; }
//------------------------------------------------------------- void CglZeroHalf::generateCuts(const OsiSolverInterface & si, OsiCuts & cs, const CglTreeInfo info) { if (mnz_) { int cnum=0,cnzcnt=0; int *cbeg=NULL, *ccnt=NULL,*cind=NULL,*cval=NULL,*crhs=NULL; char *csense=NULL; const double * solution = si.getColSolution(); if ((flags_&1)==0) { // redo bounds const double * columnLower = si.getColLower(); const double * columnUpper = si.getColUpper(); int numberColumns = si.getNumCols(); for (int iColumn=0;iColumn<numberColumns;iColumn++) { if (vlb_[iColumn]!=COIN_INT_MAX) { int ilo,iup; double lo = columnLower[iColumn]; if (lo<-COIN_INT_MAX) lo=-COIN_INT_MAX; ilo= static_cast<int> (ceil(lo)); double up = columnUpper[iColumn]; if (up>COIN_INT_MAX) up=COIN_INT_MAX; iup= static_cast<int> (floor(up)); vlb_[iColumn]=ilo; vub_[iColumn]=iup; } } } if (true) { cutInfo_.sep_012_cut(mr_,mc_,mnz_, mtbeg_,mtcnt_, mtind_, mtval_, vlb_, vub_, mrhs_, msense_, solution, info.inTree ? false : true, &cnum,&cnzcnt, &cbeg,&ccnt,&cind,&cval,&crhs,&csense); } else { int k = 4*mr_+2*mnz_; int * temp = new int[k]; int * mtbeg = temp; int * mtcnt = mtbeg + mr_; int * mtind = mtcnt+mr_; int * mtval = mtind+mnz_; int * mrhs = mtval+mnz_; char * msense = reinterpret_cast<char*> (mrhs+mr_); int i; k=0; int kel=0; for (i=0;i<mr_;i++) { int kel2=kel; int rhs = mrhs_[i]; for (int j=mtbeg_[i];j<mtbeg_[i]+mtcnt_[i];j++) { int iColumn=mtind_[j]; int value=mtval_[j]; if (vlb_[iColumn]<vub_[iColumn]) { mtind[kel]=mtind_[j]; mtval[kel++]=mtval_[j]; } else { rhs -= vlb_[iColumn]*value; } } if (kel>kel2) { mtcnt[k]=kel-kel2; mtbeg[k]=kel2; mrhs[k]=rhs; msense[k++]=msense_[i]; } } if (kel) { cutInfo_.sep_012_cut(k,mc_,kel, mtbeg,mtcnt, mtind, mtval, vlb_, vub_, mrhs, msense, solution, info.inTree ? false : true, &cnum,&cnzcnt, &cbeg,&ccnt,&cind,&cval,&crhs,&csense); } delete [] temp; } if (cnum) { // add cuts double * element = new double[mc_]; for (int i=0;i<cnum;i++) { int n = ccnt[i]; int start = cbeg[i]; for (int j=0;j<n;j++) element[j]=cval[start+j]; OsiRowCut rc; if (csense[i]=='L') { rc.setLb(-COIN_DBL_MAX); rc.setUb(crhs[i]); } else if (csense[i]=='G') { rc.setLb(crhs[i]); rc.setUb(COIN_DBL_MAX); } else { abort(); } rc.setRow(n,cind+start,element,false); if ((flags_&1)!=0) rc.setGloballyValid(); //double violation = rc.violated(solution); //if (violation>1.0e-6) cs.insert(rc); //else //printf("violation of %g\n",violation); } delete [] element; free(cbeg); free(ccnt); free(cind); free(cval); free(crhs); free(csense); } } }
void OsiGlpkSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir) { // Test default constructor { OsiGlpkSolverInterface m; OSIUNITTEST_ASSERT_ERROR(m.obj_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.collower_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.colupper_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.ctype_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.rowsense_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.rhs_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.rowrange_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.rowlower_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.rowupper_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.colsol_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.rowsol_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.matrixByRow_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.matrixByCol_ == NULL, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(m.getApplicationData() == NULL, {}, "glpk", "default constructor"); int i=2346; m.setApplicationData(&i); OSIUNITTEST_ASSERT_ERROR(*((int *)(m.getApplicationData())) == i, {}, "glpk", "default constructor"); } { CoinRelFltEq eq; OsiGlpkSolverInterface m; std::string fn = mpsDir+"exmip1"; m.readMps(fn.c_str(),"mps"); { OsiGlpkSolverInterface im; OSIUNITTEST_ASSERT_ERROR(im.getNumCols() == 0, {}, "glpk", "default constructor"); OSIUNITTEST_ASSERT_ERROR(im.getModelPtr() != NULL, {}, "glpk", "default constructor"); // Test reset im.reset(); OSIUNITTEST_ASSERT_ERROR(m.obj_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.collower_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.colupper_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.ctype_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.rowsense_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.rhs_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.rowrange_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.rowlower_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.rowupper_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.colsol_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.rowsol_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.matrixByRow_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.matrixByCol_ == NULL, {}, "glpk", "reset"); OSIUNITTEST_ASSERT_ERROR(m.getApplicationData() == NULL, {}, "glpk", "reset"); } // Test copy constructor and assignment operator { OsiGlpkSolverInterface lhs; { OsiGlpkSolverInterface im(m); OsiGlpkSolverInterface imC1(im); OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != im.getModelPtr(), {}, "glpk", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getNumCols() == im.getNumCols(), {}, "glpk", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getNumRows() == im.getNumRows(), {}, "glpk", "copy constructor"); OsiGlpkSolverInterface imC2(im); OSIUNITTEST_ASSERT_ERROR(imC2.getModelPtr() != im.getModelPtr(), {}, "glpk", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC2.getNumCols() == im.getNumCols(), {}, "glpk", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC2.getNumRows() == im.getNumRows(), {}, "glpk", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != imC2.getModelPtr(), {}, "glpk", "copy constructor"); lhs = imC2; } // Test that lhs has correct values even though rhs has gone out of scope OSIUNITTEST_ASSERT_ERROR(lhs.getModelPtr() != m.getModelPtr(), {}, "glpk", "assignment operator"); OSIUNITTEST_ASSERT_ERROR(lhs.getNumCols() == m.getNumCols(), {}, "glpk", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(lhs.getNumRows() == m.getNumRows(), {}, "glpk", "copy constructor"); } // Test clone { OsiGlpkSolverInterface glpkSi(m); OsiSolverInterface * siPtr = &glpkSi; OsiSolverInterface * siClone = siPtr->clone(); OsiGlpkSolverInterface * glpkClone = dynamic_cast<OsiGlpkSolverInterface*>(siClone); OSIUNITTEST_ASSERT_ERROR(glpkClone != NULL, {}, "glpk", "clone"); OSIUNITTEST_ASSERT_ERROR(glpkClone->getModelPtr() != glpkSi.getModelPtr(), {}, "glpk", "clone"); OSIUNITTEST_ASSERT_ERROR(glpkClone->getNumRows() == glpkSi.getNumRows(), {}, "glpk", "clone"); OSIUNITTEST_ASSERT_ERROR(glpkClone->getNumCols() == glpkSi.getNumCols(), {}, "glpk", "clone"); delete siClone; } // test infinity { OsiGlpkSolverInterface si; OSIUNITTEST_ASSERT_ERROR(si.getInfinity() == COIN_DBL_MAX, {}, "glpk", "infinity"); } #if 0 // ??? These index error 'throw's aren't in OsiGlpk // Test some catches { OsiGlpkSolverInterface solver; try { solver.setObjCoeff(0,0.0); } catch (CoinError e) { std::cout<<"Correct throw"<<std::endl; } std::string fn = mpsDir+"exmip1"; solver.readMps(fn.c_str(),"mps"); try { solver.setObjCoeff(0,0.0); } catch (CoinError e) { std::cout<<"** Incorrect throw"<<std::endl; abort(); } try { int index[]={0,20}; double value[]={0.0,0.0,0.0,0.0}; solver.setColSetBounds(index,index+2,value); } catch (CoinError e) { std::cout<<"Correct throw"<<std::endl; } } #endif { OsiGlpkSolverInterface glpkSi(m); int nc = glpkSi.getNumCols(); int nr = glpkSi.getNumRows(); const double * cl = glpkSi.getColLower(); const double * cu = glpkSi.getColUpper(); const double * rl = glpkSi.getRowLower(); const double * ru = glpkSi.getRowUpper(); OSIUNITTEST_ASSERT_ERROR(nc == 8, return, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(nr == 5, return, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cl[0],2.5), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cl[1],0.0), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cu[1],4.1), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cu[2],1.0), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(rl[0],2.5), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(rl[4],3.0), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(ru[1],2.1), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(ru[4],15.), {}, "glpk", "read and copy exmip1"); const double * cs = glpkSi.getColSolution(); OSIUNITTEST_ASSERT_ERROR(eq(cs[0],2.5), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cs[7],0.0), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(!eq(cl[3],1.2345), {}, "glpk", "set col lower"); glpkSi.setColLower( 3, 1.2345 ); OSIUNITTEST_ASSERT_ERROR( eq(cl[3],1.2345), {}, "glpk", "set col lower"); OSIUNITTEST_ASSERT_ERROR(!eq(glpkSi.getColUpper()[4],10.2345), {}, "glpk", "set col upper"); glpkSi.setColUpper( 4, 10.2345 ); OSIUNITTEST_ASSERT_ERROR( eq(glpkSi.getColUpper()[4],10.2345), {}, "glpk", "set col upper"); double objValue = glpkSi.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,3.5), {}, "glpk", "getObjValue() before solve"); OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[0], 1.0), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[1], 0.0), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[2], 0.0), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[3], 0.0), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[4], 2.0), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[5], 0.0), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[6], 0.0), {}, "glpk", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[7],-1.0), {}, "glpk", "read and copy exmip1"); } // Test matrixByRow method { const OsiGlpkSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim() == 5, return, "glpk", "getMatrixByRow: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "glpk", "getMatrixByRow: num elements"); CoinRelFltEq eq; const double * ev = smP->getElements(); // GLPK returns each row in reverse order. This is consistent with // the sparse matrix format but is not what most solvers do. That's // why this section is different. OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 3.0), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 1.0), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1],-1.0), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0],-1.0), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 2.0), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.1), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 2.8), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9],-1.2), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 5.6), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "glpk", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 1.9), {}, "glpk", "getMatrixByRow: elements"); const CoinBigIndex * mi = smP->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "glpk", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "glpk", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "glpk", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "glpk", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "glpk", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "glpk", "getMatrixByRow: vector starts"); const int * ei = smP->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 0, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 7, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 1, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 2, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 5, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 3, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 6, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 0, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "glpk", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 7, {}, "glpk", "getMatrixByRow: indices"); } // Test adding several cuts { OsiGlpkSolverInterface fim; std::string fn = mpsDir+"exmip1"; fim.readMps(fn.c_str(),"mps"); // exmip1.mps has 2 integer variables with index 2 & 3 fim.initialSolve(); OsiRowCut cuts[3]; // Generate one ineffective cut plus two trivial cuts int c; int nc = fim.getNumCols(); int *inx = new int[nc]; for (c=0;c<nc;c++) inx[c]=c; double *el = new double[nc]; for (c=0;c<nc;c++) el[c]=1.0e-50+((double)c)*((double)c); cuts[0].setRow(nc,inx,el); cuts[0].setLb(-100.); cuts[0].setUb(500.); cuts[0].setEffectiveness(22); el[4]=0.0; // to get inf later for (c=2;c<4;c++) { el[0]=1.0; inx[0]=c; cuts[c-1].setRow(1,inx,el); cuts[c-1].setLb(1.); cuts[c-1].setUb(100.); cuts[c-1].setEffectiveness(c); } fim.writeMps("x1.mps"); fim.applyRowCuts(3,cuts); fim.writeMps("x2.mps"); // resolve - should get message about zero elements fim.resolve(); fim.writeMps("x3.mps"); // check integer solution const double * cs = fim.getColSolution(); CoinRelFltEq eq; OSIUNITTEST_ASSERT_ERROR(eq(cs[2], 1.0), {}, "glpk", "add cuts"); OSIUNITTEST_ASSERT_ERROR(eq(cs[3], 1.0), {}, "glpk", "add cuts"); #if 0 // ??? Not working for some reason. // check will find invalid matrix el[0]=1.0/el[4]; inx[0]=0; cuts[0].setRow(nc,inx,el); cuts[0].setLb(-100.); cuts[0].setUb(500.); cuts[0].setEffectiveness(22); fim.applyRowCut(cuts[0]); // resolve - should get message about zero elements fim.resolve(); OSIUNITTEST_ASSERT_WARNING(fim.isAbandoned(), {}, "glpk", "add cuts"); #endif delete[]el; delete[]inx; } // Test matrixByCol method { const OsiGlpkSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByCol(); OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim() == 8, return, "glpk", "getMatrixByCol: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getMinorDim() == 5, return, "glpk", "getMatrixByCol: minor dim"); OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "glpk", "getMatrixByCol: number of elements"); OSIUNITTEST_ASSERT_ERROR(smP->getSizeVectorStarts() == 9, return, "glpk", "getMatrixByCol: vector starts size"); CoinRelFltEq eq; const double * ev = smP->getElements(); // Unlike row-ordered matrices, GLPK does column-ordered the "normal" way OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 5.6), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2], 1.0), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 2.0), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 1.1), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.0), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6],-2.0), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 2.8), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8],-1.0), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 1.0), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 1.0), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11],-1.2), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12],-1.0), {}, "glpk", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "glpk", "getMatrixByCol: elements"); const CoinBigIndex * mi = smP->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "glpk", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 2, {}, "glpk", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 4, {}, "glpk", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 6, {}, "glpk", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 8, {}, "glpk", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 10, {}, "glpk", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[6] == 11, {}, "glpk", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[7] == 12, {}, "glpk", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[8] == 14, {}, "glpk", "getMatrixByCol: vector starts"); const int * ei = smP->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 0, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 1, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 0, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 3, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 0, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 4, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 2, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 3, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 0, {}, "glpk", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 4, {}, "glpk", "getMatrixByCol: indices"); } //-------------- // Test rowsense, rhs, rowrange, matrixByRow { OsiGlpkSolverInterface lhs; { #if 0 // FIXME ??? these won't work because the copy constructor changes the values in m OSIUNITTEST_ASSERT_ERROR(m.rowrange_ == NULL, {}, "glpk", "???"); OSIUNITTEST_ASSERT_ERROR(m.rowsense_ == NULL, {}, "glpk", "???"); OSIUNITTEST_ASSERT_ERROR(m.rhs_ == NULL, {}, "glpk", "???"); OSIUNITTEST_ASSERT_ERROR(m.matrixByRow_ == NULL, {}, "glpk", "???"); #endif OsiGlpkSolverInterface siC1(m); OSIUNITTEST_ASSERT_WARNING(siC1.rowrange_ == NULL, {}, "glpk", "row range"); OSIUNITTEST_ASSERT_WARNING(siC1.rowsense_ == NULL, {}, "glpk", "row sense"); OSIUNITTEST_ASSERT_WARNING(siC1.rhs_ == NULL, {}, "glpk", "right hand side"); OSIUNITTEST_ASSERT_WARNING(siC1.matrixByRow_ == NULL, {}, "glpk", "matrix by row"); const char * siC1rs = siC1.getRowSense(); OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "glpk", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "glpk", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "glpk", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "glpk", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "glpk", "row sense"); const double * siC1rhs = siC1.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "glpk", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "glpk", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "glpk", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "glpk", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "glpk", "right hand side"); const double * siC1rr = siC1.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "glpk", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "glpk", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "glpk", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "glpk", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "glpk", "row range"); const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(siC1mbr != NULL, {}, "glpk", "matrix by row"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMajorDim() == 5, return, "glpk", "matrix by row: major dim"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getNumElements() == 14, return, "glpk", "matrix by row: num elements"); const double * ev = siC1mbr->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 3.0), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 1.0), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1],-1.0), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0],-1.0), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 2.0), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.1), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 2.8), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9],-1.2), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 5.6), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "glpk", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 1.9), {}, "glpk", "matrix by row: elements"); const CoinBigIndex * mi = siC1mbr->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "glpk", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "glpk", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "glpk", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "glpk", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "glpk", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "glpk", "matrix by row: vector starts"); const int * ei = siC1mbr->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 0, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 7, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 1, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 2, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 5, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 3, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 6, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 0, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 7, {}, "glpk", "matrix by row: indices"); OSIUNITTEST_ASSERT_WARNING(siC1rs == siC1.getRowSense(), {}, "glpk", "row sense"); OSIUNITTEST_ASSERT_WARNING(siC1rhs == siC1.getRightHandSide(), {}, "glpk", "right hand side"); OSIUNITTEST_ASSERT_WARNING(siC1rr == siC1.getRowRange(), {}, "glpk", "row range"); // Change glpk 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. OSIUNITTEST_ASSERT_ERROR(siC1.rowrange_ == NULL, {}, "glpk", "free cached data after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1.rowsense_ == NULL, {}, "glpk", "free cached data after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1.rhs_ == NULL, {}, "glpk", "free cached data after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1.matrixByRow_ == NULL, {}, "glpk", "free cached data after adding row"); siC1rs = siC1.getRowSense(); OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "glpk", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "glpk", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "glpk", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "glpk", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "glpk", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[5] == 'N', {}, "glpk", "row sense after adding row"); siC1rhs = siC1.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "glpk", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "glpk", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "glpk", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "glpk", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "glpk", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[5],0.0), {}, "glpk", "right hand side after adding row"); siC1rr = siC1.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "glpk", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "glpk", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "glpk", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "glpk", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "glpk", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[5],0.0), {}, "glpk", "row range after adding row"); lhs = siC1; } // Test that lhs has correct values even though siC1 has gone out of scope OSIUNITTEST_ASSERT_ERROR(lhs.rowrange_ == NULL, {}, "glpk", "freed origin after assignment"); OSIUNITTEST_ASSERT_ERROR(lhs.rowsense_ == NULL, {}, "glpk", "freed origin after assignment"); OSIUNITTEST_ASSERT_ERROR(lhs.rhs_ == NULL, {}, "glpk", "freed origin after assignment"); OSIUNITTEST_ASSERT_ERROR(lhs.matrixByRow_ == NULL, {}, "glpk", "freed origin after assignment"); const char * lhsrs = lhs.getRowSense(); OSIUNITTEST_ASSERT_ERROR(lhsrs[0] == 'G', {}, "glpk", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[1] == 'L', {}, "glpk", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[2] == 'E', {}, "glpk", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[3] == 'R', {}, "glpk", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[4] == 'R', {}, "glpk", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[5] == 'N', {}, "glpk", "row sense after assignment"); const double * lhsrhs = lhs.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[0],2.5), {}, "glpk", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[1],2.1), {}, "glpk", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[2],4.0), {}, "glpk", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[3],5.0), {}, "glpk", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[4],15.), {}, "glpk", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[5],0.0), {}, "glpk", "right hand side after assignment"); const double *lhsrr = lhs.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[0],0.0), {}, "glpk", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[1],0.0), {}, "glpk", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[2],0.0), {}, "glpk", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[3],5.0-1.8), {}, "glpk", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[4],15.0-3.0), {}, "glpk", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[5],0.0), {}, "glpk", "row range after assignment"); const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(lhsmbr != NULL, return, "glpk", "matrix by row after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsmbr->getMajorDim() == 6, return, "glpk", "matrix by row after assignment: major dim"); OSIUNITTEST_ASSERT_ERROR(lhsmbr->getNumElements() == 14, return, "glpk", "matrix by row after assignment: num elements"); const double * ev = lhsmbr->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 3.0), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 1.0), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1],-1.0), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0],-1.0), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 2.0), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.1), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 2.8), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9],-1.2), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 5.6), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "glpk", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 1.9), {}, "glpk", "matrix by row after assignment: elements"); const CoinBigIndex * mi = lhsmbr->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "glpk", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "glpk", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "glpk", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "glpk", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "glpk", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "glpk", "matrix by row after assignment: vector starts"); const int * ei = lhsmbr->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 0, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 7, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 1, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 2, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 5, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 3, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 6, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 0, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "glpk", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 7, {}, "glpk", "matrix by row after assignment: indices"); } } // Test add/delete columns { OsiGlpkSolverInterface m; std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); double inf = m.getInfinity(); CoinPackedVector c0; c0.insert(0, 4); c0.insert(1, 1); m.addCol(c0, 0, inf, 3); m.initialSolve(); double objValue = m.getObjValue(); CoinRelFltEq eq(1.0e-2); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "glpk", "add/delete columns: first optimal value"); // Try deleting first column that's nonbasic at lower bound (0). int * d = new int[1]; CoinWarmStartBasis *cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ; OSIUNITTEST_ASSERT_ERROR(cwsb != NULL, {}, "glpk", "add/delete columns: have warm start basis"); CoinWarmStartBasis::Status stati ; int iCol ; for (iCol = 0 ; iCol < cwsb->getNumStructural() ; iCol++) { stati = cwsb->getStructStatus(iCol) ; if (stati == CoinWarmStartBasis::atLowerBound) break ; } d[0]=iCol; m.deleteCols(1,d); delete [] d; delete cwsb; d=NULL; m.resolve(); objValue = m.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "glpk", "add/delete columns: optimal value after deleting nonbasic column"); // Try deleting column we added. If basic, go to initialSolve as deleting // basic variable trashes basis required for warm start. iCol = m.getNumCols()-1; cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ; stati = cwsb->getStructStatus(iCol) ; delete cwsb; m.deleteCols(1,&iCol); if (stati == CoinWarmStartBasis::basic) { m.initialSolve() ; } else { m.resolve(); } objValue = m.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "glpk", "add/delete columns: optimal value after deleting added column"); } #if 0 // ??? Simplex routines not adapted to OsiGlpk yet // Solve an lp by hand { OsiGlpkSolverInterface m; std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); m.setObjSense(-1.0); m.getModelPtr()->messageHandler()->setLogLevel(4); m.initialSolve(); m.getModelPtr()->factorization()->maximumPivots(5); m.setObjSense(1.0); // enable special mode m.enableSimplexInterface(true); // we happen to know that variables are 0-1 and rows are L int numberIterations=0; int numberColumns = m.getNumCols(); int numberRows = m.getNumRows(); double * fakeCost = new double[numberColumns]; double * duals = new double [numberRows]; double * djs = new double [numberColumns]; const double * solution = m.getColSolution(); memcpy(fakeCost,m.getObjCoefficients(),numberColumns*sizeof(double)); while (1) { const double * dj; const double * dual; if ((numberIterations&1)==0) { // use given ones dj = m.getReducedCost(); dual = m.getRowPrice(); } else { // create dj = djs; dual = duals; m.getReducedGradient(djs,duals,fakeCost); } int i; int colIn=9999; int direction=1; double best=1.0e-6; // find most negative reduced cost // Should check basic - but should be okay on this problem for (i=0;i<numberRows;i++) { double value=dual[i]; if (value>best) { direction=-1; best=value; colIn=-i-1; } } for (i=0;i<numberColumns;i++) { double value=dj[i]; if (value<-best&&solution[i]<1.0e-6) { direction=1; best=-value; colIn=i; } else if (value>best&&solution[i]>1.0-1.0e-6) { direction=-1; best=value; colIn=i; } } if (colIn==9999) break; // should be optimal int colOut; int outStatus; double theta; OSIUNITTEST_ASSERT_ERROR(m.primalPivotResult(colIn,direction,colOut,outStatus,theta,NULL) == 0, {}, "glpk", "simplex routines"); printf("out %d, direction %d theta %g\n", colOut,outStatus,theta); numberIterations++; } delete [] fakeCost; delete [] duals; delete [] djs; // exit special mode m.disableSimplexInterface(); m.getModelPtr()->messageHandler()->setLogLevel(4); m.resolve(); OSIUNITTEST_ASSERT_ERROR(m.getIterationCount() == 0, {}, "glpk", "simplex routines"); m.setObjSense(-1.0); m.initialSolve(); } // Solve an lp when interface is on { OsiGlpkSolverInterface m; std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); // enable special mode m.setHintParam(OsiDoScale,false,OsiHintDo); m.setHintParam(OsiDoPresolveInInitial,false,OsiHintDo); m.setHintParam(OsiDoDualInInitial,false,OsiHintDo); m.setHintParam(OsiDoPresolveInResolve,false,OsiHintDo); m.setHintParam(OsiDoDualInResolve,false,OsiHintDo); m.enableSimplexInterface(true); m.initialSolve(); } // Check tableau stuff when simplex interface is on { OsiGlpkSolverInterface m; /* Wolsey : Page 130 max 4x1 - x2 7x1 - 2x2 <= 14 x2 <= 3 2x1 - 2x2 <= 3 x1 in Z+, x2 >= 0 */ double inf_ = m.getInfinity(); int n_cols = 2; int n_rows = 3; double obj[2] = {-4.0, 1.0}; double collb[2] = {0.0, 0.0}; double colub[2] = {inf_, inf_}; double rowlb[3] = {-inf_, -inf_, -inf_}; double rowub[3] = {14.0, 3.0, 3.0}; int rowIndices[5] = {0, 2, 0, 1, 2}; int colIndices[5] = {0, 0, 1, 1, 1}; double elements[5] = {7.0, 2.0, -2.0, 1.0, -2.0}; CoinPackedMatrix M(true, rowIndices, colIndices, elements, 5); m.loadProblem(M, collb, colub, obj, rowlb, rowub); m.enableSimplexInterface(true); m.initialSolve(); //check that the tableau matches wolsey (B-1 A) // slacks in second part of binvA double * binvA = (double*) malloc((n_cols+n_rows) * sizeof(double)); printf("B-1 A"); for(int i = 0; i < n_rows; i++){ m.getBInvARow(i, binvA,binvA+n_cols); printf("\nrow: %d -> ",i); for(int j=0; j < n_cols+n_rows; j++){ printf("%g, ", binvA[j]); } } printf("\n"); m.disableSimplexInterface(); free(binvA); } #endif /* Read in exmip1 and solve it with verbose output setting. */ { OsiGlpkSolverInterface osi ; std::cout << "Boosting verbosity.\n" ; osi.setHintParam(OsiDoReducePrint,false,OsiForceDo) ; std::string exmpsfile = mpsDir+"exmip1" ; std::string probname ; std::cout << "Reading mps file \"" << exmpsfile << "\"\n" ; osi.readMps(exmpsfile.c_str(), "mps") ; OSIUNITTEST_ASSERT_ERROR(osi.getStrParam(OsiProbName,probname), {}, "glpk", "get problem name"); std::cout << "Solving " << probname << " ... \n" ; osi.initialSolve() ; double val = osi.getObjValue() ; std::cout << "And the answer is " << val << ".\n" ; OSIUNITTEST_ASSERT_ERROR(fabs(val - 3.23) < 0.01, {}, "glpk", "solve exmip1"); } // Do common solverInterface testing { OsiGlpkSolverInterface m; OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } }