From 76f966e81567aa677cc72a8510d27c638e3f20af Mon Sep 17 00:00:00 2001 From: Andreas Lundell Date: Mon, 12 Jul 2021 12:41:26 +0300 Subject: [PATCH 1/4] Wrong sign for linear terms in reformulated problem --- src/Tasks/TaskReformulateProblem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tasks/TaskReformulateProblem.cpp b/src/Tasks/TaskReformulateProblem.cpp index 1c1afb2d..ee887de0 100644 --- a/src/Tasks/TaskReformulateProblem.cpp +++ b/src/Tasks/TaskReformulateProblem.cpp @@ -676,7 +676,7 @@ void TaskReformulateProblem::reformulateObjectiveFunction() if(copyOriginalLinearTerms) copyLinearTermsToObjectiveFunction( std::dynamic_pointer_cast(env->problem->objectiveFunction)->linearTerms, - std::dynamic_pointer_cast(objective), isSignReversed); + std::dynamic_pointer_cast(objective)); if(destinationLinearTerms.size() > 0) std::dynamic_pointer_cast(objective)->add(destinationLinearTerms); From 3767635b6f06b6be33dd737e753e777b98804476 Mon Sep 17 00:00:00 2001 From: Andreas Lundell Date: Mon, 12 Jul 2021 16:05:24 +0300 Subject: [PATCH 2/4] CPLEX and Gurobi: Fix for cutoff constraints in problems with a constant in the objective --- src/MIPSolver/MIPSolverCplex.cpp | 6 ++++-- src/MIPSolver/MIPSolverGurobi.cpp | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/MIPSolver/MIPSolverCplex.cpp b/src/MIPSolver/MIPSolverCplex.cpp index 30ebf670..0102dd62 100644 --- a/src/MIPSolver/MIPSolverCplex.cpp +++ b/src/MIPSolver/MIPSolverCplex.cpp @@ -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."); } diff --git a/src/MIPSolver/MIPSolverGurobi.cpp b/src/MIPSolver/MIPSolverGurobi.cpp index e0cdcb8e..026fd00d 100644 --- a/src/MIPSolver/MIPSolverGurobi.cpp +++ b/src/MIPSolver/MIPSolverGurobi.cpp @@ -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."); } From 2757238fa34ccb75b40bc6f30f25626db78ae84c Mon Sep 17 00:00:00 2001 From: Andreas Lundell Date: Mon, 12 Jul 2021 16:06:11 +0300 Subject: [PATCH 3/4] Cbc: Improve handling of problems with constant in objective function --- src/MIPSolver/MIPSolverCbc.cpp | 56 ++++++++++++++++++++++++---------- src/MIPSolver/MIPSolverCbc.h | 1 + 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/MIPSolver/MIPSolverCbc.cpp b/src/MIPSolver/MIPSolverCbc.cpp index 12101951..c3869a8f 100644 --- a/src/MIPSolver/MIPSolverCbc.cpp +++ b/src/MIPSolver/MIPSolverCbc.cpp @@ -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); } @@ -296,6 +292,7 @@ bool MIPSolverCbc::finalizeProblem() { cbcModel->setLogLevel(0); osiInterface->setHintParam(OsiDoReducePrint, false, OsiHintTry); + osiInterface->setDblParam(OsiObjOffset, this->objectiveConstant); } setSolutionLimit(1); @@ -478,7 +475,7 @@ E_ProblemSolutionStatus MIPSolverCbc::getSolutionStatus() { E_ProblemSolutionStatus MIPSolutionStatus; - if(cbcModel->isProvenOptimal()) + if(cbcModel->isProvenOptimal() && cbcModel->numberSavedSolutions() > 0) { MIPSolutionStatus = E_ProblemSolutionStatus::Optimal; } @@ -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; } @@ -693,6 +690,7 @@ E_ProblemSolutionStatus MIPSolverCbc::solveProblem() { cbcModel->setLogLevel(0); osiInterface->setHintParam(OsiDoReducePrint, false, OsiHintTry); + osiInterface->setDblParam(OsiObjOffset, this->objectiveConstant); } TerminationEventHandler eventHandler(env); @@ -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(argv), *cbcModel, dummyCallback, solverData); MIPSolutionStatus = getSolutionStatus(); + if(MIPSolutionStatus == E_ProblemSolutionStatus::Optimal) + MIPSolutionStatus = E_ProblemSolutionStatus::Feasible; + osiInterface->setColBounds(getDualAuxiliaryObjectiveVariableIndex(), -getUnboundedVariableBoundValue(), getUnboundedVariableBoundValue()); } @@ -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(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); @@ -930,6 +936,7 @@ bool MIPSolverCbc::repairInfeasibility() { cbcModel->setLogLevel(0); osiInterface->setHintParam(OsiDoReducePrint, false, OsiHintTry); + osiInterface->setDblParam(OsiObjOffset, this->objectiveConstant); } cachedSolutionHasChanged = true; @@ -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->outputInfo(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->outputInfo(fmt::format(" Setting cutoff value to {} for maximization.", this->cutOff)); } } @@ -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); @@ -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."); @@ -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) { @@ -1651,6 +1671,10 @@ double MIPSolverCbc::getDualObjectiveValue() { objVal = getObjectiveValue(); } + else + { + objVal = cbcModel->getBestPossibleObjValue(); + } } catch(std::exception& e) { diff --git a/src/MIPSolver/MIPSolverCbc.h b/src/MIPSolver/MIPSolverCbc.h index 4f7f6bff..224b76a2 100644 --- a/src/MIPSolver/MIPSolverCbc.h +++ b/src/MIPSolver/MIPSolverCbc.h @@ -196,6 +196,7 @@ class MIPSolverCbc : public IMIPSolver, MIPSolverBase double timeLimit = 1e100; double cutOff; int numberOfThreads = 1; + double objectiveConstant = 0.0; std::vector> MIPStart; From 7270bcdc9bfc7935d80741b1288f0d92c18e8534 Mon Sep 17 00:00:00 2001 From: Andreas Lundell Date: Mon, 12 Jul 2021 16:43:28 +0300 Subject: [PATCH 4/4] Correct sign in cutoff in Cbc --- src/MIPSolver/MIPSolverCbc.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/MIPSolver/MIPSolverCbc.cpp b/src/MIPSolver/MIPSolverCbc.cpp index c3869a8f..b7cc1a83 100644 --- a/src/MIPSolver/MIPSolverCbc.cpp +++ b/src/MIPSolver/MIPSolverCbc.cpp @@ -1173,13 +1173,13 @@ void MIPSolverCbc::setCutOff(double cutOff) { this->cutOff = cutOff + cutOffTol; - env->output->outputInfo(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->outputInfo(fmt::format(" Setting cutoff value to {} for maximization.", this->cutOff)); + env->output->outputDebug(fmt::format(" Setting cutoff value to {} for maximization.", this->cutOff)); } } @@ -1195,7 +1195,7 @@ void MIPSolverCbc::setCutOffAsConstraint([[maybe_unused]] double cutOff) if(isMinimizationProblem) { osiInterface->addRow(objectiveLinearExpression, -osiInterface->getInfinity(), - (cutOff + this->objectiveConstant), "CUTOFF_C"); + (cutOff - this->objectiveConstant), "CUTOFF_C"); env->output->outputDebug( " Setting cutoff constraint to " + Utilities::toString(cutOff) + " for minimization."); @@ -1203,7 +1203,7 @@ void MIPSolverCbc::setCutOffAsConstraint([[maybe_unused]] double cutOff) else { osiInterface->addRow(objectiveLinearExpression, -osiInterface->getInfinity(), - -1.0 * (cutOff + this->objectiveConstant), "CUTOFF_C"); + -1.0 * (cutOff - this->objectiveConstant), "CUTOFF_C"); env->output->outputDebug( " Setting cutoff constraint value to " + Utilities::toString(cutOff) + " for maximization."); @@ -1220,14 +1220,14 @@ void MIPSolverCbc::setCutOffAsConstraint([[maybe_unused]] double cutOff) { if(isMinimizationProblem) { - osiInterface->setRowUpper(cutOffConstraintIndex, cutOff + this->objectiveConstant); + osiInterface->setRowUpper(cutOffConstraintIndex, cutOff - this->objectiveConstant); env->output->outputDebug( " Setting cutoff constraint value to " + Utilities::toString(cutOff) + " for minimization."); } else { - osiInterface->setRowUpper(cutOffConstraintIndex, -(cutOff + this->objectiveConstant)); + osiInterface->setRowUpper(cutOffConstraintIndex, -(cutOff - this->objectiveConstant)); env->output->outputDebug( " Setting cutoff constraint value to " + Utilities::toString(cutOff) + " for maximization.");