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

Fix bug for maximization problems with nonlinear objective #171

Merged
merged 6 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}*/
Copy link
Member

@svigerske svigerske Oct 10, 2023

Choose a reason for hiding this comment

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

You really mean to comment out the complete code that sets the starting point for Ipopt? Doesn't that mean that Ipopt will start with some uninitialized values for x?

Copy link
Member

Choose a reason for hiding this comment

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

I also get a lot of complains from valgrind about using uninitialized data unless I reenable this code.

Copy link
Member Author

Choose a reason for hiding this comment

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

I thought that by adding
ipoptApplication->Options()->SetStringValue("warm_start_init_point", "no", true, true)
that Ipopt would not call this code at all, but am I mistaken?

As far as I understood from the Ipopt documentation, it is not really possible to warm start Ipopt without also providing the z and lambda values. That's why I removed this functionality altogether.

Copy link
Member

Choose a reason for hiding this comment

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

Enabling warm_start_init_point will make Ipopt ask for dual values (z, lambda) as well.
But not enabling it will still ask for primal values to start from (x). And the code you disabled was setting x only, as far as I remember.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, then I misunderstood. Thanks. I will fix it.


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
Loading
Loading