From 4eff087cf5239dbba61e8fd6bbd4bcbc358596bf Mon Sep 17 00:00:00 2001 From: Ted Ralphs Date: Wed, 9 Aug 2023 10:42:52 -0400 Subject: [PATCH 1/5] Changes for allowing prioritizing branching on the lower level variables --- src/MibSBilevel.cpp | 23 +-- src/MibSBranchStrategyPseudo.cpp | 327 ++++++++++++++----------------- src/MibSBranchStrategyStrong.cpp | 19 +- src/MibSConstants.hpp | 11 +- src/MibSCutGenerator.cpp | 28 +-- src/MibSHeuristic.cpp | 14 +- src/MibSModel.cpp | 20 +- src/MibSModel.hpp | 4 +- 8 files changed, 215 insertions(+), 231 deletions(-) diff --git a/src/MibSBilevel.cpp b/src/MibSBilevel.cpp index 84db02df..ecf18fbf 100644 --- a/src/MibSBilevel.cpp +++ b/src/MibSBilevel.cpp @@ -80,7 +80,7 @@ MibSBilevel::createBilevel(CoinPackedVector* sol, int *indices = sol->getIndices(); double *values = sol->getElements(); int numElements(sol->getNumElements()); // number of nonzero elements - int * fixedInd = model_->fixedInd_; + int * varType = model_->varType_; if(!upperSolutionOrd_){ upperSolutionOrd_ = new double[uN]; @@ -134,7 +134,7 @@ MibSBilevel::createBilevel(CoinPackedVector* sol, if(binarySearch(0, uN - 1, index, upperColInd) >= 0){ if(fabs(floor(value + 0.5) - value) > etol){ #if 1 - if(fixedInd[index] == 1){ + if(varType[index] == MibSVarLinking){ isLinkVarsIntegral_ = false; } if(mibs->solver()->isInteger(index)){ @@ -162,7 +162,8 @@ MibSBilevel::createBilevel(CoinPackedVector* sol, for(i = 0; i < N; i ++){ if(binarySearch(0, uN - 1, i, upperColInd) >= 0){ - if((fixedInd[i] == 1) && (fabs(upper[i] - lower[i]) > etol)){ + if((varType[i] == MibSVarLinking) && + (fabs(upper[i] - lower[i]) > etol)){ isLinkVarsFixed_ = false; break; } @@ -204,7 +205,7 @@ MibSBilevel::createBilevel(CoinPackedVector* sol, std::vector linkSol; for(i = 0; i < uN; i++){ index = upperColInd[i]; - if(fixedInd[index] == 1){ + if(varType[index] == MibSVarLinking){ linkSol.push_back(upperSolutionOrd_[i]); } } @@ -288,7 +289,7 @@ MibSBilevel::checkBilevelFeasibility(bool isRoot) int uN(model_->upperDim_); // upper-level dimension int i(0), index(0), pos(0); double etol(model_->etol_), objVal(0.0), lowerObj(0.0); - int * fixedInd = model_->fixedInd_; + int * varType = model_->varType_; int * lowerColInd = model_->getLowerColInd(); int * upperColInd = model_->getUpperColInd(); double *lowerSol = new double[lN]; @@ -302,7 +303,7 @@ MibSBilevel::checkBilevelFeasibility(bool isRoot) std::vector linkSol; for(i = 0; i < uN; i++){ index = upperColInd[i]; - if(fixedInd[index] == 1){ + if(varType[index] == MibSVarLinking){ linkSol.push_back(upperSolutionOrd_[i]); } } @@ -709,7 +710,7 @@ MibSBilevel::setUpUBModel(OsiSolverInterface * oSolver, double objValLL, lpSol = oSolver->getColSolution(); } - int * fixedInd = model_->fixedInd_; + int * varType = model_->varType_; int i(0), index1(0); double value(0.0); @@ -753,7 +754,7 @@ MibSBilevel::setUpUBModel(OsiSolverInterface * oSolver, double objValLL, for(i = 0; i < uCols; i++){ index1 = uColIndices[i]; - if(fixedInd[index1] == 1){ + if(varType[index1] == MibSVarLinking){ colLb[index1] = floor(lpSol[index1] + 0.5); colUb[index1] = colLb[index1]; } @@ -846,7 +847,7 @@ MibSBilevel::setUpUBModel(OsiSolverInterface * oSolver, double objValLL, nSolver->setRowUpper(rowNum-1, objValLL); for(i = 0; i < uCols; i++){ index1 = uColIndices[i]; - if(fixedInd[index1] == 1){ + if(varType[index1] == MibSVarLinking){ value = floor(lpSol[index1] + 0.5); nSolver->setColLower(index1, value); nSolver->setColUpper(index1, value); @@ -1345,7 +1346,7 @@ void int i(0),index(0); int uN(model_->upperDim_); int * upperColInd = model_->getUpperColInd(); - int * fixedInd = model_->fixedInd_; + int * varType = model_->varType_; int solType = static_cast(solTag); LINKING_SOLUTION linkingSolution; @@ -1353,7 +1354,7 @@ void std::vector linkSol; for(i = 0; i < uN; i++){ index = upperColInd[i]; - if(fixedInd[index] == 1){ + if(varType[index] == MibSVarLinking){ linkSol.push_back(upperSolutionOrd_[i]); } } diff --git a/src/MibSBranchStrategyPseudo.cpp b/src/MibSBranchStrategyPseudo.cpp index aba91e5f..4189d98f 100644 --- a/src/MibSBranchStrategyPseudo.cpp +++ b/src/MibSBranchStrategyPseudo.cpp @@ -68,7 +68,7 @@ MibSBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) int minCount = 0; int numLowerTightens = 0; int numUpperTightens = 0; - double lpX, score, infeasibility, downDeg, upDeg, sumDeg = 0.0; + double lpX, score, downDeg, upDeg, sumDeg = 0.0; bool roundAgain, downKeep, downGood, upKeep, upGood; @@ -78,10 +78,6 @@ MibSBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) double *newLB = NULL; double *newUB = NULL; - double *saveUpper = NULL; - double *saveLower = NULL; - double *saveSolution = NULL; - BlisModel *model = dynamic_cast(model_); MibSModel *mibsmodel = dynamic_cast(model); MibSBilevel *bS = mibsmodel->bS_; @@ -92,13 +88,13 @@ MibSBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) int aveIterations = model->getAveIterations(); int uN = mibsmodel->upperDim_; int * upperColInd = mibsmodel->getUpperColInd(); - int * fixedInd = mibsmodel->fixedInd_; + int * varType = mibsmodel->varType_; char * colType = mibsmodel->colType_; // If upper-level variable is fixed -> fixedVar = 1 - int *fixedVar = new int[numCols](); + //int *fixedVar = new int[numCols](); - int *candidate = new int[numCols](); + bool *candidate = new bool[numCols](); //------------------------------------------------------ // Check if max time is reached or no pass is left. @@ -107,7 +103,8 @@ MibSBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) double timeLimit = model->AlpsPar()->entry(AlpsParams::timeLimit); AlpsKnowledgeBroker *broker = model->getKnowledgeBroker(); bool maxTimeReached = (broker->timer().getTime() > timeLimit); - bool selectNow = false; + bool selectNow(false); + bool isFractional; if (maxTimeReached || !numPassesLeft) { selectNow = true; @@ -130,8 +127,8 @@ MibSBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); - saveSolution = new double[numCols]; - memcpy(saveSolution, solver->getColSolution(), numCols*sizeof(double)); + double * solution = new double[numCols]; + memcpy(solution, solver->getColSolution(), numCols*sizeof(double)); //-------------------------------------------------- // Find the infeasible objects. @@ -139,171 +136,144 @@ MibSBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) // a "feasible" solution. //-------------------------------------------------- - for (pass = 0; pass < 2; ++pass) { - - numInfs = 0; - - BcpsObject * object = NULL; - BlisObjectInt * intObject = NULL; - - infObjects.clear(); - firstObjects.clear(); - - int index(0), found(0); - - double value(0.0); - - MibSBranchingStrategy branchPar = static_cast - (mibsmodel->MibSPar_->entry(MibSParams::branchStrategy)); - - if(branchPar == MibSBranchingStrategyLinking){ - for (i = 0; i < uN; ++i){ - index = upperColInd[i]; - if (fabs(lower[index]-upper[index])<=etol){ - fixedVar[index]=1; - } - } - for (i = 0; i < numCols; ++i) { - value = saveSolution[i]; - infeasibility = fabs(floor(value + 0.5) - value); - if((fixedInd[i] == 1) && (fabs(infeasibility) > etol)){ - found = 1; - break; - } - } - } - - for (i = 0; i < numCols; ++i) { - if(colType[i] == 'C'){ - candidate[i] = 0; - } - else{ - candidate[i] = 2; - value = saveSolution[i]; - infeasibility = fabs(floor(value + 0.5) - value); - if(branchPar == MibSBranchingStrategyLinking){ - if((bS->isLinkVarsFixed_ == true) && (bS->isIntegral_ == false)){ - if(fabs(infeasibility) > etol){ - candidate[i] = 1; - } - } - else if((fixedInd[i] == 1) && (((found == 0) && - (fixedVar[i] != 1)) || - (fabs(infeasibility) > etol))){ - candidate[i] = 1; - } - } - else if(infeasibility > etol){ - candidate[i] = 1; - } - } - } - - index = -1; - for (i = 0; i < numCols; ++i) { - if(candidate[i] != 0){ - index ++; - object = model->objects(index); - } - - if (candidate[i] == 1) { - - ++numInfs; - intObject = dynamic_cast(object); + BcpsObject * object = NULL; + BlisObjectInt * intObject = NULL; + + infObjects.clear(); + firstObjects.clear(); + + bool fractionalLinkingVar(false), fractionalLowerVar(false); + + MibSBranchingStrategy branchPar = static_cast + (mibsmodel->MibSPar_->entry(MibSParams::branchStrategy)); + + // Check for fractional linking variables + if(branchPar == MibSBranchingStrategyLinking){ + for (i = 0; i < numCols; ++i) { + if (fabs(floor(solution[i] + 0.5) - solution[i]) > etol){ + if (varType[i] == MibSVarLinking){ + fractionalLinkingVar = true; + break; + }else if (varType[i] == MibSVarLower){ + fractionalLowerVar = true; + break; + } + } + } + } + + for (i = 0; i < numCols; ++i) { + if(colType[i] == 'C'){ + candidate[i] = false; + continue; + } + + candidate[i] = false; + isFractional = fabs(floor(solution[i] + 0.5) - solution[i]) > etol; + switch (branchPar){ + case MibSBranchingStrategyLinking: + if(bS->isLinkVarsFixed_ && isFractional){ + candidate[i] = true; + }else if(varType[i] == MibSVarLinking && + ((!fractionalLinkingVar && fabs(upper[i]-lower[i]) > etol) || + isFractional)){ + candidate[i] = true; + } + break; + case MibSBranchingStrategyFractional: + if(isFractional){ + candidate[i] = true; + } + break; + case MibSBranchingStrategyLower: + if (isFractional && + (varType[i] == MibSVarLower || !fractionalLowerVar)){ + candidate[i] = true; + } + break; + } + } + + int index = 0; + for (i = 0; i < numCols; ++i) { + if(colType[i] == 'C'){ + continue; + } + if (candidate[i]) { + ++numInfs; + intObject = dynamic_cast(model->objects(index)); + + if (intObject) { + infObjects.push_back(intObject); + + if (!selectNow) { + minCount = + ALPS_MIN(intObject->pseudocost().getDownCount(), + intObject->pseudocost().getUpCount()); - 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 (minCount < 1) { + firstObjects.push_back(intObject); } - - } - } - - if (numInfs) { -#if 0 - std::cout << "PSEUDO: numInfs = " << numInfs - << std::endl; -#endif - break; - } - else if (pass == 0) { - // The first pass and is IP feasible. + } + + intObject = NULL; + } + } + index++; + } + if (!numInfs){ + // In general, we shouldn't end up here. Not sure we eed this. #if 1 - std::cout << "ERROR: PSEUDO: given a integer feasible sol, no fraction variable" << std::endl; - assert(0); + std::cout << "ERROR: PSEUDO: given a integer feasible sol, no fraction variable" << std::endl; + assert(0); #endif - - roundAgain = false; - CoinWarmStartBasis * ws = - dynamic_cast(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 + + roundAgain = false; + CoinWarmStartBasis * ws = + dynamic_cast(solver->getWarmStart()); + + if (ws){ + // Force solution values within bounds + for (i = 0; i < numCols; ++i) { + lpX = solution[i]; + if (lpX < lower[i]) { + solution[i] = lower[i]; + roundAgain = true; + ws->setStructStatus(i, CoinWarmStartBasis::atLowerBound); + } + else if (lpX > upper[i]) { + solution[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(solution, solver->getColSolution(), + numCols * sizeof(double)); + objValue = solver->getObjSense() * solver->getObjValue(); + } + } + else { + delete ws; + } + } + } //-------------------------------------------------- // If we have a set of first time object, @@ -318,8 +288,8 @@ MibSBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) //-------------------------------------------------- // Backup solver status and mark hot start. //-------------------------------------------------- - saveLower = new double[numCols]; - saveUpper = new double[numCols]; + double * saveLower = new double[numCols]; + double * saveUpper = new double[numCols]; memcpy(saveLower, lower, numCols * sizeof(double)); memcpy(saveUpper, upper, numCols * sizeof(double)); @@ -340,7 +310,7 @@ MibSBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) colInd = firstObjects[i]->columnIndex(); - lpX = saveSolution[colInd]; + lpX = solution[colInd]; BlisStrongBranch(model, objValue, colInd, lpX, saveLower, saveUpper, @@ -387,10 +357,12 @@ MibSBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) //-------------------------------------------------- solver->unmarkHotStart(); - solver->setColSolution(saveSolution); + solver->setColSolution(solution); solver->setIntParam(OsiMaxNumIterationHotStart, saveLimit); solver->setWarmStart(ws); delete ws; + delete [] saveLower; + delete [] saveUpper; } if (bStatus < 0) { @@ -444,10 +416,7 @@ MibSBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) delete [] ubInd; delete [] newLB; delete [] newUB; - delete [] saveSolution; - delete [] saveLower; - delete [] saveUpper; - delete [] fixedVar; + delete [] solution; delete [] candidate; return bStatus; diff --git a/src/MibSBranchStrategyStrong.cpp b/src/MibSBranchStrategyStrong.cpp index 9189a49b..2406efec 100644 --- a/src/MibSBranchStrategyStrong.cpp +++ b/src/MibSBranchStrategyStrong.cpp @@ -86,7 +86,7 @@ MibSBranchStrategyStrong::createCandBranchObjects(int numPassesLeft, double ub) double etol = mibsmodel->etol_; int uN = mibsmodel->upperDim_; int * upperColInd = mibsmodel->getUpperColInd(); - int * fixedInd = mibsmodel->fixedInd_; + int * varType = mibsmodel->varType_; char * colType = mibsmodel->colType_; // If upper-level variable is fixed -> fixedVar = 1 @@ -169,18 +169,21 @@ MibSBranchStrategyStrong::createCandBranchObjects(int numPassesLeft, double ub) value = saveSolution[i]; infeasibility = fabs(floor(value + 0.5) - value); if(branchPar == MibSBranchingStrategyLinking){ - if((fixedInd[i] == 1) && (fabs(infeasibility) > etol)){ - found = 1; - break; + if((varType[i] == MibSVarLinking) && + (fabs(infeasibility) > etol)){ + found = 1; + break; } - if((bS->isLinkVarsFixed_ == true) && (bS->isIntegral_ == false)){ + if((bS->isLinkVarsFixed_ == true) && + (bS->isIntegral_ == false)){ if(fabs(infeasibility) > etol){ candidate[i] = 1; } } - else if((fixedInd[i] == 1) && (((found == 0) && - (fixedVar[i] != 1)) || - (fabs(infeasibility) > etol))){ + else if((varType[i] == MibSVarLinking) && + (((found == 0) && + (fixedVar[i] != 1)) || + (fabs(infeasibility) > etol))){ candidate[i] = 1; } } diff --git a/src/MibSConstants.hpp b/src/MibSConstants.hpp index bf7d13bc..05dd7104 100644 --- a/src/MibSConstants.hpp +++ b/src/MibSConstants.hpp @@ -30,6 +30,14 @@ //############################################################################# +enum MibSVarType{ + MibSVarUpper, + MibSVarLinking, + MibSVarLower, +}; + +//############################################################################# + enum MibSSolType{ MibSNoSol = -1, MibSRelaxationSol, @@ -41,7 +49,8 @@ enum MibSSolType{ enum MibSBranchingStrategy{ MibSBranchingStrategyNotSet = -1, MibSBranchingStrategyFractional, - MibSBranchingStrategyLinking + MibSBranchingStrategyLinking, + MibSBranchingStrategyLower }; //############################################################################# diff --git a/src/MibSCutGenerator.cpp b/src/MibSCutGenerator.cpp index e0b1c0ed..763ffbcb 100644 --- a/src/MibSCutGenerator.cpp +++ b/src/MibSCutGenerator.cpp @@ -1709,14 +1709,14 @@ MibSCutGenerator::storeBestSolHypercubeIC(const double* lpSol, double optLowerOb int lN(localModel_->getLowerDim()); double objVal(0.0); //double startTimeUB(0.0); - int * fixedInd = localModel_->getFixedInd(); + int * varType = localModel_->getVarType(); int useLinkingSolutionPool(localModel_->MibSPar_->entry (MibSParams::useLinkingSolutionPool)); std::vector linkSol; for(i = 0; i < uN + lN; i++){ - if(fixedInd[i] == 1){ + if(varType[i] == MibSVarLinking){ linkSol.push_back(lpSol[i]); } } @@ -1843,7 +1843,7 @@ void MibSCutGenerator::getAlphaHypercubeIC(double** extRay, int numStruct, int numNonBasic, std::vector &alphaVec) { - int * fixedInd = localModel_->getFixedInd(); + int * varType = localModel_->getVarType(); double etol(localModel_->etol_); int i(0), j(0); @@ -1853,7 +1853,7 @@ MibSCutGenerator::getAlphaHypercubeIC(double** extRay, int numStruct, int numNon for(i = 0; i < numNonBasic; i++){ alphaVec[i] = -1; for(j = 0; j < numStruct; j++){ - if(fixedInd[j] == 1){ + if(varType[j] == MibSVarLinking){ coeff = extRay[i][j]; if(coeff > etol){ mult = 1; @@ -1898,7 +1898,7 @@ MibSCutGenerator::storeBestSolTenderIC(const double* lpSol, double optLowerObj) int * uColIndices = localModel_->getUpperColInd(); int * lColIndices = localModel_->getLowerColInd(); int * lRowIndices = localModel_->getLowerRowInd(); - int * fixedInd = localModel_->getFixedInd(); + int * varType = localModel_->getVarType(); const double * uObjCoeffs = oSolver->getObjCoefficients(); double * lObjCoeffs = localModel_->getLowerObjCoeffs(); double * colUb = new double[numCols]; @@ -2004,7 +2004,7 @@ MibSCutGenerator::storeBestSolTenderIC(const double* lpSol, double optLowerObj) cnt++; indexRow = lRowIndices[i]; for(j = 0; j < numCols; j++){ - if(fixedInd[j] == 1){ + if(varType[j] == MibSVarLinking){ tmp = matrix->getCoefficient(indexRow, j); row.insert(j, tmp); rowLb[origNumRows+cnt] += tmp * lpSol[j]; @@ -2075,7 +2075,7 @@ MibSCutGenerator::getAlphaTenderIC(double** extRay, int numNonBasic, double etol(localModel_->etol_); int * uColIndices = localModel_->getUpperColInd(); int * lRowIndices = localModel_->getLowerRowInd(); - int * fixedInd = localModel_->getFixedInd(); + int * varType = localModel_->getVarType(); int withULVarSize(0); int * withULVar = new int[lRows](); @@ -2105,7 +2105,7 @@ MibSCutGenerator::getAlphaTenderIC(double** extRay, int numNonBasic, indexRow = lRowIndices[j]; coeff = 0; for(k = 0; k < numCols; k++){ - if(fixedInd[k] == 1){ + if(varType[k] == MibSVarLinking){ tmp = matrix->getCoefficient(indexRow, k); coeff += tmp * extRay[i][k]; } @@ -2698,7 +2698,7 @@ MibSCutGenerator::solveLeafNode(int leafNodeIndex, bool *isTimeLimReached) double *lObjCoeffs = localModel_->getLowerObjCoeffs(); int *uColInd = localModel_->getUpperColInd(); int *lColInd = localModel_->getLowerColInd(); - int *fixedInd = localModel_->getFixedInd(); + int *varType = localModel_->getVarType(); double *leafColLb = new double[numCols]; double *leafColUb = new double[numCols]; @@ -2748,7 +2748,7 @@ MibSCutGenerator::solveLeafNode(int leafNodeIndex, bool *isTimeLimReached) memcpy(upperSol, newColLb, sizeof(double) * numCols); for(i = 0; i < uCols; i++){ index = uColInd[i]; - if(fixedInd[index] == 1){ + if(varType[index] == MibSVarLinking){ if(fabs(newColLb[index] - newColUb[index]) <= etol){ value = floor(newColLb[index] + 0.5); linkSol.push_back(floor(value)); @@ -3196,7 +3196,7 @@ MibSCutGenerator::generalizedNoGoodCut(BcpsConstraintPool &conPool) const double * sol = solver->getColSolution(); int uN(localModel_->upperDim_); int * upperColInd = localModel_->getUpperColInd(); - int * fixedInd = localModel_->getFixedInd(); + int * varType = localModel_->getVarType(); int i(0), index(0); double cutub(- 1.0); @@ -3235,7 +3235,7 @@ MibSCutGenerator::generalizedNoGoodCut(BcpsConstraintPool &conPool) for(i = 0; i < uN; i++){ index = upperColInd[i]; - if(fixedInd[index] == 1){ + if(varType[index] == MibSVarLinking){ indexList.push_back(index); if(sol[index] > etol){ valsList.push_back(1.0); @@ -4813,7 +4813,7 @@ MibSCutGenerator::generalWeakBendersBinaryCutCurrent(BcpsConstraintPool &conPool double etol(localModel_->etol_); int uN(localModel_->getUpperDim()); int lN(localModel_->getLowerDim()); - int *fixedInd(localModel_->getFixedInd()); + int *varType(localModel_->getVarType()); int *upperColInd(localModel_->getUpperColInd()); int *lowerColInd(localModel_->getLowerColInd()); double *lObjCoeffs(localModel_->getLowerObjCoeffs()); @@ -4843,7 +4843,7 @@ MibSCutGenerator::generalWeakBendersBinaryCutCurrent(BcpsConstraintPool &conPool for(i = 0; i < uN; i++){ index = upperColInd[i]; - if (fixedInd[index]){ + if (varType[index] == MibSVarLinking){ if (sol[index] < etol){ if (localModel_->colSignsA2_[i] != MibSModel::colSignPositive){ indexList.push_back(index); diff --git a/src/MibSHeuristic.cpp b/src/MibSHeuristic.cpp index 77159178..77940419 100644 --- a/src/MibSHeuristic.cpp +++ b/src/MibSHeuristic.cpp @@ -195,7 +195,7 @@ MibSHeuristic::lowerObjHeuristic() double * lObjCoeffs(model->getLowerObjCoeffs()); const double * uObjCoeffs(oSolver->getObjCoefficients()); //CoinPackedMatrix origMatrix = *model->origConstCoefMatrix_; - int * fixedInd = model->fixedInd_; + int * varType = model->varType_; MibSBilevel *bS = model->bS_; double * optUpperSolutionOrd = NULL; double * lSol = new double[lCols]; @@ -314,7 +314,7 @@ MibSHeuristic::lowerObjHeuristic() else{ optUpperSolutionOrd[i] = value; } - if(fixedInd[index] == 1){ + if(varType[index] == MibSVarLinking){ linkSol.push_back(optUpperSolutionOrd[i]); } } @@ -539,7 +539,7 @@ MibSHeuristic::objCutHeuristic() int * lColIndices = model->getLowerColInd(); const double * uObjCoeffs = oSolver->getObjCoefficients(); double * lObjCoeffs = model->getLowerObjCoeffs(); - int * fixedInd = model->fixedInd_; + int * varType = model->varType_; MibSLinkingPoolTag tagInSeenLinkingPool(bS->tagInSeenLinkingPool_); double *lSol = NULL; @@ -653,7 +653,7 @@ MibSHeuristic::objCutHeuristic() double *upperSolutionOrd = bS->upperSolutionOrd_; for(i = 0; i < uCols; i++){ index = uColIndices[i]; - if(fixedInd[index] == 1){ + if(varType[index] == MibSVarLinking){ linkSol.push_back(upperSolutionOrd[i]); } } @@ -790,7 +790,7 @@ MibSHeuristic::objCutHeuristic() else{ optUpperSolutionOrd[i] = value; } - if(fixedInd[index] == 1){ + if(varType[index] == MibSVarLinking){ linkSol.push_back(optUpperSolutionOrd[i]); } } @@ -1488,7 +1488,7 @@ MibSHeuristic::getBilevelSolution(const double * sol, double origLower, int tCols(oSolver->getNumCols()); int *uColIndices = model->getUpperColInd(); int *lColIndices = model->getLowerColInd(); - int *fixedInd = model->fixedInd_; + int *varType = model->varType_; const double *uObjCoeff = oSolver->getObjCoefficients(); double * colSol = new double[tCols]; @@ -1499,7 +1499,7 @@ MibSHeuristic::getBilevelSolution(const double * sol, double origLower, if(useLinkingSolutionPool){ for(i = 0; i < uCols; i++){ index = uColIndices[i]; - if(fixedInd[index] == 1){ + if(varType[index] == MibSVarLinking){ value = sol[index]; if((oSolver->isInteger(index)) && (((value - floor(value)) < etol) || diff --git a/src/MibSModel.cpp b/src/MibSModel.cpp index 889c156d..7e527a31 100644 --- a/src/MibSModel.cpp +++ b/src/MibSModel.cpp @@ -89,7 +89,7 @@ MibSModel::~MibSModel() if(lowerRowInd_) delete [] lowerRowInd_; if(inputLowerRowInd_) delete [] inputLowerRowInd_; if(structRowInd_) delete [] structRowInd_; - if(fixedInd_) delete [] fixedInd_; + if(varType_) delete [] varType_; if(interdictCost_) delete [] interdictCost_; if(origColLb_) delete [] origColLb_; if(origColUb_) delete [] origColUb_; @@ -164,7 +164,7 @@ MibSModel::initialize() lowerRowInd_ = NULL; inputLowerRowInd_ = NULL; structRowInd_ = NULL; - fixedInd_ = NULL; + varType_ = NULL; origColLb_ = NULL; origColUb_ = NULL; lColLbInLProb_ = NULL; @@ -1030,7 +1030,7 @@ MibSModel::readProblemData() delete [] colType; for (int i = 0; i < upperDim_; i++){ - if (fixedInd_[i] == 1){ + if (varType_[i] == MibSVarLinking){ if (colType_[i] == 'C'){ throw CoinError("All linking variables should be integer", "readProblemData", @@ -3469,25 +3469,27 @@ MibSModel::setRequiredFixedList() int rowIndex, posRow, start, end; int i, j; - if(!fixedInd_){ - fixedInd_ = new int[numVars_](); + if(!varType_){ + varType_ = new int[numVars_](); } for(i = 0; i < numVars_; i++){ - fixedInd_[i] = 0; if(binarySearch(0, uCols - 1, i, upperColInd) >= 0){ + varType_[i] = MibSVarUpper; start = matStarts[i]; end = start + colMatrix_->getVectorSize(i); for(j = start; j < end; j++){ rowIndex = matIndices[j]; posRow = binarySearch(0, lRows - 1, rowIndex, lowerRowInd); if(posRow >= 0){ - fixedInd_[i] = 1; + varType_[i] = MibSVarLinking; sizeFixedInd_ ++; break; } } - } + }else{ + varType_[i] = MibSVarLower; + } } } @@ -3533,7 +3535,7 @@ MibSModel::analyzeStructure() for (i = 0; i < numCols; i++){ if (colType_[i] != 'B'){ if (binarySearch(0, lCols - 1, i, lColIndices) < 0){ - if(fixedInd_[i] == 1){ + if(varType_[i] == MibSVarLinking){ allLinkingBin_ = false; } allUpperBin_ = false; diff --git a/src/MibSModel.hpp b/src/MibSModel.hpp index 30c456d2..92d8b223 100644 --- a/src/MibSModel.hpp +++ b/src/MibSModel.hpp @@ -189,7 +189,7 @@ class MibSModel : public BlisModel { int * structRowInd_; /** Indices of first-stage variables in second-stage constraints **/ - int * fixedInd_; + int * varType_; /** LL objective coefficients **/ double * lowerObjCoeffs_; @@ -498,7 +498,7 @@ class MibSModel : public BlisModel { int * getLowerRowInd() {return lowerRowInd_;} /** Get pointer to the UL columns in LL problem array **/ - int * getFixedInd() {return fixedInd_;} + int * getVarType() {return varType_;} /** Get pointer to the array of original column lower bounds **/ double * getOrigColLb() const {return origColLb_;} From 98564cd2cea3a0e1d1582d04534bce1b5608aa4b Mon Sep 17 00:00:00 2001 From: Ted Ralphs Date: Wed, 9 Aug 2023 21:33:49 -0400 Subject: [PATCH 2/5] Fixing a small bug and changing the name of a method --- src/MibSBranchStrategyPseudo.cpp | 23 +++++++++++++++-------- src/MibSModel.cpp | 4 ++-- src/MibSModel.hpp | 2 +- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/MibSBranchStrategyPseudo.cpp b/src/MibSBranchStrategyPseudo.cpp index 4189d98f..4ba5efd3 100644 --- a/src/MibSBranchStrategyPseudo.cpp +++ b/src/MibSBranchStrategyPseudo.cpp @@ -150,14 +150,21 @@ MibSBranchStrategyPseudo::createCandBranchObjects(int numPassesLeft, double ub) // Check for fractional linking variables if(branchPar == MibSBranchingStrategyLinking){ for (i = 0; i < numCols; ++i) { - if (fabs(floor(solution[i] + 0.5) - solution[i]) > etol){ - if (varType[i] == MibSVarLinking){ - fractionalLinkingVar = true; - break; - }else if (varType[i] == MibSVarLower){ - fractionalLowerVar = true; - break; - } + if (fabs(floor(solution[i] + 0.5) - solution[i]) > etol && + varType[i] == MibSVarLinking){ + fractionalLinkingVar = true; + break; + } + } + } + + // Check for fractional lower level variables variables + if(branchPar == MibSBranchingStrategyLower){ + for (i = 0; i < numCols; ++i) { + if (fabs(floor(solution[i] + 0.5) - solution[i]) > etol && + varType[i] == MibSVarLower){ + fractionalLowerVar = true; + break; } } } diff --git a/src/MibSModel.cpp b/src/MibSModel.cpp index 7e527a31..a110e70c 100644 --- a/src/MibSModel.cpp +++ b/src/MibSModel.cpp @@ -1439,7 +1439,7 @@ MibSModel::loadProblemData(const CoinPackedMatrix& matrix, //checkProblemType(); // checks if MibS can solve problem entered setProblemType(); //determine the type of MIBLP //determine the list of first-stage variables participate in second-stage constraints - setRequiredFixedList(); + setVarTypes(); } //############################################################################# @@ -3456,7 +3456,7 @@ MibSModel::decodeToSelf(AlpsEncoded& encoded) //############################################################################# void -MibSModel::setRequiredFixedList() +MibSModel::setVarTypes() { int uCols(upperDim_); int lRows(lowerRowNum_); diff --git a/src/MibSModel.hpp b/src/MibSModel.hpp index 92d8b223..452419a4 100644 --- a/src/MibSModel.hpp +++ b/src/MibSModel.hpp @@ -637,7 +637,7 @@ class MibSModel : public BlisModel { virtual void decodeToSelf(AlpsEncoded&); /** Determine the list of first-stage variables participate in second-stage constraints */ - void setRequiredFixedList(); + void setVarTypes(); /** Determines the properties of instance. */ void analyzeStructure(); From ed96800b5c2c93bcb4a4717ef6f0197ab8c7cbf7 Mon Sep 17 00:00:00 2001 From: Ted Ralphs Date: Wed, 16 Aug 2023 22:41:11 -0400 Subject: [PATCH 3/5] Disable tailing off detection whenever there is an integer solution, no matter what the branching strategy is. --- src/MibSTreeNode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MibSTreeNode.cpp b/src/MibSTreeNode.cpp index 10fa8f54..c3c5c962 100644 --- a/src/MibSTreeNode.cpp +++ b/src/MibSTreeNode.cpp @@ -385,8 +385,8 @@ MibSTreeNode::process(bool isRoot, bool rampUp) //if((bS->useBilevelBranching_ == false) && // (bS->LPSolStatus_ != MibSLPSolStatusFeasible)){ - if((((branchPar == MibSBranchingStrategyLinking) && (bS->isLinkVarsFixed_)) || - (branchPar == MibSBranchingStrategyFractional)) && (bS->isIntegral_)){ + if((branchPar == MibSBranchingStrategyLinking && bS->isLinkVarsFixed_) || + bS->isIntegral_){ tailOffTol = -1000; } else{ From c71e2392d9bcf4faaf0c4ef67ae42439dbd76319 Mon Sep 17 00:00:00 2001 From: Ted Ralphs Date: Wed, 30 Aug 2023 13:10:58 -0400 Subject: [PATCH 4/5] Changing the way tail off is set --- src/MibSTreeNode.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/MibSTreeNode.cpp b/src/MibSTreeNode.cpp index c3c5c962..02a5c734 100644 --- a/src/MibSTreeNode.cpp +++ b/src/MibSTreeNode.cpp @@ -385,11 +385,13 @@ MibSTreeNode::process(bool isRoot, bool rampUp) //if((bS->useBilevelBranching_ == false) && // (bS->LPSolStatus_ != MibSLPSolStatusFeasible)){ - if((branchPar == MibSBranchingStrategyLinking && bS->isLinkVarsFixed_) || - bS->isIntegral_){ - tailOffTol = -1000; - } - else{ + if ((depth_ == 0 || + (branchPar == MibSBranchingStrategyLinking && + bS->isLinkVarsFixed_) || + branchPar == MibSBranchingStrategyFractional) + && bS->isIntegral_){ + tailOffTol = -1; + } else{ tailOffTol = BlisPar->entry(BlisParams::tailOff); } @@ -421,7 +423,9 @@ MibSTreeNode::process(bool isRoot, bool rampUp) //------------------------------------------ if (model->boundingPass_ > 1) { - improvement = quality_ - preObjValue; + improvement = fabs(quality_) > 1 ? + fabs((quality_ - preObjValue)/quality_) : + quality_ - preObjValue; if (improvement > tailOffTol) { // NOTE: still need remove slacks, although // tailoff. From 7031abcd0f328276bc7bcfc2af0170574f4bfdf8 Mon Sep 17 00:00:00 2001 From: Ted Ralphs Date: Wed, 30 Aug 2023 21:42:28 -0400 Subject: [PATCH 5/5] Setting new default for tailoff parameter. --- src/MibSModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MibSModel.cpp b/src/MibSModel.cpp index a110e70c..5c957523 100644 --- a/src/MibSModel.cpp +++ b/src/MibSModel.cpp @@ -295,7 +295,7 @@ MibSModel::setBlisParameters() /* override defaults for some Blis paramters */ BlisPar()->setEntry(BlisParams::cutFactor, ALPS_DBL_MAX); BlisPar()->setEntry(BlisParams::cutPass, ALPS_INT_MAX); - BlisPar()->setEntry(BlisParams::tailOff, 1); + BlisPar()->setEntry(BlisParams::tailOff, .05); BlisPar()->setEntry(BlisParams::denseConFactor, ALPS_DBL_MAX); BlisPar()->setEntry(BlisParams::heurStrategy, 0);