bool DcModel::solveWithoutCuts (OsiCuts & cuts, int numberTries, DcTreeNode * node, int & numberOldActiveCuts, int & numberNewCuts, int & maximumWhich, int *& whichGenerator, const bool cutDuringRampup, int & found ) { found = -10; bool feasible; feasible = resolve(); if(!feasible) { return false; // If lost feasibility, bail out right now } // check integer feasibility of solution found = -1; // If found a solution, Record it before we free the vector int numberIntegerInfeasibilities = 0; bool integerFeasible = feasibleSolution(numberIntegerInfeasibilities); bool better; double currentObjValue = getCurrentObjValue(); double cutoff = getCutoff(); if (integerFeasible) { if (currentObjValue < cutoff) { better = setBestSolution(DC_BRANCH, currentObjValue, currentSolution()); } } reducedCostFix(); double minimumDrop = minimumDrop_; if (numberTries < 0) { numberTries = -numberTries; minimumDrop = -1.0; } incrementNodeCount(); return feasible; }
// inner part of dive int CbcHeuristicDive::solution(double & solutionValue, int & numberNodes, int & numberCuts, OsiRowCut ** cuts, CbcSubProblem ** & nodes, double * newSolution) { #ifdef DIVE_DEBUG int nRoundInfeasible = 0; int nRoundFeasible = 0; #endif int reasonToStop = 0; double time1 = CoinCpuTime(); int numberSimplexIterations = 0; int maxSimplexIterations = (model_->getNodeCount()) ? maxSimplexIterations_ : maxSimplexIterationsAtRoot_; // but can't be exactly coin_int_max maxSimplexIterations = CoinMin(maxSimplexIterations,COIN_INT_MAX>>3); OsiSolverInterface * solver = cloneBut(6); // was model_->solver()->clone(); # ifdef COIN_HAS_CLP OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); if (clpSolver) { ClpSimplex * clpSimplex = clpSolver->getModelPtr(); int oneSolveIts = clpSimplex->maximumIterations(); oneSolveIts = CoinMin(1000+2*(clpSimplex->numberRows()+clpSimplex->numberColumns()),oneSolveIts); clpSimplex->setMaximumIterations(oneSolveIts); if (!nodes) { // say give up easily clpSimplex->setMoreSpecialOptions(clpSimplex->moreSpecialOptions() | 64); } else { // get ray int specialOptions = clpSimplex->specialOptions(); specialOptions &= ~0x3100000; specialOptions |= 32; clpSimplex->setSpecialOptions(specialOptions); clpSolver->setSpecialOptions(clpSolver->specialOptions() | 1048576); if ((model_->moreSpecialOptions()&16777216)!=0) { // cutoff is constraint clpSolver->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX); } } } # endif const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); const double * rowLower = solver->getRowLower(); const double * rowUpper = solver->getRowUpper(); const double * solution = solver->getColSolution(); const double * objective = solver->getObjCoefficients(); double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance); double primalTolerance; solver->getDblParam(OsiPrimalTolerance, primalTolerance); int numberRows = matrix_.getNumRows(); assert (numberRows <= solver->getNumRows()); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); double direction = solver->getObjSense(); // 1 for min, -1 for max double newSolutionValue = direction * solver->getObjValue(); int returnCode = 0; // Column copy const double * element = matrix_.getElements(); const int * row = matrix_.getIndices(); const CoinBigIndex * columnStart = matrix_.getVectorStarts(); const int * columnLength = matrix_.getVectorLengths(); #ifdef DIVE_FIX_BINARY_VARIABLES // Row copy const double * elementByRow = matrixByRow_.getElements(); const int * column = matrixByRow_.getIndices(); const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts(); const int * rowLength = matrixByRow_.getVectorLengths(); #endif // Get solution array for heuristic solution int numberColumns = solver->getNumCols(); memcpy(newSolution, solution, numberColumns*sizeof(double)); // vectors to store the latest variables fixed at their bounds int* columnFixed = new int [numberIntegers]; double* originalBound = new double [numberIntegers+2*numberColumns]; double * lowerBefore = originalBound+numberIntegers; double * upperBefore = lowerBefore+numberColumns; memcpy(lowerBefore,lower,numberColumns*sizeof(double)); memcpy(upperBefore,upper,numberColumns*sizeof(double)); double * lastDjs=newSolution+numberColumns; bool * fixedAtLowerBound = new bool [numberIntegers]; PseudoReducedCost * candidate = new PseudoReducedCost [numberIntegers]; double * random = new double [numberIntegers]; int maxNumberAtBoundToFix = static_cast<int> (floor(percentageToFix_ * numberIntegers)); assert (!maxNumberAtBoundToFix||!nodes); // count how many fractional variables int numberFractionalVariables = 0; for (int i = 0; i < numberIntegers; i++) { random[i] = randomNumberGenerator_.randomDouble() + 0.3; int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { numberFractionalVariables++; } } const double* reducedCost = NULL; // See if not NLP if (model_->solverCharacteristics()->reducedCostsAccurate()) reducedCost = solver->getReducedCost(); int iteration = 0; while (numberFractionalVariables) { iteration++; // initialize any data initializeData(); // select a fractional variable to bound int bestColumn = -1; int bestRound; // -1 rounds down, +1 rounds up bool canRound = selectVariableToBranch(solver, newSolution, bestColumn, bestRound); // if the solution is not trivially roundable, we don't try to round; // if the solution is trivially roundable, we try to round. However, // if the rounded solution is worse than the current incumbent, // then we don't round and proceed normally. In this case, the // bestColumn will be a trivially roundable variable if (canRound) { // check if by rounding all fractional variables // we get a solution with an objective value // better than the current best integer solution double delta = 0.0; for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { assert(downLocks_[i] == 0 || upLocks_[i] == 0); double obj = objective[iColumn]; if (downLocks_[i] == 0 && upLocks_[i] == 0) { if (direction * obj >= 0.0) delta += (floor(value) - value) * obj; else delta += (ceil(value) - value) * obj; } else if (downLocks_[i] == 0) delta += (floor(value) - value) * obj; else delta += (ceil(value) - value) * obj; } } if (direction*(solver->getObjValue() + delta) < solutionValue) { #ifdef DIVE_DEBUG nRoundFeasible++; #endif if (!nodes||bestColumn<0) { // Round all the fractional variables for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { assert(downLocks_[i] == 0 || upLocks_[i] == 0); if (downLocks_[i] == 0 && upLocks_[i] == 0) { if (direction * objective[iColumn] >= 0.0) newSolution[iColumn] = floor(value); else newSolution[iColumn] = ceil(value); } else if (downLocks_[i] == 0) newSolution[iColumn] = floor(value); else newSolution[iColumn] = ceil(value); } } break; } else { // can't round if going to use in branching int i; for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[bestColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { if (iColumn==bestColumn) { assert(downLocks_[i] == 0 || upLocks_[i] == 0); double obj = objective[bestColumn]; if (downLocks_[i] == 0 && upLocks_[i] == 0) { if (direction * obj >= 0.0) bestRound=-1; else bestRound=1; } else if (downLocks_[i] == 0) bestRound=-1; else bestRound=1; break; } } } } } #ifdef DIVE_DEBUG else nRoundInfeasible++; #endif } // do reduced cost fixing #ifdef DIVE_DEBUG int numberFixed = reducedCostFix(solver); std::cout << "numberReducedCostFixed = " << numberFixed << std::endl; #else reducedCostFix(solver); #endif int numberAtBoundFixed = 0; #ifdef DIVE_FIX_BINARY_VARIABLES // fix binary variables based on pseudo reduced cost if (binVarIndex_.size()) { int cnt = 0; int n = static_cast<int>(binVarIndex_.size()); for (int j = 0; j < n; j++) { int iColumn1 = binVarIndex_[j]; double value = newSolution[iColumn1]; if (fabs(value) <= integerTolerance && lower[iColumn1] != upper[iColumn1]) { double maxPseudoReducedCost = 0.0; #ifdef DIVE_DEBUG std::cout << "iColumn1 = " << iColumn1 << ", value = " << value << std::endl; #endif int iRow = vbRowIndex_[j]; double chosenValue = 0.0; for (int k = rowStart[iRow]; k < rowStart[iRow] + rowLength[iRow]; k++) { int iColumn2 = column[k]; #ifdef DIVE_DEBUG std::cout << "iColumn2 = " << iColumn2 << std::endl; #endif if (iColumn1 != iColumn2) { double pseudoReducedCost = fabs(reducedCost[iColumn2] * elementByRow[k]); #ifdef DIVE_DEBUG int k2; for (k2 = rowStart[iRow]; k2 < rowStart[iRow] + rowLength[iRow]; k2++) { if (column[k2] == iColumn1) break; } std::cout << "reducedCost[" << iColumn2 << "] = " << reducedCost[iColumn2] << ", elementByRow[" << iColumn2 << "] = " << elementByRow[k] << ", elementByRow[" << iColumn1 << "] = " << elementByRow[k2] << ", pseudoRedCost = " << pseudoReducedCost << std::endl; #endif if (pseudoReducedCost > maxPseudoReducedCost) maxPseudoReducedCost = pseudoReducedCost; } else { // save value chosenValue = fabs(elementByRow[k]); } } assert (chosenValue); maxPseudoReducedCost /= chosenValue; #ifdef DIVE_DEBUG std::cout << ", maxPseudoRedCost = " << maxPseudoReducedCost << std::endl; #endif candidate[cnt].var = iColumn1; candidate[cnt++].pseudoRedCost = maxPseudoReducedCost; } } #ifdef DIVE_DEBUG std::cout << "candidates for rounding = " << cnt << std::endl; #endif std::sort(candidate, candidate + cnt, compareBinaryVars); for (int i = 0; i < cnt; i++) { int iColumn = candidate[i].var; if (numberAtBoundFixed < maxNumberAtBoundToFix) { columnFixed[numberAtBoundFixed] = iColumn; originalBound[numberAtBoundFixed] = upper[iColumn]; fixedAtLowerBound[numberAtBoundFixed] = true; solver->setColUpper(iColumn, lower[iColumn]); numberAtBoundFixed++; if (numberAtBoundFixed == maxNumberAtBoundToFix) break; } } } #endif // fix other integer variables that are at their bounds int cnt = 0; #ifdef GAP double gap = 1.0e30; #endif if (reducedCost && true) { #ifndef JJF_ONE cnt = fixOtherVariables(solver, solution, candidate, random); #else #ifdef GAP double cutoff = model_->getCutoff() ; if (cutoff < 1.0e20 && false) { double direction = solver->getObjSense() ; gap = cutoff - solver->getObjValue() * direction ; gap *= 0.1; // Fix more if plausible double tolerance; solver->getDblParam(OsiDualTolerance, tolerance) ; if (gap <= 0.0) gap = tolerance; gap += 100.0 * tolerance; } int nOverGap = 0; #endif int numberFree = 0; int numberFixed = 0; for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; if (upper[iColumn] > lower[iColumn]) { numberFree++; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) <= integerTolerance) { candidate[cnt].var = iColumn; candidate[cnt++].pseudoRedCost = fabs(reducedCost[iColumn] * random[i]); #ifdef GAP if (fabs(reducedCost[iColumn]) > gap) nOverGap++; #endif } } else { numberFixed++; } } #ifdef GAP int nLeft = maxNumberAtBoundToFix - numberAtBoundFixed; #ifdef CLP_INVESTIGATE4 printf("cutoff %g obj %g nover %d - %d free, %d fixed\n", cutoff, solver->getObjValue(), nOverGap, numberFree, numberFixed); #endif if (nOverGap > nLeft && true) { nOverGap = CoinMin(nOverGap, nLeft + maxNumberAtBoundToFix / 2); maxNumberAtBoundToFix += nOverGap - nLeft; } #else #ifdef CLP_INVESTIGATE4 printf("cutoff %g obj %g - %d free, %d fixed\n", model_->getCutoff(), solver->getObjValue(), numberFree, numberFixed); #endif #endif #endif } else { for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; if (upper[iColumn] > lower[iColumn]) { double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) <= integerTolerance) { candidate[cnt].var = iColumn; candidate[cnt++].pseudoRedCost = numberIntegers - i; } } } } std::sort(candidate, candidate + cnt, compareBinaryVars); for (int i = 0; i < cnt; i++) { int iColumn = candidate[i].var; if (upper[iColumn] > lower[iColumn]) { double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) <= integerTolerance && numberAtBoundFixed < maxNumberAtBoundToFix) { // fix the variable at one of its bounds if (fabs(lower[iColumn] - value) <= integerTolerance) { columnFixed[numberAtBoundFixed] = iColumn; originalBound[numberAtBoundFixed] = upper[iColumn]; fixedAtLowerBound[numberAtBoundFixed] = true; solver->setColUpper(iColumn, lower[iColumn]); numberAtBoundFixed++; } else if (fabs(upper[iColumn] - value) <= integerTolerance) { columnFixed[numberAtBoundFixed] = iColumn; originalBound[numberAtBoundFixed] = lower[iColumn]; fixedAtLowerBound[numberAtBoundFixed] = false; solver->setColLower(iColumn, upper[iColumn]); numberAtBoundFixed++; } if (numberAtBoundFixed == maxNumberAtBoundToFix) break; } } } #ifdef DIVE_DEBUG std::cout << "numberAtBoundFixed = " << numberAtBoundFixed << std::endl; #endif double originalBoundBestColumn; double bestColumnValue; int whichWay; if (bestColumn >= 0) { bestColumnValue = newSolution[bestColumn]; if (bestRound < 0) { originalBoundBestColumn = upper[bestColumn]; solver->setColUpper(bestColumn, floor(bestColumnValue)); whichWay=0; } else { originalBoundBestColumn = lower[bestColumn]; solver->setColLower(bestColumn, ceil(bestColumnValue)); whichWay=1; } } else { break; } int originalBestRound = bestRound; int saveModelOptions = model_->specialOptions(); while (1) { model_->setSpecialOptions(saveModelOptions | 2048); solver->resolve(); model_->setSpecialOptions(saveModelOptions); if (!solver->isAbandoned()&&!solver->isIterationLimitReached()) { numberSimplexIterations += solver->getIterationCount(); } else { numberSimplexIterations = maxSimplexIterations + 1; reasonToStop += 100; break; } if (!solver->isProvenOptimal()) { if (nodes) { if (solver->isProvenPrimalInfeasible()) { if (maxSimplexIterationsAtRoot_!=COIN_INT_MAX) { // stop now printf("stopping on first infeasibility\n"); break; } else if (cuts) { // can do conflict cut printf("could do intermediate conflict cut\n"); bool localCut; OsiRowCut * cut = model_->conflictCut(solver,localCut); if (cut) { if (!localCut) { model_->makePartialCut(cut,solver); cuts[numberCuts++]=cut; } else { delete cut; } } } } else { reasonToStop += 10; break; } } if (numberAtBoundFixed > 0) { // Remove the bound fix for variables that were at bounds for (int i = 0; i < numberAtBoundFixed; i++) { int iColFixed = columnFixed[i]; if (fixedAtLowerBound[i]) solver->setColUpper(iColFixed, originalBound[i]); else solver->setColLower(iColFixed, originalBound[i]); } numberAtBoundFixed = 0; } else if (bestRound == originalBestRound) { bestRound *= (-1); whichWay |=2; if (bestRound < 0) { solver->setColLower(bestColumn, originalBoundBestColumn); solver->setColUpper(bestColumn, floor(bestColumnValue)); } else { solver->setColLower(bestColumn, ceil(bestColumnValue)); solver->setColUpper(bestColumn, originalBoundBestColumn); } } else break; } else break; } if (!solver->isProvenOptimal() || direction*solver->getObjValue() >= solutionValue) { reasonToStop += 1; } else if (iteration > maxIterations_) { reasonToStop += 2; } else if (CoinCpuTime() - time1 > maxTime_) { reasonToStop += 3; } else if (numberSimplexIterations > maxSimplexIterations) { reasonToStop += 4; // also switch off #ifdef CLP_INVESTIGATE printf("switching off diving as too many iterations %d, %d allowed\n", numberSimplexIterations, maxSimplexIterations); #endif when_ = 0; } else if (solver->getIterationCount() > 1000 && iteration > 3 && !nodes) { reasonToStop += 5; // also switch off #ifdef CLP_INVESTIGATE printf("switching off diving one iteration took %d iterations (total %d)\n", solver->getIterationCount(), numberSimplexIterations); #endif when_ = 0; } memcpy(newSolution, solution, numberColumns*sizeof(double)); numberFractionalVariables = 0; double sumFractionalVariables=0.0; for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; double away = fabs(floor(value + 0.5) - value); if (away > integerTolerance) { numberFractionalVariables++; sumFractionalVariables += away; } } if (nodes) { // save information //branchValues[numberNodes]=bestColumnValue; //statuses[numberNodes]=whichWay+(bestColumn<<2); //bases[numberNodes]=solver->getWarmStart(); ClpSimplex * simplex = clpSolver->getModelPtr(); CbcSubProblem * sub = new CbcSubProblem(clpSolver,lowerBefore,upperBefore, simplex->statusArray(),numberNodes); nodes[numberNodes]=sub; // other stuff sub->branchValue_=bestColumnValue; sub->problemStatus_=whichWay; sub->branchVariable_=bestColumn; sub->objectiveValue_ = simplex->objectiveValue(); sub->sumInfeasibilities_ = sumFractionalVariables; sub->numberInfeasibilities_ = numberFractionalVariables; printf("DiveNode %d column %d way %d bvalue %g obj %g\n", numberNodes,sub->branchVariable_,sub->problemStatus_, sub->branchValue_,sub->objectiveValue_); numberNodes++; if (solver->isProvenOptimal()) { memcpy(lastDjs,solver->getReducedCost(),numberColumns*sizeof(double)); memcpy(lowerBefore,lower,numberColumns*sizeof(double)); memcpy(upperBefore,upper,numberColumns*sizeof(double)); } } if (!numberFractionalVariables||reasonToStop) break; } if (nodes) { printf("Exiting dive for reason %d\n",reasonToStop); if (reasonToStop>1) { printf("problems in diving\n"); int whichWay=nodes[numberNodes-1]->problemStatus_; CbcSubProblem * sub; if ((whichWay&2)==0) { // leave both ways sub = new CbcSubProblem(*nodes[numberNodes-1]); nodes[numberNodes++]=sub; } else { sub = nodes[numberNodes-1]; } if ((whichWay&1)==0) sub->problemStatus_=whichWay|1; else sub->problemStatus_=whichWay&~1; } if (!numberNodes) { // was good at start! - create fake clpSolver->resolve(); ClpSimplex * simplex = clpSolver->getModelPtr(); CbcSubProblem * sub = new CbcSubProblem(clpSolver,lowerBefore,upperBefore, simplex->statusArray(),numberNodes); nodes[numberNodes]=sub; // other stuff sub->branchValue_=0.0; sub->problemStatus_=0; sub->branchVariable_=-1; sub->objectiveValue_ = simplex->objectiveValue(); sub->sumInfeasibilities_ = 0.0; sub->numberInfeasibilities_ = 0; printf("DiveNode %d column %d way %d bvalue %g obj %g\n", numberNodes,sub->branchVariable_,sub->problemStatus_, sub->branchValue_,sub->objectiveValue_); numberNodes++; assert (solver->isProvenOptimal()); } nodes[numberNodes-1]->problemStatus_ |= 256*reasonToStop; // use djs as well if (solver->isProvenPrimalInfeasible()&&cuts) { // can do conflict cut and re-order printf("could do final conflict cut\n"); bool localCut; OsiRowCut * cut = model_->conflictCut(solver,localCut); if (cut) { printf("cut - need to use conflict and previous djs\n"); if (!localCut) { model_->makePartialCut(cut,solver); cuts[numberCuts++]=cut; } else { delete cut; } } else { printf("bad conflict - just use previous djs\n"); } } } // re-compute new solution value double objOffset = 0.0; solver->getDblParam(OsiObjOffset, objOffset); newSolutionValue = -objOffset; for (int i = 0 ; i < numberColumns ; i++ ) newSolutionValue += objective[i] * newSolution[i]; newSolutionValue *= direction; //printf("new solution value %g %g\n",newSolutionValue,solutionValue); if (newSolutionValue < solutionValue && !reasonToStop) { double * rowActivity = new double[numberRows]; memset(rowActivity, 0, numberRows*sizeof(double)); // paranoid check memset(rowActivity, 0, numberRows*sizeof(double)); for (int i = 0; i < numberColumns; i++) { int j; double value = newSolution[i]; if (value) { for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iRow = row[j]; rowActivity[iRow] += value * element[j]; } } } // check was approximately feasible bool feasible = true; for (int i = 0; i < numberRows; i++) { if (rowActivity[i] < rowLower[i]) { if (rowActivity[i] < rowLower[i] - 1000.0*primalTolerance) feasible = false; } else if (rowActivity[i] > rowUpper[i]) { if (rowActivity[i] > rowUpper[i] + 1000.0*primalTolerance) feasible = false; } } for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { feasible = false; break; } } if (feasible) { // new solution solutionValue = newSolutionValue; //printf("** Solution of %g found by CbcHeuristicDive\n",newSolutionValue); //if (cuts) //clpSolver->getModelPtr()->writeMps("good8.mps", 2); returnCode = 1; } else { // Can easily happen //printf("Debug CbcHeuristicDive giving bad solution\n"); } delete [] rowActivity; } #ifdef DIVE_DEBUG std::cout << "nRoundInfeasible = " << nRoundInfeasible << ", nRoundFeasible = " << nRoundFeasible << ", returnCode = " << returnCode << ", reasonToStop = " << reasonToStop << ", simplexIts = " << numberSimplexIterations << ", iterations = " << iteration << std::endl; #endif delete [] columnFixed; delete [] originalBound; delete [] fixedAtLowerBound; delete [] candidate; delete [] random; delete [] downArray_; downArray_ = NULL; delete [] upArray_; upArray_ = NULL; delete solver; return returnCode; }
//############################################################################# // Parameters: // cuts: (o) all cuts generated in this round of cut generation // numberTries: (i) the maximum number of iterations for this round of cut // generation; no a priori limit if 0 // whichGenerator: (i/o) whichGenerator[i] is loaded with the index of the // generator that produced cuts[i]; reallocated as // required // numberOldActiveCuts: (o) the number of active cuts at this node from // previous rounds of cut generation // numberNewCuts: (o) the number of cuts produced in this round of cut // generation // maximumWhich: (i/o) capacity of whichGenerator; may be updated if // whichGenerator grows. // cutDuringRampup: (i) Whether generating cuts during rampup // found: (o) great than 0 means that heuristics found solutions; // otherwise not. bool DcModel::solveWithCuts(OsiCuts & cuts, int numberTries, DcTreeNode * node, int & numberOldActiveCuts, int & numberNewCuts, int & maximumWhich, int *& whichGenerator, const bool cutDuringRampup, int & found) { found = -10; bool feasible; int lastNumberCuts = 0; double lastObjective = -1.0e100 ; int violated = 0; int numberRowsAtStart = solver_->getNumRows(); int numberColumns = solver_->getNumCols(); numberOldActiveCuts = numberRowsAtStart - numberRowsAtContinuous_; numberNewCuts = 0; feasible = resolve(); if(!feasible) { return false; // If lost feasibility, bail out right now } reducedCostFix(); const double *lower = solver_->getColLower(); const double *upper = solver_->getColUpper(); const double *solution = solver_->getColSolution(); double minimumDrop = minimumDrop_; if (numberTries < 0) { numberTries = -numberTries; minimumDrop = -1.0; } //------------------------------------------------------------------------- // Is it time to scan the cuts in order to remove redundant cuts? If so, // set up to do it. # define SCANCUTS 100 int *countColumnCuts = NULL; int *countRowCuts = NULL; bool fullScan = false; if ((numberNodes_ % SCANCUTS) == 0) { fullScan = true; countColumnCuts = new int[numberCutGenerators_ + numberHeuristics_]; countRowCuts = new int[numberCutGenerators_ + numberHeuristics_]; memset(countColumnCuts, 0, (numberCutGenerators_ + numberHeuristics_) * sizeof(int)); memset(countRowCuts, 0, (numberCutGenerators_ + numberHeuristics_) * sizeof(int)); } double direction = solver_->getObjSense(); double startObjective = solver_->getObjValue() * direction; int numberPasses = 0; double primalTolerance = 1.0e-7; //------------------------------------------------------------------------- // Start cut generation loop // do { // numberPasses++; // numberTries--; // OsiCuts theseCuts; // // First check if there are cuts violated in global cut pool // if (numberPasses == 1 && howOftenGlobalScan_ > 0 && // (numberNodes_ % howOftenGlobalScan_) == 0) { // int numberCuts = globalCuts_.sizeColCuts(); // int i; // for ( i = 0; i < numberCuts; ++i) { // const OsiColCut *thisCut = globalCuts_.colCutPtr(i); // if (thisCut->violated(solution) > primalTolerance) { // printf("Global cut added - violation %g\n", // thisCut->violated(solution)); // theseCuts.insert(*thisCut); // } // } // numberCuts = globalCuts_.sizeRowCuts(); // for ( i = 0; i < numberCuts; ++i) { // const OsiRowCut * thisCut = globalCuts_.rowCutPtr(i); // if (thisCut->violated(solution) > primalTolerance) { // printf("Global cut added - violation %g\n", // thisCut->violated(solution)); // theseCuts.insert(*thisCut); // } // } // } // //--------------------------------------------------------------------- // // Generate new cuts (global and/or local) and/or apply heuristics // // NOTE: Make sure CglProbing is added FIRST // double * newSolution = new double [numberColumns]; // double heuristicValue = getCutoff(); // #if defined(DC_DEBUG_MORE) // std::cout << "numberCutGenerators_ = " << numberCutGenerators_ // << "numberHeuristics_ = " << numberHeuristics_ // << std::endl; // #endif // for (int i = 0; i < numberCutGenerators_ + numberHeuristics_; ++i) { // int numberRowCutsBefore = theseCuts.sizeRowCuts(); // int numberColumnCutsBefore = theseCuts.sizeColCuts(); // if (i < numberCutGenerators_) { // if (cutDuringRampup) { // bool mustResolve = // generator_[i]->generateCuts(theseCuts, fullScan); // if (mustResolve) { // feasible = resolve(); // if (!feasible) // break; // } // } // } // else { // double saveValue = heuristicValue; // int ifSol = heuristic_[i-numberCutGenerators_]-> // solution(heuristicValue, newSolution); // // solution(heuristicValue, newSolution, theseCuts); // if (ifSol > 0) { // found = i; // } // else if (ifSol < 0) { // heuristicValue = saveValue; // } // } // int numberRowCutsAfter = theseCuts.sizeRowCuts(); // int numberColumnCutsAfter = theseCuts.sizeColCuts(); // int numberBefore = // numberRowCutsBefore + numberColumnCutsBefore + lastNumberCuts; // int numberAfter = // numberRowCutsAfter + numberColumnCutsAfter + lastNumberCuts; // if (numberAfter > maximumWhich) { // maximumWhich = std::max(maximumWhich * 2 + 100, numberAfter); // int * temp = new int[2 * maximumWhich]; // memcpy(temp, whichGenerator, numberBefore * sizeof(int)); // delete [] whichGenerator; // whichGenerator = temp; // } // int j; // if (fullScan) { // countRowCuts[i] += numberRowCutsAfter - // numberRowCutsBefore; // countColumnCuts[i] += numberColumnCutsAfter - // numberColumnCutsBefore; // } // for (j = numberRowCutsBefore; j < numberRowCutsAfter; ++j) { // whichGenerator[numberBefore++] = i; // const OsiRowCut * thisCut = theseCuts.rowCutPtr(j); // if (thisCut->globallyValid()) { // globalCuts_.insert(*thisCut); // } // } // for (j = numberColumnCutsBefore; j < numberColumnCutsAfter; ++j) { // whichGenerator[numberBefore++] = i; // const OsiColCut * thisCut = theseCuts.colCutPtr(j); // if (thisCut->globallyValid()) { // globalCuts_.insert(*thisCut); // } // } // } // //--------------------------------------------------------------------- // // If found a solution, Record it before we free the vector // if (found >= 0) { // bool better = // setBestSolution(DC_ROUNDING, heuristicValue, newSolution); // // if (!better){ // // found = -1; // //} // //std::cout << "better = " << better // // << "; found = " << found << std::endl; // } // if(newSolution != 0) delete [] newSolution; // int numberColumnCuts = theseCuts.sizeColCuts(); // int numberRowCuts = theseCuts.sizeRowCuts(); // violated = numberRowCuts + numberColumnCuts; // //--------------------------------------------------------------------- // // Apply column cuts // if (numberColumnCuts) { // double integerTolerance = getDblParam(DcIntegerTolerance); // for (int i = 0; i < numberColumnCuts; ++i) { // const OsiColCut * thisCut = theseCuts.colCutPtr(i); // const CoinPackedVector & lbs = thisCut->lbs(); // const CoinPackedVector & ubs = thisCut->ubs(); // int j; // int n; // const int * which; // const double * values; // n = lbs.getNumElements(); // which = lbs.getIndices(); // values = lbs.getElements(); // for (j = 0; j < n; ++j){ // int iColumn = which[j]; // double value = solution[iColumn]; // solver_->setColLower(iColumn, values[j]); // if (value < values[j] - integerTolerance) // violated = -1; // violated, TODO: when happen? // if (values[j] > upper[iColumn] + integerTolerance) { // violated = -2; // infeasible // break; // } // } // n = ubs.getNumElements(); // which = ubs.getIndices(); // values = ubs.getElements(); // for (j = 0; j < n; ++j) { // int iColumn = which[j]; // double value = solution[iColumn]; // solver_->setColUpper(iColumn, values[j]); // if (value > values[j] + integerTolerance) // violated = -1; // if (values[j] < lower[iColumn] - integerTolerance) { // violated = -2; // infeasible // break; // } // } // } // } // if (violated == -2) { // feasible = false ; // break ; // break the cut generation loop // } // //--------------------------------------------------------------------- // // Now apply the row (constraint) cuts. // int numberRowsNow = solver_->getNumRows(); // assert(numberRowsNow == numberRowsAtStart + lastNumberCuts); // int numberToAdd = theseCuts.sizeRowCuts(); // numberNewCuts = lastNumberCuts + numberToAdd; // // Get a basis by asking the solver for warm start information. // // Resize it (retaining the basis) so it can accommodate the cuts. // delete basis_; // basis_ = dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()); // assert(basis_ != NULL); // make sure not volume // basis_->resize(numberRowsAtStart + numberNewCuts, numberColumns); // // Now actually add the row cuts and reoptimise. // if (numberRowCuts > 0 || numberColumnCuts > 0) { // if (numberToAdd > 0) { // int i; // OsiRowCut * addCuts = new OsiRowCut [numberToAdd]; // for (i = 0; i < numberToAdd; ++i) { // addCuts[i] = theseCuts.rowCut(i); // } // solver_->applyRowCuts(numberToAdd, addCuts); // // AJK this caused a memory fault on Win32 // delete [] addCuts; // for (i = 0; i < numberToAdd; ++i) { // cuts.insert(theseCuts.rowCut(i)); // } // for (i = 0; i < numberToAdd; ++i) { // basis_->setArtifStatus(numberRowsNow + i, // CoinWarmStartBasis::basic); // } // if (solver_->setWarmStart(basis_) == false) { // throw CoinError("Fail setWarmStart() after cut install.", // "solveWithCuts", "SbbModel"); // } // } // feasible = resolve() ; // } // else { // numberTries = 0; // } // //--------------------------------------------------------------------- // if (feasible) { // int cutIterations = solver_->getIterationCount(); // //takeOffCuts(cuts, whichGenerator, // // numberOldActiveCuts, numberNewCuts, true); // if (solver_->isDualObjectiveLimitReached()) { // feasible = false; // #ifdef DC_DEBUG // double z = solver_->getObjValue(); // double cut = getCutoff(); // // printf("Lost feasibility by %g in takeOffCuts; z = %g, cutoff = %g\n", // // z - cut, z, cut); // #endif // } // if (feasible) { // numberRowsAtStart = numberOldActiveCuts + // numberRowsAtContinuous_; // lastNumberCuts = numberNewCuts; // if ((direction * solver_->getObjValue() < // lastObjective + minimumDrop) && (numberPasses >= 3)) { // numberTries = 0; // } // if (numberRowCuts+numberColumnCuts == 0 || cutIterations == 0) // { break; } // if (numberTries > 0) { // reducedCostFix(); // lastObjective = direction * solver_->getObjValue(); // lower = solver_->getColLower(); // upper = solver_->getColUpper(); // solution = solver_->getColSolution(); // } // } // } // // We've lost feasibility // if (!feasible) { // numberTries = 0; // } // } while (numberTries); // END OF GENERATING CUTS //------------------------------------------------------------------------ // Adjust the frequency of use for any of the cut generator double thisObjective = solver_->getObjValue() * direction; if (feasible && fullScan && numberCutGenerators_) { double totalCuts = 0.0; int i; for (int i = 0; i < numberCutGenerators_; ++i) totalCuts += countRowCuts[i] + 5.0 * countColumnCuts[i]; // Root node or every so often - see what to turn off if (!numberNodes_) handler_->message(DC_ROOT, messages_) << numberNewCuts << startObjective << thisObjective << numberPasses << CoinMessageEol; int * count = new int[numberCutGenerators_]; memset(count, 0, numberCutGenerators_ * sizeof(int)); for (i = 0; i < numberNewCuts; ++i) count[whichGenerator[i]]++; double small = (0.5 * totalCuts) / ((double) numberCutGenerators_); for (i = 0; i < numberCutGenerators_; ++i) { int howOften = generator_[i]->howOften(); if (howOften < -99) continue; if (howOften < 0 || howOften >= 1000000) { // If small number switch mostly off double thisCuts = countRowCuts[i] + 5.0 * countColumnCuts[i]; if (!thisCuts || howOften == -99) { if (howOften == -99) howOften = -100; else howOften = 1000000 + SCANCUTS; // wait until next time } else if (thisCuts < small) { int k = (int) sqrt(small / thisCuts); howOften = k + 1000000; } else { howOften = 1 + 1000000; } } generator_[i]->setHowOften(howOften); int newFrequency = generator_[i]->howOften() % 1000000; // if (handler_->logLevel() > 1 || !numberNodes_) if (!numberNodes_) handler_->message(DC_GENERATOR, messages_) << i << generator_[i]->cutGeneratorName() << countRowCuts[i] << countRowCuts[i] //<<count[i] << countColumnCuts[i] << newFrequency << CoinMessageEol; } delete [] count; } delete [] countRowCuts; delete [] countColumnCuts; #ifdef CHECK_CUT_COUNTS if (feasible) { delete basis_; basis_ = dynamic_cast<CoinWarmStartBasis*>(solver_->getWarmStart()); printf("solveWithCuts: Number of rows at end (only active cuts) %d\n", numberRowsAtContinuous_+numberNewCuts+numberOldActiveCuts); basis_->print(); } if (numberNodes_ % 1000 == 0) { messageHandler()->message(DC_CUTS, messages_) << numberNodes_ << numberNewCuts << startObjective << thisObjective << numberPasses << CoinMessageEol; } #endif //takeOffCuts(cuts, whichGenerator, numberOldActiveCuts, // numberNewCuts, true); incrementNodeCount(); return feasible; }