Skip to content

Commit

Permalink
Merge pull request #132 from coin-or/cbcobjfix
Browse files Browse the repository at this point in the history
Improve the handling of subproblems with a constant in the objective
  • Loading branch information
andreaslundell authored Jul 12, 2021
2 parents 4742193 + 7270bcd commit c898dd8
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 21 deletions.
56 changes: 40 additions & 16 deletions src/MIPSolver/MIPSolverCbc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,15 +206,11 @@ bool MIPSolverCbc::finalizeObjective(bool isMinimize, double constant)
}

if(!isMinimize)
{
isMinimizationProblem = false;
coinModel->setObjectiveOffset(-constant);
}
else
{
isMinimizationProblem = true;
coinModel->setObjectiveOffset(constant);
}

this->objectiveConstant = constant;

coinModel->setOptimizationDirection(1.0);
}
Expand Down Expand Up @@ -296,6 +292,7 @@ bool MIPSolverCbc::finalizeProblem()
{
cbcModel->setLogLevel(0);
osiInterface->setHintParam(OsiDoReducePrint, false, OsiHintTry);
osiInterface->setDblParam(OsiObjOffset, this->objectiveConstant);
}

setSolutionLimit(1);
Expand Down Expand Up @@ -478,7 +475,7 @@ E_ProblemSolutionStatus MIPSolverCbc::getSolutionStatus()
{
E_ProblemSolutionStatus MIPSolutionStatus;

if(cbcModel->isProvenOptimal())
if(cbcModel->isProvenOptimal() && cbcModel->numberSavedSolutions() > 0)
{
MIPSolutionStatus = E_ProblemSolutionStatus::Optimal;
}
Expand All @@ -490,7 +487,7 @@ E_ProblemSolutionStatus MIPSolverCbc::getSolutionStatus()
{
MIPSolutionStatus = E_ProblemSolutionStatus::Unbounded;
}
else if(cbcModel->isSolutionLimitReached())
else if(cbcModel->isSolutionLimitReached() && cbcModel->numberSavedSolutions() > 0)
{
MIPSolutionStatus = E_ProblemSolutionStatus::SolutionLimit;
}
Expand Down Expand Up @@ -693,6 +690,7 @@ E_ProblemSolutionStatus MIPSolverCbc::solveProblem()
{
cbcModel->setLogLevel(0);
osiInterface->setHintParam(OsiDoReducePrint, false, OsiHintTry);
osiInterface->setDblParam(OsiObjOffset, this->objectiveConstant);
}

TerminationEventHandler eventHandler(env);
Expand Down Expand Up @@ -727,12 +725,16 @@ E_ProblemSolutionStatus MIPSolverCbc::solveProblem()
{
cbcModel->setLogLevel(0);
osiInterface->setHintParam(OsiDoReducePrint, false, OsiHintTry);
osiInterface->setDblParam(OsiObjOffset, this->objectiveConstant);
}

CbcMain1(numArguments, const_cast<const char**>(argv), *cbcModel, dummyCallback, solverData);

MIPSolutionStatus = getSolutionStatus();

if(MIPSolutionStatus == E_ProblemSolutionStatus::Optimal)
MIPSolutionStatus = E_ProblemSolutionStatus::Feasible;

osiInterface->setColBounds(getDualAuxiliaryObjectiveVariableIndex(), -getUnboundedVariableBoundValue(),
getUnboundedVariableBoundValue());
}
Expand Down Expand Up @@ -806,12 +808,16 @@ E_ProblemSolutionStatus MIPSolverCbc::solveProblem()
{
cbcModel->setLogLevel(0);
osiInterface->setHintParam(OsiDoReducePrint, false, OsiHintTry);
osiInterface->setDblParam(OsiObjOffset, this->objectiveConstant);
}

CbcMain1(numArguments, const_cast<const char**>(argv), *cbcModel, dummyCallback, solverData);

MIPSolutionStatus = getSolutionStatus();

if(MIPSolutionStatus == E_ProblemSolutionStatus::Optimal)
MIPSolutionStatus = E_ProblemSolutionStatus::Feasible;

for(auto& P : originalObjectiveCoefficients)
{
osiInterface->setObjCoeff(P.index, P.value);
Expand Down Expand Up @@ -930,6 +936,7 @@ bool MIPSolverCbc::repairInfeasibility()
{
cbcModel->setLogLevel(0);
osiInterface->setHintParam(OsiDoReducePrint, false, OsiHintTry);
osiInterface->setDblParam(OsiObjOffset, this->objectiveConstant);
}

cachedSolutionHasChanged = true;
Expand Down Expand Up @@ -1166,13 +1173,13 @@ void MIPSolverCbc::setCutOff(double cutOff)
{
this->cutOff = cutOff + cutOffTol;

env->output->outputDebug(fmt::format(" Setting cutoff value to {} for minimization.", this->cutOff));
env->output->outputDebug(fmt::format(" Setting cutoff value to {} for minimization.", this->cutOff));
}
else
{
this->cutOff = -1 * (cutOff + cutOffTol);

env->output->outputDebug(fmt::format(" Setting cutoff value to {} for maximization.", this->cutOff));
env->output->outputDebug(fmt::format(" Setting cutoff value to {} for maximization.", this->cutOff));
}
}

Expand All @@ -1186,10 +1193,21 @@ void MIPSolverCbc::setCutOffAsConstraint([[maybe_unused]] double cutOff)
if(!cutOffConstraintDefined)
{
if(isMinimizationProblem)
osiInterface->addRow(objectiveLinearExpression, -osiInterface->getInfinity(), cutOff, "CUTOFF_C");
{
osiInterface->addRow(objectiveLinearExpression, -osiInterface->getInfinity(),
(cutOff - this->objectiveConstant), "CUTOFF_C");

env->output->outputDebug(
" Setting cutoff constraint to " + Utilities::toString(cutOff) + " for minimization.");
}
else
osiInterface->addRow(
objectiveLinearExpression, -osiInterface->getInfinity(), -1.0 * cutOff, "CUTOFF_C");
{
osiInterface->addRow(objectiveLinearExpression, -osiInterface->getInfinity(),
-1.0 * (cutOff - this->objectiveConstant), "CUTOFF_C");

env->output->outputDebug(
" Setting cutoff constraint value to " + Utilities::toString(cutOff) + " for maximization.");
}

allowRepairOfConstraint.push_back(false);

Expand All @@ -1202,14 +1220,14 @@ void MIPSolverCbc::setCutOffAsConstraint([[maybe_unused]] double cutOff)
{
if(isMinimizationProblem)
{
osiInterface->setRowUpper(cutOffConstraintIndex, cutOff);
osiInterface->setRowUpper(cutOffConstraintIndex, cutOff - this->objectiveConstant);

env->output->outputDebug(
" Setting cutoff constraint to " + Utilities::toString(cutOff) + " for minimization.");
" Setting cutoff constraint value to " + Utilities::toString(cutOff) + " for minimization.");
}
else
{
osiInterface->setRowUpper(cutOffConstraintIndex, -cutOff);
osiInterface->setRowUpper(cutOffConstraintIndex, -(cutOff - this->objectiveConstant));

env->output->outputDebug(
" Setting cutoff constraint value to " + Utilities::toString(cutOff) + " for maximization.");
Expand Down Expand Up @@ -1279,6 +1297,8 @@ double MIPSolverCbc::getObjectiveValue(int solIdx)
objectiveValue += factor * objectiveLinearExpression.getElements()[i]
* variableSolution[objectiveLinearExpression.getIndices()[i]];
}

objectiveValue += this->objectiveConstant;
}
catch(std::exception& e)
{
Expand Down Expand Up @@ -1651,6 +1671,10 @@ double MIPSolverCbc::getDualObjectiveValue()
{
objVal = getObjectiveValue();
}
else
{
objVal = cbcModel->getBestPossibleObjValue();
}
}
catch(std::exception& e)
{
Expand Down
1 change: 1 addition & 0 deletions src/MIPSolver/MIPSolverCbc.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ class MIPSolverCbc : public IMIPSolver, MIPSolverBase
double timeLimit = 1e100;
double cutOff;
int numberOfThreads = 1;
double objectiveConstant = 0.0;

std::vector<std::pair<std::string, double>> MIPStart;

Expand Down
6 changes: 4 additions & 2 deletions src/MIPSolver/MIPSolverCplex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1220,13 +1220,15 @@ void MIPSolverCplex::setCutOffAsConstraint(double cutOff)
{
if(env->reformulatedProblem->objectiveFunction->properties.isMaximize)
{
cplexConstrs[cutOffConstraintIndex].setLB(cutOff);
cplexConstrs[cutOffConstraintIndex].setLB(
cutOff - env->reformulatedProblem->objectiveFunction->constant);
env->output->outputDebug(
" Setting cutoff constraint value to " + Utilities::toString(cutOff) + " for maximization.");
}
else
{
cplexConstrs[cutOffConstraintIndex].setUB(cutOff);
cplexConstrs[cutOffConstraintIndex].setUB(
cutOff - env->reformulatedProblem->objectiveFunction->constant);
env->output->outputDebug(
" Setting cutoff constraint to " + Utilities::toString(cutOff) + " for minimization.");
}
Expand Down
4 changes: 2 additions & 2 deletions src/MIPSolver/MIPSolverGurobi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1158,13 +1158,13 @@ void MIPSolverGurobi::setCutOffAsConstraint(double cutOff)

if(env->reformulatedProblem->objectiveFunction->properties.isMaximize)
{
constraint.set(GRB_DoubleAttr_RHS, -cutOff);
constraint.set(GRB_DoubleAttr_RHS, -(cutOff - env->reformulatedProblem->objectiveFunction->constant));
env->output->outputDebug(
" Setting cutoff constraint value to " + Utilities::toString(cutOff) + " for maximization.");
}
else
{
constraint.set(GRB_DoubleAttr_RHS, cutOff);
constraint.set(GRB_DoubleAttr_RHS, cutOff - env->reformulatedProblem->objectiveFunction->constant);
env->output->outputDebug(
" Setting cutoff constraint to " + Utilities::toString(cutOff) + " for minimization.");
}
Expand Down
2 changes: 1 addition & 1 deletion src/Tasks/TaskReformulateProblem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ void TaskReformulateProblem::reformulateObjectiveFunction()
if(copyOriginalLinearTerms)
copyLinearTermsToObjectiveFunction(
std::dynamic_pointer_cast<LinearObjectiveFunction>(env->problem->objectiveFunction)->linearTerms,
std::dynamic_pointer_cast<LinearObjectiveFunction>(objective), isSignReversed);
std::dynamic_pointer_cast<LinearObjectiveFunction>(objective));

if(destinationLinearTerms.size() > 0)
std::dynamic_pointer_cast<LinearObjectiveFunction>(objective)->add(destinationLinearTerms);
Expand Down

0 comments on commit c898dd8

Please sign in to comment.