Skip to content

Commit

Permalink
Merge pull request #7 from coin-or/cutoffnodelim
Browse files Browse the repository at this point in the history
User provided cutoff and node limit
  • Loading branch information
svigerske committed Oct 21, 2019
2 parents 22065ba + 96673b3 commit b4b10d6
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 23 deletions.
13 changes: 12 additions & 1 deletion src/MIPSolver/MIPSolverCbc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,17 @@ void MIPSolverCbc::initializeSolverSettings()
cbcModel->setCutoff(this->cutOff);
env->output->outputDebug(" Setting cutoff value to " + std::to_string(cutOff) + " for maximization.");
}

// Adds a user-provided node limit
if(env->settings->getSetting<double>("MIP.NodeLimit", "Dual") > 0)
{
auto nodeLimit = env->settings->getSetting<double>("MIP.NodeLimit", "Dual");

if(nodeLimit > SHOT_INT_MAX)
nodeLimit = SHOT_INT_MAX;

cbcModel->setMaximumNodes(nodeLimit);
}
}

int MIPSolverCbc::addLinearConstraint(
Expand Down Expand Up @@ -531,7 +542,7 @@ void MIPSolverCbc::setTimeLimit(double seconds)

void MIPSolverCbc::setCutOff(double cutOff)
{
double cutOffTol = env->settings->getSetting<double>("MIP.CutOffTolerance", "Dual");
double cutOffTol = env->settings->getSetting<double>("MIP.CutOff.Tolerance", "Dual");

try
{
Expand Down
12 changes: 12 additions & 0 deletions src/MIPSolver/MIPSolverCplex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,18 @@ void MIPSolverCplex::initializeSolverSettings()
cplexInstance.setParam(IloCplex::NodeFileInd, env->settings->getSetting<int>("Cplex.NodeFileInd", "Subsolver"));

cplexInstance.setParam(IloCplex::FeasOptMode, 2);

// Adds a user-provided node limit
if(env->settings->getSetting<double>("MIP.NodeLimit", "Dual") > 0)
{
auto nodeLimit = env->settings->getSetting<double>("MIP.NodeLimit", "Dual");

if(nodeLimit > SHOT_LONG_MAX)
nodeLimit = SHOT_LONG_MAX;

cplexInstance.setParam(
IloCplex::NodeLim, (CPXLONG)env->settings->getSetting<double>("MIP.NodeLimit", "Dual"));
}
}
catch(IloException& e)
{
Expand Down
2 changes: 1 addition & 1 deletion src/MIPSolver/MIPSolverCplexSingleTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ void CplexCallback::invoke(const IloCplex::Callback::Context& context)
// Adds cutoff
double cutOffTol
= env->settings->getSetting<double>("MIP.CutOffTolerance", "Dual");
= env->settings->getSetting<double>("MIP.CutOff.Tolerance", "Dual");
if(isMinimization)
{
Expand Down
11 changes: 9 additions & 2 deletions src/MIPSolver/MIPSolverGurobi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,10 +392,17 @@ void MIPSolverGurobi::initializeSolverSettings()
// gurobiModel->getEnv().set(GRB_DoubleParam_IntFeasTol, 1e-6);
// gurobiModel->getEnv().set(GRB_DoubleParam_OptimalityTol, 1e-6);
// gurobiModel->getEnv().set(GRB_DoubleParam_MarkowitzTol, 1e-4);
// gurobiModel->getEnv().set(GRB_DoubleParam_NodeLimit, 1e15);

gurobiModel->getEnv().set(GRB_IntParam_SolutionLimit, GRB_MAXINT);
gurobiModel->getEnv().set(
GRB_IntParam_SolutionNumber, env->settings->getSetting<int>("MIP.SolutionPool.Capacity", "Dual") + 1);

// Adds a user-provided node limit
if(env->settings->getSetting<double>("MIP.NodeLimit", "Dual") > 0)
{
gurobiModel->getEnv().set(
GRB_DoubleParam_NodeLimit, env->settings->getSetting<double>("MIP.NodeLimit", "Dual"));
}
}
catch(GRBException& e)
{
Expand Down Expand Up @@ -839,7 +846,7 @@ void MIPSolverGurobi::setCutOff(double cutOff)
{
// Gurobi has problems if not an epsilon value is added to the cutoff...

double cutOffTol = env->settings->getSetting<double>("MIP.CutOffTolerance", "Dual");
double cutOffTol = env->settings->getSetting<double>("MIP.CutOff.Tolerance", "Dual");

if(isMinimizationProblem)
{
Expand Down
4 changes: 2 additions & 2 deletions src/MIPSolver/MIPSolverGurobiSingleTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ void GurobiCallback::callback()
solutionCandidate.objectiveValue = getDoubleInfo(GRB_CB_MIPSOL_OBJ);
solutionCandidate.iterFound = env->results->getCurrentIteration()->iterationNumber;

std::vector<SolutionPoint> candidatePoints{ solutionCandidate };
std::vector<SolutionPoint> candidatePoints { solutionCandidate };

addLazyConstraint(candidatePoints);

Expand Down Expand Up @@ -445,7 +445,7 @@ void GurobiCallback::callback()

// Adds cutoff

/*double cutOffTol = env->settings->getSetting<double>("MIP.CutOffTolerance", "Dual");
/*double cutOffTol = env->settings->getSetting<double>("MIP.CutOff.Tolerance", "Dual");
if(isMinimization)
{
Expand Down
24 changes: 17 additions & 7 deletions src/ModelingSystem/ModelingSystemGAMS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,22 @@ void ModelingSystemGAMS::updateSettings(SettingsPtr settings, [[maybe_unused]] p
env->settings->updateSetting(
"ObjectiveGap.Relative", "Termination", gevGetDblOpt(modelingEnvironment, gevOptCR));

env->settings->updateSetting("MIP.NumberOfThreads", "Dual", gevThreads(modelingEnvironment));
// Sets cutoff value for dual solver
if(gevGetIntOpt(modelingEnvironment, gevUseCutOff) == 1)
{
env->settings->updateSetting("MIP.CutOff.UseInitialValue", "Dual", true);
env->settings->updateSetting(
"MIP.CutOff.InitialValue", "Dual", gevGetDblOpt(modelingEnvironment, gevCutOff));
}

// TODO? gevDomLim: stop if so many evaluation errors in nonlinear functions
// TODO gevNodeLim: should be node limit for single-tree strategy, if > 0
// TODO? gevCutOff, gevUseCutOff: stop if dual bound is above this value (if I remember right)
// TODO gevCheat, gevUseCheat -> MIP.CutOffTolerance ?
// TODO?? gevTryInt: handling of fractional values in initial solution for repair heuristics
// Sets node limit for dual solver
if(gevGetIntOpt(modelingEnvironment, gevNodeLim) > 0)
{
env->settings->updateSetting(
"MIP.NodeLimit", "Dual", (double)gevGetIntOpt(modelingEnvironment, gevNodeLim));
}

env->settings->updateSetting("MIP.NumberOfThreads", "Dual", gevThreads(modelingEnvironment));

env->output->outputDebug("Time limit set to "
+ Utilities::toString(env->settings->getSetting<double>("TimeLimit", "Termination")) + " by GAMS");
Expand Down Expand Up @@ -456,7 +465,8 @@ void ModelingSystemGAMS::finalizeSolution()
gmoSetHeadnTail(modelingObject, gmoTmipbest,
r->currentDualBound); // TODO how do we know that a dual bound has actually been computed
gmoSetHeadnTail(modelingObject, gmoHiterused, r->getCurrentIteration()->iterationNumber);
// TODO this seems to be 0: gmoSetHeadnTail(modelingObject, gmoHiterused, env->solutionStatistics.numberOfIterations);
// TODO this seems to be 0: gmoSetHeadnTail(modelingObject, gmoHiterused,
// env->solutionStatistics.numberOfIterations);
gmoSetHeadnTail(modelingObject, gmoHresused, env->timing->getElapsedTime("Total"));
gmoSetHeadnTail(modelingObject, gmoTmipnod, env->solutionStatistics.numberOfExploredNodes);

Expand Down
16 changes: 12 additions & 4 deletions src/Solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,10 +693,21 @@ void Solver::initializeSettings()

// Dual strategy settings: MIP solver

env->settings->createSetting("MIP.CutOffTolerance", "Dual", 0.00001,
env->settings->createSetting(
"MIP.CutOff.InitialValue", "Dual", SHOT_DBL_MAX, "Initial cutoff value to use", SHOT_DBL_MIN, SHOT_DBL_MAX);

env->settings->createSetting("MIP.CutOff.UseInitialValue", "Dual", false, "Use the initial cutoff value");

env->settings->createSetting("MIP.CutOff.Tolerance", "Dual", 0.00001,
"An extra tolerance for the objective cutoff value (to prevent infeasible subproblems)", SHOT_DBL_MIN,
SHOT_DBL_MAX);

env->settings->createSetting("MIP.NodeLimit", "Dual", SHOT_DBL_MAX,
"Node limit to use for MIP solver in single-tree strategy", 0.0, SHOT_DBL_MAX);

env->settings->createSetting(
"MIP.NumberOfThreads", "Dual", 8, "Number of threads to use in MIP solver: 0: Automatic", 0, 999);

VectorString enumPresolve;
enumPresolve.push_back("Never");
enumPresolve.push_back("Once");
Expand All @@ -711,9 +722,6 @@ void Solver::initializeSettings()
env->settings->createSetting(
"MIP.Presolve.UpdateObtainedBounds", "Dual", true, "Update bounds (from presolve) to the MIP model");

env->settings->createSetting(
"MIP.NumberOfThreads", "Dual", 8, "Number of threads to use in MIP solver: 0: Automatic", 0, 999);

env->settings->createSetting("MIP.SolutionLimit.ForceOptimal.Iteration", "Dual", 10000,
"Iterations without dual bound updates for forcing optimal MIP solution", 0, SHOT_INT_MAX);

Expand Down
9 changes: 5 additions & 4 deletions src/Structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const double SHOT_DBL_MAX = std::numeric_limits<double>::max();
const double SHOT_DBL_INF = std::numeric_limits<double>::infinity();
const double SHOT_DBL_EPS = std::numeric_limits<double>::epsilon();
const int SHOT_INT_MAX = std::numeric_limits<int>::max();
const long SHOT_LONG_MAX = std::numeric_limits<long>::max();

class Results;
class Settings;
Expand Down Expand Up @@ -110,7 +111,7 @@ struct PairIndexValue

public:
PairIndexValue() = default;
PairIndexValue(int index, double value) : index(index), value(value){};
PairIndexValue(int index, double value) : index(index), value(value) {};
};

struct PairCoordinateValue
Expand Down Expand Up @@ -142,9 +143,9 @@ struct PrimalSolution
std::string sourceDescription;
double objValue;
int iterFound;
PairIndexValue maxDevatingConstraintLinear{ -1, SHOT_DBL_INF };
PairIndexValue maxDevatingConstraintQuadratic{ -1, SHOT_DBL_INF };
PairIndexValue maxDevatingConstraintNonlinear{ -1, SHOT_DBL_INF };
PairIndexValue maxDevatingConstraintLinear { -1, SHOT_DBL_INF };
PairIndexValue maxDevatingConstraintQuadratic { -1, SHOT_DBL_INF };
PairIndexValue maxDevatingConstraintNonlinear { -1, SHOT_DBL_INF };
double maxIntegerToleranceError; // The maximum integer error before rounding
bool boundProjectionPerformed = false; // Has the variable bounds been corrected to either upper or lower bounds?
bool integerRoundingPerformed = false; // Has the integers been rounded?
Expand Down
14 changes: 12 additions & 2 deletions src/Tasks/TaskSolveIteration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,26 @@ void TaskSolveIteration::run()
double cutOffValue;
double cutOffValueConstraint;

// Setting a user provided cutoff value
if(env->dualSolver->cutOffToUse == SHOT_DBL_MAX
&& env->settings->getSetting<bool>("MIP.CutOff.UseInitialValue", "Dual"))
{
env->dualSolver->useCutOff = true;
env->dualSolver->cutOffToUse = env->settings->getSetting<double>("MIP.CutOff.InitialValue", "Dual");
env->output->outputDebug(
fmt::format(" Setting user-provided cutoff value to {}.", env->dualSolver->cutOffToUse));
}

if(isMinimization)
{
cutOffValue
= env->dualSolver->cutOffToUse + env->settings->getSetting<double>("MIP.CutOffTolerance", "Dual");
= env->dualSolver->cutOffToUse + env->settings->getSetting<double>("MIP.CutOff.Tolerance", "Dual");
cutOffValueConstraint = env->dualSolver->cutOffToUse;
}
else
{
cutOffValue
= env->dualSolver->cutOffToUse - env->settings->getSetting<double>("MIP.CutOffTolerance", "Dual");
= env->dualSolver->cutOffToUse - env->settings->getSetting<double>("MIP.CutOff.Tolerance", "Dual");
cutOffValueConstraint = env->dualSolver->cutOffToUse;
}

Expand Down

0 comments on commit b4b10d6

Please sign in to comment.