From cdced2be01a5451e91374fcce86243e9ad4521ef Mon Sep 17 00:00:00 2001 From: andreaslundell Date: Tue, 11 Jun 2024 16:29:55 +0300 Subject: [PATCH] Work on Highs support --- CMakeLists.txt | 26 +++++++------- ThirdParty/HiGHS | 2 +- src/MIPSolver/MIPSolverHighs.cpp | 60 +++++++++++++++++++++++++++----- src/Solver.cpp | 28 +++++++++++++++ 4 files changed, 94 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c9671db..fb0a8589 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,27 +47,27 @@ option(SIMPLE_OUTPUT_CHARS "Whether to avoid using special characters in the con option(HAS_AMPL "Should the AMPL .nl interface be build" ON) # GAMS -option(HAS_GAMS "Is GAMS available" OFF) -set(GAMS_DIR "/opt/gams/gams30.2" CACHE STRING "The base directory where GAMS is located (if available)") +option(HAS_GAMS "Is GAMS available" ON) +set(GAMS_DIR "/opt/gams/gams46.4" CACHE STRING "The base directory where GAMS is located (if available)") # CPLEX -option(HAS_CPLEX "Is Cplex available" OFF) -set(CPLEX_DIR "/opt/ibm/ILOG/CPLEX_Studio1210" CACHE STRING "The base directory where CPLEX is located (if available)") +option(HAS_CPLEX "Is Cplex available" ON) +set(CPLEX_DIR "/opt/ibm/ILOG/CPLEX_Studio221" CACHE STRING "The base directory where CPLEX is located (if available)") # Gurobi -option(HAS_GUROBI "Is Gurobi available" OFF) -set(GUROBI_DIR "/opt/gurobi/gurobi900" CACHE STRING "The base directory where Gurobi is located (if available)") +option(HAS_GUROBI "Is Gurobi available" ON) +set(GUROBI_DIR "/opt/gurobi/gurobi1101" CACHE STRING "The base directory where Gurobi is located (if available)") # Cbc -option(HAS_CBC "Is Cbc available" OFF) -set(CBC_DIR "/opt/Cbc-2.10" CACHE STRING "The base directory where Cbc is located (if available).") - -# Cbc -option(HAS_HIGHS "Is HiGHS available" ON) +option(HAS_CBC "Is Cbc available" ON) +set(CBC_DIR "/opt/cbc-2.10.10" CACHE STRING "The base directory where Cbc is located (if available).") # Ipopt -option(HAS_IPOPT "Is Ipopt available" OFF) -set(IPOPT_DIR "/opt/ipopt" CACHE STRING "The base directory where Ipopt is located (if available).") +option(HAS_IPOPT "Is Ipopt available" ON) +set(IPOPT_DIR "/opt/ipopt-3.14" CACHE STRING "The base directory where Ipopt is located (if available).") + +# Highs +option(HAS_HIGHS "Is HiGHS available" ON) # Create also the executable option(GENERATE_EXE "Should the SHOT executable be generated (requires at least that either OS or GAMS is available)" diff --git a/ThirdParty/HiGHS b/ThirdParty/HiGHS index 6f665585..0c240d83 160000 --- a/ThirdParty/HiGHS +++ b/ThirdParty/HiGHS @@ -1 +1 @@ -Subproject commit 6f665585cf1f64d4f6c13be0663f62ad508433c7 +Subproject commit 0c240d831128aa6fb01ad59536e5844c9b27abed diff --git a/src/MIPSolver/MIPSolverHighs.cpp b/src/MIPSolver/MIPSolverHighs.cpp index 1aeb1470..ff637091 100644 --- a/src/MIPSolver/MIPSolverHighs.cpp +++ b/src/MIPSolver/MIPSolverHighs.cpp @@ -3,7 +3,7 @@ @author Andreas Lundell, Åbo Akademi University - @section LICENSE + @section∏LICENSE This software is licensed under the Eclipse Public License 2.0. Please see the README and LICENSE files for more information. */ @@ -84,7 +84,7 @@ HighsCallbackFunctionType highsCallback currentSolution.hashValue = hashValue; MIPSolver->currentSolutions.push_back(currentSolution); - env->output->outputInfo(fmt::format(" | #sols: {} \t obj.val: {:.4f} \t gap: {:.4f} ", + env->output->outputDebug(fmt::format(" | #sols: {} \t obj.val: {:.4f} \t gap: {:.4f} ", MIPSolver->currentSolutions.size(), data_out->objective_function_value, data_out->mip_gap)); // Sorts the solutions so that the best one is at the first position @@ -317,7 +317,6 @@ void MIPSolverHighs::initializeSolverSettings() "mip_abs_gap", env->settings->getSetting("ObjectiveGap.Absolute", "Termination")); highsInstance.setOptionValue( "mip_feasibility_tolerance", env->settings->getSetting("Tolerance.Integer", "Primal")); - // highsInstance.setOptionValue("mip_heuristic_effort", 1.0); // Adds a user-provided node limit if(auto nodeLimit = env->settings->getSetting("MIP.NodeLimit", "Dual"); nodeLimit > 0) @@ -328,11 +327,57 @@ void MIPSolverHighs::initializeSolverSettings() highsInstance.setOptionValue("mip_max_nodes", (int)nodeLimit); } + highsInstance.setOptionValue( + "mip_allow_restart", env->settings->getSetting("Highs.MIPAllowRestart", "Subsolver")); + highsInstance.setOptionValue( + "mip_detect_symmetry", env->settings->getSetting("Highs.MIPDetectSymmetry", "Subsolver")); + highsInstance.setOptionValue( + "mip_heuristic_effort", env->settings->getSetting("Highs.MIPHeuristicEffort", "Subsolver")); + + switch(env->settings->getSetting("Highs.Parallel", "Subsolver")) + { + case 0: + highsInstance.setOptionValue("parallel", "off"); + break; + case 1: + highsInstance.setOptionValue("parallel", "choose"); + break; + case 2: + highsInstance.setOptionValue("parallel", "on"); + break; + default: + highsInstance.setOptionValue("parallel", "choose"); + break; + } + + switch(env->settings->getSetting("Highs.Presolve", "Subsolver")) + { + case 0: + highsInstance.setOptionValue("presolve", "off"); + break; + case 1: + highsInstance.setOptionValue("presolve", "choose"); + break; + case 2: + highsInstance.setOptionValue("presolve", "on"); + break; + default: + highsInstance.setOptionValue("presolve", "choose"); + break; + } + + highsInstance.setOptionValue("threads", env->settings->getSetting("MIP.NumberOfThreads", "Dual")); + + // highsInstance.setOptionValue("simplex_strategy", 0); + // highsInstance.setOptionValue("solver", "choose"); + // highsInstance.setOptionValue("primal_feasibility_tolerance", 1e-6); + // highsInstance.setOptionValue("dual_feasibility_tolerance", 1e-6); + // highsInstance.setOptionValue("highs_debug_level", 3); // highsInstance.setOptionValue("mip_report_level", 2); + // highsInstance.setOptionValue("output_flag", true); - highsInstance.setOptionValue("output_flag", false); - highsInstance.setOptionValue("threads", env->settings->getSetting("MIP.NumberOfThreads", "Dual")); + highsCallbackData.env = env; highsInstance.setCallback(highsCallback, reinterpret_cast(&highsCallbackData)); highsInstance.startCallback(kCallbackMipSolution); @@ -491,8 +536,7 @@ E_ProblemSolutionStatus MIPSolverHighs::solveProblem() cachedSolutionHasChanged = true; currentSolutions.clear(); - HighsLp lp = highsInstance.getLp(); - highsCallbackData.env = env; + // HighsLp lp = highsInstance.getLp(); highsReturnStatus = highsInstance.run(); MIPSolutionStatus = getSolutionStatus(); @@ -610,7 +654,7 @@ void MIPSolverHighs::addMIPStart(VectorDouble point) auto return_status = highsInstance.setSolution(solution); if(return_status != HighsStatus::kOk) - env->output->outputDebug(" Could not att MIP start in Highs."); + env->output->outputDebug(" Could not add MIP start in Highs."); } void MIPSolverHighs::writeProblemToFile(std::string filename) diff --git a/src/Solver.cpp b/src/Solver.cpp index 9956c8f4..1318644f 100644 --- a/src/Solver.cpp +++ b/src/Solver.cpp @@ -1536,6 +1536,34 @@ void Solver::initializeSettings() env->settings->createSetting("Cbc.Strategy", "Subsolver", 1, "This turns on newer features", enumStrategy, 0); enumStrategy.clear(); +#endif + +#ifdef HAS_HIGHS + + env->settings->createSettingGroup("Subsolver", "Highs", "Highs", ""); + + env->settings->createSetting("Highs.MIPAllowRestart", "Subsolver", true, "Whether MIP restart is permitted"); + + env->settings->createSetting( + "Highs.MIPDetectSymmetry", "Subsolver", true, "Whether MIP symmetry should be detected"); + + env->settings->createSetting( + "Highs.MIPHeuristicEffort", "Subsolver", 0.05, "Effort spent for MIP heuristics", 0, 1); + + VectorString enumHighsParallel; + enumHighsParallel.push_back("off"); + enumHighsParallel.push_back("choose"); + enumHighsParallel.push_back("on"); + env->settings->createSetting("Highs.Parallel", "Subsolver", 1, "Use parallelization", enumHighsParallel, 0); + enumHighsParallel.clear(); + + VectorString enumHighsPresolve; + enumHighsPresolve.push_back("off"); + enumHighsPresolve.push_back("choose"); + enumHighsPresolve.push_back("on"); + env->settings->createSetting("Highs.Presolve", "Subsolver", 1, "Use presolve", enumHighsPresolve, 0); + enumHighsPresolve.clear(); + #endif // Subsolver settings: Ipopt