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
18 changes: 13 additions & 5 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::solveSecondLevelWhenXVarsInt) == 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,8 +243,11 @@ 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_);
Expand Down Expand Up @@ -420,6 +427,7 @@ MibSBilevel::checkBilevelFeasibility(bool isRoot)
}else{
startTimeVF = model_->broker_->subTreeTimer().getTime();
lSolver->branchAndBound();
lSolver->writeLp("water");

Choose a reason for hiding this comment

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

I think this is a typo, shouldn't this be commented out?

model_->timerVF_ += model_->broker_->subTreeTimer().getTime() - startTimeVF;
}

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

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

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

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

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

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

enum MibSRelaxTypeParamBoundCut{
MibSRelaxTypeParamBoundCutLP = 0,
MibSRelaxTypeParamBoundCutMIP
Expand Down
67 changes: 52 additions & 15 deletions src/MibSCutGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5870,11 +5870,11 @@ 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(),
Expand Down Expand Up @@ -6012,14 +6012,25 @@ MibSCutGenerator::generateConstraints(BcpsConstraintPool &conPool)
numCuts += bendersInterdictionMultipleCuts(conPool);
}
}
if (useImprovingSolutionIC == PARAM_ON && ((haveSecondLevelSol &&
relaxedObjVal > localModel_->bS_->objVal_ + localModel_->etol_) ||
localModel_->MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) == 1)){
if (useImprovingSolutionIC == PARAM_ON &&
((haveSecondLevelSol &&
relaxedObjVal > localModel_->bS_->objVal_ + localModel_->etol_) ||
(localModel_->MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) ==
MibSBilevelFreeSetTypeISICWithNewLLSol &&
ISICGenStrategy == MibSIDICGenStrategyLInt))){
cutType = MibSIntersectionCutImprovingSolution;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
}

if (useFractionalCuts && useImprovingDirectionIC == PARAM_ON){
if (useImprovingDirectionIC == PARAM_ON &&
((haveSecondLevelSol &&
relaxedObjVal > localModel_->bS_->objVal_ + localModel_->etol_) ||
(localModel_->MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) ==
MibSBilevelFreeSetTypeISICWithNewLLSol &&
(ISICGenStrategy == MibSIDICGenStrategyLInt ||
ISICGenStrategy == MibSIDICGenStrategyAlways ||
(ISICGenStrategy == MibSIDICGenStrategyAlwaysRoot &&
localModel_->activeNode_->getDepth() == 0))))){
Copy link

@febattista febattista Oct 30, 2024

Choose a reason for hiding this comment

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

I can't make sense out of this straightforwardly. Here the code should decide whether to undertake the generation of an IDIC, but is checking for the bilevel free set type for ISIC and whether an improving solution is available or not. Moreover, I might be wrong but I guess here ISICGenStrategy should be replaced with IDICGenStrategy.

cutType = MibSIntersectionCutImprovingDirection;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
}
Expand All @@ -6044,17 +6055,43 @@ MibSCutGenerator::generateConstraints(BcpsConstraintPool &conPool)
//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 == MibSIDICGenStrategyAlways ||
IDICGenStrategy == MibSIDICGenStrategyYInt ||
(IDICGenStrategy == MibSIDICGenStrategyAlwaysRoot &&
localModel_->activeNode_->getDepth() == 0))){
cutType = MibSIntersectionCutImprovingDirection;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
}
if (useImprovingSolutionIC == PARAM_ON &&
((haveSecondLevelSol &&
relaxedObjVal > localModel_->bS_->objVal_ + localModel_->etol_) ||
(localModel_->MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) ==
MibSBilevelFreeSetTypeISICWithNewLLSol &&
(ISICGenStrategy == MibSIDICGenStrategyYInt ||
ISICGenStrategy == MibSIDICGenStrategyAlways ||
(ISICGenStrategy == MibSIDICGenStrategyAlwaysRoot &&
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);
}
}else{
if (useImprovingDirectionIC == PARAM_ON &&
(IDICGenStrategy == MibSIDICGenStrategyAlways ||
(IDICGenStrategy == MibSIDICGenStrategyAlwaysRoot &&
localModel_->activeNode_->getDepth() == 0))){
cutType = MibSIntersectionCutImprovingDirection;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
}
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 == MibSIDICGenStrategyAlways ||
(ISICGenStrategy == MibSIDICGenStrategyAlwaysRoot &&
localModel_->activeNode_->getDepth() == 0))))){
cutType = MibSIntersectionCutImprovingSolution;
numCuts += intersectionCuts(conPool, bS->optLowerSolutionOrd_, cutType);
}
Expand Down
102 changes: 79 additions & 23 deletions src/MibSModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3933,7 +3933,10 @@ MibSModel::adjustParameters()
}
}
if (MibSPar_->entry(MibSParams::useImprovingDirectionIC) == PARAM_ON){
defaultCutIsOn = true;
defaultCutIsOn = true;
if (MibSPar_->entry(MibSParams::IDICGenStrategy) == MibSIDICGenStrategyNotSet){
MibSPar()->setEntry(MibSParams::IDICGenStrategy, MibSIDICGenStrategyXYInt);
}
}

//Param: "MibS_useImprovingSolutionIC"
Expand All @@ -3958,15 +3961,36 @@ MibSModel::adjustParameters()
std::cout << std::endl;
MibSPar()->setEntry(MibSParams::useImprovingSolutionIC, PARAM_OFF);
}
if (MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) == 1 &&
isLowerObjInt_ == false){
if (MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) ==
MibSBilevelFreeSetTypeISICWithNewLLSol && isLowerObjInt_ == false){
std::cout << "The improving solution intersection cut (type II) are "
<< "only valid for problems with integer lower-level "
<< "objective coefficients.";
std::cout << std::endl;
MibSPar()->setEntry(MibSParams::useImprovingSolutionIC, PARAM_OFF);
}
}
if (MibSPar_->entry(MibSParams::useImprovingSolutionIC) == PARAM_ON){
switch (MibSPar_->entry(MibSParams::ISICGenStrategy)) {
case MibSISICGenStrategyNotSet:
MibSPar()->setEntry(MibSParams::ISICGenStrategy, MibSISICGenStrategyXYInt);
case MibSISICGenStrategyXYInt:
MibSPar()->setEntry(MibSParams::solveSecondLevelWhenXYVarsInt, 1);
break;
case MibSISICGenStrategyLInt:
MibSPar()->setEntry(MibSParams::solveSecondLevelWhenLVarsInt, 1);
break;
case MibSISICGenStrategyYInt:
MibSPar()->setEntry(MibSParams::solveSecondLevelWhenYVarsInt, 1);
break;
case MibSISICGenStrategyAlways:
MibSPar()->setEntry(MibSParams::solveSecondLevelEveryIteration, 1);
break;
case MibSISICGenStrategyAlwaysRoot:
MibSPar()->setEntry(MibSParams::solveSecondLevelEveryIterationRoot, 1);
break;
}
}

//Param: "MibS_useHyperCubeIC"
if ((turnOffDefaultCuts == true) &&
Expand Down Expand Up @@ -4155,36 +4179,68 @@ MibSModel::printProblemInfo(){
if (MibSPar_->entry(MibSParams::useImprovingSolutionIC) == PARAM_ON){
if (MibSPar_->entry(MibSParams::bilevelFreeSetTypeISIC) ==
MibSBilevelFreeSetTypeISICWithLLOptSol){
std::cout << "Improving solution intersection cut generator (Type I) is on." << std::endl;
std::cout << "Improving solution intersection cut generator "
<< "(Type I) is on." << std::endl;
}else{
std::cout << "Improving solution intersection cut generator (Type II) is on." << std::endl;
std::cout << "Improving solution intersection cut generator "
<< "(Type II) is on." << std::endl;
}
switch (MibSPar_->entry(MibSParams::ISICGenStrategy)){
case MibSISICGenStrategyLInt:
std::cout << "ISICs will be used to separate solutions "
<< "with integer linking variables." << std::endl;
break;
case MibSISICGenStrategyYInt:
std::cout << "ISICs will be used to separate solutions "
<< "with integer lower-level variables." << std::endl;
break;
case MibSISICGenStrategyXYInt:
std::cout << "ISICs will be used to separate only solutions "
<< "that are fully integer." << std::endl;
break;
case MibSISICGenStrategyAlwaysRoot:
std::cout << "ISICs will be used to separate fractional solutions "
<< "only in the root node." << std::endl;
break;
case MibSISICGenStrategyAlways:
std::cout << "ISICs will be used to separate all solutions."
<< std::endl;
break;
}
}

if (MibSPar_->entry(MibSParams::useImprovingDirectionIC) == PARAM_ON){
std::cout << "Improving direction intersection cut generator is on." << std::endl;
std::cout << "Improving direction intersection cut generator is on."
<< std::endl;
switch (MibSPar_->entry(MibSParams::IDICGenStrategy)){
case MibSIDICGenStrategyLInt:
std::cout << "IDICs will be used to separate solutions "
<< "with integer linking variables." << std::endl;
break;
case MibSIDICGenStrategyYInt:
std::cout << "IDICs will be used to separate solutions "
<< "with integer lower-level variables." << std::endl;
break;
case MibSIDICGenStrategyXYInt:
std::cout << "IDICs will be used to separate only solutions "
<< "that are fully integer." << std::endl;
break;
case MibSIDICGenStrategyAlwaysRoot:
std::cout << "IDICs will be used to separate fractional solutions "
<< "only in the root node." << std::endl;
break;
case MibSIDICGenStrategyAlways:
std::cout << "IDICs will be used to separate all solutions."
<< std::endl;
break;
}
}

if (MibSPar_->entry(MibSParams::useHypercubeIC) == PARAM_ON){
std::cout << "Hypercube intersection cut generator is on." << std::endl;
std::cout << "Hypercube intersection cut generator is on."
<< std::endl;
}

if (MibSPar_->entry(MibSParams::useImprovingSolutionIC) == PARAM_ON ||
MibSPar_->entry(MibSParams::useImprovingDirectionIC) == PARAM_ON){

if (MibSPar_->entry(MibSParams::useFractionalCutsRootOnly) == 1){
std::cout << "Fractional solutions will be seperated in the root node." << std::endl;
MibSPar_->setEntry(MibSParams::useFractionalCuts, 0);
}
if (MibSPar_->entry(MibSParams::useFractionalCuts) == 1){
std::cout << "Fractional solutions will be separated using intersection cuts."
<< std::endl;
}else{
std::cout << "Only integer solutions will be separated using intersection cuts."
<< std::endl;
}
}

if (MibSPar_->entry(MibSParams::solveSecondLevelEveryIteration) ==
PARAM_OFF &&
MibSPar_->entry(MibSParams::solveSecondLevelWhenXYVarsInt) ==
Expand Down
31 changes: 20 additions & 11 deletions src/MibSParams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,21 @@ MibSParams::createKeywordList() {
keys_.push_back(make_pair(std::string("MibS_useTypeIC"),
AlpsParameter(AlpsIntPar, useImprovingSolutionIC)));

keys_.push_back(make_pair(std::string("MibS_ISICGenStrategy"),
AlpsParameter(AlpsIntPar, ISICGenStrategy)));

keys_.push_back(make_pair(std::string("MibS_useImprovingDirectionIC"),
AlpsParameter(AlpsIntPar, useImprovingDirectionIC)));
//legacy parameter name
keys_.push_back(make_pair(std::string("MibS_useTypeWatermelon"),
AlpsParameter(AlpsIntPar, useImprovingDirectionIC)));

keys_.push_back(make_pair(std::string("MibS_IDICGenStrategy"),
AlpsParameter(AlpsIntPar, IDICGenStrategy)));

keys_.push_back(make_pair(std::string("MibS_useTypeWatermelon"),
AlpsParameter(AlpsIntPar, useImprovingDirectionIC)));

keys_.push_back(make_pair(std::string("MibS_useHypercubeIC"),
AlpsParameter(AlpsIntPar, useHypercubeIC)));

Expand All @@ -195,23 +204,23 @@ MibSParams::createKeywordList() {
keys_.push_back(make_pair(std::string("MibS_bilevelFreeSetTypeISIC"),
AlpsParameter(AlpsIntPar, bilevelFreeSetTypeISIC)));

keys_.push_back(make_pair(std::string("MibS_useFractionalCuts"),
AlpsParameter(AlpsIntPar, useFractionalCuts)));

keys_.push_back(make_pair(std::string("MibS_useFractionalCutsRootOnly"),
AlpsParameter(AlpsIntPar,
useFractionalCutsRootOnly)));

//solve lower-level Parameters
keys_.push_back(make_pair(std::string("MibS_solveSecondLevelEveryIteration"),
AlpsParameter(AlpsIntPar, solveSecondLevelEveryIteration)));

keys_.push_back(make_pair(std::string("MibS_solveSecondLevelEveryIterationRoot"),
AlpsParameter(AlpsIntPar,
solveSecondLevelEveryIterationRoot)));

keys_.push_back(make_pair(std::string("MibS_solveSecondLevelWhenXYVarsInt"),
AlpsParameter(AlpsIntPar, solveSecondLevelWhenXYVarsInt)));

keys_.push_back(make_pair(std::string("MibS_solveSecondLevelWhenXVarsInt"),
AlpsParameter(AlpsIntPar, solveSecondLevelWhenXVarsInt)));

keys_.push_back(make_pair(std::string("MibS_solveSecondLevelWhenYVarsInt"),
AlpsParameter(AlpsIntPar, solveSecondLevelWhenYVarsInt)));

keys_.push_back(make_pair(std::string("MibS_solveSecondLevelWhenLVarsInt"),
AlpsParameter(AlpsIntPar, solveSecondLevelWhenLVarsInt)));

Expand Down Expand Up @@ -384,18 +393,18 @@ MibSParams::setDefaultEntries() {

setEntry(useHybridIC, PARAM_NOTSET);

setEntry(useFractionalCuts, 1);

setEntry(useFractionalCutsRootOnly, 0);

setEntry(bilevelFreeSetTypeISIC, MibSBilevelFreeSetTypeISICWithLLOptSol);

setEntry(solveSecondLevelEveryIteration, PARAM_OFF);

setEntry(solveSecondLevelEveryIterationRoot, PARAM_OFF);

setEntry(solveSecondLevelWhenXYVarsInt, PARAM_ON);

setEntry(solveSecondLevelWhenXVarsInt, PARAM_OFF);

setEntry(solveSecondLevelWhenYVarsInt, PARAM_OFF);

setEntry(solveSecondLevelWhenLVarsInt, PARAM_OFF);

setEntry(solveSecondLevelWhenLVarsFixed, PARAM_ON);
Expand Down
Loading