diff --git a/src/DualSolver.cpp b/src/DualSolver.cpp index f9696e9d..3732635a 100644 --- a/src/DualSolver.cpp +++ b/src/DualSolver.cpp @@ -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; diff --git a/src/MIPSolver/MIPSolverCbc.cpp b/src/MIPSolver/MIPSolverCbc.cpp index 13abcd49..9cf31c6d 100644 --- a/src/MIPSolver/MIPSolverCbc.cpp +++ b/src/MIPSolver/MIPSolverCbc.cpp @@ -793,15 +793,14 @@ E_ProblemSolutionStatus MIPSolverCbc::solveProblem() { if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream ss; - ss << env->settings->getSetting("Debug.Path", "Output"); - ss << "/lp"; - ss << env->results->getCurrentIteration()->iterationNumber - 1; - ss << "unbounded.lp"; + + auto filename = fmt::format("{}/dualiter{}_unbounded.lp", + env->settings->getSetting("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) { @@ -890,12 +889,11 @@ bool MIPSolverCbc::repairInfeasibility() constraints[i] = osiInterface->getRowName(repairConstraints[i]); } - std::stringstream ss; - ss << env->settings->getSetting("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("Debug.Path", "Output"), + env->results->getCurrentIteration()->iterationNumber - 1); + + Utilities::saveVariablePointVectorToFile(relaxParameters, constraints, filename); } for(int i = 0; i < numConstraintsToRepair; i++) @@ -922,15 +920,13 @@ bool MIPSolverCbc::repairInfeasibility() if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream ss; - ss << env->settings->getSetting("Debug.Path", "Output"); - ss << "/lp"; - ss << env->results->getCurrentIteration()->iterationNumber - 1; - ss << "infeasrelax.lp"; + auto filename = fmt::format("{}/dualiter{}_infeasrelax.lp", + env->settings->getSetting("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) { @@ -1130,12 +1126,11 @@ bool MIPSolverCbc::repairInfeasibility() if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream ss; - ss << env->settings->getSetting("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("Debug.Path", "Output"), + env->results->getCurrentIteration()->iterationNumber - 1); + + writeProblemToFile(filename); } delete repairedInterface; diff --git a/src/MIPSolver/MIPSolverCplex.cpp b/src/MIPSolver/MIPSolverCplex.cpp index 1fc2fdc4..16a0574c 100644 --- a/src/MIPSolver/MIPSolverCplex.cpp +++ b/src/MIPSolver/MIPSolverCplex.cpp @@ -914,12 +914,11 @@ bool MIPSolverCplex::repairInfeasibility() constraints[i] = expression.str(); } - std::stringstream ss; - ss << env->settings->getSetting("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("Debug.Path", "Output"), + env->results->getCurrentIteration()->iterationNumber - 1); + + Utilities::saveVariablePointVectorToFile(weights, constraints, filename); } if(cplexInstance.feasOpt(cplexConstrs, relax)) @@ -958,12 +957,11 @@ bool MIPSolverCplex::repairInfeasibility() if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream ss; - ss << env->settings->getSetting("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("Debug.Path", "Output"), + env->results->getCurrentIteration()->iterationNumber - 1); + + writeProblemToFile(filename); } if(numRepairs == 0) @@ -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); diff --git a/src/MIPSolver/MIPSolverGurobi.cpp b/src/MIPSolver/MIPSolverGurobi.cpp index 015d8a7e..2f150219 100644 --- a/src/MIPSolver/MIPSolverGurobi.cpp +++ b/src/MIPSolver/MIPSolverGurobi.cpp @@ -953,12 +953,11 @@ bool MIPSolverGurobi::repairInfeasibility() constraints[i] = repairConstraints[i].get(GRB_StringAttr_ConstrName); } - std::stringstream ss; - ss << env->settings->getSetting("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("Debug.Path", "Output"), + env->results->getCurrentIteration()->iterationNumber - 1); + + Utilities::saveVariablePointVectorToFile(relaxParameters, constraints, filename); } // Gurobi modifies the value when running feasModel.optimize() @@ -977,15 +976,13 @@ bool MIPSolverGurobi::repairInfeasibility() // Saves the relaxation model to file if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream ss; - ss << env->settings->getSetting("Debug.Path", "Output"); - ss << "/lp"; - ss << env->results->getCurrentIteration()->iterationNumber - 1; - ss << "infeasrelax.lp"; + auto filename = fmt::format("{}/dualiter{}_infeasrelax.lp", + env->settings->getSetting("Debug.Path", "Output"), + env->results->getCurrentIteration()->iterationNumber - 1); try { - feasModel.write(ss.str()); + feasModel.write(filename); } catch(GRBException& e) { @@ -1025,12 +1022,11 @@ bool MIPSolverGurobi::repairInfeasibility() if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream ss; - ss << env->settings->getSetting("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("Debug.Path", "Output"), + env->results->getCurrentIteration()->iterationNumber - 1); + + writeProblemToFile(filename); } if(numRepairs == 0) diff --git a/src/NLPSolver/NLPSolverCuttingPlaneMinimax.cpp b/src/NLPSolver/NLPSolverCuttingPlaneMinimax.cpp index cb5c3576..110aba75 100644 --- a/src/NLPSolver/NLPSolverCuttingPlaneMinimax.cpp +++ b/src/NLPSolver/NLPSolverCuttingPlaneMinimax.cpp @@ -147,12 +147,10 @@ E_NLPSolutionStatus NLPSolverCuttingPlaneMinimax::solveProblemInstance() // Saves the LP problem to file if in debug mode if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream ss; - ss << env->settings->getSetting("Debug.Path", "Output"); - ss << "/lpminimax"; - ss << i; - ss << ".lp"; - LPSolver->writeProblemToFile(ss.str()); + auto filename + = fmt::format("{}/minimax{}.lp", env->settings->getSetting("Debug.Path", "Output"), i); + + LPSolver->writeProblemToFile(filename); } // Solves the problem and obtains the solution @@ -193,12 +191,10 @@ E_NLPSolutionStatus NLPSolverCuttingPlaneMinimax::solveProblemInstance() // Saves the LP solution to file if in debug mode if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream ss; - ss << env->settings->getSetting("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("Debug.Path", "Output"), i); + + Utilities::saveVariablePointVectorToFile(LPVarSol, variableNames, filename); } if(std::isnan(LPObjVar)) @@ -238,12 +234,10 @@ E_NLPSolutionStatus NLPSolverCuttingPlaneMinimax::solveProblemInstance() // Saves the LP solution to file if in debug mode if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream ss; - ss << env->settings->getSetting("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("Debug.Path", "Output"), i); + + Utilities::saveVariablePointVectorToFile(currSol, variableNames, filename); } } diff --git a/src/NLPSolver/NLPSolverIpoptBase.cpp b/src/NLPSolver/NLPSolverIpoptBase.cpp index 60550bb3..051407bb 100644 --- a/src/NLPSolver/NLPSolverIpoptBase.cpp +++ b/src/NLPSolver/NLPSolverIpoptBase.cpp @@ -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); @@ -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); } @@ -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) @@ -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, @@ -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(); } diff --git a/src/NLPSolver/NLPSolverIpoptBase.h b/src/NLPSolver/NLPSolverIpoptBase.h index 0c2bc326..22ae0c91 100644 --- a/src/NLPSolver/NLPSolverIpoptBase.h +++ b/src/NLPSolver/NLPSolverIpoptBase.h @@ -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, diff --git a/src/Results.cpp b/src/Results.cpp index 2457ff9c..b9376457 100644 --- a/src/Results.cpp +++ b/src/Results.cpp @@ -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++; @@ -159,13 +157,11 @@ void Results::addPrimalSolution(PrimalSolution solution) // Write the new primal point to a file if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream fileName; - fileName << env->settings->getSetting("Debug.Path", "Output"); - fileName << "/primalpoint"; - fileName << env->solutionStatistics.numberOfFoundPrimalSolutions; - fileName << ".txt"; + auto filename + = fmt::format("{}/primal_solpt{}.txt", env->settings->getSetting("Debug.Path", "Output"), + env->solutionStatistics.numberOfFoundPrimalSolutions); - savePrimalSolutionToFile(solution, env->problem->allVariables, fileName.str()); + savePrimalSolutionToFile(solution, env->problem->allVariables, filename); } // TODO: Add primal objective cut diff --git a/src/Solver.cpp b/src/Solver.cpp index e5f7a268..f4d8e192 100644 --- a/src/Solver.cpp +++ b/src/Solver.cpp @@ -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); diff --git a/src/Solver.h b/src/Solver.h index fd624951..ed764abd 100644 --- a/src/Solver.h +++ b/src/Solver.h @@ -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(); diff --git a/src/Tasks/TaskCreateDualProblem.cpp b/src/Tasks/TaskCreateDualProblem.cpp index 88334ea5..fb1cafc1 100644 --- a/src/Tasks/TaskCreateDualProblem.cpp +++ b/src/Tasks/TaskCreateDualProblem.cpp @@ -35,7 +35,7 @@ TaskCreateDualProblem::TaskCreateDualProblem(EnvironmentPtr envPtr) : TaskBase(e if(env->settings->getSetting("Debug.Enable", "Output")) { env->dualSolver->MIPSolver->writeProblemToFile( - env->settings->getSetting("Debug.Path", "Output") + "/lp0.lp"); + env->settings->getSetting("Debug.Path", "Output") + "/dualiter0_problem.lp"); } env->output->outputDebug(" Dual problem created"); @@ -79,7 +79,8 @@ bool TaskCreateDualProblem::createProblem(MIPSolverPtr destination, ProblemPtr s for(auto& V : sourceProblem->allVariables) { variablesInitialized = variablesInitialized - && destination->addVariable(V->name.c_str(), V->properties.type, V->lowerBound, V->upperBound, V->semiBound); + && destination->addVariable( + V->name.c_str(), V->properties.type, V->lowerBound, V->upperBound, V->semiBound); } if(!variablesInitialized) @@ -106,11 +107,11 @@ bool TaskCreateDualProblem::createProblem(MIPSolverPtr destination, ProblemPtr s destination->setDualAuxiliaryObjectiveVariableIndex(sourceProblem->properties.numberOfVariables); - if(sourceProblem->objectiveFunction->properties.isMinimize) - destination->addVariable("shot_dual_objvar", E_VariableType::Real, objectiveBound.l(), objectiveBound.u(), 0.0); - else - destination->addVariable( - "shot_dual_objvar", E_VariableType::Real, -objectiveBound.u(), -objectiveBound.l(), 0.0); + destination->addVariable("shot_dual_objvar", E_VariableType::Real, objectiveBound.l(), objectiveBound.u(), 0.0); + + env->output->outputDebug(fmt::format( + " SHOT internal dual objective variable created with index {} and bounds [{},{}] created.", + sourceProblem->properties.numberOfVariables, objectiveBound.l(), objectiveBound.u())); } // Now creating the objective function diff --git a/src/Tasks/TaskRepairInfeasibleDualProblem.cpp b/src/Tasks/TaskRepairInfeasibleDualProblem.cpp index 8c630622..e13755c8 100644 --- a/src/Tasks/TaskRepairInfeasibleDualProblem.cpp +++ b/src/Tasks/TaskRepairInfeasibleDualProblem.cpp @@ -125,7 +125,7 @@ void TaskRepairInfeasibleDualProblem::run() env->solutionStatistics.numberOfDualRepairsSinceLastPrimalUpdate = 0; env->tasks->setNextTask(taskIDIfTrue); mainRepairTries++; - tmpType << "-FAIL-" << mainRepairTries; + tmpType << "-F-" << mainRepairTries; } else { @@ -134,7 +134,7 @@ void TaskRepairInfeasibleDualProblem::run() env->tasks->setNextTask(taskIDIfFalse); mainRepairTries++; - tmpType << "-FAIL-" << mainRepairTries; + tmpType << "-F-" << mainRepairTries; } totRepairTries++; diff --git a/src/Tasks/TaskSelectPrimalCandidatesFromNLP.cpp b/src/Tasks/TaskSelectPrimalCandidatesFromNLP.cpp index 9c6d6e06..f8485de9 100644 --- a/src/Tasks/TaskSelectPrimalCandidatesFromNLP.cpp +++ b/src/Tasks/TaskSelectPrimalCandidatesFromNLP.cpp @@ -265,9 +265,9 @@ bool TaskSelectPrimalCandidatesFromNLP::solveFixedNLP() if(env->settings->getSetting("Debug.Enable", "Output")) { - std::string filename = env->settings->getSetting("Debug.Path", "Output") - + "/primalnlp_warmstart" + std::to_string(currIter->iterationNumber) + "_" + std::to_string(counter) - + ".txt"; + auto filename = fmt::format("{}/primalnlp{}_warmstart_{}.txt", + env->settings->getSetting("Debug.Path", "Output"), + env->results->getCurrentIteration()->iterationNumber - 1, counter); Utilities::saveVariablePointVectorToFile(startingPointValues, variableNames, filename); } diff --git a/src/Tasks/TaskSolveIteration.cpp b/src/Tasks/TaskSolveIteration.cpp index f0654243..11bf9dd8 100644 --- a/src/Tasks/TaskSolveIteration.cpp +++ b/src/Tasks/TaskSolveIteration.cpp @@ -111,12 +111,10 @@ void TaskSolveIteration::run() if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream ss; - ss << env->settings->getSetting("Debug.Path", "Output"); - ss << "/lp"; - ss << currIter->iterationNumber - 1; - ss << ".lp"; - env->dualSolver->MIPSolver->writeProblemToFile(ss.str()); + auto filename = fmt::format("{}/dualiter{}_problem.lp", + env->settings->getSetting("Debug.Path", "Output"), currIter->iterationNumber - 1); + + env->dualSolver->MIPSolver->writeProblemToFile(filename); } if(env->reformulatedProblem->properties.isLPProblem || env->reformulatedProblem->properties.isMILPProblem @@ -155,12 +153,23 @@ void TaskSolveIteration::run() if(env->settings->getSetting("Debug.Enable", "Output")) { - std::stringstream ss; - ss << env->settings->getSetting("Debug.Path", "Output"); - ss << "/lpsolpt"; - ss << currIter->iterationNumber - 1; - ss << ".txt"; - Utilities::saveVariablePointVectorToFile(sols.at(0).point, variableNames, ss.str()); + auto debugPath = env->settings->getSetting("Debug.Path", "Output"); + + for(int i = 0; i < sols.size(); i++) + { + auto filename = fmt::format("{}/dualiter{}_solpt_{}.txt", debugPath, currIter->iterationNumber - 1, i); + Utilities::saveVariablePointVectorToFile(sols.at(i).point, variableNames, filename); + } + + for(int i = 0; i < sols.size(); i++) + { + auto filename + = fmt::format("{}/dualiter{}_solinfo_{}.txt", debugPath, currIter->iterationNumber - 1, i); + auto filecontents + = fmt::format("objective function value\t\t{}\nmax constr. dev. ([index]: value)\t[{}]: {}\n", + sols.at(i).objectiveValue, sols.at(i).maxDeviation.index, sols.at(i).maxDeviation.value); + Utilities::writeStringToFile(filename, filecontents); + } } currIter->objectiveValue = env->dualSolver->MIPSolver->getObjectiveValue(); @@ -173,22 +182,6 @@ void TaskSolveIteration::run() currIter->solutionPoints = sols; - if(env->settings->getSetting("Debug.Enable", "Output")) - { - VectorDouble tmpObjValue; - VectorString tmpObjName; - - tmpObjValue.push_back(env->dualSolver->MIPSolver->getObjectiveValue()); - tmpObjName.push_back("objective"); - - std::stringstream ss; - ss << env->settings->getSetting("Debug.Path", "Output"); - ss << "/lpobjsol"; - ss << currIter->iterationNumber - 1; - ss << ".txt"; - Utilities::saveVariablePointVectorToFile(tmpObjValue, tmpObjName, ss.str()); - } - if(env->reformulatedProblem->properties.numberOfNonlinearConstraints > 0) { auto mostDevConstr = env->reformulatedProblem->getMaxNumericConstraintValue( @@ -199,18 +192,12 @@ void TaskSolveIteration::run() if(env->settings->getSetting("Debug.Enable", "Output")) { - VectorDouble tmpMostDevValue; - VectorString tmpConstrIndex; - - tmpMostDevValue.push_back(currIter->maxDeviation); - tmpConstrIndex.push_back(std::to_string(currIter->maxDeviationConstraint)); - - std::stringstream ss; - ss << env->settings->getSetting("Debug.Path", "Output"); - ss << "/lpmostdevm"; - ss << currIter->iterationNumber - 1; - ss << ".txt"; - Utilities::saveVariablePointVectorToFile(tmpMostDevValue, tmpConstrIndex, ss.str()); + auto filename = fmt::format("{}/dualiter{}_mostdev.txt", + env->settings->getSetting("Debug.Path", "Output"), currIter->iterationNumber - 1); + auto filecontents = fmt::format("most dev. constraint ([index]: value)\t[{}]: {}\n", + currIter->maxDeviationConstraint, currIter->maxDeviation); + + Utilities::writeStringToFile(filename, filecontents); } } else diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b0bce3df..8442ec47 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,17 +21,17 @@ set(Model_parts set(Settings_parts 1 2) if(HAS_CBC) - set(Cbc_parts 1 2 3) + set(Cbc_parts 1 2 3 4 5 6 7) set(cpptests ${cpptests} Cbc) endif() if(HAS_CPLEX) - set(Cplex_parts 1 2 3) + set(Cplex_parts 1 2 3 4 5 6 7) set(cpptests ${cpptests} Cplex) endif() if(HAS_GUROBI) - set(Gurobi_parts 1 2 3) + set(Gurobi_parts 1 2 3 4 5 6 7) set(cpptests ${cpptests} Gurobi) endif() diff --git a/test/CbcTest.cpp b/test/CbcTest.cpp index 1c5046d2..c05600db 100644 --- a/test/CbcTest.cpp +++ b/test/CbcTest.cpp @@ -9,19 +9,18 @@ */ #include "../src/Results.h" -#include "../src/Output.h" -#include "../src/Settings.h" #include "../src/Solver.h" -#include "../src/Utilities.h" #include "../src/TaskHandler.h" +#include "../src/Utilities.h" #include "../src/Model/Problem.h" +#include "../src/Model/ObjectiveFunction.h" #include using namespace SHOT; -bool CbcTest1(std::string filename) +bool CbcTest1(std::string filename, double correctObjectiveValue) { bool passed = true; @@ -71,6 +70,41 @@ bool CbcTest1(std::string filename) passed = false; } + if(solver->getOriginalProblem()->objectiveFunction->properties.isMinimize) + { + if(correctObjectiveValue <= solver->getPrimalBound() + 1e-5 + && correctObjectiveValue >= solver->getCurrentDualBound() - 1e-5) + { + std::cout << std::endl + << "Global objective value is within dual and primal bounds for minimization problem." + << std::endl; + } + else + { + std::cout << std::endl + << "Global objective value is not within dual and primal bounds for minimization problem." + << std::endl; + passed = false; + } + } + else + { + if(correctObjectiveValue >= solver->getPrimalBound() - 1e-5 + && correctObjectiveValue <= solver->getCurrentDualBound() + 1e-5) + { + std::cout << std::endl + << "Global objective value " << correctObjectiveValue + << " is within primal and dual bounds for maximization problem." << std::endl; + } + else + { + std::cout << std::endl + << "Global objective value is not within primal and dual bounds for maximization problem." + << std::endl; + passed = false; + } + } + return passed; } @@ -92,12 +126,14 @@ bool CbcTerminationCallbackTest(std::string filename) } // Registers a callback that terminates in the third iteration - solver->registerCallback(E_EventType::UserTerminationCheck, [&env] { - std::cout << "Callback activated. Terminating.\n"; + solver->registerCallback(E_EventType::UserTerminationCheck, + [&env] + { + std::cout << "Callback activated. Terminating.\n"; - if(env->results->getNumberOfIterations() == 3) - env->tasks->terminate(); - }); + if(env->results->getNumberOfIterations() == 3) + env->tasks->terminate(); + }); // Solving the problem if(!solver->solveProblem()) @@ -136,7 +172,7 @@ int CbcTest(int argc, char* argv[]) { case 1: std::cout << "Starting test to solve a MINLP problem with Cbc." << std::endl; - passed = CbcTest1("data/tls2.osil"); + passed = CbcTest1("data/tls2.osil", 5.3); std::cout << "Finished test to solve a MINLP problem with Cbc." << std::endl; break; case 2: @@ -146,9 +182,29 @@ int CbcTest(int argc, char* argv[]) break; case 3: std::cout << "Starting test to solve problem with semicont. variables:" << std::endl; - passed = CbcTest1("data/meanvarxsc.osil"); + passed = CbcTest1("data/meanvarxsc.osil", 14.36923211); std::cout << "Finished test to solve problem with semicont. variables." << std::endl; break; + case 4: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_max_div.nl':" << std::endl; + passed = CbcTest1("data/ncvx_max_div.nl", 13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_max_div.nl'." << std::endl; + break; + case 5: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_min_div.nl':" << std::endl; + passed = CbcTest1("data/ncvx_min_div.nl", -13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_min_div.nl'." << std::endl; + break; + case 6: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_max_ndiv.nl':" << std::endl; + passed = CbcTest1("data/ncvx_max_ndiv.nl", 13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_max_ndiv.nl'." << std::endl; + break; + case 7: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_min_ndiv.nl':" << std::endl; + passed = CbcTest1("data/ncvx_min_ndiv.nl", -13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_min_ndiv.nl'." << std::endl; + break; default: passed = false; std::cout << "Test #" << choice << " does not exist!\n"; diff --git a/test/CplexTest.cpp b/test/CplexTest.cpp index d07f0a89..01c37579 100644 --- a/test/CplexTest.cpp +++ b/test/CplexTest.cpp @@ -11,11 +11,14 @@ #include "../src/Utilities.h" #include "../src/TaskHandler.h" +#include "../src/Model/Problem.h" +#include "../src/Model/ObjectiveFunction.h" + #include using namespace SHOT; -bool CplexTest1(std::string filename) +bool CplexTest1(std::string filename, double correctObjectiveValue) { bool passed = true; @@ -65,6 +68,41 @@ bool CplexTest1(std::string filename) passed = false; } + if(solver->getOriginalProblem()->objectiveFunction->properties.isMinimize) + { + if(correctObjectiveValue <= solver->getPrimalBound() + 1e-5 + && correctObjectiveValue >= solver->getCurrentDualBound() - 1e-5) + { + std::cout << std::endl + << "Global objective value is within dual and primal bounds for minimization problem." + << std::endl; + } + else + { + std::cout << std::endl + << "Global objective value is not within dual and primal bounds for minimization problem." + << std::endl; + passed = false; + } + } + else + { + if(correctObjectiveValue >= solver->getPrimalBound() - 1e-5 + && correctObjectiveValue <= solver->getCurrentDualBound() + 1e-5) + { + std::cout << std::endl + << "Global objective value " << correctObjectiveValue + << " is within primal and dual bounds for maximization problem." << std::endl; + } + else + { + std::cout << std::endl + << "Global objective value is not within primal and dual bounds for maximization problem." + << std::endl; + passed = false; + } + } + return passed; } @@ -86,12 +124,14 @@ bool CplexTerminationCallbackTest(std::string filename) } // Registers a callback that terminates in the third iteration - solver->registerCallback(E_EventType::UserTerminationCheck, [&env] { - std::cout << "Callback activated. Terminating.\n"; + solver->registerCallback(E_EventType::UserTerminationCheck, + [&env] + { + std::cout << "Callback activated. Terminating.\n"; - if(env->results->getNumberOfIterations() == 3) - env->tasks->terminate(); - }); + if(env->results->getNumberOfIterations() == 3) + env->tasks->terminate(); + }); // Solving the problem if(!solver->solveProblem()) @@ -131,7 +171,7 @@ int CplexTest(int argc, char* argv[]) { case 1: std::cout << "Starting test to solve a MINLP problem with Cplex:" << std::endl; - passed = CplexTest1("data/tls2.osil"); + passed = CplexTest1("data/tls2.osil", 5.3); std::cout << "Finished test to solve a MINLP problem with Cplex." << std::endl; break; case 2: @@ -141,9 +181,29 @@ int CplexTest(int argc, char* argv[]) break; case 3: std::cout << "Starting test to solve problem with semicont. variables with Cplex:" << std::endl; - passed = CplexTest1("data/meanvarxsc.osil"); + passed = CplexTest1("data/meanvarxsc.osil", 14.36923211); std::cout << "Finished test to solve problem with semicont. variables with Cplex." << std::endl; break; + case 4: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_max_div.nl':" << std::endl; + passed = CplexTest1("data/ncvx_max_div.nl", 13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_max_div.nl'." << std::endl; + break; + case 5: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_min_div.nl':" << std::endl; + passed = CplexTest1("data/ncvx_min_div.nl", -13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_min_div.nl'." << std::endl; + break; + case 6: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_max_ndiv.nl':" << std::endl; + passed = CplexTest1("data/ncvx_max_ndiv.nl", 13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_max_ndiv.nl'." << std::endl; + break; + case 7: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_min_ndiv.nl':" << std::endl; + passed = CplexTest1("data/ncvx_min_ndiv.nl", -13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_min_ndiv.nl'." << std::endl; + break; default: passed = false; std::cout << "Test #" << choice << " does not exist!\n"; diff --git a/test/GurobiTest.cpp b/test/GurobiTest.cpp index b9967b32..09ea86eb 100644 --- a/test/GurobiTest.cpp +++ b/test/GurobiTest.cpp @@ -9,19 +9,18 @@ */ #include "../src/Results.h" -#include "../src/Output.h" -#include "../src/Settings.h" #include "../src/Solver.h" #include "../src/TaskHandler.h" #include "../src/Utilities.h" #include "../src/Model/Problem.h" +#include "../src/Model/ObjectiveFunction.h" #include using namespace SHOT; -bool GurobiTest1(std::string filename) +bool GurobiTest1(std::string filename, double correctObjectiveValue) { bool passed = true; @@ -71,6 +70,45 @@ bool GurobiTest1(std::string filename) passed = false; } + if(solver->getOriginalProblem()->objectiveFunction->properties.isMinimize) + { + if(correctObjectiveValue <= solver->getPrimalBound() + 1e-5 + && correctObjectiveValue >= solver->getCurrentDualBound() - 1e-5) + { + std::cout << std::endl + << "Given objective value (" << correctObjectiveValue << ") is within dual (" + << solver->getCurrentDualBound() << ") and primal (" << solver->getPrimalBound() + << ") for minimization problem." << std::endl; + } + else + { + std::cout << std::endl + << "Given objective value (" << correctObjectiveValue << ") is not within dual (" + << solver->getCurrentDualBound() << ") and primal (" << solver->getPrimalBound() + << ") for minimization problem." << std::endl; + passed = false; + } + } + else + { + if(correctObjectiveValue >= solver->getPrimalBound() - 1e-5 + && correctObjectiveValue <= solver->getCurrentDualBound() + 1e-5) + { + std::cout << std::endl + << "Given objective value (" << correctObjectiveValue << ") is within primal (" + << solver->getPrimalBound() << ") and dual (" << solver->getCurrentDualBound() + << ") for maximization problem." << std::endl; + } + else + { + std::cout << std::endl + << "Given objective value (" << correctObjectiveValue << ") is not within primal (" + << solver->getPrimalBound() << ") and dual (" << solver->getCurrentDualBound() + << ") for maximization problem." << std::endl; + passed = false; + } + } + return passed; } @@ -92,12 +130,14 @@ bool GurobiTerminationCallbackTest(std::string filename) } // Registers a callback that terminates in the third iteration - solver->registerCallback(E_EventType::UserTerminationCheck, [&env] { - std::cout << "Callback activated. Terminating.\n"; + solver->registerCallback(E_EventType::UserTerminationCheck, + [&env] + { + std::cout << "Callback activated. Terminating.\n"; - if(env->results->getNumberOfIterations() == 3) - env->tasks->terminate(); - }); + if(env->results->getNumberOfIterations() == 3) + env->tasks->terminate(); + }); // Solving the problem if(!solver->solveProblem()) @@ -137,7 +177,7 @@ int GurobiTest(int argc, char* argv[]) { case 1: std::cout << "Starting test to solve a MINLP problem with Gurobi." << std::endl; - passed = GurobiTest1("data/tls2.osil"); + passed = GurobiTest1("data/tls2.osil", 5.3); std::cout << "Finished test to solve a MINLP problem with Gurobi." << std::endl; break; case 2: @@ -147,9 +187,29 @@ int GurobiTest(int argc, char* argv[]) break; case 3: std::cout << "Starting test to solve problem with semicont. variables with Gurobi.:" << std::endl; - passed = GurobiTest1("data/meanvarxsc.osil"); + passed = GurobiTest1("data/meanvarxsc.osil", 14.36923211); std::cout << "Finished test to solve problem with semicont. variables with Gurobi." << std::endl; break; + case 4: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_max_div.nl':" << std::endl; + passed = GurobiTest1("data/ncvx_max_div.nl", 13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_max_div.nl'." << std::endl; + break; + case 5: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_min_div.nl':" << std::endl; + passed = GurobiTest1("data/ncvx_min_div.nl", -13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_min_div.nl'." << std::endl; + break; + case 6: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_max_ndiv.nl':" << std::endl; + passed = GurobiTest1("data/ncvx_max_ndiv.nl", 13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_max_ndiv.nl'." << std::endl; + break; + case 7: + std::cout << "Starting test to solve nonconvex maximization problem 'ncvx_min_ndiv.nl':" << std::endl; + passed = GurobiTest1("data/ncvx_min_ndiv.nl", -13.0); + std::cout << "Finished test to solve nonconvex maximization problem 'ncvx_min_ndiv.nl'." << std::endl; + break; default: passed = false; std::cout << "Test #" << choice << " does not exist!\n"; diff --git a/test/data/ncvx_max_div.nl b/test/data/ncvx_max_div.nl new file mode 100644 index 00000000..e6765ae5 --- /dev/null +++ b/test/data/ncvx_max_div.nl @@ -0,0 +1,38 @@ +g3 1 1 0 # problem unknown + 3 0 1 0 0 # vars, constraints, objectives, ranges, eqns + 0 1 0 0 0 0 # nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb + 0 0 # network constraints: nonlinear, linear + 0 3 0 # nonlinear vars in constraints, objectives, both + 0 0 0 1 # linear network variables; functions; arith, flags + 0 0 0 0 1 # discrete variables: binary, integer, nonlinear (b,c,o) + 0 3 # nonzeros in Jacobian, obj. gradient + 0 0 # max name lengths: constraints, variables + 0 0 0 0 0 # common exprs: b,c,o,c1,o1 +O0 1 +o0 +o3 +o0 +o2 +n-1 +v2 +n1 +v0 +o3 +o2 +n1.3 +v2 +v1 +x1 +2 1 +r +b +0 0.5 0.6 +0 0.1 0.2 +0 0 1 +k2 +0 +0 +G0 3 +0 0 +1 0 +2 0 diff --git a/test/data/ncvx_max_ndiv.nl b/test/data/ncvx_max_ndiv.nl new file mode 100644 index 00000000..de487d5b --- /dev/null +++ b/test/data/ncvx_max_ndiv.nl @@ -0,0 +1,42 @@ +g3 1 1 0 # problem unknown + 3 0 1 0 0 # vars, constraints, objectives, ranges, eqns + 0 1 0 0 0 0 # nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb + 0 0 # network constraints: nonlinear, linear + 0 3 0 # nonlinear vars in constraints, objectives, both + 0 0 0 1 # linear network variables; functions; arith, flags + 0 0 0 0 1 # discrete variables: binary, integer, nonlinear (b,c,o) + 0 3 # nonzeros in Jacobian, obj. gradient + 0 0 # max name lengths: constraints, variables + 0 0 0 0 0 # common exprs: b,c,o,c1,o1 +O0 1 +o0 +o2 +o0 +o2 +n-1 +v2 +n1 +o5 +v0 +n-1 +o2 +o2 +n1.3 +v2 +o5 +v1 +n-1 +x1 +2 1 +r +b +0 0.5 0.6 +0 0.1 0.2 +0 0 1 +k2 +0 +0 +G0 3 +0 0 +1 0 +2 0 diff --git a/test/data/ncvx_min_div.nl b/test/data/ncvx_min_div.nl new file mode 100644 index 00000000..4636792b --- /dev/null +++ b/test/data/ncvx_min_div.nl @@ -0,0 +1,39 @@ +g3 1 1 0 # problem unknown + 3 0 1 0 0 # vars, constraints, objectives, ranges, eqns + 0 1 0 0 0 0 # nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb + 0 0 # network constraints: nonlinear, linear + 0 3 0 # nonlinear vars in constraints, objectives, both + 0 0 0 1 # linear network variables; functions; arith, flags + 0 0 0 0 1 # discrete variables: binary, integer, nonlinear (b,c,o) + 0 3 # nonzeros in Jacobian, obj. gradient + 0 0 # max name lengths: constraints, variables + 0 0 0 0 0 # common exprs: b,c,o,c1,o1 +O0 0 +o16 +o0 +o3 +o0 +o2 +n-1 +v2 +n1 +v0 +o3 +o2 +n1.3 +v2 +v1 +x1 +2 1 +r +b +0 0.5 0.6 +0 0.1 0.2 +0 0 1 +k2 +0 +0 +G0 3 +0 0 +1 0 +2 0 diff --git a/test/data/ncvx_min_ndiv.nl b/test/data/ncvx_min_ndiv.nl new file mode 100644 index 00000000..58a38002 --- /dev/null +++ b/test/data/ncvx_min_ndiv.nl @@ -0,0 +1,43 @@ +g3 1 1 0 # problem unknown + 3 0 1 0 0 # vars, constraints, objectives, ranges, eqns + 0 1 0 0 0 0 # nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb + 0 0 # network constraints: nonlinear, linear + 0 3 0 # nonlinear vars in constraints, objectives, both + 0 0 0 1 # linear network variables; functions; arith, flags + 0 0 0 0 1 # discrete variables: binary, integer, nonlinear (b,c,o) + 0 3 # nonzeros in Jacobian, obj. gradient + 0 0 # max name lengths: constraints, variables + 0 0 0 0 0 # common exprs: b,c,o,c1,o1 +O0 0 +o16 +o0 +o2 +o0 +o2 +n-1 +v2 +n1 +o5 +v0 +n-1 +o2 +o2 +n1.3 +v2 +o5 +v1 +n-1 +x1 +2 1 +r +b +0 0.5 0.6 +0 0.1 0.2 +0 0 1 +k2 +0 +0 +G0 3 +0 0 +1 0 +2 0