// Creates a branching object from this infeasible object. BcpsBranchObject * BlisObjectInt::createBranchObject(BcpsModel *m, int direction) const { BlisModel *model = dynamic_cast<BlisModel* >(m); OsiSolverInterface * solver = model->solver(); double integerTolerance = model->BlisPar()->entry(BlisParams::integerTol); const double * solution = solver->getColSolution(); const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); double value = solution[columnIndex_]; //std::cout << "COL"<< columnIndex_ << ": x = " << value << std::endl; // Force value in bounds. value = CoinMax(value, lower[columnIndex_]); value = CoinMin(value, upper[columnIndex_]); double nearest = floor(value + 0.5); assert (upper[columnIndex_] > lower[columnIndex_]); int hotstartStrategy = model->getHotstartStrategy(); if (hotstartStrategy <= 0) { if (fabs(value - nearest) < integerTolerance) { // Already integeral. std::cout << "ERROR: COL" << columnIndex_ << ": x=" << value << ", nearest=" << nearest << ", intTol=" << integerTolerance << std::endl; assert(0); } } else { const double * incumbent = model->incumbent(); double targetValue = incumbent[columnIndex_]; if (direction > 0) { value = targetValue - 0.1; } else { value = targetValue + 0.1; } } return new BlisBranchObjectInt(model, objectIndex_, direction, value); }
// Compute the infeasibility based on currently relax solution. double BlisObjectInt::infeasibility(BcpsModel *m, int & preferredWay) const { BlisModel * model = dynamic_cast<BlisModel *>(m); OsiSolverInterface * solver = model->solver(); const double * solution = solver->getColSolution(); const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); double value = solution[columnIndex_]; value = std::max(value, lower[columnIndex_]); value = std::min(value, upper[columnIndex_]); //printf("%d %g %g %g %g\n",columnIndex_,value,lower[columnIndex_], // solution[columnIndex_],upper[columnIndex_]); double nearest = floor(value + (1.0 - breakEven_)); double integerTolerance = model->BlisPar()->entry(BlisParams::integerTol); if (nearest > value) { preferredWay = 1; } else { preferredWay = -1; } double weight = fabs(value - nearest); // normalize so weight is 0.5 at break even if (nearest < value) { weight = (0.5/breakEven_) * weight; } else { weight = (0.5/(1.0 - breakEven_)) * weight; } if (fabs(value - nearest) <= integerTolerance) { return 0.0; } else { return weight; } }
BcpsBranchObject * BlisObjectInt::preferredNewFeasible(BcpsModel *m) const { BlisModel *model = dynamic_cast<BlisModel* >(m); OsiSolverInterface * solver = model->solver(); double value = solver->getColSolution()[columnIndex_]; double nearest = floor(value + 0.5); double integerTolerance = model->BlisPar()->entry(BlisParams::integerTol); assert(fabs(value - nearest) <= integerTolerance); double dj = solver->getObjSense()*solver->getReducedCost()[columnIndex_]; BlisBranchObjectInt * object = NULL; if (dj >= 0.0) { // Better go down if (nearest > originalLower_ + 0.5) { // Has room to go down object = new BlisBranchObjectInt(model, objectIndex_, -1, nearest - 1.0, nearest - 1.0); } } else { // Better go up if (nearest < originalUpper_ - 0.5) { // Has room to go up object = new BlisBranchObjectInt(model, objectIndex_, -1, nearest + 1.0, nearest + 1.0); } } return object; }
// Force this object within exiting bounds, then fix the bounds at the // the nearest integer value. Assume solution value is within tolerance of // the nearest integer. void BlisObjectInt::feasibleRegion(BcpsModel *m) { BlisModel *model = dynamic_cast<BlisModel* >(m); OsiSolverInterface * solver = model->solver(); const double * solution = solver->getColSolution(); const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); double value = solution[columnIndex_]; // 1) Force value to be in bounds. value = CoinMax(value, lower[columnIndex_]); value = CoinMin(value, upper[columnIndex_]); double nearest = floor(value + 0.5); // 2) Fix variable at the nearest integer assert (fabs(value - nearest) <= 0.01); solver->setColLower(columnIndex_, nearest); solver->setColUpper(columnIndex_, nearest); }
/** Create a set of candidate branching objects. */ int BlisBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) { int bStatus = 0; int i, pass, colInd; int preferDir, saveLimit; int numFirsts = 0; int numInfs = 0; int minCount = 0; int numLowerTightens = 0; int numUpperTightens = 0; double lpX, score, infeasibility, downDeg, upDeg, sumDeg = 0.0; bool roundAgain, downKeep, downGood, upKeep, upGood; int *lbInd = NULL; int *ubInd = NULL; double *newLB = NULL; double *newUB = NULL; double *saveUpper = NULL; double *saveLower = NULL; double *saveSolution = NULL; BlisModel *model = dynamic_cast<BlisModel *>(model_); OsiSolverInterface *solver = model->solver(); int numCols = model->getNumCols(); int numObjects = model->numObjects(); int aveIterations = model->getAveIterations(); //std::cout << "aveIterations = " << aveIterations << std::endl; //------------------------------------------------------ // Check if max time is reached or no pass is left. //------------------------------------------------------ double timeLimit = model->AlpsPar()->entry(AlpsParams::timeLimit); AlpsKnowledgeBroker *broker = model->getKnowledgeBroker(); bool maxTimeReached = (broker->timer().getTime() > timeLimit); bool selectNow = false; if (maxTimeReached || !numPassesLeft) { selectNow = true; #ifdef BLIS_DEBUG printf("PSEUDO: CREATE: maxTimeReached %d, numPassesLeft %d\n", maxTimeReached, numPassesLeft); #endif } // Store first time objects. std::vector<BlisObjectInt *> firstObjects; // Store infeasible objects. std::vector<BlisObjectInt *> infObjects; // TODO: check if sorting is expensive. std::multimap<double, BcpsBranchObject*, BlisPseuoGreater> candObjects; double objValue = solver->getObjSense() * solver->getObjValue(); const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); saveSolution = new double[numCols]; memcpy(saveSolution, solver->getColSolution(), numCols*sizeof(double)); //-------------------------------------------------- // Find the infeasible objects. // NOTE: we might go round this loop twice if we are feed in // a "feasible" solution. //-------------------------------------------------- for (pass = 0; pass < 2; ++pass) { numInfs = 0; BcpsObject * object = NULL; BlisObjectInt * intObject = NULL; infObjects.clear(); firstObjects.clear(); for (i = 0; i < numObjects; ++i) { object = model->objects(i); infeasibility = object->infeasibility(model, preferDir); if (infeasibility) { ++numInfs; intObject = dynamic_cast<BlisObjectInt *>(object); if (intObject) { infObjects.push_back(intObject); if (!selectNow) { minCount = ALPS_MIN(intObject->pseudocost().getDownCount(), intObject->pseudocost().getUpCount()); if (minCount < 1) { firstObjects.push_back(intObject); } } #ifdef BLIS_DEBUG if (intObject->columnIndex() == 40) { std::cout << "x[40] = " << saveSolution[40] << std::endl; } #endif intObject = NULL; } else { // TODO: currently all are integer objects. #ifdef BLIS_DEBU assert(0); #endif } } } if (numInfs) { #if 0 std::cout << "PSEUDO: numInfs = " << numInfs << std::endl; #endif break; } else if (pass == 0) { // The first pass and is IP feasible. #if 1 std::cout << "ERROR: PSEUDO: given a integer feasible sol, no fraction variable" << std::endl; assert(0); #endif roundAgain = false; CoinWarmStartBasis * ws = dynamic_cast<CoinWarmStartBasis*>(solver->getWarmStart()); if (!ws) break; // Force solution values within bounds for (i = 0; i < numCols; ++i) { lpX = saveSolution[i]; if (lpX < lower[i]) { saveSolution[i] = lower[i]; roundAgain = true; ws->setStructStatus(i, CoinWarmStartBasis::atLowerBound); } else if (lpX > upper[i]) { saveSolution[i] = upper[i]; roundAgain = true; ws->setStructStatus(i, CoinWarmStartBasis::atUpperBound); } } if (roundAgain) { // Need resolve and do the second round selection. solver->setWarmStart(ws); delete ws; // Resolve. solver->resolve(); if (!solver->isProvenOptimal()) { // Become infeasible, can do nothing. bStatus = -2; goto TERM_CREATE; } else { // Save new lp solution. memcpy(saveSolution, solver->getColSolution(), numCols * sizeof(double)); objValue = solver->getObjSense() * solver->getObjValue(); } } else { delete ws; break; } } } // EOF 2 pass //-------------------------------------------------- // If we have a set of first time object, // branch up and down to initialize pseudo-cost. //-------------------------------------------------- numFirsts = static_cast<int> (firstObjects.size()); //std::cout << "PSEUDO: numFirsts = " << numFirsts << std::endl; if (numFirsts > 0) { //std::cout << "PSEUDO: numFirsts = " << numFirsts << std::endl; //-------------------------------------------------- // Backup solver status and mark hot start. //-------------------------------------------------- saveLower = new double[numCols]; saveUpper = new double[numCols]; memcpy(saveLower, lower, numCols * sizeof(double)); memcpy(saveUpper, upper, numCols * sizeof(double)); CoinWarmStart * ws = solver->getWarmStart(); solver->getIntParam(OsiMaxNumIterationHotStart, saveLimit); aveIterations = ALPS_MIN(50, aveIterations); solver->setIntParam(OsiMaxNumIterationHotStart, aveIterations); solver->markHotStart(); lbInd = new int [numFirsts]; ubInd = new int [numFirsts]; newLB = new double [numFirsts]; newUB = new double [numFirsts]; for (i = 0; i < numFirsts && bStatus != -2; ++i) { colInd = firstObjects[i]->columnIndex(); lpX = saveSolution[colInd]; BlisStrongBranch(model, objValue, colInd, lpX, saveLower, saveUpper, downKeep, downGood, downDeg, upKeep, upGood, upDeg); if(!downKeep && !upKeep) { // Both branch can be fathomed bStatus = -2; } else if (!downKeep) { // Down branch can be fathomed. lbInd[numLowerTightens] = colInd; newLB[numLowerTightens++] = ceil(lpX); } else if (!upKeep) { // Up branch can be fathomed. ubInd[numUpperTightens] = colInd; newUB[numUpperTightens++] = floor(lpX); } } //-------------------------------------------------- // Set new bounds in lp solver for resolving //-------------------------------------------------- if (bStatus != -2) { if (numUpperTightens > 0) { bStatus = -1; for (i = 0; i < numUpperTightens; ++i) { solver->setColUpper(ubInd[i], newUB[i]); } } if (numLowerTightens > 0) { bStatus = -1; for (i = 0; i < numLowerTightens; ++i) { solver->setColLower(lbInd[i], newLB[i]); } } } //-------------------------------------------------- // Unmark hotstart and recover LP solver. //-------------------------------------------------- solver->unmarkHotStart(); solver->setColSolution(saveSolution); solver->setIntParam(OsiMaxNumIterationHotStart, saveLimit); solver->setWarmStart(ws); delete ws; } if (bStatus < 0) { goto TERM_CREATE; } else { // Create a set of candidate branching objects. numBranchObjects_ = numInfs; branchObjects_ = new BcpsBranchObject* [numInfs]; // NOTE: it set model->savedLpSolution. sumDeg = 0.0; for (i = 0; i < numInfs; ++i) { if (infObjects[i]->pseudocost().getUpCost() < infObjects[i]->pseudocost().getDownCost()) { preferDir = 1; } else { preferDir = -1; } branchObjects_[i] = infObjects[i]->createBranchObject(model, preferDir); score = infObjects[i]->pseudocost().getScore(); branchObjects_[i]->setUpScore(score); sumDeg += score; #ifdef BLIS_DEBUG_MORE std::cout << "col[" << infObjects[i]->columnIndex() << "]: score=" << score << ", dir=" << branchObjects_[i]->getDirection() << ", up=" << infObjects[i]->pseudocost().getUpCost() << ", down=" << infObjects[i]->pseudocost().getDownCost() << std::endl; #endif } model->setSolEstimate(objValue + sumDeg); } TERM_CREATE: //------------------------------------------------------ // Cleanup. //------------------------------------------------------ delete [] lbInd; delete [] ubInd; delete [] newLB; delete [] newUB; delete [] saveSolution; delete [] saveLower; delete [] saveUpper; return bStatus; }
/** Create a set of candidate branching objects. */ int BlisBranchStrategyRel::createCandBranchObjects(int numPassesLeft) { int bStatus = 0; int i, pass, colInd; int preferDir, saveLimit; int numFirsts = 0; int numInfs = 0; int minCount = 0; int numLowerTightens = 0; int numUpperTightens = 0; double lpX, score, infeasibility, downDeg, upDeg, sumDeg = 0.0; bool roundAgain, downKeep, downGood, upKeep, upGood; int *lbInd = NULL; int *ubInd = NULL; double *newLB = NULL; double *newUB = NULL; double * saveUpper = NULL; double * saveLower = NULL; double * saveSolution = NULL; BlisModel *model = dynamic_cast<BlisModel *>(model_); OsiSolverInterface * solver = model->solver(); int numCols = model->getNumCols(); int numObjects = model->numObjects(); //int lookAhead = dynamic_cast<BlisParams*> // (model->blisPar())->entry(BlisParams::lookAhead); //------------------------------------------------------ // Check if max time is reached or no pass is left. //------------------------------------------------------ double timeLimit = model->AlpsPar()->entry(AlpsParams::timeLimit); bool maxTimeReached = (CoinCpuTime() - model->startTime_ > timeLimit); bool selectNow = false; if (maxTimeReached || !numPassesLeft) { selectNow = true; #ifdef BLIS_DEBUG printf("REL: CREATE: maxTimeReached %d, numPassesLeft %d\n", maxTimeReached, numPassesLeft); #endif } // Store first time objects. std::vector<BlisObjectInt *> firstObjects; // Store infeasible objects. std::vector<BlisObjectInt *> infObjects; // TODO: check if sorting is expensive. std::multimap<double, BlisObjectInt*, BlisPseuoGreater> sortedObjects; double objValue = solver->getObjSense() * solver->getObjValue(); const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); int lookAhead = dynamic_cast<BlisParams*> (model->BlisPar())->entry(BlisParams::lookAhead); BlisObjectInt * intObject = NULL; //------------------------------------------------------ // Backup solver status and mark hot start. //----------------------------------------------------- saveSolution = new double[numCols]; memcpy(saveSolution, solver->getColSolution(), numCols*sizeof(double)); saveLower = new double[numCols]; saveUpper = new double[numCols]; memcpy(saveLower, lower, numCols * sizeof(double)); memcpy(saveUpper, upper, numCols * sizeof(double)); //------------------------------------------------------ // Find the infeasible objects. // NOTE: we might go round this loop twice if we are feed in // a "feasible" solution. //------------------------------------------------------ for (pass = 0; pass < 2; ++pass) { numInfs = 0; BcpsObject * object = NULL; infObjects.clear(); firstObjects.clear(); for (i = 0; i < numObjects; ++i) { object = model->objects(i); infeasibility = object->infeasibility(model, preferDir); if (infeasibility) { ++numInfs; intObject = dynamic_cast<BlisObjectInt *>(object); if (intObject) { //score = object->pseudocost().getScore(); //tempBO = object->createBranchObject(model, preferDir); //candObjects.insert(std::make_pair(score, tempBO)); //tempBO = NULL; infObjects.push_back(intObject); if (!selectNow) { minCount = ALPS_MIN(intObject->pseudocost().getDownCount(), intObject->pseudocost().getUpCount()); if (minCount < 1) { firstObjects.push_back(intObject); } } #ifdef BLIS_DEBUG_MORE if (intObject->columnIndex() == 15) { std::cout << "x[15] = " << saveSolution[15] << std::endl; } #endif intObject = NULL; } else { // TODO: currently all are integer objects. #ifdef BLIS_DEBU assert(0); #endif } } } if (numInfs) { #ifdef BLIS_DEBUG_MORE std::cout << "REL: numInfs = " << numInfs << std::endl; #endif break; } else if (pass == 0) { // The first pass and is IP feasible. #ifdef BLIS_DEBUG std::cout << "REL: given a feasible sol" << std::endl; #endif roundAgain = false; CoinWarmStartBasis * ws = dynamic_cast<CoinWarmStartBasis*>(solver->getWarmStart()); if (!ws) break; // Force solution values within bounds for (i = 0; i < numCols; ++i) { lpX = saveSolution[i]; if (lpX < lower[i]) { saveSolution[i] = lower[i]; roundAgain = true; ws->setStructStatus(i, CoinWarmStartBasis::atLowerBound); } else if (lpX > upper[i]) { saveSolution[i] = upper[i]; roundAgain = true; ws->setStructStatus(i, CoinWarmStartBasis::atUpperBound); } } if (roundAgain) { // Need resolve and do the second round selection. solver->setWarmStart(ws); delete ws; // Resolve. solver->resolve(); if (!solver->isProvenOptimal()) { // Become infeasible, can do nothing. bStatus = -2; goto TERM_CREATE; } else { // Save new lp solution. memcpy(saveSolution, solver->getColSolution(), numCols * sizeof(double)); objValue = solver->getObjSense() * solver->getObjValue(); } } else { delete ws; break; } } } // EOF 2 pass //-------------------------------------------------- // If we have a set of first time object, // branch up and down to initialize pseudo-cost. //-------------------------------------------------- numFirsts = static_cast<int> (firstObjects.size()); if (numFirsts > 0) { CoinWarmStart * ws = solver->getWarmStart(); solver->getIntParam(OsiMaxNumIterationHotStart, saveLimit); int maxIter = ALPS_MAX(model->getAveIterations(), 50); solver->setIntParam(OsiMaxNumIterationHotStart, maxIter); solver->markHotStart(); lbInd = new int [numFirsts]; ubInd = new int [numFirsts]; newLB = new double [numFirsts]; newUB = new double [numFirsts]; for (i = 0; i < numFirsts && bStatus != -2; ++i) { colInd = firstObjects[i]->columnIndex(); lpX = saveSolution[colInd]; BlisStrongBranch(model, objValue, colInd, lpX, saveLower, saveUpper, downKeep, downGood, downDeg, upKeep, upGood, upDeg); if(!downKeep && !upKeep) { // Both branch can be fathomed bStatus = -2; } else if (!downKeep) { // Down branch can be fathomed. lbInd[numLowerTightens] = colInd; newLB[numLowerTightens++] = ceil(lpX); //break; } else if (!upKeep) { // Up branch can be fathomed. ubInd[numUpperTightens] = colInd; newUB[numUpperTightens++] = floor(lpX); // break; } // Update pseudocost. if(downGood) { firstObjects[i]->pseudocost().update(-1, downDeg, lpX); } if(downGood) { firstObjects[i]->pseudocost().update(1, upDeg, lpX); } } //-------------------------------------------------- // Set new bounds in lp solver for resolving //-------------------------------------------------- if (bStatus != -2) { if (numUpperTightens > 0) { bStatus = -1; for (i = 0; i < numUpperTightens; ++i) { solver->setColUpper(ubInd[i], newUB[i]); } } if (numLowerTightens > 0) { bStatus = -1; for (i = 0; i < numLowerTightens; ++i) { solver->setColLower(lbInd[i], newLB[i]); } } } //-------------------------------------------------- // Unmark hotstart and recover LP solver. //-------------------------------------------------- solver->unmarkHotStart(); solver->setColSolution(saveSolution); solver->setIntParam(OsiMaxNumIterationHotStart, saveLimit); solver->setWarmStart(ws); delete ws; } //std::cout << "REL: bStatus = " << bStatus << std::endl; if (bStatus < 0) { // Infeasible or monotone. goto TERM_CREATE; } else { // All object's pseudocost have been initialized. // Sort them, and do strong branch for the unreliable one // NOTE: it set model->savedLpSolution. // model->feasibleSolution(numIntegerInfs, numObjectInfs); sumDeg = 0.0; for (i = 0; i < numInfs; ++i) { score = infObjects[i]->pseudocost().getScore(); sumDeg += score; std::pair<const double, BlisObjectInt*> sa(score, infObjects[i]); sortedObjects.insert(sa); #ifdef BLIS_DEBUG_MORE std::cout << "col[" << infObjects[i]->columnIndex() << "]=" << score << ", "<< std::endl; #endif } int numNotChange = 0; std::multimap< double, BlisObjectInt*, BlisPseuoGreater >::iterator pos; CoinWarmStart * ws = solver->getWarmStart(); solver->getIntParam(OsiMaxNumIterationHotStart, saveLimit); int maxIter = ALPS_MAX(model->getAveIterations(), 50); solver->setIntParam(OsiMaxNumIterationHotStart, maxIter); solver->markHotStart(); BlisObjectInt *bestObject = NULL; double bestScore = -10.0; for (pos = sortedObjects.begin(); pos != sortedObjects.end(); ++pos) { intObject = pos->second; colInd = intObject->columnIndex(); #ifdef BLIS_DEBUG_MORE std::cout << "col[" << colInd << "]: " << "score=" << pos->first << ", upCount=" << intObject->pseudocost().getUpCount() <<", downCount="<< intObject->pseudocost().getDownCount() << std::endl; #endif // Check if reliable. int objRelibility=ALPS_MIN(intObject->pseudocost().getUpCount(), intObject->pseudocost().getDownCount()); if (objRelibility < relibility_) { // Unrelible object. Do strong branching. lpX = saveSolution[colInd]; BlisStrongBranch(model, objValue, colInd, lpX, saveLower, saveUpper, downKeep, downGood, downDeg, upKeep, upGood, upDeg); // Update pseudocost. if(downGood) { intObject->pseudocost().update(-1, downDeg, lpX); } if(downGood) { intObject->pseudocost().update(1, upDeg, lpX); } } // Compare with the best. if (intObject->pseudocost().getScore() > bestScore) { bestScore = intObject->pseudocost().getScore(); bestObject = intObject; // Reset numNotChange = 0; } else { // If best doesn't change for "lookAhead" comparisons, then // the best is reliable. if (++numNotChange > lookAhead) { if (bestObject->pseudocost().getUpCost() > bestObject->pseudocost().getDownCost()) { preferDir = 1; } else { preferDir = -1; } break; } } } solver->unmarkHotStart(); solver->setColSolution(saveSolution); solver->setIntParam(OsiMaxNumIterationHotStart, saveLimit); solver->setWarmStart(ws); delete ws; model->setSolEstimate(objValue + sumDeg); assert(bestObject != NULL); bestBranchObject_ = bestObject->createBranchObject(model, preferDir); } TERM_CREATE: //------------------------------------------------------ // Cleanup. //------------------------------------------------------ delete [] lbInd; delete [] ubInd; delete [] newLB; delete [] newUB; delete [] saveSolution; delete [] saveLower; delete [] saveUpper; return bStatus; }