// Apply bounds void OsiSolverBranch::applyBounds(OsiSolverInterface &solver, int way) const { int base = way + 1; assert(way == -1 || way == 1); int numberColumns = solver.getNumCols(); const double *columnLower = solver.getColLower(); int i; for (i = start_[base]; i < start_[base + 1]; i++) { int iColumn = indices_[i]; if (iColumn < numberColumns) { double value = CoinMax(bound_[i], columnLower[iColumn]); solver.setColLower(iColumn, value); } else { int iRow = iColumn - numberColumns; const double *rowLower = solver.getRowLower(); double value = CoinMax(bound_[i], rowLower[iRow]); solver.setRowLower(iRow, value); } } const double *columnUpper = solver.getColUpper(); for (i = start_[base + 1]; i < start_[base + 2]; i++) { int iColumn = indices_[i]; if (iColumn < numberColumns) { double value = CoinMin(bound_[i], columnUpper[iColumn]); solver.setColUpper(iColumn, value); } else { int iRow = iColumn - numberColumns; const double *rowUpper = solver.getRowUpper(); double value = CoinMin(bound_[i], rowUpper[iRow]); solver.setRowUpper(iRow, value); } } }
void CglClique::selectRowCliques(const OsiSolverInterface& si,int numOriginalRows) { const int numrows = si.getNumRows(); std::vector<int> clique(numrows, 1); int i, j, k; // First scan through the binary fractional variables and see where do they // have a 1 coefficient const CoinPackedMatrix& mcol = *si.getMatrixByCol(); for (j = 0; j < sp_numcols; ++j) { const CoinShallowPackedVector& vec = mcol.getVector(sp_orig_col_ind[j]); const int* ind = vec.getIndices(); const double* elem = vec.getElements(); for (i = vec.getNumElements() - 1; i >= 0; --i) { if (elem[i] != 1.0) { clique[ind[i]] = 0; } } } // Now check the sense and rhs (by checking rowupper) and the rest of the // coefficients const CoinPackedMatrix& mrow = *si.getMatrixByRow(); const double* rub = si.getRowUpper(); for (i = 0; i < numrows; ++i) { if (rub[i] != 1.0||i>=numOriginalRows) { clique[i] = 0; continue; } if (clique[i] == 1) { const CoinShallowPackedVector& vec = mrow.getVector(i); const double* elem = vec.getElements(); for (j = vec.getNumElements() - 1; j >= 0; --j) { if (elem[j] < 0) { clique[i] = 0; break; } } } } // Finally collect the still standing rows into sp_orig_row_ind sp_numrows = std::accumulate(clique.begin(), clique.end(), 0); sp_orig_row_ind = new int[sp_numrows]; for (i = 0, k = 0; i < numrows; ++i) { if (clique[i] == 1) { sp_orig_row_ind[k++] = i; } } }
// Useful constructor CbcFollowOn::CbcFollowOn (CbcModel * model) : CbcObject(model) { assert (model); OsiSolverInterface * solver = model_->solver(); matrix_ = *solver->getMatrixByCol(); matrix_.removeGaps(); matrix_.setExtraGap(0.0); matrixByRow_ = *solver->getMatrixByRow(); int numberRows = matrix_.getNumRows(); rhs_ = new int[numberRows]; 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(); for (i = 0; i < numberRows; i++) { rhs_[i] = 0; double value = rowLower[i]; if (value == rowUpper[i]) { if (floor(value) == value && value >= 1.0 && value < 10.0) { // check elements bool good = true; for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) { int iColumn = column[j]; if (!solver->isBinary(iColumn)) good = false; double elValue = elementByRow[j]; if (floor(elValue) != elValue || value < 1.0) good = false; } if (good) rhs_[i] = static_cast<int> (value); } } } }
// 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); } }
// Create a list of rows which might yield cuts // The possible parameter is a list to cut down search void CglOddHole::createRowList( const OsiSolverInterface & si, const int * possible) { // Get basic problem information int nRows=si.getNumRows(); const CoinPackedMatrix * rowCopy = si.getMatrixByRow(); const int * column = rowCopy->getIndices(); const CoinBigIndex * rowStart = rowCopy->getVectorStarts(); const int * rowLength = rowCopy->getVectorLengths(); int rowIndex; delete [] suitableRows_; numberRows_=nRows; const double * rowElements = rowCopy->getElements(); const double * rowupper = si.getRowUpper(); const double * rowlower = si.getRowLower(); const double * collower = si.getColLower(); const double * colupper = si.getColUpper(); suitableRows_=new int[nRows]; if (possible) { memcpy(suitableRows_,possible,nRows*sizeof(int)); } else { int i; for (i=0;i<nRows;i++) { suitableRows_[i]=1; } } for (rowIndex=0; rowIndex<nRows; rowIndex++){ double rhs1=rowupper[rowIndex]; double rhs2=rowlower[rowIndex]; if (suitableRows_[rowIndex]) { int i; bool goodRow=true; for (i=rowStart[rowIndex]; i<rowStart[rowIndex]+rowLength[rowIndex];i++) { int thisCol=column[i]; if (colupper[thisCol]-collower[thisCol]>epsilon_) { // could allow general integer variables but unlikely if (!si.isBinary(thisCol) ) { goodRow=false; break; } if (fabs(rowElements[i]-1.0)>epsilon_) { goodRow=false; break; } } else { rhs1 -= collower[thisCol]*rowElements[i]; rhs2 -= collower[thisCol]*rowElements[i]; } } if (fabs(rhs1-1.0)>epsilon_&&fabs(rhs2-1.0)>epsilon_) { goodRow=false; } if (goodRow) { suitableRows_[rowIndex]=1; } else { suitableRows_[rowIndex]=0; } } } }
//------------------------------------------------------------------------------- // Generate three cycle cuts //------------------------------------------------------------------- void CglOddHole::generateCuts(const OsiSolverInterface & si, OsiCuts & cs, const CglTreeInfo info) { // Get basic problem information int nRows=si.getNumRows(); int nCols=si.getNumCols(); const CoinPackedMatrix * rowCopy = si.getMatrixByRow(); // Could do cliques and extra OSL cliques // For moment just easy ones // If no information exists then get a list of suitable rows // If it does then suitable rows are subset of information CglOddHole temp; int * checkRow = new int[nRows]; int i; if (!suitableRows_) { for (i=0;i<nRows;i++) { checkRow[i]=1; } } else { // initialize and extend rows to current size memset(checkRow,0,nRows*sizeof(int)); memcpy(checkRow,suitableRows_,CoinMin(nRows,numberRows_)*sizeof(int)); } temp.createRowList(si,checkRow); // now cut down further by only allowing rows with fractional solution double * solution = new double[nCols]; memcpy(solution,si.getColSolution(),nCols*sizeof(double)); const int * column = rowCopy->getIndices(); const CoinBigIndex * rowStart = rowCopy->getVectorStarts(); const int * rowLength = rowCopy->getVectorLengths(); const double * collower = si.getColLower(); const double * colupper = si.getColUpper(); int * suitable = temp.suitableRows_; // At present I am using new and delete as easier to see arrays in debugger int * fixed = new int[nCols]; // mark fixed columns for (i=0;i<nCols;i++) { if (si.isBinary(i) ) { fixed[i]=0; if (colupper[i]-collower[i]<epsilon_) { solution[i]=0.0; fixed[i]=2; } else if (solution[i]<epsilon_) { solution[i]=0.0; fixed[i]=-1; } else if (solution[i]>onetol_) { solution[i]=1.0; fixed[i]=+1; } } else { //mark as fixed even if not (can not intersect any interesting rows) solution[i]=0.0; fixed[i]=3; } } // first do packed const double * rowlower = si.getRowLower(); const double * rowupper = si.getRowUpper(); for (i=0;i<nRows;i++) { if (suitable[i]) { int k; double sum=0.0; if (rowupper[i]>1.001) suitable[i]=-1; for (k=rowStart[i]; k<rowStart[i]+rowLength[i];k++) { int icol=column[k]; if (!fixed[icol]) sum += solution[icol]; } if (sum<0.9) suitable[i]=-1; //say no good } } #ifdef CGL_DEBUG const OsiRowCutDebugger * debugger = si.getRowCutDebugger(); if (debugger&&!debugger->onOptimalPath(si)) debugger = NULL; #else const OsiRowCutDebugger * debugger = NULL; #endif temp.generateCuts(debugger, *rowCopy,solution, si.getReducedCost(),cs,suitable,fixed,info,true); // now cover //if no >= then skip bool doCover=false; int nsuitable=0; for (i=0;i<nRows;i++) { suitable[i]=abs(suitable[i]); if (suitable[i]) { int k; double sum=0.0; if (rowlower[i]<0.999) sum=2.0; if (rowupper[i]>1.001) doCover=true; for (k=rowStart[i]; k<rowStart[i]+rowLength[i];k++) { int icol=column[k]; if (!fixed[icol]) sum += solution[icol]; if (fixed[icol]==1) sum=2.0; //don't use if any at 1 } if (sum>1.1) { suitable[i]=-1; //say no good } else { nsuitable++; } } } if (doCover&&nsuitable) temp.generateCuts(debugger, *rowCopy,solution,si.getReducedCost(), cs,suitable,fixed,info,false); delete [] checkRow; delete [] solution; delete [] fixed; }
int * analyze(OsiClpSolverInterface * solverMod, int & numberChanged, double & increment, bool changeInt, CoinMessageHandler * generalMessageHandler, bool noPrinting) { bool noPrinting_ = noPrinting; OsiSolverInterface * solver = solverMod->clone(); char generalPrint[200]; if (0) { // just get increment CbcModel model(*solver); model.analyzeObjective(); double increment2 = model.getCutoffIncrement(); printf("initial cutoff increment %g\n", increment2); } const double *objective = solver->getObjCoefficients() ; const double *lower = solver->getColLower() ; const double *upper = solver->getColUpper() ; int numberColumns = solver->getNumCols() ; int numberRows = solver->getNumRows(); double direction = solver->getObjSense(); int iRow, iColumn; // Row copy CoinPackedMatrix matrixByRow(*solver->getMatrixByRow()); const double * elementByRow = matrixByRow.getElements(); const int * column = matrixByRow.getIndices(); const CoinBigIndex * rowStart = matrixByRow.getVectorStarts(); const int * rowLength = matrixByRow.getVectorLengths(); // Column copy CoinPackedMatrix matrixByCol(*solver->getMatrixByCol()); const double * element = matrixByCol.getElements(); const int * row = matrixByCol.getIndices(); const CoinBigIndex * columnStart = matrixByCol.getVectorStarts(); const int * columnLength = matrixByCol.getVectorLengths(); const double * rowLower = solver->getRowLower(); const double * rowUpper = solver->getRowUpper(); char * ignore = new char [numberRows]; int * changed = new int[numberColumns]; int * which = new int[numberRows]; double * changeRhs = new double[numberRows]; memset(changeRhs, 0, numberRows*sizeof(double)); memset(ignore, 0, numberRows); numberChanged = 0; int numberInteger = 0; for (iColumn = 0; iColumn < numberColumns; iColumn++) { if (upper[iColumn] > lower[iColumn] + 1.0e-8 && solver->isInteger(iColumn)) numberInteger++; } bool finished = false; while (!finished) { int saveNumberChanged = numberChanged; for (iRow = 0; iRow < numberRows; iRow++) { int numberContinuous = 0; double value1 = 0.0, value2 = 0.0; bool allIntegerCoeff = true; double sumFixed = 0.0; int jColumn1 = -1, jColumn2 = -1; for (CoinBigIndex j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) { int jColumn = column[j]; double value = elementByRow[j]; if (upper[jColumn] > lower[jColumn] + 1.0e-8) { if (!solver->isInteger(jColumn)) { if (numberContinuous == 0) { jColumn1 = jColumn; value1 = value; } else { jColumn2 = jColumn; value2 = value; } numberContinuous++; } else { if (fabs(value - floor(value + 0.5)) > 1.0e-12) allIntegerCoeff = false; } } else { sumFixed += lower[jColumn] * value; } } double low = rowLower[iRow]; if (low > -1.0e20) { low -= sumFixed; if (fabs(low - floor(low + 0.5)) > 1.0e-12) allIntegerCoeff = false; } double up = rowUpper[iRow]; if (up < 1.0e20) { up -= sumFixed; if (fabs(up - floor(up + 0.5)) > 1.0e-12) allIntegerCoeff = false; } if (!allIntegerCoeff) continue; // can't do if (numberContinuous == 1) { // see if really integer // This does not allow for complicated cases if (low == up) { if (fabs(value1) > 1.0e-3) { value1 = 1.0 / value1; if (fabs(value1 - floor(value1 + 0.5)) < 1.0e-12) { // integer changed[numberChanged++] = jColumn1; solver->setInteger(jColumn1); if (upper[jColumn1] > 1.0e20) solver->setColUpper(jColumn1, 1.0e20); if (lower[jColumn1] < -1.0e20) solver->setColLower(jColumn1, -1.0e20); } } } else { if (fabs(value1) > 1.0e-3) { value1 = 1.0 / value1; if (fabs(value1 - floor(value1 + 0.5)) < 1.0e-12) { // This constraint will not stop it being integer ignore[iRow] = 1; } } } } else if (numberContinuous == 2) { if (low == up) { /* need general theory - for now just look at 2 cases - 1 - +- 1 one in column and just costs i.e. matching objective 2 - +- 1 two in column but feeds into G/L row which will try and minimize */ if (fabs(value1) == 1.0 && value1*value2 == -1.0 && !lower[jColumn1] && !lower[jColumn2]) { int n = 0; int i; double objChange = direction * (objective[jColumn1] + objective[jColumn2]); double bound = CoinMin(upper[jColumn1], upper[jColumn2]); bound = CoinMin(bound, 1.0e20); for ( i = columnStart[jColumn1]; i < columnStart[jColumn1] + columnLength[jColumn1]; i++) { int jRow = row[i]; double value = element[i]; if (jRow != iRow) { which[n++] = jRow; changeRhs[jRow] = value; } } for ( i = columnStart[jColumn1]; i < columnStart[jColumn1] + columnLength[jColumn1]; i++) { int jRow = row[i]; double value = element[i]; if (jRow != iRow) { if (!changeRhs[jRow]) { which[n++] = jRow; changeRhs[jRow] = value; } else { changeRhs[jRow] += value; } } } if (objChange >= 0.0) { // see if all rows OK bool good = true; for (i = 0; i < n; i++) { int jRow = which[i]; double value = changeRhs[jRow]; if (value) { value *= bound; if (rowLength[jRow] == 1) { if (value > 0.0) { double rhs = rowLower[jRow]; if (rhs > 0.0) { double ratio = rhs / value; if (fabs(ratio - floor(ratio + 0.5)) > 1.0e-12) good = false; } } else { double rhs = rowUpper[jRow]; if (rhs < 0.0) { double ratio = rhs / value; if (fabs(ratio - floor(ratio + 0.5)) > 1.0e-12) good = false; } } } else if (rowLength[jRow] == 2) { if (value > 0.0) { if (rowLower[jRow] > -1.0e20) good = false; } else { if (rowUpper[jRow] < 1.0e20) good = false; } } else { good = false; } } } if (good) { // both can be integer changed[numberChanged++] = jColumn1; solver->setInteger(jColumn1); if (upper[jColumn1] > 1.0e20) solver->setColUpper(jColumn1, 1.0e20); if (lower[jColumn1] < -1.0e20) solver->setColLower(jColumn1, -1.0e20); changed[numberChanged++] = jColumn2; solver->setInteger(jColumn2); if (upper[jColumn2] > 1.0e20) solver->setColUpper(jColumn2, 1.0e20); if (lower[jColumn2] < -1.0e20) solver->setColLower(jColumn2, -1.0e20); } } // clear for (i = 0; i < n; i++) { changeRhs[which[i]] = 0.0; } } } } } for (iColumn = 0; iColumn < numberColumns; iColumn++) { if (upper[iColumn] > lower[iColumn] + 1.0e-8 && !solver->isInteger(iColumn)) { double value; value = upper[iColumn]; if (value < 1.0e20 && fabs(value - floor(value + 0.5)) > 1.0e-12) continue; value = lower[iColumn]; if (value > -1.0e20 && fabs(value - floor(value + 0.5)) > 1.0e-12) continue; bool integer = true; for (CoinBigIndex j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; if (!ignore[iRow]) { integer = false; break; } } if (integer) { // integer changed[numberChanged++] = iColumn; solver->setInteger(iColumn); if (upper[iColumn] > 1.0e20) solver->setColUpper(iColumn, 1.0e20); if (lower[iColumn] < -1.0e20) solver->setColLower(iColumn, -1.0e20); } } } finished = numberChanged == saveNumberChanged; } delete [] which; delete [] changeRhs; delete [] ignore; //if (numberInteger&&!noPrinting_) //printf("%d integer variables",numberInteger); if (changeInt) { //if (!noPrinting_) { //if (numberChanged) // printf(" and %d variables made integer\n",numberChanged); //else // printf("\n"); //} //increment=0.0; if (!numberChanged) { delete [] changed; delete solver; return NULL; } else { for (iColumn = 0; iColumn < numberColumns; iColumn++) { if (solver->isInteger(iColumn)) solverMod->setInteger(iColumn); } delete solver; return changed; } } else { //if (!noPrinting_) { //if (numberChanged) // printf(" and %d variables could be made integer\n",numberChanged); //else // printf("\n"); //} // just get increment int logLevel = generalMessageHandler->logLevel(); CbcModel model(*solver); if (!model.defaultHandler()) model.passInMessageHandler(generalMessageHandler); if (noPrinting_) model.setLogLevel(0); model.analyzeObjective(); generalMessageHandler->setLogLevel(logLevel); double increment2 = model.getCutoffIncrement(); if (increment2 > increment && increment2 > 0.0) { if (!noPrinting_) { sprintf(generalPrint, "Cutoff increment increased from %g to %g", increment, increment2); CoinMessages generalMessages = solverMod->getModelPtr()->messages(); generalMessageHandler->message(CLP_GENERAL, generalMessages) << generalPrint << CoinMessageEol; } increment = increment2; } delete solver; numberChanged = 0; delete [] changed; return NULL; } }
OsiSolverInterface * expandKnapsack(CoinModel & model, int * whichColumn, int * knapsackStart, int * knapsackRow, int &numberKnapsack, CglStored & stored, int logLevel, int fixedPriority, int SOSPriority, CoinModel & tightenedModel) { int maxTotal = numberKnapsack; // load from coin model OsiSolverLink *si = new OsiSolverLink(); OsiSolverInterface * finalModel = NULL; si->setDefaultMeshSize(0.001); // need some relative granularity si->setDefaultBound(100.0); si->setDefaultMeshSize(0.01); si->setDefaultBound(100000.0); si->setIntegerPriority(1000); si->setBiLinearPriority(10000); si->load(model, true, logLevel); // get priorities const int * priorities = model.priorities(); int numberColumns = model.numberColumns(); if (priorities) { OsiObject ** objects = si->objects(); int numberObjects = si->numberObjects(); for (int iObj = 0; iObj < numberObjects; iObj++) { int iColumn = objects[iObj]->columnNumber(); if (iColumn >= 0 && iColumn < numberColumns) { #ifndef NDEBUG OsiSimpleInteger * obj = dynamic_cast <OsiSimpleInteger *>(objects[iObj]) ; #endif assert (obj); int iPriority = priorities[iColumn]; if (iPriority > 0) objects[iObj]->setPriority(iPriority); } } if (fixedPriority > 0) { si->setFixedPriority(fixedPriority); } if (SOSPriority < 0) SOSPriority = 100000; } CoinModel coinModel = *si->coinModel(); assert(coinModel.numberRows() > 0); tightenedModel = coinModel; int numberRows = coinModel.numberRows(); // Mark variables int * whichKnapsack = new int [numberColumns]; int iRow, iColumn; for (iColumn = 0; iColumn < numberColumns; iColumn++) whichKnapsack[iColumn] = -1; int kRow; bool badModel = false; // analyze if (logLevel > 1) { for (iRow = 0; iRow < numberRows; iRow++) { /* Just obvious one at first positive non unit coefficients all integer positive rowUpper for now - linear (but further down in code may use nonlinear) column bounds should be tight */ //double lower = coinModel.getRowLower(iRow); double upper = coinModel.getRowUpper(iRow); if (upper < 1.0e10) { CoinModelLink triple = coinModel.firstInRow(iRow); bool possible = true; int n = 0; int n1 = 0; while (triple.column() >= 0) { int iColumn = triple.column(); const char * el = coinModel.getElementAsString(iRow, iColumn); if (!strcmp("Numeric", el)) { if (coinModel.columnLower(iColumn) == coinModel.columnUpper(iColumn)) { triple = coinModel.next(triple); continue; // fixed } double value = coinModel.getElement(iRow, iColumn); if (value < 0.0) { possible = false; } else { n++; if (value == 1.0) n1++; if (coinModel.columnLower(iColumn) < 0.0) possible = false; if (!coinModel.isInteger(iColumn)) possible = false; if (whichKnapsack[iColumn] >= 0) possible = false; } } else { possible = false; // non linear } triple = coinModel.next(triple); } if (n - n1 > 1 && possible) { double lower = coinModel.getRowLower(iRow); double upper = coinModel.getRowUpper(iRow); CoinModelLink triple = coinModel.firstInRow(iRow); while (triple.column() >= 0) { int iColumn = triple.column(); lower -= coinModel.columnLower(iColumn) * triple.value(); upper -= coinModel.columnLower(iColumn) * triple.value(); triple = coinModel.next(triple); } printf("%d is possible %g <=", iRow, lower); // print triple = coinModel.firstInRow(iRow); while (triple.column() >= 0) { int iColumn = triple.column(); if (coinModel.columnLower(iColumn) != coinModel.columnUpper(iColumn)) printf(" (%d,el %g up %g)", iColumn, triple.value(), coinModel.columnUpper(iColumn) - coinModel.columnLower(iColumn)); triple = coinModel.next(triple); } printf(" <= %g\n", upper); } } } } numberKnapsack = 0; for (kRow = 0; kRow < numberRows; kRow++) { iRow = kRow; /* Just obvious one at first positive non unit coefficients all integer positive rowUpper for now - linear (but further down in code may use nonlinear) column bounds should be tight */ //double lower = coinModel.getRowLower(iRow); double upper = coinModel.getRowUpper(iRow); if (upper < 1.0e10) { CoinModelLink triple = coinModel.firstInRow(iRow); bool possible = true; int n = 0; int n1 = 0; while (triple.column() >= 0) { int iColumn = triple.column(); const char * el = coinModel.getElementAsString(iRow, iColumn); if (!strcmp("Numeric", el)) { if (coinModel.columnLower(iColumn) == coinModel.columnUpper(iColumn)) { triple = coinModel.next(triple); continue; // fixed } double value = coinModel.getElement(iRow, iColumn); if (value < 0.0) { possible = false; } else { n++; if (value == 1.0) n1++; if (coinModel.columnLower(iColumn) < 0.0) possible = false; if (!coinModel.isInteger(iColumn)) possible = false; if (whichKnapsack[iColumn] >= 0) possible = false; } } else { possible = false; // non linear } triple = coinModel.next(triple); } if (n - n1 > 1 && possible) { // try CoinModelLink triple = coinModel.firstInRow(iRow); while (triple.column() >= 0) { int iColumn = triple.column(); if (coinModel.columnLower(iColumn) != coinModel.columnUpper(iColumn)) whichKnapsack[iColumn] = numberKnapsack; triple = coinModel.next(triple); } knapsackRow[numberKnapsack++] = iRow; } } } if (logLevel > 0) printf("%d out of %d candidate rows are possible\n", numberKnapsack, numberRows); // Check whether we can get rid of nonlinearities /* mark rows -2 in knapsack and other variables -1 not involved n only in knapsack n */ int * markRow = new int [numberRows]; for (iRow = 0; iRow < numberRows; iRow++) markRow[iRow] = -1; int canDo = 1; // OK and linear for (iColumn = 0; iColumn < numberColumns; iColumn++) { CoinModelLink triple = coinModel.firstInColumn(iColumn); int iKnapsack = whichKnapsack[iColumn]; bool linear = true; // See if quadratic objective const char * expr = coinModel.getColumnObjectiveAsString(iColumn); if (strcmp(expr, "Numeric")) { linear = false; } while (triple.row() >= 0) { int iRow = triple.row(); if (iKnapsack >= 0) { if (markRow[iRow] == -1) { markRow[iRow] = iKnapsack; } else if (markRow[iRow] != iKnapsack) { markRow[iRow] = -2; } } const char * expr = coinModel.getElementAsString(iRow, iColumn); if (strcmp(expr, "Numeric")) { linear = false; } triple = coinModel.next(triple); } if (!linear) { if (whichKnapsack[iColumn] < 0) { canDo = 0; break; } else { canDo = 2; } } } int * markKnapsack = NULL; double * coefficient = NULL; double * linear = NULL; int * whichRow = NULL; int * lookupRow = NULL; badModel = (canDo == 0); if (numberKnapsack && canDo) { /* double check - OK if no nonlinear nonlinear only on columns in knapsack nonlinear only on columns in knapsack * ONE other - same for all in knapsack AND that is only row connected to knapsack (theoretically could split knapsack if two other and small numbers) also ONE could be ONE expression - not just a variable */ int iKnapsack; markKnapsack = new int [numberKnapsack]; coefficient = new double [numberKnapsack]; linear = new double [numberColumns]; for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) markKnapsack[iKnapsack] = -1; if (canDo == 2) { for (iRow = -1; iRow < numberRows; iRow++) { int numberOdd; CoinPackedMatrix * row = coinModel.quadraticRow(iRow, linear, numberOdd); if (row) { // see if valid const double * element = row->getElements(); const int * column = row->getIndices(); const CoinBigIndex * columnStart = row->getVectorStarts(); const int * columnLength = row->getVectorLengths(); int numberLook = row->getNumCols(); for (int i = 0; i < numberLook; i++) { int iKnapsack = whichKnapsack[i]; if (iKnapsack < 0) { // might be able to swap - but for now can't have knapsack in for (int j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iColumn = column[j]; if (whichKnapsack[iColumn] >= 0) { canDo = 0; // no good badModel = true; break; } } } else { // OK if in same knapsack - or maybe just one int marked = markKnapsack[iKnapsack]; for (int j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iColumn = column[j]; if (whichKnapsack[iColumn] != iKnapsack && whichKnapsack[iColumn] >= 0) { canDo = 0; // no good badModel = true; break; } else if (marked == -1) { markKnapsack[iKnapsack] = iColumn; marked = iColumn; coefficient[iKnapsack] = element[j]; coinModel.associateElement(coinModel.columnName(iColumn), 1.0); } else if (marked != iColumn) { badModel = true; canDo = 0; // no good break; } else { // could manage with different coefficients - but for now ... assert(coefficient[iKnapsack] == element[j]); } } } } delete row; } } } if (canDo) { // for any rows which are cuts whichRow = new int [numberRows]; lookupRow = new int [numberRows]; bool someNonlinear = false; double maxCoefficient = 1.0; for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) { if (markKnapsack[iKnapsack] >= 0) { someNonlinear = true; int iColumn = markKnapsack[iKnapsack]; maxCoefficient = CoinMax(maxCoefficient, fabs(coefficient[iKnapsack] * coinModel.columnUpper(iColumn))); } } if (someNonlinear) { // associate all columns to stop possible error messages for (iColumn = 0; iColumn < numberColumns; iColumn++) { coinModel.associateElement(coinModel.columnName(iColumn), 1.0); } } ClpSimplex tempModel; tempModel.loadProblem(coinModel); // Create final model - first without knapsacks int nCol = 0; int nRow = 0; for (iRow = 0; iRow < numberRows; iRow++) { if (markRow[iRow] < 0) { lookupRow[iRow] = nRow; whichRow[nRow++] = iRow; } else { lookupRow[iRow] = -1; } } for (iColumn = 0; iColumn < numberColumns; iColumn++) { if (whichKnapsack[iColumn] < 0) whichColumn[nCol++] = iColumn; } ClpSimplex finalModelX(&tempModel, nRow, whichRow, nCol, whichColumn, false, false, false); OsiClpSolverInterface finalModelY(&finalModelX, true); finalModel = finalModelY.clone(); finalModelY.releaseClp(); // Put back priorities const int * priorities = model.priorities(); if (priorities) { finalModel->findIntegers(false); OsiObject ** objects = finalModel->objects(); int numberObjects = finalModel->numberObjects(); for (int iObj = 0; iObj < numberObjects; iObj++) { int iColumn = objects[iObj]->columnNumber(); if (iColumn >= 0 && iColumn < nCol) { #ifndef NDEBUG OsiSimpleInteger * obj = dynamic_cast <OsiSimpleInteger *>(objects[iObj]) ; #endif assert (obj); int iPriority = priorities[whichColumn[iColumn]]; if (iPriority > 0) objects[iObj]->setPriority(iPriority); } } } for (iRow = 0; iRow < numberRows; iRow++) { whichRow[iRow] = iRow; } int numberOther = finalModel->getNumCols(); int nLargest = 0; int nelLargest = 0; int nTotal = 0; for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) { iRow = knapsackRow[iKnapsack]; int nCreate = maxTotal; int nelCreate = coinModel.expandKnapsack(iRow, nCreate, NULL, NULL, NULL, NULL); if (nelCreate < 0) badModel = true; nTotal += nCreate; nLargest = CoinMax(nLargest, nCreate); nelLargest = CoinMax(nelLargest, nelCreate); } if (nTotal > maxTotal) badModel = true; if (!badModel) { // Now arrays for building nelLargest = CoinMax(nelLargest, nLargest) + 1; double * buildObj = new double [nLargest]; double * buildElement = new double [nelLargest]; int * buildStart = new int[nLargest+1]; int * buildRow = new int[nelLargest]; // alow for integers in knapsacks OsiObject ** object = new OsiObject * [numberKnapsack+nTotal]; int nSOS = 0; int nObj = numberKnapsack; for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) { knapsackStart[iKnapsack] = finalModel->getNumCols(); iRow = knapsackRow[iKnapsack]; int nCreate = 10000; coinModel.expandKnapsack(iRow, nCreate, buildObj, buildStart, buildRow, buildElement); // Redo row numbers for (iColumn = 0; iColumn < nCreate; iColumn++) { for (int j = buildStart[iColumn]; j < buildStart[iColumn+1]; j++) { int jRow = buildRow[j]; jRow = lookupRow[jRow]; assert (jRow >= 0 && jRow < nRow); buildRow[j] = jRow; } } finalModel->addCols(nCreate, buildStart, buildRow, buildElement, NULL, NULL, buildObj); int numberFinal = finalModel->getNumCols(); for (iColumn = numberOther; iColumn < numberFinal; iColumn++) { if (markKnapsack[iKnapsack] < 0) { finalModel->setColUpper(iColumn, maxCoefficient); finalModel->setInteger(iColumn); } else { finalModel->setColUpper(iColumn, maxCoefficient + 1.0); finalModel->setInteger(iColumn); } OsiSimpleInteger * sosObject = new OsiSimpleInteger(finalModel, iColumn); sosObject->setPriority(1000000); object[nObj++] = sosObject; buildRow[iColumn-numberOther] = iColumn; buildElement[iColumn-numberOther] = 1.0; } if (markKnapsack[iKnapsack] < 0) { // convexity row finalModel->addRow(numberFinal - numberOther, buildRow, buildElement, 1.0, 1.0); } else { int iColumn = markKnapsack[iKnapsack]; int n = numberFinal - numberOther; buildRow[n] = iColumn; buildElement[n++] = -fabs(coefficient[iKnapsack]); // convexity row (sort of) finalModel->addRow(n, buildRow, buildElement, 0.0, 0.0); OsiSOS * sosObject = new OsiSOS(finalModel, n - 1, buildRow, NULL, 1); sosObject->setPriority(iKnapsack + SOSPriority); // Say not integral even if is (switch off heuristics) sosObject->setIntegerValued(false); object[nSOS++] = sosObject; } numberOther = numberFinal; } finalModel->addObjects(nObj, object); for (iKnapsack = 0; iKnapsack < nObj; iKnapsack++) delete object[iKnapsack]; delete [] object; // Can we move any rows to cuts const int * cutMarker = coinModel.cutMarker(); if (cutMarker && 0) { printf("AMPL CUTS OFF until global cuts fixed\n"); cutMarker = NULL; } if (cutMarker) { // Row copy const CoinPackedMatrix * matrixByRow = finalModel->getMatrixByRow(); const double * elementByRow = matrixByRow->getElements(); const int * column = matrixByRow->getIndices(); const CoinBigIndex * rowStart = matrixByRow->getVectorStarts(); const int * rowLength = matrixByRow->getVectorLengths(); const double * rowLower = finalModel->getRowLower(); const double * rowUpper = finalModel->getRowUpper(); int nDelete = 0; for (iRow = 0; iRow < numberRows; iRow++) { if (cutMarker[iRow] && lookupRow[iRow] >= 0) { int jRow = lookupRow[iRow]; whichRow[nDelete++] = jRow; int start = rowStart[jRow]; stored.addCut(rowLower[jRow], rowUpper[jRow], rowLength[jRow], column + start, elementByRow + start); } } finalModel->deleteRows(nDelete, whichRow); } knapsackStart[numberKnapsack] = finalModel->getNumCols(); delete [] buildObj; delete [] buildElement; delete [] buildStart; delete [] buildRow; finalModel->writeMps("full"); } } } delete [] whichKnapsack; delete [] markRow; delete [] markKnapsack; delete [] coefficient; delete [] linear; delete [] whichRow; delete [] lookupRow; delete si; si = NULL; if (!badModel && finalModel) { finalModel->setDblParam(OsiObjOffset, coinModel.objectiveOffset()); return finalModel; } else { delete finalModel; printf("can't make knapsacks - did you set fixedPriority (extra1)\n"); return NULL; } }
//############################################################################# void MibSHeuristic::lowerObjHeuristic() { /* optimize wrt to lower-level objective over current feasible lp feasible region */ MibSModel * model = MibSModel_; OsiSolverInterface * oSolver = model->getSolver(); //OsiSolverInterface * hSolver = new OsiCbcSolverInterface(); OsiSolverInterface* hSolver = new OsiSymSolverInterface(); double objSense(model->getLowerObjSense()); int lCols(model->getLowerDim()); int uCols(model->getUpperDim()); int * lColIndices = model->getLowerColInd(); int * uColIndices = model->getUpperColInd(); double * lObjCoeffs = model->getLowerObjCoeffs(); //int tCols(lCols + uCols); int tCols(oSolver->getNumCols()); //assert(tCols == oSolver->getNumCols()); hSolver->loadProblem(*oSolver->getMatrixByCol(), oSolver->getColLower(), oSolver->getColUpper(), oSolver->getObjCoefficients(), oSolver->getRowLower(), oSolver->getRowUpper()); int j(0); for(j = 0; j < tCols; j++){ if(oSolver->isInteger(j)) hSolver->setInteger(j); } double * nObjCoeffs = new double[tCols]; int i(0), index(0); CoinZeroN(nObjCoeffs, tCols); for(i = 0; i < lCols; i++){ index = lColIndices[i]; nObjCoeffs[index] = lObjCoeffs[i]; } //MibS objective sense is the opposite of OSI's! hSolver->setObjSense(objSense); hSolver->setObjective(nObjCoeffs); //double cutoff(model->getCutoff()); double cutoff(model->getKnowledgeBroker()->getIncumbentValue()); if(model->getNumSolutions()){ CoinPackedVector objCon; //double rhs(cutoff * objSense); //double smlTol(1.0); double rhs(cutoff); for(i = 0; i < tCols; i++){ objCon.insert(i, oSolver->getObjCoefficients()[i] * oSolver->getObjSense()); } hSolver->addRow(objCon, - hSolver->getInfinity(), rhs); } if(0) hSolver->writeLp("lobjheurstic"); if(0){ dynamic_cast<OsiCbcSolverInterface *> (hSolver)->getModelPtr()->messageHandler()->setLogLevel(0); } else{ dynamic_cast<OsiSymSolverInterface *> (hSolver)->setSymParam("prep_level", -1); dynamic_cast<OsiSymSolverInterface *> (hSolver)->setSymParam("verbosity", -2); dynamic_cast<OsiSymSolverInterface *> (hSolver)->setSymParam("max_active_nodes", 1); } hSolver->branchAndBound(); if(hSolver->isProvenOptimal()){ double upperObjVal(0.0); /*****************NEW ******************/ MibSSolution *mibSol = NULL; OsiSolverInterface * lSolver = model->bS_->setUpModel(hSolver, true); if(0){ lSolver->writeLp("tmp"); } if(0){ dynamic_cast<OsiCbcSolverInterface *> (lSolver)->getModelPtr()->messageHandler()->setLogLevel(0); } else{ dynamic_cast<OsiSymSolverInterface *> (lSolver)->setSymParam("prep_level", -1); dynamic_cast<OsiSymSolverInterface *> (lSolver)->setSymParam("verbosity", -2); dynamic_cast<OsiSymSolverInterface *> (lSolver)->setSymParam("max_active_nodes", 1); } lSolver->branchAndBound(); if (lSolver->isProvenOptimal()){ const double * sol = hSolver->getColSolution(); double objVal(lSolver->getObjValue() * objSense); double etol(etol_); double lowerObj = getLowerObj(sol, objSense); double * optUpperSolutionOrd = new double[uCols]; double * optLowerSolutionOrd = new double[lCols]; CoinZeroN(optUpperSolutionOrd, uCols); CoinZeroN(optLowerSolutionOrd, lCols); if(fabs(objVal - lowerObj) < etol){ /** Current solution is bilevel feasible **/ for(i = 0; i < tCols; i++) upperObjVal += hSolver->getColSolution()[i] * oSolver->getObjCoefficients()[i]; mibSol = new MibSSolution(hSolver->getNumCols(), hSolver->getColSolution(), upperObjVal, model); model->storeSolution(BlisSolutionTypeHeuristic, mibSol); mibSol = NULL; } else{ /* solution is not bilevel feasible, create one that is */ const double * uSol = hSolver->getColSolution(); const double * lSol = lSolver->getColSolution(); int numElements(hSolver->getNumCols()); int i(0), pos(0), index(0); double * lpSolution = new double[numElements]; double upperObj(0.0); //FIXME: problem is still here. indices may be wrong. //also is all this necessary, or can we just paste together uSol and lSol? //this may be an old comment for(i = 0; i < numElements; i++){ pos = model->bS_->binarySearch(0, lCols - 1, i, lColIndices); if(pos < 0){ pos = model->bS_->binarySearch(0, uCols - 1, i, uColIndices); if (pos >= 0){ optUpperSolutionOrd[pos] = uSol[i]; } } else{ optLowerSolutionOrd[pos] = lSol[pos]; } } for(i = 0; i < uCols; i++){ index = uColIndices[i]; lpSolution[index] = optUpperSolutionOrd[i]; upperObj += optUpperSolutionOrd[i] * oSolver->getObjCoefficients()[index]; } for(i = 0; i < lCols; i++){ index = lColIndices[i]; lpSolution[index] = optLowerSolutionOrd[i]; upperObj += optLowerSolutionOrd[i] * oSolver->getObjCoefficients()[index]; } if(model->checkUpperFeasibility(lpSolution)){ mibSol = new MibSSolution(hSolver->getNumCols(), lpSolution, upperObj * oSolver->getObjSense(), model); model->storeSolution(BlisSolutionTypeHeuristic, mibSol); mibSol = NULL; } delete [] lpSolution; } } delete lSolver; } delete hSolver; }
//-------------------------------------------------------------------------- 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 }
// This looks at solution and sets bounds to contain solution void CbcLink::feasibleRegion() { int j; int firstNonZero=-1; int lastNonZero = -1; OsiSolverInterface * solver = model_->solver(); const double * solution = model_->testSolution(); const double * upper = solver->getColUpper(); double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance); double weight = 0.0; double sum =0.0; int base=0; for (j=0;j<numberMembers_;j++) { for (int k=0;k<numberLinks_;k++) { int iColumn = which_[base+k]; double value = CoinMax(0.0,solution[iColumn]); sum += value; if (value>integerTolerance&&upper[iColumn]) { weight += weights_[j]*value; if (firstNonZero<0) firstNonZero=j; lastNonZero=j; } } base += numberLinks_; } #ifdef DISTANCE if (lastNonZero-firstNonZero>sosType_-1) { /* may still be satisfied. For LOS type 2 we might wish to move coding around and keep initial info in model_ for speed */ int iWhere; bool possible=false; for (iWhere=firstNonZero;iWhere<=lastNonZero;iWhere++) { if (fabs(weight-weights_[iWhere])<1.0e-8) { possible=true; break; } } if (possible) { // One could move some of this (+ arrays) into model_ const CoinPackedMatrix * matrix = solver->getMatrixByCol(); const double * element = matrix->getMutableElements(); const int * row = matrix->getIndices(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const int * columnLength = matrix->getVectorLengths(); const double * rowSolution = solver->getRowActivity(); const double * rowLower = solver->getRowLower(); const double * rowUpper = solver->getRowUpper(); int numberRows = matrix->getNumRows(); double * array = new double [numberRows]; CoinZeroN(array,numberRows); int * which = new int [numberRows]; int n=0; int base=numberLinks_*firstNonZero; for (j=firstNonZero;j<=lastNonZero;j++) { for (int k=0;k<numberLinks_;k++) { int iColumn = which_[base+k]; double value = CoinMax(0.0,solution[iColumn]); if (value>integerTolerance&&upper[iColumn]) { value = CoinMin(value,upper[iColumn]); for (int j=columnStart[iColumn];j<columnStart[iColumn]+columnLength[iColumn];j++) { int iRow = row[j]; double a = array[iRow]; if (a) { a += value*element[j]; if (!a) a = 1.0e-100; } else { which[n++]=iRow; a=value*element[j]; assert (a); } array[iRow]=a; } } } base += numberLinks_; } base=numberLinks_*iWhere; for (int k=0;k<numberLinks_;k++) { int iColumn = which_[base+k]; const double value = 1.0; for (int j=columnStart[iColumn];j<columnStart[iColumn]+columnLength[iColumn];j++) { int iRow = row[j]; double a = array[iRow]; if (a) { a -= value*element[j]; if (!a) a = 1.0e-100; } else { which[n++]=iRow; a=-value*element[j]; assert (a); } array[iRow]=a; } } for (j=0;j<n;j++) { int iRow = which[j]; // moving to point will increase row solution by this double distance = array[iRow]; if (distance>1.0e-8) { if (distance+rowSolution[iRow]>rowUpper[iRow]+1.0e-8) { possible=false; break; } } else if (distance<-1.0e-8) { if (distance+rowSolution[iRow]<rowLower[iRow]-1.0e-8) { possible=false; break; } } } for (j=0;j<n;j++) array[which[j]]=0.0; delete [] array; delete [] which; if (possible) { printf("possible feas region %d %d %d\n",firstNonZero,lastNonZero,iWhere); firstNonZero=iWhere; lastNonZero=iWhere; } } } #else assert (lastNonZero-firstNonZero<sosType_) ; #endif base=0; for (j=0;j<firstNonZero;j++) { for (int k=0;k<numberLinks_;k++) { int iColumn = which_[base+k]; solver->setColUpper(iColumn,0.0); } base += numberLinks_; } // skip base += numberLinks_; for (j=lastNonZero+1;j<numberMembers_;j++) { for (int k=0;k<numberLinks_;k++) { int iColumn = which_[base+k]; solver->setColUpper(iColumn,0.0); } base += numberLinks_; } }
// Infeasibility - large is 0.5 double CbcLink::infeasibility(int & preferredWay) const { int j; int firstNonZero=-1; int lastNonZero = -1; OsiSolverInterface * solver = model_->solver(); const double * solution = model_->testSolution(); //const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance); double weight = 0.0; double sum =0.0; // check bounds etc double lastWeight=-1.0e100; int base=0; for (j=0;j<numberMembers_;j++) { for (int k=0;k<numberLinks_;k++) { int iColumn = which_[base+k]; //if (lower[iColumn]) //throw CoinError("Non zero lower bound in CBCLink","infeasibility","CbcLink"); if (lastWeight>=weights_[j]-1.0e-7) throw CoinError("Weights too close together in CBCLink","infeasibility","CbcLink"); double value = CoinMax(0.0,solution[iColumn]); sum += value; if (value>integerTolerance&&upper[iColumn]) { // Possibly due to scaling a fixed variable might slip through if (value>upper[iColumn]+1.0e-8) { // Could change to #ifdef CBC_DEBUG #ifndef NDEBUG if (model_->messageHandler()->logLevel()>1) printf("** Variable %d (%d) has value %g and upper bound of %g\n", iColumn,j,value,upper[iColumn]); #endif } value = CoinMin(value,upper[iColumn]); weight += weights_[j]*value; if (firstNonZero<0) firstNonZero=j; lastNonZero=j; } } base += numberLinks_; } double valueInfeasibility; preferredWay=1; if (lastNonZero-firstNonZero>=sosType_) { // find where to branch assert (sum>0.0); weight /= sum; valueInfeasibility = lastNonZero-firstNonZero+1; valueInfeasibility *= 0.5/((double) numberMembers_); //#define DISTANCE #ifdef DISTANCE assert (sosType_==1); // code up /* may still be satisfied. For LOS type 2 we might wish to move coding around and keep initial info in model_ for speed */ int iWhere; bool possible=false; for (iWhere=firstNonZero;iWhere<=lastNonZero;iWhere++) { if (fabs(weight-weights_[iWhere])<1.0e-8) { possible=true; break; } } if (possible) { // One could move some of this (+ arrays) into model_ const CoinPackedMatrix * matrix = solver->getMatrixByCol(); const double * element = matrix->getMutableElements(); const int * row = matrix->getIndices(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const int * columnLength = matrix->getVectorLengths(); const double * rowSolution = solver->getRowActivity(); const double * rowLower = solver->getRowLower(); const double * rowUpper = solver->getRowUpper(); int numberRows = matrix->getNumRows(); double * array = new double [numberRows]; CoinZeroN(array,numberRows); int * which = new int [numberRows]; int n=0; int base=numberLinks_*firstNonZero; for (j=firstNonZero;j<=lastNonZero;j++) { for (int k=0;k<numberLinks_;k++) { int iColumn = which_[base+k]; double value = CoinMax(0.0,solution[iColumn]); if (value>integerTolerance&&upper[iColumn]) { value = CoinMin(value,upper[iColumn]); for (int j=columnStart[iColumn];j<columnStart[iColumn]+columnLength[iColumn];j++) { int iRow = row[j]; double a = array[iRow]; if (a) { a += value*element[j]; if (!a) a = 1.0e-100; } else { which[n++]=iRow; a=value*element[j]; assert (a); } array[iRow]=a; } } } base += numberLinks_; } base=numberLinks_*iWhere; for (int k=0;k<numberLinks_;k++) { int iColumn = which_[base+k]; const double value = 1.0; for (int j=columnStart[iColumn];j<columnStart[iColumn]+columnLength[iColumn];j++) { int iRow = row[j]; double a = array[iRow]; if (a) { a -= value*element[j]; if (!a) a = 1.0e-100; } else { which[n++]=iRow; a=-value*element[j]; assert (a); } array[iRow]=a; } } for (j=0;j<n;j++) { int iRow = which[j]; // moving to point will increase row solution by this double distance = array[iRow]; if (distance>1.0e-8) { if (distance+rowSolution[iRow]>rowUpper[iRow]+1.0e-8) { possible=false; break; } } else if (distance<-1.0e-8) { if (distance+rowSolution[iRow]<rowLower[iRow]-1.0e-8) { possible=false; break; } } } for (j=0;j<n;j++) array[which[j]]=0.0; delete [] array; delete [] which; if (possible) { valueInfeasibility=0.0; printf("possible %d %d %d\n",firstNonZero,lastNonZero,iWhere); } } #endif } else { valueInfeasibility = 0.0; // satisfied } return valueInfeasibility; }
/* Does a lot of the work, Returns 0 if no good, 1 if dj, 2 if clean, 3 if both 10 if branching on ones away from bound */ int CbcBranchToFixLots::shallWe() const { int returnCode = 0; OsiSolverInterface * solver = model_->solver(); int numberRows = matrixByRow_.getNumRows(); //if (numberRows!=solver->getNumRows()) //return 0; 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(); if (numberClean_ > 1000000) { int wanted = numberClean_ % 1000000; int * sort = new int[numberIntegers]; double * dsort = new double[numberIntegers]; int nSort = 0; 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; } delete [] sort; delete [] dsort; return (n >= wanted) ? 10 : 0; } 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_); if (djTolerance_ < 1.0e10) { int nSort = 0; int numberFixed = 0; 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_) { nSort++; } } else if (solution[iColumn] > upper[iColumn] - tolerance) { if (dj[iColumn] < -djTolerance_) { nSort++; } } } } else { numberFixed++; } } if (numberFixed + nSort < wantedFixed && !alwaysCreate_) { returnCode = 0; } else if (numberFixed < wantedFixed) { returnCode = 1; } else { returnCode = 0; } } if (numberClean_) { // see how many rows clean 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 numberClean = 0; bool someToDoYet = false; int numberColumns = solver->getNumCols(); char * mark = new char[numberColumns]; int numberFixed = 0; for (i = 0; i < numberColumns; i++) { if (columnLower[i] != columnUpper[i]) { mark[i] = 0; } else { mark[i] = 1; numberFixed++; } } int numberNewFixed = 0; 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) { someToDoYet = true; } else { numberClean++; for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) { int iColumn = column[j]; if (columnLower[iColumn] != columnUpper[iColumn] && !mark[iColumn]) { mark[iColumn] = 1; numberNewFixed++; } } } } } delete [] mark; //printf("%d clean, %d old fixed, %d new fixed\n", // numberClean,numberFixed,numberNewFixed); if (someToDoYet && numberClean < numberClean_ && numberNewFixed + numberFixed < wantedFixed) { } else if (numberFixed < wantedFixed) { returnCode |= 2; } else { } } return returnCode; }
/* First tries setting a variable to better value. If feasible then tries setting others. If not feasible then tries swaps Returns 1 if solution, 0 if not The main body of this routine implements an O((q^2)/2) brute force search around the current solution, for q = number of integer variables. Call this the inc/dec heuristic. For each integer variable x<i>, first decrement the value. Then, for integer variables x<i+1>, ..., x<q-1>, try increment and decrement. If one of these permutations produces a better solution, remember it. Then repeat, with x<i> incremented. If we find a better solution, update our notion of current solution and continue. The net effect is a greedy walk: As each improving pair is found, the current solution is updated and the search continues from this updated solution. Way down at the end, we call solutionFix, which will create a drastically restricted problem based on variables marked as used, then do mini-BaC on the restricted problem. This can occur even if we don't try the inc/dec heuristic. This would be more obvious if the inc/dec heuristic were broken out as a separate routine and solutionFix had a name that reflected where it was headed. The return code of 0 is grossly overloaded, because it maps to a return code of 0 from solutionFix, which is itself grossly overloaded. See comments in solutionFix and in CbcHeuristic::smallBranchAndBound. */ int CbcHeuristicLocal::solution(double & solutionValue, double * betterSolution) { /* Execute only if a new solution has been discovered since the last time we were called. */ numCouldRun_++; // See if frequency kills off idea int swap = swap_%100; int skip = swap_/100; int nodeCount = model_->getNodeCount(); if (nodeCount<lastRunDeep_+skip && nodeCount != lastRunDeep_+1) return 0; if (numberSolutions_ == model_->getSolutionCount() && (numberSolutions_ == howOftenShallow_ || nodeCount < lastRunDeep_+2*skip)) return 0; howOftenShallow_ = numberSolutions_; numberSolutions_ = model_->getSolutionCount(); if (nodeCount<lastRunDeep_+skip ) return 0; lastRunDeep_ = nodeCount; howOftenShallow_ = numberSolutions_; if ((swap%10) == 2) { // try merge return solutionFix( solutionValue, betterSolution, NULL); } /* Exclude long (column), thin (row) systems. Given the n^2 nature of the search, more than 100,000 columns could get expensive. But I don't yet see the rationale for the second part of the condition (cols > 10*rows). And cost is proportional to number of integer variables --- shouldn't we use that? Why wait until we have more than one solution? */ if ((model_->getNumCols() > 100000 && model_->getNumCols() > 10*model_->getNumRows()) || numberSolutions_ <= 1) return 0; // probably not worth it // worth trying OsiSolverInterface * solver = model_->solver(); const double * rowLower = solver->getRowLower(); const double * rowUpper = solver->getRowUpper(); const double * solution = model_->bestSolution(); /* Shouldn't this test be redundant if we've already checked that numberSolutions_ > 1? Stronger: shouldn't this be an assertion? */ if (!solution) return 0; // No solution found yet const double * objective = solver->getObjCoefficients(); double primalTolerance; solver->getDblParam(OsiPrimalTolerance, primalTolerance); int numberRows = matrix_.getNumRows(); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); int i; double direction = solver->getObjSense(); double newSolutionValue = model_->getObjValue() * direction; int returnCode = 0; numRuns_++; // Column copy const double * element = matrix_.getElements(); const int * row = matrix_.getIndices(); const CoinBigIndex * columnStart = matrix_.getVectorStarts(); const int * columnLength = matrix_.getVectorLengths(); // Get solution array for heuristic solution int numberColumns = solver->getNumCols(); double * newSolution = new double [numberColumns]; memcpy(newSolution, solution, numberColumns*sizeof(double)); #ifdef LOCAL_FIX_CONTINUOUS // mark continuous used const double * columnLower = solver->getColLower(); for (int iColumn = 0; iColumn < numberColumns; iColumn++) { if (!solver->isInteger(iColumn)) { if (solution[iColumn] > columnLower[iColumn] + 1.0e-8) used_[iColumn] = numberSolutions_; } } #endif // way is 1 if down possible, 2 if up possible, 3 if both possible char * way = new char[numberIntegers]; // corrected costs double * cost = new double[numberIntegers]; // for array to mark infeasible rows after iColumn branch char * mark = new char[numberRows]; memset(mark, 0, numberRows); // space to save values so we don't introduce rounding errors double * save = new double[numberRows]; /* Force variables within their original bounds, then to the nearest integer. Overall, we seem to be prepared to cope with noninteger bounds. Is this necessary? Seems like we'd be better off to force the bounds to integrality as part of preprocessing. More generally, why do we need to do this? This solution should have been cleaned and checked when it was accepted as a solution! Once the value is set, decide whether we can move up or down. The only place that used_ is used is in solutionFix; if a variable is not flagged as used, it will be fixed (at lower bound). Why the asymmetric treatment? This makes some sense for binary variables (for which there are only two options). But for general integer variables, why not make a similar test against the original upper bound? */ // clean solution for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; const OsiObject * object = model_->object(i); // get original bounds double originalLower; double originalUpper; getIntegerInformation( object, originalLower, originalUpper); double value = newSolution[iColumn]; if (value < originalLower) { value = originalLower; newSolution[iColumn] = value; } else if (value > originalUpper) { value = originalUpper; newSolution[iColumn] = value; } double nearest = floor(value + 0.5); //assert(fabs(value-nearest)<10.0*primalTolerance); value = nearest; newSolution[iColumn] = nearest; // if away from lower bound mark that fact if (nearest > originalLower) { used_[iColumn] = numberSolutions_; } cost[i] = direction * objective[iColumn]; /* Given previous computation we're checking that value is at least 1 away from the original bounds. */ int iway = 0; if (value > originalLower + 0.5) iway = 1; if (value < originalUpper - 0.5) iway |= 2; way[i] = static_cast<char>(iway); } /* Calculate lhs of each constraint for groomed solution. */ // get row activities double * rowActivity = new double[numberRows]; memset(rowActivity, 0, numberRows*sizeof(double)); for (i = 0; i < numberColumns; i++) { int j; double value = newSolution[i]; if (value) { for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iRow = row[j]; rowActivity[iRow] += value * element[j]; } } } /* Check that constraints are satisfied. For small infeasibility, force the activity within bound. Again, why is this necessary if the current solution was accepted as a valid solution? Why are we scanning past the first unacceptable constraint? */ // check was feasible - if not adjust (cleaning may move) // if very infeasible then give up bool tryHeuristic = true; for (i = 0; i < numberRows; i++) { if (rowActivity[i] < rowLower[i]) { if (rowActivity[i] < rowLower[i] - 10.0*primalTolerance) tryHeuristic = false; rowActivity[i] = rowLower[i]; } else if (rowActivity[i] > rowUpper[i]) { if (rowActivity[i] < rowUpper[i] + 10.0*primalTolerance) tryHeuristic = false; rowActivity[i] = rowUpper[i]; } } /* This bit of code is not quite totally redundant: it'll bail at 10,000 instead of 100,000. Potentially we can do a lot of work to get here, only to abandon it. */ // Switch off if may take too long if (model_->getNumCols() > 10000 && model_->getNumCols() > 10*model_->getNumRows()) tryHeuristic = false; /* Try the inc/dec heuristic? */ if (tryHeuristic) { // total change in objective double totalChange = 0.0; // local best change in objective double bestChange = 0.0; // maybe just do 1000 int maxIntegers = numberIntegers; if (((swap/10) &1) != 0) { maxIntegers = CoinMin(1000,numberIntegers); } /* Outer loop to walk integer variables. Call the current variable x<i>. At the end of this loop, bestChange will contain the best (negative) change in the objective for any single pair. The trouble is, we're limited to monotonically increasing improvement. Suppose we discover an improvement of 10 for some pair. If, later in the search, we discover an improvement of 9 for some other pair, we will not use it. That seems wasteful. */ for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; bestChange = 0.0; int endInner = CoinMin(numberIntegers,i+maxIntegers); double objectiveCoefficient = cost[i]; int k; int j; int goodK = -1; int wayK = -1, wayI = -1; /* Try decrementing x<i>. */ if ((way[i]&1) != 0) { int numberInfeasible = 0; /* Adjust row activities where x<i> has a nonzero coefficient. Save the old values for restoration. Mark any rows that become infeasible as a result of the decrement. */ // save row activities and adjust for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; save[iRow] = rowActivity[iRow]; rowActivity[iRow] -= element[j]; if (rowActivity[iRow] < rowLower[iRow] - primalTolerance || rowActivity[iRow] > rowUpper[iRow] + primalTolerance) { // mark row mark[iRow] = 1; numberInfeasible++; } } /* Run through the remaining integer variables. Try increment and decrement on each one. If the potential objective change is better than anything we've seen so far, do a full evaluation of x<k> in that direction. If we can repair all infeasibilities introduced by pushing x<i> down, we have a winner. Remember the best variable, and the direction for x<i> and x<k>. */ // try down for (k = i + 1; k < endInner; k++) { if ((way[k]&1) != 0) { // try down if (-objectiveCoefficient - cost[k] < bestChange) { // see if feasible down bool good = true; int numberMarked = 0; int kColumn = integerVariable[k]; for (j = columnStart[kColumn]; j < columnStart[kColumn] + columnLength[kColumn]; j++) { int iRow = row[j]; double newValue = rowActivity[iRow] - element[j]; if (newValue < rowLower[iRow] - primalTolerance || newValue > rowUpper[iRow] + primalTolerance) { good = false; break; } else if (mark[iRow]) { // made feasible numberMarked++; } } if (good && numberMarked == numberInfeasible) { // better solution goodK = k; wayK = -1; wayI = -1; bestChange = -objectiveCoefficient - cost[k]; } } } if ((way[k]&2) != 0) { // try up if (-objectiveCoefficient + cost[k] < bestChange) { // see if feasible up bool good = true; int numberMarked = 0; int kColumn = integerVariable[k]; for (j = columnStart[kColumn]; j < columnStart[kColumn] + columnLength[kColumn]; j++) { int iRow = row[j]; double newValue = rowActivity[iRow] + element[j]; if (newValue < rowLower[iRow] - primalTolerance || newValue > rowUpper[iRow] + primalTolerance) { good = false; break; } else if (mark[iRow]) { // made feasible numberMarked++; } } if (good && numberMarked == numberInfeasible) { // better solution goodK = k; wayK = 1; wayI = -1; bestChange = -objectiveCoefficient + cost[k]; } } } } /* Remove effect of decrementing x<i> by restoring original lhs values. */ // restore row activities for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; rowActivity[iRow] = save[iRow]; mark[iRow] = 0; } } /* Try to increment x<i>. Actions as for decrement. */ if ((way[i]&2) != 0) { int numberInfeasible = 0; // save row activities and adjust for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; save[iRow] = rowActivity[iRow]; rowActivity[iRow] += element[j]; if (rowActivity[iRow] < rowLower[iRow] - primalTolerance || rowActivity[iRow] > rowUpper[iRow] + primalTolerance) { // mark row mark[iRow] = 1; numberInfeasible++; } } // try up for (k = i + 1; k < endInner; k++) { if ((way[k]&1) != 0) { // try down if (objectiveCoefficient - cost[k] < bestChange) { // see if feasible down bool good = true; int numberMarked = 0; int kColumn = integerVariable[k]; for (j = columnStart[kColumn]; j < columnStart[kColumn] + columnLength[kColumn]; j++) { int iRow = row[j]; double newValue = rowActivity[iRow] - element[j]; if (newValue < rowLower[iRow] - primalTolerance || newValue > rowUpper[iRow] + primalTolerance) { good = false; break; } else if (mark[iRow]) { // made feasible numberMarked++; } } if (good && numberMarked == numberInfeasible) { // better solution goodK = k; wayK = -1; wayI = 1; bestChange = objectiveCoefficient - cost[k]; } } } if ((way[k]&2) != 0) { // try up if (objectiveCoefficient + cost[k] < bestChange) { // see if feasible up bool good = true; int numberMarked = 0; int kColumn = integerVariable[k]; for (j = columnStart[kColumn]; j < columnStart[kColumn] + columnLength[kColumn]; j++) { int iRow = row[j]; double newValue = rowActivity[iRow] + element[j]; if (newValue < rowLower[iRow] - primalTolerance || newValue > rowUpper[iRow] + primalTolerance) { good = false; break; } else if (mark[iRow]) { // made feasible numberMarked++; } } if (good && numberMarked == numberInfeasible) { // better solution goodK = k; wayK = 1; wayI = 1; bestChange = objectiveCoefficient + cost[k]; } } } } // restore row activities for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; rowActivity[iRow] = save[iRow]; mark[iRow] = 0; } } /* We've found a pair x<i> and x<k> which produce a better solution. Update our notion of current solution to match. Why does this not update newSolutionValue? */ if (goodK >= 0) { // we found something - update solution for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; rowActivity[iRow] += wayI * element[j]; } newSolution[iColumn] += wayI; int kColumn = integerVariable[goodK]; for (j = columnStart[kColumn]; j < columnStart[kColumn] + columnLength[kColumn]; j++) { int iRow = row[j]; rowActivity[iRow] += wayK * element[j]; } newSolution[kColumn] += wayK; /* Adjust motion range for x<k>. We may have banged up against a bound with that last move. */ // See if k can go further ? const OsiObject * object = model_->object(goodK); // get original bounds double originalLower; double originalUpper; getIntegerInformation( object, originalLower, originalUpper); double value = newSolution[kColumn]; int iway = 0; if (value > originalLower + 0.5) iway = 1; if (value < originalUpper - 0.5) iway |= 2; way[goodK] = static_cast<char>(iway); totalChange += bestChange; } } /* End of loop to try increment/decrement of integer variables. newSolutionValue does not necessarily match the current newSolution, and bestChange simply reflects the best single change. Still, that's sufficient to indicate that there's been at least one change. Check that we really do have a valid solution. */ if (totalChange + newSolutionValue < solutionValue) { // paranoid check memset(rowActivity, 0, numberRows*sizeof(double)); for (i = 0; i < numberColumns; i++) { int j; double value = newSolution[i]; if (value) { for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iRow = row[j]; rowActivity[iRow] += value * element[j]; } } } int numberBad = 0; double sumBad = 0.0; // check was approximately feasible for (i = 0; i < numberRows; i++) { if (rowActivity[i] < rowLower[i]) { sumBad += rowLower[i] - rowActivity[i]; if (rowActivity[i] < rowLower[i] - 10.0*primalTolerance) numberBad++; } else if (rowActivity[i] > rowUpper[i]) { sumBad += rowUpper[i] - rowActivity[i]; if (rowActivity[i] > rowUpper[i] + 10.0*primalTolerance) numberBad++; } } if (!numberBad) { for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; const OsiObject * object = model_->object(i); // get original bounds double originalLower; double originalUpper; getIntegerInformation( object, originalLower, originalUpper); double value = newSolution[iColumn]; // if away from lower bound mark that fact if (value > originalLower) { used_[iColumn] = numberSolutions_; } } /* Copy the solution to the array returned to the client. Grab a basis from the solver (which, if it exists, is almost certainly infeasible, but it should be ok for a dual start). The value returned as solutionValue is conservative because of handling of newSolutionValue and bestChange, as described above. */ // new solution memcpy(betterSolution, newSolution, numberColumns*sizeof(double)); CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ; if (basis) { model_->setBestSolutionBasis(* basis); delete basis; } returnCode = 1; solutionValue = newSolutionValue + bestChange; } else { // bad solution - should not happen so debug if see message COIN_DETAIL_PRINT(printf("Local search got bad solution with %d infeasibilities summing to %g\n", numberBad, sumBad)); } } } /* We're done. Clean up. */ delete [] newSolution; delete [] rowActivity; delete [] way; delete [] cost; delete [] save; delete [] mark; /* Do we want to try swapping values between solutions? swap_ is set elsewhere; it's not adjusted during heuristic execution. Again, redundant test. We shouldn't be here if numberSolutions_ = 1. */ if (numberSolutions_ > 1 && (swap%10) == 1) { // try merge int returnCode2 = solutionFix( solutionValue, betterSolution, NULL); if (returnCode2) returnCode = 1; } return returnCode; }
//############################################################################# mcSol MibSHeuristic::solveSubproblem(double beta) { /* optimize wrt to weighted upper-level objective over current feasible lp feasible region */ MibSModel * model = MibSModel_; OsiSolverInterface * oSolver = model->getSolver(); //OsiSolverInterface * sSolver = new OsiCbcSolverInterface(); OsiSolverInterface* sSolver = new OsiSymSolverInterface(); //sSolver = oSolver->clone(); //OsiSolverInterface * sSolver = tmpSolver; //OsiSolverInterface * tmpSolver = new OsiSolverInterface(oSolver); double uObjSense(oSolver->getObjSense()); double lObjSense(model->getLowerObjSense()); int lCols(model->getLowerDim()); int uCols(model->getUpperDim()); int * lColIndices = model->getLowerColInd(); int * uColIndices = model->getUpperColInd(); double * lObjCoeffs = model->getLowerObjCoeffs(); const double * uObjCoeffs = oSolver->getObjCoefficients(); double etol(etol_); int tCols(uCols + lCols); assert(tCols == oSolver->getNumCols()); sSolver->loadProblem(*oSolver->getMatrixByCol(), oSolver->getColLower(), oSolver->getColUpper(), oSolver->getObjCoefficients(), oSolver->getRowLower(), oSolver->getRowUpper()); int j(0); for(j = 0; j < tCols; j++){ if(oSolver->isInteger(j)) sSolver->setInteger(j); } double * nObjCoeffs = new double[tCols]; int i(0), index(0); CoinZeroN(nObjCoeffs, tCols); /* Multiply the UL columns of the UL objective by beta */ for(i = 0; i < uCols; i++){ index = uColIndices[i]; if(fabs(uObjCoeffs[index]) > etol) nObjCoeffs[index] = beta * uObjCoeffs[index] * uObjSense; else nObjCoeffs[index] = 0.0; } /* Multiply the LL columns of the UL objective by beta */ for(i = 0; i < lCols; i++){ index = lColIndices[i]; if(fabs(uObjCoeffs[index]) > etol) nObjCoeffs[index] = beta* uObjCoeffs[index] * uObjSense; else nObjCoeffs[index] = 0.0; } /* Add the LL columns of the LL objective multiplied by (1 - beta) */ for(i = 0; i < lCols; i++){ index = lColIndices[i]; if(fabs(lObjCoeffs[i]) > etol) nObjCoeffs[index] += (1 - beta) * lObjCoeffs[i] * lObjSense; } sSolver->setObjective(nObjCoeffs); //int i(0); if(0){ for(i = 0; i < sSolver->getNumCols(); i++){ std::cout << "betaobj " << sSolver->getObjCoefficients()[i] << std::endl; } } if(0){ sSolver->writeLp("afterbeta"); //sSolver->writeMps("afterbeta"); } if(0){ for(i = 0; i < sSolver->getNumCols(); i++){ std::cout << "obj " << sSolver->getObjCoefficients()[i] << std::endl; std::cout << "upper " << sSolver->getColUpper()[i] << std::endl; std::cout << "lower " << sSolver->getColLower()[i] << std::endl; } } if(0){ dynamic_cast<OsiCbcSolverInterface *> (sSolver)->getModelPtr()->messageHandler()->setLogLevel(0); } else{ dynamic_cast<OsiSymSolverInterface *> (sSolver)->setSymParam("prep_level", -1); dynamic_cast<OsiSymSolverInterface *> (sSolver)->setSymParam("verbosity", -2); dynamic_cast<OsiSymSolverInterface *> (sSolver)->setSymParam("max_active_nodes", 1); } //dynamic_cast<OsiSymSolverInterface *> (sSolver)->branchAndBound(); sSolver->branchAndBound(); if(sSolver->isProvenOptimal()){ if(0){ std::cout << "writing lp file." << std::endl; sSolver->writeLp("afterbeta"); //sSolver->writeMps("afterbeta"); } double upperObjVal(0.0); double lowerObjVal(0.0); for(i = 0; i < tCols; i++){ upperObjVal += sSolver->getColSolution()[i] * oSolver->getObjCoefficients()[i]; if(0){ std::cout << "sSolver->getColSolution()[" << i << "] :" << sSolver->getColSolution()[i] << std::endl; } } lowerObjVal = getLowerObj(sSolver->getColSolution(), lObjSense); if(beta == 1.0){ /* fix upper-level objective to current value and reoptimize wrt to lower-level objective */ //OsiSolverInterface * nSolver = new OsiCbcSolverInterface(); OsiSolverInterface * nSolver = new OsiSymSolverInterface(); nSolver->loadProblem(*oSolver->getMatrixByCol(), oSolver->getColLower(), oSolver->getColUpper(), oSolver->getObjCoefficients(), oSolver->getRowLower(), oSolver->getRowUpper()); for(j = 0; j < tCols; j++){ if(oSolver->isInteger(j)) nSolver->setInteger(j); } CoinZeroN(nObjCoeffs, tCols); for(i = 0; i < lCols; i++){ index = lColIndices[i]; nObjCoeffs[index] = lObjCoeffs[i] * lObjSense; } nSolver->setObjective(nObjCoeffs); CoinPackedVector objCon; for(i = 0; i < tCols; i++){ objCon.insert(i, uObjCoeffs[i] * uObjSense); } nSolver->addRow(objCon, upperObjVal, upperObjVal); nSolver->writeLp("beta1"); if(0){ dynamic_cast<OsiCbcSolverInterface *> (nSolver)->getModelPtr()->messageHandler()->setLogLevel(0); } else{ dynamic_cast<OsiSymSolverInterface *> (nSolver)->setSymParam("prep_level", -1); dynamic_cast<OsiSymSolverInterface *> (nSolver)->setSymParam("verbosity", -2); dynamic_cast<OsiSymSolverInterface *> (nSolver)->setSymParam("max_active_nodes", 1); } nSolver->branchAndBound(); double * colsol = new double[tCols]; if(nSolver->isProvenOptimal()){ lowerObjVal = nSolver->getObjValue(); CoinCopyN(nSolver->getColSolution(), tCols, colsol); } else{ //just take the current solution lowerObjVal = sSolver->getObjValue(); CoinCopyN(sSolver->getColSolution(), tCols, colsol); } delete[] nObjCoeffs; nObjCoeffs = 0; delete sSolver; delete nSolver; return mcSol(std::make_pair(upperObjVal, lowerObjVal), colsol); } else if(beta == 0.0){ /* fix lower-level objective to current value and reoptimize wrt to upper-level objective */ //OsiSolverInterface * nSolver = new OsiCbcSolverInterface(); OsiSolverInterface * nSolver = new OsiSymSolverInterface(); nSolver->loadProblem(*oSolver->getMatrixByCol(), oSolver->getColLower(), oSolver->getColUpper(), oSolver->getObjCoefficients(), oSolver->getRowLower(), oSolver->getRowUpper()); for(j = 0; j < tCols; j++){ if(oSolver->isInteger(j)) nSolver->setInteger(j); } CoinZeroN(nObjCoeffs, tCols); for(i = 0; i < tCols; i++) nObjCoeffs[i] = uObjCoeffs[i] * uObjSense; nSolver->setObjective(nObjCoeffs); CoinPackedVector objCon; for(i = 0; i < lCols; i++){ index = lColIndices[i]; objCon.insert(index, lObjCoeffs[i] * lObjSense); } nSolver->addRow(objCon, lowerObjVal, lowerObjVal); if(0){ dynamic_cast<OsiCbcSolverInterface *> (nSolver)->getModelPtr()->messageHandler()->setLogLevel(0); } else{ dynamic_cast<OsiSymSolverInterface *> (nSolver)->setSymParam("prep_level", -1); dynamic_cast<OsiSymSolverInterface *> (nSolver)->setSymParam("verbosity", -2); dynamic_cast<OsiSymSolverInterface *> (nSolver)->setSymParam("max_active_nodes", 1); } if(0) nSolver->writeLp("nSolver"); nSolver->branchAndBound(); double * colsol = new double[tCols]; if(nSolver->isProvenOptimal()){ upperObjVal = nSolver->getObjValue(); CoinCopyN(nSolver->getColSolution(), tCols, colsol); } else{ upperObjVal = nSolver->getObjValue(); CoinCopyN(nSolver->getColSolution(), tCols, colsol); } delete[] nObjCoeffs; nObjCoeffs = 0; delete sSolver; delete nSolver; return mcSol(std::make_pair(upperObjVal, lowerObjVal), colsol); } else{ //no optimality cut needed here. all solutions are supported. double * colsol = new double[tCols]; CoinCopyN(sSolver->getColSolution(), tCols, colsol); delete[] nObjCoeffs; nObjCoeffs = 0; delete sSolver; return mcSol(std::make_pair(upperObjVal, lowerObjVal), colsol); } } else{ //FIXME:SHOULD JUST TAKE THIS OUT. DELETE sSolver and remove it from above nObjCoeffs = 0; delete[] nObjCoeffs; delete sSolver; std::cout << "Subproblem is not proven optimal." << std::endl; //return NULL; //abort(); } }
// See if rounding will give solution // Sets value of solution // Assumes rhs for original matrix still okay // At present only works with integers // Fix values if asked for // Returns 1 if solution, 0 if not int AbcRounding::solution(double & solutionValue, double * betterSolution) { // Get a copy of original matrix (and by row for rounding); matrix_ = *(model_->solver()->getMatrixByCol()); matrixByRow_ = *(model_->solver()->getMatrixByRow()); seed_=1; OsiSolverInterface * solver = model_->solver(); const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); const double * rowLower = solver->getRowLower(); const double * rowUpper = solver->getRowUpper(); const double * solution = solver->getColSolution(); const double * objective = solver->getObjCoefficients(); double integerTolerance = 1.0e-5; //model_->getDblParam(AbcModel::AbcIntegerTolerance); double primalTolerance; solver->getDblParam(OsiPrimalTolerance, primalTolerance); int numberRows = matrix_.getNumRows(); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); int i; double direction = solver->getObjSense(); double newSolutionValue = direction * solver->getObjValue(); int returnCode = 0; // Column copy const double * element = matrix_.getElements(); const int * row = matrix_.getIndices(); const int * columnStart = matrix_.getVectorStarts(); const int * columnLength = matrix_.getVectorLengths(); // Row copy const double * elementByRow = matrixByRow_.getElements(); const int * column = matrixByRow_.getIndices(); const int * rowStart = matrixByRow_.getVectorStarts(); const int * rowLength = matrixByRow_.getVectorLengths(); // Get solution array for heuristic solution int numberColumns = solver->getNumCols(); double * newSolution = new double [numberColumns]; memcpy(newSolution, solution, numberColumns * sizeof(double)); double * rowActivity = new double[numberRows]; memset(rowActivity, 0, numberRows*sizeof(double)); for (i = 0; i < numberColumns; i++) { int j; double value = newSolution[i]; if (value) { for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iRow = row[j]; rowActivity[iRow] += value*element[j]; } } } // check was feasible - if not adjust (cleaning may move) for (i = 0; i < numberRows; i++) { if(rowActivity[i] < rowLower[i]) { //assert (rowActivity[i]>rowLower[i]-1000.0*primalTolerance); rowActivity[i] = rowLower[i]; } else if(rowActivity[i] > rowUpper[i]) { //assert (rowActivity[i]<rowUpper[i]+1000.0*primalTolerance); rowActivity[i] = rowUpper[i]; } } for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { double below = floor(value); double newValue = newSolution[iColumn]; double cost = direction * objective[iColumn]; double move; if (cost > 0.0) { // try up move = 1.0 - (value - below); } else if (cost < 0.0) { // try down move = below - value; } else { // won't be able to move unless we can grab another variable // just for now go down move = below-value; } newValue += move; newSolution[iColumn] = newValue; newSolutionValue += move * cost; int j; for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; rowActivity[iRow] += move * element[j]; } } } double penalty = 0.0; // see if feasible for (i = 0; i < numberRows; i++) { double value = rowActivity[i]; double thisInfeasibility = 0.0; if (value < rowLower[i] - primalTolerance) thisInfeasibility = value - rowLower[i]; else if (value > rowUpper[i] + primalTolerance) thisInfeasibility = value - rowUpper[i]; if (thisInfeasibility) { // See if there are any slacks I can use to fix up // maybe put in coding for multiple slacks? double bestCost = 1.0e50; int k; int iBest = -1; double addCost = 0.0; double newValue = 0.0; double changeRowActivity = 0.0; double absInfeasibility = fabs(thisInfeasibility); for (k = rowStart[i]; k < rowStart[i] + rowLength[i]; k++) { int iColumn = column[k]; if (columnLength[iColumn] == 1) { double currentValue = newSolution[iColumn]; double elementValue = elementByRow[k]; double lowerValue = lower[iColumn]; double upperValue = upper[iColumn]; double gap = rowUpper[i] - rowLower[i]; double absElement = fabs(elementValue); if (thisInfeasibility * elementValue > 0.0) { // we want to reduce if ((currentValue - lowerValue) * absElement >= absInfeasibility) { // possible - check if integer double distance = absInfeasibility / absElement; double thisCost = -direction * objective[iColumn] * distance; if (solver->isInteger(iColumn)) { distance = ceil(distance - primalTolerance); assert (currentValue - distance >= lowerValue - primalTolerance); if (absInfeasibility - distance * absElement < -gap - primalTolerance) thisCost = 1.0e100; // no good else thisCost = -direction*objective[iColumn]*distance; } if (thisCost < bestCost) { bestCost = thisCost; iBest = iColumn; addCost = thisCost; newValue = currentValue - distance; changeRowActivity = -distance * elementValue; } } } else { // we want to increase if ((upperValue - currentValue) * absElement >= absInfeasibility) { // possible - check if integer double distance = absInfeasibility / absElement; double thisCost = direction * objective[iColumn] * distance; if (solver->isInteger(iColumn)) { distance = ceil(distance - 1.0e-7); assert (currentValue - distance <= upperValue + primalTolerance); if (absInfeasibility - distance * absElement < -gap - primalTolerance) thisCost = 1.0e100; // no good else thisCost = direction*objective[iColumn]*distance; } if (thisCost < bestCost) { bestCost = thisCost; iBest = iColumn; addCost = thisCost; newValue = currentValue + distance; changeRowActivity = distance * elementValue; } } } } } if (iBest >= 0) { /*printf("Infeasibility of %g on row %d cost %g\n", thisInfeasibility,i,addCost);*/ newSolution[iBest] = newValue; thisInfeasibility = 0.0; newSolutionValue += addCost; rowActivity[i] += changeRowActivity; } penalty += fabs(thisInfeasibility); } } // Could also set SOS (using random) and repeat if (!penalty) { // See if we can do better //seed_++; //CoinSeedRandom(seed_); // Random number between 0 and 1. double randomNumber = CoinDrand48(); int iPass; int start[2]; int end[2]; int iRandom = (int) (randomNumber * ((double) numberIntegers)); start[0] = iRandom; end[0] = numberIntegers; start[1] = 0; end[1] = iRandom; for (iPass = 0; iPass < 2; iPass++) { int i; for (i = start[iPass]; i < end[iPass]; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; assert(fabs(floor(value + 0.5) - value) < integerTolerance); double cost = direction * objective[iColumn]; double move = 0.0; if (cost > 0.0) move = -1.0; else if (cost < 0.0) move = 1.0; while (move) { bool good = true; double newValue = newSolution[iColumn] + move; if (newValue < lower[iColumn] - primalTolerance|| newValue > upper[iColumn] + primalTolerance) { move = 0.0; } else { // see if we can move int j; for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; double newActivity = rowActivity[iRow] + move*element[j]; if (newActivity < rowLower[iRow] - primalTolerance || newActivity > rowUpper[iRow]+primalTolerance) { good = false; break; } } if (good) { newSolution[iColumn] = newValue; newSolutionValue += move * cost; int j; for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; rowActivity[iRow] += move*element[j]; } } else { move=0.0; } } } } } if (newSolutionValue < solutionValue) { // paranoid check memset(rowActivity, 0, numberRows * sizeof(double)); for (i = 0; i < numberColumns; i++) { int j; double value = newSolution[i]; if (value) { for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iRow = row[j]; rowActivity[iRow] += value * element[j]; } } } // check was approximately feasible bool feasible = true; for (i = 0; i < numberRows; i++) { if(rowActivity[i] < rowLower[i]) { if (rowActivity[i] < rowLower[i] - 1000.0*primalTolerance) feasible = false; } else if(rowActivity[i] > rowUpper[i]) { if (rowActivity[i] > rowUpper[i] + 1000.0*primalTolerance) feasible = false; } } if (feasible) { // new solution memcpy(betterSolution, newSolution, numberColumns * sizeof(double)); solutionValue = newSolutionValue; //printf("** Solution of %g found by rounding\n",newSolutionValue); returnCode=1; } else { // Can easily happen //printf("Debug AbcRounding giving bad solution\n"); } } } delete [] newSolution; delete [] rowActivity; return returnCode; }
//############################################################################# void MibSHeuristic::objCutHeuristic() { /* Solve the LP relaxation with the new constraint d^2 y <= d^y* */ MibSModel * model = MibSModel_; //OsiSolverInterface * oSolver = model->origLpSolver_; OsiSolverInterface * oSolver = model->getSolver(); //OsiSolverInterface * hSolver = new OsiCbcSolverInterface(); OsiSolverInterface * hSolver = new OsiSymSolverInterface(); double objSense(model->getLowerObjSense()); int lCols(model->getLowerDim()); int uCols(model->getUpperDim()); int tCols(lCols + uCols); int * lColIndices = model->getLowerColInd(); int * uColIndices = model->getUpperColInd(); double * lObjCoeffs = model->getLowerObjCoeffs(); hSolver->loadProblem(*oSolver->getMatrixByCol(), oSolver->getColLower(), oSolver->getColUpper(), oSolver->getObjCoefficients(), oSolver->getRowLower(), oSolver->getRowUpper()); int j(0); for(j = 0; j < tCols; j++){ if(oSolver->isInteger(j)) hSolver->setInteger(j); } double * optLowerSolutionOrd = model->bS_->optLowerSolutionOrd_; CoinPackedVector objCon; int i(0), index(0); double rhs(0.0); for(i = 0; i < lCols; i++){ index = lColIndices[i]; objCon.insert(index, lObjCoeffs[i] * objSense); //should this be ordered? and should lObjCoeffs by at index? //rhs += optLowerSolutionOrd_[i] * lObjCoeffs[i] * objSense; rhs += optLowerSolutionOrd[i] * lObjCoeffs[i] * objSense; } //Hmm, I think this was wrong before...? // hSolver->addRow(objCon, - hSolver->getInfinity(), rhs); hSolver->addRow(objCon, rhs, hSolver->getInfinity()); /* optimize w.r.t. to the UL objective with the new row */ if(0){ dynamic_cast<OsiCbcSolverInterface *> (hSolver)->getModelPtr()->messageHandler()->setLogLevel(0); } else{ dynamic_cast<OsiSymSolverInterface *> (hSolver)->setSymParam("prep_level", -1); dynamic_cast<OsiSymSolverInterface *> (hSolver)->setSymParam("verbosity", -2); dynamic_cast<OsiSymSolverInterface *> (hSolver)->setSymParam("max_active_nodes", 1); } hSolver->branchAndBound(); if(0) hSolver->writeLp("objcutheuristic"); if(hSolver->isProvenOptimal()){ MibSSolution *mibSol = NULL; OsiSolverInterface * lSolver = model->bS_->setUpModel(hSolver, true); if(0){ dynamic_cast<OsiCbcSolverInterface *> (lSolver)->getModelPtr()->messageHandler()->setLogLevel(0); } else{ dynamic_cast<OsiSymSolverInterface *> (lSolver)->setSymParam("prep_level", -1); dynamic_cast<OsiSymSolverInterface *> (lSolver)->setSymParam("verbosity", -2); dynamic_cast<OsiSymSolverInterface *> (lSolver)->setSymParam("max_active_nodes", 1); } lSolver->branchAndBound(); const double * sol = hSolver->getColSolution(); double objVal(lSolver->getObjValue() * objSense); double etol(etol_); double lowerObj = getLowerObj(sol, objSense); double * optUpperSolutionOrd = new double[uCols]; double * optLowerSolutionOrd = new double[lCols]; CoinZeroN(optUpperSolutionOrd, uCols); CoinZeroN(optLowerSolutionOrd, lCols); if(fabs(objVal - lowerObj) < etol){ /** Current solution is bilevel feasible **/ mibSol = new MibSSolution(hSolver->getNumCols(), hSolver->getColSolution(), hSolver->getObjValue(), model); model->storeSolution(BlisSolutionTypeHeuristic, mibSol); mibSol = NULL; } else{ /* solution is not bilevel feasible, create one that is */ const double * uSol = hSolver->getColSolution(); const double * lSol = lSolver->getColSolution(); //int numElements(lSolver->getNumCols()); int numElements(hSolver->getNumCols()); int i(0), pos(0), index(0); double * lpSolution = new double[numElements]; double upperObj(0.0); //FIXME: problem is still here. indices may be wrong. //also is all this necessary, or can we just paste together uSol and lSol? for(i = 0; i < numElements; i++){ //index = indices[i]; pos = model->bS_->binarySearch(0, lCols - 1, i, lColIndices); if(pos < 0){ pos = model->bS_->binarySearch(0, uCols - 1, i, uColIndices); //optUpperSolutionOrd[pos] = values[i]; //optUpperSolutionOrd[pos] = uSol[pos]; if (pos >= 0){ optUpperSolutionOrd[pos] = uSol[i]; } } else{ //optLowerSolutionOrd[pos] = lSol[i]; optLowerSolutionOrd[pos] = lSol[pos]; } } for(i = 0; i < uCols; i++){ index = uColIndices[i]; lpSolution[index] = optUpperSolutionOrd[i]; upperObj += optUpperSolutionOrd[i] * hSolver->getObjCoefficients()[index]; } for(i = 0; i < lCols; i++){ index = lColIndices[i]; lpSolution[index] = optLowerSolutionOrd[i]; upperObj += optLowerSolutionOrd[i] * hSolver->getObjCoefficients()[index]; } if(model->checkUpperFeasibility(lpSolution)){ mibSol = new MibSSolution(hSolver->getNumCols(), lpSolution, upperObj * hSolver->getObjSense(), model); model->storeSolution(BlisSolutionTypeHeuristic, mibSol); mibSol = NULL; } delete [] lpSolution; } delete lSolver; } delete hSolver; }
void CglLandP::CachedData::getData(const OsiSolverInterface &si) { int nBasics = si.getNumRows(); int nNonBasics = si.getNumCols(); if (basis_ != NULL) delete basis_; basis_ = dynamic_cast<CoinWarmStartBasis *> (si.getWarmStart()); if (!basis_) throw NoBasisError(); if (nBasics_ > 0 || nBasics != nBasics_) { delete [] basics_; basics_ = NULL; } if (basics_ == NULL) { basics_ = new int[nBasics]; nBasics_ = nBasics; } if (nNonBasics_ > 0 || nNonBasics != nNonBasics_) { delete [] nonBasics_; nonBasics_ = NULL; } if (nonBasics_ == NULL) { nonBasics_ = new int[nNonBasics]; nNonBasics_ = nNonBasics; } int n = nBasics + nNonBasics; if ( nBasics_ + nNonBasics_ > 0 || nBasics_ + nNonBasics_ != n) { delete [] colsol_; delete [] integers_; integers_ = NULL; colsol_ = NULL; slacks_ = NULL; } if (colsol_ == NULL) { colsol_ = new double[n]; slacks_ = &colsol_[nNonBasics]; } if (integers_ == NULL) { integers_ = new bool[n]; } const double * rowLower = si.getRowLower(); const double * rowUpper = si.getRowUpper(); //determine which slacks are integer const CoinPackedMatrix * m = si.getMatrixByCol(); const double * elems = m->getElements(); const int * inds = m->getIndices(); const CoinBigIndex * starts = m->getVectorStarts(); const int * lengths = m->getVectorLengths(); // int numElems = m->getNumElements(); int numCols = m->getNumCols(); assert(numCols == nNonBasics_); // int numRows = m->getNumRows(); CoinFillN(integers_ ,n, true); for (int i = 0 ; i < numCols ; i++) { if (si.isContinuous(i)) integers_[i] = false; } bool * integerSlacks = integers_ + numCols; for (int i = 0 ; i < nBasics ; i++) { if (rowLower[i] > -1e50 && INT_INFEAS(rowLower[i]) > 1e-15) integerSlacks[i] = false; if (rowUpper[i] < 1e50 && INT_INFEAS(rowUpper[i]) > 1e-15) integerSlacks[i] = false; } for (int i = 0 ; i < numCols ; i++) { CoinBigIndex end = starts[i] + lengths[i]; if (integers_[i]) { for (CoinBigIndex k=starts[i] ; k < end; k++) { if (integerSlacks[inds[k]] && INT_INFEAS(elems[k])>1e-15 ) integerSlacks[inds[k]] = false; } } else { for (CoinBigIndex k=starts[i] ; k < end; k++) { if (integerSlacks[inds[k]]) integerSlacks[inds[k]] = false; } } } CoinCopyN(si.getColSolution(), si.getNumCols(), colsol_); CoinCopyN(si.getRowActivity(), si.getNumRows(), slacks_); for (int i = 0 ; i < si.getNumRows() ; i++) { slacks_[i]*=-1; if (rowLower[i]>-1e50) { slacks_[i] += rowLower[i]; } else { slacks_[i] += rowUpper[i]; } } //Now get the fill the arrays; nNonBasics = 0; nBasics = 0; //For having the index variables correctly ordered we need to access to OsiSimplexInterface { OsiSolverInterface * ncSi = (const_cast<OsiSolverInterface *>(&si)); ncSi->enableSimplexInterface(0); ncSi->getBasics(basics_); // Save enabled solver solver_ = si.clone(); #ifdef COIN_HAS_OSICLP OsiClpSolverInterface * clpSi = dynamic_cast<OsiClpSolverInterface *>(solver_); const OsiClpSolverInterface * clpSiRhs = dynamic_cast<const OsiClpSolverInterface *>(&si); if (clpSi) clpSi->getModelPtr()->copyEnabledStuff(clpSiRhs->getModelPtr());; #endif ncSi->disableSimplexInterface(); } int numStructural = basis_->getNumStructural(); for (int i = 0 ; i < numStructural ; i++) { if (basis_->getStructStatus(i)== CoinWarmStartBasis::basic) { nBasics++; //Basically do nothing } else { nonBasics_[nNonBasics++] = i; } } int numArtificial = basis_->getNumArtificial(); for (int i = 0 ; i < numArtificial ; i++) { if (basis_->getArtifStatus(i)== CoinWarmStartBasis::basic) { //Just check number of basics nBasics++; } else { nonBasics_[nNonBasics++] = i + basis_->getNumStructural(); } } }
// inner part of dive int CbcHeuristicDive::solution(double & solutionValue, int & numberNodes, int & numberCuts, OsiRowCut ** cuts, CbcSubProblem ** & nodes, double * newSolution) { #ifdef DIVE_DEBUG int nRoundInfeasible = 0; int nRoundFeasible = 0; #endif int reasonToStop = 0; double time1 = CoinCpuTime(); int numberSimplexIterations = 0; int maxSimplexIterations = (model_->getNodeCount()) ? maxSimplexIterations_ : maxSimplexIterationsAtRoot_; // but can't be exactly coin_int_max maxSimplexIterations = CoinMin(maxSimplexIterations,COIN_INT_MAX>>3); OsiSolverInterface * solver = cloneBut(6); // was model_->solver()->clone(); # ifdef COIN_HAS_CLP OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); if (clpSolver) { ClpSimplex * clpSimplex = clpSolver->getModelPtr(); int oneSolveIts = clpSimplex->maximumIterations(); oneSolveIts = CoinMin(1000+2*(clpSimplex->numberRows()+clpSimplex->numberColumns()),oneSolveIts); clpSimplex->setMaximumIterations(oneSolveIts); if (!nodes) { // say give up easily clpSimplex->setMoreSpecialOptions(clpSimplex->moreSpecialOptions() | 64); } else { // get ray int specialOptions = clpSimplex->specialOptions(); specialOptions &= ~0x3100000; specialOptions |= 32; clpSimplex->setSpecialOptions(specialOptions); clpSolver->setSpecialOptions(clpSolver->specialOptions() | 1048576); if ((model_->moreSpecialOptions()&16777216)!=0) { // cutoff is constraint clpSolver->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX); } } } # endif const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); const double * rowLower = solver->getRowLower(); const double * rowUpper = solver->getRowUpper(); const double * solution = solver->getColSolution(); const double * objective = solver->getObjCoefficients(); double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance); double primalTolerance; solver->getDblParam(OsiPrimalTolerance, primalTolerance); int numberRows = matrix_.getNumRows(); assert (numberRows <= solver->getNumRows()); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); double direction = solver->getObjSense(); // 1 for min, -1 for max double newSolutionValue = direction * solver->getObjValue(); int returnCode = 0; // Column copy const double * element = matrix_.getElements(); const int * row = matrix_.getIndices(); const CoinBigIndex * columnStart = matrix_.getVectorStarts(); const int * columnLength = matrix_.getVectorLengths(); #ifdef DIVE_FIX_BINARY_VARIABLES // Row copy const double * elementByRow = matrixByRow_.getElements(); const int * column = matrixByRow_.getIndices(); const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts(); const int * rowLength = matrixByRow_.getVectorLengths(); #endif // Get solution array for heuristic solution int numberColumns = solver->getNumCols(); memcpy(newSolution, solution, numberColumns*sizeof(double)); // vectors to store the latest variables fixed at their bounds int* columnFixed = new int [numberIntegers]; double* originalBound = new double [numberIntegers+2*numberColumns]; double * lowerBefore = originalBound+numberIntegers; double * upperBefore = lowerBefore+numberColumns; memcpy(lowerBefore,lower,numberColumns*sizeof(double)); memcpy(upperBefore,upper,numberColumns*sizeof(double)); double * lastDjs=newSolution+numberColumns; bool * fixedAtLowerBound = new bool [numberIntegers]; PseudoReducedCost * candidate = new PseudoReducedCost [numberIntegers]; double * random = new double [numberIntegers]; int maxNumberAtBoundToFix = static_cast<int> (floor(percentageToFix_ * numberIntegers)); assert (!maxNumberAtBoundToFix||!nodes); // count how many fractional variables int numberFractionalVariables = 0; for (int i = 0; i < numberIntegers; i++) { random[i] = randomNumberGenerator_.randomDouble() + 0.3; int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { numberFractionalVariables++; } } const double* reducedCost = NULL; // See if not NLP if (model_->solverCharacteristics()->reducedCostsAccurate()) reducedCost = solver->getReducedCost(); int iteration = 0; while (numberFractionalVariables) { iteration++; // initialize any data initializeData(); // select a fractional variable to bound int bestColumn = -1; int bestRound; // -1 rounds down, +1 rounds up bool canRound = selectVariableToBranch(solver, newSolution, bestColumn, bestRound); // if the solution is not trivially roundable, we don't try to round; // if the solution is trivially roundable, we try to round. However, // if the rounded solution is worse than the current incumbent, // then we don't round and proceed normally. In this case, the // bestColumn will be a trivially roundable variable if (canRound) { // check if by rounding all fractional variables // we get a solution with an objective value // better than the current best integer solution double delta = 0.0; for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { assert(downLocks_[i] == 0 || upLocks_[i] == 0); double obj = objective[iColumn]; if (downLocks_[i] == 0 && upLocks_[i] == 0) { if (direction * obj >= 0.0) delta += (floor(value) - value) * obj; else delta += (ceil(value) - value) * obj; } else if (downLocks_[i] == 0) delta += (floor(value) - value) * obj; else delta += (ceil(value) - value) * obj; } } if (direction*(solver->getObjValue() + delta) < solutionValue) { #ifdef DIVE_DEBUG nRoundFeasible++; #endif if (!nodes||bestColumn<0) { // Round all the fractional variables for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { assert(downLocks_[i] == 0 || upLocks_[i] == 0); if (downLocks_[i] == 0 && upLocks_[i] == 0) { if (direction * objective[iColumn] >= 0.0) newSolution[iColumn] = floor(value); else newSolution[iColumn] = ceil(value); } else if (downLocks_[i] == 0) newSolution[iColumn] = floor(value); else newSolution[iColumn] = ceil(value); } } break; } else { // can't round if going to use in branching int i; for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[bestColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { if (iColumn==bestColumn) { assert(downLocks_[i] == 0 || upLocks_[i] == 0); double obj = objective[bestColumn]; if (downLocks_[i] == 0 && upLocks_[i] == 0) { if (direction * obj >= 0.0) bestRound=-1; else bestRound=1; } else if (downLocks_[i] == 0) bestRound=-1; else bestRound=1; break; } } } } } #ifdef DIVE_DEBUG else nRoundInfeasible++; #endif } // do reduced cost fixing #ifdef DIVE_DEBUG int numberFixed = reducedCostFix(solver); std::cout << "numberReducedCostFixed = " << numberFixed << std::endl; #else reducedCostFix(solver); #endif int numberAtBoundFixed = 0; #ifdef DIVE_FIX_BINARY_VARIABLES // fix binary variables based on pseudo reduced cost if (binVarIndex_.size()) { int cnt = 0; int n = static_cast<int>(binVarIndex_.size()); for (int j = 0; j < n; j++) { int iColumn1 = binVarIndex_[j]; double value = newSolution[iColumn1]; if (fabs(value) <= integerTolerance && lower[iColumn1] != upper[iColumn1]) { double maxPseudoReducedCost = 0.0; #ifdef DIVE_DEBUG std::cout << "iColumn1 = " << iColumn1 << ", value = " << value << std::endl; #endif int iRow = vbRowIndex_[j]; double chosenValue = 0.0; for (int k = rowStart[iRow]; k < rowStart[iRow] + rowLength[iRow]; k++) { int iColumn2 = column[k]; #ifdef DIVE_DEBUG std::cout << "iColumn2 = " << iColumn2 << std::endl; #endif if (iColumn1 != iColumn2) { double pseudoReducedCost = fabs(reducedCost[iColumn2] * elementByRow[k]); #ifdef DIVE_DEBUG int k2; for (k2 = rowStart[iRow]; k2 < rowStart[iRow] + rowLength[iRow]; k2++) { if (column[k2] == iColumn1) break; } std::cout << "reducedCost[" << iColumn2 << "] = " << reducedCost[iColumn2] << ", elementByRow[" << iColumn2 << "] = " << elementByRow[k] << ", elementByRow[" << iColumn1 << "] = " << elementByRow[k2] << ", pseudoRedCost = " << pseudoReducedCost << std::endl; #endif if (pseudoReducedCost > maxPseudoReducedCost) maxPseudoReducedCost = pseudoReducedCost; } else { // save value chosenValue = fabs(elementByRow[k]); } } assert (chosenValue); maxPseudoReducedCost /= chosenValue; #ifdef DIVE_DEBUG std::cout << ", maxPseudoRedCost = " << maxPseudoReducedCost << std::endl; #endif candidate[cnt].var = iColumn1; candidate[cnt++].pseudoRedCost = maxPseudoReducedCost; } } #ifdef DIVE_DEBUG std::cout << "candidates for rounding = " << cnt << std::endl; #endif std::sort(candidate, candidate + cnt, compareBinaryVars); for (int i = 0; i < cnt; i++) { int iColumn = candidate[i].var; if (numberAtBoundFixed < maxNumberAtBoundToFix) { columnFixed[numberAtBoundFixed] = iColumn; originalBound[numberAtBoundFixed] = upper[iColumn]; fixedAtLowerBound[numberAtBoundFixed] = true; solver->setColUpper(iColumn, lower[iColumn]); numberAtBoundFixed++; if (numberAtBoundFixed == maxNumberAtBoundToFix) break; } } } #endif // fix other integer variables that are at their bounds int cnt = 0; #ifdef GAP double gap = 1.0e30; #endif if (reducedCost && true) { #ifndef JJF_ONE cnt = fixOtherVariables(solver, solution, candidate, random); #else #ifdef GAP double cutoff = model_->getCutoff() ; if (cutoff < 1.0e20 && false) { double direction = solver->getObjSense() ; gap = cutoff - solver->getObjValue() * direction ; gap *= 0.1; // Fix more if plausible double tolerance; solver->getDblParam(OsiDualTolerance, tolerance) ; if (gap <= 0.0) gap = tolerance; gap += 100.0 * tolerance; } int nOverGap = 0; #endif int numberFree = 0; int numberFixed = 0; for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; if (upper[iColumn] > lower[iColumn]) { numberFree++; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) <= integerTolerance) { candidate[cnt].var = iColumn; candidate[cnt++].pseudoRedCost = fabs(reducedCost[iColumn] * random[i]); #ifdef GAP if (fabs(reducedCost[iColumn]) > gap) nOverGap++; #endif } } else { numberFixed++; } } #ifdef GAP int nLeft = maxNumberAtBoundToFix - numberAtBoundFixed; #ifdef CLP_INVESTIGATE4 printf("cutoff %g obj %g nover %d - %d free, %d fixed\n", cutoff, solver->getObjValue(), nOverGap, numberFree, numberFixed); #endif if (nOverGap > nLeft && true) { nOverGap = CoinMin(nOverGap, nLeft + maxNumberAtBoundToFix / 2); maxNumberAtBoundToFix += nOverGap - nLeft; } #else #ifdef CLP_INVESTIGATE4 printf("cutoff %g obj %g - %d free, %d fixed\n", model_->getCutoff(), solver->getObjValue(), numberFree, numberFixed); #endif #endif #endif } else { for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; if (upper[iColumn] > lower[iColumn]) { double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) <= integerTolerance) { candidate[cnt].var = iColumn; candidate[cnt++].pseudoRedCost = numberIntegers - i; } } } } std::sort(candidate, candidate + cnt, compareBinaryVars); for (int i = 0; i < cnt; i++) { int iColumn = candidate[i].var; if (upper[iColumn] > lower[iColumn]) { double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) <= integerTolerance && numberAtBoundFixed < maxNumberAtBoundToFix) { // fix the variable at one of its bounds if (fabs(lower[iColumn] - value) <= integerTolerance) { columnFixed[numberAtBoundFixed] = iColumn; originalBound[numberAtBoundFixed] = upper[iColumn]; fixedAtLowerBound[numberAtBoundFixed] = true; solver->setColUpper(iColumn, lower[iColumn]); numberAtBoundFixed++; } else if (fabs(upper[iColumn] - value) <= integerTolerance) { columnFixed[numberAtBoundFixed] = iColumn; originalBound[numberAtBoundFixed] = lower[iColumn]; fixedAtLowerBound[numberAtBoundFixed] = false; solver->setColLower(iColumn, upper[iColumn]); numberAtBoundFixed++; } if (numberAtBoundFixed == maxNumberAtBoundToFix) break; } } } #ifdef DIVE_DEBUG std::cout << "numberAtBoundFixed = " << numberAtBoundFixed << std::endl; #endif double originalBoundBestColumn; double bestColumnValue; int whichWay; if (bestColumn >= 0) { bestColumnValue = newSolution[bestColumn]; if (bestRound < 0) { originalBoundBestColumn = upper[bestColumn]; solver->setColUpper(bestColumn, floor(bestColumnValue)); whichWay=0; } else { originalBoundBestColumn = lower[bestColumn]; solver->setColLower(bestColumn, ceil(bestColumnValue)); whichWay=1; } } else { break; } int originalBestRound = bestRound; int saveModelOptions = model_->specialOptions(); while (1) { model_->setSpecialOptions(saveModelOptions | 2048); solver->resolve(); model_->setSpecialOptions(saveModelOptions); if (!solver->isAbandoned()&&!solver->isIterationLimitReached()) { numberSimplexIterations += solver->getIterationCount(); } else { numberSimplexIterations = maxSimplexIterations + 1; reasonToStop += 100; break; } if (!solver->isProvenOptimal()) { if (nodes) { if (solver->isProvenPrimalInfeasible()) { if (maxSimplexIterationsAtRoot_!=COIN_INT_MAX) { // stop now printf("stopping on first infeasibility\n"); break; } else if (cuts) { // can do conflict cut printf("could do intermediate conflict cut\n"); bool localCut; OsiRowCut * cut = model_->conflictCut(solver,localCut); if (cut) { if (!localCut) { model_->makePartialCut(cut,solver); cuts[numberCuts++]=cut; } else { delete cut; } } } } else { reasonToStop += 10; break; } } if (numberAtBoundFixed > 0) { // Remove the bound fix for variables that were at bounds for (int i = 0; i < numberAtBoundFixed; i++) { int iColFixed = columnFixed[i]; if (fixedAtLowerBound[i]) solver->setColUpper(iColFixed, originalBound[i]); else solver->setColLower(iColFixed, originalBound[i]); } numberAtBoundFixed = 0; } else if (bestRound == originalBestRound) { bestRound *= (-1); whichWay |=2; if (bestRound < 0) { solver->setColLower(bestColumn, originalBoundBestColumn); solver->setColUpper(bestColumn, floor(bestColumnValue)); } else { solver->setColLower(bestColumn, ceil(bestColumnValue)); solver->setColUpper(bestColumn, originalBoundBestColumn); } } else break; } else break; } if (!solver->isProvenOptimal() || direction*solver->getObjValue() >= solutionValue) { reasonToStop += 1; } else if (iteration > maxIterations_) { reasonToStop += 2; } else if (CoinCpuTime() - time1 > maxTime_) { reasonToStop += 3; } else if (numberSimplexIterations > maxSimplexIterations) { reasonToStop += 4; // also switch off #ifdef CLP_INVESTIGATE printf("switching off diving as too many iterations %d, %d allowed\n", numberSimplexIterations, maxSimplexIterations); #endif when_ = 0; } else if (solver->getIterationCount() > 1000 && iteration > 3 && !nodes) { reasonToStop += 5; // also switch off #ifdef CLP_INVESTIGATE printf("switching off diving one iteration took %d iterations (total %d)\n", solver->getIterationCount(), numberSimplexIterations); #endif when_ = 0; } memcpy(newSolution, solution, numberColumns*sizeof(double)); numberFractionalVariables = 0; double sumFractionalVariables=0.0; for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; double away = fabs(floor(value + 0.5) - value); if (away > integerTolerance) { numberFractionalVariables++; sumFractionalVariables += away; } } if (nodes) { // save information //branchValues[numberNodes]=bestColumnValue; //statuses[numberNodes]=whichWay+(bestColumn<<2); //bases[numberNodes]=solver->getWarmStart(); ClpSimplex * simplex = clpSolver->getModelPtr(); CbcSubProblem * sub = new CbcSubProblem(clpSolver,lowerBefore,upperBefore, simplex->statusArray(),numberNodes); nodes[numberNodes]=sub; // other stuff sub->branchValue_=bestColumnValue; sub->problemStatus_=whichWay; sub->branchVariable_=bestColumn; sub->objectiveValue_ = simplex->objectiveValue(); sub->sumInfeasibilities_ = sumFractionalVariables; sub->numberInfeasibilities_ = numberFractionalVariables; printf("DiveNode %d column %d way %d bvalue %g obj %g\n", numberNodes,sub->branchVariable_,sub->problemStatus_, sub->branchValue_,sub->objectiveValue_); numberNodes++; if (solver->isProvenOptimal()) { memcpy(lastDjs,solver->getReducedCost(),numberColumns*sizeof(double)); memcpy(lowerBefore,lower,numberColumns*sizeof(double)); memcpy(upperBefore,upper,numberColumns*sizeof(double)); } } if (!numberFractionalVariables||reasonToStop) break; } if (nodes) { printf("Exiting dive for reason %d\n",reasonToStop); if (reasonToStop>1) { printf("problems in diving\n"); int whichWay=nodes[numberNodes-1]->problemStatus_; CbcSubProblem * sub; if ((whichWay&2)==0) { // leave both ways sub = new CbcSubProblem(*nodes[numberNodes-1]); nodes[numberNodes++]=sub; } else { sub = nodes[numberNodes-1]; } if ((whichWay&1)==0) sub->problemStatus_=whichWay|1; else sub->problemStatus_=whichWay&~1; } if (!numberNodes) { // was good at start! - create fake clpSolver->resolve(); ClpSimplex * simplex = clpSolver->getModelPtr(); CbcSubProblem * sub = new CbcSubProblem(clpSolver,lowerBefore,upperBefore, simplex->statusArray(),numberNodes); nodes[numberNodes]=sub; // other stuff sub->branchValue_=0.0; sub->problemStatus_=0; sub->branchVariable_=-1; sub->objectiveValue_ = simplex->objectiveValue(); sub->sumInfeasibilities_ = 0.0; sub->numberInfeasibilities_ = 0; printf("DiveNode %d column %d way %d bvalue %g obj %g\n", numberNodes,sub->branchVariable_,sub->problemStatus_, sub->branchValue_,sub->objectiveValue_); numberNodes++; assert (solver->isProvenOptimal()); } nodes[numberNodes-1]->problemStatus_ |= 256*reasonToStop; // use djs as well if (solver->isProvenPrimalInfeasible()&&cuts) { // can do conflict cut and re-order printf("could do final conflict cut\n"); bool localCut; OsiRowCut * cut = model_->conflictCut(solver,localCut); if (cut) { printf("cut - need to use conflict and previous djs\n"); if (!localCut) { model_->makePartialCut(cut,solver); cuts[numberCuts++]=cut; } else { delete cut; } } else { printf("bad conflict - just use previous djs\n"); } } } // re-compute new solution value double objOffset = 0.0; solver->getDblParam(OsiObjOffset, objOffset); newSolutionValue = -objOffset; for (int i = 0 ; i < numberColumns ; i++ ) newSolutionValue += objective[i] * newSolution[i]; newSolutionValue *= direction; //printf("new solution value %g %g\n",newSolutionValue,solutionValue); if (newSolutionValue < solutionValue && !reasonToStop) { double * rowActivity = new double[numberRows]; memset(rowActivity, 0, numberRows*sizeof(double)); // paranoid check memset(rowActivity, 0, numberRows*sizeof(double)); for (int i = 0; i < numberColumns; i++) { int j; double value = newSolution[i]; if (value) { for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iRow = row[j]; rowActivity[iRow] += value * element[j]; } } } // check was approximately feasible bool feasible = true; for (int i = 0; i < numberRows; i++) { if (rowActivity[i] < rowLower[i]) { if (rowActivity[i] < rowLower[i] - 1000.0*primalTolerance) feasible = false; } else if (rowActivity[i] > rowUpper[i]) { if (rowActivity[i] > rowUpper[i] + 1000.0*primalTolerance) feasible = false; } } for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { feasible = false; break; } } if (feasible) { // new solution solutionValue = newSolutionValue; //printf("** Solution of %g found by CbcHeuristicDive\n",newSolutionValue); //if (cuts) //clpSolver->getModelPtr()->writeMps("good8.mps", 2); returnCode = 1; } else { // Can easily happen //printf("Debug CbcHeuristicDive giving bad solution\n"); } delete [] rowActivity; } #ifdef DIVE_DEBUG std::cout << "nRoundInfeasible = " << nRoundInfeasible << ", nRoundFeasible = " << nRoundFeasible << ", returnCode = " << returnCode << ", reasonToStop = " << reasonToStop << ", simplexIts = " << numberSimplexIterations << ", iterations = " << iteration << std::endl; #endif delete [] columnFixed; delete [] originalBound; delete [] fixedAtLowerBound; delete [] candidate; delete [] random; delete [] downArray_; downArray_ = NULL; delete [] upArray_; upArray_ = NULL; delete solver; return returnCode; }
// Returns type int CbcFathomDynamicProgramming::checkPossible(int allowableSize) { algorithm_ = -1; assert(model_->solver()); OsiSolverInterface * solver = model_->solver(); const CoinPackedMatrix * matrix = solver->getMatrixByCol(); int numberIntegers = model_->numberIntegers(); int numberColumns = solver->getNumCols(); size_ = 0; if (numberIntegers != numberColumns) return -1; // can't do dynamic programming const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); const double * rowUpper = solver->getRowUpper(); int numberRows = model_->getNumRows(); int i; // First check columns to see if possible double * rhs = new double [numberRows]; CoinCopyN(rowUpper, numberRows, rhs); // Column copy const double * element = matrix->getElements(); const int * row = matrix->getIndices(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const int * columnLength = matrix->getVectorLengths(); bool bad = false; /* It is just possible that we could say okay as variables may get fixed but seems unlikely */ for (i = 0; i < numberColumns; i++) { int j; double lowerValue = lower[i]; assert (lowerValue == floor(lowerValue)); for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iRow = row[j]; double value = element[j]; if (upper[i] > lowerValue && (value <= 0.0 || value != floor(value))) bad = true; if (lowerValue) rhs[iRow] -= lowerValue * value; } } // check possible (at present do not allow covering) int numberActive = 0; bool infeasible = false; bool saveBad = bad; for (i = 0; i < numberRows; i++) { if (rhs[i] < 0) infeasible = true; else if (rhs[i] > 1.0e5 || fabs(rhs[i] - floor(rhs[i] + 0.5)) > 1.0e-7) bad = true; else if (rhs[i] > 0.0) numberActive++; } if (bad || infeasible) { delete [] rhs; if (!saveBad && infeasible) return -2; else return -1; } // check size of array needed double size = 1.0; double check = COIN_INT_MAX; for (i = 0; i < numberRows; i++) { int n = static_cast<int> (floor(rhs[i] + 0.5)); if (n) { n++; // allow for 0,1... n if (numberActive != 1) { // power of 2 int iBit = 0; int k = n; k &= ~1; while (k) { iBit++; k &= ~(1 << iBit); } // See if exact power if (n != (1 << iBit)) { // round up to next power of 2 n = 1 << (iBit + 1); } size *= n; if (size >= check) break; } else { size = n; // just one constraint } } } // set size needed if (size >= check) size_ = COIN_INT_MAX; else size_ = static_cast<int> (size); int n01 = 0; int nbadcoeff = 0; // See if we can tighten bounds for (i = 0; i < numberColumns; i++) { int j; double lowerValue = lower[i]; double gap = upper[i] - lowerValue; for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iRow = row[j]; double value = element[j]; if (value != 1.0) nbadcoeff++; if (gap*value > rhs[iRow] + 1.0e-8) gap = rhs[iRow] / value; } gap = lowerValue + floor(gap + 1.0e-7); if (gap < upper[i]) solver->setColUpper(i, gap); if (gap <= 1.0) n01++; } if (allowableSize && size_ <= allowableSize) { if (n01 == numberColumns && !nbadcoeff) algorithm_ = 0; // easiest else algorithm_ = 1; } if (allowableSize && size_ <= allowableSize) { numberActive_ = numberActive; indices_ = new int [numberActive_]; cost_ = new double [size_]; CoinFillN(cost_, size_, COIN_DBL_MAX); // but do nothing is okay cost_[0] = 0.0; back_ = new int[size_]; CoinFillN(back_, size_, -1); startBit_ = new int[numberActive_]; numberBits_ = new int[numberActive_]; lookup_ = new int [numberRows]; rhs_ = new int [numberActive_]; numberActive = 0; int kBit = 0; for (i = 0; i < numberRows; i++) { int n = static_cast<int> (floor(rhs[i] + 0.5)); if (n) { lookup_[i] = numberActive; rhs_[numberActive] = n; startBit_[numberActive] = kBit; n++; // allow for 0,1... n int iBit = 0; // power of 2 int k = n; k &= ~1; while (k) { iBit++; k &= ~(1 << iBit); } // See if exact power if (n != (1 << iBit)) { // round up to next power of 2 iBit++; } if (numberActive != 1) { n = 1 << iBit; size *= n; if (size >= check) break; } else { size = n; // just one constraint } numberBits_[numberActive++] = iBit; kBit += iBit; } else { lookup_[i] = -1; } } const double * rowLower = solver->getRowLower(); if (algorithm_ == 0) { // rhs 1 and coefficients 1 // Get first possible solution for printing target_ = -1; int needed = 0; int numberActive = 0; for (i = 0; i < numberRows; i++) { int newRow = lookup_[i]; if (newRow >= 0) { if (rowLower[i] == rowUpper[i]) { needed += 1 << numberActive; numberActive++; } } } for (i = 0; i < size_; i++) { if ((i&needed) == needed) { break; } } target_ = i; } else { coefficients_ = new int[numberActive_]; // If not too many general rhs then we can be more efficient numberNonOne_ = 0; for (i = 0; i < numberActive_; i++) { if (rhs_[i] != 1) numberNonOne_++; } if (numberNonOne_*2 < numberActive_) { // put rhs >1 every second int * permute = new int[numberActive_]; int * temp = new int[numberActive_]; // try different ways int k = 0; for (i = 0; i < numberRows; i++) { int newRow = lookup_[i]; if (newRow >= 0 && rhs_[newRow] > 1) { permute[newRow] = k; k += 2; } } // adjust so k points to last k -= 2; // and now rest int k1 = 1; for (i = 0; i < numberRows; i++) { int newRow = lookup_[i]; if (newRow >= 0 && rhs_[newRow] == 1) { permute[newRow] = k1; k1++; if (k1 <= k) k1++; } } for (i = 0; i < numberActive_; i++) { int put = permute[i]; temp[put] = rhs_[i]; } memcpy(rhs_, temp, numberActive_*sizeof(int)); for (i = 0; i < numberActive_; i++) { int put = permute[i]; temp[put] = numberBits_[i]; } memcpy(numberBits_, temp, numberActive_*sizeof(int)); k = 0; for (i = 0; i < numberActive_; i++) { startBit_[i] = k; k += numberBits_[i]; } for (i = 0; i < numberRows; i++) { int newRow = lookup_[i]; if (newRow >= 0) lookup_[i] = permute[newRow]; } delete [] permute; delete [] temp; // mark new method algorithm_ = 2; } // Get first possible solution for printing target_ = -1; int needed = 0; int * lower2 = new int[numberActive_]; for (i = 0; i < numberRows; i++) { int newRow = lookup_[i]; if (newRow >= 0) { int gap = static_cast<int> (rowUpper[i] - CoinMax(0.0, rowLower[i])); lower2[newRow] = rhs_[newRow] - gap; int numberBits = numberBits_[newRow]; int startBit = startBit_[newRow]; if (numberBits == 1 && !gap) { needed |= 1 << startBit; } } } for (i = 0; i < size_; i++) { if ((i&needed) == needed) { // this one may do bool good = true; for (int kk = 0; kk < numberActive_; kk++) { int numberBits = numberBits_[kk]; int startBit = startBit_[kk]; int size = 1 << numberBits; int start = 1 << startBit; int mask = start * (size - 1); int level = (i & mask) >> startBit; if (level < lower2[kk]) { good = false; break; } } if (good) { break; } } } delete [] lower2; target_ = i; }