//----------------------------------------------------------------------------- template <class Iter_S, class Iter_T> void CoinSort_2(Iter_S sfirst, Iter_S slast, Iter_T tfirst) { typedef typename std::iterator_traits<Iter_S>::value_type S; typedef typename std::iterator_traits<Iter_T>::value_type T; CoinSort_2(sfirst, slast, tfirst, CoinFirstLess_2<S,T>()); }
CbcBranchingObject * CbcNWay::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * /*info*/, int /*way*/) { int numberFree = 0; int j; //OsiSolverInterface * solver = model_->solver(); const double * solution = model_->testSolution(); const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); int * list = new int[numberMembers_]; double * sort = new double[numberMembers_]; for (j = 0; j < numberMembers_; j++) { int iColumn = members_[j]; double value = solution[iColumn]; value = CoinMax(value, lower[iColumn]); value = CoinMin(value, upper[iColumn]); if (upper[iColumn] > lower[iColumn]) { double distance = upper[iColumn] - value; list[numberFree] = j; sort[numberFree++] = distance; } } assert (numberFree); // sort CoinSort_2(sort, sort + numberFree, list); // create object CbcBranchingObject * branch; branch = new CbcNWayBranchingObject(model_, this, numberFree, list); branch->setOriginalObject(this); delete [] list; delete [] sort; return branch; }
//------------------------------------------------------------------- // Useful Constructor //------------------------------------------------------------------- ClpConstraintLinear::ClpConstraintLinear (int row, int numberCoefficents , int numberColumns, const int * column, const double * coefficient) : ClpConstraint() { type_ = 0; rowNumber_ = row; numberColumns_ = numberColumns; numberCoefficients_ = numberCoefficents; column_ = CoinCopyOfArray(column, numberCoefficients_); coefficient_ = CoinCopyOfArray(coefficient, numberCoefficients_); CoinSort_2(column_, column_ + numberCoefficients_, coefficient_); }
CbcBranchingObject * CbcBranchAllDifferent::createCbcBranch(OsiSolverInterface * /*solver*/ , const OsiBranchingInformation * /*info*/, int /*way*/) { // by default way must be -1 //assert (way==-1); const double * solution = model_->testSolution(); double * values = new double[numberInSet_]; int * which = new int[numberInSet_]; int i; for (i = 0; i < numberInSet_; i++) { int iColumn = which_[i]; values[i] = solution[iColumn]; which[i] = iColumn; } CoinSort_2(values, values + numberInSet_, which); double last = -1.0; double closest = 1.0; int worst = -1; for (i = 0; i < numberInSet_; i++) { if (values[i] - last < closest) { closest = values[i] - last; worst = i - 1; } last = values[i]; } assert (closest <= 0.99999); OsiRowCut down; down.setLb(-COIN_DBL_MAX); down.setUb(-1.0); int pair[2]; double elements[] = {1.0, -1.0}; pair[0] = which[worst]; pair[1] = which[worst+1]; delete [] values; delete [] which; down.setRow(2, pair, elements); // up is same - just with rhs changed OsiRowCut up = down; up.setLb(1.0); up.setUb(COIN_DBL_MAX); // Say is not a fix type branch CbcCutBranchingObject * newObject = new CbcCutBranchingObject(model_, down, up, false); if (model_->messageHandler()->logLevel() > 1) printf("creating cut in CbcBranchCut\n"); return newObject; }
/* Insert a row cut unless it is a duplicate (CoinRelFltEq)*/ void OsiCuts::insertIfNotDuplicate( OsiRowCut & rc , CoinRelFltEq treatAsSame) { double newLb = rc.lb(); double newUb = rc.ub(); CoinPackedVector vector = rc.row(); int numberElements =vector.getNumElements(); int * newIndices = vector.getIndices(); double * newElements = vector.getElements(); CoinSort_2(newIndices,newIndices+numberElements,newElements); bool notDuplicate=true; int numberRowCuts = sizeRowCuts(); for ( int i =0; i<numberRowCuts;i++) { const OsiRowCut * cutPtr = rowCutPtr(i); if (cutPtr->row().getNumElements()!=numberElements) continue; if (!treatAsSame(cutPtr->lb(),newLb)) continue; if (!treatAsSame(cutPtr->ub(),newUb)) continue; const CoinPackedVector * thisVector = &(cutPtr->row()); const int * indices = thisVector->getIndices(); const double * elements = thisVector->getElements(); int j; for(j=0;j<numberElements;j++) { if (indices[j]!=newIndices[j]) break; if (!treatAsSame(elements[j],newElements[j])) break; } if (j==numberElements) { notDuplicate=false; break; } } if (notDuplicate) { OsiRowCut * newCutPtr = new OsiRowCut(); newCutPtr->setLb(newLb); newCutPtr->setUb(newUb); newCutPtr->setRow(vector); rowCutPtrs_.push_back(newCutPtr); } }
CbcBranchingObject * CbcBranchToFixLots::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * /*info*/, int /*way*/) { // by default way must be -1 //assert (way==-1); //OsiSolverInterface * solver = model_->solver(); const double * solution = model_->testSolution(); const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); const double * dj = solver->getReducedCost(); int i; int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance); // make smaller ? double tolerance = CoinMin(1.0e-8, integerTolerance); // How many fixed are we aiming at int wantedFixed = static_cast<int> (static_cast<double>(numberIntegers) * fractionFixed_); int nSort = 0; int numberFixed = 0; int numberColumns = solver->getNumCols(); int * sort = new int[numberColumns]; double * dsort = new double[numberColumns]; if (djTolerance_ != -1.234567) { int type = shallWe(); assert (type); // Take clean first if (type == 1) { for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; if (upper[iColumn] > lower[iColumn]) { if (!mark_ || !mark_[iColumn]) { if (solution[iColumn] < lower[iColumn] + tolerance) { if (dj[iColumn] > djTolerance_) { dsort[nSort] = -dj[iColumn]; sort[nSort++] = iColumn; } } else if (solution[iColumn] > upper[iColumn] - tolerance) { if (dj[iColumn] < -djTolerance_) { dsort[nSort] = dj[iColumn]; sort[nSort++] = iColumn; } } } } else { numberFixed++; } } // sort CoinSort_2(dsort, dsort + nSort, sort); nSort = CoinMin(nSort, wantedFixed - numberFixed); } else if (type < 10) { int i; //const double * rowLower = solver->getRowLower(); const double * rowUpper = solver->getRowUpper(); // Row copy const double * elementByRow = matrixByRow_.getElements(); const int * column = matrixByRow_.getIndices(); const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts(); const int * rowLength = matrixByRow_.getVectorLengths(); const double * columnLower = solver->getColLower(); const double * columnUpper = solver->getColUpper(); const double * solution = solver->getColSolution(); int numberColumns = solver->getNumCols(); int numberRows = solver->getNumRows(); for (i = 0; i < numberColumns; i++) { sort[i] = i; if (columnLower[i] != columnUpper[i]) { dsort[i] = 1.0e100; } else { dsort[i] = 1.0e50; numberFixed++; } } for (i = 0; i < numberRows; i++) { double rhsValue = rowUpper[i]; bool oneRow = true; // check elements int numberUnsatisfied = 0; for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) { int iColumn = column[j]; double value = elementByRow[j]; double solValue = solution[iColumn]; if (columnLower[iColumn] != columnUpper[iColumn]) { if (solValue < 1.0 - integerTolerance && solValue > integerTolerance) numberUnsatisfied++; if (value != 1.0) { oneRow = false; break; } } else { rhsValue -= value * floor(solValue + 0.5); } } if (oneRow && rhsValue <= 1.0 + tolerance) { if (!numberUnsatisfied) { for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) { int iColumn = column[j]; if (dsort[iColumn] > 1.0e50) { dsort[iColumn] = 0; nSort++; } } } } } // sort CoinSort_2(dsort, dsort + numberColumns, sort); } else { // new way for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; if (upper[iColumn] > lower[iColumn]) { if (!mark_ || !mark_[iColumn]) { double distanceDown = solution[iColumn] - lower[iColumn]; double distanceUp = upper[iColumn] - solution[iColumn]; double distance = CoinMin(distanceDown, distanceUp); if (distance > 0.001 && distance < 0.5) { dsort[nSort] = distance; sort[nSort++] = iColumn; } } } } // sort CoinSort_2(dsort, dsort + nSort, sort); int n = 0; double sum = 0.0; for (int k = 0; k < nSort; k++) { sum += dsort[k]; if (sum <= djTolerance_) n = k; else break; } nSort = CoinMin(n, numberClean_ / 1000000); } } else { #define FIX_IF_LESS -0.1 // 3 in same row and sum <FIX_IF_LESS? int numberRows = matrixByRow_.getNumRows(); const double * solution = model_->testSolution(); const int * column = matrixByRow_.getIndices(); const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts(); const int * rowLength = matrixByRow_.getVectorLengths(); double bestSum = 1.0; int nBest = -1; int kRow = -1; OsiSolverInterface * solver = model_->solver(); for (int i = 0; i < numberRows; i++) { int numberUnsatisfied = 0; double sum = 0.0; for (int j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) { int iColumn = column[j]; if (solver->isInteger(iColumn)) { double solValue = solution[iColumn]; if (solValue > 1.0e-5 && solValue < FIX_IF_LESS) { numberUnsatisfied++; sum += solValue; } } } if (numberUnsatisfied >= 3 && sum < FIX_IF_LESS) { // possible if (numberUnsatisfied > nBest || (numberUnsatisfied == nBest && sum < bestSum)) { nBest = numberUnsatisfied; bestSum = sum; kRow = i; } } } assert (nBest > 0); for (int j = rowStart[kRow]; j < rowStart[kRow] + rowLength[kRow]; j++) { int iColumn = column[j]; if (solver->isInteger(iColumn)) { double solValue = solution[iColumn]; if (solValue > 1.0e-5 && solValue < FIX_IF_LESS) { sort[nSort++] = iColumn; } } } } OsiRowCut down; down.setLb(-COIN_DBL_MAX); double rhs = 0.0; for (i = 0; i < nSort; i++) { int iColumn = sort[i]; double distanceDown = solution[iColumn] - lower[iColumn]; double distanceUp = upper[iColumn] - solution[iColumn]; if (distanceDown < distanceUp) { rhs += lower[iColumn]; dsort[i] = 1.0; } else { rhs -= upper[iColumn]; dsort[i] = -1.0; } } down.setUb(rhs); down.setRow(nSort, sort, dsort); down.setEffectiveness(COIN_DBL_MAX); // so will persist delete [] sort; delete [] dsort; // up is same - just with rhs changed OsiRowCut up = down; up.setLb(rhs + 1.0); up.setUb(COIN_DBL_MAX); // Say can fix one way CbcCutBranchingObject * newObject = new CbcCutBranchingObject(model_, down, up, true); if (model_->messageHandler()->logLevel() > 1) printf("creating cut in CbcBranchCut\n"); return newObject; }
//----------------------------------------------------------------------------- template <class S, class T> void CoinSort_2(S* sfirst, S* slast, T* tfirst) { CoinSort_2(sfirst, slast, tfirst, CoinFirstLess_2<S,T>()); }
/** Useful constructor Loads actual upper & lower bounds for the specified variable. */ CbcLotsize::CbcLotsize (CbcModel * model, int iColumn, int numberPoints, const double * points, bool range) : CbcObject(model) { #if CBC_PRINT if (!saveModel) saveModel = model; #endif assert (numberPoints > 0); columnNumber_ = iColumn ; // and set id so can be used for branching id_ = iColumn; // sort ranges int * sort = new int[numberPoints]; double * weight = new double [numberPoints]; int i; if (range) { rangeType_ = 2; } else { rangeType_ = 1; } for (i = 0; i < numberPoints; i++) { sort[i] = i; weight[i] = points[i*rangeType_]; } CoinSort_2(weight, weight + numberPoints, sort); numberRanges_ = 1; largestGap_ = 0; if (rangeType_ == 1) { bound_ = new double[numberPoints+1]; bound_[0] = weight[0]; for (i = 1; i < numberPoints; i++) { if (weight[i] != weight[i-1]) bound_[numberRanges_++] = weight[i]; } // and for safety bound_[numberRanges_] = bound_[numberRanges_-1]; for (i = 1; i < numberRanges_; i++) { largestGap_ = CoinMax(largestGap_, bound_[i] - bound_[i-1]); } } else { bound_ = new double[2*numberPoints+2]; bound_[0] = points[sort[0] * 2]; bound_[1] = points[sort[0] * 2 + 1]; double hi = bound_[1]; assert (hi >= bound_[0]); for (i = 1; i < numberPoints; i++) { double thisLo = points[sort[i] * 2]; double thisHi = points[sort[i] * 2 + 1]; assert (thisHi >= thisLo); if (thisLo > hi) { bound_[2*numberRanges_] = thisLo; bound_[2*numberRanges_+1] = thisHi; numberRanges_++; hi = thisHi; } else { //overlap hi = CoinMax(hi, thisHi); bound_[2*numberRanges_-1] = hi; } } // and for safety bound_[2*numberRanges_] = bound_[2*numberRanges_-2]; bound_[2*numberRanges_+1] = bound_[2*numberRanges_-1]; for (i = 1; i < numberRanges_; i++) { largestGap_ = CoinMax(largestGap_, bound_[2*i] - bound_[2*i-1]); } } delete [] sort; delete [] weight; range_ = 0; }
void CglClique::find_scl(OsiCuts& cs) { const int nodenum = fgraph.nodenum; const fnode *nodes = fgraph.nodes; // Return at once if no nodes - otherwise we get invalid reads if (!nodenum) return; int *current_indices = new int[nodenum]; int *current_degrees = new int[nodenum]; double *current_values = new double[nodenum]; int *star = cl_indices; int *star_deg = new int[nodenum]; /** An array used in the recursive complete enumeration of maximal cliques. The first cl_length entries are used. */ bool* label = new bool[nodenum]; int i, cnt1 = 0, cnt2 = 0, cnt3 = 0; int clique_cnt_e = 0, clique_cnt_g = 0; int largest_star_size = 0; /* initialize global variables */ cl_del_length = 0; /* initialize current_nodes, current_degrees and current_values */ int current_nodenum = nodenum; for (i = 0; i < nodenum; i++) { current_indices[i] = i; current_degrees[i] = nodes[i].degree; current_values[i] = nodes[i].val; } /* find first node to be checked */ int best_ind = scl_choose_next_node(current_nodenum, current_indices, current_degrees, current_values); int v = current_indices[best_ind]; int v_deg = current_degrees[best_ind]; double v_val = current_values[best_ind]; /* while there are nodes left in the graph ... (more precisely, while there are at least 3 nodes in the graph) */ while (current_nodenum > 2) { /* if the best node is of degree < 2 then it can be deleted */ if (v_deg < 2) { cl_del_indices[cl_del_length++] = v; scl_delete_node(best_ind, current_nodenum, current_indices, current_degrees, current_values); best_ind = scl_choose_next_node(current_nodenum, current_indices, current_degrees, current_values); v = current_indices[best_ind]; v_deg = current_degrees[best_ind]; v_val = current_values[best_ind]; largest_star_size = CoinMax(largest_star_size, v_deg); continue; } /* star will contain the indices of v's neighbors (but not v's index) */ const bool* node_node_start = node_node + nodenum * v; int& star_length = cl_length; star_length = 0; double star_val = v_val; for (i = 0; i < current_nodenum; i++) { const int other_node = current_indices[i]; if (node_node_start[other_node]) { star[star_length] = other_node; star_deg[star_length++] = current_degrees[i]; star_val += current_values[i]; } } /* quick check: if sum of values for the star does not exceed 1 then there won't be a violated clique in the star */ if (star_val >= 1 + petol) { /* node whose star we're evaluating is always in */ cl_perm_length = 1; cl_perm_indices = &v; /* find maximal violated cliques in star. cliques found here might not be maximal wrt to entire fractional graph, only for the current subset of it (some nodes might be already deleted...) Note that star is the same as cl_indices and start_length is cl_length... */ if (v_deg < scl_candidate_length_threshold) { // par /* enumerate if v_deg is small enough */ for (i = 0; i < star_length; i++) label[i] = false; int pos = 0; clique_cnt_e += enumerate_maximal_cliques(pos, label, cs); cnt1++; } else { /* greedily find if v_deg is too big */ /* order nodes in *decreasing* order of their degrees in star */ CoinSort_2(star_deg, star_deg + star_length, star, CoinFirstGreater_2<int,int>()); /* find maxl clique greedily, including v */ clique_cnt_g += greedy_maximal_clique(cs); cnt2++; } } else { cnt3++; } /* delete v from current_indices */ cl_del_indices[cl_del_length++] = v; scl_delete_node(best_ind, current_nodenum, current_indices, current_degrees, current_values); best_ind = scl_choose_next_node(current_nodenum, current_indices, current_degrees, current_values); v = current_indices[best_ind]; v_deg = current_degrees[best_ind]; v_val = current_values[best_ind]; largest_star_size = CoinMax(largest_star_size, v_deg); } const int clique_cnt = clique_cnt_e + clique_cnt_g; if (scl_report_result) { printf("\nscl Found %i new violated cliques with the star-clique method", clique_cnt); printf("\nscl The largest star size was %i (threshold %i)\n", largest_star_size, scl_candidate_length_threshold); // par printf("scl Enumeration %i times, found %i maxl cliques\n", cnt1, clique_cnt_e); printf("scl Greedy %i times, found %i maxl cliques\n", cnt2, clique_cnt_g); printf("scl Skipped a star b/c of small solution value %i times\n", cnt3); if (cnt2 == 0) printf("scl all cliques have been enumerated\n"); else printf("scl not all cliques have been eliminated\n"); } delete[] current_indices; delete[] current_degrees; delete[] current_values; delete[] star_deg; delete[] label; }
/* This is the real constructor*/ ClpDynamicExampleMatrix::ClpDynamicExampleMatrix(ClpSimplex * model, int numberSets, int numberGubColumns, const int * starts, const double * lower, const double * upper, const CoinBigIndex * startColumn, const int * row, const double * element, const double * cost, const double * columnLower, const double * columnUpper, const unsigned char * status, const unsigned char * dynamicStatus, int numberIds, const int *ids) : ClpDynamicMatrix(model, numberSets, 0, NULL, lower, upper, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) { setType(25); numberColumns_ = numberGubColumns; // start with safe values - then experiment maximumGubColumns_ = numberColumns_; maximumElements_ = startColumn[numberColumns_]; // delete odd stuff created by ClpDynamicMatrix constructor delete [] startSet_; startSet_ = new int [numberSets_]; delete [] next_; next_ = new int [maximumGubColumns_]; delete [] row_; delete [] element_; delete [] startColumn_; delete [] cost_; delete [] columnLower_; delete [] columnUpper_; delete [] dynamicStatus_; delete [] status_; delete [] id_; // and size correctly row_ = new int [maximumElements_]; element_ = new double [maximumElements_]; startColumn_ = new CoinBigIndex [maximumGubColumns_+1]; // say no columns yet numberGubColumns_ = 0; startColumn_[0] = 0; cost_ = new double[maximumGubColumns_]; dynamicStatus_ = new unsigned char [2*maximumGubColumns_]; memset(dynamicStatus_, 0, maximumGubColumns_); id_ = new int[maximumGubColumns_]; if (columnLower) columnLower_ = new double[maximumGubColumns_]; else columnLower_ = NULL; if (columnUpper) columnUpper_ = new double[maximumGubColumns_]; else columnUpper_ = NULL; // space for ids idGen_ = new int [maximumGubColumns_]; int iSet; for (iSet = 0; iSet < numberSets_; iSet++) startSet_[iSet] = -1; // This starts code specific to this storage method CoinBigIndex i; fullStartGen_ = ClpCopyOfArray(starts, numberSets_ + 1); startColumnGen_ = ClpCopyOfArray(startColumn, numberColumns_ + 1); CoinBigIndex numberElements = startColumnGen_[numberColumns_]; rowGen_ = ClpCopyOfArray(row, numberElements); elementGen_ = new double[numberElements]; for (i = 0; i < numberElements; i++) elementGen_[i] = element[i]; costGen_ = new double[numberColumns_]; for (i = 0; i < numberColumns_; i++) { costGen_[i] = cost[i]; // I don't think I need sorted but ... CoinSort_2(rowGen_ + startColumnGen_[i], rowGen_ + startColumnGen_[i+1], elementGen_ + startColumnGen_[i]); } if (columnLower) { columnLowerGen_ = new double[numberColumns_]; for (i = 0; i < numberColumns_; i++) { columnLowerGen_[i] = columnLower[i]; if (columnLowerGen_[i]) { printf("Non-zero lower bounds not allowed - subtract from model\n"); abort(); } } } else { columnLowerGen_ = NULL; } if (columnUpper) { columnUpperGen_ = new double[numberColumns_]; for (i = 0; i < numberColumns_; i++) columnUpperGen_[i] = columnUpper[i]; } else { columnUpperGen_ = NULL; } // end specific coding if (columnUpper_) { // set all upper bounds so we have enough space double * columnUpper = model->columnUpper(); for(i = firstDynamic_; i < lastDynamic_; i++) columnUpper[i] = 1.0e10; } status_ = new unsigned char [2*numberSets_+4]; if (status) { memcpy(status_,status, numberSets_ * sizeof(char)); assert (dynamicStatus); CoinMemcpyN(dynamicStatus, numberIds, dynamicStatus_); assert (numberIds); } else { assert (!numberIds); memset(status_, 0, numberSets_); for (i = 0; i < numberSets_; i++) { // make slack key setStatus(i, ClpSimplex::basic); } } dynamicStatusGen_ = new unsigned char [numberColumns_]; memset(dynamicStatusGen_, 0, numberColumns_); // for clarity for (i = 0; i < numberColumns_; i++) setDynamicStatusGen(i, atLowerBound); // Populate with enough columns if (!numberIds) { // This could be made more sophisticated for (iSet = 0; iSet < numberSets_; iSet++) { int sequence = fullStartGen_[iSet]; CoinBigIndex start = startColumnGen_[sequence]; addColumn(startColumnGen_[sequence+1] - start, rowGen_ + start, elementGen_ + start, costGen_[sequence], columnLowerGen_ ? columnLowerGen_[sequence] : 0, columnUpperGen_ ? columnUpperGen_[sequence] : 1.0e30, iSet, getDynamicStatusGen(sequence)); idGen_[iSet] = sequence; // say which one in setDynamicStatusGen(sequence, inSmall); } } else { // put back old ones int * set = new int[numberColumns_]; for (iSet = 0; iSet < numberSets_; iSet++) { for (CoinBigIndex j = fullStartGen_[iSet]; j < fullStartGen_[iSet+1]; j++) set[j] = iSet; } for (int i = 0; i < numberIds; i++) { int sequence = ids[i]; CoinBigIndex start = startColumnGen_[sequence]; addColumn(startColumnGen_[sequence+1] - start, rowGen_ + start, elementGen_ + start, costGen_[sequence], columnLowerGen_ ? columnLowerGen_[sequence] : 0, columnUpperGen_ ? columnUpperGen_[sequence] : 1.0e30, set[sequence], getDynamicStatus(i)); idGen_[iSet] = sequence; // say which one in setDynamicStatusGen(sequence, inSmall); } delete [] set; } if (!status) { gubCrash(); } else { initialProblem(); } }
int main(int argc, const char *argv[]) { ClpSimplex model; int status; // Keep names if (argc < 2) { status = model.readMps("small.mps", true); } else { status = model.readMps(argv[1], true); } if (status) exit(10); /* This driver implements the presolve variation of Sprint. This assumes we can get feasible easily */ int numberRows = model.numberRows(); int numberColumns = model.numberColumns(); // We will need arrays to choose variables. These are too big but .. double * weight = new double [numberRows+numberColumns]; int * sort = new int [numberRows+numberColumns]; double * columnLower = model.columnLower(); double * columnUpper = model.columnUpper(); double * saveLower = new double [numberColumns]; memcpy(saveLower, columnLower, numberColumns * sizeof(double)); double * saveUpper = new double [numberColumns]; memcpy(saveUpper, columnUpper, numberColumns * sizeof(double)); double * solution = model.primalColumnSolution(); // Fix in some magical way so remaining problem is easy #if 0 // This is from a real-world problem for (int iColumn = 0; iColumn < numberColumns; iColumn++) { char firstCharacter = model.columnName(iColumn)[0]; if (firstCharacter == 'F' || firstCharacter == 'P' || firstCharacter == 'L' || firstCharacter == 'T') { columnUpper[iColumn] = columnLower[iColumn]; } } #else double * obj = model.objective(); double * saveObj = new double [numberColumns]; memcpy(saveObj, obj, numberColumns * sizeof(double)); memset(obj, 0, numberColumns * sizeof(double)); model.dual(); memcpy(obj, saveObj, numberColumns * sizeof(double)); delete [] saveObj; for (int iColumn = 0; iColumn < numberColumns; iColumn++) { if (solution[iColumn]<columnLower[iColumn]+1.0e-8) { columnUpper[iColumn] = columnLower[iColumn]; } } #endif // Just do this number of passes int maxPass = 100; int iPass; double lastObjective = 1.0e31; // Just take this number of columns in small problem int smallNumberColumns = 3 * numberRows; // And we want number of rows to be this int smallNumberRows = numberRows / 4; for (iPass = 0; iPass < maxPass; iPass++) { printf("Start of pass %d\n", iPass); ClpSimplex * model2; ClpPresolve pinfo; int numberPasses = 1; // can change this model2 = pinfo.presolvedModel(model, 1.0e-8, false, numberPasses, false); if (!model2) { fprintf(stdout, "ClpPresolve says %s is infeasible with tolerance of %g\n", argv[1], 1.0e-8); // model was infeasible - maybe try again with looser tolerances model2 = pinfo.presolvedModel(model, 1.0e-7, false, numberPasses, false); if (!model2) { fprintf(stdout, "ClpPresolve says %s is infeasible with tolerance of %g\n", argv[1], 1.0e-7); exit(2); } } // change factorization frequency from 200 model2->setFactorizationFrequency(100 + model2->numberRows() / 50); model2->primal(); pinfo.postsolve(true); // adjust smallNumberColumns if necessary if (iPass) { double ratio = ((double) smallNumberRows) / ((double) model2->numberRows()); smallNumberColumns = (int)(smallNumberColumns * ratio); } delete model2; /* After this postsolve model should be optimal. We can use checkSolution and test feasibility */ model.checkSolution(); if (model.numberDualInfeasibilities() || model.numberPrimalInfeasibilities()) printf("%g dual %g(%d) Primal %g(%d)\n", model.objectiveValue(), model.sumDualInfeasibilities(), model.numberDualInfeasibilities(), model.sumPrimalInfeasibilities(), model.numberPrimalInfeasibilities()); // Put back true bounds memcpy(columnLower, saveLower, numberColumns * sizeof(double)); memcpy(columnUpper, saveUpper, numberColumns * sizeof(double)); if ((model.objectiveValue() > lastObjective - 1.0e-7 && iPass > 5) || iPass == maxPass - 1) { break; // finished } else { lastObjective = model.objectiveValue(); // now massage weight so all basic in plus good djs const double * djs = model.dualColumnSolution(); for (int iColumn = 0; iColumn < numberColumns; iColumn++) { double dj = djs[iColumn]; double value = solution[iColumn]; if (model.getStatus(iColumn) == ClpSimplex::basic) dj = -1.0e50; else if (dj < 0.0 && value < columnUpper[iColumn]) dj = dj; else if (dj > 0.0 && value > columnLower[iColumn]) dj = -dj; else if (columnUpper[iColumn] > columnLower[iColumn]) dj = fabs(dj); else dj = 1.0e50; weight[iColumn] = dj; sort[iColumn] = iColumn; } // sort CoinSort_2(weight, weight + numberColumns, sort); // and fix others for (int iColumn = smallNumberColumns; iColumn < numberColumns; iColumn++) { int kColumn = sort[iColumn]; double value = solution[kColumn]; columnLower[kColumn] = value; columnUpper[kColumn] = value; } } } delete [] weight; delete [] sort; delete [] saveLower; delete [] saveUpper; model.primal(1); return 0; }
const CoinPresolveAction *subst_constraint_action::presolve ( CoinPresolveMatrix *prob, const int *implied_free, const int *whichFree, int numberFree, const CoinPresolveAction *next, int maxLook) { # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering subst_constraint_action::presolve, fill level " << maxLook << ", " << numberFree << " candidates." << std::endl ; # endif presolve_consistent(prob) ; presolve_links_ok(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int startEmptyRows = 0 ; int startEmptyColumns = 0 ; startEmptyRows = prob->countEmptyRows() ; startEmptyColumns = prob->countEmptyCols() ; # if COIN_PRESOLVE_TUNING > 0 double startTime = 0.0 ; if (prob->tuning_) startTime = CoinCpuTime() ; # endif # endif /* Unpack the row- and column-major representations. */ const int ncols = prob->ncols_ ; const int nrows = prob->nrows_ ; CoinBigIndex *rowStarts = prob->mrstrt_ ; int *rowLengths = prob->hinrow_ ; double *rowCoeffs = prob->rowels_ ; int *colIndices = prob->hcol_ ; presolvehlink *rlink = prob->rlink_ ; CoinBigIndex *colStarts = prob->mcstrt_ ; int *colLengths = prob->hincol_ ; double *colCoeffs = prob->colels_ ; int *rowIndices = prob->hrow_ ; presolvehlink *clink = prob->clink_ ; /* Row bounds and activity, objective. */ double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; double *acts = prob->acts_ ; double *cost = prob->cost_ ; const double tol = prob->feasibilityTolerance_ ; action *actions = new action [ncols] ; # ifdef ZEROFAULT CoinZeroN(reinterpret_cast<char *>(actions),ncols*sizeof(action)) ; # endif int nactions = 0 ; /* This array is used to hold the indices of columns involved in substitutions, where we have the potential for cancellation. At the end they'll be checked to eliminate any actual zeros that may result. At the end of processing of each target row, the column indices of the target row are copied into zerocols. NOTE that usefulColumnInt_ is already in use for parameters implied_free and whichFree when this routine is called from implied_free. */ int *zerocols = new int[ncols] ; int nzerocols = 0 ; int *x_to_y = new int[ncols] ; int *rowsUsed = &prob->usefulRowInt_[0] ; int nRowsUsed = 0 ; /* Open a loop to process the (equality r, implied free variable t) pairs in whichFree and implied_free. It can happen that removal of (row, natural singleton) pairs back in implied_free will reduce the length of column t. It can also happen that previous processing here has resulted in fillin or cancellation. So check again for column length and exclude natural singletons and overly dense columns. */ for (int iLook = 0 ; iLook < numberFree ; iLook++) { const int tgtcol = whichFree[iLook] ; const int tgtcol_len = colLengths[tgtcol] ; const int tgtrow = implied_free[iLook] ; const int tgtrow_len = rowLengths[tgtrow] ; assert(fabs(rlo[tgtrow]-rup[tgtrow]) < tol) ; if (colLengths[tgtcol] < 2 || colLengths[tgtcol] > maxLook) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); length now " << colLengths[tgtcol] << "." << std::endl ; # endif continue ; } CoinBigIndex tgtcs = colStarts[tgtcol] ; CoinBigIndex tgtce = tgtcs+colLengths[tgtcol] ; /* A few checks to make sure that the candidate pair is still suitable. Processing candidates earlier in the list can eliminate coefficients. * Don't use this pair if any involved row i has become a row singleton or empty. * Don't use this pair if any involved row has been modified as part of the processing for a previous candidate pair on this call. * Don't use this pair if a(i,tgtcol) has become zero. The checks on a(i,tgtcol) seem superfluous but it's possible that implied_free identified two candidate pairs to eliminate the same column. If we've already processed one of them, we could be in trouble. */ double tgtcoeff = 0.0 ; bool dealBreaker = false ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const int i = rowIndices[kcol] ; if (rowLengths[i] < 2 || prob->rowUsed(i)) { dealBreaker = true ; break ; } const double aij = colCoeffs[kcol] ; if (fabs(aij) <= ZTOLDP2) { dealBreaker = true ; break ; } if (i == tgtrow) tgtcoeff = aij ; } if (dealBreaker == true) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); deal breaker (1)." << std::endl ; # endif continue ; } /* Check for numerical stability.A large coeff_factor will inflate the coefficients in the substitution formula. */ dealBreaker = false ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const double coeff_factor = fabs(colCoeffs[kcol]/tgtcoeff) ; if (coeff_factor > 10.0) dealBreaker = true ; } /* Given enough target rows with sufficient overlap, there's an outside chance we could overflow zerocols. Unlikely to ever happen. */ if (!dealBreaker && nzerocols+rowLengths[tgtrow] >= ncols) dealBreaker = true ; if (dealBreaker == true) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); deal breaker (2)." << std::endl ; # endif continue ; } /* If c(t) != 0, we will need to modify the objective coefficients and remember the original objective. */ const bool nonzero_cost = (fabs(cost[tgtcol]) > tol) ; double *costsx = (nonzero_cost?new double[rowLengths[tgtrow]]:0) ; # if PRESOLVE_DEBUG > 1 std::cout << " Eliminating row " << tgtrow << ", col " << tgtcol ; if (nonzero_cost) std::cout << ", cost " << cost[tgtcol] ; std::cout << "." << std::endl ; # endif /* Count up the total number of coefficients in entangled rows and mark them as contaminated. */ int ntotels = 0 ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const int i = rowIndices[kcol] ; ntotels += rowLengths[i] ; PRESOLVEASSERT(!prob->rowUsed(i)) ; prob->setRowUsed(i) ; rowsUsed[nRowsUsed++] = i ; } /* Create the postsolve object. Copy in all the affected rows. Take the opportunity to mark the entangled rows as changed and put them on the list of rows to process in the next round. coeffxs in particular holds the coefficients of the target column. */ action *ap = &actions[nactions++] ; ap->col = tgtcol ; ap->rowy = tgtrow ; PRESOLVE_DETAIL_PRINT(printf("pre_subst %dC %dR E\n",tgtcol,tgtrow)) ; ap->nincol = tgtcol_len ; ap->rows = new int[tgtcol_len] ; ap->rlos = new double[tgtcol_len] ; ap->rups = new double[tgtcol_len] ; ap->costsx = costsx ; ap->coeffxs = new double[tgtcol_len] ; ap->ninrowxs = new int[tgtcol_len] ; ap->rowcolsxs = new int[ntotels] ; ap->rowelsxs = new double[ntotels] ; ntotels = 0 ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const int ndx = kcol-tgtcs ; const int i = rowIndices[kcol] ; const CoinBigIndex krs = rowStarts[i] ; prob->addRow(i) ; ap->rows[ndx] = i ; ap->ninrowxs[ndx] = rowLengths[i] ; ap->rlos[ndx] = rlo[i] ; ap->rups[ndx] = rup[i] ; ap->coeffxs[ndx] = colCoeffs[kcol] ; CoinMemcpyN(&colIndices[krs],rowLengths[i],&ap->rowcolsxs[ntotels]) ; CoinMemcpyN(&rowCoeffs[krs],rowLengths[i],&ap->rowelsxs[ntotels]) ; ntotels += rowLengths[i] ; } CoinBigIndex tgtrs = rowStarts[tgtrow] ; CoinBigIndex tgtre = tgtrs+rowLengths[tgtrow] ; /* Adjust the objective coefficients based on the substitution formula c'(j) = c(j) - a(rj)c(t)/a(rt) */ if (nonzero_cost) { const double tgtcost = cost[tgtcol] ; for (CoinBigIndex krow = tgtrs ; krow < tgtre ; krow ++) { const int j = colIndices[krow] ; prob->addCol(j) ; costsx[krow-tgtrs] = cost[j] ; double coeff = rowCoeffs[krow] ; cost[j] -= (tgtcost*coeff)/tgtcoeff ; } prob->change_bias(tgtcost*rlo[tgtrow]/tgtcoeff) ; cost[tgtcol] = 0.0 ; } # if PRESOLVE_DEBUG > 1 std::cout << " tgt (" << tgtrow << ") (" << tgtrow_len << "): " ; for (CoinBigIndex krow = tgtrs ; krow < tgtre ; ++krow) { const int j = colIndices[krow] ; const double arj = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << arj << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif // kill small if wanted int relax= (prob->presolveOptions()&0x60000)>>17; double tolerance = 1.0e-12; for (int i=0;i<relax;i++) tolerance *= 10.0; /* Sort the target row for efficiency when doing elimination. */ CoinSort_2(colIndices+tgtrs,colIndices+tgtre,rowCoeffs+tgtrs) ; /* Get down to the business of substituting for tgtcol in the entangled rows. Open a loop to walk the target column. We walk the saved column because the bulk store can change as we work. We don't want to repeat or miss a row. */ for (int colndx = 0 ; colndx < tgtcol_len ; ++colndx) { int i = ap->rows[colndx] ; if (i == tgtrow) continue ; double ait = ap->coeffxs[colndx] ; double coeff_factor = -ait/tgtcoeff ; CoinBigIndex krs = rowStarts[i] ; CoinBigIndex kre = krs+rowLengths[i] ; # if PRESOLVE_DEBUG > 1 std::cout << " subst pre (" << i << ") (" << rowLengths[i] << "): " ; for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const int j = colIndices[krow] ; const double aij = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif /* Sort the row for efficiency and call add_row to do the actual business of changing coefficients due to substitution. This has the potential to trigger compaction of the row-major bulk store, so update bulk store indices. */ CoinSort_2(colIndices+krs,colIndices+kre,rowCoeffs+krs) ; bool outOfSpace = add_row(rowStarts,rlo,acts,rup,rowCoeffs,colIndices, rowLengths,rlink,nrows,coeff_factor,tolerance,i,tgtrow, x_to_y) ; if (outOfSpace) throwCoinError("out of memory","CoinImpliedFree::presolve") ; krs = rowStarts[i] ; kre = krs+rowLengths[i] ; tgtrs = rowStarts[tgtrow] ; tgtre = tgtrs+rowLengths[tgtrow] ; # if PRESOLVE_DEBUG > 1 std::cout << " subst aft (" << i << ") (" << rowLengths[i] << "): " ; for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const int j = colIndices[krow] ; const double aij = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif /* Now update the column-major representation from the row-major representation. This is easy if the coefficient already exists, but painful if there's fillin. presolve_find_row1 will return the index of the row in the column vector, or one past the end if it's missing. If the coefficient is fill, presolve_expand_col will make sure that there's room in the column for one more coefficient. This may require that the column be moved in the bulk store, so we need to update kcs and kce. Once we're done, a(it) = 0 (i.e., we've eliminated x(t) from row i). Physically remove the explicit zero from the row-major representation with presolve_delete_from_row. */ for (CoinBigIndex rowndx = 0 ; rowndx < tgtrow_len ; ++rowndx) { const CoinBigIndex ktgt = tgtrs+rowndx ; const int j = colIndices[ktgt] ; CoinBigIndex kcs = colStarts[j] ; CoinBigIndex kce = kcs+colLengths[j] ; assert(colIndices[krs+x_to_y[rowndx]] == j) ; const double coeff = rowCoeffs[krs+x_to_y[rowndx]] ; CoinBigIndex kcol = presolve_find_row1(i,kcs,kce,rowIndices) ; if (kcol < kce) { colCoeffs[kcol] = coeff ; } else { outOfSpace = presolve_expand_col(colStarts,colCoeffs,rowIndices, colLengths,clink,ncols,j) ; if (outOfSpace) throwCoinError("out of memory","CoinImpliedFree::presolve") ; kcs = colStarts[j] ; kce = kcs+colLengths[j] ; rowIndices[kce] = i ; colCoeffs[kce] = coeff ; colLengths[j]++ ; } } presolve_delete_from_row(i,tgtcol, rowStarts,rowLengths,colIndices,rowCoeffs) ; # if PRESOLVE_DEBUG > 1 kre-- ; std::cout << " subst fin (" << i << ") (" << rowLengths[i] << "): " ; for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const int j = colIndices[krow] ; const double aij = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif } /* End of the substitution loop. Record the column indices of the target row so we can groom these columns later to remove possible explicit zeros. */ CoinMemcpyN(&colIndices[rowStarts[tgtrow]],rowLengths[tgtrow], &zerocols[nzerocols]) ; nzerocols += rowLengths[tgtrow] ; /* Remove the target equality from the column- and row-major representations Somewhat painful in the colum-major representation. We have to walk the target row in the row-major representation and look up each coefficient in the column-major representation. */ for (CoinBigIndex krow = tgtrs ; krow < tgtre ; ++krow) { const int j = colIndices[krow] ; # if PRESOLVE_DEBUG > 1 std::cout << " removing row " << tgtrow << " from col " << j << std::endl ; # endif presolve_delete_from_col(tgtrow,j, colStarts,colLengths,rowIndices,colCoeffs) ; if (colLengths[j] == 0) { PRESOLVE_REMOVE_LINK(clink,j) ; } } /* Finally, physically remove the column from the column-major representation and the row from the row-major representation. */ PRESOLVE_REMOVE_LINK(clink, tgtcol) ; colLengths[tgtcol] = 0 ; PRESOLVE_REMOVE_LINK(rlink, tgtrow) ; rowLengths[tgtrow] = 0 ; rlo[tgtrow] = 0.0 ; rup[tgtrow] = 0.0 ; # if PRESOLVE_CONSISTENCY > 0 presolve_links_ok(prob) ; presolve_consistent(prob) ; # endif } /* That's it, we've processed all the candidate pairs. Clear the row used flags. */ for (int i = 0 ; i < nRowsUsed ; i++) prob->unsetRowUsed(rowsUsed[i]) ; /* Trim the array of substitution transforms and queue up objects for postsolve. Also groom the problem representation to remove explicit zeros. */ if (nactions) { # if PRESOLVE_SUMMARY > 0 std::cout << "NSUBSTS: " << nactions << std::endl ; # endif next = new subst_constraint_action(nactions, CoinCopyOfArray(actions,nactions),next) ; next = drop_zero_coefficients_action::presolve(prob,zerocols, nzerocols, next) ; # if PRESOLVE_CONSISTENCY > 0 presolve_links_ok(prob) ; presolve_consistent(prob) ; # endif } deleteAction(actions,action*) ; delete [] x_to_y ; delete [] zerocols ; # if COIN_PRESOLVE_TUNING > 0 if (prob->tuning_) double thisTime = CoinCpuTime() ; # endif # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 presolve_check_sol(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving subst_constraint_action::presolve, " << droppedRows << " rows, " << droppedColumns << " columns dropped" ; # if COIN_PRESOLVE_TUNING > 0 std::cout << " in " << thisTime-startTime << "s" ; # endif std::cout << "." << std::endl ; # endif return (next) ; }
// As some computation is needed in more than one place - returns row int CbcFollowOn::gutsOfFollowOn(int & otherRow, int & preferredWay) const { int whichRow = -1; otherRow = -1; int numberRows = matrix_.getNumRows(); int i; // For sorting int * sort = new int [numberRows]; int * isort = new int [numberRows]; // Column copy //const double * element = matrix_.getElements(); const int * row = matrix_.getIndices(); const CoinBigIndex * columnStart = matrix_.getVectorStarts(); const int * columnLength = matrix_.getVectorLengths(); // Row copy const double * elementByRow = matrixByRow_.getElements(); const int * column = matrixByRow_.getIndices(); const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts(); const int * rowLength = matrixByRow_.getVectorLengths(); OsiSolverInterface * solver = model_->solver(); const double * columnLower = solver->getColLower(); const double * columnUpper = solver->getColUpper(); const double * solution = solver->getColSolution(); double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance); int nSort = 0; for (i = 0; i < numberRows; i++) { if (rhs_[i]) { // check elements double smallest = 1.0e10; double largest = 0.0; int rhsValue = rhs_[i]; int number1 = 0; 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]) { smallest = CoinMin(smallest, value); largest = CoinMax(largest, value); if (value == 1.0) number1++; if (solValue < 1.0 - integerTolerance && solValue > integerTolerance) numberUnsatisfied++; } else { rhsValue -= static_cast<int>(value * floor(solValue + 0.5)); } } if (numberUnsatisfied > 1) { if (smallest < largest) { // probably no good but check a few things assert (largest <= rhsValue); if (number1 == 1 && largest == rhsValue) printf("could fix\n"); } else if (largest == rhsValue) { sort[nSort] = i; isort[nSort++] = -numberUnsatisfied; } } } } if (nSort > 1) { CoinSort_2(isort, isort + nSort, sort); CoinZeroN(isort, numberRows); double * other = new double[numberRows]; CoinZeroN(other, numberRows); int * which = new int[numberRows]; //#define COUNT #ifndef COUNT bool beforeSolution = model_->getSolutionCount() == 0; #endif for (int k = 0; k < nSort - 1; k++) { i = sort[k]; int numberUnsatisfied = 0; int n = 0; int j; for (j = rowStart[i]; j < rowStart[i] + rowLength[i]; j++) { int iColumn = column[j]; if (columnLower[iColumn] != columnUpper[iColumn]) { double solValue = solution[iColumn] - columnLower[iColumn]; if (solValue < 1.0 - integerTolerance && solValue > integerTolerance) { numberUnsatisfied++; for (int jj = columnStart[iColumn]; jj < columnStart[iColumn] + columnLength[iColumn]; jj++) { int iRow = row[jj]; if (rhs_[iRow]) { other[iRow] += solValue; if (isort[iRow]) { isort[iRow]++; } else { isort[iRow] = 1; which[n++] = iRow; } } } } } } double total = 0.0; // Take out row double sumThis = other[i]; other[i] = 0.0; assert (numberUnsatisfied == isort[i]); // find one nearest half if solution, one if before solution int iBest = -1; double dtarget = 0.5 * total; #ifdef COUNT int target = (numberUnsatisfied + 1) >> 1; int best = numberUnsatisfied; #else double best; if (beforeSolution) best = dtarget; else best = 1.0e30; #endif for (j = 0; j < n; j++) { int iRow = which[j]; double dvalue = other[iRow]; other[iRow] = 0.0; #ifdef COUNT int value = isort[iRow]; #endif isort[iRow] = 0; if (fabs(dvalue) < 1.0e-8 || fabs(sumThis - dvalue) < 1.0e-8) continue; if (dvalue < integerTolerance || dvalue > 1.0 - integerTolerance) continue; #ifdef COUNT if (abs(value - target) < best && value != numberUnsatisfied) { best = abs(value - target); iBest = iRow; if (dvalue < dtarget) preferredWay = 1; else preferredWay = -1; } #else if (beforeSolution) { if (fabs(dvalue - dtarget) > best) { best = fabs(dvalue - dtarget); iBest = iRow; if (dvalue < dtarget) preferredWay = 1; else preferredWay = -1; } } else { if (fabs(dvalue - dtarget) < best) { best = fabs(dvalue - dtarget); iBest = iRow; if (dvalue < dtarget) preferredWay = 1; else preferredWay = -1; } } #endif } if (iBest >= 0) { whichRow = i; otherRow = iBest; break; } } delete [] which; delete [] other; }
int main (int argc, const char *argv[]) { ClpSimplex model; int status; // Keep names if (argc < 2) { status = model.readMps("small.mps", true); } else { status = model.readMps(argv[1], true); } if (status) exit(10); /* This driver implements what I called Sprint. Cplex calls it "sifting" which is just as silly. When I thought of this trivial idea it reminded me of an LP code of the 60's called sprint which after every factorization took a subset of the matrix into memory (all 64K words!) and then iterated very fast on that subset. On the problems of those days it did not work very well, but it worked very well on aircrew scheduling problems where there were very large numbers of columns all with the same flavor. */ /* The idea works best if you can get feasible easily. To make it more general we can add in costed slacks */ int originalNumberColumns = model.numberColumns(); int numberRows = model.numberRows(); // We will need arrays to choose variables. These are too big but .. double * weight = new double [numberRows+originalNumberColumns]; int * sort = new int [numberRows+originalNumberColumns]; int numberSort = 0; // Say we are going to add slacks - if you can get a feasible // solution then do that at the comment - Add in your own coding here bool addSlacks = true; if (addSlacks) { // initial list will just be artificials // first we will set all variables as close to zero as possible int iColumn; const double * columnLower = model.columnLower(); const double * columnUpper = model.columnUpper(); double * columnSolution = model.primalColumnSolution(); for (iColumn = 0; iColumn < originalNumberColumns; iColumn++) { double value = 0.0; if (columnLower[iColumn] > 0.0) value = columnLower[iColumn]; else if (columnUpper[iColumn] < 0.0) value = columnUpper[iColumn]; columnSolution[iColumn] = value; } // now see what that does to row solution double * rowSolution = model.primalRowSolution(); memset (rowSolution, 0, numberRows * sizeof(double)); model.times(1.0, columnSolution, rowSolution); int * addStarts = new int [numberRows+1]; int * addRow = new int[numberRows]; double * addElement = new double[numberRows]; const double * lower = model.rowLower(); const double * upper = model.rowUpper(); addStarts[0] = 0; int numberArtificials = 0; double * addCost = new double [numberRows]; const double penalty = 1.0e8; int iRow; for (iRow = 0; iRow < numberRows; iRow++) { if (lower[iRow] > rowSolution[iRow]) { addRow[numberArtificials] = iRow; addElement[numberArtificials] = 1.0; addCost[numberArtificials] = penalty; numberArtificials++; addStarts[numberArtificials] = numberArtificials; } else if (upper[iRow] < rowSolution[iRow]) { addRow[numberArtificials] = iRow; addElement[numberArtificials] = -1.0; addCost[numberArtificials] = penalty; numberArtificials++; addStarts[numberArtificials] = numberArtificials; } } model.addColumns(numberArtificials, NULL, NULL, addCost, addStarts, addRow, addElement); delete [] addStarts; delete [] addRow; delete [] addElement; delete [] addCost; // Set up initial list numberSort = numberArtificials; int i; for (i = 0; i < numberSort; i++) sort[i] = i + originalNumberColumns; } else { // Get initial list in some magical way // Add in your own coding here abort(); } int numberColumns = model.numberColumns(); const double * columnLower = model.columnLower(); const double * columnUpper = model.columnUpper(); double * fullSolution = model.primalColumnSolution(); // Just do this number of passes int maxPass = 100; int iPass; double lastObjective = 1.0e31; // Just take this number of columns in small problem int smallNumberColumns = CoinMin(3 * numberRows, numberColumns); smallNumberColumns = CoinMax(smallNumberColumns, 3000); // We will be using all rows int * whichRows = new int [numberRows]; for (int iRow = 0; iRow < numberRows; iRow++) whichRows[iRow] = iRow; double originalOffset; model.getDblParam(ClpObjOffset, originalOffset); for (iPass = 0; iPass < maxPass; iPass++) { printf("Start of pass %d\n", iPass); //printf("Bug until submodel new version\n"); CoinSort_2(sort, sort + numberSort, weight); // Create small problem ClpSimplex small(&model, numberRows, whichRows, numberSort, sort); // now see what variables left out do to row solution double * rowSolution = model.primalRowSolution(); memset (rowSolution, 0, numberRows * sizeof(double)); int iRow, iColumn; // zero out ones in small problem for (iColumn = 0; iColumn < numberSort; iColumn++) { int kColumn = sort[iColumn]; fullSolution[kColumn] = 0.0; } // Get objective offset double offset = 0.0; const double * objective = model.objective(); for (iColumn = 0; iColumn < originalNumberColumns; iColumn++) offset += fullSolution[iColumn] * objective[iColumn]; small.setDblParam(ClpObjOffset, originalOffset - offset); model.times(1.0, fullSolution, rowSolution); double * lower = small.rowLower(); double * upper = small.rowUpper(); for (iRow = 0; iRow < numberRows; iRow++) { if (lower[iRow] > -1.0e50) lower[iRow] -= rowSolution[iRow]; if (upper[iRow] < 1.0e50) upper[iRow] -= rowSolution[iRow]; } /* For some problems a useful variant is to presolve problem. In this case you need to adjust smallNumberColumns to get right size problem. Also you can dispense with creating small problem and fix variables in large problem and do presolve on that. */ // Solve small.primal(); // move solution back const double * solution = small.primalColumnSolution(); for (iColumn = 0; iColumn < numberSort; iColumn++) { int kColumn = sort[iColumn]; model.setColumnStatus(kColumn, small.getColumnStatus(iColumn)); fullSolution[kColumn] = solution[iColumn]; } for (iRow = 0; iRow < numberRows; iRow++) model.setRowStatus(iRow, small.getRowStatus(iRow)); memcpy(model.primalRowSolution(), small.primalRowSolution(), numberRows * sizeof(double)); if ((small.objectiveValue() > lastObjective - 1.0e-7 && iPass > 5) || !small.numberIterations() || iPass == maxPass - 1) { break; // finished } else { lastObjective = small.objectiveValue(); // get reduced cost for large problem // this assumes minimization memcpy(weight, model.objective(), numberColumns * sizeof(double)); model.transposeTimes(-1.0, small.dualRowSolution(), weight); // now massage weight so all basic in plus good djs for (iColumn = 0; iColumn < numberColumns; iColumn++) { double dj = weight[iColumn]; double value = fullSolution[iColumn]; if (model.getColumnStatus(iColumn) == ClpSimplex::basic) dj = -1.0e50; else if (dj < 0.0 && value < columnUpper[iColumn]) dj = dj; else if (dj > 0.0 && value > columnLower[iColumn]) dj = -dj; else if (columnUpper[iColumn] > columnLower[iColumn]) dj = fabs(dj); else dj = 1.0e50; weight[iColumn] = dj; sort[iColumn] = iColumn; } // sort CoinSort_2(weight, weight + numberColumns, sort); numberSort = smallNumberColumns; } } if (addSlacks) { int i; int numberArtificials = numberColumns - originalNumberColumns; for (i = 0; i < numberArtificials; i++) sort[i] = i + originalNumberColumns; model.deleteColumns(numberArtificials, sort); } delete [] weight; delete [] sort; delete [] whichRows; model.primal(1); return 0; }
/* 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; }
// Converts to ordered and takes out duplicates void CglTreeProbingInfo::convert() { if (numberEntries_>=0) { CoinSort_2( fixingEntry_, fixingEntry_+numberEntries_, fixEntry_); assert (!toZero_); toZero_ = new int [numberIntegers_+1]; toOne_ = new int [numberIntegers_]; toZero_[0]=0; int n=0; int put=0; for (int intVariable = 0;intVariable<numberIntegers_;intVariable++) { int last = n; for (;n<numberEntries_;n++) { int value = fixingEntry_[n]; int iVar = value>>1; int way = value &1; if (intVariable!=iVar||way) break; } if (n>last) { // sort assert (sizeof(int)==4); std::sort(reinterpret_cast<unsigned int *> (fixEntry_)+last, reinterpret_cast<unsigned int *> (fixEntry_)+n); CliqueEntry temp2; temp2.fixes=0; setSequenceInCliqueEntry(temp2,numberVariables_+1); for (int i=last;i<n;i++) { if (sequenceInCliqueEntry(temp2)!=sequenceInCliqueEntry(fixEntry_[i])||oneFixesInCliqueEntry(temp2)||oneFixesInCliqueEntry(fixEntry_[i])) { temp2 = fixEntry_[i]; fixEntry_[put++]=temp2; } } } toOne_[intVariable]=put; last = n; for (;n<numberEntries_;n++) { int value = fixingEntry_[n]; int iVar = value>>1; if (intVariable!=iVar) break; } if (n>last) { // sort assert (sizeof(int)==4); std::sort(reinterpret_cast<unsigned int *> (fixEntry_)+last, reinterpret_cast<unsigned int *> (fixEntry_)+n); CliqueEntry temp2; temp2.fixes=0; setSequenceInCliqueEntry(temp2,numberVariables_+1); for (int i=last;i<n;i++) { if (sequenceInCliqueEntry(temp2)!=sequenceInCliqueEntry(fixEntry_[i])||oneFixesInCliqueEntry(temp2)||oneFixesInCliqueEntry(fixEntry_[i])) { temp2 = fixEntry_[i]; fixEntry_[put++]=temp2; } } last=n; } toZero_[intVariable+1]=put; } delete [] fixingEntry_; fixingEntry_ = NULL; numberEntries_ = -2; }
const CoinPresolveAction *implied_free_action::presolve ( CoinPresolveMatrix *prob, const CoinPresolveAction *next, int &fill_level) { # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering implied_free_action::presolve, fill level " << fill_level << "." << std::endl ; # endif presolve_consistent(prob) ; presolve_links_ok(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 const int startEmptyRows = prob->countEmptyRows() ; const int startEmptyColumns = prob->countEmptyCols() ; # if COIN_PRESOLVE_TUNING > 0 double startTime = 0.0 ; if (prob->tuning_) startTime = CoinCpuTime() ; # endif # endif /* Unpack the row- and column-major representations. */ const int m = prob->nrows_ ; const int n = prob->ncols_ ; const CoinBigIndex *rowStarts = prob->mrstrt_ ; int *rowLengths = prob->hinrow_ ; const int *colIndices = prob->hcol_ ; const double *rowCoeffs = prob->rowels_ ; presolvehlink *rlink = prob->rlink_ ; CoinBigIndex *colStarts = prob->mcstrt_ ; int *colLengths = prob->hincol_ ; int *rowIndices = prob->hrow_ ; double *colCoeffs = prob->colels_ ; presolvehlink *clink = prob->clink_ ; /* Column bounds, row bounds, cost, integrality. */ double *clo = prob->clo_ ; double *cup = prob->cup_ ; double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; double *cost = prob->cost_ ; const unsigned char *integerType = prob->integerType_ ; /* Documented as `inhibit x+y+z = 1 mods'. From the code below, it's clear that this is intended to avoid removing SOS equalities with length >= 5 (hardcoded). */ const bool stopSomeStuff = ((prob->presolveOptions()&0x04) != 0) ; /* Ignore infeasibility. `Fix' is overly optimistic. */ const bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ; /* Defaults to 0.0. */ const double feasTol = prob->feasibilityTolerance_ ; # if 0 /* Tentatively moved to be a front-end function for useless_constraint_action, much as make_fixed is a front-end for make_fixed_action. This bit of code left for possible tuning. -- lh, 121127 -- Original comment: This needs to be made faster. */ # ifdef COIN_LIGHTWEIGHT_PRESOLVE if (prob->pass_ == 1) { #else if (prob->presolveOptions_&0x10) { # endif next = testRedundant(prob,next) ; if (prob->status_&0x01 != 0) { if ((prob->presolveOptions_&0x4000) != 0) prob->status_ &= !0x01 ; else return (next) ; } # if 1 //def COIN_LIGHTWEIGHT_PRESOLVE } # endif # endif /* implied_free and subst take a fair bit of effort to scan for candidates. This is a hook to allow a presolve driver to avoid that work. */ if (prob->pass_ > 15 && (prob->presolveOptions_&0x10000) != 0) { fill_level = 2 ; return (next) ; } /* Set up to collect implied_free actions. */ action *actions = new action [n] ; # ifdef ZEROFAULT CoinZeroN(reinterpret_cast<char *>(actions),n*sizeof(action)) ; # endif int nactions = 0 ; int *implied_free = prob->usefulColumnInt_ ; int *whichFree = implied_free+n ; int numberFree = 0 ; /* Arrays to hold row activity (row lhs) min and max values. Each row lhs bound is held as two components: a sum of finite column bounds and a count of infinite column bounds. */ int *infiniteDown = new int[m] ; int *infiniteUp = new int[m] ; double *maxDown = new double[m] ; double *maxUp = new double[m] ; /* Overload infiniteUp with row status codes: -1: L(i)/U(i) not yet computed, -2: do not use (empty or useless row), -3: give up (infeasible) -4: chosen as implied free row */ for (int i = 0 ; i < m ; i++) { if (rowLengths[i] > 1) infiniteUp[i] = -1 ; else infiniteUp[i] = -2 ; } // Get rid of rows with prohibited columns if (prob->anyProhibited_) { for (int i = 0 ; i < m ; i++) { CoinBigIndex rStart = rowStarts[i]; CoinBigIndex rEnd = rStart+rowLengths[i]; bool badRow=false; for (CoinBigIndex j = rStart; j < rEnd; ++j) { if (prob->colProhibited(colIndices[j])) { badRow=true; break; } } if (badRow) infiniteUp[i] = -2 ; } } // Can't go on without a suitable finite infinity, can we? #ifdef USE_SMALL_LARGE const double large = 1.0e10 ; #else const double large = 1.0e20 ; #endif /* Decide which columns we're going to look at. There are columns already queued in colsToDo_, but sometimes we want to look at all of them. Don't suck in prohibited columns. See comments at the head of the routine for fill_level. NOTE the overload on usefulColumnInt_. It was assigned above to whichFree (indices of interesting columns). We'll be ok because columns are consumed out of look at one per main loop iteration, but not all columns are interesting. Original comment: if gone from 2 to 3 look at all */ int numberLook = prob->numberColsToDo_ ; int iLook ; int *look = prob->colsToDo_ ; if (fill_level < 0) { look = prob->usefulColumnInt_+n ; if (!prob->anyProhibited()) { CoinIotaN(look,n,0) ; numberLook = n ; } else { numberLook = 0 ; for (iLook = 0 ; iLook < n ; iLook++) if (!prob->colProhibited(iLook)) look[numberLook++] = iLook ; } } /* Step through the columns of interest looking for suitable x(tgt). Interesting columns are limited by number of nonzeros to minimise fill-in during substitution. */ bool infeas = false ; const int maxLook = abs(fill_level) ; for (iLook = 0 ; iLook < numberLook ; iLook++) { const int tgtcol = look[iLook] ; const int tgtcol_len = colLengths[tgtcol] ; if (tgtcol_len <= 0 || tgtcol_len > maxLook) continue ; /* Set up to reconnoiter the column. The initial value for ait_max is chosen to make sure that anything that satisfies the stability check is big enough to use (though we'd clearly like something better). */ const CoinBigIndex kcs = colStarts[tgtcol] ; const CoinBigIndex kce = kcs+tgtcol_len ; const bool singletonCol = (tgtcol_len == 1) ; bool possibleRow = false ; bool singletonRow = false ; double ait_max = 20*ZTOLDP2 ; /* If this is a singleton column, the only concern is that the row is not a singleton row (that has its own, simpler, transform: slack_doubleton). But make sure we're not dealing with some tiny a(it). Note that there's no point in marking a singleton row. By definition, we won't encounter it again. */ if (singletonCol) { const int i = rowIndices[kcs] ; singletonRow = (rowLengths[i] == 1) ; possibleRow = (fabs(colCoeffs[kcs]) > ZTOLDP2) ; } else { /* If the column is not a singleton, we'll need a numerically stable substitution formula. Check that this is possible. One of the entangled rows must be an equality with a numerically stable coefficient, at least .1*MAX{i}a(it). */ for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) { const int i = rowIndices[kcol] ; if (rowLengths[i] == 1) { singletonRow = true ; break ; } const double abs_ait = fabs(colCoeffs[kcol]) ; ait_max = CoinMax(ait_max,abs_ait) ; if (fabs(rlo[i]-rup[i]) < feasTol && abs_ait > .1*ait_max) { possibleRow = true ; } } } if (singletonRow || !possibleRow) continue ; /* The column has possibilities. Walk the column, calculate row activity bounds L(i) and U(i) for suitable entangled rows, then calculate the improvement (if any) on the column bounds for l(j) and u(j). The goal is to satisfy the implied free condition over all entangled rows and find at least one row suitable for a substitution formula (if the column is not a natural singleton). Suitable: If this is a natural singleton, we need to look at the single entangled constraint. If we're attempting to create a singleton by substitution, only look at equalities with stable coefficients. If x(t) is integral, make sure the scaled rhs will be integral. */ # if PRESOLVE_DEBUG > 2 std::cout << " Checking x(" << tgtcol << "), " << tgtcol_len << " nonzeros" << ", l(" << tgtcol << ") " << clo[tgtcol] << ", u(" << tgtcol << ") " << cup[tgtcol] << ", c(" << tgtcol << ") " << cost[tgtcol] << "." << std::endl ; # endif const double lt = clo[tgtcol] ; const double ut = cup[tgtcol] ; double impliedLow = -COIN_DBL_MAX ; double impliedHigh = COIN_DBL_MAX ; int subst_ndx = -1 ; int subst_len = n ; for (CoinBigIndex kcol = kcs ; kcol < kce ; ++kcol) { const int i = rowIndices[kcol] ; assert(infiniteUp[i] != -3) ; if (infiniteUp[i] <= -2) continue ; const double ait = colCoeffs[kcol] ; const int leni = rowLengths[i] ; const double rloi = rlo[i] ; const double rupi = rup[i] ; /* A suitable row for substitution must * be an equality; * the entangled coefficient must be large enough to be numerically stable; * if x(t) is integer, the constant term in the substitution formula must be integer. */ bool rowiOK = (fabs(rloi-rupi) < feasTol) && (fabs(ait) > .1*ait_max) ; rowiOK = rowiOK && ((integerType[tgtcol] == 0) || (fabs((rloi/ait)-floor((rloi/ait)+0.5)) < feasTol)) ; /* If we don't already have L(i) and U(i), calculate now. Check for useless and infeasible constraints when that's done. */ int infUi = 0 ; int infLi = 0 ; double maxUi = 0.0 ; double maxLi = 0.0 ; const CoinBigIndex krs = rowStarts[i] ; const CoinBigIndex kre = krs+leni ; if (infiniteUp[i] == -1) { for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const double aik = rowCoeffs[krow] ; const int k = colIndices[krow] ; const double lk = clo[k] ; const double uk = cup[k] ; if (aik > 0.0) { if (uk < large) maxUi += uk*aik ; else ++infUi ; if (lk > -large) maxLi += lk*aik ; else ++infLi ; } else if (aik < 0.0) { if (uk < large) maxLi += uk*aik ; else ++infLi ; if (lk > -large) maxUi += lk*aik ; else ++infUi ; } } const double maxUinf = maxUi+infUi*1.0e31 ; const double maxLinf = maxLi-infLi*1.0e31 ; if (maxUinf <= rupi+feasTol && maxLinf >= rloi-feasTol) { infiniteUp[i] = -2 ; } else if (maxUinf < rloi-feasTol && !fixInfeasibility) { prob->status_|= 1 ; infeas = true ; prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS, prob->messages()) << i << rloi << rupi << CoinMessageEol ; infiniteUp[i] = -3 ; } else if (maxLinf > rupi+feasTol && !fixInfeasibility) { prob->status_|= 1 ; infeas = true ; prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS, prob->messages()) << i << rloi << rupi << CoinMessageEol ; infiniteUp[i] = -3 ; } else { infiniteUp[i] = infUi ; infiniteDown[i] = infLi ; maxUp[i] = maxUi ; maxDown[i] = maxLi ; } } else { infUi = infiniteUp[i] ; infLi = infiniteDown[i] ; maxUi = maxUp[i] ; maxLi = maxDown[i] ; } # if PRESOLVE_DEBUG > 2 std::cout << " row(" << i << ") " << leni << " nonzeros, blow " << rloi << ", L (" << infLi << "," << maxLi << "), U (" << infUi << "," << maxUi << "), b " << rupi ; if (infeas) std::cout << " infeas" ; if (infiniteUp[i] == -2) std::cout << " useless" ; std::cout << "." << std::endl ; # endif /* If we're infeasible, no sense checking further; escape the implied bound loop. The other possibility is that we've just discovered the constraint is useless, in which case we just move on to the next one in the column. */ if (infeas) break ; if (infiniteUp[i] == -2) continue ; assert(infiniteUp[i] >= 0 && infiniteUp[i] <= leni) ; /* At this point we have L(i) and U(i), expressed as finite and infinite components, and constraint i is neither useless or infeasible. Calculate the implied bounds l'(t) and u'(t) on x(t). The calculation (for a(it) > 0) is u'(t) <= (b(i) - (L(i)-a(it)l(t)))/a(it) = l(t)+(b(i)-L(i))/a(it) l'(t) >= (blow(i) - (U(i)-a(it)u(t)))/a(it) = u(t)+(blow(i)-U(i))/a(it) Insert the appropriate flips for a(it) < 0. Notice that if there's exactly one infinite contribution to L(i) or U(i) and x(t) is responsible, then the finite portion of L(i) or U(i) is already correct. Cut some slack for possible numerical inaccuracy if the finite portion of L(i) or U(i) is very large. If the new bound is very large, force it to infinity. */ double ltprime = -COIN_DBL_MAX ; double utprime = COIN_DBL_MAX ; if (ait > 0.0) { if (rloi > -large) { if (!infUi) { assert(ut < large) ; ltprime = ut+(rloi-maxUi)/ait ; if (fabs(maxUi) > 1.0e8 && !singletonCol) ltprime -= 1.0e-12*fabs(maxUi) ; } else if (infUi == 1 && ut > large) { ltprime = (rloi-maxUi)/ait ; if (fabs(maxUi) > 1.0e8 && !singletonCol) ltprime -= 1.0e-12*fabs(maxUi) ; } else { ltprime = -COIN_DBL_MAX ; } impliedLow = CoinMax(impliedLow,ltprime) ; } if (rupi < large) { if (!infLi) { assert(lt > -large) ; utprime = lt+(rupi-maxLi)/ait ; if (fabs(maxLi) > 1.0e8 && !singletonCol) utprime += 1.0e-12*fabs(maxLi) ; } else if (infLi == 1 && lt < -large) { utprime = (rupi-maxLi)/ait ; if (fabs(maxLi) > 1.0e8 && !singletonCol) utprime += 1.0e-12*fabs(maxLi) ; } else { utprime = COIN_DBL_MAX ; } impliedHigh = CoinMin(impliedHigh,utprime) ; } } else { if (rloi > -large) { if (!infUi) { assert(lt > -large) ; utprime = lt+(rloi-maxUi)/ait ; if (fabs(maxUi) > 1.0e8 && !singletonCol) utprime += 1.0e-12*fabs(maxUi) ; } else if (infUi == 1 && lt < -large) { utprime = (rloi-maxUi)/ait ; if (fabs(maxUi) > 1.0e8 && !singletonCol) utprime += 1.0e-12*fabs(maxUi) ; } else { utprime = COIN_DBL_MAX ; } impliedHigh = CoinMin(impliedHigh,utprime) ; } if (rupi < large) { if (!infLi) { assert(ut < large) ; ltprime = ut+(rupi-maxLi)/ait ; if (fabs(maxLi) > 1.0e8 && !singletonCol) ltprime -= 1.0e-12*fabs(maxLi) ; } else if (infLi == 1 && ut > large) { ltprime = (rupi-maxLi)/ait ; if (fabs(maxLi) > 1.0e8 && !singletonCol) ltprime -= 1.0e-12*fabs(maxLi) ; } else { ltprime = -COIN_DBL_MAX ; } impliedLow = CoinMax(impliedLow,ltprime) ; } } # if PRESOLVE_DEBUG > 2 std::cout << " row(" << i << ") l'(" << tgtcol << ") " << ltprime << ", u'(" << tgtcol << ") " << utprime ; if (lt <= impliedLow && impliedHigh <= ut) std::cout << "; implied free satisfied" ; std::cout << "." << std::endl ; # endif /* For x(t) integral, see if a substitution formula based on row i will preserve integrality. The final check in this clause aims to preserve SOS equalities (i.e., don't eliminate a non-trivial SOS equality from the system using this transform). Note that this can't be folded into the L(i)/U(i) loop because the answer changes with x(t). Original comment: can only accept if good looking row */ if (integerType[tgtcol]) { possibleRow = true ; bool allOnes = true ; for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const int j = colIndices[krow] ; const double scaled_aij = rowCoeffs[krow]/ait ; if (fabs(scaled_aij) != 1.0) allOnes = false ; if (!integerType[j] || fabs(scaled_aij-floor(scaled_aij+0.5)) > feasTol) { possibleRow = false ; break ; } } if (rloi == 1.0 && leni >= 5 && stopSomeStuff && allOnes) possibleRow = false ; rowiOK = rowiOK && possibleRow ; } /* Do we have a winner? If we have an incumbent, prefer the one with fewer coefficients. */ if (rowiOK) { if (subst_ndx < 0 || (leni < subst_len)) { # if PRESOLVE_DEBUG > 2 std::cout << " row(" << i << ") now candidate for x(" << tgtcol << ")." << std::endl ; # endif subst_ndx = i ; subst_len = leni ; } } } if (infeas) break ; /* Can we do the transform? If so, subst_ndx will have a valid row. Record the implied free variable and the equality we'll use to substitute it out. Take the row out of the running --- we can't use the same row for two substitutions. */ if (lt <= impliedLow && impliedHigh <= ut && (subst_ndx >= 0 || singletonRow)) { implied_free[numberFree] = subst_ndx ; infiniteUp[subst_ndx] = -4 ; whichFree[numberFree++] = tgtcol ; # if PRESOLVE_DEBUG > 1 std::cout << " x(" << tgtcol << ") implied free by row " << subst_ndx << std::endl ; # endif } } delete[] infiniteDown ; delete[] infiniteUp ; delete[] maxDown ; delete[] maxUp ; /* If we're infeasible, there's nothing more to be done. */ if (infeas) { # if PRESOLVE_SUMMARY > 0 || PRESOLVE_DEBUG > 0 std::cout << " IMPLIED_FREE: infeasible." << std::endl ; # endif return (next) ; } /* We have a list of implied free variables, each with a row that can be used to substitute the variable to singleton status if the variable is not a natural singleton. The loop here will only process natural singletons. We'll hand the remainder to subst_constraint_action below, if there is a remainder. The natural singletons processed here are compressed out of whichFree and implied_free. */ int unprocessed = 0 ; for (iLook = 0 ; iLook < numberFree ; iLook++) { const int tgtcol = whichFree[iLook] ; if (colLengths[tgtcol] != 1) { whichFree[unprocessed] = whichFree[iLook] ; implied_free[unprocessed] = implied_free[iLook] ; unprocessed++ ; continue ; } const int tgtrow = implied_free[iLook] ; const int tgtrow_len = rowLengths[tgtrow] ; const CoinBigIndex kcs = colStarts[tgtcol] ; const double tgtcol_coeff = colCoeffs[kcs] ; const double tgtcol_cost = cost[tgtcol] ; const CoinBigIndex krs = rowStarts[tgtrow] ; const CoinBigIndex kre = krs+tgtrow_len ; if (tgtcol_cost != 0.0) { // Check costs don't make unstable //double minOldCost=COIN_DBL_MAX; double maxOldCost=0.0; //double minNewCost=COIN_DBL_MAX; double maxNewCost=0.0; for (CoinBigIndex krow = krs ; krow < kre ; krow++) { const int j = colIndices[krow] ; if (j != tgtcol) { double oldCost = cost[j] ; double newCost = oldCost - (tgtcol_cost*rowCoeffs[krow])/tgtcol_coeff ; oldCost = fabs(oldCost); newCost = fabs(newCost); //minOldCost=CoinMin(minOldCost,oldCost); maxOldCost=CoinMax(maxOldCost,oldCost); //minNewCost=CoinMin(minNewCost,newCost); maxNewCost=CoinMax(maxNewCost,newCost); } } if (maxNewCost>1000.0*(maxOldCost+1.0) && maxOldCost) { //printf("too big %d tgtcost %g maxOld %g maxNew %g\n", // tgtcol,tgtcol_cost,maxOldCost,maxNewCost); continue; } } /* Initialise the postsolve action. We need to remember the row and column. */ action *s = &actions[nactions++] ; s->row = tgtrow ; s->col = tgtcol ; s->clo = clo[tgtcol] ; s->cup = cup[tgtcol] ; s->rlo = rlo[tgtrow] ; s->rup = rup[tgtrow] ; s->ninrow = tgtrow_len ; s->rowels = presolve_dupmajor(rowCoeffs,colIndices,tgtrow_len,krs) ; s->costs = NULL ; /* We're processing a singleton, hence no substitutions in the matrix, but we do need to fix up the cost vector. The substitution formula is x(t) = (rhs(i) - SUM{j\t}a(ik)x(k))/a(it) hence c'(k) = c(k)-c(t)a(ik)/a(it) and there's a constant offset c(t)rhs(i)/a(it). where rhs(i) is one of blow(i) or b(i). For general constraints where blow(i) != b(i), we need to take a bit of care. If only one of blow(i) or b(i) is finite, that's the one to use. Where we have two finite but unequal bounds, choose the bound that will result in the most favourable value for x(t). For minimisation, if c(t) < 0 we want to maximise x(t), so choose b(i) if a(it) > 0, blow(i) if a(it) < 0. A bit of case analysis says choose b(i) when c(t)a(it) < 0, blow(i) when c(t)a(it) > 0. We shouldn't be here if both row bounds are infinite. Fortunately, the objective coefficients are not affected by this. */ if (tgtcol_cost != 0.0) { double tgtrow_rhs = rup[tgtrow] ; if (fabs(rlo[tgtrow]-rup[tgtrow]) > feasTol) { const double rlot = rlo[tgtrow] ; const double rupt = rup[tgtrow] ; if (rlot > -COIN_DBL_MAX && rupt < COIN_DBL_MAX) { if ((tgtcol_cost*tgtcol_coeff) > 0) tgtrow_rhs = rlot ; else tgtrow_rhs = rupt ; } else if (rupt >= COIN_DBL_MAX) { tgtrow_rhs = rlot ; } } assert(fabs(tgtrow_rhs) <= large) ; double *save_costs = new double[tgtrow_len] ; for (CoinBigIndex krow = krs ; krow < kre ; krow++) { const int j = colIndices[krow] ; save_costs[krow-krs] = cost[j] ; cost[j] -= (tgtcol_cost*rowCoeffs[krow])/tgtcol_coeff ; } prob->change_bias((tgtcol_cost*tgtrow_rhs)/tgtcol_coeff) ; cost[tgtcol] = 0.0 ; s->costs = save_costs ; } /* Remove the row from the column-major representation, queuing up each column for reconsideration. Then remove the row from the row-major representation. */ for (CoinBigIndex krow = krs ; krow < kre ; krow++) { const int j = colIndices[krow] ; presolve_delete_from_col(tgtrow,j,colStarts,colLengths,rowIndices, colCoeffs) ; if (colLengths[j] == 0) { PRESOLVE_REMOVE_LINK(prob->clink_,j) ; } else { prob->addCol(j) ; } } PRESOLVE_REMOVE_LINK(clink,tgtcol) ; colLengths[tgtcol] = 0 ; PRESOLVE_REMOVE_LINK(rlink,tgtrow) ; rowLengths[tgtrow] = 0 ; rlo[tgtrow] = 0.0 ; rup[tgtrow] = 0.0 ; } /* We're done with the natural singletons. Trim actions to length and create the postsolve object. */ if (nactions) { # if PRESOLVE_SUMMARY > 0 || PRESOLVE_DEBUG > 0 printf("NIMPLIED FREE: %d\n", nactions) ; # endif action *actions1 = new action[nactions] ; CoinMemcpyN(actions, nactions, actions1) ; next = new implied_free_action(nactions,actions1,next) ; } delete [] actions ; # if PRESOLVE_DEBUG > 0 std::cout << " IMPLIED_FREE: identified " << numberFree << " implied free transforms, processed " << numberFree-unprocessed << " natural singletons." << std::endl ; # endif /* Now take a stab at the columns that aren't natural singletons, if there are any left. */ if (unprocessed != 0) { // if not integer - don't allow much fill if (!prob->anyInteger()) { int numberFree=unprocessed; int nBad=0; unprocessed=0; // Take out ones that make much denser or might lead to instability /* Unpack the row- and column-major representations. */ CoinBigIndex *rowStarts = prob->mrstrt_ ; int *rowLengths = prob->hinrow_ ; double *rowCoeffs = prob->rowels_ ; int *colIndices = prob->hcol_ ; CoinBigIndex *colStarts = prob->mcstrt_ ; int *colLengths = prob->hincol_ ; double *colCoeffs = prob->colels_ ; int *rowIndices = prob->hrow_ ; /* This array is used to hold the indices of columns involved in substitutions, where we have the potential for cancellation. At the end they'll be checked to eliminate any actual zeros that may result. NOTE that usefulColumnInt_ is already in use for parameters implied_free and whichFree when this routine is called from implied_free. */ int *rowsUsed = &prob->usefulRowInt_[0] ; int nRowsUsed = 0 ; /* Open a loop to process the (equality r, implied free variable t) pairs in whichFree and implied_free. It can happen that removal of (row, natural singleton) pairs back in implied_free will reduce the length of column t. It can also happen that previous processing here has resulted in fillin or cancellation. So check again for column length and exclude natural singletons and overly dense columns. */ for (int iLook = 0 ; iLook < numberFree ; iLook++) { const int tgtcol = whichFree[iLook] ; const int tgtrow = implied_free[iLook] ; if (colLengths[tgtcol] < 2 || colLengths[tgtcol] > maxLook) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); length now " << colLengths[tgtcol] << "." << std::endl ; # endif continue ; } CoinBigIndex tgtcs = colStarts[tgtcol] ; CoinBigIndex tgtce = tgtcs+colLengths[tgtcol] ; /* A few checks to make sure that the candidate pair is still suitable. Processing candidates earlier in the list can eliminate coefficients. * Don't use this pair if any involved row i has become a row singleton or empty. * Don't use this pair if any involved row has been modified as part of the processing for a previous candidate pair on this call. * Don't use this pair if a(i,tgtcol) has become zero. The checks on a(i,tgtcol) seem superfluous but it's possible that implied_free identified two candidate pairs to eliminate the same column. If we've already processed one of them, we could be in trouble. */ double tgtcoeff = 0.0 ; bool dealBreaker = false ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const int i = rowIndices[kcol] ; if (rowLengths[i] < 2 || prob->rowUsed(i)) { dealBreaker = true ; break ; } const double aij = colCoeffs[kcol] ; if (fabs(aij) <= ZTOLDP2) { dealBreaker = true ; break ; } if (i == tgtrow) tgtcoeff = aij ; } if (dealBreaker == true) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); deal breaker (1)." << std::endl ; # endif continue ; } /* Check for numerical stability.A large coeff_factor will inflate the coefficients in the substitution formula. */ dealBreaker = false ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const double coeff_factor = fabs(colCoeffs[kcol]/tgtcoeff) ; if (coeff_factor > 10.0) dealBreaker = true ; } if (dealBreaker == true) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); deal breaker (2)." << std::endl ; # endif continue ; } /* Count up the total number of coefficients in entangled rows and mark them as contaminated. */ int ntotels = 0 ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const int i = rowIndices[kcol] ; ntotels += rowLengths[i] ; PRESOLVEASSERT(!prob->rowUsed(i)) ; prob->setRowUsed(i) ; rowsUsed[nRowsUsed++] = i ; } CoinBigIndex tgtrs = rowStarts[tgtrow] ; CoinBigIndex tgtre = tgtrs+rowLengths[tgtrow] ; // kill small if wanted int relax= (prob->presolveOptions()&0x60000)>>17; double tolerance = 1.0e-12; for (int i=0;i<relax;i++) tolerance *= 10.0; /* Sort the target row for efficiency */ CoinSort_2(colIndices+tgtrs,colIndices+tgtre,rowCoeffs+tgtrs) ; CoinBigIndex start=colStarts[tgtcol]; CoinBigIndex end = start+colLengths[tgtcol]; numberBadElements=0; int numberFill=-rowLengths[tgtrow]; for (int colndx = start ; colndx < end ; ++colndx) { int i = rowIndices[colndx] ; if (i == tgtrow) continue ; double ait = colCoeffs[colndx] ; double coeff_factor = -ait/tgtcoeff ; CoinBigIndex krs = rowStarts[i] ; CoinBigIndex kre = krs+rowLengths[i] ; /* Sort the row for efficiency and call add_row to do the actual business of changing coefficients due to substitution. This has the potential to trigger compaction of the row-major bulk store, so update bulk store indices. */ CoinSort_2(colIndices+krs,colIndices+kre,rowCoeffs+krs) ; numberFill += check_row(rowStarts,rowCoeffs,colIndices, rowLengths,coeff_factor,tolerance,i,tgtrow); } if (numberBadElements||3*numberFill>2*(colLengths[tgtcol]+rowLengths[tgtrow])) { //printf("Bad subst col %d row %d - %d small elements, fill %d\n", // tgtcol,tgtrow,numberBadElements,numberFill); if (numberBadElements) nBad++; } else { whichFree[unprocessed]=tgtcol; implied_free[unprocessed++]=tgtrow; //printf("Good subst col %d row %d - fill %d\n", // tgtcol,tgtrow,numberFill); } } /* That's it, we've processed all the candidate pairs. Clear the row used flags. */ for (int i = 0 ; i < nRowsUsed ; i++) prob->unsetRowUsed(rowsUsed[i]) ; #if CLP_USEFUL_PRINTOUT printf("%d allowed through out of %d - %d on coefficient\n", unprocessed,numberFree,nBad); #endif } next = subst_constraint_action::presolve(prob,implied_free,whichFree, unprocessed,next,maxLook) ; } /* Give some feedback to the presolve driver. If we aren't finding enough candidates and haven't reached the limit, bump fill_level and return a negated value. The presolve driver can tweak this value or simply return it on the next call. See the top of the routine for a full explanation. */ if (numberFree < 30 && maxLook < prob->maxSubstLevel_) { fill_level = -(maxLook+1) ; } else { fill_level = maxLook ; } # if COIN_PRESOLVE_TUNING > 0 double thisTime ; if (prob->tuning_) thisTime = CoinCpuTime() ; # endif # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 presolve_consistent(prob) ; presolve_links_ok(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving implied_free_action::presolve, fill level " << fill_level << ", " << droppedRows << " rows, " << droppedColumns << " columns dropped" ; # if COIN_PRESOLVE_TUNING > 0 std::cout << " in " << thisTime-startTime << "s" ; # endif std::cout << "." << std::endl ; # endif return (next) ; }
static int outDupsEtc(int numberIntegers, int & numberCliques, int & numberMatrixCliques, int * & cliqueStart, char * & cliqueType, CliqueEntry *& entry, int numberLastTime, int printit) { bool allNew=false; int * whichP = new int [numberIntegers]; int iClique; assert (sizeof(int)==4); assert (sizeof(CliqueEntry)==4); // If lots then get rid of short ones #define KEEP_CLIQUES 10000 if (numberCliques-numberMatrixCliques>KEEP_CLIQUES) { int * sort = new int [numberCliques]; for (iClique=numberMatrixCliques;iClique<numberCliques;iClique++) { int j = cliqueStart[iClique]; int n = cliqueStart[iClique+1]-j; sort[iClique]=n; } std::sort(sort+numberMatrixCliques,sort+numberCliques); int allow = sort[numberCliques-KEEP_CLIQUES]; int nEqual=0; for (iClique=numberCliques-KEEP_CLIQUES;iClique<numberCliques;iClique++) { if (sort[iClique]>allow) break; else nEqual++; } delete [] sort; int j=cliqueStart[numberMatrixCliques]; int put=j; int nClique=numberMatrixCliques; for (iClique=numberMatrixCliques;iClique<numberCliques;iClique++) { int end = cliqueStart[iClique+1]; int n = end-j; bool copy=false; if (n>allow) { copy=true; } else if (n==allow&&nEqual) { copy=true; nEqual--; } if (copy) { cliqueType[nClique++]=cliqueType[iClique]; for (;j<end;j++) entry[put++]=entry[j]; } j = cliqueStart[iClique+1]; cliqueStart[nClique]=put; } numberCliques = nClique; } // sort for (iClique=0;iClique<numberCliques;iClique++) { int j = cliqueStart[iClique]; int n = cliqueStart[iClique+1]-j; for (int i=0;i<n;i++) whichP[i]=sequenceInCliqueEntry(entry[i+j]); CoinSort_2(whichP,whichP+n,(reinterpret_cast<int *>(entry))+j); } // lexicographic sort int * which = new int [numberCliques]; int * position = new int [numberCliques]; int * sort = new int [numberCliques]; int * value = new int [numberCliques]; for (iClique=0;iClique<numberCliques;iClique++) { which[iClique]=iClique; sort[iClique]=sequenceInCliqueEntry(entry[cliqueStart[iClique]]); value[iClique]=sort[iClique]; position[iClique]=0; } CoinSort_2(sort,sort+numberCliques,which); int lastDone=-1; int nDup=0; int nSave=0; while (lastDone<numberCliques-1) { int jClique=lastDone+1; int jFirst = jClique; int iFirst = which[jFirst]; int iValue = value[iFirst]; int iPos = position[iFirst]; jClique++; for (;jClique<numberCliques;jClique++) { int kClique = which[jClique]; int jValue = value[kClique]; if (jValue>iValue||position[kClique]<iPos) break; } if (jClique==jFirst+1) { // done that bit lastDone++; } else { // use next bit to sort and then repeat int jLast=jClique; for (jClique=jFirst;jClique<jLast;jClique++) { int kClique = which[jClique]; int iValue = value[kClique]; // put at end if finished if (iValue<numberIntegers) { int kPos=position[kClique]+1; position[kClique]=kPos; kPos += cliqueStart[kClique]; if (kPos==cliqueStart[kClique+1]) { iValue = numberIntegers; } else { iValue = sequenceInCliqueEntry(entry[kPos]); } value[kClique]=iValue; } sort[jClique]=iValue; } CoinSort_2(sort+jFirst,sort+jLast,which+jFirst); // if duplicate mark and move on int iLowest=numberCliques; for (jClique=jFirst;jClique<jLast;jClique++) { int kClique = which [jClique]; int iValue = value[kClique]; if (iValue<numberIntegers) break; iLowest = CoinMin(iLowest,kClique); } if (jClique>jFirst) { // mark all apart from lowest number as duplicate and move on lastDone =jClique-1; for (jClique=jFirst;jClique<=lastDone;jClique++) { int kClique = which [jClique]; if (kClique!=iLowest) { value[kClique]=-2; nDup++; nSave += cliqueStart[kClique+1]-cliqueStart[kClique]; } } } } } if (printit) printf("%d duplicates\n",nDup); // Now see if any subset int nOut=0; for (int jClique=0;jClique<numberCliques;jClique++) { if (value[jClique]!=-2) { position[jClique]=cliqueStart[jClique]; value[jClique]=sequenceInCliqueEntry(entry[cliqueStart[jClique]]); } } nSave=0; int startLooking=0; for (int jClique=0;jClique<numberCliques;jClique++) { int kClique = which[jClique]; if (value[kClique]==-2) { nOut++; nSave += cliqueStart[kClique+1]-cliqueStart[kClique]; if (jClique==startLooking) startLooking++; continue; } int kValue =value[kClique]; for (int iiClique=startLooking;iiClique<jClique;iiClique++) { int iClique = which[iiClique]; int iValue = value[iClique]; if (iValue==-2||iValue==numberIntegers) { if (iiClique==startLooking) startLooking++; continue; } else { if (kValue>static_cast<int> (sequenceInCliqueEntry(entry[cliqueStart[iClique+1]-1]))) { value[iClique]=numberIntegers; continue; } } if (iValue<kValue) { while (iValue<kValue) { int iPos=position[iClique]+1; position[iClique]=iPos; if (iPos==cliqueStart[iClique+1]) { iValue = numberIntegers; } else { iValue = sequenceInCliqueEntry(entry[iPos]); } value[iClique]=iValue; } } if (iValue>kValue) continue; // not a candidate // See if subset (remember duplicates have gone) if (cliqueStart[iClique+1]-position[iClique]> cliqueStart[kClique+1]-cliqueStart[kClique]) { // could be subset ? int offset = cliqueStart[iClique]-position[kClique]; int j; bool subset=true; // what about different fixes bool odd=false; for (j=cliqueStart[kClique]+1;j<cliqueStart[kClique+1];j++) { int kColumn = sequenceInCliqueEntry(entry[j]); int iColumn = sequenceInCliqueEntry(entry[j+offset]); if (iColumn>kColumn) { subset=false; } else { while (iColumn<kColumn) { offset++; if (j+offset<cliqueStart[iClique+1]) { iColumn = sequenceInCliqueEntry(entry[j+offset]); } else { subset=false; break; } } } if (!subset) break; } if (subset) { value[kClique]=-2; if (printit>1) printf("clique %d is subset of %d\n",kClique,iClique); nOut++; break; } } } } if (nOut) { if(printit) printf("Can get rid of %d cliques\n",nOut); // make new copy int nNewC=numberCliques-nOut; int size = cliqueStart[numberCliques]-nSave; int n=0; int * start = new int [nNewC+1]; char * type = new char [nNewC]; start[0]=0; CliqueEntry * entryC = new CliqueEntry [size]; int nel=0; allNew = true; for (int jClique=0;jClique<numberCliques;jClique++) { int kClique = which[jClique]; if (value[kClique]!=-2&&kClique<numberMatrixCliques) { if (kClique>=numberLastTime) allNew=false; int nn=cliqueStart[kClique+1]-cliqueStart[kClique]; memcpy(entryC+nel,entry+cliqueStart[kClique],nn*sizeof(CliqueEntry)); nel += nn; type[n++]=cliqueType[kClique]; start[n]=nel; } } int nM=n; for (int jClique=0;jClique<numberCliques;jClique++) { int kClique = which[jClique]; if (value[kClique]!=-2&&kClique>=numberMatrixCliques) { if (kClique>=numberLastTime) allNew=false; int nn=cliqueStart[kClique+1]-cliqueStart[kClique]; memcpy(entryC+nel,entry+cliqueStart[kClique],nn*sizeof(CliqueEntry)); nel += nn; type[n++]=cliqueType[kClique]; start[n]=nel; } } // move numberCliques=n; numberMatrixCliques=nM; delete [] cliqueStart; cliqueStart=start; delete [] entry; entry = entryC; delete [] cliqueType; cliqueType = type; if (printit>1) { for (int jClique=0;jClique<numberCliques;jClique++) { printf("%d [ ",jClique); for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++) printf("%d(%d) ",sequenceInCliqueEntry(entry[i]),oneFixesInCliqueEntry(entry[i])); printf("]\n"); } } if (printit) printf("%d matrix cliques and %d found by probing\n",numberMatrixCliques,numberCliques-numberMatrixCliques); } delete [] value; delete [] sort; delete [] which; delete [] position; delete [] whichP; if (!allNew) return nOut; else return -1; }
void CglClique::find_rcl(OsiCuts& cs) { const int nodenum = fgraph.nodenum; const fnode *nodes = fgraph.nodes; /* A flag for each column that might be used to extend the current row clique */ bool *cand = new bool[nodenum]; /* In cl_indices we'll list the indices of the 'true' entries in cand */ /* The degree of each candidate (those listed in cl_indices) */ int *degrees = new int[nodenum]; /** An array used in the recursive complete enumeration of maximal cliques. The first cl_length entries are used. */ bool* label = new bool[nodenum]; int i, j, k; /* initialize global variables */ cl_del_length = 0; cl_length = 0; int clique_count = 0; int largest_length = 0; /* for each row of the matrix */ for (j = 0; j < sp_numrows; j++) { /* if the row is of zero length, take the next row */ const int len = sp_row_start[j+1] - sp_row_start[j]; if (!len) continue; /* the beginning of the row to be considered */ const int *row = sp_row_ind + sp_row_start[j]; /* copy the row of node_node corresponding to the first column in 'row' into cand, and take the AND of this vector with every row of node_node corresponding to the rest of the columns in 'row' to determine those columns that are non-orthog to every column in row */ std::copy(node_node + row[0]*nodenum, node_node + (row[0]+1)*nodenum, cand); for (i = 1; i < len; i++) { const bool* node_node_col = node_node + row[i] * nodenum; for (k = 0; k < nodenum; k++) cand[k] &= node_node_col[k]; } cl_length = 0; for (k = 0; k < nodenum; k++) if (cand[k]) cl_indices[cl_length++] = k; largest_length = CoinMax(cl_length, largest_length); /* if there is anything in indices, enumerate (or greedily find) maximal cliques */ if (cl_length > 0) { cl_perm_length = len; cl_perm_indices = row; if (cl_length <= rcl_candidate_length_threshold) { for (i = 0; i < cl_length; i++) label[i] = false; int pos = 0; clique_count += enumerate_maximal_cliques(pos, label, cs); } else { /* order cl_indices into decreasing order of their degrees */ for (i = 0; i < cl_length; i++) degrees[i] = nodes[cl_indices[i]].degree; CoinSort_2(degrees, degrees + cl_length, cl_indices, CoinFirstGreater_2<int,int>()); clique_count += greedy_maximal_clique(cs); } } } if (rcl_report_result) { printf("\nrcl Found %i new violated cliques with the row-clique method", clique_count); printf("\nrcl The largest admissible number was %i (threshold %i)\n", largest_length, rcl_candidate_length_threshold); if (largest_length < rcl_candidate_length_threshold) printf("rcl all row cliques have been enumerated\n"); else printf("rcl not all row cliques have been eliminated\n"); } delete[] degrees; delete[] cand; delete[] label; }
OsiSolverInterface * CglTreeProbingInfo::analyze(const OsiSolverInterface & si,int createSolver, int numberExtraCliques,const int * starts, const CliqueEntry * entries,const char * type) { if (!createSolver) return NULL; convert(); if (!numberIntegers_) return NULL; bool alwaysDo=false; if (numberExtraCliques<0) { alwaysDo=true; numberExtraCliques=0; } bool printit=false; int numberCliques=0; int numberEntries=0; int * cliqueStart = NULL; CliqueEntry * entry = NULL; char * cliqueType=NULL; int * whichP = new int [numberIntegers_]; int * whichM = new int [numberIntegers_]; int *whichClique=NULL; int numberRows=si.getNumRows(); int numberMatrixCliques=0; const CoinPackedMatrix * rowCopy = si.getMatrixByRow(); assert(numberRows&&si.getNumCols()); int iRow; const int * column = rowCopy->getIndices(); const double * elementByRow = rowCopy->getElements(); const CoinBigIndex * rowStart = rowCopy->getVectorStarts(); const int * rowLength = rowCopy->getVectorLengths(); const double * lower = si.getColLower(); const double * upper = si.getColUpper(); const double * rowLower = si.getRowLower(); const double * rowUpper = si.getRowUpper(); for (int iPass=0;iPass<2;iPass++) { if (iPass) { int numberExtraEntries=0; if (numberExtraCliques) numberExtraEntries = starts[numberExtraCliques]; cliqueStart = new int [numberCliques+1+numberExtraCliques]; cliqueStart[0]=0; entry = new CliqueEntry [numberEntries+numberExtraEntries]; cliqueType = new char [numberCliques+numberExtraCliques]; whichClique = new int [numberEntries+numberExtraEntries]; numberCliques=0; numberEntries=0; } #if 1 for (iRow=0;iRow<numberRows;iRow++) { int numberP1=0, numberM1=0; int numberTotal=0; CoinBigIndex j; double upperValue=rowUpper[iRow]; double lowerValue=rowLower[iRow]; bool good=true; for (j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) { int iColumn = column[j]; double value = elementByRow[j]; if (upper[iColumn]-lower[iColumn]<1.0e-8) { // fixed upperValue -= lower[iColumn]*value; lowerValue -= lower[iColumn]*value; continue; } else if (backward_[iColumn]<0) { good = false; break; } else { iColumn = backward_[iColumn]; numberTotal++; } if (fabs(value)!=1.0) { good=false; } else if (value>0.0) { assert (numberP1<numberIntegers_); whichP[numberP1++]=iColumn;; } else { assert (numberM1<numberIntegers_); whichM[numberM1++]=iColumn; } } int iUpper = static_cast<int> (floor(upperValue+1.0e-5)); int iLower = static_cast<int> (ceil(lowerValue-1.0e-5)); int state=0; if (upperValue<1.0e6) { if (iUpper==1-numberM1) state=1; else if (iUpper==-numberM1) state=2; else if (iUpper<-numberM1) state=3; if (fabs(static_cast<double> (iUpper)-upperValue)>1.0e-9) state =-1; } if (!state&&lowerValue>-1.0e6) { if (-iLower==1-numberP1) state=-1; else if (-iLower==-numberP1) state=-2; else if (-iLower<-numberP1) state=-3; if (fabs(static_cast<double> (iLower)-lowerValue)>1.0e-9) state =-1; } if (numberP1+numberM1<2) state=-1; if (good&&state>0) { if (abs(state)==3) { // infeasible printf("FFF Infeasible\n");; //feasible=false; break; } else if (abs(state)==2) { // we can fix all //numberFixed += numberP1+numberM1; printf("FFF can fix %d\n",numberP1+numberM1); } else { for (j=0;j<numberP1;j++) { int iColumn = whichP[j]; if (iPass) { CliqueEntry temp; setOneFixesInCliqueEntry(temp,true); setSequenceInCliqueEntry(temp,iColumn); entry[numberEntries]=temp; } numberEntries++; } for (j=0;j<numberM1;j++) { int iColumn = whichM[j]; if (iPass) { CliqueEntry temp; setOneFixesInCliqueEntry(temp,false); setSequenceInCliqueEntry(temp,iColumn); entry[numberEntries]=temp; } numberEntries++; } if (iPass) { if (iLower!=iUpper) { // slack cliqueType[numberCliques]='S'; } else { cliqueType[numberCliques]='E'; } cliqueStart[numberCliques+1]=numberEntries; } numberCliques++; } } } #endif if (numberExtraCliques) { int numberExtraEntries = starts[numberExtraCliques]; memcpy(entry+numberEntries,entries,numberExtraEntries*sizeof(CliqueEntry)); for (int iClique=0;iClique<numberExtraCliques;iClique++) { cliqueType[numberCliques] = type[iClique]; numberCliques++; cliqueStart[numberCliques]=starts[iClique]+numberEntries; } numberEntries += numberExtraEntries; } numberMatrixCliques=numberCliques; //int size = toZero_[numberIntegers_]; //char * used = new char [size]; //memset(used,0,size); // find two cliques int nFix=0; for (int iColumn=0;iColumn<static_cast<int> (numberIntegers_);iColumn++) { int j; for ( j=toZero_[iColumn];j<toOne_[iColumn];j++) { int jColumn=sequenceInCliqueEntry(fixEntry_[j]); // just look at ones beore (this also skips non 0-1) if (jColumn<iColumn) { int k; for ( k=toZero_[jColumn];k<toOne_[jColumn];k++) { if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) { if (oneFixesInCliqueEntry(fixEntry_[j])) { if (oneFixesInCliqueEntry(fixEntry_[k])) { if (printit&&!iPass) printf("%d to zero implies %d to one and %d to zero implies %d to one\n", iColumn,jColumn,jColumn,iColumn); //0-0 illegal if (iPass) { CliqueEntry temp; setOneFixesInCliqueEntry(temp,false); setSequenceInCliqueEntry(temp,iColumn); entry[numberEntries]=temp; } numberEntries++; if (iPass) { CliqueEntry temp; setOneFixesInCliqueEntry(temp,false); setSequenceInCliqueEntry(temp,jColumn); entry[numberEntries]=temp; } numberEntries++; if (iPass) { // slack cliqueType[numberCliques]='S'; cliqueStart[numberCliques+1]=numberEntries; } numberCliques++; } else { if (printit&&!iPass) printf("%d to zero implies %d to one and %d to zero implies %d to zero\n", iColumn,jColumn,jColumn,iColumn); nFix++; // jColumn is 1 } } else { if (oneFixesInCliqueEntry(fixEntry_[k])) { if (printit&&!iPass) printf("%d to zero implies %d to zero and %d to zero implies %d to one\n", iColumn,jColumn,jColumn,iColumn); nFix++; // iColumn is 1 } else { if (printit&&!iPass) printf("%d to zero implies %d to zero and %d to zero implies %d to zero\n", iColumn,jColumn,jColumn,iColumn); nFix++; // jColumn=iColumn } } } } for ( k=toOne_[jColumn];k<toZero_[jColumn+1];k++) { if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) { if (oneFixesInCliqueEntry(fixEntry_[j])) { if (oneFixesInCliqueEntry(fixEntry_[k])) { if (printit&&!iPass) printf("%d to zero implies %d to one and %d to one implies %d to one\n", iColumn,jColumn,jColumn,iColumn); nFix++; //iColumn is 1 } else { if (printit&&!iPass) printf("%d to zero implies %d to one and %d to one implies %d to zero\n", iColumn,jColumn,jColumn,iColumn); nFix++; // iColumn+jcolumn=1 } } else { if (oneFixesInCliqueEntry(fixEntry_[k])) { if (printit&&!iPass) printf("%d to zero implies %d to zero and %d to one implies %d to one\n", iColumn,jColumn,jColumn,iColumn); // 0-1 illegal if (iPass) { CliqueEntry temp; setOneFixesInCliqueEntry(temp,false); setSequenceInCliqueEntry(temp,iColumn); entry[numberEntries]=temp; } numberEntries++; if (iPass) { CliqueEntry temp; setOneFixesInCliqueEntry(temp,true); setSequenceInCliqueEntry(temp,jColumn); entry[numberEntries]=temp; } numberEntries++; if (iPass) { // slack cliqueType[numberCliques]='S'; cliqueStart[numberCliques+1]=numberEntries; } numberCliques++; } else { if (printit&&!iPass) printf("%d to zero implies %d to zero and %d to one implies %d to zero\n", iColumn,jColumn,jColumn,iColumn); nFix++; // jColumn is 0 } } } } } } for ( j=toOne_[iColumn];j<toZero_[iColumn+1];j++) { int jColumn=sequenceInCliqueEntry(fixEntry_[j]); if (jColumn<iColumn) { int k; for ( k=toZero_[jColumn];k<toOne_[jColumn];k++) { if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) { if (oneFixesInCliqueEntry(fixEntry_[j])) { if (oneFixesInCliqueEntry(fixEntry_[k])) { if (printit&&!iPass) printf("%d to one implies %d to one and %d to zero implies %d to one\n", iColumn,jColumn,jColumn,iColumn); nFix++; // jColumn is 1 } else { if (printit&&!iPass) printf("%d to one implies %d to one and %d to zero implies %d to zero\n", iColumn,jColumn,jColumn,iColumn); // 1-0 illegal if (iPass) { CliqueEntry temp; setOneFixesInCliqueEntry(temp,true); setSequenceInCliqueEntry(temp,iColumn); entry[numberEntries]=temp; } numberEntries++; if (iPass) { CliqueEntry temp; setOneFixesInCliqueEntry(temp,false); setSequenceInCliqueEntry(temp,jColumn); entry[numberEntries]=temp; } numberEntries++; if (iPass) { // slack cliqueType[numberCliques]='S'; cliqueStart[numberCliques+1]=numberEntries; } numberCliques++; } } else { if (oneFixesInCliqueEntry(fixEntry_[k])) { if (printit&&!iPass) printf("%d to one implies %d to zero and %d to zero implies %d to one\n", iColumn,jColumn,jColumn,iColumn); nFix++; // iColumn+jColumn=1 } else { if (printit&&!iPass) printf("%d to one implies %d to zero and %d to zero implies %d to zero\n", iColumn,jColumn,jColumn,iColumn); nFix++; // iColumn is 0 } } } } for ( k=toOne_[jColumn];k<toZero_[jColumn+1];k++) { if (sequenceInCliqueEntry(fixEntry_[k])== (iColumn)) { if (oneFixesInCliqueEntry(fixEntry_[j])) { if (oneFixesInCliqueEntry(fixEntry_[k])) { if (printit&&!iPass) printf("%d to one implies %d to one and %d to one implies %d to one\n", iColumn,jColumn,jColumn,iColumn); nFix++; // iColumn == jColumn } else { if (printit&&!iPass) printf("%d to one implies %d to one and %d to one implies %d to zero\n", iColumn,jColumn,jColumn,iColumn); nFix++; // iColumn is 0 } } else { if (oneFixesInCliqueEntry(fixEntry_[k])) { if (printit&&!iPass) printf("%d to one implies %d to zero and %d to one implies %d to one\n", iColumn,jColumn,jColumn,iColumn); nFix++; // jColumn is 0 } else { if (printit&&!iPass) printf("%d to one implies %d to zero and %d to one implies %d to zero\n", iColumn,jColumn,jColumn,iColumn); // 1-1 illegal if (iPass) { CliqueEntry temp; setOneFixesInCliqueEntry(temp,true); setSequenceInCliqueEntry(temp,iColumn); entry[numberEntries]=temp; } numberEntries++; if (iPass) { CliqueEntry temp; setOneFixesInCliqueEntry(temp,true); setSequenceInCliqueEntry(temp,jColumn); entry[numberEntries]=temp; } numberEntries++; if (iPass) { // slack cliqueType[numberCliques]='S'; cliqueStart[numberCliques+1]=numberEntries; } numberCliques++; } } } } } } } if (!iPass) printf("%d cliques and %d fixed (%d already from matrix))\n", numberCliques-numberMatrixCliques,nFix,numberMatrixCliques); } int iClique; outDupsEtc(numberIntegers_, numberCliques, numberMatrixCliques, cliqueStart, cliqueType, entry, -1, printit ? 2 : 1); printf("%d matrix cliques and %d found by probing\n",numberMatrixCliques,numberCliques-numberMatrixCliques); int * zeroStart = new int [numberIntegers_+1]; int * oneStart = new int [numberIntegers_]; int * zeroCount = new int [numberIntegers_]; int * oneCount = new int [numberIntegers_]; char * mark = new char [numberIntegers_]; memset(mark,0,numberIntegers_); int nStrengthen=-1; int iPass=0; while (nStrengthen&&iPass<20) { iPass++; int numberLastTime = numberCliques; int * count = new int [numberCliques]; int i,iColumn; for (i=0;i<numberCliques;i++) { count[i]=0; } int * whichCount = new int [numberCliques]; CoinZeroN(zeroCount,numberIntegers_); CoinZeroN(oneCount,numberIntegers_); for (iClique=0;iClique<numberCliques;iClique++) { for (int j=cliqueStart[iClique];j<cliqueStart[iClique+1];j++) { int iColumn = static_cast<int> (sequenceInCliqueEntry(entry[j])); if (oneFixesInCliqueEntry(entry[j])) { oneCount[iColumn]++; } else { zeroCount[iColumn]++; } } } int j; zeroStart[0]=0; cliqueStart[0]=0; for (j=0;j<numberIntegers_;j++) { int n; n=zeroCount[j]; zeroCount[j]=0; oneStart[j] = zeroStart[j]+n; n=oneCount[j]; oneCount[j]=0; zeroStart[j+1] = oneStart[j]+n; } for (iClique=0;iClique<numberCliques;iClique++) { for (int j=cliqueStart[iClique];j<cliqueStart[iClique+1];j++) { int iColumn = static_cast<int> (sequenceInCliqueEntry(entry[j])); if (oneFixesInCliqueEntry(entry[j])) { int k=oneCount[iColumn]; oneCount[iColumn]++; int put = oneStart[iColumn]+k; whichClique[put]=iClique; } else { int k=zeroCount[iColumn]; zeroCount[iColumn]++; int put = zeroStart[iColumn]+k; whichClique[put]=iClique; } } } nStrengthen=0; int numberEntries=cliqueStart[numberCliques]; int maximumEntries=numberEntries; int maximumCliques=numberCliques; for (iColumn=0;iColumn<numberIntegers_;iColumn++) { int i; int n; int nCount=0; n=0; for (i=zeroStart[iColumn];i<oneStart[iColumn];i++) { int jClique = whichClique[i]; //if (jClique<numberMatrixCliques) //continue; int j = cliqueStart[jClique]; //assert (cliqueStart[jClique+1]==j+2); for (;j<cliqueStart[jClique+1];j++) { CliqueEntry eJ = entry[j]; int jColumn = sequenceInCliqueEntry(eJ); if (jColumn>iColumn&&!mark[jColumn]) { mark[jColumn]=1; whichP[n++]=jColumn; assert (n<numberIntegers_); if (oneFixesInCliqueEntry(eJ)) { for (int k=oneStart[jColumn];k<zeroStart[jColumn+1];k++) { int jClique = whichClique[k]; if (!count[jClique]) whichCount[nCount++]=jClique; count[jClique]++; } } else { for (int k=zeroStart[jColumn];k<oneStart[jColumn];k++) { int jClique = whichClique[k]; if (!count[jClique]) whichCount[nCount++]=jClique; count[jClique]++; } } } } } std::sort(whichP,whichP+n); for (i=0;i<nCount;i++) { int jClique = whichCount[i]; int jCount = count[jClique]; count[jClique]=0; if (jCount==cliqueStart[jClique+1]-cliqueStart[jClique]) { printf("Zero can extend %d [ ",jClique); for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++) printf("%d(%d) ",sequenceInCliqueEntry(entry[i]),oneFixesInCliqueEntry(entry[i])); printf("] by %d(0)\n",iColumn); nStrengthen++; if (numberEntries+jCount+1>maximumEntries) { maximumEntries = CoinMax(numberEntries+jCount+1,(maximumEntries*12)/10+100); CliqueEntry * temp = new CliqueEntry [maximumEntries]; memcpy(temp,entry,numberEntries*sizeof(CliqueEntry)); delete [] entry; entry=temp; int * tempI = new int [maximumEntries]; memcpy(tempI,whichClique,numberEntries*sizeof(int)); delete [] whichClique; whichClique=tempI; } if (numberCliques==maximumCliques) { maximumCliques = (maximumCliques*12)/10+100; int * temp = new int [maximumCliques+1]; memcpy(temp,cliqueStart,(numberCliques+1)*sizeof(int)); delete [] cliqueStart; cliqueStart=temp; char * tempT = new char [maximumCliques]; memcpy(tempT,cliqueType,numberCliques); delete [] cliqueType; cliqueType=tempT; } CliqueEntry eI; eI.fixes=0; setSequenceInCliqueEntry(eI,iColumn); setOneFixesInCliqueEntry(eI,false); entry[numberEntries++]=eI; whichM[0]=iColumn; int n=1; for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++) { entry[numberEntries++]=entry[i]; whichM[n++]=sequenceInCliqueEntry(entry[i]); } CoinSort_2(whichM,whichM+n,(reinterpret_cast<int *>(entry))+numberEntries-n); cliqueType[numberCliques]='S'; numberCliques++; cliqueStart[numberCliques]=numberEntries; } } for (i=0;i<n;i++) mark[whichP[i]]=0; nCount=0; n=0; for (i=oneStart[iColumn];i<zeroStart[iColumn+1];i++) { int jClique = whichClique[i]; //if (jClique<numberMatrixCliques) //continue; int j = cliqueStart[jClique]; //assert (cliqueStart[jClique+1]==j+2); for (;j<cliqueStart[jClique+1];j++) { CliqueEntry eJ = entry[j]; int jColumn = sequenceInCliqueEntry(eJ); if (jColumn>iColumn&&!mark[jColumn]) { mark[jColumn]=1; whichP[n++]=jColumn; assert (n<numberIntegers_); if (oneFixesInCliqueEntry(eJ)) { for (int k=oneStart[jColumn];k<zeroStart[jColumn+1];k++) { int jClique = whichClique[k]; if (!count[jClique]) whichCount[nCount++]=jClique; count[jClique]++; } } else { for (int k=zeroStart[jColumn];k<oneStart[jColumn];k++) { int jClique = whichClique[k]; if (!count[jClique]) whichCount[nCount++]=jClique; count[jClique]++; } } } } } std::sort(whichP,whichP+n); for (i=0;i<nCount;i++) { int jClique = whichCount[i]; int jCount = count[jClique]; count[jClique]=0; if (jCount==cliqueStart[jClique+1]-cliqueStart[jClique]) { #if 1 if (printit) { printf("One can extend %d [ ",jClique); for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++) printf("%d(%d) ",sequenceInCliqueEntry(entry[i]),oneFixesInCliqueEntry(entry[i])); printf("] by %d(1)\n",iColumn); } #endif nStrengthen++; if (numberEntries+jCount+1>maximumEntries) { maximumEntries = CoinMax(numberEntries+jCount+1,(maximumEntries*12)/10+100); CliqueEntry * temp = new CliqueEntry [maximumEntries]; memcpy(temp,entry,numberEntries*sizeof(CliqueEntry)); delete [] entry; entry=temp; int * tempI = new int [maximumEntries]; memcpy(tempI,whichClique,numberEntries*sizeof(int)); delete [] whichClique; whichClique=tempI; } if (numberCliques==maximumCliques) { maximumCliques = (maximumCliques*12)/10+100; int * temp = new int [maximumCliques+1]; memcpy(temp,cliqueStart,(numberCliques+1)*sizeof(int)); delete [] cliqueStart; cliqueStart=temp; char * tempT = new char [maximumCliques]; memcpy(tempT,cliqueType,numberCliques); delete [] cliqueType; cliqueType=tempT; } CliqueEntry eI; eI.fixes=0; setSequenceInCliqueEntry(eI,iColumn); setOneFixesInCliqueEntry(eI,true); entry[numberEntries++]=eI; whichM[0]=iColumn; int n=1; for (int i=cliqueStart[jClique];i<cliqueStart[jClique+1];i++) { entry[numberEntries++]=entry[i]; whichM[n++]=sequenceInCliqueEntry(entry[i]); } CoinSort_2(whichM,whichM+n,(reinterpret_cast<int *>(entry))+numberEntries-n); cliqueType[numberCliques]='S'; numberCliques++; cliqueStart[numberCliques]=numberEntries; } } for (i=0;i<n;i++) mark[whichP[i]]=0; } if (nStrengthen) { int numberDeleted = outDupsEtc(numberIntegers_, numberCliques, numberMatrixCliques, cliqueStart, cliqueType, entry, numberLastTime,printit ? 2 : 1); if (numberDeleted<0||(iPass>1&&numberCliques-numberDeleted>5000)) nStrengthen=0; } delete [] count; delete [] whichCount; } #if 0 if (numberCliques>numberMatrixCliques) { // should keep as cliques and also use in branching ?? double * element = new double [numberIntegers_]; for (iClique=numberMatrixCliques;iClique<numberCliques;iClique++) { int n=0; double rhs=1.0; for (int i=cliqueStart[iClique];i<cliqueStart[iClique+1];i++) { CliqueEntry eI=entry[i]; int iColumn = integerVariable_[sequenceInCliqueEntry(eI)]; whichP[n]=iColumn; if (oneFixesInCliqueEntry(eI)) { element[n++]=1.0; } else { element[n++]=-1.0; rhs -= 1.0; } } stored->addCut(-COIN_DBL_MAX,rhs,n,whichP,element); } delete [] element; } #endif OsiSolverInterface * newSolver=NULL; if (numberCliques>numberMatrixCliques||alwaysDo) { newSolver = si.clone(); // Delete all rows int * start = new int [ CoinMax(numberRows,numberCliques+1)]; int i; for (i=0;i<numberRows;i++) start[i]=i; newSolver->deleteRows(numberRows,start); start[0]=0; int numberElements = cliqueStart[numberCliques]; int * column = new int [numberElements]; double * element = new double [numberElements]; double * lower = new double [numberCliques]; double * upper = new double [numberCliques]; numberElements=0; for (iClique=0;iClique<numberCliques;iClique++) { double rhs=1.0; for (int i=cliqueStart[iClique];i<cliqueStart[iClique+1];i++) { CliqueEntry eI=entry[i]; int iColumn = integerVariable_[sequenceInCliqueEntry(eI)]; column[numberElements]=iColumn; if (oneFixesInCliqueEntry(eI)) { element[numberElements++]=1.0; } else { element[numberElements++]=-1.0; rhs -= 1.0; } } start[iClique+1]=numberElements; assert (cliqueType[iClique]=='S'|| cliqueType[iClique]=='E'); if (cliqueType[iClique]=='S') lower[iClique]=-COIN_DBL_MAX; else lower[iClique] = rhs; upper[iClique]=rhs; } newSolver->addRows(numberCliques,start,column,element,lower,upper); delete [] start; delete [] column; delete [] element; delete [] lower; delete [] upper; } delete [] mark; delete [] whichP; delete [] whichM; delete [] cliqueStart; delete [] entry; delete [] cliqueType; delete [] zeroStart; delete [] oneStart; delete [] zeroCount; delete [] oneCount; delete [] whichClique; return newSolver; }
CbcBranchingObject * CbcGeneralDepth::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int /*way*/) { int numberDo = numberNodes_; if (whichSolution_ >= 0 && (model_->moreSpecialOptions()&33554432)==0) numberDo--; assert (numberDo > 0); // create object CbcGeneralBranchingObject * branch = new CbcGeneralBranchingObject(model_); // skip solution branch->numberSubProblems_ = numberDo; // If parentBranch_ back in then will have to be 2* branch->numberSubLeft_ = numberDo; branch->setNumberBranches(numberDo); CbcSubProblem * sub = new CbcSubProblem[numberDo]; int iProb = 0; branch->subProblems_ = sub; branch->numberRows_ = model_->solver()->getNumRows(); int iNode; //OsiSolverInterface * solver = model_->solver(); OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); assert (clpSolver); ClpSimplex * simplex = clpSolver->getModelPtr(); int numberColumns = simplex->numberColumns(); if ((model_->moreSpecialOptions()&33554432)==0) { double * lowerBefore = CoinCopyOfArray(simplex->getColLower(), numberColumns); double * upperBefore = CoinCopyOfArray(simplex->getColUpper(), numberColumns); ClpNodeStuff * info = nodeInfo_; double * weight = new double[numberNodes_]; int * whichNode = new int [numberNodes_]; // Sort for (iNode = 0; iNode < numberNodes_; iNode++) { if (iNode != whichSolution_) { double objectiveValue = info->nodeInfo_[iNode]->objectiveValue(); double sumInfeasibilities = info->nodeInfo_[iNode]->sumInfeasibilities(); int numberInfeasibilities = info->nodeInfo_[iNode]->numberInfeasibilities(); double thisWeight = 0.0; #if 1 // just closest thisWeight = 1.0e9 * numberInfeasibilities; thisWeight += sumInfeasibilities; thisWeight += 1.0e-7 * objectiveValue; // Try estimate thisWeight = info->nodeInfo_[iNode]->estimatedSolution(); #else thisWeight = 1.0e-3 * numberInfeasibilities; thisWeight += 1.0e-5 * sumInfeasibilities; thisWeight += objectiveValue; #endif whichNode[iProb] = iNode; weight[iProb++] = thisWeight; } } assert (iProb == numberDo); CoinSort_2(weight, weight + numberDo, whichNode); for (iProb = 0; iProb < numberDo; iProb++) { iNode = whichNode[iProb]; ClpNode * node = info->nodeInfo_[iNode]; // move bounds node->applyNode(simplex, 3); // create subproblem sub[iProb] = CbcSubProblem(clpSolver, lowerBefore, upperBefore, node->statusArray(), node->depth()); sub[iProb].objectiveValue_ = node->objectiveValue(); sub[iProb].sumInfeasibilities_ = node->sumInfeasibilities(); sub[iProb].numberInfeasibilities_ = node->numberInfeasibilities(); #ifdef CHECK_PATH if (simplex->numberColumns() == numberColumns_Z) { bool onOptimal = true; const double * columnLower = simplex->columnLower(); const double * columnUpper = simplex->columnUpper(); for (int i = 0; i < numberColumns_Z; i++) { if (iNode == gotGoodNode_Z) printf("good %d %d %g %g\n", iNode, i, columnLower[i], columnUpper[i]); if (columnUpper[i] < debuggerSolution_Z[i] || columnLower[i] > debuggerSolution_Z[i] && simplex->isInteger(i)) { onOptimal = false; break; } } if (onOptimal) { printf("adding to node %x as %d - objs\n", this, iProb); for (int j = 0; j <= iProb; j++) printf("%d %g\n", j, sub[j].objectiveValue_); } } #endif } delete [] weight; delete [] whichNode; const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); // restore bounds for ( int j = 0; j < numberColumns; j++) { if (lowerBefore[j] != lower[j]) solver->setColLower(j, lowerBefore[j]); if (upperBefore[j] != upper[j]) solver->setColUpper(j, upperBefore[j]); } delete [] upperBefore; delete [] lowerBefore; } else { // from diving CbcSubProblem ** nodes = reinterpret_cast<CbcSubProblem **> (model_->temporaryPointer()); assert (nodes); int adjustDepth=info->depth_; assert (numberDo); numberNodes_=0; for (iProb = 0; iProb < numberDo; iProb++) { if ((nodes[iProb]->problemStatus_&2)==0) { // create subproblem (and swap way and/or make inactive) sub[numberNodes_].takeOver(*nodes[iProb],true); // but adjust depth sub[numberNodes_].depth_+=adjustDepth; numberNodes_++; } delete nodes[iProb]; } branch->numberSubProblems_ = numberNodes_; branch->numberSubLeft_ = numberNodes_; branch->setNumberBranches(numberNodes_); if (!numberNodes_) { // infeasible delete branch; branch=NULL; } delete [] nodes; } return branch; }
int main (int argc, const char *argv[]) { ClpSimplex model; int status; int maxFactor = 100; if (argc < 2) { status = model.readMps("../../Data/Netlib/czprob.mps"); if (status) { printf("Unable to read matrix - trying gzipped version\n"); status = model.readMps("../../Data/Netlib/czprob.mps.gz"); } } else { status = model.readMps(argv[1]); } if (status) { printf("errors on input\n"); exit(77); } if (argc > 2) { maxFactor = atoi(argv[2]); printf("max factor %d\n", maxFactor); } if (argc > 3) { printf("Using ClpDynamicMatrix\n"); } else { printf("Using ClpDynamicExampleMatrix\n"); } // find gub int numberRows = model.numberRows(); int * gubStart = new int[numberRows+1]; int * gubEnd = new int[numberRows]; int * which = new int[numberRows]; int * whichGub = new int[numberRows]; int numberColumns = model.numberColumns(); int * mark = new int[numberColumns]; int iRow, iColumn; // delete variables fixed to zero const double * columnLower = model.columnLower(); const double * columnUpper = model.columnUpper(); int numberDelete = 0; for (iColumn = 0; iColumn < numberColumns; iColumn++) { if (columnUpper[iColumn] == 0.0 && columnLower[iColumn] == 0.0) mark[numberDelete++] = iColumn; } if (numberDelete) { model.deleteColumns(numberDelete, mark); numberColumns -= numberDelete; columnLower = model.columnLower(); columnUpper = model.columnUpper(); } double * lower = new double[numberRows]; double * upper = new double[numberRows]; const double * rowLower = model.rowLower(); const double * rowUpper = model.rowUpper(); for (iColumn = 0; iColumn < numberColumns; iColumn++) mark[iColumn] = -1; CoinPackedMatrix * matrix = model.matrix(); // get row copy CoinPackedMatrix rowCopy = *matrix; rowCopy.reverseOrdering(); const int * column = rowCopy.getIndices(); const int * rowLength = rowCopy.getVectorLengths(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); const double * element = rowCopy.getElements(); int putGub = numberRows; int putNonGub = numberRows; int * rowIsGub = new int [numberRows]; for (iRow = numberRows - 1; iRow >= 0; iRow--) { bool gubRow = true; int first = numberColumns + 1; int last = -1; for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) { if (element[j] != 1.0) { gubRow = false; break; } else { int iColumn = column[j]; if (mark[iColumn] >= 0) { gubRow = false; break; } else { last = CoinMax(last, iColumn); first = CoinMin(first, iColumn); } } } if (last - first + 1 != rowLength[iRow] || !gubRow) { which[--putNonGub] = iRow; rowIsGub[iRow] = 0; } else { for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) { int iColumn = column[j]; mark[iColumn] = iRow; } rowIsGub[iRow] = -1; putGub--; gubStart[putGub] = first; gubEnd[putGub] = last + 1; lower[putGub] = rowLower[iRow]; upper[putGub] = rowUpper[iRow]; whichGub[putGub] = iRow; } } int numberNonGub = numberRows - putNonGub; int numberGub = numberRows - putGub; if (numberGub > 0) { printf("** %d gub rows\n", numberGub); int numberNormal = 0; const int * row = matrix->getIndices(); const int * columnLength = matrix->getVectorLengths(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const double * elementByColumn = matrix->getElements(); int numberElements = 0; bool doLower = false; bool doUpper = false; for (iColumn = 0; iColumn < numberColumns; iColumn++) { if (mark[iColumn] < 0) { mark[numberNormal++] = iColumn; } else { numberElements += columnLength[iColumn]; if (columnLower[iColumn] != 0.0) doLower = true; if (columnUpper[iColumn] < 1.0e20) doUpper = true; } } if (!numberNormal) { printf("Putting back one gub row to make non-empty\n"); for (iColumn = gubStart[putGub]; iColumn < gubEnd[putGub]; iColumn++) mark[numberNormal++] = iColumn; putGub++; numberGub--; } ClpSimplex model2(&model, numberNonGub, which + putNonGub, numberNormal, mark); // and copy for restart test ClpSimplex model3 = model2; int numberGubColumns = numberColumns - numberNormal; // sort gubs so monotonic int * which = new int[numberGub]; int i; for (i = 0; i < numberGub; i++) which[i] = i; CoinSort_2(gubStart + putGub, gubStart + putGub + numberGub, which); // move to bottom if we want to use later memmove(gubStart, gubStart + putGub, numberGub * sizeof(int)); int * temp1 = new int [numberGub]; for (i = 0; i < numberGub; i++) { int k = which[i]; temp1[i] = gubEnd[putGub+k]; } memcpy(gubEnd, temp1, numberGub * sizeof(int)); delete [] temp1; double * temp2 = new double [numberGub]; for (i = 0; i < numberGub; i++) { int k = which[i]; temp2[i] = lower[putGub+k]; } memcpy(lower, temp2, numberGub * sizeof(double)); for (i = 0; i < numberGub; i++) { int k = which[i]; temp2[i] = upper[putGub+k]; } memcpy(upper, temp2, numberGub * sizeof(double)); delete [] temp2; delete [] which; numberElements -= numberGubColumns; int * start2 = new int[numberGubColumns+1]; int * row2 = new int[numberElements]; double * element2 = new double[numberElements]; double * cost2 = new double [numberGubColumns]; double * lowerColumn2 = NULL; if (doLower) { lowerColumn2 = new double [numberGubColumns]; CoinFillN(lowerColumn2, numberGubColumns, 0.0); } double * upperColumn2 = NULL; if (doUpper) { upperColumn2 = new double [numberGubColumns]; CoinFillN(upperColumn2, numberGubColumns, COIN_DBL_MAX); } numberElements = 0; int numberNonGubRows = 0; for (iRow = 0; iRow < numberRows; iRow++) { if (!rowIsGub[iRow]) rowIsGub[iRow] = numberNonGubRows++; } numberColumns = 0; int iStart = gubStart[0]; gubStart[0] = 0; start2[0] = 0; const double * cost = model.objective(); for (int iSet = 0; iSet < numberGub; iSet++) { int iEnd = gubEnd[iSet]; for (int k = iStart; k < iEnd; k++) { cost2[numberColumns] = cost[k]; if (columnLower[k]) lowerColumn2[numberColumns] = columnLower[k]; if (columnUpper[k] < 1.0e20) upperColumn2[numberColumns] = columnUpper[k]; for (int j = columnStart[k]; j < columnStart[k] + columnLength[k]; j++) { int iRow = rowIsGub[row[j]]; if (iRow >= 0) { row2[numberElements] = iRow; element2[numberElements++] = elementByColumn[j]; } } start2[++numberColumns] = numberElements; } if (iSet < numberGub - 1) iStart = gubStart[iSet+1]; gubStart[iSet+1] = numberColumns; } printf("** Before adding matrix there are %d rows and %d columns\n", model2.numberRows(), model2.numberColumns()); if (argc > 3) { ClpDynamicMatrix * newMatrix = new ClpDynamicMatrix(&model2, numberGub, numberColumns, gubStart, lower, upper, start2, row2, element2, cost2, lowerColumn2, upperColumn2); model2.replaceMatrix(newMatrix); newMatrix->switchOffCheck(); newMatrix->setRefreshFrequency(1000); } else { ClpDynamicExampleMatrix * newMatrix = new ClpDynamicExampleMatrix(&model2, numberGub, numberColumns, gubStart, lower, upper, start2, row2, element2, cost2, lowerColumn2, upperColumn2); model2.replaceMatrix(newMatrix); newMatrix->switchOffCheck(); newMatrix->setRefreshFrequency(1000); } printf("** While after adding matrix there are %d rows and %d columns\n", model2.numberRows(), model2.numberColumns()); model2.setSpecialOptions(4); // exactly to bound // For now scaling off model2.scaling(0); ClpPrimalColumnSteepest steepest(5); model2.setPrimalColumnPivotAlgorithm(steepest); //model2.messageHandler()->setLogLevel(63); model2.setFactorizationFrequency(maxFactor); model2.setMaximumIterations(4000000); double time1 = CoinCpuTime(); model2.primal(); // can't use values pass model2.primal(0); // test proper restart if (argc > 3) { ClpDynamicMatrix * oldMatrix = dynamic_cast< ClpDynamicMatrix*>(model2.clpMatrix()); assert (oldMatrix); ClpDynamicMatrix * newMatrix = new ClpDynamicMatrix(&model3, numberGub, numberColumns, gubStart, lower, upper, start2, row2, element2, cost2, lowerColumn2, upperColumn2, oldMatrix->gubRowStatus(), oldMatrix->dynamicStatus()); model3.replaceMatrix(newMatrix); // and ordinary status (but only NON gub rows) memcpy(model3.statusArray(), model2.statusArray(), (newMatrix->numberStaticRows() + model3.numberColumns())*sizeof(unsigned char)); newMatrix->switchOffCheck(); newMatrix->setRefreshFrequency(1000); } else { ClpDynamicExampleMatrix * oldMatrix = dynamic_cast< ClpDynamicExampleMatrix*>(model2.clpMatrix()); assert (oldMatrix); ClpDynamicExampleMatrix * newMatrix = new ClpDynamicExampleMatrix(&model3, numberGub, numberColumns, gubStart, lower, upper, start2, row2, element2, cost2, lowerColumn2, upperColumn2, oldMatrix->gubRowStatus(), oldMatrix->dynamicStatus(), oldMatrix->numberGubColumns(), oldMatrix->idGen()); model3.replaceMatrix(newMatrix); // and ordinary status (but only NON gub rows) memcpy(model3.statusArray(), model2.statusArray(), (newMatrix->numberStaticRows() + model3.numberColumns())*sizeof(unsigned char)); newMatrix->switchOffCheck(); newMatrix->setRefreshFrequency(1000); } model3.setSpecialOptions(4); // exactly to bound // For now scaling off model3.scaling(0); model3.setPrimalColumnPivotAlgorithm(steepest); model3.messageHandler()->setLogLevel(63); model3.setFactorizationFrequency(maxFactor); model3.setMaximumIterations(4000000); delete [] rowIsGub; delete [] start2; delete [] row2; delete [] element2; delete [] cost2; delete [] lowerColumn2; delete [] upperColumn2; model3.primal(); // this code expects non gub first in original matrix // and only works at present for ClpDynamicMatrix ClpDynamicMatrix * gubMatrix = dynamic_cast< ClpDynamicMatrix*>(model2.clpMatrix()); assert (gubMatrix); ClpDynamicExampleMatrix * gubMatrix2 = dynamic_cast< ClpDynamicExampleMatrix*>(model2.clpMatrix()); if (!gubMatrix2) { const double * solution = model2.primalColumnSolution(); const double * cost = model.objective(); int numberGubColumns = gubMatrix->numberGubColumns(); int firstOdd = gubMatrix->firstDynamic(); int lastOdd = gubMatrix->firstAvailable(); int numberTotalColumns = firstOdd + numberGubColumns; int originalNumberRows = model.numberRows(); int numberStaticRows = gubMatrix->numberStaticRows(); char * status = new char [numberTotalColumns]; double * gubSolution = new double [numberTotalColumns]; int numberSets = gubMatrix->numberSets(); const int * id = gubMatrix->id(); int i; const float * columnLower = gubMatrix->columnLower(); const float * columnUpper = gubMatrix->columnUpper(); for (i = 0; i < numberGubColumns; i++) { if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atUpperBound) { gubSolution[i+firstOdd] = columnUpper[i]; status[i+firstOdd] = 2; } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atLowerBound && columnLower) { gubSolution[i+firstOdd] = columnLower[i]; status[i+firstOdd] = 1; } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::soloKey) { int iSet = gubMatrix->whichSet(i); gubSolution[i+firstOdd] = gubMatrix->keyValue(iSet); status[i+firstOdd] = 0; } else { gubSolution[i+firstOdd] = 0.0; status[i+firstOdd] = 1; } } for (i = 0; i < firstOdd; i++) { ClpSimplex::Status thisStatus = model2.getStatus(i); if (thisStatus == ClpSimplex::basic) status[i] = 0; else if (thisStatus == ClpSimplex::atLowerBound) status[i] = 1; else if (thisStatus == ClpSimplex::atUpperBound) status[i] = 2; else if (thisStatus == ClpSimplex::isFixed) status[i] = 3; else abort(); gubSolution[i] = solution[i]; } for (i = firstOdd; i < lastOdd; i++) { int iBig = id[i-firstOdd] + firstOdd; ClpSimplex::Status thisStatus = model2.getStatus(i); if (thisStatus == ClpSimplex::basic) status[iBig] = 0; else if (thisStatus == ClpSimplex::atLowerBound) status[iBig] = 1; else if (thisStatus == ClpSimplex::atUpperBound) status[iBig] = 2; else if (thisStatus == ClpSimplex::isFixed) status[iBig] = 3; else abort(); gubSolution[iBig] = solution[i]; } char * rowStatus = new char[originalNumberRows]; for (i = 0; i < numberStaticRows; i++) { ClpSimplex::Status thisStatus = model2.getRowStatus(i); if (thisStatus == ClpSimplex::basic) rowStatus[i] = 0; else if (thisStatus == ClpSimplex::atLowerBound) rowStatus[i] = 1; else if (thisStatus == ClpSimplex::atUpperBound) rowStatus[i] = 2; else if (thisStatus == ClpSimplex::isFixed) rowStatus[i] = 3; else abort(); } double objValue = 0.0; for (i = 0; i < numberTotalColumns; i++) objValue += cost[i] * gubSolution[i]; printf("objective value is %g\n", objValue); for (i = 0; i < numberSets; i++) { ClpSimplex::Status thisStatus = gubMatrix->getStatus(i); if (thisStatus == ClpSimplex::basic) rowStatus[numberStaticRows+i] = 0; else if (thisStatus == ClpSimplex::atLowerBound) rowStatus[numberStaticRows+i] = 1; else if (thisStatus == ClpSimplex::atUpperBound) rowStatus[numberStaticRows+i] = 2; else if (thisStatus == ClpSimplex::isFixed) rowStatus[numberStaticRows+i] = 3; else abort(); } // Coding below may not work if gub rows not at end FILE * fp = fopen ("xx.sol", "w"); fwrite(gubSolution, sizeof(double), numberTotalColumns, fp); fwrite(status, sizeof(char), numberTotalColumns, fp); const double * rowsol = model2.primalRowSolution(); double * rowsol2 = new double[originalNumberRows]; memset(rowsol2, 0, originalNumberRows * sizeof(double)); model.times(1.0, gubSolution, rowsol2); for (i = 0; i < numberStaticRows; i++) assert (fabs(rowsol[i] - rowsol2[i]) < 1.0e-3); for (; i < originalNumberRows; i++) assert (rowsol2[i] > lower[i-numberStaticRows] - 1.0e-3 && rowsol2[i] < upper[i-numberStaticRows] + 1.0e-3); //for (;i<originalNumberRows;i++) //printf("%d %g\n",i,rowsol2[i]); fwrite(rowsol2, sizeof(double), originalNumberRows, fp); delete [] rowsol2; fwrite(rowStatus, sizeof(char), originalNumberRows, fp); fclose(fp); delete [] status; delete [] gubSolution; // ** if going to rstart as dynamic need id_ // also copy coding in useEf.. from ClpGubMatrix (i.e. test for basis) } printf("obj offset is %g\n", model2.objectiveOffset()); printf("Primal took %g seconds\n", CoinCpuTime() - time1); } delete [] mark; delete [] gubStart; delete [] gubEnd; delete [] which; delete [] whichGub; delete [] lower; delete [] upper; return 0; }
int main (int argc, const char *argv[]) { ClpSimplex model; int status; // Keep names if (argc < 2) { status = model.readMps("small.mps", true); } else { status = model.readMps(argv[1], false); } if (status) exit(10); /* This driver implements a method of treating a problem as all cuts. So it adds in all E rows, solves and then adds in violated rows. */ double time1 = CoinCpuTime(); ClpSimplex * model2; ClpPresolve pinfo; int numberPasses = 5; // can change this /* Use a tolerance of 1.0e-8 for feasibility, treat problem as not being integer, do "numberpasses" passes and throw away names in presolved model */ model2 = pinfo.presolvedModel(model, 1.0e-8, false, numberPasses, false); if (!model2) { fprintf(stderr, "ClpPresolve says %s is infeasible with tolerance of %g\n", argv[1], 1.0e-8); fprintf(stdout, "ClpPresolve says %s is infeasible with tolerance of %g\n", argv[1], 1.0e-8); // model was infeasible - maybe try again with looser tolerances model2 = pinfo.presolvedModel(model, 1.0e-7, false, numberPasses, false); if (!model2) { fprintf(stderr, "ClpPresolve says %s is infeasible with tolerance of %g\n", argv[1], 1.0e-7); fprintf(stdout, "ClpPresolve says %s is infeasible with tolerance of %g\n", argv[1], 1.0e-7); exit(2); } } // change factorization frequency from 200 model2->setFactorizationFrequency(100 + model2->numberRows() / 50); int numberColumns = model2->numberColumns(); int originalNumberRows = model2->numberRows(); // We will need arrays to choose rows to add double * weight = new double [originalNumberRows]; int * sort = new int [originalNumberRows]; int numberSort = 0; char * take = new char [originalNumberRows]; const double * rowLower = model2->rowLower(); const double * rowUpper = model2->rowUpper(); int iRow, iColumn; // Set up initial list numberSort = 0; for (iRow = 0; iRow < originalNumberRows; iRow++) { weight[iRow] = 1.123e50; if (rowLower[iRow] == rowUpper[iRow]) { sort[numberSort++] = iRow; weight[iRow] = 0.0; } } numberSort /= 2; // Just add this number of rows each time in small problem int smallNumberRows = 2 * numberColumns; smallNumberRows = CoinMin(smallNumberRows, originalNumberRows / 20); // and pad out with random rows double ratio = ((double)(smallNumberRows - numberSort)) / ((double) originalNumberRows); for (iRow = 0; iRow < originalNumberRows; iRow++) { if (weight[iRow] == 1.123e50 && CoinDrand48() < ratio) sort[numberSort++] = iRow; } /* This is optional. The best thing to do is to miss out random rows and do a set which makes dual feasible. If that is not possible then make sure variables have bounds. One way that normally works is to automatically tighten bounds. */ #if 0 // However for some we need to do anyway double * columnLower = model2->columnLower(); double * columnUpper = model2->columnUpper(); for (iColumn = 0; iColumn < numberColumns; iColumn++) { columnLower[iColumn] = CoinMax(-1.0e6, columnLower[iColumn]); columnUpper[iColumn] = CoinMin(1.0e6, columnUpper[iColumn]); } #endif model2->tightenPrimalBounds(-1.0e4, true); printf("%d rows in initial problem\n", numberSort); double * fullSolution = model2->primalRowSolution(); // Just do this number of passes int maxPass = 50; // And take out slack rows until this pass int takeOutPass = 30; int iPass; const int * start = model2->clpMatrix()->getVectorStarts(); const int * length = model2->clpMatrix()->getVectorLengths(); const int * row = model2->clpMatrix()->getIndices(); int * whichColumns = new int [numberColumns]; for (iColumn = 0; iColumn < numberColumns; iColumn++) whichColumns[iColumn] = iColumn; int numberSmallColumns = numberColumns; for (iPass = 0; iPass < maxPass; iPass++) { printf("Start of pass %d\n", iPass); // Cleaner this way std::sort(sort, sort + numberSort); // Create small problem ClpSimplex small(model2, numberSort, sort, numberSmallColumns, whichColumns); small.setFactorizationFrequency(100 + numberSort / 200); //small.setPerturbation(50); //small.setLogLevel(63); // A variation is to just do N iterations //if (iPass) //small.setMaximumIterations(100); // Solve small.factorization()->messageLevel(8); if (iPass) { small.dual(); } else { small.writeMps("continf.mps"); ClpSolve solveOptions; solveOptions.setSolveType(ClpSolve::useDual); //solveOptions.setSolveType(ClpSolve::usePrimalorSprint); //solveOptions.setSpecialOption(1,2,200); // idiot small.initialSolve(solveOptions); } bool dualInfeasible = (small.status() == 2); // move solution back double * solution = model2->primalColumnSolution(); const double * smallSolution = small.primalColumnSolution(); for (int j = 0; j < numberSmallColumns; j++) { iColumn = whichColumns[j]; solution[iColumn] = smallSolution[j]; model2->setColumnStatus(iColumn, small.getColumnStatus(j)); } for (iRow = 0; iRow < numberSort; iRow++) { int kRow = sort[iRow]; model2->setRowStatus(kRow, small.getRowStatus(iRow)); } // compute full solution memset(fullSolution, 0, originalNumberRows * sizeof(double)); model2->times(1.0, model2->primalColumnSolution(), fullSolution); if (iPass != maxPass - 1) { // Mark row as not looked at for (iRow = 0; iRow < originalNumberRows; iRow++) weight[iRow] = 1.123e50; // Look at rows already in small problem int iSort; int numberDropped = 0; int numberKept = 0; int numberBinding = 0; int numberInfeasibilities = 0; double sumInfeasibilities = 0.0; for (iSort = 0; iSort < numberSort; iSort++) { iRow = sort[iSort]; //printf("%d %g %g\n",iRow,fullSolution[iRow],small.primalRowSolution()[iSort]); if (model2->getRowStatus(iRow) == ClpSimplex::basic) { // Basic - we can get rid of if early on if (iPass < takeOutPass && !dualInfeasible) { // may have hit max iterations so check double infeasibility = CoinMax(fullSolution[iRow] - rowUpper[iRow], rowLower[iRow] - fullSolution[iRow]); weight[iRow] = -infeasibility; if (infeasibility > 1.0e-8) { numberInfeasibilities++; sumInfeasibilities += infeasibility; } else { weight[iRow] = 1.0; numberDropped++; } } else { // keep weight[iRow] = -1.0e40; numberKept++; } } else { // keep weight[iRow] = -1.0e50; numberKept++; numberBinding++; } } // Now rest for (iRow = 0; iRow < originalNumberRows; iRow++) { sort[iRow] = iRow; if (weight[iRow] == 1.123e50) { // not looked at yet double infeasibility = CoinMax(fullSolution[iRow] - rowUpper[iRow], rowLower[iRow] - fullSolution[iRow]); weight[iRow] = -infeasibility; if (infeasibility > 1.0e-8) { numberInfeasibilities++; sumInfeasibilities += infeasibility; } } } // sort CoinSort_2(weight, weight + originalNumberRows, sort); numberSort = CoinMin(originalNumberRows, smallNumberRows + numberKept); memset(take, 0, originalNumberRows); for (iRow = 0; iRow < numberSort; iRow++) take[sort[iRow]] = 1; numberSmallColumns = 0; for (iColumn = 0; iColumn < numberColumns; iColumn++) { int n = 0; for (int j = start[iColumn]; j < start[iColumn] + length[iColumn]; j++) { int iRow = row[j]; if (take[iRow]) n++; } if (n) whichColumns[numberSmallColumns++] = iColumn; } printf("%d rows binding, %d rows kept, %d rows dropped - new size %d rows, %d columns\n", numberBinding, numberKept, numberDropped, numberSort, numberSmallColumns); printf("%d rows are infeasible - sum is %g\n", numberInfeasibilities, sumInfeasibilities); if (!numberInfeasibilities) { printf("Exiting as looks optimal\n"); break; } numberInfeasibilities = 0; sumInfeasibilities = 0.0; for (iSort = 0; iSort < numberSort; iSort++) { if (weight[iSort] > -1.0e30 && weight[iSort] < -1.0e-8) { numberInfeasibilities++; sumInfeasibilities += -weight[iSort]; } } printf("in small model %d rows are infeasible - sum is %g\n", numberInfeasibilities, sumInfeasibilities); } } delete [] weight; delete [] sort; delete [] whichColumns; delete [] take; // If problem is big you may wish to skip this model2->dual(); int numberBinding = 0; for (iRow = 0; iRow < originalNumberRows; iRow++) { if (model2->getRowStatus(iRow) != ClpSimplex::basic) numberBinding++; } printf("%d binding rows at end\n", numberBinding); pinfo.postsolve(true); int numberIterations = model2->numberIterations();; delete model2; /* After this postsolve model should be optimal. We can use checkSolution and test feasibility */ model.checkSolution(); if (model.numberDualInfeasibilities() || model.numberPrimalInfeasibilities()) printf("%g dual %g(%d) Primal %g(%d)\n", model.objectiveValue(), model.sumDualInfeasibilities(), model.numberDualInfeasibilities(), model.sumPrimalInfeasibilities(), model.numberPrimalInfeasibilities()); // But resolve for safety model.primal(1); numberIterations += model.numberIterations();; printf("Solve took %g seconds\n", CoinCpuTime() - time1); return 0; }
void CbcTreeArray::cleanTree(CbcModel * model, double cutoff, double & bestPossibleObjective) { int j; int nNodes = size(); int lastNode = nNodes + 1; CbcNode ** nodeArray = new CbcNode * [lastNode]; int * depth = new int [lastNode]; int k = 0; int kDelete = lastNode; bestPossibleObjective = 1.0e100 ; /* Destructively scan the heap. Nodes to be retained go into the front of nodeArray, nodes to be deleted into the back. Store the depth in a correlated array for nodes to be deleted. */ for (j = 0; j < nNodes; j++) { CbcNode * node = nodes_.front(); nodes_.front()->setOnTree(false); std::pop_heap(nodes_.begin(), nodes_.end(), comparison_); nodes_.pop_back(); double value = node ? node->objectiveValue() : COIN_DBL_MAX; if (node && value >= cutoff) { // double check in case node can change its mind! value = node->checkIsCutoff(cutoff); } if (value >= cutoff || !node->active()) { if (node) { nodeArray[--kDelete] = node; depth[kDelete] = node->depth(); } } else { bestPossibleObjective = CoinMin(bestPossibleObjective, value); nodeArray[k++] = node; } } if (lastNode_) { double value = lastNode_->objectiveValue(); bestPossibleObjective = CoinMin(bestPossibleObjective, value); if (value >= cutoff || !lastNode_->active()) { nodeArray[--kDelete] = lastNode_; depth[kDelete] = lastNode_->depth(); lastNode_ = NULL; } } CbcCompareDefault * compareDefault = dynamic_cast<CbcCompareDefault *> (comparison_.test_); assert (compareDefault); compareDefault->setBestPossible(bestPossibleObjective); compareDefault->setCutoff(cutoff); /* Rebuild the heap using the retained nodes. */ for (j = 0; j < k; j++) { CbcNode * node = nodeArray[j]; node->setOnTree(true); nodes_.push_back(node); std::push_heap(nodes_.begin(), nodes_.end(), comparison_); } /* Sort the list of nodes to be deleted, nondecreasing. */ CoinSort_2(depth + kDelete, depth + lastNode, nodeArray + kDelete); /* Work back from deepest to shallowest. In spite of the name, addCuts1 is just a preparatory step. When it returns, the following will be true: * all cuts are removed from the solver's copy of the constraint system; * lastws will be a basis appropriate for the specified node; * variable bounds will be adjusted to be appropriate for the specified node; * addedCuts_ (returned via addedCuts()) will contain a list of cuts that should be added to the constraint system at this node (but they have not actually been added). Then we scan the cut list for the node. Decrement the reference count for the cut, and if it's gone to 0, really delete it. I don't yet see why the checks for status != basic and addedCuts_[i] != 0 are necessary. When reconstructing a node, these checks are used to skip over loose cuts, excluding them from the reconstituted basis. But here we're just interested in correcting the reference count. Tight/loose should make no difference. Arguably a separate routine should be used in place of addCuts1. It's doing more work than needed, modifying the model to match a subproblem at a node that will be discarded. Then again, we seem to need the basis. */ for (j = lastNode - 1; j >= kDelete; j--) { CbcNode * node = nodeArray[j]; CoinWarmStartBasis *lastws = model->getEmptyBasis() ; model->addCuts1(node, lastws); // Decrement cut counts assert (node); //assert (node->nodeInfo()); int numberLeft = (node->nodeInfo()) ? node->nodeInfo()->numberBranchesLeft() : 0; int i; for (i = 0; i < model->currentNumberCuts(); i++) { // take off node CoinWarmStartBasis::Status status = lastws->getArtifStatus(i + model->numberRowsAtContinuous()); if (status != CoinWarmStartBasis::basic && model->addedCuts()[i]) { if (!model->addedCuts()[i]->decrement(numberLeft)) delete model->addedCuts()[i]; } } // node should not have anything pointing to it if (node->nodeInfo()) node->nodeInfo()->throwAway(); delete node ; delete lastws ; } delete [] nodeArray; delete [] depth; }
/* 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 */ int CbcHeuristicVND::solution(double & solutionValue, double * betterSolution) { numCouldRun_++; int returnCode = 0; const double * bestSolution = model_->bestSolution(); if (!bestSolution) return 0; // No solution found yet #ifdef HEURISTIC_INFORM printf("Entering heuristic %s - nRuns %d numCould %d when %d\n", heuristicName(),numRuns_,numCouldRun_,when_); #endif if (numberSolutions_ < model_->getSolutionCount()) { // new solution - add info numberSolutions_ = model_->getSolutionCount(); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); int i; 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 = bestSolution[iColumn]; if (value < originalLower) { value = originalLower; } else if (value > originalUpper) { value = originalUpper; } } } int numberNodes = model_->getNodeCount(); if (howOften_ == 100) { if (numberNodes < lastNode_ + 12) return 0; // Do at 50 and 100 if ((numberNodes > 40 && numberNodes <= 50) || (numberNodes > 90 && numberNodes < 100)) numberNodes = howOften_; } if ((numberNodes % howOften_) == 0 && (model_->getCurrentPassNumber() <= 1 || model_->getCurrentPassNumber() == 999999)) { lastNode_ = model_->getNodeCount(); OsiSolverInterface * solver = model_->solver(); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); const double * currentSolution = solver->getColSolution(); OsiSolverInterface * newSolver = cloneBut(3); // was model_->continuousSolver()->clone(); //const double * colLower = newSolver->getColLower(); //const double * colUpper = newSolver->getColUpper(); double primalTolerance; solver->getDblParam(OsiPrimalTolerance, primalTolerance); // Sort on distance double * distance = new double [numberIntegers]; int * which = new int [numberIntegers]; int i; int nFix = 0; double tolerance = 10.0 * primalTolerance; 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 valueInt = bestSolution[iColumn]; if (valueInt < originalLower) { valueInt = originalLower; } else if (valueInt > originalUpper) { valueInt = originalUpper; } baseSolution_[iColumn] = currentSolution[iColumn]; distance[i] = fabs(currentSolution[iColumn] - valueInt); which[i] = i; if (fabs(currentSolution[iColumn] - valueInt) < tolerance) nFix++; } CoinSort_2(distance, distance + numberIntegers, which); nDifferent_ = numberIntegers - nFix; stepSize_ = nDifferent_ / 10; k_ = stepSize_; //nFix = numberIntegers-stepSize_; for (i = 0; i < nFix; i++) { int j = which[i]; int iColumn = integerVariable[j]; const OsiObject * object = model_->object(i); // get original bounds double originalLower; double originalUpper; getIntegerInformation( object, originalLower, originalUpper); double valueInt = bestSolution[iColumn]; if (valueInt < originalLower) { valueInt = originalLower; } else if (valueInt > originalUpper) { valueInt = originalUpper; } double nearest = floor(valueInt + 0.5); newSolver->setColLower(iColumn, nearest); newSolver->setColUpper(iColumn, nearest); } delete [] distance; delete [] which; if (nFix > numberIntegers / 5) { //printf("%d integers have samish value\n",nFix); returnCode = smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue, model_->getCutoff(), "CbcHeuristicVND"); if (returnCode < 0) returnCode = 0; // returned on size else numRuns_++; if ((returnCode&1) != 0) numberSuccesses_++; //printf("return code %d",returnCode); if ((returnCode&2) != 0) { // could add cut returnCode &= ~2; //printf("could add cut with %d elements (if all 0-1)\n",nFix); } else { //printf("\n"); } numberTries_++; if ((numberTries_ % 10) == 0 && numberSuccesses_*3 < numberTries_) howOften_ += static_cast<int> (howOften_ * decayFactor_); } delete newSolver; } return returnCode; }
int BonNWayChoose::setupList ( OsiBranchingInformation *info, bool initialize) { assert(initialize); if (initialize) { status_=-2; delete [] goodSolution_; bestObjectIndex_=-1; goodSolution_ = NULL; goodObjectiveValue_ = COIN_DBL_MAX; } numberOnList_=0; numberUnsatisfied_=0; int numberObjects = info->solver_->numberObjects() - start_nway_; double cutoff = info->cutoff_; if(info->depth_ == 0){ bounds_.resize(0); unit_changes_.resize(0); bounds_.resize(numberObjects, std::vector<double>(numberObjects,cutoff)); unit_changes_.resize(numberObjects, std::vector<double>(numberObjects,0)); num_eval_.resize(numberObjects, 0); num_ps_costs_.resize(numberObjects, std::vector<int>(numberObjects,0)); } else { assert(unit_changes_.size() == numberObjects); assert(bounds_.size() == unit_changes_.size()); } //Always allow all objects on the list int maximumStrong = numberObjects; double check = -COIN_DBL_MAX; int checkIndex=0; int bestPriority=COIN_INT_MAX; int putOther = numberObjects; int i; for (i=0;i<numberObjects;i++) { list_[i]=-1; useful_[i]=0.0; } OsiObject ** object = info->solver_->objects(); object += start_nway_; // Say feasible bool feasible = true; for ( i=0;i<numberObjects;i++) { int way; double value = object[i]->infeasibility(info,way); if (value>0.0) { numberUnsatisfied_++; int priorityLevel = object[i]->priority(); // Better priority? Flush choices. if (priorityLevel<bestPriority) { for (int j=maximumStrong-1;j>=0;j--) { if (list_[j]>=0) { int iObject = list_[j]; list_[j]=-1; useful_[j]=0.0; list_[--putOther]=iObject; } } bestPriority = priorityLevel; check=-COIN_DBL_MAX; checkIndex=0; } if (priorityLevel==bestPriority) { // Modify value //Compute usefullness if(info->depth_ != 0){ value = compute_usefulness(i + start_nway_, info); } if (value>check) { //add to list int iObject = list_[checkIndex]; if (iObject>=0) { assert (list_[putOther-1]<0); list_[--putOther]=iObject; // to end } list_[checkIndex]= i + start_nway_; assert (checkIndex<putOther); useful_[checkIndex]=value; // find worst check=COIN_DBL_MAX; maximumStrong = CoinMin(maximumStrong,putOther); for (int j=0;j<maximumStrong;j++) { if (list_[j]>=0) { if (useful_[j]<check) { check=useful_[j]; checkIndex=j; } } else { check=0.0; checkIndex = j; break; } } } else { // to end assert (list_[putOther-1]<0); list_[--putOther]=i + start_nway_; maximumStrong = CoinMin(maximumStrong,putOther); } } else { // worse priority // to end assert (list_[putOther-1]<0); list_[--putOther]=i + start_nway_; maximumStrong = CoinMin(maximumStrong,putOther); } } } // Get list numberOnList_=0; if (feasible) { maximumStrong = CoinMin(maximumStrong,putOther); for (i=0;i<maximumStrong;i++) { if (list_[i]>=0) { list_[numberOnList_]=list_[i]; useful_[numberOnList_++]=-useful_[i]; } } if (numberOnList_) { // Sort CoinSort_2(useful_,useful_+numberOnList_,list_); // move others i = numberOnList_; for (;putOther<numberObjects;putOther++) list_[i++]=list_[putOther]; assert (i==numberUnsatisfied_); if (!numberStrong_) numberOnList_=0; } } else { // not feasible numberUnsatisfied_=-1; } // Get rid of any shadow prices info info->defaultDual_ = -1.0; // switch off delete [] info->usefulRegion_; delete [] info->indexRegion_; return numberUnsatisfied_; }
template <class S, class T> void // This Always uses std::sort CoinSort_2Std(S* sfirst, S* slast, T* tfirst) { CoinSort_2(sfirst, slast, tfirst, CoinFirstLess_2<S,T>()); }
//------------------------------------------------------------------- // Given the model data, a row of the model, and a LP solution, // this function tries to generate a violated lifted simple generalized // flow cover. //------------------------------------------------------------------- bool CglFlowCover::generateOneFlowCut( const OsiSolverInterface & si, const int rowLen, int* ind, double* coef, char sense, double rhs, OsiRowCut& flowCut, double& violation ) const { bool generated = false; const double* xlp = si.getColSolution(); const int numCols = si.getNumCols(); double* up = new double [rowLen]; double* x = new double [rowLen]; double* y = new double [rowLen]; CglFlowColType* sign = new CglFlowColType [rowLen]; int i, j; double value, LB, UB; CglFlowVLB VLB; CglFlowVUB VUB; static int count=0; ++count; CGLFLOW_DEBUG=false; doLift=true; // Get integer types const char * columnType = si.getColType (); for (i = 0; i < rowLen; ++i) { if ( xlp[ind[i]] - floor(xlp[ind[i]]) > EPSILON_ && ceil(xlp[ind[i]]) - xlp[ind[i]] > EPSILON_ ) break; } if (i == rowLen) { delete [] sign; delete [] up; delete [] x; delete [] y; return generated; } //------------------------------------------------------------------------- if (sense == 'G') flipRow(rowLen, coef, rhs); // flips everything, // but the sense if(CGLFLOW_DEBUG) { std::cout << "***************************" << std::endl; std::cout << "Generate Flow cover -- initial constraint, converted to L sense..." << std::endl; std::cout << "Rhs = " << rhs << std::endl; std::cout << "coef [var_index]" << " -- " << "xlp[var_index]" << '\t' << "vub_coef[vub_index] vub_lp_value OR var_index_col_ub" << std::endl; for(int iD = 0; iD < rowLen; ++iD) { VUB = getVubs(ind[iD]); std::cout << std::setw(5) << coef[iD] << "[" << std::setw(5) << ind[iD] << "] -- " << std::setw(20) << xlp[ind[iD]] << '\t'; if (VUB.getVar() != UNDEFINED_) { std::cout << std::setw(20) << VUB.getVal() << "[" << std::setw(5) << VUB.getVar() << "]" << std::setw(20) << xlp[VUB.getVar()] << std::endl; } else std::cout << std::setw(20) << si.getColUpper()[ind[iD]] << " " << std::setw(20) << 1.0 << std::endl; } } //------------------------------------------------------------------------- // Generate conservation inequality and capacity equalities from // the given row. for (i = 0; i < rowLen; ++i) { VLB = getVlbs(ind[i]); LB = ( VLB.getVar() != UNDEFINED_ ) ? VLB.getVal() : si.getColLower()[ind[i]]; VUB = getVubs(ind[i]); UB = ( VUB.getVar() != UNDEFINED_ ) ? VUB.getVal() : si.getColUpper()[ind[i]]; if (LB < -EPSILON_) { // Only consider rows whose variables are all delete [] sign; // non-negative (LB>= 0). delete [] up; delete [] x; delete [] y; return generated; } if ( columnType[ind[i]]==1 ) { // Binary variable value = coef[i]; if (value > EPSILON_) sign[i] = CGLFLOW_COL_BINPOS; else { sign[i] = CGLFLOW_COL_BINNEG; value = -value; } up[i] = value; x[i] = xlp[ind[i]]; y[i] = value * x[i]; } else { value = coef[i]; if (value > EPSILON_) sign[i] = CGLFLOW_COL_CONTPOS; else { sign[i] = CGLFLOW_COL_CONTNEG; value = -value; } up[i] = value* UB; x[i] = (VUB.getVar() != UNDEFINED_) ? xlp[VUB.getVar()] : 1.0; y[i] = value * xlp[ind[i]]; } } //------------------------------------------------------------------------- // Find a initial cover (C+, C-) in (N+, N-) double knapRHS = rhs; double tempSum = 0.0; double tempMin = INFTY_; CglFlowColCut * candidate = new CglFlowColCut [rowLen]; CglFlowColCut * label = new CglFlowColCut [rowLen]; double* ratio = new double [rowLen]; int t = -1; for (i = 0; i < rowLen; ++i) { candidate[i] = label[i] = CGLFLOW_COL_OUTCUT; ratio[i] = INFTY_; switch(sign[i]) { case CGLFLOW_COL_CONTPOS: case CGLFLOW_COL_BINPOS: if( y[i] > EPSILON_ ) { ratio[i] = (1.0 - x[i]) / up[i]; if( y[i] > up[i] * x[i] - EPSILON_ ) { // Violated candidate[i] = CGLFLOW_COL_PRIME; tempSum += up[i]; } else { candidate[i] = CGLFLOW_COL_SECONDARY; } } break; case CGLFLOW_COL_CONTNEG: case CGLFLOW_COL_BINNEG: if( up[i] > ( (1.0 - EPSILON_) * INFTY_ ) ) { // UB is infty label[i] = CGLFLOW_COL_INCUT; } else { knapRHS += up[i]; if( y[i] < up[i] ) { candidate[i] = CGLFLOW_COL_PRIME; ratio[i] = x[i] / up[i]; tempSum += up[i]; } } break; } } double diff, tempD, lambda; int xID = -1; if (knapRHS >1.0e10) { if(CGLFLOW_DEBUG) { std::cout << "knapsack RHS too large. RETURN." << std::endl; } delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; return generated; } while (tempSum < knapRHS + EPSILON_) { // Not a cover yet diff = INFTY_; for (i = 0; i < rowLen; ++i) { if (candidate[i] == CGLFLOW_COL_SECONDARY) { tempD = up[i] * x[i] - y[i]; if (tempD < diff - EPSILON_) { diff = tempD; xID = i; } } } if( diff > (1.0 - EPSILON_) * INFTY_ ) { // NO cover exits. delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; return generated; } else { tempSum += up[xID]; candidate[xID] = CGLFLOW_COL_PRIME; } } // Solve the knapsack problem to get an initial cover tempSum = 0.0; for (i = 0; i < rowLen; ++i) { if (candidate[i] == CGLFLOW_COL_PRIME && ratio[i] < EPSILON_) { //Zero ratio label[i] = CGLFLOW_COL_INCUT; tempSum += up[i]; } } while (tempSum < knapRHS + EPSILON_) { tempMin = INFTY_; xID=-1; for (i = 0; i < rowLen; i++) { // Search the col with minimum ratio if (candidate[i] == CGLFLOW_COL_PRIME && label[i] == 0 && ratio[i] < tempMin) { tempMin = ratio[i]; xID = i; } } if (xID>=0) { label[xID] = CGLFLOW_COL_INCUT; tempSum += up[xID]; } else { if(CGLFLOW_DEBUG) { std::cout << "knapsack RHS too large B. RETURN." << std::endl; } delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; return generated; } } // Reduce to a minimal cover for (i = 0; i < rowLen; ++i) { if (label[i] == CGLFLOW_COL_INCUT && ratio[i] > EPSILON_) { if (tempSum - up[i] > knapRHS + EPSILON_) { label[i] = CGLFLOW_COL_OUTCUT; tempSum -= up[i]; } } } for (i = 0; i < rowLen; ++i) { if (label[i] == CGLFLOW_COL_INCUT && ratio[i] < EPSILON_) { if (tempSum - up[i] > knapRHS + EPSILON_) { label[i] = CGLFLOW_COL_OUTCUT; tempSum -= up[i]; } } } // Due to the way to handle N- for(i = 0; i < rowLen; ++i) { if( sign[i] < 0 ) label[i] = label[i]==CGLFLOW_COL_OUTCUT?CGLFLOW_COL_INCUT:CGLFLOW_COL_OUTCUT; } // No cover, no cut. bool emptyCover = true; for (i = 0; i < rowLen; ++i) { if (label[i] == CGLFLOW_COL_INCUT) { emptyCover = false; break; } } if (emptyCover) { if(CGLFLOW_DEBUG) { std::cout << "No cover. RETURN." << std::endl; } delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; return generated; } lambda = tempSum - knapRHS; if(CGLFLOW_DEBUG) { double sum_mj_Cplus = 0.0; double sum_mj_Cminus= 0.0; // double checkLambda; // variable not used anywhere (LL) // print out the knapsack variables std::cout << "Knapsack Cover: C+" << std::endl; for (i = 0; i < rowLen; ++i) { if ( label[i] == CGLFLOW_COL_INCUT && sign[i] > 0 ) { std::cout << ind[i] << '\t' << up[i] << std::endl; sum_mj_Cplus += up[i]; } } std::cout << "Knapsack Cover: C-" << std::endl; for (i = 0; i < rowLen; ++i) { if ( label[i] == CGLFLOW_COL_INCUT && sign[i] < 0 ) { std::cout << ind[i] << '\t' << up[i] << std::endl; sum_mj_Cminus += up[i]; } } // rlh: verified "lambda" is lambda in the paper. // lambda = (sum coefficients in C+) - (sum of VUB // coefficients in C-) - rhs-orig-constraint std::cout << "lambda = " << lambda << std::endl; } //------------------------------------------------------------------------- // Generate a violated SGFC int numCMinus = 0; int numPlusPlus = 0; double* rho = new double [rowLen]; double* xCoef = new double [rowLen]; double* yCoef = new double [rowLen]; double cutRHS = rhs; double temp = 0.0; double sum = 0.0; double minPlsM = INFTY_; double minNegM = INFTY_; for(i = 0; i < rowLen; ++i) { rho[i] = 0.0; xCoef[i] = 0.0; yCoef[i] = 0.0; } // Project out variables in C- // d^' = d + sum_{i in C^-} m_i. Now cutRHS = d^' for (i = 0; i < rowLen; ++i) { if ( label[i] == CGLFLOW_COL_INCUT && sign[i] < 0 ) { cutRHS += up[i]; ++numCMinus; } } // (1) Compute the coefficients of the simple generalized flow cover // (2) Compute minPlsM, minNegM and sum // // sum = sum_{i in C+\C++} m_i + sum_{i in L--} m_i = m. Page 15. // minPlsM = min_{i in C++} m_i // minNegM = min_{i in L-} m_i temp = cutRHS; for (i = 0; i < rowLen; ++i) { if (label[i] == CGLFLOW_COL_INCUT && sign[i] > 0) { // C+ yCoef[i] = 1.0; if ( up[i] > lambda + EPSILON_ ) { // C++ ++numPlusPlus; xCoef[i] = lambda - up[i]; cutRHS += xCoef[i]; if( up[i] < minPlsM ) { minPlsM = up[i]; } } else { // C+\C++ xCoef[i] = 0.0; // rlh: is this necesarry? (xCoef initialized to zero) sum += up[i]; } } if (label[i] != CGLFLOW_COL_INCUT && sign[i] < 0) { // N-\C- temp += up[i]; if ( up[i] > lambda) { // L- if(CGLFLOW_DEBUG) { std::cout << "Variable " << ind[i] << " is in L-" << std::endl; } yCoef[i] = 0.0; xCoef[i] = -lambda; label[i] = CGLFLOW_COL_INLMIN; if ( up[i] < minNegM ) { minNegM = up[i]; } } else { // L-- if(CGLFLOW_DEBUG) { std::cout << "Variable " << ind[i] << " is in L-- " << std::endl; } yCoef[i] = -1.0; xCoef[i] = 0.0; // rlh: is this necesarry? (xCoef initialized to zero) label[i] = CGLFLOW_COL_INLMINMIN; sum += up[i]; } } } // Sort the upper bounds (m_i) of variables in C++ and L-. int ix; int index = 0; double temp1 = 0.0; double* mt = new double [rowLen]; double* M = new double [rowLen + 1]; // order to look at variables int * order = new int [rowLen]; int nLook=0; for (int i = 0; i < rowLen; ++i) { if ( (label[i] == CGLFLOW_COL_INCUT && sign[i] > 0) || label[i] == CGLFLOW_COL_INLMIN ) { // C+ || L- // possible M[nLook]=-up[i]; order[nLook++]=i; } } CoinSort_2(M,M+nLook,order); int kLook=0; while (kLook<nLook) { ix = UNDEFINED_; i = order[kLook]; kLook++; if ( (label[i] == CGLFLOW_COL_INCUT && sign[i] > 0) || label[i] == CGLFLOW_COL_INLMIN ) { // C+ || L- if ( up[i] > lambda ) { // C++ || L-(up[i] > lambda) ix = i; } } if( ix == UNDEFINED_ ) break; mt[index++] = up[ix]; // Record m_i in C++ and L-(not all) in descending order. if( label[ix] == CGLFLOW_COL_INLMIN ) label[ix] = CGLFLOW_COL_INLMINDONE; else label[ix] = CGLFLOW_COL_INCUTDONE; } //printf("mins %g %g\n",minNegM,minPlsM); if( index == 0 || numPlusPlus == 0) { // No column in C++ and L-(not all). RETURN. if(CGLFLOW_DEBUG) { std::cout << "index = 0. RETURN." << std::endl; } delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; delete [] rho; delete [] xCoef; delete [] yCoef; delete [] mt; delete [] M; delete [] order; return generated; } for ( i = 0; i < rowLen; i++ ) { switch( label[i] ) { case CGLFLOW_COL_INCUTDONE: label[i] = CGLFLOW_COL_INCUT; break; case CGLFLOW_COL_INLMIN: case CGLFLOW_COL_INLMINDONE: case CGLFLOW_COL_INLMINMIN: label[i] = CGLFLOW_COL_OUTCUT; break; case CGLFLOW_COL_INCUT: case CGLFLOW_COL_OUTCUT: case CGLFLOW_COL_PRIME: case CGLFLOW_COL_SECONDARY: break; } } temp1 = temp; /* Get t */ t = 0; for ( i = 0; i < index; ++i ) { if ( mt[i] < minPlsM ) { t = i; break; } } if (i == index) { t = index; } /* Compute M_i */ M[0] = 0.0; for ( i = 1; i <= index; ++i ) { M[i] = M[(i-1)] + mt[(i-1)]; if(CGLFLOW_DEBUG) { std::cout << "t = " << t << std::endl; std::cout << "mt[" << std::setw(5) << (i-1) << "]=" << std::setw(2) << ", M[" << std::setw(5) << i << "]=" << std::setw(20) << M[i] << std::endl; } } // Exit if very big M if (M[index]>1.0e30) { // rlh: should test for huge col UB earler // no sense doing all this work in that case. if(CGLFLOW_DEBUG) { std::cout << "M[index]>1.0e30. RETURN." << std::endl; delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; delete [] rho; delete [] xCoef; delete [] yCoef; delete [] mt; delete [] M; delete [] order; return generated; } } /* Get ml */ double ml = CoinMin(sum, lambda); if(CGLFLOW_DEBUG) { // sum = sum_{i in C+\C++} m_i + sum_{i in L--} m_i = m. Page 15. std::cout << "ml = CoinMin(m, lambda) = CoinMin(" << sum << ", " << lambda << ") =" << ml << std::endl; } /* rho_i = max[0, m_i - (minPlsM - lamda) - ml */ if (t < index ) { /* rho exits only for t <= index-1 */ value = (minPlsM - lambda) + ml; for (i = t; i < index; ++i) { rho[i] = CoinMax(0.0, mt[i] - value); if(CGLFLOW_DEBUG) { std::cout << "rho[" << std::setw(5) << i << "]=" << std::setw(20) << rho[i] << std::endl; } } } // Calculate the violation violation = -cutRHS; for ( i = 0; i < rowLen; ++i ) { #ifdef CGLFLOW_DEBUG2 if(CGLFLOW_DEBUG) { std::cout << "i = " << i << " ind = " << ind[i] << " sign = " << sign[i] << " coef = " << coef[i] << " x = " << x[i] << " xCoef = " << xCoef[i] << " y = " << y[i] << " yCoef = " << yCoef[i] << " up = " << up[i] << " label = " << label[i] << std::endl; } #endif violation += y[i] * yCoef[i] + x[i] * xCoef[i]; } if(CGLFLOW_DEBUG) { std::cout << "violation = " << violation << std::endl; } // double violationBeforeLift=violation; // variable not used anywhere (LL) if(doLift && fabs(violation) > TOLERANCE_ ) { // LIFTING double estY, estX; double movement = 0.0; double dPrimePrime = temp + cutRHS; bool lifted = false; for( i = 0; i < rowLen; ++i ) { if ( (label[i] != CGLFLOW_COL_INCUT) && (sign[i] > 0) ) {/* N+\C+*/ lifted = liftPlus(estY, estX, index, up[i], lambda, y[i], x[i], dPrimePrime, M); xCoef[i] = -estX; yCoef[i] = estY; if(CGLFLOW_DEBUG) { if (lifted) { printf("Success: Lifted col %i (up_i=%f,yCoef[i]=%f,xCoef[i]=%f) in N+\\C+\n", ind[i], up[i], yCoef[i], xCoef[i]); } else { printf("Failed to Lift col %i (m_i=%f) in N+\\C+\n", ind[i], up[i]); } } } if (label[i] == CGLFLOW_COL_INCUT && sign[i] < 0) { /* C- */ liftMinus(movement, t, index, up[i], dPrimePrime, lambda, ml, M, rho); if(movement > EPSILON_) { if(CGLFLOW_DEBUG) { printf("Success: Lifted col %i in C-, movement=%f\n", ind[i], movement); } lifted = true; xCoef[i] = -movement; cutRHS -= movement; } else { if(CGLFLOW_DEBUG) { printf("Failed to Lift col %i in C-, g=%f\n", ind[i], movement); } } } } } //------------------------------------------------------------------- // Calculate the violation violation = -cutRHS; for ( i = 0; i < rowLen; ++i ) { #ifdef CGLFLOW_DEBUG2 if(CGLFLOW_DEBUG) { std::cout << "i = " << i << " ind = " << ind[i] << " sign = " << sign[i] << " coef = " << coef[i] << " x = " << x[i] << " xCoef = " << xCoef[i] << " y = " << y[i] << " yCoef = " << yCoef[i] << " up = " << up[i] << " label = " << label[i] << std::endl; } #endif violation += y[i] * yCoef[i] + x[i] * xCoef[i]; } if(CGLFLOW_DEBUG) { std::cout << "violation = " << violation << std::endl; } int cutLen = 0; char cutSense = 'L'; int* cutInd = 0; double* cutCoef = 0; // If violated, transform the inequality back to original system if ( violation > TOLERANCE_ ) { cutLen = 0; cutSense = 'L'; cutInd = new int [numCols]; cutCoef = new double [numCols]; for ( i = 0; i < rowLen; ++i ) { VUB = getVubs(ind[i]); if ( ( sign[i] == CGLFLOW_COL_CONTPOS ) || ( sign[i] == CGLFLOW_COL_CONTNEG ) ) { if ( fabs( yCoef[i] ) > EPSILON_ ) { if ( sign[i] == CGLFLOW_COL_CONTPOS ) cutCoef[cutLen] = coef[i] * yCoef[i]; else cutCoef[cutLen] = -coef[i] * yCoef[i]; cutInd[cutLen++] = ind[i]; } if ( fabs( xCoef[i] ) > EPSILON_ ) { if ( VUB.getVar() != UNDEFINED_ ) { cutCoef[cutLen] = xCoef[i]; cutInd[cutLen++] = VUB.getVar(); } else cutRHS -= xCoef[i]; } } if ( ( sign[i] == CGLFLOW_COL_BINPOS ) || ( sign[i] == CGLFLOW_COL_BINNEG ) ) { if (fabs(yCoef[i]) > EPSILON_ || fabs(xCoef[i]) > EPSILON_) { if (sign[i] == CGLFLOW_COL_BINPOS) cutCoef[cutLen] = coef[i] * yCoef[i] + xCoef[i]; else cutCoef[cutLen] = -coef[i] * yCoef[i] + xCoef[i]; cutInd[cutLen++] = ind[i]; } } } for ( i = 0; i < cutLen; ++i ) { for ( j = 0; j < i; j++ ) { if ( cutInd[j] == cutInd[i] ) { /* Duplicate*/ cutCoef[j] += cutCoef[i]; cutInd[i] = -1; } } } for ( j = 0, i = 0; i < cutLen; ++i ) { if ( ( cutInd[i] == -1 ) || ( fabs( cutCoef[i]) < EPSILON_ ) ){ /* Small coeff*/ } else { cutCoef[j] = cutCoef[i]; cutInd[j] = cutInd[i]; j++; } } cutLen = j; // Skip if no elements ? - bug somewhere assert (cutLen); // Recheck the violation. violation = 0.0; for (i = 0; i < cutLen; ++i) violation += cutCoef[i] * xlp[cutInd[i]]; violation -= cutRHS; if ( violation > TOLERANCE_ ) { flowCut.setRow(cutLen, cutInd, cutCoef); flowCut.setLb(-1.0 * si.getInfinity()); flowCut.setUb(cutRHS); flowCut.setEffectiveness(violation); generated = true; if(CGLFLOW_DEBUG) { std::cout << "generateOneFlowCover(): Found a cut" << std::endl; } } else { if(CGLFLOW_DEBUG) { std::cout << "generateOneFlowCover(): Lost a cut" << std::endl; } } } //------------------------------------------------------------------------- delete [] sign; delete [] up; delete [] x; delete [] y; delete [] candidate; delete [] label; delete [] ratio; delete [] rho; delete [] xCoef; delete [] yCoef; delete [] mt; delete [] M; delete [] order; delete [] cutInd; delete [] cutCoef; return generated; }
int main(int argc, const char *argv[]) { #if COIN_BIG_INDEX<2 ClpSimplex model; int status; int maxIts = 0; int maxFactor = 100; if (argc < 2) { #if defined(SAMPLEDIR) status = model.readMps(SAMPLEDIR "/p0033.mps", true); #else fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); #endif } else status = model.readMps(argv[1]); if (status) { printf("errors on input\n"); exit(77); } if (argc > 2) { maxFactor = atoi(argv[2]); printf("max factor %d\n", maxFactor); } if (argc > 3) { maxIts = atoi(argv[3]); printf("max its %d\n", maxIts); } // For now scaling off model.scaling(0); if (maxIts) { // Do partial dantzig ClpPrimalColumnSteepest dantzig(5); model.setPrimalColumnPivotAlgorithm(dantzig); //model.messageHandler()->setLogLevel(63); model.setFactorizationFrequency(maxFactor); model.setMaximumIterations(maxIts); model.primal(); if (!model.status()) exit(1); } // find gub int numberRows = model.numberRows(); int * gubStart = new int[numberRows+1]; int * gubEnd = new int[numberRows]; int * which = new int[numberRows]; int * whichGub = new int[numberRows]; int numberColumns = model.numberColumns(); int * mark = new int[numberColumns]; int iRow, iColumn; // delete variables fixed to zero const double * columnLower = model.columnLower(); const double * columnUpper = model.columnUpper(); int numberDelete = 0; for (iColumn = 0; iColumn < numberColumns; iColumn++) { if (columnUpper[iColumn] == 0.0 && columnLower[iColumn] == 0.0) mark[numberDelete++] = iColumn; } if (numberDelete) { model.deleteColumns(numberDelete, mark); numberColumns -= numberDelete; columnLower = model.columnLower(); columnUpper = model.columnUpper(); #if 0 CoinMpsIO writer; writer.setMpsData(*model.matrix(), COIN_DBL_MAX, model.getColLower(), model.getColUpper(), model.getObjCoefficients(), (const char*) 0 /*integrality*/, model.getRowLower(), model.getRowUpper(), NULL, NULL); writer.writeMps("cza.mps", 0, 0, 1); #endif } double * lower = new double[numberRows]; double * upper = new double[numberRows]; const double * rowLower = model.rowLower(); const double * rowUpper = model.rowUpper(); for (iColumn = 0; iColumn < numberColumns; iColumn++) mark[iColumn] = -1; CoinPackedMatrix * matrix = model.matrix(); // get row copy CoinPackedMatrix rowCopy = *matrix; rowCopy.reverseOrdering(); const int * column = rowCopy.getIndices(); const int * rowLength = rowCopy.getVectorLengths(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); const double * element = rowCopy.getElements(); int putGub = numberRows; int putNonGub = numberRows; int * rowIsGub = new int [numberRows]; for (iRow = numberRows - 1; iRow >= 0; iRow--) { bool gubRow = true; int first = numberColumns + 1; int last = -1; for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) { if (element[j] != 1.0) { gubRow = false; break; } else { int iColumn = column[j]; if (mark[iColumn] >= 0) { gubRow = false; break; } else { last = CoinMax(last, iColumn); first = CoinMin(first, iColumn); } } } if (last - first + 1 != rowLength[iRow] || !gubRow) { which[--putNonGub] = iRow; rowIsGub[iRow] = 0; } else { for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) { int iColumn = column[j]; mark[iColumn] = iRow; } rowIsGub[iRow] = -1; putGub--; gubStart[putGub] = first; gubEnd[putGub] = last + 1; lower[putGub] = rowLower[iRow]; upper[putGub] = rowUpper[iRow]; whichGub[putGub] = iRow; } } int numberNonGub = numberRows - putNonGub; int numberGub = numberRows - putGub; if (numberGub > 0) { printf("** %d gub rows\n", numberGub); int numberNormal = 0; const int * row = matrix->getIndices(); const int * columnLength = matrix->getVectorLengths(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const double * elementByColumn = matrix->getElements(); int numberElements = 0; bool doLower = false; bool doUpper = false; for (iColumn = 0; iColumn < numberColumns; iColumn++) { if (mark[iColumn] < 0) { mark[numberNormal++] = iColumn; } else { numberElements += columnLength[iColumn]; if (columnLower[iColumn] != 0.0) doLower = true; if (columnUpper[iColumn] < 1.0e20) doUpper = true; } } if (!numberNormal) { printf("Putting back one gub row to make non-empty\n"); for (iColumn = gubStart[putGub]; iColumn < gubEnd[putGub]; iColumn++) mark[numberNormal++] = iColumn; putGub++; numberGub--; } ClpSimplex model2(&model, numberNonGub, which + putNonGub, numberNormal, mark); int numberGubColumns = numberColumns - numberNormal; // sort gubs so monotonic int * which = new int[numberGub]; int i; for (i = 0; i < numberGub; i++) which[i] = i; CoinSort_2(gubStart + putGub, gubStart + putGub + numberGub, which); int * temp1 = new int [numberGub]; for (i = 0; i < numberGub; i++) { int k = which[i]; temp1[i] = gubEnd[putGub+k]; } memcpy(gubEnd + putGub, temp1, numberGub * sizeof(int)); delete [] temp1; double * temp2 = new double [numberGub]; for (i = 0; i < numberGub; i++) { int k = which[i]; temp2[i] = lower[putGub+k]; } memcpy(lower + putGub, temp2, numberGub * sizeof(double)); for (i = 0; i < numberGub; i++) { int k = which[i]; temp2[i] = upper[putGub+k]; } memcpy(upper + putGub, temp2, numberGub * sizeof(double)); delete [] temp2; delete [] which; numberElements -= numberGubColumns; int * start2 = new int[numberGubColumns+1]; int * row2 = new int[numberElements]; double * element2 = new double[numberElements]; double * cost2 = new double [numberGubColumns]; double * lowerColumn2 = NULL; if (doLower) { lowerColumn2 = new double [numberGubColumns]; CoinFillN(lowerColumn2, numberGubColumns, 0.0); } double * upperColumn2 = NULL; if (doUpper) { upperColumn2 = new double [numberGubColumns]; CoinFillN(upperColumn2, numberGubColumns, COIN_DBL_MAX); } numberElements = 0; int numberNonGubRows = 0; for (iRow = 0; iRow < numberRows; iRow++) { if (!rowIsGub[iRow]) rowIsGub[iRow] = numberNonGubRows++; } numberColumns = 0; gubStart[0] = 0; start2[0] = 0; const double * cost = model.objective(); for (int iSet = 0; iSet < numberGub; iSet++) { int iStart = gubStart[iSet+putGub]; int iEnd = gubEnd[iSet+putGub]; for (int k = iStart; k < iEnd; k++) { cost2[numberColumns] = cost[k]; if (columnLower[k]) lowerColumn2[numberColumns] = columnLower[k]; if (columnUpper[k] < 1.0e20) upperColumn2[numberColumns] = columnUpper[k]; for (int j = columnStart[k]; j < columnStart[k] + columnLength[k]; j++) { int iRow = rowIsGub[row[j]]; if (iRow >= 0) { row2[numberElements] = iRow; element2[numberElements++] = elementByColumn[j]; } } start2[++numberColumns] = numberElements; } gubStart[iSet+1] = numberColumns; } model2.replaceMatrix(new ClpGubDynamicMatrix(&model2, numberGub, numberColumns, gubStart, lower + putGub, upper + putGub, start2, row2, element2, cost2, lowerColumn2, upperColumn2)); delete [] rowIsGub; delete [] start2; delete [] row2; delete [] element2; delete [] cost2; delete [] lowerColumn2; delete [] upperColumn2; // For now scaling off model2.scaling(0); // Do partial dantzig ClpPrimalColumnSteepest dantzig(5); model2.setPrimalColumnPivotAlgorithm(dantzig); //model2.messageHandler()->setLogLevel(63); model2.setFactorizationFrequency(maxFactor); model2.setMaximumIterations(4000000); double time1 = CoinCpuTime(); model2.primal(); { ClpGubDynamicMatrix * gubMatrix = dynamic_cast< ClpGubDynamicMatrix*>(model2.clpMatrix()); assert(gubMatrix); const double * solution = model2.primalColumnSolution(); int numberGubColumns = gubMatrix->numberGubColumns(); int firstOdd = gubMatrix->firstDynamic(); int lastOdd = gubMatrix->firstAvailable(); int numberTotalColumns = firstOdd + numberGubColumns; int numberRows = model2.numberRows(); char * status = new char [numberTotalColumns]; double * gubSolution = new double [numberTotalColumns]; int numberSets = gubMatrix->numberSets(); const int * id = gubMatrix->id(); int i; const double * lowerColumn = gubMatrix->lowerColumn(); const double * upperColumn = gubMatrix->upperColumn(); for (i = 0; i < numberGubColumns; i++) { if (gubMatrix->getDynamicStatus(i) == ClpGubDynamicMatrix::atUpperBound) { gubSolution[i+firstOdd] = upperColumn[i]; status[i+firstOdd] = 2; } else if (gubMatrix->getDynamicStatus(i) == ClpGubDynamicMatrix::atLowerBound && lowerColumn) { gubSolution[i+firstOdd] = lowerColumn[i]; status[i+firstOdd] = 1; } else { gubSolution[i+firstOdd] = 0.0; status[i+firstOdd] = 1; } } for (i = 0; i < firstOdd; i++) { ClpSimplex::Status thisStatus = model2.getStatus(i); if (thisStatus == ClpSimplex::basic) status[i] = 0; else if (thisStatus == ClpSimplex::atLowerBound) status[i] = 1; else if (thisStatus == ClpSimplex::atUpperBound) status[i] = 2; else if (thisStatus == ClpSimplex::isFixed) status[i] = 3; else abort(); gubSolution[i] = solution[i]; } for (i = firstOdd; i < lastOdd; i++) { int iBig = id[i-firstOdd] + firstOdd; ClpSimplex::Status thisStatus = model2.getStatus(i); if (thisStatus == ClpSimplex::basic) status[iBig] = 0; else if (thisStatus == ClpSimplex::atLowerBound) status[iBig] = 1; else if (thisStatus == ClpSimplex::atUpperBound) status[iBig] = 2; else if (thisStatus == ClpSimplex::isFixed) status[iBig] = 3; else abort(); gubSolution[iBig] = solution[i]; } char * rowStatus = new char[numberRows]; for (i = 0; i < numberRows; i++) { ClpSimplex::Status thisStatus = model2.getRowStatus(i); if (thisStatus == ClpSimplex::basic) rowStatus[i] = 0; else if (thisStatus == ClpSimplex::atLowerBound) rowStatus[i] = 1; else if (thisStatus == ClpSimplex::atUpperBound) rowStatus[i] = 2; else if (thisStatus == ClpSimplex::isFixed) rowStatus[i] = 3; else abort(); } char * setStatus = new char[numberSets]; int * keyVariable = new int[numberSets]; memcpy(keyVariable, gubMatrix->keyVariable(), numberSets * sizeof(int)); for (i = 0; i < numberSets; i++) { int iKey = keyVariable[i]; if (iKey > lastOdd) iKey = numberTotalColumns + i; else iKey = id[iKey-firstOdd] + firstOdd; keyVariable[i] = iKey; ClpSimplex::Status thisStatus = gubMatrix->getStatus(i); if (thisStatus == ClpSimplex::basic) setStatus[i] = 0; else if (thisStatus == ClpSimplex::atLowerBound) setStatus[i] = 1; else if (thisStatus == ClpSimplex::atUpperBound) setStatus[i] = 2; else if (thisStatus == ClpSimplex::isFixed) setStatus[i] = 3; else abort(); } FILE * fp = fopen("xx.sol", "w"); fwrite(gubSolution, sizeof(double), numberTotalColumns, fp); fwrite(status, sizeof(char), numberTotalColumns, fp); const double * rowsol = model2.primalRowSolution(); int originalNumberRows = model.numberRows(); double * rowsol2 = new double[originalNumberRows]; memset(rowsol2, 0, originalNumberRows * sizeof(double)); model.times(1.0, gubSolution, rowsol2); for (i = 0; i < numberRows; i++) assert(fabs(rowsol[i] - rowsol2[i]) < 1.0e-3); //for (;i<originalNumberRows;i++) //printf("%d %g\n",i,rowsol2[i]); delete [] rowsol2; fwrite(rowsol, sizeof(double), numberRows, fp); fwrite(rowStatus, sizeof(char), numberRows, fp); fwrite(setStatus, sizeof(char), numberSets, fp); fwrite(keyVariable, sizeof(int), numberSets, fp); fclose(fp); delete [] status; delete [] gubSolution; delete [] setStatus; delete [] keyVariable; // ** if going to rstart as dynamic need id_ // also copy coding in useEf.. from ClpGubMatrix (i.e. test for basis) } printf("obj offset is %g\n", model2.objectiveOffset()); printf("Primal took %g seconds\n", CoinCpuTime() - time1); //model2.primal(1); } delete [] mark; delete [] gubStart; delete [] gubEnd; delete [] which; delete [] whichGub; delete [] lower; delete [] upper; #else printf("testGub2 not available with COIN_BIG_INDEX=2\n"); #endif return 0; }
// This version fixes stuff and does IP int CbcHeuristicLocal::solutionFix(double & objectiveValue, double * newSolution, const int * /*keep*/) { /* If when is set to off (0), or set to root (1) and we're not at the root, return. If this heuristic discovered the current solution, don't continue. */ numCouldRun_++; // See if to do if (!when() || (when() == 1 && model_->phase() != 1)) return 0; // switched off // Don't do if it was this heuristic which found solution! if (this == model_->lastHeuristic()) return 0; /* Load up a new solver with the solution. Why continuousSolver(), as opposed to solver()? */ OsiSolverInterface * newSolver = model_->continuousSolver()->clone(); const double * colLower = newSolver->getColLower(); //const double * colUpper = newSolver->getColUpper(); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); /* The net effect here is that anything that hasn't moved from its lower bound will be fixed at lower bound. See comments in solution() w.r.t. asymmetric treatment of upper and lower bounds. */ int i; int nFix = 0; 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); newSolver->setColLower(iColumn, CoinMax(colLower[iColumn], originalLower)); if (!used_[iColumn]) { newSolver->setColUpper(iColumn, colLower[iColumn]); nFix++; } } /* Try a `small' branch-and-bound search. The notion here is that we've fixed a lot of variables and reduced the amount of `free' problem to a point where a small BaB search will suffice to fully explore the remaining problem. This routine will execute integer presolve, then call branchAndBound to do the actual search. */ int returnCode = 0; #ifdef CLP_INVESTIGATE2 printf("Fixing %d out of %d (%d continuous)\n", nFix, numberIntegers, newSolver->getNumCols() - numberIntegers); #endif if (nFix*10 <= numberIntegers) { // see if we can fix more int * which = new int [2*(numberIntegers-nFix)]; int * sort = which + (numberIntegers - nFix); int n = 0; for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; if (used_[iColumn]) { which[n] = iColumn; sort[n++] = used_[iColumn]; } } CoinSort_2(sort, sort + n, which); // only half fixed in total n = CoinMin(n, numberIntegers / 2 - nFix); int allow = CoinMax(numberSolutions_ - 2, sort[0]); int nFix2 = 0; for (i = 0; i < n; i++) { int iColumn = integerVariable[i]; if (used_[iColumn] <= allow) { newSolver->setColUpper(iColumn, colLower[iColumn]); nFix2++; } else { break; } } delete [] which; nFix += nFix2; #ifdef CLP_INVESTIGATE2 printf("Number fixed increased from %d to %d\n", nFix - nFix2, nFix); #endif } if (nFix*10 > numberIntegers) { returnCode = smallBranchAndBound(newSolver, numberNodes_, newSolution, objectiveValue, objectiveValue, "CbcHeuristicLocal"); /* -2 is return due to user event, and -1 is overloaded with what look to be two contradictory meanings. */ if (returnCode < 0) { returnCode = 0; // returned on size int numberColumns = newSolver->getNumCols(); int numberContinuous = numberColumns - numberIntegers; if (numberContinuous > 2*numberIntegers && nFix*10 < numberColumns) { #define LOCAL_FIX_CONTINUOUS #ifdef LOCAL_FIX_CONTINUOUS //const double * colUpper = newSolver->getColUpper(); const double * colLower = newSolver->getColLower(); int nAtLb = 0; //double sumDj=0.0; const double * dj = newSolver->getReducedCost(); double direction = newSolver->getObjSense(); for (int iColumn = 0; iColumn < numberColumns; iColumn++) { if (!newSolver->isInteger(iColumn)) { if (!used_[iColumn]) { //double djValue = dj[iColumn]*direction; nAtLb++; //sumDj += djValue; } } } if (nAtLb) { // fix some continuous double * sort = new double[nAtLb]; int * which = new int [nAtLb]; //double threshold = CoinMax((0.01*sumDj)/static_cast<double>(nAtLb),1.0e-6); int nFix2 = 0; for (int iColumn = 0; iColumn < numberColumns; iColumn++) { if (!newSolver->isInteger(iColumn)) { if (!used_[iColumn]) { double djValue = dj[iColumn] * direction; if (djValue > 1.0e-6) { sort[nFix2] = -djValue; which[nFix2++] = iColumn; } } } } CoinSort_2(sort, sort + nFix2, which); int divisor = 2; nFix2 = CoinMin(nFix2, (numberColumns - nFix) / divisor); for (int i = 0; i < nFix2; i++) { int iColumn = which[i]; newSolver->setColUpper(iColumn, colLower[iColumn]); } delete [] sort; delete [] which; #ifdef CLP_INVESTIGATE2 printf("%d integers have zero value, and %d continuous fixed at lb\n", nFix, nFix2); #endif returnCode = smallBranchAndBound(newSolver, numberNodes_, newSolution, objectiveValue, objectiveValue, "CbcHeuristicLocal"); if (returnCode < 0) returnCode = 0; // returned on size } #endif } } } /* If the result is complete exploration with a solution (3) or proven infeasibility (2), we could generate a cut (the AI folks would call it a nogood) to prevent us from going down this route in the future. */ if ((returnCode&2) != 0) { // could add cut returnCode &= ~2; } delete newSolver; return returnCode; }