Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding parameters to allow more fine-grained control of cut generation #145

Merged
merged 9 commits into from
Nov 24, 2024
20 changes: 14 additions & 6 deletions src/MibSBilevel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,19 @@ MibSBilevel::createBilevel(CoinPackedVector* sol,
(model_->MibSPar_->entry(MibSParams::branchStrategy));

bool solveSecondLevelEveryIteration(model_->MibSPar_->entry
(MibSParams::solveSecondLevelEveryIteration) == PARAM_ON);
(MibSParams::solveSecondLevelEveryIteration) == PARAM_ON);
bool solveSecondLevelEveryIterationRoot(model_->MibSPar_->entry
(MibSParams::solveSecondLevelEveryIterationRoot) == PARAM_ON);
bool solveSecondLevelWhenXYVarsInt(model_->MibSPar_->entry
(MibSParams::solveSecondLevelWhenXYVarsInt) == PARAM_ON);
(MibSParams::solveSecondLevelWhenXYVarsInt) == PARAM_ON);
bool solveSecondLevelWhenXVarsInt(model_->MibSPar_->entry
(MibSParams::solveSecondLevelWhenXVarsInt) == PARAM_ON);
(MibSParams::solveSecondLevelWhenXVarsInt) == PARAM_ON);
bool solveSecondLevelWhenYVarsInt(model_->MibSPar_->entry
(MibSParams::solveSecondLevelWhenYVarsInt) == PARAM_ON);
bool solveSecondLevelWhenLVarsInt(model_->MibSPar_->entry
(MibSParams::solveSecondLevelWhenLVarsInt) == PARAM_ON);
(MibSParams::solveSecondLevelWhenLVarsInt) == PARAM_ON);
bool solveSecondLevelWhenLVarsFixed(model_->MibSPar_->entry
(MibSParams::solveSecondLevelWhenLVarsFixed) == PARAM_ON);
(MibSParams::solveSecondLevelWhenLVarsFixed) == PARAM_ON);
int cutStrategy(model_->MibSPar_->entry
(MibSParams::cutStrategy));

Expand Down Expand Up @@ -239,11 +243,14 @@ MibSBilevel::createBilevel(CoinPackedVector* sol,
isLinkVarsFixed_) ||
(branchPar == MibSBranchingStrategyFractional && isIntegral_) ||
(solveSecondLevelEveryIteration) ||
(solveSecondLevelEveryIterationRoot &&
model_->activeNode_->getDepth() == 0) ||
(solveSecondLevelWhenXYVarsInt && isIntegral_) ||
(solveSecondLevelWhenXVarsInt && isUpperIntegral_) ||
(solveSecondLevelWhenYVarsInt && isLowerIntegral_) ||
(solveSecondLevelWhenLVarsInt && isLinkVarsIntegral_) ||
(solveSecondLevelWhenLVarsFixed && isLinkVarsFixed_ )))){
storeSol = checkBilevelFeasibility(mibs->isRoot_);
storeSol = checkBilevelFeasibility(mibs->isRoot_);
}
}

Expand Down Expand Up @@ -420,6 +427,7 @@ MibSBilevel::checkBilevelFeasibility(bool isRoot)
}else{
startTimeVF = model_->broker_->subTreeTimer().getTime();
lSolver->branchAndBound();
//lSolver->writeLp("water");
model_->timerVF_ += model_->broker_->subTreeTimer().getTime() - startTimeVF;
}

Expand Down
24 changes: 24 additions & 0 deletions src/MibSConstants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,30 @@ enum MibSBilevelFreeSetTypeISIC{

//#############################################################################

enum MibSIDICGenStrategy{
MibSIDICGenStrategyNotSet = -1,
MibSIDICGenStrategyAlways,
MibSIDICGenStrategyAlwaysRoot,
MibSIDICGenStrategyXYInt,
MibSIDICGenStrategyLInt,
MibSIDICGenStrategyYInt,
MibSIDICGenStrategyYLInt
};

//#############################################################################

enum MibSISICGenStrategy{
MibSISICGenStrategyNotSet = -1,
MibSISICGenStrategyAlways,
MibSISICGenStrategyAlwaysRoot,
MibSISICGenStrategyXYInt,
MibSISICGenStrategyLInt,
MibSISICGenStrategyYInt,
MibSISICGenStrategyYLInt,
};

//#############################################################################

enum MibSRelaxTypeParamBoundCut{
MibSRelaxTypeParamBoundCutLP = 0,
MibSRelaxTypeParamBoundCutMIP
Expand Down
199 changes: 152 additions & 47 deletions src/MibSCutGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,14 +302,13 @@ MibSCutGenerator::feasibilityCuts(BcpsConstraintPool &conPool)
= localModel_->MibSPar_->entry(MibSParams::useValFuncCut);

if(useIntegerNoGoodCut && !useValFuncCut){
return bilevelFeasCut1(conPool) ? true : false;
return bilevelFeasCut1(conPool);
}
else if(!useIntegerNoGoodCut && useValFuncCut){
return bilevelFeasCut2(conPool) ? true : false;
return bilevelFeasCut2(conPool);
}
else if(useIntegerNoGoodCut && useValFuncCut){
return ((bilevelFeasCut1(conPool) ? true : false) ||
(bilevelFeasCut2(conPool) ? true : false));
return (bilevelFeasCut1(conPool) + bilevelFeasCut2(conPool));
}
else{
//std::cout << "No MIBS Cuts generated" << std::endl;
Expand Down Expand Up @@ -828,7 +827,7 @@ MibSCutGenerator::findLowerLevelSolImprovingSolutionIC(double *uselessIneqs,
double infinity(oSolver->getInfinity());
int i, j;
int index(0), cntInt(0);
double lObjVal(0.0), value(0.0);
double lObjVal(0.0);
int uCols(localModel_->getUpperDim());
int lCols(localModel_->getLowerDim());
int lRows(localModel_->getLowerRowNum());
Expand Down Expand Up @@ -5870,22 +5869,26 @@ MibSCutGenerator::generateConstraints(BcpsConstraintPool &conPool)
int useBendersBinaryCut
= localModel_->MibSPar_->entry(MibSParams::useBendersBinaryCut);

int useFractionalCuts =
localModel_->MibSPar_->entry(MibSParams::useFractionalCuts);
int IDICGenStrategy =
localModel_->MibSPar_->entry(MibSParams::IDICGenStrategy);

int useFractionalCutsRootOnly =
localModel_->MibSPar_->entry(MibSParams::useFractionalCutsRootOnly);
int ISICGenStrategy =
localModel_->MibSPar_->entry(MibSParams::ISICGenStrategy);

double relaxedObjVal = localModel_->bS_->getLowerObj(
localModel_->solver()->getColSolution(),
localModel_->getLowerObjSense());

bool haveSecondLevelSol = ((useLinkingSolutionPool == PARAM_ON &&
bS->isLinkVarsIntegral_ &&
bS->tagInSeenLinkingPool_ != MibSLinkingPoolTagIsNotSet &&
bS->tagInSeenLinkingPool_ != MibSLinkingPoolTagLowerIsInfeasible) ||
(useLinkingSolutionPool != PARAM_ON &&
((useLinkingSolutionPool != PARAM_ON ||
!bS->isLinkVarsIntegral_) &&
bS->isLowerSolved_ != false &&
bS->isProvenOptimal_ != false));

int returnVal(0);

if ((useBoundCut) && (localModel_->boundingPass_ <= 1)){

Expand Down Expand Up @@ -5951,27 +5954,43 @@ MibSCutGenerator::generateConstraints(BcpsConstraintPool &conPool)
int bendersInterdictionCutType =
localModel_->MibSPar_->entry(MibSParams::bendersInterdictionCutType);
if(bendersInterdictionCutType == MibSBendersInterdictionCutTypeJustOneCut){
numCuts += bendersInterdictionOneCut(conPool,
returnVal = bendersInterdictionOneCut(conPool,
bS->optLowerSolutionOrd_);
}
else{
numCuts += bendersInterdictionMultipleCuts(conPool);
}
returnVal = bendersInterdictionMultipleCuts(conPool);
}
numCuts += returnVal;
localModel_->counterBendersInterdict_ += returnVal;
}

if (useImprovingSolutionIC == PARAM_ON){
cutType = MibSIntersectionCutImprovingSolution;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
returnVal = intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
if (returnVal){
localModel_->counterXYIntISIC_++;
}else{
localModel_->counterXYIntISICFail_++;
}
numCuts += returnVal;
}

if (useImprovingDirectionIC == PARAM_ON){
cutType = MibSIntersectionCutImprovingDirection;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
returnVal = intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
if (returnVal){
localModel_->counterXYIntIDIC_++;
}else{
localModel_->counterXYIntIDICFail_++;
}
numCuts += returnVal;
}

if (useHypercubeIC == PARAM_ON){
cutType = MibSIntersectionCutHypercube;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
returnVal = intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
localModel_->counterHypercubeIC_ += returnVal;
numCuts += returnVal;
}

if (useTenderIC == PARAM_ON){
Expand All @@ -5985,15 +6004,21 @@ MibSCutGenerator::generateConstraints(BcpsConstraintPool &conPool)
}

if (useGeneralizedNoGoodCut == PARAM_ON){
numCuts += generalizedNoGoodCut(conPool);
returnVal = generalizedNoGoodCut(conPool);
localModel_->counterGeneralizedNoGood_ += returnVal;
numCuts += returnVal;
}

if (useBendersBinaryCut == PARAM_ON &&
relaxedObjVal > localModel_->bS_->objVal_ + localModel_->etol_){
numCuts += bendersBinaryCut(conPool);
returnVal = bendersBinaryCut(conPool);
localModel_->counterBendersBinary_ += returnVal;
numCuts += returnVal;
}

numCuts += feasibilityCuts(conPool) ? true : false;
returnVal = feasibilityCuts(conPool);
localModel_->counterBendersInterdict_ += returnVal;
numCuts += returnVal;

//This return value indicates whether the relaxation needs to be re-solved
//and should always be false (see BlisTreeNode.cpp)
Expand All @@ -6005,58 +6030,138 @@ MibSCutGenerator::generateConstraints(BcpsConstraintPool &conPool)
int bendersInterdictionCutType =
localModel_->MibSPar_->entry(MibSParams::bendersInterdictionCutType);
if(bendersInterdictionCutType == MibSBendersInterdictionCutTypeJustOneCut){
numCuts += bendersInterdictionOneCut(conPool,
bS->optLowerSolutionOrd_);
returnVal = bendersInterdictionOneCut(conPool,
bS->optLowerSolutionOrd_);
}else{
returnVal = bendersInterdictionMultipleCuts(conPool);
}
else{
numCuts += bendersInterdictionMultipleCuts(conPool);
}
localModel_->counterBendersInterdict_ += returnVal;
numCuts += returnVal;
}
if (useImprovingSolutionIC == PARAM_ON && ((haveSecondLevelSol &&
relaxedObjVal > localModel_->bS_->objVal_ + localModel_->etol_) ||
localModel_->MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) == 1)){
cutType = MibSIntersectionCutImprovingSolution;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
}

if (useFractionalCuts && useImprovingDirectionIC == PARAM_ON){
if (useImprovingDirectionIC == PARAM_ON &&
(IDICGenStrategy == MibSIDICGenStrategyLInt ||
IDICGenStrategy == MibSIDICGenStrategyYLInt ||
IDICGenStrategy == MibSIDICGenStrategyAlways ||
(IDICGenStrategy == MibSIDICGenStrategyAlwaysRoot &&
localModel_->activeNode_->getDepth() == 0))){
cutType = MibSIntersectionCutImprovingDirection;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
returnVal = intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
if (returnVal){
localModel_->counterLIntIDIC_++;
}else{
localModel_->counterLIntIDICFail_++;
}
numCuts += returnVal;
}
if (useImprovingSolutionIC == PARAM_ON &&
((haveSecondLevelSol &&
relaxedObjVal > localModel_->bS_->objVal_ + localModel_->etol_) ||
(localModel_->MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) ==
MibSBilevelFreeSetTypeISICWithNewLLSol)) &&
(ISICGenStrategy == MibSISICGenStrategyLInt ||
ISICGenStrategy == MibSISICGenStrategyYLInt ||
ISICGenStrategy == MibSISICGenStrategyAlways ||
(ISICGenStrategy == MibSISICGenStrategyAlwaysRoot &&
localModel_->activeNode_->getDepth() == 0))){
cutType = MibSIntersectionCutImprovingSolution;
returnVal = intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
if (returnVal){
localModel_->counterLIntISIC_++;
}else{
localModel_->counterLIntISICFail_++;
}
numCuts += returnVal;
}

if (useHypercubeIC == PARAM_ON && haveSecondLevelSol){
cutType = MibSIntersectionCutHypercube;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
returnVal = intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
localModel_->counterHypercubeIC_ += returnVal;
numCuts += returnVal;
}

if (localModel_->allUpperBin_){
//problem with binary UL variables and integer LL variables
if (useGeneralizedNoGoodCut == PARAM_ON){
numCuts += generalizedNoGoodCut(conPool);
returnVal = generalizedNoGoodCut(conPool);
localModel_->counterGeneralizedNoGood_ += returnVal;
numCuts += returnVal;
}
if (useBendersBinaryCut == PARAM_ON &&
relaxedObjVal > localModel_->bS_->objVal_ + localModel_->etol_){
numCuts += bendersBinaryCut(conPool);
returnVal = bendersBinaryCut(conPool);
localModel_->counterBendersBinary_ += returnVal;
numCuts += returnVal;
}
}

//This return value indicates whether the relaxation needs to be re-solved
//and should always be false (see BlisTreeNode.cpp)
return (false);

}else if (bS->isLowerIntegral_ &&
(useFractionalCuts ||
(useFractionalCutsRootOnly &&
localModel_->activeNode_->getDepth() == 0))){
if (useImprovingDirectionIC == PARAM_ON){
}else if (bS->isLowerIntegral_){
if (useImprovingDirectionIC == PARAM_ON &&
(IDICGenStrategy == MibSIDICGenStrategyYInt ||
IDICGenStrategy == MibSIDICGenStrategyYLInt ||
IDICGenStrategy == MibSIDICGenStrategyAlways ||
(IDICGenStrategy == MibSIDICGenStrategyAlwaysRoot &&
localModel_->activeNode_->getDepth() == 0))){
cutType = MibSIntersectionCutImprovingDirection;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
returnVal = intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
if (returnVal){
localModel_->counterYIntIDIC_++;
}else{
localModel_->counterYIntIDICFail_++;
}
numCuts += returnVal;
}
if (useImprovingSolutionIC == PARAM_ON && ((haveSecondLevelSol &&
if (useImprovingSolutionIC == PARAM_ON &&
((haveSecondLevelSol &&
relaxedObjVal > localModel_->bS_->objVal_ + localModel_->etol_) ||
localModel_->MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) == 1)){
(localModel_->MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) ==
MibSBilevelFreeSetTypeISICWithNewLLSol &&
(ISICGenStrategy == MibSISICGenStrategyYInt ||
ISICGenStrategy == MibSISICGenStrategyYLInt ||
ISICGenStrategy == MibSISICGenStrategyAlways ||
(ISICGenStrategy == MibSISICGenStrategyAlwaysRoot &&
localModel_->activeNode_->getDepth() == 0))))){
cutType = MibSIntersectionCutImprovingSolution;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly as above, I guess MibSIDICGenStrategyYInt, MibSIDICGenStrategyAlways and MibSIDICGenStrategyAlwaysRoot should be replaced with MibSISICGenStrategyYInt, MibSISICGenStrategyAlways and MibSISICGenStrategyAlwaysRoot, respectively.

numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
returnVal = intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
if (returnVal){
localModel_->counterYIntISIC_++;
}else{
localModel_->counterYIntISICFail_++;
}
numCuts += returnVal;
}
}else{
if (useImprovingDirectionIC == PARAM_ON &&
(IDICGenStrategy == MibSIDICGenStrategyAlways ||
(IDICGenStrategy == MibSIDICGenStrategyAlwaysRoot &&
localModel_->activeNode_->getDepth() == 0))){
cutType = MibSIntersectionCutImprovingDirection;
returnVal = intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
if (returnVal){
localModel_->counterFracIDIC_++;
}else{
localModel_->counterFracIDICFail_++;
}
numCuts += returnVal;
}
if (useImprovingSolutionIC == PARAM_ON &&
((haveSecondLevelSol &&
relaxedObjVal > localModel_->bS_->objVal_ + localModel_->etol_) ||
(localModel_->MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) ==
MibSBilevelFreeSetTypeISICWithNewLLSol &&
(ISICGenStrategy == MibSIDICGenStrategyAlways ||
(ISICGenStrategy == MibSIDICGenStrategyAlwaysRoot &&
localModel_->activeNode_->getDepth() == 0))))){
cutType = MibSIntersectionCutImprovingSolution;
returnVal = intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
if (returnVal){
localModel_->counterFracISIC_++;
}else{
localModel_->counterFracISICFail_++;
}
numCuts += returnVal;
}
}

Expand Down
Loading
Loading