Skip to content

Commit

Permalink
Merge pull request #171 from coin-or/issue166
Browse files Browse the repository at this point in the history
Fix bug for maximization problems with nonlinear objective
  • Loading branch information
andreaslundell committed Oct 6, 2023
2 parents 4136f52 + db906f4 commit 74311d6
Show file tree
Hide file tree
Showing 22 changed files with 494 additions and 181 deletions.
2 changes: 2 additions & 0 deletions src/DualSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ void DualSolver::addIntegerCut(IntegerCut integerCut)
{
if(env->reformulatedProblem->properties.numberOfIntegerVariables > 0
|| env->reformulatedProblem->properties.numberOfSemiintegerVariables > 0)
{
integerCut.areAllVariablesBinary = false;
}
else
{
integerCut.areAllVariablesBinary = true;
Expand Down
43 changes: 19 additions & 24 deletions src/MIPSolver/MIPSolverCbc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -793,15 +793,14 @@ E_ProblemSolutionStatus MIPSolverCbc::solveProblem()
{
if(env->settings->getSetting<bool>("Debug.Enable", "Output"))
{
std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lp";
ss << env->results->getCurrentIteration()->iterationNumber - 1;
ss << "unbounded.lp";

auto filename = fmt::format("{}/dualiter{}_unbounded.lp",
env->settings->getSetting<std::string>("Debug.Path", "Output"),
env->results->getCurrentIteration()->iterationNumber - 1);

try
{
osiInterface->writeLp(ss.str().c_str(), "", 1e-7, 10, 10, 0.0, true);
osiInterface->writeLp(filename.c_str(), "", 1e-7, 10, 10, 0.0, true);
}
catch(std::exception& e)
{
Expand Down Expand Up @@ -890,12 +889,11 @@ bool MIPSolverCbc::repairInfeasibility()
constraints[i] = osiInterface->getRowName(repairConstraints[i]);
}

std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lp";
ss << env->results->getCurrentIteration()->iterationNumber - 1;
ss << "repairedweights.txt";
Utilities::saveVariablePointVectorToFile(relaxParameters, constraints, ss.str());
auto filename = fmt::format("{}/dualiter{}_infeasrelaxweights.txt",
env->settings->getSetting<std::string>("Debug.Path", "Output"),
env->results->getCurrentIteration()->iterationNumber - 1);

Utilities::saveVariablePointVectorToFile(relaxParameters, constraints, filename);
}

for(int i = 0; i < numConstraintsToRepair; i++)
Expand All @@ -922,15 +920,13 @@ bool MIPSolverCbc::repairInfeasibility()

if(env->settings->getSetting<bool>("Debug.Enable", "Output"))
{
std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lp";
ss << env->results->getCurrentIteration()->iterationNumber - 1;
ss << "infeasrelax.lp";
auto filename = fmt::format("{}/dualiter{}_infeasrelax.lp",
env->settings->getSetting<std::string>("Debug.Path", "Output"),
env->results->getCurrentIteration()->iterationNumber - 1);

try
{
repairedInterface->writeLp(ss.str().c_str(), "", 1e-7, 10, 10, 0.0, true);
repairedInterface->writeLp(filename.c_str(), "", 1e-7, 10, 10, 0.0, true);
}
catch(std::exception& e)
{
Expand Down Expand Up @@ -1130,12 +1126,11 @@ bool MIPSolverCbc::repairInfeasibility()

if(env->settings->getSetting<bool>("Debug.Enable", "Output"))
{
std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lp";
ss << env->results->getCurrentIteration()->iterationNumber - 1;
ss << "repaired.lp";
writeProblemToFile(ss.str());
auto filename = fmt::format("{}/dualiter{}_infeasrelax.lp",
env->settings->getSetting<std::string>("Debug.Path", "Output"),
env->results->getCurrentIteration()->iterationNumber - 1);

writeProblemToFile(filename);
}

delete repairedInterface;
Expand Down
26 changes: 13 additions & 13 deletions src/MIPSolver/MIPSolverCplex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -914,12 +914,11 @@ bool MIPSolverCplex::repairInfeasibility()
constraints[i] = expression.str();
}

std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lp";
ss << env->results->getCurrentIteration()->iterationNumber - 1;
ss << "repairedweights.txt";
Utilities::saveVariablePointVectorToFile(weights, constraints, ss.str());
auto filename = fmt::format("{}/dualiter{}_infeasrelaxweights.txt",
env->settings->getSetting<std::string>("Debug.Path", "Output"),
env->results->getCurrentIteration()->iterationNumber - 1);

Utilities::saveVariablePointVectorToFile(weights, constraints, filename);
}

if(cplexInstance.feasOpt(cplexConstrs, relax))
Expand Down Expand Up @@ -958,12 +957,11 @@ bool MIPSolverCplex::repairInfeasibility()

if(env->settings->getSetting<bool>("Debug.Enable", "Output"))
{
std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lp";
ss << env->results->getCurrentIteration()->iterationNumber - 1;
ss << "repaired.lp";
writeProblemToFile(ss.str());
auto filename = fmt::format("{}/dualiter{}_infeasrelax.lp",
env->settings->getSetting<std::string>("Debug.Path", "Output"),
env->results->getCurrentIteration()->iterationNumber - 1);

writeProblemToFile(filename);
}

if(numRepairs == 0)
Expand Down Expand Up @@ -1141,7 +1139,9 @@ void MIPSolverCplex::setTimeLimit(double seconds)
{
try
{
if(seconds > 1e+75) { }
if(seconds > 1e+75)
{
}
else if(seconds > 0)
{
cplexInstance.setParam(IloCplex::Param::TimeLimit, seconds);
Expand Down
32 changes: 14 additions & 18 deletions src/MIPSolver/MIPSolverGurobi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -953,12 +953,11 @@ bool MIPSolverGurobi::repairInfeasibility()
constraints[i] = repairConstraints[i].get(GRB_StringAttr_ConstrName);
}

std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lp";
ss << env->results->getCurrentIteration()->iterationNumber - 1;
ss << "repairedweights.txt";
Utilities::saveVariablePointVectorToFile(relaxParameters, constraints, ss.str());
auto filename = fmt::format("{}/dualiter{}_infeasrelaxweights.txt",
env->settings->getSetting<std::string>("Debug.Path", "Output"),
env->results->getCurrentIteration()->iterationNumber - 1);

Utilities::saveVariablePointVectorToFile(relaxParameters, constraints, filename);
}

// Gurobi modifies the value when running feasModel.optimize()
Expand All @@ -977,15 +976,13 @@ bool MIPSolverGurobi::repairInfeasibility()
// Saves the relaxation model to file
if(env->settings->getSetting<bool>("Debug.Enable", "Output"))
{
std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lp";
ss << env->results->getCurrentIteration()->iterationNumber - 1;
ss << "infeasrelax.lp";
auto filename = fmt::format("{}/dualiter{}_infeasrelax.lp",
env->settings->getSetting<std::string>("Debug.Path", "Output"),
env->results->getCurrentIteration()->iterationNumber - 1);

try
{
feasModel.write(ss.str());
feasModel.write(filename);
}
catch(GRBException& e)
{
Expand Down Expand Up @@ -1025,12 +1022,11 @@ bool MIPSolverGurobi::repairInfeasibility()

if(env->settings->getSetting<bool>("Debug.Enable", "Output"))
{
std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lp";
ss << env->results->getCurrentIteration()->iterationNumber - 1;
ss << "repaired.lp";
writeProblemToFile(ss.str());
auto filename = fmt::format("{}/dualiter{}_infeasrelax.lp",
env->settings->getSetting<std::string>("Debug.Path", "Output"),
env->results->getCurrentIteration()->iterationNumber - 1);

writeProblemToFile(filename);
}

if(numRepairs == 0)
Expand Down
30 changes: 12 additions & 18 deletions src/NLPSolver/NLPSolverCuttingPlaneMinimax.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,10 @@ E_NLPSolutionStatus NLPSolverCuttingPlaneMinimax::solveProblemInstance()
// Saves the LP problem to file if in debug mode
if(env->settings->getSetting<bool>("Debug.Enable", "Output"))
{
std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lpminimax";
ss << i;
ss << ".lp";
LPSolver->writeProblemToFile(ss.str());
auto filename
= fmt::format("{}/minimax{}.lp", env->settings->getSetting<std::string>("Debug.Path", "Output"), i);

LPSolver->writeProblemToFile(filename);
}

// Solves the problem and obtains the solution
Expand Down Expand Up @@ -193,12 +191,10 @@ E_NLPSolutionStatus NLPSolverCuttingPlaneMinimax::solveProblemInstance()
// Saves the LP solution to file if in debug mode
if(env->settings->getSetting<bool>("Debug.Enable", "Output"))
{
std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lpminimaxsolpt";
ss << i;
ss << ".txt";
Utilities::saveVariablePointVectorToFile(LPVarSol, variableNames, ss.str());
auto filename = fmt::format(
"{}/minimax{}_solpt.txt", env->settings->getSetting<std::string>("Debug.Path", "Output"), i);

Utilities::saveVariablePointVectorToFile(LPVarSol, variableNames, filename);
}

if(std::isnan(LPObjVar))
Expand Down Expand Up @@ -238,12 +234,10 @@ E_NLPSolutionStatus NLPSolverCuttingPlaneMinimax::solveProblemInstance()
// Saves the LP solution to file if in debug mode
if(env->settings->getSetting<bool>("Debug.Enable", "Output"))
{
std::stringstream ss;
ss << env->settings->getSetting<std::string>("Debug.Path", "Output");
ss << "/lpminimaxlinesearchsolpt";
ss << i;
ss << ".txt";
Utilities::saveVariablePointVectorToFile(currSol, variableNames, ss.str());
auto filename = fmt::format(
"{}/minimax{}_lsearchsolpt.txt", env->settings->getSetting<std::string>("Debug.Path", "Output"), i);

Utilities::saveVariablePointVectorToFile(currSol, variableNames, filename);
}
}

Expand Down
20 changes: 11 additions & 9 deletions src/NLPSolver/NLPSolverIpoptBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ bool IpoptProblem::get_starting_point(Index n, [[maybe_unused]] bool init_x, [[m
[[maybe_unused]] bool init_z, [[maybe_unused]] Number* z_L, [[maybe_unused]] Number* z_U, [[maybe_unused]] Index m,
[[maybe_unused]] bool init_lambda, [[maybe_unused]] Number* lambda)
{
/*
assert(init_x == true);
assert(init_z == false);
assert(init_lambda == false);
Expand Down Expand Up @@ -294,7 +295,7 @@ bool IpoptProblem::get_starting_point(Index n, [[maybe_unused]] bool init_x, [[m
x[k] = variableLB;
else
x[k] = variableUB;
}
}*/

return (true);
}
Expand Down Expand Up @@ -477,6 +478,7 @@ bool IpoptProblem::eval_h(Index n, const Number* x, [[maybe_unused]] bool new_x,
return (true);
}

/*
bool IpoptProblem::get_scaling_parameters(Number& obj_scaling, [[maybe_unused]] bool& use_x_scaling,
[[maybe_unused]] Index n, [[maybe_unused]] Number* x_scaling, [[maybe_unused]] bool& use_g_scaling,
[[maybe_unused]] Index m, [[maybe_unused]] Number* g_scaling)
Expand All @@ -487,7 +489,7 @@ bool IpoptProblem::get_scaling_parameters(Number& obj_scaling, [[maybe_unused]]
use_g_scaling = false;
return (true);
}
}*/

void IpoptProblem::finalize_solution(SolverReturn status, [[maybe_unused]] Index n, const Number* x,
[[maybe_unused]] const Number* z_L, [[maybe_unused]] const Number* z_U, [[maybe_unused]] Index m,
Expand Down Expand Up @@ -896,25 +898,25 @@ void NLPSolverIpoptBase::setInitialSettings()
// ipoptApplication->Options()->SetStringValue("derivative_test_print_all", "no");

// These are default settings for Ipopt in Bonmin, so should work here as well
ipoptApplication->Options()->SetNumericValue("bound_relax_factor", 1e-10, true, true);
ipoptApplication->Options()->SetNumericValue("bound_relax_factor", 1e-8, true, true);
ipoptApplication->Options()->SetStringValue("mu_strategy", "adaptive", true, true);
ipoptApplication->Options()->SetStringValue("ma86_order", "auto", true, true);
// ipoptApplication->Options()->SetStringValue("ma86_order", "auto", true, true);
ipoptApplication->Options()->SetStringValue("mu_oracle", "probing", true, true);
ipoptApplication->Options()->SetStringValue("expect_infeasible_problem", "yes", true, true);
// ipoptApplication->Options()->SetStringValue("warm_start_init_point", "yes", true, true);
ipoptApplication->Options()->SetStringValue("warm_start_init_point", "no", true,
true); // Cannot warm start since we do not have all required info, just a starting point
ipoptApplication->Options()->SetNumericValue("gamma_phi", 1e-8, true, true);
ipoptApplication->Options()->SetNumericValue("gamma_theta", 1e-4, true, true);
ipoptApplication->Options()->SetNumericValue("required_infeasibility_reduction", 0.1, true, true);
ipoptApplication->Options()->SetNumericValue("bound_relax_factor", 1e-10, true, true);
// ipoptApplication->Options()->SetStringValue("nlp_scaling_method", "none", true, true);
ipoptApplication->Options()->SetNumericValue(
"obj_scaling_factor", sourceProblem->objectiveFunction->properties.isMinimize ? 1.0 : -1.0, true, true);

// if we have linear constraint and a quadratic objective, then the hessian of the Lagrangian is constant, and
// Ipopt can make use of this
if(sourceProblem->properties.isMIQPProblem)
ipoptApplication->Options()->SetStringValue("hessian_constant", "yes", true, true);

ipoptApplication->Options()->GetNumericValue(
"diverging_iterates_tol", ipoptProblem->divergingIterativesTolerance, "");

setSolverSpecificInitialSettings();
}

Expand Down
4 changes: 2 additions & 2 deletions src/NLPSolver/NLPSolverIpoptBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ class IpoptProblem : public Ipopt::TNLP
const Ipopt::Number* lambda, bool new_lambda, Ipopt::Index nele_hess, Ipopt::Index* iRow, Ipopt::Index* jCol,
Ipopt::Number* values) override;

bool get_scaling_parameters(Ipopt::Number& obj_scaling, bool& use_x_scaling, Ipopt::Index n,
Ipopt::Number* x_scaling, bool& use_g_scaling, Ipopt::Index m, Ipopt::Number* g_scaling) override;
/*bool get_scaling_parameters(Ipopt::Number& obj_scaling, bool& use_x_scaling, Ipopt::Index n,
Ipopt::Number* x_scaling, bool& use_g_scaling, Ipopt::Index m, Ipopt::Number* g_scaling) override;*/

/** This method is called when the algorithm is complete so the TNLP can store/write the solution */
void finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n, const Ipopt::Number* x, const Ipopt::Number* z_L,
Expand Down
20 changes: 8 additions & 12 deletions src/Results.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,14 @@ void Results::addPrimalSolution(PrimalSolution solution)
if(env->problem->objectiveFunction->properties.isMinimize)
{
std::sort(this->primalSolutions.begin(), this->primalSolutions.end(),
[](const PrimalSolution& firstSolution, const PrimalSolution& secondSolution) {
return (firstSolution.objValue < secondSolution.objValue);
});
[](const PrimalSolution& firstSolution, const PrimalSolution& secondSolution)
{ return (firstSolution.objValue < secondSolution.objValue); });
}
else
{
std::sort(this->primalSolutions.begin(), this->primalSolutions.end(),
[](const PrimalSolution& firstSolution, const PrimalSolution& secondSolution) {
return (firstSolution.objValue > secondSolution.objValue);
});
[](const PrimalSolution& firstSolution, const PrimalSolution& secondSolution)
{ return (firstSolution.objValue > secondSolution.objValue); });
}

env->solutionStatistics.numberOfFoundPrimalSolutions++;
Expand Down Expand Up @@ -159,13 +157,11 @@ void Results::addPrimalSolution(PrimalSolution solution)
// Write the new primal point to a file
if(env->settings->getSetting<bool>("Debug.Enable", "Output"))
{
std::stringstream fileName;
fileName << env->settings->getSetting<std::string>("Debug.Path", "Output");
fileName << "/primalpoint";
fileName << env->solutionStatistics.numberOfFoundPrimalSolutions;
fileName << ".txt";
auto filename
= fmt::format("{}/primal_solpt{}.txt", env->settings->getSetting<std::string>("Debug.Path", "Output"),
env->solutionStatistics.numberOfFoundPrimalSolutions);

savePrimalSolutionToFile(solution, env->problem->allVariables, fileName.str());
savePrimalSolutionToFile(solution, env->problem->allVariables, filename);
}

// TODO: Add primal objective cut
Expand Down
1 change: 0 additions & 1 deletion src/Solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1932,7 +1932,6 @@ void Solver::setConvexityBasedSettings()
env->settings->updateSetting("FixedInteger.CallStrategy", "Primal", 0);
env->settings->updateSetting("FixedInteger.CreateInfeasibilityCut", "Primal", false);
env->settings->updateSetting("FixedInteger.Source", "Primal", 0);
env->settings->updateSetting("FixedInteger.Warmstart", "Primal", true);

env->settings->updateSetting("FixedInteger.OnlyUniqueIntegerCombinations", "Primal", false);

Expand Down
3 changes: 3 additions & 0 deletions src/Solver.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ class DllExport Solver
return setProblem(problem, nullptr, modelingSystem);
};

ProblemPtr getOriginalProblem() { return (env->problem); };
ProblemPtr getReformulatedProblem() { return (env->reformulatedProblem); };

bool solveProblem();

void finalizeSolution();
Expand Down

0 comments on commit 74311d6

Please sign in to comment.