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; }
// 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); } }
/** 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); }
/** 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); }
/* 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); } }
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; }
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); }
//-------------------------------------------------------------------------- // test solution methods. void OsiCbcSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir) { { CoinRelFltEq eq; OsiCbcSolverInterface m; std::string fn = mpsDir+"exmip1"; m.readMps(fn.c_str(),"mps"); { OsiCbcSolverInterface im; OSIUNITTEST_ASSERT_ERROR(im.getNumCols() == 0, {}, "cbc", "default constructor"); OSIUNITTEST_ASSERT_ERROR(im.getModelPtr() != NULL, {}, "cbc", "default constructor"); } // Test copy constructor and assignment operator { OsiCbcSolverInterface lhs; { OsiCbcSolverInterface im(m); OsiCbcSolverInterface imC1(im); OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != im.getModelPtr(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getNumCols() == im.getNumCols(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getNumRows() == im.getNumRows(), {}, "cbc", "copy constructor"); OsiCbcSolverInterface imC2(im); OSIUNITTEST_ASSERT_ERROR(imC2.getModelPtr() != im.getModelPtr(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC2.getNumCols() == im.getNumCols(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC2.getNumRows() == im.getNumRows(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != imC2.getModelPtr(), {}, "cbc", "copy constructor"); lhs = imC2; } // Test that lhs has correct values even though rhs has gone out of scope OSIUNITTEST_ASSERT_ERROR(lhs.getModelPtr() != m.getModelPtr(), {}, "cbc", "assignment operator"); OSIUNITTEST_ASSERT_ERROR(lhs.getNumCols() == m.getNumCols(), {}, "cbc", "copy constructor"); OSIUNITTEST_ASSERT_ERROR(lhs.getNumRows() == m.getNumRows(), {}, "cbc", "copy constructor"); } // Test clone { OsiCbcSolverInterface cbcSi(m); OsiSolverInterface * siPtr = &cbcSi; OsiSolverInterface * siClone = siPtr->clone(); OsiCbcSolverInterface * cbcClone = dynamic_cast<OsiCbcSolverInterface*>(siClone); OSIUNITTEST_ASSERT_ERROR(cbcClone != NULL, {}, "cbc", "clone"); OSIUNITTEST_ASSERT_ERROR(cbcClone->getModelPtr() != cbcSi.getModelPtr(), {}, "cbc", "clone"); OSIUNITTEST_ASSERT_ERROR(cbcClone->getNumRows() == cbcSi.getNumRows(), {}, "cbc", "clone"); OSIUNITTEST_ASSERT_ERROR(cbcClone->getNumCols() == m.getNumCols(), {}, "cbc", "clone"); delete siClone; } // test infinity { OsiCbcSolverInterface si; OSIUNITTEST_ASSERT_ERROR(si.getInfinity() == OsiCbcInfinity, {}, "cbc", "infinity"); } // Test some catches if (!OsiCbcHasNDEBUG()) { OsiCbcSolverInterface solver; try { solver.setObjCoeff(0,0.0); OSIUNITTEST_ADD_OUTCOME("cbc", "setObjCoeff on empty model", "should throw exception", OsiUnitTest::TestOutcome::ERROR, false); } catch (CoinError e) { if (OsiUnitTest::verbosity >= 1) std::cout<<"Correct throw from setObjCoeff on empty model"<<std::endl; } std::string fn = mpsDir+"exmip1"; solver.readMps(fn.c_str(),"mps"); OSIUNITTEST_CATCH_ERROR(solver.setObjCoeff(0,0.0), {}, "cbc", "setObjCoeff on nonempty model"); try { int index[]={0,20}; double value[]={0.0,0.0,0.0,0.0}; solver.setColSetBounds(index,index+2,value); OSIUNITTEST_ADD_OUTCOME("cbc", "setColSetBounds on cols not in model", "should throw exception", OsiUnitTest::TestOutcome::ERROR, false); } catch (CoinError e) { if (OsiUnitTest::verbosity >= 1) std::cout<<"Correct throw from setObjCoeff on empty model"<<std::endl; } } { OsiCbcSolverInterface cbcSi(m); int nc = cbcSi.getNumCols(); int nr = cbcSi.getNumRows(); const double * cl = cbcSi.getColLower(); const double * cu = cbcSi.getColUpper(); const double * rl = cbcSi.getRowLower(); const double * ru = cbcSi.getRowUpper(); OSIUNITTEST_ASSERT_ERROR(nc == 8, return, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(nr == 5, return, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cl[0],2.5), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cl[1],0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cu[1],4.1), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cu[2],1.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(rl[0],2.5), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(rl[4],3.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(ru[1],2.1), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(ru[4],15.), {}, "cbc", "read and copy exmip1"); const double * cs = cbcSi.getColSolution(); OSIUNITTEST_ASSERT_ERROR(eq(cs[0],2.5), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cs[7],0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(!eq(cl[3],1.2345), {}, "cbc", "set col lower"); cbcSi.setColLower( 3, 1.2345 ); OSIUNITTEST_ASSERT_ERROR( eq(cbcSi.getColLower()[3],1.2345), {}, "cbc", "set col lower"); OSIUNITTEST_ASSERT_ERROR(!eq(cbcSi.getColUpper()[4],10.2345), {}, "cbc", "set col upper"); cbcSi.setColUpper( 4, 10.2345 ); OSIUNITTEST_ASSERT_ERROR( eq(cbcSi.getColUpper()[4],10.2345), {}, "cbc", "set col upper"); // LH: Objective will depend on how underlying solver constructs and maintains initial solution double objValue = cbcSi.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,3.5) || eq(objValue,10.5), {}, "cbc", "getObjValue() before solve"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[0], 1.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[1], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[2], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[3], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[4], 2.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[5], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[6], 0.0), {}, "cbc", "read and copy exmip1"); OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[7],-1.0), {}, "cbc", "read and copy exmip1"); } // Test matrixByRow method { const OsiCbcSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim() == 5, return, "cbc", "getMatrixByRow: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getMinorDim() == 8, return, "cbc", "getMatrixByRow: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "cbc", "getMatrixByRow: num elements"); OSIUNITTEST_ASSERT_ERROR(smP->getSizeVectorStarts() == 6, return, "cbc", "getMatrixByRow: num elements"); #ifdef OSICBC_TEST_MTX_STRUCTURE CoinRelFltEq eq; const double * ev = smP->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[0], 3.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[1], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[2], -2.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[3], -1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[4], -1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[5], 2.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[6], 1.1), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[7], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[8], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[9], 2.8), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10], -1.2), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "cbc", "getMatrixByRow: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "getMatrixByRow: elements"); const int * mi = smP->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "getMatrixByRow: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "getMatrixByRow: vector starts"); const int * ei = smP->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "getMatrixByRow: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "getMatrixByRow: indices"); #else // OSICBC_TEST_MTX_STRUCTURE CoinPackedMatrix exmip1Mtx ; exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*smP), {}, "cbc", "getMatrixByRow") ; #endif // OSICBC_TEST_MTX_STRUCTURE } // Test adding several cuts, and handling of a coefficient of infinity // in the constraint matrix. { OsiCbcSolverInterface fim; std::string fn = mpsDir+"exmip1"; fim.readMps(fn.c_str(),"mps"); // exmip1.mps has 2 integer variables with index 2 & 3 fim.initialSolve(); OsiRowCut cuts[3]; // Generate one ineffective cut plus two trivial cuts int c; int nc = fim.getNumCols(); int *inx = new int[nc]; for (c=0;c<nc;c++) inx[c]=c; double *el = new double[nc]; for (c=0;c<nc;c++) el[c]=1.0e-50+((double)c)*((double)c); cuts[0].setRow(nc,inx,el); cuts[0].setLb(-100.); cuts[0].setUb(500.); cuts[0].setEffectiveness(22); el[4]=0.0; // to get inf later for (c=2;c<4;c++) { el[0]=1.0; inx[0]=c; cuts[c-1].setRow(1,inx,el); cuts[c-1].setLb(1.); cuts[c-1].setUb(100.); cuts[c-1].setEffectiveness(c); } fim.writeMps("x1.mps"); fim.applyRowCuts(3,cuts); fim.writeMps("x2.mps"); // resolve - should get message about zero elements fim.resolve(); fim.writeMps("x3.mps"); // check integer solution const double * cs = fim.getColSolution(); CoinRelFltEq eq; OSIUNITTEST_ASSERT_ERROR(eq(cs[2], 1.0), {}, "cbc", "add cuts"); OSIUNITTEST_ASSERT_ERROR(eq(cs[3], 1.0), {}, "cbc", "add cuts"); // check will find invalid matrix el[0]=1.0/el[4]; inx[0]=0; cuts[0].setRow(nc,inx,el); cuts[0].setLb(-100.); cuts[0].setUb(500.); cuts[0].setEffectiveness(22); fim.applyRowCut(cuts[0]); // resolve - should get message about zero elements fim.resolve(); OSIUNITTEST_ASSERT_WARNING(fim.isAbandoned(), {}, "cbc", "add cuts"); delete[]el; delete[]inx; } // Test matrixByCol method { const OsiCbcSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByCol(); OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim() == 8, return, "cbc", "getMatrixByCol: major dim"); OSIUNITTEST_ASSERT_ERROR(smP->getMinorDim() == 5, return, "cbc", "getMatrixByCol: minor dim"); OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "cbc", "getMatrixByCol: number of elements"); OSIUNITTEST_ASSERT_ERROR(smP->getSizeVectorStarts() == 9, return, "cbc", "getMatrixByCol: vector starts size"); #ifdef OSICBC_TEST_MTX_STRUCTURE CoinRelFltEq eq; const double * ev = smP->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 5.6), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 2.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 1.1), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6],-2.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 2.8), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8],-1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11],-1.2), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12],-1.0), {}, "cbc", "getMatrixByCol: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "getMatrixByCol: elements"); const CoinBigIndex * mi = smP->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 2, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 4, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 6, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 8, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 10, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[6] == 11, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[7] == 12, {}, "cbc", "getMatrixByCol: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[8] == 14, {}, "cbc", "getMatrixByCol: vector starts"); const int * ei = smP->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 1, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 3, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 4, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 2, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 3, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 0, {}, "cbc", "getMatrixByCol: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 4, {}, "cbc", "getMatrixByCol: indices"); #else // OSICBC_TEST_MTX_STRUCTURE CoinPackedMatrix &exmip1Mtx = BuildExmip1Mtx() ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*smP), {}, "cbc", "getMatrixByCol"); #endif // OSICBC_TEST_MTX_STRUCTURE } //-------------- // Test rowsense, rhs, rowrange, matrixByRow, solver assignment { OsiCbcSolverInterface lhs; { OsiCbcSolverInterface siC1(m); const char * siC1rs = siC1.getRowSense(); OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "cbc", "row sense"); const double * siC1rhs = siC1.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "cbc", "right hand side"); const double * siC1rr = siC1.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "cbc", "row range"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "cbc", "row range"); const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(siC1mbr != NULL, {}, "cbc", "matrix by row"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMajorDim() == 5, return, "cbc", "matrix by row: major dim"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMinorDim() == 8, return, "cbc", "matrix by row: major dim"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getNumElements() == 14, return, "cbc", "matrix by row: num elements"); OSIUNITTEST_ASSERT_ERROR(siC1mbr->getSizeVectorStarts() == 6, return, "cbc", "matrix by row: num elements"); #ifdef OSICBC_TEST_MTX_STRUCTURE const double * ev = siC1mbr->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "cbc", "matrix by row: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "matrix by row: elements"); const CoinBigIndex * mi = siC1mbr->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "matrix by row: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "matrix by row: vector starts"); const int * ei = siC1mbr->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "matrix by row: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "matrix by row: indices"); #else // OSICBC_TEST_MTX_STRUCTURE CoinPackedMatrix exmip1Mtx ; exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*siC1mbr), {}, "cbc", "matrix by row"); #endif // OSICBC_TEST_MTX_STRUCTURE OSIUNITTEST_ASSERT_WARNING(siC1rs == siC1.getRowSense(), {}, "cbc", "row sense"); OSIUNITTEST_ASSERT_WARNING(siC1rhs == siC1.getRightHandSide(), {}, "cbc", "right hand side"); OSIUNITTEST_ASSERT_WARNING(siC1rr == siC1.getRowRange(), {}, "cbc", "row range"); // Change CBC Model by adding free row OsiRowCut rc; rc.setLb(-COIN_DBL_MAX); rc.setUb( COIN_DBL_MAX); OsiCuts cuts; cuts.insert(rc); siC1.applyCuts(cuts); siC1rs = siC1.getRowSense(); OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "cbc", "row sense after adding row"); OSIUNITTEST_ASSERT_ERROR(siC1rs[5] == 'N', {}, "cbc", "row sense after adding row"); siC1rhs = siC1.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "cbc", "right hand side after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[5],0.0), {}, "cbc", "right hand side after adding row"); siC1rr = siC1.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "cbc", "row range after adding row"); OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[5],0.0), {}, "cbc", "row range after adding row"); lhs = siC1; } // Test that lhs has correct values even though siC1 has gone out of scope const char * lhsrs = lhs.getRowSense(); OSIUNITTEST_ASSERT_ERROR(lhsrs[0] == 'G', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[1] == 'L', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[2] == 'E', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[3] == 'R', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[4] == 'R', {}, "cbc", "row sense after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsrs[5] == 'N', {}, "cbc", "row sense after assignment"); const double * lhsrhs = lhs.getRightHandSide(); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[0],2.5), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[1],2.1), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[2],4.0), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[3],5.0), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[4],15.), {}, "cbc", "right hand side after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[5],0.0), {}, "cbc", "right hand side after assignment"); const double *lhsrr = lhs.getRowRange(); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[0],0.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[1],0.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[2],0.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[3],5.0-1.8), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[4],15.0-3.0), {}, "cbc", "row range after assignment"); OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[5],0.0), {}, "cbc", "row range after assignment"); const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow(); OSIUNITTEST_ASSERT_ERROR(lhsmbr != NULL, {}, "cbc", "matrix by row after assignment"); OSIUNITTEST_ASSERT_ERROR(lhsmbr->getMajorDim() == 6, return, "cbc", "matrix by row after assignment: major dim"); OSIUNITTEST_ASSERT_ERROR(lhsmbr->getNumElements() == 14, return, "cbc", "matrix by row after assignment: num elements"); #ifdef OSICBC_TEST_MTX_STRUCTURE const double * ev = lhsmbr->getElements(); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "cbc", "matrix by row after assignment: elements"); OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "matrix by row after assignment: elements"); const CoinBigIndex * mi = lhsmbr->getVectorStarts(); OSIUNITTEST_ASSERT_ERROR(mi[0] == 0, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[1] == 5, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[2] == 7, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[3] == 9, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "matrix by row after assignment: vector starts"); OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "matrix by row after assignment: vector starts"); const int * ei = lhsmbr->getIndices(); OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "matrix by row after assignment: indices"); OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "matrix by row after assignment: indices"); #else // OSICBC_TEST_MTX_STRUCTURE /* This admittedly looks bogus, but it's the equivalent operation on the matrix for inserting a cut of the form -Inf <= +Inf (i.e., a cut with no coefficients). */ CoinPackedMatrix exmip1Mtx ; exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ; CoinPackedVector freeRow ; exmip1Mtx.appendRow(freeRow) ; OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*lhsmbr), {}, "cbc", "matrix by row after assignment"); #endif // OSICBC_TEST_MTX_STRUCTURE } } // Test add/delete columns { OsiCbcSolverInterface m; std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); double inf = m.getInfinity(); CoinPackedVector c0; c0.insert(0, 4); c0.insert(1, 1); m.addCol(c0, 0, inf, 3); m.initialSolve(); double objValue = m.getObjValue(); CoinRelFltEq eq(1.0e-2); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "cbc", "objvalue after adding col"); // Try deleting first column that's nonbasic at lower bound (0). int * d = new int[1]; CoinWarmStartBasis *cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ; OSIUNITTEST_ASSERT_ERROR(cwsb != NULL, {}, "cbc", "get warmstart basis"); CoinWarmStartBasis::Status stati ; int iCol ; for (iCol = 0 ; iCol < cwsb->getNumStructural() ; iCol++) { stati = cwsb->getStructStatus(iCol) ; if (stati == CoinWarmStartBasis::atLowerBound) break ; } d[0]=iCol; m.deleteCols(1,d); delete [] d; delete cwsb; d=NULL; m.resolve(); objValue = m.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "clp", "objvalue after deleting first col"); // Try deleting column we added. If basic, go to initialSolve as deleting // basic variable trashes basis required for warm start. iCol = m.getNumCols()-1; cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ; stati = cwsb->getStructStatus(iCol) ; delete cwsb; m.deleteCols(1,&iCol); if (stati == CoinWarmStartBasis::basic) { m.initialSolve() ; } else { m.resolve(); } objValue = m.getObjValue(); OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "clp", "objvalue after deleting added col"); } // Build a model { OsiCbcSolverInterface model; std::string fn = mpsDir+"p0033"; model.readMps(fn.c_str(),"mps"); // Point to data int numberRows = model.getNumRows(); const double * rowLower = model.getRowLower(); const double * rowUpper = model.getRowUpper(); int numberColumns = model.getNumCols(); const double * columnLower = model.getColLower(); const double * columnUpper = model.getColUpper(); const double * columnObjective = model.getObjCoefficients(); // get row copy CoinPackedMatrix rowCopy = *model.getMatrixByRow(); const int * column = rowCopy.getIndices(); const int * rowLength = rowCopy.getVectorLengths(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); const double * element = rowCopy.getElements(); // solve model.initialSolve(); // Now build new model CoinModel build; // Row bounds int iRow; for (iRow=0;iRow<numberRows;iRow++) { build.setRowBounds(iRow,rowLower[iRow],rowUpper[iRow]); } // Column bounds and objective int iColumn; for (iColumn=0;iColumn<numberColumns;iColumn++) { build.setColumnLower(iColumn,columnLower[iColumn]); build.setColumnUpper(iColumn,columnUpper[iColumn]); build.setObjective(iColumn,columnObjective[iColumn]); } // Adds elements one by one by row (backwards by row) for (iRow=numberRows-1;iRow>=0;iRow--) { int start = rowStart[iRow]; for (int j=start;j<start+rowLength[iRow];j++) build(iRow,column[j],element[j]); } // Now create Model OsiCbcSolverInterface model2; model2.loadFromCoinModel(build); model2.initialSolve(); // Save - should be continuous model2.writeMps("continuous"); int * whichInteger = new int[numberColumns]; for (iColumn=0;iColumn<numberColumns;iColumn++) whichInteger[iColumn]=iColumn; // mark as integer model2.setInteger(whichInteger,numberColumns); delete [] whichInteger; // save - should be integer model2.writeMps("integer"); // Now do with strings attached // Save build to show how to go over rows CoinModel saveBuild = build; build = CoinModel(); // Column bounds for (iColumn=0;iColumn<numberColumns;iColumn++) { build.setColumnLower(iColumn,columnLower[iColumn]); build.setColumnUpper(iColumn,columnUpper[iColumn]); } // Objective - half the columns as is and half with multiplier of "1.0+multiplier" // Pick up from saveBuild (for no reason at all) for (iColumn=0;iColumn<numberColumns;iColumn++) { double value = saveBuild.objective(iColumn); if (iColumn*2<numberColumns) { build.setObjective(iColumn,columnObjective[iColumn]); } else { // create as string char temp[100]; sprintf(temp,"%g + abs(%g*multiplier)",value,value); build.setObjective(iColumn,temp); } } // It then adds rows one by one but for half the rows sets their values // with multiplier of "1.0+1.5*multiplier" for (iRow=0;iRow<numberRows;iRow++) { if (iRow*2<numberRows) { // add row in simple way int start = rowStart[iRow]; build.addRow(rowLength[iRow],column+start,element+start, rowLower[iRow],rowUpper[iRow]); } else { // As we have to add one by one let's get from saveBuild CoinModelLink triple=saveBuild.firstInRow(iRow); while (triple.column()>=0) { int iColumn = triple.column(); if (iColumn*2<numberColumns) { // just value as normal build(iRow,triple.column(),triple.value()); } else { // create as string char temp[100]; sprintf(temp,"%g + (1.5*%g*multiplier)",triple.value(), triple.value()); build(iRow,iColumn,temp); } triple=saveBuild.next(triple); } // but remember to do rhs build.setRowLower(iRow,rowLower[iRow]); build.setRowUpper(iRow,rowUpper[iRow]); } } // If small switch on error printing if (numberColumns<50) build.setLogLevel(1); // should fail as we never set multiplier OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build) != 0, {}, "cbc", "build model with missing multipliers"); build.associateElement("multiplier",0.0); OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build) == 0, {}, "cbc", "build model"); model2.initialSolve(); // It then loops with multiplier going from 0.0 to 2.0 in increments of 0.1 for (double multiplier=0.0;multiplier<2.0;multiplier+= 0.1) { build.associateElement("multiplier",multiplier); OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build,true) == 0, {}, "cbc", "build model with increasing multiplier"); model2.resolve(); } } // branch and bound { OsiCbcSolverInterface m; std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); m.initialSolve(); //m.messageHandler()->setLogLevel(0); m.getModelPtr()->messageHandler()->setLogLevel(0); m.branchAndBound(); } // branch and bound using CbcModel!!!!!!! { OsiCbcSolverInterface mm; OsiCbcSolverInterface m(&mm); std::string fn = mpsDir+"p0033"; m.readMps(fn.c_str(),"mps"); m.initialSolve(); m.branchAndBound(); } // Do common solverInterface testing { OsiCbcSolverInterface m; OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } { OsiCbcSolverInterface mm; OsiCbcSolverInterface m(&mm); OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } }
//-------------------------------------------------------------------------- // test 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; } }
//------------------------------------------------------------- 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 CglGMI::generateCuts(OsiCuts &cs) { isInteger = new bool[ncol]; computeIsInteger(); cstat = new int[ncol]; rstat = new int[nrow]; solver->getBasisStatus(cstat, rstat); // 0: free 1: basic // 2: upper 3: lower #if defined GMI_TRACETAB printvecINT("cstat", cstat, ncol); printvecINT("rstat", rstat, nrow); #endif // list of basic integer fractional variables int *listFracBasic = new int[nrow]; int numFracBasic = 0; for (int i = 0; i < ncol; ++i) { // j is the variable which is basic in row i if ((cstat[i] == 1) && (isInteger[i])) { if (CoinMin(aboveInteger(xlp[i]), 1-aboveInteger(xlp[i])) > param.getAway()) { listFracBasic[numFracBasic] = i; numFracBasic++; } #if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE else if (trackRejection) { // Say that we tried to generate a cut, but it was discarded // because of small fractionality if (!isIntegerValue(xlp[i])) { fracFail++; numGeneratedCuts++; } } #endif } } #if defined GMI_TRACE printf("CglGMI::generateCuts() : %d fractional rows\n", numFracBasic); #endif if (numFracBasic == 0) { delete[] listFracBasic; delete[] cstat; delete[] rstat; delete[] isInteger; return; } // there are rows with basic integer fractional variables, so we can // generate cuts // Basis index for columns and rows; each element is -1 if corresponding // variable is nonbasic, and contains the basis index if basic. // The basis index is the row in which the variable is basic. int* colBasisIndex = new int[ncol]; int* rowBasisIndex = new int[nrow]; #if defined OSI_TABLEAU memset(colBasisIndex, -1, ncol*sizeof(int)); memset(rowBasisIndex, -1, nrow*sizeof(int)); solver->enableFactorization(); int* basicVars = new int[nrow]; solver->getBasics(basicVars); for (int i = 0; i < nrow; ++i) { if (basicVars[i] < ncol) { colBasisIndex[basicVars[i]] = i; } else { rowBasisIndex[basicVars[i] - ncol] = i; } } #else CoinFactorization factorization; if (factorize(factorization, colBasisIndex, rowBasisIndex)) { printf("### WARNING: CglGMI::generateCuts(): error during factorization!\n"); return; } #endif // cut in sparse form double* cutElem = new double[ncol]; int* cutIndex = new int[ncol]; int cutNz = 0; double cutRhs; // cut in dense form double* cut = new double[ncol]; double *slackVal = new double[nrow]; for (int i = 0; i < nrow; ++i) { slackVal[i] = rowRhs[i] - rowActivity[i]; } #if defined OSI_TABLEAU // Column part and row part of a row of the simplex tableau double* tableauColPart = new double[ncol]; double* tableauRowPart = new double[nrow]; #else // Need some more data for simplex tableau computation const int * row = byCol->getIndices(); const CoinBigIndex * columnStart = byCol->getVectorStarts(); const int * columnLength = byCol->getVectorLengths(); const double * columnElements = byCol->getElements(); // Create work arrays for factorization // two vectors for updating: the first one is needed to do the computations // but we do not use it, the second one contains a row of the basis inverse CoinIndexedVector work; CoinIndexedVector array; // Make sure they large enough work.reserve(nrow); array.reserve(nrow); int * arrayRows = array.getIndices(); double * arrayElements = array.denseVector(); // End of code to create work arrays double one = 1.0; #endif // Matrix elements by row for slack substitution const double *elements = byRow->getElements(); const int *rowStart = byRow->getVectorStarts(); const int *indices = byRow->getIndices(); const int *rowLength = byRow->getVectorLengths(); // Indices of basic and slack variables, and cut elements int iBasic, slackIndex; double cutCoeff; double rowElem; // Now generate the cuts: obtain a row of the simplex tableau // where an integer variable is basic and fractional, and compute the cut for (int i = 0; i < numFracBasic; ++i) { if (!computeCutFractionality(xlp[listFracBasic[i]], cutRhs)) { // cut is discarded because of the small fractionalities involved #if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE if (trackRejection) { // Say that we tried to generate a cut, but it was discarded // because of small fractionality fracFail++; numGeneratedCuts++; } #endif continue; } // the variable listFracBasic[i] is basic in row iBasic iBasic = colBasisIndex[listFracBasic[i]]; #if defined GMI_TRACE printf("Row %d with var %d basic, f0 = %f\n", i, listFracBasic[i], f0); #endif #if defined OSI_TABLEAU solver->getBInvARow(iBasic, tableauColPart, tableauRowPart); #else array.clear(); array.setVector(1, &iBasic, &one); factorization.updateColumnTranspose (&work, &array); int numberInArray=array.getNumElements(); #endif // reset the cut memset(cut, 0, ncol*sizeof(double)); // columns for (int j = 0; j < ncol; ++j) { if ((colBasisIndex[j] >= 0) || (areEqual(colLower[j], colUpper[j], param.getEPS(), param.getEPS()))) { // Basic or fixed variable -- skip continue; } #ifdef OSI_TABLEAU rowElem = tableauColPart[j]; #else rowElem = 0.0; // add in row of tableau for (int h = columnStart[j]; h < columnStart[j]+columnLength[j]; ++h) { rowElem += columnElements[h]*arrayElements[row[h]]; } #endif if (!isZero(fabs(rowElem))) { // compute cut coefficient flip(rowElem, j); cutCoeff = computeCutCoefficient(rowElem, j); if (isZero(cutCoeff)) { continue; } unflipOrig(cutCoeff, j, cutRhs); cut[j] = cutCoeff; #if defined GMI_TRACE printf("var %d, row %f, cut %f\n", j, rowElem, cutCoeff); #endif } } // now do slacks part #if defined OSI_TABLEAU for (int j = 0 ; j < nrow; ++j) { // index of the row corresponding to the slack variable slackIndex = j; if (rowBasisIndex[j] >= 0) { // Basic variable -- skip it continue; } rowElem = tableauRowPart[j]; #else for (int j = 0 ; j < numberInArray ; ++j) { // index of the row corresponding to the slack variable slackIndex = arrayRows[j]; rowElem = arrayElements[slackIndex]; #endif if (!isZero(fabs(rowElem))) { slackIndex += ncol; // compute cut coefficient flip(rowElem, slackIndex); cutCoeff = computeCutCoefficient(rowElem, slackIndex); if (isZero(fabs(cutCoeff))) { continue; } unflipSlack(cutCoeff, slackIndex, cutRhs, slackVal); eliminateSlack(cutCoeff, slackIndex, cut, cutRhs, elements, rowStart, indices, rowLength, rowRhs); #if defined GMI_TRACE printf("var %d, row %f, cut %f\n", slackIndex, rowElem, cutCoeff); #endif } } packRow(cut, cutElem, cutIndex, cutNz); if (cutNz == 0) continue; #if defined GMI_TRACE printvecDBL("final cut:", cutElem, cutIndex, cutNz); printf("cutRhs: %f\n", cutRhs); #endif #if defined TRACK_REJECT || defined TRACK_REJECT_SIMPLE if (trackRejection) { numGeneratedCuts++; } #endif if (cleanCut(cutElem, cutIndex, cutNz, cutRhs, xlp) && cutNz > 0) { OsiRowCut rc; rc.setRow(cutNz, cutIndex, cutElem); rc.setLb(-param.getINFINIT()); rc.setUb(cutRhs); if (!param.getCHECK_DUPLICATES()) { cs.insert(rc); } else{ cs.insertIfNotDuplicate(rc, CoinAbsFltEq(param.getEPS_COEFF())); } } } #if defined GMI_TRACE printf("CglGMI::generateCuts() : number of cuts : %d\n", cs.sizeRowCuts()); #endif #if defined OSI_TABLEAU solver->disableFactorization(); delete[] basicVars; delete[] tableauColPart; delete[] tableauRowPart; #endif delete[] colBasisIndex; delete[] rowBasisIndex; delete[] cut; delete[] slackVal; delete[] cutElem; delete[] cutIndex; delete[] listFracBasic; delete[] cstat; delete[] rstat; delete[] isInteger; } /* generateCuts */ /***********************************************************************/ void CglGMI::setParam(const CglGMIParam &source) { param = source; } /* setParam */ /***********************************************************************/ void CglGMI::computeIsInteger() { for (int i = 0; i < ncol; ++i) { if(solver->isInteger(i)) { isInteger[i] = true; } else { if((areEqual(colLower[i], colUpper[i], param.getEPS(), param.getEPS())) && (isIntegerValue(colUpper[i]))) { // continuous variable fixed to an integer value isInteger[i] = true; } else { isInteger[i] = false; } } } } /* computeIsInteger */ /***********************************************************************/ void CglGMI::printOptTab(OsiSolverInterface *lclSolver) const { int *cstat = new int[ncol]; int *rstat = new int[nrow]; lclSolver->enableFactorization(); lclSolver->getBasisStatus(cstat, rstat); // 0: free 1: basic // 2: upper 3: lower int *basisIndex = new int[nrow]; // basisIndex[i] = // index of pivot var in row i // (slack if number >= ncol) lclSolver->getBasics(basisIndex); double *z = new double[ncol]; // workspace to get row of the tableau double *slack = new double[nrow]; // workspace to get row of the tableau double *slackVal = new double[nrow]; for (int i = 0; i < nrow; i++) { slackVal[i] = rowRhs[i] - rowActivity[i]; } const double *rc = lclSolver->getReducedCost(); const double *dual = lclSolver->getRowPrice(); const double *solution = lclSolver->getColSolution(); printvecINT("cstat", cstat, ncol); printvecINT("rstat", rstat, nrow); printvecINT("basisIndex", basisIndex, nrow); printvecDBL("solution", solution, ncol); printvecDBL("slackVal", slackVal, nrow); printvecDBL("reduced_costs", rc, ncol); printvecDBL("dual solution", dual, nrow); printf("Optimal Tableau:\n"); for (int i = 0; i < nrow; i++) { lclSolver->getBInvARow(i, z, slack); for (int ii = 0; ii < ncol; ++ii) { printf("%5.2f ", z[ii]); } printf(" | "); for (int ii = 0; ii < nrow; ++ii) { printf("%5.2f ", slack[ii]); } printf(" | "); if(basisIndex[i] < ncol) { printf("%5.2f ", solution[basisIndex[i]]); } else { printf("%5.2f ", slackVal[basisIndex[i]-ncol]); } printf("\n"); } for (int ii = 0; ii < 7*(ncol+nrow+1); ++ii) { printf("-"); } printf("\n"); for (int ii = 0; ii < ncol; ++ii) { printf("%5.2f ", rc[ii]); } printf(" | "); for (int ii = 0; ii < nrow; ++ii) { printf("%5.2f ", -dual[ii]); } printf(" | "); printf("%5.2f\n", -lclSolver->getObjValue()); lclSolver->disableFactorization(); delete[] cstat; delete[] rstat; delete[] basisIndex; delete[] slack; delete[] z; delete[] slackVal; } /* printOptTab */
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); } }
//----------------------------------------------------------------------------- // 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; }
/** 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; }
//-------------------------------------------------------------------------- void CglKnapsackCoverUnitTest( const OsiSolverInterface * baseSiP, const std::string mpsDir ) { int i; CoinRelFltEq eq(0.000001); // Test default constructor { CglKnapsackCover kccGenerator; } // Test copy & assignment { CglKnapsackCover rhs; { CglKnapsackCover kccGenerator; CglKnapsackCover cgC(kccGenerator); rhs=kccGenerator; } } // test exactSolveKnapsack { CglKnapsackCover kccg; const int n=7; double c=50; double p[n] = {70,20,39,37,7,5,10}; double w[n] = {31, 10, 20, 19, 4, 3, 6}; double z; int x[n]; int exactsol = kccg.exactSolveKnapsack(n, c, p, w, z, x); assert(exactsol==1); assert (z == 107); assert (x[0]==1); assert (x[1]==0); assert (x[2]==0); assert (x[3]==1); assert (x[4]==0); assert (x[5]==0); assert (x[6]==0); } /* // Testcase /u/rlh/osl2/mps/scOneInt.mps // Model has 3 continous, 2 binary, and 1 general // integer variable. { OsiSolverInterface * siP = baseSiP->clone(); int * complement=NULL; double * xstar=NULL; siP->readMps("../Mps/scOneInt","mps"); CglKnapsackCover kccg; int nCols=siP->getNumCols(); // Test the siP methods for detecting // variable type int numCont=0, numBinary=0, numIntNonBinary=0, numInt=0; for (int thisCol=0; thisCol<nCols; thisCol++) { if ( siP->isContinuous(thisCol) ) numCont++; if ( siP->isBinary(thisCol) ) numBinary++; if ( siP->isIntegerNonBinary(thisCol) ) numIntNonBinary++; if ( siP->isInteger(thisCol) ) numInt++; } assert(numCont==3); assert(numBinary==2); assert(numIntNonBinary==1); assert(numInt==3); // Test initializeCutGenerator siP->initialSolve(); assert(xstar !=NULL); for (i=0; i<nCols; i++){ assert(complement[i]==0); } int nRows=siP->getNumRows(); for (i=0; i<nRows; i++){ int vectorsize = siP->getMatrixByRow()->vectorSize(i); assert(vectorsize==2); } kccg.cleanUpCutGenerator(complement,xstar); delete siP; } */ // Testcase /u/rlh/osl2/mps/tp3.mps // Models has 3 cols, 3 rows // Row 0 yields a knapsack, others do not. { // setup OsiSolverInterface * siP = baseSiP->clone(); std::string fn(mpsDir+"tp3"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); OsiCuts cs; CoinPackedVector krow; double b=0; int nCols=siP->getNumCols(); int * complement=new int [nCols]; double * xstar=new double [nCols]; CglKnapsackCover kccg; // solve LP relaxation // a "must" before calling initialization siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); std::cout<<"Initial LP value: "<<lpRelaxBefore<<std::endl; assert( eq(siP->getObjValue(), 97.185) ); double mycs[] = {.627, .667558333333, .038}; siP->setColSolution(mycs); const double *colsol = siP->getColSolution(); int k; for (k=0; k<nCols; k++){ xstar[k]=colsol[k]; complement[k]=0; } // test deriveAKnapsack int rind = ( siP->getRowSense()[0] == 'N' ) ? 1 : 0; const CoinShallowPackedVector reqdBySunCC = siP->getMatrixByRow()->getVector(rind) ; int deriveaknap = kccg.deriveAKnapsack(*siP, cs, krow,b,complement,xstar,rind,reqdBySunCC); assert(deriveaknap ==1); assert(complement[0]==0); assert(complement[1]==1); assert(complement[2]==1); int inx[3] = {0,1,2}; double el[3] = {161, 120, 68}; CoinPackedVector r; r.setVector(3,inx,el); assert (krow == r); //assert (b == 183.0); ????? but x1 and x2 at 1 is valid // test findGreedyCover CoinPackedVector cover,remainder; #if 0 int findgreedy = kccg.findGreedyCover( 0, krow, b, xstar, cover, remainder ); assert( findgreedy == 1 ); int coveri = cover.getNumElements(); assert( cover.getNumElements() == 2); coveri = cover.getIndices()[0]; assert( cover.getIndices()[0] == 0); assert( cover.getIndices()[1] == 1); assert( cover.getElements()[0] == 161.0); assert( cover.getElements()[1] == 120.0); assert( remainder.getNumElements() == 1); assert( remainder.getIndices()[0] == 2); assert( remainder.getElements()[0] == 68.0); // test liftCoverCut CoinPackedVector cut; double * rowupper = ekk_rowupper(model); double cutRhs = cover.getNumElements() - 1.0; kccg.liftCoverCut(b, krow.getNumElements(), cover, remainder, cut); assert ( cut.getNumElements() == 3 ); assert ( cut.getIndices()[0] == 0 ); assert ( cut.getIndices()[1] == 1 ); assert ( cut.getIndices()[2] == 2 ); assert( cut.getElements()[0] == 1 ); assert( cut.getElements()[1] == 1 ); assert( eq(cut.getElements()[2], 0.087719) ); // test liftAndUncomplementAndAdd OsiCuts cuts; kccg.liftAndUncomplementAndAdd(*siP.getRowUpper()[0],krow,b,complement,0, cover,remainder,cuts); int sizerowcuts = cuts.sizeRowCuts(); assert ( sizerowcuts== 1 ); OsiRowCut testRowCut = cuts.rowCut(0); CoinPackedVector testRowPV = testRowCut.row(); OsiRowCut sampleRowCut; const int sampleSize = 3; int sampleCols[sampleSize]={0,1,2}; double sampleElems[sampleSize]={1.0,-1.0,-0.087719}; sampleRowCut.setRow(sampleSize,sampleCols,sampleElems); sampleRowCut.setLb(-DBL_MAX); sampleRowCut.setUb(-0.087719); bool equiv = testRowPV.equivalent(sampleRowCut.row(),CoinRelFltEq(1.0e-05) ); assert ( equiv ); #endif // test find PseudoJohnAndEllisCover cover.setVector(0,NULL, NULL); remainder.setVector(0,NULL,NULL); rind = ( siP->getRowSense()[0] == 'N' ) ? 1 : 0; int findPJE = kccg.findPseudoJohnAndEllisCover( rind, krow, b, xstar, cover, remainder ); assert( findPJE == 1 ); assert ( cover.getIndices()[0] == 0 ); assert ( cover.getIndices()[1] == 2 ); assert ( cover.getElements()[0] == 161 ); assert ( cover.getElements()[1] == 68 ); assert ( remainder.getIndices()[0] == 1 ); assert ( remainder.getElements()[0] == 120 ); OsiCuts cuts; kccg.liftAndUncomplementAndAdd((*siP).getRowUpper()[rind],krow,b, complement, rind, cover,remainder,cuts); assert (cuts.sizeRowCuts() == 1 ); OsiRowCut testRowCut = cuts.rowCut(0); CoinPackedVector testRowPV = testRowCut.row(); const int sampleSize = 3; int sampleCols[sampleSize]={0,1,2}; double sampleElems[sampleSize]={1.0, -1.0, -1.0}; OsiRowCut sampleRowCut; sampleRowCut.setRow(sampleSize,sampleCols,sampleElems); sampleRowCut.setLb(-COIN_DBL_MAX); sampleRowCut.setUb(-1.0); // test for 'close enough' assert( testRowPV.isEquivalent(sampleRowCut.row(),CoinRelFltEq(1.0e-05) ) ); // Reset complement & test next row for (i=0; i<nCols; i++){ complement[i]=0; } rind++; const CoinShallowPackedVector reqdBySunCC2 = siP->getMatrixByRow()->getVector(rind) ; deriveaknap = kccg.deriveAKnapsack(*siP,cuts,krow,b,complement,xstar,rind,reqdBySunCC2); assert(deriveaknap==0); // Reset complement & test next row for (i=0; i<nCols; i++){ complement[i]=0; } const CoinShallowPackedVector reqdBySunCC3 = siP->getMatrixByRow()->getVector(2) ; deriveaknap = kccg.deriveAKnapsack(*siP,cuts,krow,b,complement,xstar,2, reqdBySunCC3); assert(deriveaknap == 0); // Clean up delete [] complement; delete [] xstar; delete siP; } #if 0 // Testcase /u/rlh/osl2/mps/tp4.mps // Models has 6 cols, 1 knapsack row and // 3 rows explicily bounding variables // Row 0 yields a knapsack cover cut // using findGreedyCover which moves the // LP objective function value. { // Setup EKKContext * env=ekk_initializeContext(); EKKModel * model = ekk_newModel(env,""); OsiSolverInterface si(model); ekk_importModel(model, "tp4.mps"); CglKnapsackCover kccg; kccg.ekk_validateIntType(si); // Solve the LP relaxation of the model and // print out ofv for sake of comparison ekk_allSlackBasis(model); ekk_crash(model,1); ekk_primalSimplex(model,1); double lpRelaxBefore=ekk_getRobjvalue(model); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif // Determine if lp sol is ip optimal // Note: no ekk_function to do this int nCols=ekk_getInumcols(model); double * optLpSol = ekk_colsol(model); int ipOpt = 1; i=0; while (i++<nCols && ipOpt){ if(optLpSol[i] < 1.0-1.0e-08 && optLpSol[i]> 1.0e-08) ipOpt = 0; } if (ipOpt){ #ifdef CGL_DEBUG printf("Lp solution is within ip optimality tolerance\n"); #endif } else { OsiSolverInterface iModel(model); OsiCuts cuts; // Test generateCuts method kccg.generateCuts(iModel,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = iModel.applyCuts(cuts); ekk_mergeBlocks(model,1); ekk_dualSimplex(model); double lpRelaxAfter=ekk_getRobjvalue(model); #ifdef CGL_DEBUG printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore < lpRelaxAfter ); // This may need to be updated as other // minimal cover finders are added assert( cuts.sizeRowCuts() == 1 ); OsiRowCut testRowCut = cuts.rowCut(0); CoinPackedVector testRowPV = testRowCut.row(); OsiRowCut sampleRowCut; const int sampleSize = 6; int sampleCols[sampleSize]={0,1,2,3,4,5}; double sampleElems[sampleSize]={1.0,1.0,1.0,1.0,0.5, 2.0}; sampleRowCut.setRow(sampleSize,sampleCols,sampleElems); sampleRowCut.setLb(-DBL_MAX); sampleRowCut.setUb(3.0); bool equiv = testRowPV.equivalent(sampleRowCut.row(),CoinRelFltEq(1.0e-05) ); assert( testRowPV.equivalent(sampleRowCut.row(),CoinRelFltEq(1.0e-05) ) ); } // Exit out of OSL ekk_deleteModel(model); ekk_endContext(env); } #endif // Testcase /u/rlh/osl2/mps/tp5.mps // Models has 6 cols, 1 knapsack row and // 3 rows explicily bounding variables // Row 0 yields a knapsack cover cut // using findGreedyCover which moves the // LP objective function value. { // Setup OsiSolverInterface * siP = baseSiP->clone(); std::string fn(mpsDir+"tp5"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); CglKnapsackCover kccg; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, -51.66666666667) ); double mycs[] = {.8999999999, .899999999999, .89999999999, 1.110223e-16, .5166666666667, 0}; siP->setColSolution(mycs); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif // Determine if lp sol is 0/1 optimal int nCols=siP->getNumCols(); const double * optLpSol = siP->getColSolution(); bool ipOpt = true; i=0; while (i++<nCols && ipOpt){ if(optLpSol[i] > kccg.epsilon_ && optLpSol[i] < kccg.onetol_) ipOpt = false; } if (ipOpt){ #ifdef CGL_DEBUG printf("Lp solution is within ip optimality tolerance\n"); #endif } else { // set up OsiCuts cuts; CoinPackedVector krow; double b=0.0; int * complement=new int[nCols]; double * xstar=new double[nCols]; // initialize cut generator const double *colsol = siP->getColSolution(); for (i=0; i<nCols; i++){ xstar[i]=colsol[i]; complement[i]=0; } int row = ( siP->getRowSense()[0] == 'N' ) ? 1 : 0; // transform row into canonical knapsack form const CoinShallowPackedVector reqdBySunCC = siP->getMatrixByRow()->getVector(row) ; if (kccg.deriveAKnapsack(*siP, cuts, krow, b, complement, xstar, row,reqdBySunCC)){ CoinPackedVector cover, remainder; // apply greedy logic to detect violated minimal cover inequalities if (kccg.findGreedyCover(row, krow, b, xstar, cover, remainder) == 1){ // lift, uncomplements, and add cut to cut set kccg.liftAndUncomplementAndAdd((*siP).getRowUpper()[row],krow, b, complement, row, cover, remainder, cuts); } // reset optimal column solution (xstar) information in OSL const double * rowupper = siP->getRowUpper(); int k; if (fabs(b-rowupper[row]) > 1.0e-05) { for(k=0; k<krow.getNumElements(); k++) { if (complement[krow.getIndices()[k]]){ xstar[krow.getIndices()[k]]= 1.0-xstar[krow.getIndices()[k]]; complement[krow.getIndices()[k]]=0; } } } // clean up delete [] complement; delete [] xstar; } // apply the cuts OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); assert( eq(lpRelaxAfter, -30.0) ); #ifdef CGL_DEBUG printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif // test that expected cut was detected assert( lpRelaxBefore < lpRelaxAfter ); assert( cuts.sizeRowCuts() == 1 ); OsiRowCut testRowCut = cuts.rowCut(0); CoinPackedVector testRowPV = testRowCut.row(); OsiRowCut sampleRowCut; const int sampleSize = 6; int sampleCols[sampleSize]={0,1,2,3,4,5}; double sampleElems[sampleSize]={1.0,1.0,1.0,0.25,1.0,2.0}; sampleRowCut.setRow(sampleSize,sampleCols,sampleElems); sampleRowCut.setLb(-COIN_DBL_MAX); sampleRowCut.setUb(3.0); assert(testRowPV.isEquivalent(sampleRowCut.row(),CoinRelFltEq(1.0e-05))); } delete siP; } // Testcase /u/rlh/osl2/mps/p0033 // Miplib3 problem p0033 // Test that no cuts chop off the optimal solution { // Setup OsiSolverInterface * siP = baseSiP->clone(); std::string fn(mpsDir+"p0033"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); int nCols=siP->getNumCols(); CglKnapsackCover kccg; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, 2520.5717391304347) ); double mycs[] = {0, 1, 0, 0, -2.0837010502455788e-19, 1, 0, 0, 1, 0.021739130434782594, 0.35652173913043478, -6.7220534694101275e-18, 5.3125906451789717e-18, 1, 0, 1.9298798670241979e-17, 0, 0, 0, 7.8875708048320448e-18, 0.5, 0, 0.85999999999999999, 1, 1, 0.57999999999999996, 1, 0, 1, 0, 0.25, 0, 0.67500000000000004}; siP->setColSolution(mycs); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif OsiCuts cuts; // Test generateCuts method kccg.generateCuts(*siP,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); assert( eq(lpRelaxAfter, 2829.0597826086955) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore < lpRelaxAfter ); // the CoinPackedVector p0033 is the optimal // IP solution to the miplib problem p0033 int objIndices[14] = { 0, 6, 7, 9, 13, 17, 18, 22, 24, 25, 26, 27, 28, 29 }; CoinPackedVector p0033(14,objIndices,1.0); // Sanity check const double * objective=siP->getObjCoefficients(); double ofv =0 ; int r; for (r=0; r<nCols; r++){ ofv=ofv + p0033[r]*objective[r]; } CoinRelFltEq eq; assert( eq(ofv,3089.0) ); int nRowCuts = cuts.sizeRowCuts(); OsiRowCut rcut; CoinPackedVector rpv; for (i=0; i<nRowCuts; i++){ rcut = cuts.rowCut(i); rpv = rcut.row(); double p0033Sum = (rpv*p0033).sum(); assert (p0033Sum <= rcut.ub() ); } delete siP; } // if a debug file is there then look at it { FILE * fp = fopen("knapsack.debug","r"); if (fp) { int ncol,nel; double up; int x = fscanf(fp,"%d %d %lg",&ncol,&nel,&up); if (x<=0) throw("bad fscanf"); printf("%d columns, %d elements, upper %g\n",ncol,nel,up); double * sol1 = new double[nel]; double * el1 = new double[nel]; int * col1 = new int[nel]; CoinBigIndex * start = new CoinBigIndex [ncol+1]; memset(start,0,ncol*sizeof(CoinBigIndex )); int * row = new int[nel]; int i; for (i=0;i<nel;i++) { x=fscanf(fp,"%d %lg %lg",col1+i,el1+i,sol1+i); if (x<=0) throw("bad fscanf"); printf("[%d, e=%g, v=%g] ",col1[i],el1[i],sol1[i]); start[col1[i]]=1; row[i]=0; } printf("\n"); // Setup OsiSolverInterface * siP = baseSiP->clone(); double lo=-1.0e30; double * upper = new double[ncol]; start[ncol]=nel; int last=0; for (i=0;i<ncol;i++) { upper[i]=1.0; int marked=start[i]; start[i]=last; if (marked) last++; } siP->loadProblem(ncol,1,start,row,el1,NULL,upper,NULL,&lo,&up); // use upper for solution memset(upper,0,ncol*sizeof(double)); for (i=0;i<nel;i++) { int icol=col1[i]; upper[icol]=sol1[i]; siP->setInteger(icol); } siP->setColSolution(upper); delete [] sol1; delete [] el1; delete [] col1; delete [] start; delete [] row; delete [] upper; CglKnapsackCover kccg; OsiCuts cuts; // Test generateCuts method kccg.generateCuts(*siP,cuts); // print out and compare to known cuts int numberCuts = cuts.sizeRowCuts(); if (numberCuts) { for (i=0;i<numberCuts;i++) { OsiRowCut * thisCut = cuts.rowCutPtr(i); int n=thisCut->row().getNumElements(); printf("Cut %d has %d entries, rhs %g %g =>",i,n,thisCut->lb(), thisCut->ub()); int j; const int * index = thisCut->row().getIndices(); const double * element = thisCut->row().getElements(); for (j=0;j<n;j++) { printf(" (%d,%g)",index[j],element[j]); } printf("\n"); } } fclose(fp); } } // Testcase /u/rlh/osl2/mps/p0201 // Miplib3 problem p0282 // Test that no cuts chop off the optimal ip solution { // Setup OsiSolverInterface * siP = baseSiP->clone(); std::string fn(mpsDir+"p0201"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); const int nCols=siP->getNumCols(); CglKnapsackCover kccg; // Solve the LP relaxation of the model and // print out ofv for sake of comparisn siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, 6875.) ); double mycs[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; siP->setColSolution(mycs); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); #endif OsiCuts cuts; // Test generateCuts method kccg.generateCuts(*siP,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); assert( eq(lpRelaxAfter, 7125) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore < lpRelaxAfter ); // Optimal IP solution to p0201 int objIndices[22] = { 8, 10, 21, 38, 39, 56, 60, 74, 79, 92, 94, 110, 111, 128, 132, 146, 151,164, 166, 182,183, 200 }; CoinPackedVector p0201(22,objIndices,1.0); // Sanity check const double * objective=siP->getObjCoefficients(); double ofv =0 ; int r; for (r=0; r<nCols; r++){ ofv=ofv + p0201[r]*objective[r]; } CoinRelFltEq eq; assert( eq(ofv,7615.0) ); //printf("p0201 optimal ofv = %g\n",ofv); int nRowCuts = cuts.sizeRowCuts(); OsiRowCut rcut; CoinPackedVector rpv; for (i=0; i<nRowCuts; i++){ rcut = cuts.rowCut(i); rpv = rcut.row(); double p0201Sum = (rpv*p0201).sum(); assert (p0201Sum <= rcut.ub() ); } delete siP; } // see if I get the same covers that N&W get { OsiSolverInterface * siP=baseSiP->clone(); std::string fn(mpsDir+"nw460"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); CglKnapsackCover kccg; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, -225.68951787852194) ); double mycs[] = {0.7099213482046447, 0, 0.34185802225477174, 1, 1, 0, 1, 1, 0}; siP->setColSolution(mycs); OsiCuts cuts; // Test generateCuts method kccg.generateCuts(*siP,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); assert( eq(lpRelaxAfter, -176) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif #ifdef MJS assert( lpRelaxBefore < lpRelaxAfter ); #endif int nRowCuts = cuts.sizeRowCuts(); OsiRowCut rcut; CoinPackedVector rpv; for (i=0; i<nRowCuts; i++){ rcut = cuts.rowCut(i); rpv = rcut.row(); int j; printf("Row cut number %i has rhs = %g\n",i,rcut.ub()); for (j=0; j<rpv.getNumElements(); j++){ printf("index %i, element %g\n", rpv.getIndices()[j], rpv.getElements()[j]); } printf("\n"); } delete siP; } // Debugging: try "exmip1.mps" { // Setup OsiSolverInterface * siP = baseSiP->clone(); std::string fn(mpsDir+"exmip1"); siP->readMps(fn.c_str(),"mps"); // All integer variables should be binary. // Assert that this is true. for ( i = 0; i < siP->getNumCols(); i++ ) if ( siP->isInteger(i) ) assert(siP->getColUpper()[i]==1.0 && siP->isBinary(i)); CglKnapsackCover kccg; // Solve the LP relaxation of the model and // print out ofv for sake of comparison siP->initialSolve(); double lpRelaxBefore=siP->getObjValue(); assert( eq(lpRelaxBefore, 3.2368421052631575) ); double mycs[] = {2.5, 0, 0, 0.6428571428571429, 0.5, 4, 0, 0.26315789473684253}; siP->setColSolution(mycs); // Test generateCuts method OsiCuts cuts; kccg.generateCuts(*siP,cuts); OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts); siP->resolve(); double lpRelaxAfter=siP->getObjValue(); assert( eq(lpRelaxAfter, 3.2368421052631575) ); #ifdef CGL_DEBUG printf("\n\nOrig LP min=%f\n",lpRelaxBefore); printf("\n\nFinal LP min=%f\n",lpRelaxAfter); #endif assert( lpRelaxBefore <= lpRelaxAfter ); delete siP; } #ifdef CGL_DEBUG // See what findLPMostViolatedMinCover for knapsack with 2 elements does { int nCols = 2; int row = 1; CoinPackedVector krow; double e[2] = {5,10}; int ii[2] = {0,1}; krow.setVector(nCols,ii,e); double b=11; double xstar[2] = {.2,.9}; CoinPackedVector cover; CoinPackedVector remainder; CglKnapsackCover kccg; kccg.findLPMostViolatedMinCover(nCols, row, krow, b, xstar, cover, remainder); printf("num in cover = %i\n",cover.getNumElements()); int j; for (j=0; j<cover.getNumElements(); j++){ printf(" index %i element % g\n", cover.getIndices()[j], cover.getElements()[j]); } } #endif #ifdef CGL_DEBUG // see what findLPMostViolatedMinCover does { int nCols = 5; int row = 1; CoinPackedVector krow; double e[5] = {1,1,1,1,10}; int ii[5] = {0,1,2,3,4}; krow.setVector(nCols,ii,e); double b=11; double xstar[5] = {.9,.9,1,1,.1}; CoinPackedVector cover; CoinPackedVector remainder; CglKnapsackCover kccg; kccg.findLPMostViolatedMinCover(nCols, row, krow, b, xstar, cover, remainder); printf("num in cover = %i\n",cover.getNumElements()); int j; for (j=0; j<cover.getNumElements(); j++){ printf(" index %i element % g\n", cover.getIndices()[j], cover.getElements()[j]); } } #endif }
//------------------------------------------------------------------- // Generate cuts //------------------------------------------------------------------- void CglAllDifferent::generateCuts(const OsiSolverInterface & si, OsiCuts & cs, const CglTreeInfo ) const { #ifndef NDEBUG int nCols=si.getNumCols(); #endif int i; const double * lower = si.getColLower(); const double * upper = si.getColUpper(); #ifdef CGL_DEBUG const OsiRowCutDebugger * debugger = si.getRowCutDebugger(); if (debugger&&debugger->onOptimalPath(si)) { printf("On optimal path %d\n",nPath); nPath++; int nCols=si.getNumCols(); const double * solution = si.getColSolution(); const double * optimal = debugger->optimalSolution(); const double * objective = si.getObjCoefficients(); double objval1=0.0,objval2=0.0; for (i=0;i<nCols;i++) { #if CGL_DEBUG>1 printf("%d %g %g %g %g\n",i,lower[i],solution[i],upper[i],optimal[i]); #endif objval1 += solution[i]*objective[i]; objval2 += optimal[i]*objective[i]; assert(optimal[i]>=lower[i]&&optimal[i]<=upper[i]); } printf("current obj %g, integer %g\n",objval1,objval2); } #endif int * lo = new int[numberDifferent_]; int * up = new int[numberDifferent_]; for (i=0;i<numberDifferent_;i++) { int iColumn = originalWhich_[i]; assert (iColumn<nCols); lo[i] = static_cast<int> (lower[iColumn]); assert (floor(lower[iColumn]+0.5)==lower[iColumn]); up[i] = static_cast<int> (upper[iColumn]); assert (floor(upper[iColumn]+0.5)==upper[iColumn]); assert (up[i]>=lo[i]); } // We are going to assume we can just have one big 2d array! // Could save by going to bits // also could skip sets where all are fixed // could do some of above by separate first pass // once a variable fixed - can take out of list // so need to redo complete stuff (including temp which_) every big pass int offset = COIN_INT_MAX; int maxValue = -COIN_INT_MAX; int numberLook=0; // copies //int * which = new int [numberTotal]; //int * start = new int [numberSets_+1]; for (i=0;i<numberSets_;i++) { for (int j=start_[i];j<start_[i+1];j++) { int k=which_[j]; offset = CoinMin(offset,lo[k]); maxValue = CoinMax(maxValue,up[k]); } numberLook++; int gap = maxValue-offset+1; double size = static_cast<double> (gap) * numberDifferent_; if (size>1.0e7) { if (logLevel_) printf("Only looking at %d sets\n",numberLook); break; } } // Which sets a variable is in int * back = new int [start_[numberSets_]]; int * backStart = new int[numberDifferent_+1]; memset(backStart,0,(numberDifferent_+1)*sizeof(int)); int numberTotal = start_[numberLook]; for (i=0;i<numberTotal;i++) { int k=which_[i]; // note +1 backStart[k+1]++; } int n=0; for (i=0;i<numberDifferent_;i++) { int nThis = backStart[i+1]; backStart[i+1]=n; n+= nThis; } // at end all backStart correct! for (i=0;i<numberLook;i++) { for (int j=start_[i];j<start_[i+1];j++) { int k=which_[j]; // note +1 int iPut = backStart[k+1]; back[iPut]=i; backStart[k+1]=iPut+1; } } // value is possible for variable k if possible[k*gap+value] is nonzero int gap = maxValue-offset+1; char * possible = new char[gap*numberDifferent_]; memset(possible,0,gap*numberDifferent_); // initialize int numberFixed=0; int * alreadyFixed = new int[numberDifferent_]; for (i=0;i<numberDifferent_;i++) { alreadyFixed[i]=-1; int startV = i*gap + lo[i] - offset; int n = up[i]-lo[i]+1; memset(possible+startV,1,n); } for (i=0;i<numberDifferent_;i++) { int n = up[i]-lo[i]+1; if (n==1) { int fixedAt = lo[i]-offset; numberFixed++; alreadyFixed[i]=fixedAt; // take out of all others for (int j=backStart[i];j<backStart[i+1];j++) { int iSet = back[j]; for (int jj=start_[iSet];jj<start_[iSet+1];jj++) { int k=which_[jj]; if (k!=i) { // impossible possible[k*gap+fixedAt]=0; } } } } } bool finished=false; //int numberTightened=0; bool infeasible=false; // space to see which values possible int * check = new int[gap]; unsigned int * bitmap = new unsigned int[numberDifferent_]; int * stack = new int[numberDifferent_+1]; int * first = new int[numberDifferent_+1]; // just for valgrind etc memset(stack,0,(numberDifferent_+1)*sizeof(int)); memset(first,0,(numberDifferent_+1)*sizeof(int)); // do one set at a time while (!finished) { finished=true; int fixed=numberFixed; for (i=0;i<numberLook;i++) { memset(check,0,gap*sizeof(int)); for (int j=start_[i];j<start_[i+1];j++) { int k=which_[j]; if (alreadyFixed[k]>=0) { if (check[alreadyFixed[k]]==0) { check[alreadyFixed[k]]=1; continue; } else { // infeasible infeasible=true; i=numberLook; break; } } char * allowed = possible + k*gap; int n=0; for (int jj=0;jj<gap;jj++) { if (allowed[jj]) { n++; check[jj]++; } } if (n<2) { if (n==1) { // fix int fixedAt = -1; for (int jj=0;jj<gap;jj++) { if (allowed[jj]) { fixedAt=jj; break; } } numberFixed++; alreadyFixed[k]=fixedAt; check[fixedAt]=1; // take out of all others for (int j=backStart[k];j<backStart[k+1];j++) { int iSet = back[j]; for (int jj=start_[iSet];jj<start_[iSet+1];jj++) { int kk=which_[jj]; if (kk!=k) { // impossible possible[kk*gap+fixedAt]=0; } } } } else { // infeasible infeasible=true; j=numberTotal; i=numberLook; break; } } } // now check set // If number covered < number in set infeasible if (gap<30&&!infeasible) { int n=start_[i+1]-start_[i]; memset(bitmap,0,n*sizeof(unsigned int)); int j; int * which = which_+start_[i]; unsigned int covered=0; bool good=true; for (j=0;j<n;j++) { int k=which[j]; char * allowed = possible + k*gap; int jj; for (jj=0;jj<gap;jj++) if (allowed[jj]) break; assert (jj<gap); first[j]=jj; unsigned int iBit = 1<<jj; if ((covered&iBit)==0) { stack[j]=jj; covered |= iBit; } else { // can't jj++; for (;jj<gap;jj++) { iBit = iBit << 1; if (allowed[jj]&&(covered&iBit)==0) break; } if (jj<gap) { stack[j]=jj; covered |= iBit; } else { good = false; break; } } } int nStack=j; // just do first for rest for (;j<n;j++) { int k=which[j]; char * allowed = possible + k*gap; int jj; for (jj=0;jj<gap;jj++) if (allowed[jj]) break; assert (jj<gap); first[j]=jj; } int kLook=0; while (nStack) { nStack--; if (good) { #if 0 printf("con %d = ",i); for (j=0;j<n;j++) printf("%d ",stack[j]+1); printf("\n"); #endif // bug - kLook >= 0 kLook=0; for (j=kLook;j<n;j++) { int iBit = 1 << stack[j]; bitmap[j] |= iBit; } } kLook=nStack; int jj=stack[nStack]; unsigned int iBit = 1<<jj; covered &= ~iBit; { unsigned int kBit=0; for (int k=0;k<nStack;k++) { int kk=stack[k]; kBit |= 1<<kk; } assert (covered==kBit); } jj++; stack[nStack]=jj; while (nStack<n) { int k=which[nStack]; char * allowed = possible + k*gap; for (;jj<gap;jj++) { iBit = 1 << jj; if (allowed[jj]&&(covered&iBit)==0) break; } if (jj<gap) { stack[nStack]=jj; covered |= iBit; nStack++; stack[nStack]=first[nStack]; jj = first[nStack]; good=true; } else { good = false; break; } } } int nnFix=0; // Now see if we can fix any for (j=0;j<n;j++) { int k=which[j]; unsigned int mapped = bitmap[j]; char * allowed = possible + k*gap; unsigned int iBit=1; for (int jj=0;jj<gap;jj++) { if ((mapped&iBit)==0) { if (allowed[jj]) { if (!nnFix) printf("for con %d x ",i); nnFix++; printf("%d not %d ",j,jj+1); allowed[jj]=0; finished=false; } } iBit = iBit << 1; } } if (nnFix) printf("\n"); } } if (numberFixed>fixed) finished=false; // try again } // Could try two sets if (infeasible) { // create infeasible cut OsiRowCut rc; rc.setLb(COIN_DBL_MAX); rc.setUb(0.0); cs.insert(rc); } else { // check to see if can tighten bounds CoinPackedVector lbs; CoinPackedVector ubs; int nTightened=0; for (i=0;i<numberDifferent_;i++) { int iColumn = originalWhich_[i]; char * allowed = possible+i*gap; int firstLo=-1; int lastUp=-1; for (int jj=0;jj<gap;jj++) { if (allowed[jj]) { if (firstLo<0) firstLo=jj; lastUp = jj; } } if (firstLo+offset>lo[i]) { lbs.insert(iColumn,static_cast<double> (firstLo+offset)); nTightened++; } if (lastUp+offset<up[i]) { ubs.insert(iColumn,static_cast<double> (lastUp+offset)); nTightened++; } } if (nTightened) { OsiColCut cc; cc.setUbs(ubs); cc.setLbs(lbs); cc.setEffectiveness(100.0); cs.insert(cc); } } //delete [] which; //delete [] start; delete [] first; delete [] stack; delete [] bitmap; delete [] check; delete [] alreadyFixed; delete [] back; delete [] backStart; delete [] possible; delete [] lo; delete [] up; }
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 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); } }
//----------------------------------------------------------------------- // Test XPRESS-MP solution methods. void OsiXprSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir) { #if 0 // Test to at least see if licence managment is working { int iret = initlz(NULL, 0); if ( iret != 0 ) getipv(N_ERRNO, &iret); assert(iret == 0); } #endif // Test default constructor { assert( OsiXprSolverInterface::getNumInstances()==0 ); OsiXprSolverInterface m; // assert( m.xprSaved_ == false ); // assert( m.xprMatrixId_ = -1 ); assert( m.xprProbname_ == "" ); assert( m.matrixByRow_ == NULL ); assert( m.colupper_ == NULL ); assert( m.collower_ == NULL ); assert( m.rowupper_ == NULL ); assert( m.rowlower_ == NULL ); assert( m.rowsense_ == NULL ); assert( m.rhs_ == NULL ); assert( m.rowrange_ == NULL ); assert( m.colsol_ == NULL ); assert( m.rowprice_ == NULL ); assert( m.ivarind_ == NULL ); assert( m.ivartype_ == NULL ); assert( m.vartype_ == NULL ); assert( OsiXprSolverInterface::getNumInstances() == 1 ); // assert( OsiXprSolverInterface::xprCurrentProblem_ == NULL ); assert( m.getApplicationData() == NULL ); int i = 2346; m.setApplicationData(&i); assert( *((int *)(m.getApplicationData())) == i ); } assert( OsiXprSolverInterface::getNumInstances() == 0 ); { CoinRelFltEq eq; OsiXprSolverInterface m; assert( OsiXprSolverInterface::getNumInstances() == 1 ); std::string fn = mpsDir+"exmip1"; m.readMps(fn.c_str()); // assert( OsiXprSolverInterface::xprCurrentProblem_ == &m ); // This assert fails on windows because fn is mixed case and xprProbname_is uppercase. //assert( m.xprProbname_ == fn ); int ad = 13579; m.setApplicationData(&ad); assert( *((int *)(m.getApplicationData())) == ad ); { OsiXprSolverInterface im; // assert( im.modelPtr_==NULL ); assert( im.getNumCols() == 0 ); // assert( im.modelPtr()!=NULL ); // assert( im.mutableModelPtr()!=NULL ); // assert( im.modelPtr() == im.mutableModelPtr() ); } // Test copy constructor and assignment operator { OsiXprSolverInterface lhs; { assert( *((int *)(m.getApplicationData())) == ad ); OsiXprSolverInterface im(m); assert( *((int *)(im.getApplicationData())) == ad ); OsiXprSolverInterface imC1(im); // assert( imC1.mutableModelPtr()!=im.mutableModelPtr() ); // assert( imC1.modelPtr()!=im.modelPtr() ); assert( imC1.getNumCols() == im.getNumCols() ); assert( imC1.getNumRows() == im.getNumRows() ); assert( *((int *)(imC1.getApplicationData())) == ad ); //im.setModelPtr(m); OsiXprSolverInterface imC2(im); // assert( imC2.mutableModelPtr()!=im.mutableModelPtr() ); // assert( imC2.modelPtr()!=im.modelPtr() ); assert( imC2.getNumCols() == im.getNumCols() ); assert( imC2.getNumRows() == im.getNumRows() ); assert( *((int *)(imC2.getApplicationData())) == ad ); // assert( imC2.mutableModelPtr()!=imC1.mutableModelPtr() ); // assert( imC2.modelPtr()!=imC1.modelPtr() ); lhs=imC2; } // Test that lhs has correct values even though rhs has gone out of scope // assert( lhs.mutableModelPtr() != m.mutableModelPtr() ); // assert( lhs.modelPtr() != m.modelPtr() ); assert( lhs.getNumCols() == m.getNumCols() ); assert( lhs.getNumRows() == m.getNumRows() ); assert( *((int *)(lhs.getApplicationData())) == ad ); } // Test clone { OsiXprSolverInterface xprSi(m); OsiSolverInterface * siPtr = &xprSi; OsiSolverInterface * siClone = siPtr->clone(); OsiXprSolverInterface * xprClone = dynamic_cast<OsiXprSolverInterface*>(siClone); assert( xprClone != NULL ); // assert( xprClone->modelPtr() != xprSi.modelPtr() ); // assert( xprClone->modelPtr() != m.modelPtr() ); assert( xprClone->getNumRows() == xprSi.getNumRows() ); assert( xprClone->getNumCols() == m.getNumCols() ); assert( *((int *)(xprClone->getApplicationData())) == ad ); delete siClone; } // Test infinity { OsiXprSolverInterface si; assert( eq(si.getInfinity(), XPRS_PLUSINFINITY) ); } // Test setting solution { OsiXprSolverInterface m1(m); int i; double * cs = new double[m1.getNumCols()]; for ( i = 0; i < m1.getNumCols(); i++ ) cs[i] = i + .5; m1.setColSolution(cs); for ( i = 0; i < m1.getNumCols(); i++ ) assert(m1.getColSolution()[i] == i + .5); double * rs = new double[m1.getNumRows()]; for ( i = 0; i < m1.getNumRows(); i++ ) rs[i] = i - .5; m1.setRowPrice(rs); for ( i = 0; i < m1.getNumRows(); i++ ) assert(m1.getRowPrice()[i] == i - .5); delete [] cs; delete [] rs; } // Test fraction Indices { OsiXprSolverInterface fim; std::string fn = mpsDir+"exmip1"; fim.readMps(fn.c_str()); //fim.setModelPtr(m); // exmip1.mps has 2 integer variables with index 2 & 3 assert( fim.isContinuous(0) ); assert( fim.isContinuous(1) ); assert( !fim.isContinuous(2) ); assert( !fim.isContinuous(3) ); assert( fim.isContinuous(4) ); assert( !fim.isInteger(0) ); assert( !fim.isInteger(1) ); assert( fim.isInteger(2) ); assert( fim.isInteger(3) ); assert( !fim.isInteger(4) ); // XPRESS-MP incorrectly treats unbounded integer variables as // general integers instead of binary (as in MPSX standard) assert( !fim.isBinary(0) ); assert( !fim.isBinary(1) ); assert( fim.isBinary(2) ); assert( fim.isBinary(3) ); assert( !fim.isBinary(4) ); assert( !fim.isIntegerNonBinary(0) ); assert( !fim.isIntegerNonBinary(1) ); assert( !fim.isIntegerNonBinary(2) ); assert( !fim.isIntegerNonBinary(3) ); assert( !fim.isIntegerNonBinary(4) ); // Test fractionalIndices { // Set a solution vector double * cs = new double[fim.getNumCols()]; for ( int i = 0; i < fim.getNumCols(); cs[i++] = 0.0 ); cs[2] = 2.9; cs[3] = 3.0; fim.setColSolution(cs); OsiVectorInt fi = fim.getFractionalIndices(); assert( fi.size() == 1 ); assert( fi[0]==2 ); // Set integer variables very close to integer values cs[2] = 5 + .00001/2.; cs[3] = 8 - .00001/2.; fim.setColSolution(cs); fi = fim.getFractionalIndices(1e-5); assert( fi.size() == 0 ); // Set integer variables close, but beyond tolerances cs[2] = 5 + .00001*2.; cs[3] = 8 - .00001*2.; fim.setColSolution(cs); fi = fim.getFractionalIndices(1e-5); assert( fi.size() == 2 ); assert( fi[0]==2 ); assert( fi[1]==3 ); delete [] cs; } // Change data so column 2 & 3 are integerNonBinary fim.setColUpper(2, 5); fim.setColUpper(3, 6.0); assert( !fim.isBinary(0) ); assert( !fim.isBinary(1) ); assert( !fim.isBinary(2) ); assert( !fim.isBinary(3) ); assert( !fim.isBinary(4) ); assert( !fim.isIntegerNonBinary(0) ); assert( !fim.isIntegerNonBinary(1) ); assert( fim.isIntegerNonBinary(2) ); assert( fim.isIntegerNonBinary(3) ); assert( !fim.isIntegerNonBinary(4) ); } // Test apply cut method { OsiXprSolverInterface im(m); OsiCuts cuts; // Generate some cuts //cg.generateCuts(im,cuts); { // Get number of rows and columns in model int nr=im.getNumRows(); int nc=im.getNumCols(); assert ( nr == 5 ); assert ( nc == 8 ); // Generate a valid row cut from thin air int c; { int *inx = new int[nc]; for (c=0;c<nc;c++) inx[c]=c; double *el = new double[nc]; for (c=0;c<nc;c++) el[c]=((double)c)*((double)c); OsiRowCut rc; rc.setRow(nc,inx,el); rc.setLb(-100.); rc.setUb(100.); rc.setEffectiveness(22); cuts.insert(rc); delete[]el; delete[]inx; } // Generate valid col cut from thin air { const double * xprColLB = im.getColLower(); const double * xprColUB = im.getColUpper(); int *inx = new int[nc]; for (c=0;c<nc;c++) inx[c]=c; double *lb = new double[nc]; double *ub = new double[nc]; for (c=0;c<nc;c++) lb[c]=xprColLB[c]+0.001; for (c=0;c<nc;c++) ub[c]=xprColUB[c]-0.001; OsiColCut cc; cc.setLbs(nc,inx,lb); cc.setUbs(nc,inx,ub); cuts.insert(cc); delete [] ub; delete [] lb; delete [] inx; } { // Generate a row and column cut which have are ineffective OsiRowCut * rcP= new OsiRowCut; rcP->setEffectiveness(-1.); cuts.insert(rcP); assert(rcP==NULL); OsiColCut * ccP= new OsiColCut; ccP->setEffectiveness(-12.); cuts.insert(ccP); assert(ccP==NULL); } { //Generate inconsistent Row cut OsiRowCut rc; const int ne=1; int inx[ne]={-10}; double el[ne]={2.5}; rc.setRow(ne,inx,el); rc.setLb(3.); rc.setUb(4.); assert(!rc.consistent()); cuts.insert(rc); } { //Generate inconsistent col cut OsiColCut cc; const int ne=1; int inx[ne]={-10}; double el[ne]={2.5}; cc.setUbs(ne,inx,el); assert(!cc.consistent()); cuts.insert(cc); } { // Generate row cut which is inconsistent for model m OsiRowCut rc; const int ne=1; int inx[ne]={10}; double el[ne]={2.5}; rc.setRow(ne,inx,el); assert(rc.consistent()); assert(!rc.consistent(im)); cuts.insert(rc); } { // Generate col cut which is inconsistent for model m OsiColCut cc; const int ne=1; int inx[ne]={30}; double el[ne]={2.0}; cc.setLbs(ne,inx,el); assert(cc.consistent()); assert(!cc.consistent(im)); cuts.insert(cc); } { // Generate col cut which is infeasible OsiColCut cc; const int ne=1; int inx[ne]={0}; double el[ne]={2.0}; cc.setUbs(ne,inx,el); cc.setEffectiveness(1000.); assert(cc.consistent()); assert(cc.consistent(im)); assert(cc.infeasible(im)); cuts.insert(cc); } } assert(cuts.sizeRowCuts()==4); assert(cuts.sizeColCuts()==5); OsiSolverInterface::ApplyCutsReturnCode rc = im.applyCuts(cuts); assert( rc.getNumIneffective() == 2 ); assert( rc.getNumApplied() == 2 ); assert( rc.getNumInfeasible() == 1 ); assert( rc.getNumInconsistentWrtIntegerModel() == 2 ); assert( rc.getNumInconsistent() == 2 ); assert( cuts.sizeCuts() == rc.getNumIneffective() + rc.getNumApplied() + rc.getNumInfeasible() + rc.getNumInconsistentWrtIntegerModel() + rc.getNumInconsistent() ); } { OsiXprSolverInterface xprSi(m); int nc = xprSi.getNumCols(); int nr = xprSi.getNumRows(); assert( nc == 8 ); assert( nr == 5 ); assert( eq(xprSi.getColLower()[0],2.5) ); assert( eq(xprSi.getColLower()[1],0.0) ); assert( eq(xprSi.getColUpper()[1],4.1) ); assert( eq(xprSi.getRowLower()[0],2.5) ); assert( eq(xprSi.getRowLower()[4],3.0) ); assert( eq(xprSi.getRowUpper()[1],2.1) ); assert( eq(xprSi.getRowUpper()[4],15.0) ); // const double * cs = xprSi.getColSolution(); // assert( eq(cs[0],2.5) ); // assert( eq(cs[7],0.0) ); assert( !eq(xprSi.getColLower()[3],1.2345) ); xprSi.setColLower( 3, 1.2345 ); assert( eq(xprSi.getColLower()[3],1.2345) ); assert( !eq(xprSi.getColUpper()[4],10.2345) ); xprSi.setColUpper( 4, 10.2345 ); assert( eq(xprSi.getColUpper()[4],10.2345) ); //assert( eq(xprSi.getObjValue(),0.0) ); assert( eq( xprSi.getObjCoefficients()[0], 1.0) ); assert( eq( xprSi.getObjCoefficients()[1], 0.0) ); assert( eq( xprSi.getObjCoefficients()[2], 0.0) ); assert( eq( xprSi.getObjCoefficients()[3], 0.0) ); assert( eq( xprSi.getObjCoefficients()[4], 2.0) ); assert( eq( xprSi.getObjCoefficients()[5], 0.0) ); assert( eq( xprSi.getObjCoefficients()[6], 0.0) ); assert( eq( xprSi.getObjCoefficients()[7], -1.0) ); } // Test matrixByRow method { const OsiXprSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByRow(); CoinRelFltEq eq; const double * ev = smP->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = smP->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = smP->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7] == 2 ); assert( ei[8] == 5 ); assert( ei[9] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); assert( smP->getMajorDim() == 5 ); assert( smP->getMinorDim() == 8 ); assert( smP->getNumElements() == 14 ); assert( smP->getSizeVectorStarts()==6 ); } //-------------- // Test rowsense, rhs, rowrange, matrixByRow { OsiXprSolverInterface lhs; { assert( m.rowrange_==NULL ); assert( m.rowsense_==NULL ); assert( m.rhs_==NULL ); OsiXprSolverInterface siC1(m); assert( siC1.rowrange_==NULL ); assert( siC1.rowsense_==NULL ); assert( siC1.rhs_==NULL ); const char * siC1rs = siC1.getRowSense(); assert( siC1rs[0] == 'G' ); assert( siC1rs[1] == 'L' ); assert( siC1rs[2] == 'E' ); assert( siC1rs[3] == 'R' ); assert( siC1rs[4] == 'R' ); const double * siC1rhs = siC1.getRightHandSide(); assert( eq(siC1rhs[0], 2.5) ); assert( eq(siC1rhs[1], 2.1) ); assert( eq(siC1rhs[2], 4.0) ); assert( eq(siC1rhs[3], 5.0) ); assert( eq(siC1rhs[4], 15.0) ); const double * siC1rr = siC1.getRowRange(); assert( eq(siC1rr[0], 0.0) ); assert( eq(siC1rr[1], 0.0) ); assert( eq(siC1rr[2], 0.0) ); assert( eq(siC1rr[3], 5.0 - 1.8) ); assert( eq(siC1rr[4], 15.0 - 3.0) ); const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow(); assert( siC1mbr != NULL ); const double * ev = siC1mbr->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = siC1mbr->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = siC1mbr->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7 ] == 2 ); assert( ei[8 ] == 5 ); assert( ei[9 ] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); assert( siC1mbr->getMajorDim() == 5 ); assert( siC1mbr->getMinorDim() == 8 ); assert( siC1mbr->getNumElements() == 14 ); assert( siC1mbr->getSizeVectorStarts()==6 ); assert( siC1rs == siC1.getRowSense() ); assert( siC1rhs == siC1.getRightHandSide() ); assert( siC1rr == siC1.getRowRange() ); // Change XPRESS Model by adding free row OsiRowCut rc; rc.setLb(-COIN_DBL_MAX); rc.setUb(COIN_DBL_MAX); OsiCuts cuts; cuts.insert(rc); siC1.applyCuts(cuts); // Since model was changed, test that cached // data is now freed. assert( siC1.rowrange_ == NULL ); assert( siC1.rowsense_ == NULL ); assert( siC1.rhs_ == NULL ); assert( siC1.matrixByRow_ == NULL ); siC1rs = siC1.getRowSense(); assert( siC1rs[0] == 'G' ); assert( siC1rs[1] == 'L' ); assert( siC1rs[2] == 'E' ); assert( siC1rs[3] == 'R' ); assert( siC1rs[4] == 'R' ); assert( siC1rs[5] == 'N' ); siC1rhs = siC1.getRightHandSide(); assert( eq(siC1rhs[0],2.5) ); assert( eq(siC1rhs[1],2.1) ); assert( eq(siC1rhs[2],4.0) ); assert( eq(siC1rhs[3],5.0) ); assert( eq(siC1rhs[4],15.0) ); assert( eq(siC1rhs[5],0.0) ); siC1rr = siC1.getRowRange(); assert( eq(siC1rr[0], 0.0) ); assert( eq(siC1rr[1], 0.0) ); assert( eq(siC1rr[2], 0.0) ); assert( eq(siC1rr[3], 5.0 - 1.8) ); assert( eq(siC1rr[4], 15.0 - 3.0) ); assert( eq(siC1rr[5], 0.0) ); lhs=siC1; } // Test that lhs has correct values even though siC1 has gone out of scope assert( lhs.rowrange_ == NULL ); assert( lhs.rowsense_ == NULL ); assert( lhs.rhs_ == NULL ); assert( lhs.matrixByRow_ == NULL ); const char * lhsrs = lhs.getRowSense(); assert( lhsrs[0] == 'G' ); assert( lhsrs[1] == 'L' ); assert( lhsrs[2] == 'E' ); assert( lhsrs[3] == 'R' ); assert( lhsrs[4] == 'R' ); assert( lhsrs[5] == 'N' ); const double * lhsrhs = lhs.getRightHandSide(); assert( eq(lhsrhs[0], 2.5) ); assert( eq(lhsrhs[1], 2.1) ); assert( eq(lhsrhs[2], 4.0) ); assert( eq(lhsrhs[3], 5.0) ); assert( eq(lhsrhs[4], 15.0) ); assert( eq(lhsrhs[5], 0.0) ); const double *lhsrr = lhs.getRowRange(); assert( eq(lhsrr[0], 0.0) ); assert( eq(lhsrr[1], 0.0) ); assert( eq(lhsrr[2], 0.0) ); assert( eq(lhsrr[3], 5.0 - 1.8) ); assert( eq(lhsrr[4], 15.0 - 3.0) ); assert( eq(lhsrr[5], 0.0) ); const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow(); assert( lhsmbr != NULL ); const double * ev = lhsmbr->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = lhsmbr->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = lhsmbr->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7] == 2 ); assert( ei[8] == 5 ); assert( ei[9] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); assert( lhsmbr->getMajorDim() == 6 ); assert( lhsmbr->getMinorDim() == 8 ); assert( lhsmbr->getNumElements() == 14 ); assert( lhsmbr->getSizeVectorStarts()==7 ); } //-------------- // Test load problem { OsiXprSolverInterface base(m); base.initialSolve(); assert(m.getNumRows() == base.getNumRows()); OsiXprSolverInterface si1,si2,si3,si4; si1.loadProblem( *base.getMatrixByCol(), base.getColLower(),base.getColUpper(),base.getObjCoefficients(), base.getRowSense(),base.getRightHandSide(),base.getRowRange()); si1.initialSolve(); assert(eq(base.getObjValue(), si1.getObjValue())); assert(m.getNumRows() == si1.getNumRows()); si2.loadProblem( *base.getMatrixByRow(), base.getColLower(),base.getColUpper(),base.getObjCoefficients(), base.getRowSense(),base.getRightHandSide(),base.getRowRange()); si2.initialSolve(); assert(eq(base.getObjValue(), si2.getObjValue())); assert(m.getNumRows() == si2.getNumRows()); si3.loadProblem( *base.getMatrixByCol(), base.getColLower(),base.getColUpper(),base.getObjCoefficients(), base.getRowLower(),base.getRowUpper() ); si3.initialSolve(); assert(eq(base.getObjValue(), si3.getObjValue())); assert(m.getNumRows() == si3.getNumRows()); si4.loadProblem( *base.getMatrixByCol(), base.getColLower(),base.getColUpper(),base.getObjCoefficients(), base.getRowLower(),base.getRowUpper() ); si4.initialSolve(); assert(eq(base.getObjValue(), si4.getObjValue())); assert(m.getNumRows() == si4.getNumRows()); base.initialSolve(); si1.initialSolve(); si2.initialSolve(); si3.initialSolve(); si4.initialSolve(); // Create an indices vector assert(base.getNumCols()<10); assert(base.getNumRows()<10); int indices[10]; int i; for (i=0; i<10; i++) indices[i]=i; // Test collower CoinPackedVector basePv,pv; basePv.setVector(base.getNumCols(),indices,base.getColLower()); pv.setVector( si1.getNumCols(),indices, si1.getColLower()); assert(basePv.isEquivalent(pv)); pv.setVector( si2.getNumCols(),indices, si2.getColLower()); assert(basePv.isEquivalent(pv)); pv.setVector( si3.getNumCols(),indices, si3.getColLower()); assert(basePv.isEquivalent(pv)); pv.setVector( si4.getNumCols(),indices, si4.getColLower()); assert(basePv.isEquivalent(pv)); // Test colupper basePv.setVector(base.getNumCols(),indices,base.getColUpper()); pv.setVector( si1.getNumCols(),indices, si1.getColUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si2.getNumCols(),indices, si2.getColUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si3.getNumCols(),indices, si3.getColUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si4.getNumCols(),indices, si4.getColUpper()); assert(basePv.isEquivalent(pv)); // Test getObjCoefficients basePv.setVector(base.getNumCols(),indices,base.getObjCoefficients()); pv.setVector( si1.getNumCols(),indices, si1.getObjCoefficients()); assert(basePv.isEquivalent(pv)); pv.setVector( si2.getNumCols(),indices, si2.getObjCoefficients()); assert(basePv.isEquivalent(pv)); pv.setVector( si3.getNumCols(),indices, si3.getObjCoefficients()); assert(basePv.isEquivalent(pv)); pv.setVector( si4.getNumCols(),indices, si4.getObjCoefficients()); assert(basePv.isEquivalent(pv)); // Test rowlower basePv.setVector(base.getNumRows(),indices,base.getRowLower()); pv.setVector( si1.getNumRows(),indices, si1.getRowLower()); assert( eq(base.getRowLower()[3],si1.getRowLower()[3]) ); assert(basePv.isEquivalent(pv)); pv.setVector( si2.getNumRows(),indices, si2.getRowLower()); assert(basePv.isEquivalent(pv)); pv.setVector( si3.getNumRows(),indices, si3.getRowLower()); assert(basePv.isEquivalent(pv)); pv.setVector( si4.getNumRows(),indices, si4.getRowLower()); assert(basePv.isEquivalent(pv)); // Test rowupper basePv.setVector(base.getNumRows(),indices,base.getRowUpper()); pv.setVector( si1.getNumRows(),indices, si1.getRowUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si2.getNumRows(),indices, si2.getRowUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si3.getNumRows(),indices, si3.getRowUpper()); assert(basePv.isEquivalent(pv)); pv.setVector( si4.getNumRows(),indices, si4.getRowUpper()); assert(basePv.isEquivalent(pv)); // Test Constraint Matrix assert( base.getMatrixByCol()->isEquivalent(*si1.getMatrixByCol()) ); assert( base.getMatrixByRow()->isEquivalent(*si1.getMatrixByRow()) ); assert( base.getMatrixByCol()->isEquivalent(*si2.getMatrixByCol()) ); assert( base.getMatrixByRow()->isEquivalent(*si2.getMatrixByRow()) ); assert( base.getMatrixByCol()->isEquivalent(*si3.getMatrixByCol()) ); assert( base.getMatrixByRow()->isEquivalent(*si3.getMatrixByRow()) ); assert( base.getMatrixByCol()->isEquivalent(*si4.getMatrixByCol()) ); assert( base.getMatrixByRow()->isEquivalent(*si4.getMatrixByRow()) ); // Test Objective Value assert( eq(base.getObjValue(),si1.getObjValue()) ); assert( eq(base.getObjValue(),si2.getObjValue()) ); assert( eq(base.getObjValue(),si3.getObjValue()) ); assert( eq(base.getObjValue(),si4.getObjValue()) ); } //-------------- assert(OsiXprSolverInterface::getNumInstances()==1); } assert(OsiXprSolverInterface::getNumInstances()==0); // Do common solverInterface testing by calling the // base class testing method. { OsiXprSolverInterface m; OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } }
// Generate cuts void 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); } }
/** 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; }
/**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; }
CbcBranchingObject * CbcBranchToFixLots::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * /*info*/, int /*way*/) { // by default way must be -1 //assert (way==-1); //OsiSolverInterface * solver = model_->solver(); const double * solution = model_->testSolution(); const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); const double * dj = solver->getReducedCost(); int i; int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance); // make smaller ? double tolerance = CoinMin(1.0e-8, integerTolerance); // How many fixed are we aiming at int wantedFixed = static_cast<int> (static_cast<double>(numberIntegers) * fractionFixed_); int nSort = 0; int numberFixed = 0; int numberColumns = solver->getNumCols(); int * sort = new int[numberColumns]; double * dsort = new double[numberColumns]; if (djTolerance_ != -1.234567) { int type = shallWe(); assert (type); // Take clean first if (type == 1) { for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; if (upper[iColumn] > lower[iColumn]) { if (!mark_ || !mark_[iColumn]) { if (solution[iColumn] < lower[iColumn] + tolerance) { if (dj[iColumn] > djTolerance_) { dsort[nSort] = -dj[iColumn]; sort[nSort++] = iColumn; } } else if (solution[iColumn] > upper[iColumn] - tolerance) { if (dj[iColumn] < -djTolerance_) { dsort[nSort] = dj[iColumn]; sort[nSort++] = iColumn; } } } } else { numberFixed++; } } // sort CoinSort_2(dsort, dsort + nSort, sort); nSort = CoinMin(nSort, wantedFixed - numberFixed); } else if (type < 10) { int i; //const double * rowLower = solver->getRowLower(); const double * rowUpper = solver->getRowUpper(); // Row copy const double * elementByRow = matrixByRow_.getElements(); const int * column = matrixByRow_.getIndices(); const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts(); const int * rowLength = matrixByRow_.getVectorLengths(); const double * columnLower = solver->getColLower(); const double * columnUpper = solver->getColUpper(); const double * solution = solver->getColSolution(); int numberColumns = solver->getNumCols(); int numberRows = solver->getNumRows(); for (i = 0; i < numberColumns; i++) { sort[i] = i; if (columnLower[i] != columnUpper[i]) { dsort[i] = 1.0e100; } else { dsort[i] = 1.0e50; numberFixed++; } } for (i = 0; i < numberRows; i++) { double rhsValue = rowUpper[i]; bool oneRow = true; // check elements int numberUnsatisfied = 0; for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) { int iColumn = column[j]; double value = elementByRow[j]; double solValue = solution[iColumn]; if (columnLower[iColumn] != columnUpper[iColumn]) { if (solValue < 1.0 - integerTolerance && solValue > integerTolerance) numberUnsatisfied++; if (value != 1.0) { oneRow = false; break; } } else { rhsValue -= value * floor(solValue + 0.5); } } if (oneRow && rhsValue <= 1.0 + tolerance) { if (!numberUnsatisfied) { for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) { int iColumn = column[j]; if (dsort[iColumn] > 1.0e50) { dsort[iColumn] = 0; nSort++; } } } } } // sort CoinSort_2(dsort, dsort + numberColumns, sort); } else { // new way for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; if (upper[iColumn] > lower[iColumn]) { if (!mark_ || !mark_[iColumn]) { double distanceDown = solution[iColumn] - lower[iColumn]; double distanceUp = upper[iColumn] - solution[iColumn]; double distance = CoinMin(distanceDown, distanceUp); if (distance > 0.001 && distance < 0.5) { dsort[nSort] = distance; sort[nSort++] = iColumn; } } } } // sort CoinSort_2(dsort, dsort + nSort, sort); int n = 0; double sum = 0.0; for (int k = 0; k < nSort; k++) { sum += dsort[k]; if (sum <= djTolerance_) n = k; else break; } nSort = CoinMin(n, numberClean_ / 1000000); } } else { #define FIX_IF_LESS -0.1 // 3 in same row and sum <FIX_IF_LESS? int numberRows = matrixByRow_.getNumRows(); const double * solution = model_->testSolution(); const int * column = matrixByRow_.getIndices(); const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts(); const int * rowLength = matrixByRow_.getVectorLengths(); double bestSum = 1.0; int nBest = -1; int kRow = -1; OsiSolverInterface * solver = model_->solver(); for (int i = 0; i < numberRows; i++) { int numberUnsatisfied = 0; double sum = 0.0; for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) { int iColumn = column[j]; if (solver->isInteger(iColumn)) { double solValue = solution[iColumn]; if (solValue > 1.0e-5 && solValue < FIX_IF_LESS) { numberUnsatisfied++; sum += solValue; } } } if (numberUnsatisfied >= 3 && sum < FIX_IF_LESS) { // possible if (numberUnsatisfied > nBest || (numberUnsatisfied == nBest && sum < bestSum)) { nBest = numberUnsatisfied; bestSum = sum; kRow = i; } } } assert (nBest > 0); for (int j = rowStart[kRow]; j < rowStart[kRow] + rowLength[kRow]; j++) { int iColumn = column[j]; if (solver->isInteger(iColumn)) { double solValue = solution[iColumn]; if (solValue > 1.0e-5 && solValue < FIX_IF_LESS) { sort[nSort++] = iColumn; } } } } OsiRowCut down; down.setLb(-COIN_DBL_MAX); double rhs = 0.0; for (i = 0; i < nSort; i++) { int iColumn = sort[i]; double distanceDown = solution[iColumn] - lower[iColumn]; double distanceUp = upper[iColumn] - solution[iColumn]; if (distanceDown < distanceUp) { rhs += lower[iColumn]; dsort[i] = 1.0; } else { rhs -= upper[iColumn]; dsort[i] = -1.0; } } down.setUb(rhs); down.setRow(nSort, sort, dsort); down.setEffectiveness(COIN_DBL_MAX); // so will persist delete [] sort; delete [] dsort; // up is same - just with rhs changed OsiRowCut up = down; up.setLb(rhs + 1.0); up.setUb(COIN_DBL_MAX); // Say can fix one way CbcCutBranchingObject * newObject = new CbcCutBranchingObject(model_, down, up, true); if (model_->messageHandler()->logLevel() > 1) printf("creating cut in CbcBranchCut\n"); return newObject; }
//------------------------------------------------------------------- // 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; }
//-------------------------------------------------------------------------- void OsiCpxSolverInterfaceUnitTest( const std::string & mpsDir, const std::string & netlibDir ) { // Test default constructor { OsiCpxSolverInterface m; assert( m.obj_==NULL ); assert( m.collower_==NULL ); assert( m.colupper_==NULL ); assert( m.coltype_==NULL ); assert( m.rowsense_==NULL ); assert( m.rhs_==NULL ); assert( m.rowrange_==NULL ); assert( m.rowlower_==NULL ); assert( m.rowupper_==NULL ); assert( m.colsol_==NULL ); assert( m.rowsol_==NULL ); assert( m.matrixByRow_==NULL ); assert( m.matrixByCol_==NULL ); assert( m.coltype_==NULL ); assert( m.coltypesize_==0 ); assert( m.getApplicationData() == NULL ); int i=2346; m.setApplicationData(&i); assert( *((int *)(m.getApplicationData())) == i ); } { CoinRelFltEq eq; OsiCpxSolverInterface m; std::string fn = mpsDir+"exmip1"; m.readMps(fn.c_str(),"mps"); int ad = 13579; m.setApplicationData(&ad); assert( *((int *)(m.getApplicationData())) == ad ); { assert( m.getNumCols()==8 ); const CoinPackedMatrix * colCopy = m.getMatrixByCol(); assert( colCopy->getNumCols() == 8 ); assert( colCopy->getMajorDim() == 8 ); assert( colCopy->getNumRows() == 5 ); assert( colCopy->getMinorDim() == 5 ); assert (colCopy->getVectorLengths()[7] == 2 ); CoinPackedMatrix revColCopy; revColCopy.reverseOrderedCopyOf(*colCopy); CoinPackedMatrix rev2ColCopy; rev2ColCopy.reverseOrderedCopyOf(revColCopy); assert( rev2ColCopy.getNumCols() == 8 ); assert( rev2ColCopy.getMajorDim() == 8 ); assert( rev2ColCopy.getNumRows() == 5 ); assert( rev2ColCopy.getMinorDim() == 5 ); assert( rev2ColCopy.getVectorLengths()[7] == 2 ); } { OsiCpxSolverInterface im; assert( im.getNumCols() == 0 ); } // Test copy constructor and assignment operator { OsiCpxSolverInterface lhs; { assert( *((int *)(m.getApplicationData())) == ad ); OsiCpxSolverInterface im(m); assert( *((int *)(im.getApplicationData())) == ad ); OsiCpxSolverInterface imC1(im); assert( imC1.lp_ != im.lp_ ); assert( imC1.getNumCols() == im.getNumCols() ); assert( imC1.getNumRows() == im.getNumRows() ); assert( *((int *)(imC1.getApplicationData())) == ad ); //im.setModelPtr(m); OsiCpxSolverInterface imC2(im); assert( imC2.lp_ != im.lp_ ); assert( imC2.getNumCols() == im.getNumCols() ); assert( imC2.getNumRows() == im.getNumRows() ); assert( *((int *)(imC2.getApplicationData())) == ad ); assert( imC2.lp_ != imC1.lp_ ); lhs=imC2; } // Test that lhs has correct values even though rhs has gone out of scope assert( lhs.lp_ != m.lp_ ); assert( lhs.getNumCols() == m.getNumCols() ); assert( lhs.getNumRows() == m.getNumRows() ); assert( *((int *)(lhs.getApplicationData())) == ad ); } // Test clone { OsiCpxSolverInterface cplexSi(m); OsiSolverInterface * siPtr = &cplexSi; OsiSolverInterface * siClone = siPtr->clone(); OsiCpxSolverInterface * cplexClone = dynamic_cast<OsiCpxSolverInterface*>(siClone); assert( cplexClone != NULL ); assert( cplexClone->lp_ != cplexSi.lp_ ); assert( cplexClone->getNumRows() == cplexSi.getNumRows() ); assert( cplexClone->getNumCols() == m.getNumCols() ); assert( *((int *)(cplexClone->getApplicationData())) == ad ); delete siClone; } // test infinity { OsiCpxSolverInterface si; assert( eq( si.getInfinity(), CPX_INFBOUND ) ); } // Test setting solution { OsiCpxSolverInterface m1(m); int i; double * cs = new double[m1.getNumCols()]; for ( i = 0; i < m1.getNumCols(); i++ ) cs[i] = i + .5; m1.setColSolution(cs); for ( i = 0; i < m1.getNumCols(); i++ ) assert(m1.getColSolution()[i] == i + .5); double * rs = new double[m1.getNumRows()]; for ( i = 0; i < m1.getNumRows(); i++ ) rs[i] = i - .5; m1.setRowPrice(rs); for ( i = 0; i < m1.getNumRows(); i++ ) assert(m1.getRowPrice()[i] == i - .5); delete [] cs; delete [] rs; } // Test fraction Indices { OsiCpxSolverInterface fim; std::string fn = mpsDir+"exmip1"; fim.readMps(fn.c_str(),"mps"); //fim.setModelPtr(m); // exmip1.mps has 2 integer variables with index 2 & 3 assert( fim.isContinuous(0) ); assert( fim.isContinuous(1) ); assert( !fim.isContinuous(2) ); assert( !fim.isContinuous(3) ); assert( fim.isContinuous(4) ); assert( !fim.isInteger(0) ); assert( !fim.isInteger(1) ); assert( fim.isInteger(2) ); assert( fim.isInteger(3) ); assert( !fim.isInteger(4) ); assert( !fim.isBinary(0) ); assert( !fim.isBinary(1) ); assert( fim.isBinary(2) ); assert( fim.isBinary(3) ); assert( !fim.isBinary(4) ); assert( !fim.isIntegerNonBinary(0) ); assert( !fim.isIntegerNonBinary(1) ); assert( !fim.isIntegerNonBinary(2) ); assert( !fim.isIntegerNonBinary(3) ); assert( !fim.isIntegerNonBinary(4) ); // Test fractionalIndices { // Set a solution vector double * cs = new double[fim.getNumCols()]; for ( int i = 0; i < fim.getNumCols(); cs[i++] = 0.0 ); cs[2] = 2.9; cs[3] = 3.0; fim.setColSolution(cs); OsiVectorInt fi = fim.getFractionalIndices(); assert( fi.size() == 1 ); assert( fi[0]==2 ); // Set integer variables very close to integer values cs[2] = 5 + .00001/2.; cs[3] = 8 - .00001/2.; fim.setColSolution(cs); fi = fim.getFractionalIndices(1e-5); assert( fi.size() == 0 ); // Set integer variables close, but beyond tolerances cs[2] = 5 + .00001*2.; cs[3] = 8 - .00001*2.; fim.setColSolution(cs); fi = fim.getFractionalIndices(1e-5); assert( fi.size() == 2 ); assert( fi[0]==2 ); assert( fi[1]==3 ); delete [] cs; } // Change data so column 2 & 3 are integerNonBinary fim.setColUpper(2, 5); fim.setColUpper(3, 6.0); assert( !fim.isBinary(0) ); assert( !fim.isBinary(1) ); assert( !fim.isBinary(2) ); assert( !fim.isBinary(3) ); assert( !fim.isBinary(4) ); assert( !fim.isIntegerNonBinary(0) ); assert( !fim.isIntegerNonBinary(1) ); assert( fim.isIntegerNonBinary(2) ); assert( fim.isIntegerNonBinary(3) ); assert( !fim.isIntegerNonBinary(4) ); } // Test apply cuts method { OsiCpxSolverInterface im(m); OsiCuts cuts; // Generate some cuts { // Get number of rows and columns in model int nr=im.getNumRows(); int nc=im.getNumCols(); assert( nr == 5 ); assert( nc == 8 ); // Generate a valid row cut from thin air int c; { int *inx = new int[nc]; for (c=0;c<nc;c++) inx[c]=c; double *el = new double[nc]; for (c=0;c<nc;c++) el[c]=((double)c)*((double)c); OsiRowCut rc; rc.setRow(nc,inx,el); rc.setLb(-100.); rc.setUb(100.); rc.setEffectiveness(22); cuts.insert(rc); delete[]el; delete[]inx; } // Generate valid col cut from thin air { const double * cplexColLB = im.getColLower(); const double * cplexColUB = im.getColUpper(); int *inx = new int[nc]; for (c=0;c<nc;c++) inx[c]=c; double *lb = new double[nc]; double *ub = new double[nc]; for (c=0;c<nc;c++) lb[c]=cplexColLB[c]+0.001; for (c=0;c<nc;c++) ub[c]=cplexColUB[c]-0.001; OsiColCut cc; cc.setLbs(nc,inx,lb); cc.setUbs(nc,inx,ub); cuts.insert(cc); delete [] ub; delete [] lb; delete [] inx; } { // Generate a row and column cut which have are ineffective OsiRowCut * rcP= new OsiRowCut; rcP->setEffectiveness(-1.); cuts.insert(rcP); assert(rcP==NULL); OsiColCut * ccP= new OsiColCut; ccP->setEffectiveness(-12.); cuts.insert(ccP); assert(ccP==NULL); } { //Generate inconsistent Row cut OsiRowCut rc; const int ne=1; int inx[ne]={-10}; double el[ne]={2.5}; rc.setRow(ne,inx,el); rc.setLb(3.); rc.setUb(4.); assert(!rc.consistent()); cuts.insert(rc); } { //Generate inconsistent col cut OsiColCut cc; const int ne=1; int inx[ne]={-10}; double el[ne]={2.5}; cc.setUbs(ne,inx,el); assert(!cc.consistent()); cuts.insert(cc); } { // Generate row cut which is inconsistent for model m OsiRowCut rc; const int ne=1; int inx[ne]={10}; double el[ne]={2.5}; rc.setRow(ne,inx,el); assert(rc.consistent()); assert(!rc.consistent(im)); cuts.insert(rc); } { // Generate col cut which is inconsistent for model m OsiColCut cc; const int ne=1; int inx[ne]={30}; double el[ne]={2.0}; cc.setLbs(ne,inx,el); assert(cc.consistent()); assert(!cc.consistent(im)); cuts.insert(cc); } { // Generate col cut which is infeasible OsiColCut cc; const int ne=1; int inx[ne]={0}; double el[ne]={2.0}; cc.setUbs(ne,inx,el); cc.setEffectiveness(1000.); assert(cc.consistent()); assert(cc.consistent(im)); assert(cc.infeasible(im)); cuts.insert(cc); } } assert(cuts.sizeRowCuts()==4); assert(cuts.sizeColCuts()==5); OsiSolverInterface::ApplyCutsReturnCode rc = im.applyCuts(cuts); assert( rc.getNumIneffective() == 2 ); assert( rc.getNumApplied() == 2 ); assert( rc.getNumInfeasible() == 1 ); assert( rc.getNumInconsistentWrtIntegerModel() == 2 ); assert( rc.getNumInconsistent() == 2 ); assert( cuts.sizeCuts() == rc.getNumIneffective() + rc.getNumApplied() + rc.getNumInfeasible() + rc.getNumInconsistentWrtIntegerModel() + rc.getNumInconsistent() ); } { OsiCpxSolverInterface cplexSi(m); int nc = cplexSi.getNumCols(); int nr = cplexSi.getNumRows(); const double * cl = cplexSi.getColLower(); const double * cu = cplexSi.getColUpper(); const double * rl = cplexSi.getRowLower(); const double * ru = cplexSi.getRowUpper(); assert( nc == 8 ); assert( nr == 5 ); assert( eq(cl[0],2.5) ); assert( eq(cl[1],0.0) ); assert( eq(cu[1],4.1) ); assert( eq(cu[2],1.0) ); assert( eq(rl[0],2.5) ); assert( eq(rl[4],3.0) ); assert( eq(ru[1],2.1) ); assert( eq(ru[4],15.0) ); double newCs[8] = {1., 2., 3., 4., 5., 6., 7., 8.}; cplexSi.setColSolution(newCs); const double * cs = cplexSi.getColSolution(); assert( eq(cs[0],1.0) ); assert( eq(cs[7],8.0) ); { OsiCpxSolverInterface solnSi(cplexSi); const double * cs = solnSi.getColSolution(); assert( eq(cs[0],1.0) ); assert( eq(cs[7],8.0) ); } assert( !eq(cl[3],1.2345) ); cplexSi.setColLower( 3, 1.2345 ); assert( eq(cplexSi.getColLower()[3],1.2345) ); assert( !eq(cu[4],10.2345) ); cplexSi.setColUpper( 4, 10.2345 ); assert( eq(cplexSi.getColUpper()[4],10.2345) ); assert( eq(cplexSi.getObjValue(),0.0) ); assert( eq( cplexSi.getObjCoefficients()[0], 1.0) ); assert( eq( cplexSi.getObjCoefficients()[1], 0.0) ); assert( eq( cplexSi.getObjCoefficients()[2], 0.0) ); assert( eq( cplexSi.getObjCoefficients()[3], 0.0) ); assert( eq( cplexSi.getObjCoefficients()[4], 2.0) ); assert( eq( cplexSi.getObjCoefficients()[5], 0.0) ); assert( eq( cplexSi.getObjCoefficients()[6], 0.0) ); assert( eq( cplexSi.getObjCoefficients()[7], -1.0) ); } // Test getMatrixByRow method { const OsiCpxSolverInterface si(m); const CoinPackedMatrix * smP = si.getMatrixByRow(); //const CoinPackedMatrix * osmP = dynamic_cast(const OsiCpxPackedMatrix*)(smP); //assert( osmP!=NULL ); CoinRelFltEq eq; const double * ev = smP->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = smP->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = smP->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7] == 2 ); assert( ei[8] == 5 ); assert( ei[9] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); assert( smP->getMajorDim() == 5 ); assert( smP->getNumElements() == 14 ); } //-------------- // Test rowsense, rhs, rowrange, getMatrixByRow { OsiCpxSolverInterface lhs; { #if 0 assert( m.obj_==NULL ); assert( m.collower_==NULL ); assert( m.colupper_==NULL ); assert( m.rowrange_==NULL ); assert( m.rowsense_==NULL ); assert( m.rhs_==NULL ); assert( m.rowlower_==NULL ); assert( m.rowupper_==NULL ); assert( m.colsol_==NULL ); assert( m.rowsol_==NULL ); assert( m.getMatrixByRow_==NULL ); #endif OsiCpxSolverInterface siC1(m); assert( siC1.obj_==NULL ); assert( siC1.collower_==NULL ); assert( siC1.colupper_==NULL ); // assert( siC1.coltype_==NULL ); assert( siC1.rowrange_==NULL ); assert( siC1.rowsense_==NULL ); assert( siC1.rhs_==NULL ); assert( siC1.rowlower_==NULL ); assert( siC1.rowupper_==NULL ); assert( siC1.colsol_!=NULL ); assert( siC1.rowsol_!=NULL ); assert( siC1.matrixByRow_==NULL ); const char * siC1rs = siC1.getRowSense(); assert( siC1rs[0]=='G' ); assert( siC1rs[1]=='L' ); assert( siC1rs[2]=='E' ); assert( siC1rs[3]=='R' ); assert( siC1rs[4]=='R' ); const double * siC1rhs = siC1.getRightHandSide(); assert( eq(siC1rhs[0],2.5) ); assert( eq(siC1rhs[1],2.1) ); assert( eq(siC1rhs[2],4.0) ); assert( eq(siC1rhs[3],5.0) ); assert( eq(siC1rhs[4],15.) ); const double * siC1rr = siC1.getRowRange(); assert( eq(siC1rr[0],0.0) ); assert( eq(siC1rr[1],0.0) ); assert( eq(siC1rr[2],0.0) ); assert( eq(siC1rr[3],5.0-1.8) ); assert( eq(siC1rr[4],15.0-3.0) ); const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow(); assert( siC1mbr != NULL ); const double * ev = siC1mbr->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = siC1mbr->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = siC1mbr->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7] == 2 ); assert( ei[8] == 5 ); assert( ei[9] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); assert( siC1mbr->getMajorDim() == 5 ); assert( siC1mbr->getNumElements() == 14 ); assert( siC1rs == siC1.getRowSense() ); assert( siC1rhs == siC1.getRightHandSide() ); assert( siC1rr == siC1.getRowRange() ); // Change CPLEX Model by adding free row OsiRowCut rc; rc.setLb(-COIN_DBL_MAX); rc.setUb( COIN_DBL_MAX); OsiCuts cuts; cuts.insert(rc); siC1.applyCuts(cuts); // Since model was changed, test that cached // data is now freed. assert( siC1.obj_==NULL ); assert( siC1.collower_==NULL ); assert( siC1.colupper_==NULL ); // assert( siC1.coltype_==NULL ); assert( siC1.rowrange_==NULL ); assert( siC1.rowsense_==NULL ); assert( siC1.rhs_==NULL ); assert( siC1.rowlower_==NULL ); assert( siC1.rowupper_==NULL ); assert( siC1.colsol_==NULL ); assert( siC1.rowsol_==NULL ); assert( siC1.matrixByRow_==NULL ); siC1rs = siC1.getRowSense(); siC1rhs = siC1.getRightHandSide(); siC1rr = siC1.getRowRange(); assert( siC1rs[0]=='G' ); assert( siC1rs[1]=='L' ); assert( siC1rs[2]=='E' ); assert( siC1rs[3]=='R' ); assert( siC1rs[4]=='R' ); assert( siC1rs[5]=='N' ); assert( eq(siC1rhs[0],2.5) ); assert( eq(siC1rhs[1],2.1) ); assert( eq(siC1rhs[2],4.0) ); assert( eq(siC1rhs[3],5.0) ); assert( eq(siC1rhs[4],15.) ); assert( eq(siC1rhs[5],0.0) ); assert( eq(siC1rr[0],0.0) ); assert( eq(siC1rr[1],0.0) ); assert( eq(siC1rr[2],0.0) ); assert( eq(siC1rr[3],5.0-1.8) ); assert( eq(siC1rr[4],15.0-3.0) ); assert( eq(siC1rr[5],0.0) ); lhs=siC1; } // Test that lhs has correct values even though siC1 has gone out of scope assert( lhs.obj_==NULL ); assert( lhs.collower_==NULL ); assert( lhs.colupper_==NULL ); // assert( lhs.coltype_==NULL ); assert( lhs.rowrange_==NULL ); assert( lhs.rowsense_==NULL ); assert( lhs.rhs_==NULL ); assert( lhs.rowlower_==NULL ); assert( lhs.rowupper_==NULL ); assert( lhs.colsol_!=NULL ); assert( lhs.rowsol_!=NULL ); assert( lhs.matrixByRow_==NULL ); const char * lhsrs = lhs.getRowSense(); assert( lhsrs[0]=='G' ); assert( lhsrs[1]=='L' ); assert( lhsrs[2]=='E' ); assert( lhsrs[3]=='R' ); assert( lhsrs[4]=='R' ); assert( lhsrs[5]=='N' ); const double * lhsrhs = lhs.getRightHandSide(); assert( eq(lhsrhs[0],2.5) ); assert( eq(lhsrhs[1],2.1) ); assert( eq(lhsrhs[2],4.0) ); assert( eq(lhsrhs[3],5.0) ); assert( eq(lhsrhs[4],15.) ); assert( eq(lhsrhs[5],0.0) ); const double *lhsrr = lhs.getRowRange(); assert( eq(lhsrr[0],0.0) ); assert( eq(lhsrr[1],0.0) ); assert( eq(lhsrr[2],0.0) ); assert( eq(lhsrr[3],5.0-1.8) ); assert( eq(lhsrr[4],15.0-3.0) ); assert( eq(lhsrr[5],0.0) ); const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow(); assert( lhsmbr != NULL ); const double * ev = lhsmbr->getElements(); assert( eq(ev[0], 3.0) ); assert( eq(ev[1], 1.0) ); assert( eq(ev[2], -2.0) ); assert( eq(ev[3], -1.0) ); assert( eq(ev[4], -1.0) ); assert( eq(ev[5], 2.0) ); assert( eq(ev[6], 1.1) ); assert( eq(ev[7], 1.0) ); assert( eq(ev[8], 1.0) ); assert( eq(ev[9], 2.8) ); assert( eq(ev[10], -1.2) ); assert( eq(ev[11], 5.6) ); assert( eq(ev[12], 1.0) ); assert( eq(ev[13], 1.9) ); const int * mi = lhsmbr->getVectorStarts(); assert( mi[0]==0 ); assert( mi[1]==5 ); assert( mi[2]==7 ); assert( mi[3]==9 ); assert( mi[4]==11 ); assert( mi[5]==14 ); const int * ei = lhsmbr->getIndices(); assert( ei[0] == 0 ); assert( ei[1] == 1 ); assert( ei[2] == 3 ); assert( ei[3] == 4 ); assert( ei[4] == 7 ); assert( ei[5] == 1 ); assert( ei[6] == 2 ); assert( ei[7] == 2 ); assert( ei[8] == 5 ); assert( ei[9] == 3 ); assert( ei[10] == 6 ); assert( ei[11] == 0 ); assert( ei[12] == 4 ); assert( ei[13] == 7 ); int md = lhsmbr->getMajorDim(); assert( md == 6 ); assert( lhsmbr->getNumElements() == 14 ); } } // Do common solverInterface testing by calling the // base class testing method. { OsiCpxSolverInterface m; OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir); } }
//------------------------------------------------------------------- // 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); } } } } } } }
int MilpRounding::solution(double &solutionValue, double *betterSolution) { if(model_->getCurrentPassNumber() > 1) return 0; if (model_->currentDepth() > 2 && (model_->getNodeCount()%howOften_)!=0) return 0; int returnCode = 0; // 0 means it didn't find a feasible solution OsiTMINLPInterface * nlp = NULL; if(setup_->getAlgorithm() == B_BB) nlp = dynamic_cast<OsiTMINLPInterface *>(model_->solver()->clone()); else nlp = dynamic_cast<OsiTMINLPInterface *>(setup_->nonlinearSolver()->clone()); TMINLP2TNLP* minlp = nlp->problem(); // set tolerances double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance); //double primalTolerance = 1.0e-6; int n; int m; int nnz_jac_g; int nnz_h_lag; Ipopt::TNLP::IndexStyleEnum index_style; minlp->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style); const Bonmin::TMINLP::VariableType* variableType = minlp->var_types(); const double* x_sol = minlp->x_sol(); const double* g_l = minlp->g_l(); const double* g_u = minlp->g_u(); const double * colsol = model_->solver()->getColSolution(); // Get information about the linear and nonlinear part of the instance TMINLP* tminlp = nlp->model(); vector<Ipopt::TNLP::LinearityType> c_lin(m); tminlp->get_constraints_linearity(m, c_lin()); vector<int> c_idx(m); int n_lin = 0; for (int i=0;i<m;i++) { if (c_lin[i]==Ipopt::TNLP::LINEAR) c_idx[i] = n_lin++; else c_idx[i] = -1; } // Get the structure of the jacobian vector<int> indexRow(nnz_jac_g); vector<int> indexCol(nnz_jac_g); minlp->eval_jac_g(n, x_sol, false, m, nnz_jac_g, indexRow(), indexCol(), 0); // get the jacobian values vector<double> jac_g(nnz_jac_g); minlp->eval_jac_g(n, x_sol, false, m, nnz_jac_g, NULL, NULL, jac_g()); // Sort the matrix to column ordered vector<int> sortedIndex(nnz_jac_g); CoinIotaN(sortedIndex(), nnz_jac_g, 0); MatComp c; c.iRow = indexRow(); c.jCol = indexCol(); std::sort(sortedIndex.begin(), sortedIndex.end(), c); vector<int> row (nnz_jac_g); vector<double> value (nnz_jac_g); vector<int> columnStart(n,0); vector<int> columnLength(n,0); int indexCorrection = (index_style == Ipopt::TNLP::C_STYLE) ? 0 : 1; int iniCol = -1; int nnz = 0; for(int i=0; i<nnz_jac_g; i++) { int thisIndexCol = indexCol[sortedIndex[i]]-indexCorrection; int thisIndexRow = c_idx[indexRow[sortedIndex[i]] - indexCorrection]; if(thisIndexCol != iniCol) { iniCol = thisIndexCol; columnStart[thisIndexCol] = nnz; columnLength[thisIndexCol] = 0; } if(thisIndexRow == -1) continue; columnLength[thisIndexCol]++; row[nnz] = thisIndexRow; value[nnz] = jac_g[i]; nnz++; } // Build the row lower and upper bounds vector<double> newRowLower(n_lin); vector<double> newRowUpper(n_lin); for(int i = 0 ; i < m ; i++){ if(c_idx[i] == -1) continue; newRowLower[c_idx[i]] = g_l[i]; newRowUpper[c_idx[i]] = g_u[i]; } // Get solution array for heuristic solution vector<double> newSolution(n); std::copy(x_sol, x_sol + n, newSolution.begin()); // Define the constraint matrix for MILP CoinPackedMatrix matrix(true,n_lin,n, nnz, value(), row(), columnStart(), columnLength()); // create objective function and columns lower and upper bounds for MILP // and create columns for matrix in MILP //double alpha = 0; double beta = 1; vector<double> objective(n); vector<int> idxIntegers; idxIntegers.reserve(n); for(int i = 0 ; i < n ; i++){ if(variableType[i] != Bonmin::TMINLP::CONTINUOUS){ idxIntegers.push_back(i); objective[i] = beta*(1 - 2*colsol[i]); } } #if 0 // Get dual multipliers and build gradient of the lagrangean const double * duals = nlp->getRowPrice() + 2 *n; vector<double> grad(n, 0); vector<int> indices(n, 0); tminlp->eval_grad_f(n, x_sol, false, grad()); for(int i = 0 ; i < m ; i++){ if(c_lin[i] == Ipopt::TNLP::LINEAR) continue; int nnz; tminlp->eval_grad_gi(n, x_sol, false, i, nnz, indices(), NULL); tminlp->eval_grad_gi(n, x_sol, false, i, nnz, NULL, grad()); for(int k = 0 ; k < nnz ; k++){ objective[indices[k]] += alpha *duals[i] * grad[k]; } } for(int i = 0 ; i < n ; i++){ if(variableType[i] != Bonmin::TMINLP::CONTINUOUS) objective[i] += alpha * grad[i]; //if(fabs(objective[i]) < 1e-4) objective[i] = 0; else objective[i] = 0; } std::copy(objective.begin(), objective.end(), std::ostream_iterator<double>(std::cout, " ")); std::cout<<std::endl; #endif // load the problem to OSI OsiSolverInterface *si = mip_->solver(); assert(si != NULL); CoinMessageHandler * handler = model_->messageHandler()->clone(); si->passInMessageHandler(handler); si->messageHandler()->setLogLevel(1); si->loadProblem(matrix, model_->solver()->getColLower(), model_->solver()->getColUpper(), objective(), newRowLower(), newRowUpper()); si->setInteger(idxIntegers(), static_cast<int>(idxIntegers.size())); si->applyCuts(noGoods); bool hasFractionnal = true; while(hasFractionnal){ mip_->optimize(DBL_MAX, 0, 60); hasFractionnal = false; #if 0 bool feasible = false; if(mip_->getLastSolution()) { const double* solution = mip_->getLastSolution(); std::copy(solution, solution + n, newSolution.begin()); feasible = true; } if(feasible) { // fix the integer variables and solve the NLP // also add no good cut CoinPackedVector v; double lb = 1; for (int iColumn=0;iColumn<n;iColumn++) { if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) { double value=newSolution[iColumn]; if (fabs(floor(value+0.5)-value)>integerTolerance) { #ifdef DEBUG_BON_HEURISTIC_DIVE_MIP cout<<"It should be infeasible because: "<<endl; cout<<"variable "<<iColumn<<" is not integer"<<endl; #endif feasible = false; break; } else { value=floor(newSolution[iColumn]+0.5); if(value > 0.5){ v.insert(iColumn, -1); lb -= value; } minlp->SetVariableUpperBound(iColumn, value); minlp->SetVariableLowerBound(iColumn, value); } } } } #endif } bool feasible = false; if(mip_->getLastSolution()) { const double* solution = mip_->getLastSolution(); std::copy(solution, solution + n, newSolution.begin()); feasible = true; delete handler; } if(feasible) { // fix the integer variables and solve the NLP // also add no good cut CoinPackedVector v; double lb = 1; for (int iColumn=0;iColumn<n;iColumn++) { if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) { double value=newSolution[iColumn]; if (fabs(floor(value+0.5)-value)>integerTolerance) { feasible = false; break; } else { value=floor(newSolution[iColumn]+0.5); if(value > 0.5){ v.insert(iColumn, -1); lb -= value; } minlp->SetVariableUpperBound(iColumn, value); minlp->SetVariableLowerBound(iColumn, value); } } } OsiRowCut c; c.setRow(v); c.setLb(lb); c.setUb(DBL_MAX); noGoods.insert(c); if(feasible) { nlp->initialSolve(); if(minlp->optimization_status() != Ipopt::SUCCESS) { feasible = false; } std::copy(x_sol,x_sol+n, newSolution.begin()); } } if(feasible) { double newSolutionValue; minlp->eval_f(n, newSolution(), true, newSolutionValue); if(newSolutionValue < solutionValue) { std::copy(newSolution.begin(), newSolution.end(), betterSolution); solutionValue = newSolutionValue; returnCode = 1; } } delete nlp; #ifdef DEBUG_BON_HEURISTIC_DIVE_MIP std::cout<<"DiveMIP returnCode = "<<returnCode<<std::endl; #endif return returnCode; }