diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index 5f8c59407..9ebf684a0 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -141,5 +141,6 @@ jobs: run: | set PATH=%PATH%;C:\Program Files\Microsoft MPI\Bin set PATH=%PATH%;${{ env.XPRESS }} + set XPRESSDIR=${{ env.XPRESSDIR }} cd _build ctest -C Release --output-on-failure -L "medium|unit|benders|lpnamer" \ No newline at end of file diff --git a/.github/workflows/windows-vcpkg.yml b/.github/workflows/windows-vcpkg.yml index 063bdab22..2a3478883 100644 --- a/.github/workflows/windows-vcpkg.yml +++ b/.github/workflows/windows-vcpkg.yml @@ -193,6 +193,7 @@ jobs: run: | set PATH=%PATH%;C:\Program Files\Microsoft MPI\Bin\ set PATH=%PATH%;${{ env.XPRESS }} + set XPRESSDIR=${{ env.XPRESSDIR }} cd _build ctest -C Release --output-on-failure -L "medium|unit|benders|lpnamer" diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e7050ca1..412f7fcba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,31 +237,6 @@ endif() find_package(jsoncpp CONFIG REQUIRED) -# Third-party solver -## Xpress -if(XPRESS) - message("XPRESS is ${XPRESS}") - - #Default xpress install dir - if (NOT XPRESS_ROOT) - if (MSVC) - set(XPRESS_ROOT "C:/xpressmp") - elseif(UNIX) - set(XPRESS_ROOT "/opt/xpressmp") - endif() - endif() - - find_package(XPRESS REQUIRED) - - # Add solver variables for usage in C++ source code - # There are already some variables defined by SOLVER, -DUSE_XPRESS, -DUSE_CBC - # But they are exclusive, only one can be set to True - # We need to keep COIN-OR at least COIN-OR to True while it is required in lpnamer - # and we want to allow compilation with several solvers so that the user can switch - # the solver without any compilation phase. - # @TODO : I think those parameters should be merged in a future version - add_definitions( -DXPRESS=true ) -endif(XPRESS) ## Coin-OR (Clp and CBC solvers) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d6e783575..903eeb892 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,9 +6,7 @@ if (COIN_OR) SET(AVAILABLE_SOLVER_YML_LIST "${AVAILABLE_SOLVER_YML_LIST}- Cbc\n") SET(AVAILABLE_SOLVER_YML_LIST "${AVAILABLE_SOLVER_YML_LIST}- Coin\n") endif() -if (XPRESS) SET(AVAILABLE_SOLVER_YML_LIST "${AVAILABLE_SOLVER_YML_LIST}- Xpress\n") -endif() #configure file to define antares-solver executable diff --git a/src/cpp/lpnamer/main/RunProblemGeneration.cpp b/src/cpp/lpnamer/main/RunProblemGeneration.cpp index c6cbf682f..527075c13 100644 --- a/src/cpp/lpnamer/main/RunProblemGeneration.cpp +++ b/src/cpp/lpnamer/main/RunProblemGeneration.cpp @@ -1,13 +1,11 @@ #include "RunProblemGeneration.h" -#include #include #include #include "ActiveLinks.h" #include "AdditionalConstraints.h" -#include "Clock.h" #include "GeneralDataReader.h" #include "LauncherHelpers.h" #include "LinkProblemsGenerator.h" @@ -17,14 +15,12 @@ #include "MasterGeneration.h" #include "MasterProblemBuilder.h" #include "MpsTxtWriter.h" -#include "ProblemGenerationExeOptions.h" #include "ProblemVariablesFromProblemAdapter.h" #include "ProblemVariablesZipAdapter.h" #include "StringManip.h" #include "Timer.h" #include "WeightsFileReader.h" #include "WeightsFileWriter.h" -#include "XpansionProblemsFromAntaresProvider.h" #include "ZipProblemsProviderAdapter.h" #include "config.h" @@ -59,6 +55,7 @@ struct Version { int major; int minor; }; + std::shared_ptr InstantiateZipReader( const std::filesystem::path& antares_archive_path); void ProcessWeights( @@ -128,6 +125,7 @@ std::vector> getXpansionProblems( problem_names); return adapter->provideProblems(solver_name, solver_log_manager); } + void RunProblemGeneration( const std::filesystem::path& xpansion_output_dir, const std::string& master_formulation, @@ -169,14 +167,10 @@ void RunProblemGeneration( auto files_mapper = FilesMapper(antares_archive_path); auto mpsList = files_mapper.MpsAndVariablesFilesVect(); - bool use_zip_implementation = true; - bool use_file_implementation = false; - auto solver_log_manager = SolverLogManager(log_file_path); Couplings couplings; LinkProblemsGenerator linkProblemsGenerator( lpDir_, links, solver_name, logger, solver_log_manager, rename_problems); - if (use_zip_implementation) { std::shared_ptr reader = InstantiateZipReader(antares_archive_path); @@ -185,79 +179,33 @@ void RunProblemGeneration( getXpansionProblems(solver_log_manager, solver_name, mpsList, lpDir_, reader); - std::vector, ProblemData>> - problems_and_data; - for (int i = 0; i < xpansion_problems.size(); ++i) { - xpansion_problems.at(i)->_name = mpsList.at(i)._problem_mps; - problems_and_data.emplace_back(xpansion_problems.at(i), mpsList.at(i)); - } - auto mps_file_writer = std::make_shared(lpDir_); - std::for_each( - std::execution::par, problems_and_data.begin(), problems_and_data.end(), - [&](const auto& problem_and_data) { - const auto& [problem, data] = problem_and_data; - std::shared_ptr variables_provider; - if (rename_problems) { - variables_provider = std::make_shared( - reader, data, links, logger); - } else { - variables_provider = - std::make_shared( - problem, links, logger); - } - linkProblemsGenerator.treat(data._problem_mps, couplings, problem.get(), - variables_provider.get(), mps_file_writer.get()); - }); - - reader->Close(); - reader->Delete(); - } else if (use_file_implementation) { - /* Main stuff */ - auto mps_file_writer = std::make_shared(lpDir_); - linkProblemsGenerator.treatloop(xpansion_output_dir, couplings, mpsList, + std::vector, ProblemData>> + problems_and_data; + for (int i = 0; i < xpansion_problems.size(); ++i) { + xpansion_problems.at(i)->_name = mpsList.at(i)._problem_mps; + problems_and_data.emplace_back(xpansion_problems.at(i), mpsList.at(i)); + } + auto mps_file_writer = std::make_shared(lpDir_); + std::for_each( + std::execution::par, problems_and_data.begin(), problems_and_data.end(), + [&](const auto& problem_and_data) { + const auto& [problem, data] = problem_and_data; + std::shared_ptr variables_provider; + if (rename_problems) { + variables_provider = std::make_shared( + reader, data, links, logger); + } else { + variables_provider = + std::make_shared( + problem, links, logger); + } + linkProblemsGenerator.treat(data._problem_mps, couplings, problem.get(), + variables_provider.get(), mps_file_writer.get()); - } else { - std::filesystem::path path = - xpansion_output_dir.parent_path().parent_path() / - "fichierDeSerialisation"; - std::ifstream ifs(xpansion_output_dir.parent_path().parent_path() / - "fichierDeSerialisation"); - boost::archive::text_iarchive ia(ifs); - - LpsFromAntares lps; - ia >> lps; - lps._constant->Mdeb.push_back(lps._constant->NombreDeCoefficients); - - XpansionProblemsFromAntaresProvider adapter(lps); - auto xpansion_problems = - adapter.provideProblems(solver_name, solver_log_manager); - std::vector, ProblemData>> - problems_and_data; - for (int i = 0; i < xpansion_problems.size(); ++i) { - xpansion_problems.at(i)->_name = mpsList.at(i)._problem_mps; - problems_and_data.emplace_back(xpansion_problems.at(i), mpsList.at(i)); - } - - auto reader = InstantiateZipReader(antares_archive_path); - auto mps_file_writer = std::make_shared(lpDir_); + }); - std::for_each( - std::execution::par, problems_and_data.begin(), problems_and_data.end(), - [&](const auto& problem_and_data) { - const auto& [problem, data] = problem_and_data; - std::shared_ptr variables_provider; - if (rename_problems) { - variables_provider = std::make_shared( - reader, data, links, logger); - } else { - variables_provider = - std::make_shared( - problem, links, logger); - } - linkProblemsGenerator.treat(data._problem_mps, couplings, problem.get(), - variables_provider.get(), mps_file_writer.get()); - }); - } + reader->Close(); + reader->Delete(); MasterGeneration master_generation( xpansion_output_dir, links, additionalConstraints, couplings, diff --git a/src/cpp/multisolver_interface/CMakeLists.txt b/src/cpp/multisolver_interface/CMakeLists.txt index 4a02be465..b03d8800a 100644 --- a/src/cpp/multisolver_interface/CMakeLists.txt +++ b/src/cpp/multisolver_interface/CMakeLists.txt @@ -17,12 +17,14 @@ list(APPEND Solver_sources ${CMAKE_CURRENT_LIST_DIR}/SolverFactory.cpp ) +list(APPEND XPRESS_LOAD + ${CMAKE_CURRENT_LIST_DIR}/environment.cc +) + # XPRESS -IF( XPRESS ) list(APPEND Solver_sources ${CMAKE_CURRENT_LIST_DIR}/SolverXpress.cpp ) -ENDIF( XPRESS ) #Clp - CBc IF(COIN_OR) @@ -39,6 +41,7 @@ ENDIF(COIN_OR) # --------------------------------------------------------------------------- add_library (solvers STATIC ${Solver_sources} + ${XPRESS_LOAD} ) get_target_property(xpansion_interfaces_path xpansion_interfaces INTERFACE_INCLUDE_DIRECTORIES) target_include_directories (solvers @@ -52,12 +55,12 @@ target_include_directories (solvers # XPRESS -if(XPRESS) - target_link_libraries (solvers - PUBLIC - XPRESS::XPRESS - ) -endif() +#if(XPRESS) + # target_link_libraries (solvers + # PUBLIC + # XPRESS::XPRESS + # ) +#endif() #CLP-CBC if(COIN_OR) @@ -68,5 +71,6 @@ if(COIN_OR) Coin::CoinUtils Coin::Osi Coin::Cbc + ${CMAKE_DL_LIBS} ) endif() diff --git a/src/cpp/multisolver_interface/SolverFactory.cpp b/src/cpp/multisolver_interface/SolverFactory.cpp index 1ec81c52b..fb38d45b1 100644 --- a/src/cpp/multisolver_interface/SolverFactory.cpp +++ b/src/cpp/multisolver_interface/SolverFactory.cpp @@ -1,22 +1,33 @@ -#ifdef XPRESS + #include "SolverXpress.h" -#endif +#include "multisolver_interface/environment.h" + #ifdef COIN_OR #include "SolverCbc.h" #include "SolverClp.h" #endif #include "LogUtils.h" #include "multisolver_interface/SolverFactory.h" +std::vector available_solvers; -SolverFactory::SolverFactory() { - _available_solvers.clear(); -#ifdef XPRESS - _available_solvers.push_back(XPRESS_STR); -#endif +std::vector SolverLoader::GetAvailableSolvers() { + if (available_solvers.empty()) { + if (LoadXpress::XpressIsCorrectlyInstalled()) { + available_solvers.push_back(XPRESS_STR); + } #ifdef COIN_OR - _available_solvers.push_back(CLP_STR); - _available_solvers.push_back(CBC_STR); + available_solvers.push_back(CLP_STR); + available_solvers.push_back(CBC_STR); #endif + } + return available_solvers; +} + +SolverFactory::SolverFactory() + : _available_solvers(SolverLoader::GetAvailableSolvers()) { + isXpress_available_ = + std::find(available_solvers.cbegin(), available_solvers.cend(), + XPRESS_STR) != available_solvers.cend(); } SolverAbstract::Ptr SolverFactory::create_solver( @@ -24,11 +35,10 @@ SolverAbstract::Ptr SolverFactory::create_solver( if (solver_name == "") { throw InvalidSolverNameException(solver_name, LOGLOCATION); } -#ifdef XPRESS - else if (solver_name == XPRESS_STR) { + + else if (isXpress_available_ && solver_name == XPRESS_STR) { return std::make_shared(); } -#endif #ifdef COIN_OR if (solver_name == COIN_STR && solver_type == SOLVER_TYPE::CONTINUOUS) { return std::make_shared(); @@ -58,12 +68,9 @@ SolverAbstract::Ptr SolverFactory::create_solver( const std::string &solver_name) const { if (solver_name == "") { throw InvalidSolverNameException(solver_name, LOGLOCATION); - } -#ifdef XPRESS - else if (solver_name == XPRESS_STR) { + } else if (isXpress_available_ && solver_name == XPRESS_STR) { return std::make_shared(); } -#endif #ifdef COIN_OR else if (solver_name == CLP_STR) { return std::make_shared(); @@ -81,11 +88,9 @@ SolverAbstract::Ptr SolverFactory::create_solver( if (solver_name == "") { throw InvalidSolverNameException(solver_name, LOGLOCATION); } -#ifdef XPRESS - else if (solver_name == XPRESS_STR) { + if (isXpress_available_ && solver_name == XPRESS_STR) { return std::make_shared(log_manager); } -#endif #ifdef COIN_OR else if (solver_name == CLP_STR) { return std::make_shared(log_manager); @@ -105,11 +110,9 @@ SolverAbstract::Ptr SolverFactory::copy_solver( if (solver_name == "") { throw InvalidSolverNameException(solver_name, LOGLOCATION); } -#ifdef XPRESS - else if (solver_name == XPRESS_STR) { + if (isXpress_available_ && solver_name == XPRESS_STR) { return std::make_shared(to_copy); } -#endif #ifdef COIN_OR else if (solver_name == CLP_STR) { return std::make_shared(to_copy); diff --git a/src/cpp/multisolver_interface/SolverXpress.cpp b/src/cpp/multisolver_interface/SolverXpress.cpp index 1832f0c3d..e7df31e5c 100644 --- a/src/cpp/multisolver_interface/SolverXpress.cpp +++ b/src/cpp/multisolver_interface/SolverXpress.cpp @@ -6,6 +6,8 @@ #include "StringManip.h" +using namespace LoadXpress; + /************************************************************************************************* ----------------------------------- Constructor/Desctructor -------------------------------- @@ -25,6 +27,7 @@ SolverXpress::SolverXpress() { std::lock_guard guard(license_guard); int status = 0; if (_NumberOfProblems == 0) { + initXpressEnv(); status = XPRSinit(NULL); zero_status_check(status, "initialize XPRESS environment", LOGLOCATION); } diff --git a/src/cpp/multisolver_interface/SolverXpress.h b/src/cpp/multisolver_interface/SolverXpress.h index 06cd8bf61..432936690 100644 --- a/src/cpp/multisolver_interface/SolverXpress.h +++ b/src/cpp/multisolver_interface/SolverXpress.h @@ -4,7 +4,7 @@ #include #include "multisolver_interface/SolverAbstract.h" -#include "xprs.h" +#include "multisolver_interface/environment.h" /*! * \class class SolverXpress diff --git a/src/cpp/multisolver_interface/environment.cc b/src/cpp/multisolver_interface/environment.cc new file mode 100644 index 000000000..e4f77ca5a --- /dev/null +++ b/src/cpp/multisolver_interface/environment.cc @@ -0,0 +1,432 @@ +// This this file is an adaptation of OR-Tools for Antares-Xpansion needs +// see orginal at https://github.com/google/or-tools +// Copyright 2010-2021 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "multisolver_interface/environment.h" + +#include +#include +#include +#include + +namespace LoadXpress { + +#define STRINGIFY2(X) #X +#define STRINGIFY(X) STRINGIFY2(X) + +// This was generated with the parse_header_xpress.py script. +// See the comment at the top of the script. + +std::string StringJoin(const std::vector& vec) { + std::string ret; + for (const auto& str : vec) ret += str + "', '"; + return ret; +} +// This is the 'define' section. +std::function XPRSinit = nullptr; +std::function XPRScopyprob = + nullptr; +std::function + XPRSwritebasis = nullptr; +std::function + XPRSreadprob = nullptr; +std::function + XPRSreadbasis = nullptr; +std::function + XPRSgetrows = nullptr; +std::function + XPRSgetindex = nullptr; +std::function + XPRSgetnames = nullptr; +std::function + XPRSaddnames = nullptr; +std::function XPRSlpoptimize = nullptr; +std::function XPRSmipoptimize = nullptr; +std::function XPRSfree = nullptr; +std::function XPRScreateprob = nullptr; +std::function + XPRSloadlp = nullptr; +std::function XPRSdestroyprob = nullptr; + +std::function + XPRSwriteprob = nullptr; +std::function XPRSgetintcontrol = + nullptr; +std::function + XPRSgetobj = nullptr; +std::function + XPRSgetrowtype = nullptr; +std::function + XPRSgetrhs = nullptr; +std::function + XPRSgetrhsrange = nullptr; +std::function + XPRSgetcoltype = nullptr; +std::function XPRSgetlb = + nullptr; +std::function XPRSgetub = + nullptr; +std::function XPRSdelrows = + nullptr; +std::function + XPRSaddrows = nullptr; +std::function + XPRSaddcols = nullptr; + +std::function + XPRSchgobj = nullptr; +std::function XPRSchgobjsense = nullptr; +std::function + XPRSchgbounds = nullptr; +std::function + XPRSchgcoltype = nullptr; +std::function + XPRSchgrhs = nullptr; + +std::function XPRSchgcoef = + nullptr; +std::function XPRSgetbasis = + nullptr; +std::function + XPRSgetdblattrib = nullptr; +std::function + XPRSgetlpsol = nullptr; +std::function XPRSgetmipsol = + nullptr; +std::function + XPRSsetcbmessage = nullptr; +std::function XPRSsetintcontrol = + nullptr; +std::function XPRSsetdblcontrol = + nullptr; +std::function XPRSgetbanner = nullptr; + +std::function XPRSgetlicerrmsg = nullptr; +std::function XPRSlicense = nullptr; +std::function XPRSgetversion = nullptr; +std::function XPRSgetintattrib = + nullptr; + +bool LoadXpressFunctions(DynamicLibrary* xpress_dynamic_library) { + // This was generated with the parse_header_xpress.py script. + // See the comment at the top of the script. + + // This is the 'assign' section. + xpress_dynamic_library->GetFunction(&XPRSinit, "XPRSinit"); + xpress_dynamic_library->GetFunction(&XPRScopyprob, "XPRScopyprob"); + xpress_dynamic_library->GetFunction(&XPRSwritebasis, "XPRSwritebasis"); + xpress_dynamic_library->GetFunction(&XPRSreadprob, "XPRSreadprob"); + xpress_dynamic_library->GetFunction(&XPRSreadbasis, "XPRSreadbasis"); + xpress_dynamic_library->GetFunction(&XPRSgetrows, "XPRSgetrows"); + xpress_dynamic_library->GetFunction(&XPRSgetindex, "XPRSgetindex"); + xpress_dynamic_library->GetFunction(&XPRSgetnames, "XPRSgetnames"); + xpress_dynamic_library->GetFunction(&XPRSaddnames, "XPRSaddnames"); + xpress_dynamic_library->GetFunction(&XPRSlpoptimize, "XPRSlpoptimize"); + xpress_dynamic_library->GetFunction(&XPRSmipoptimize, "XPRSmipoptimize"); + xpress_dynamic_library->GetFunction(&XPRSfree, "XPRSfree"); + xpress_dynamic_library->GetFunction(&XPRSloadlp, "XPRSloadlp"); + xpress_dynamic_library->GetFunction(&XPRScreateprob, "XPRScreateprob"); + xpress_dynamic_library->GetFunction(&XPRSdestroyprob, "XPRSdestroyprob"); + xpress_dynamic_library->GetFunction(&XPRSwriteprob, "XPRSwriteprob"); + xpress_dynamic_library->GetFunction(&XPRSgetintcontrol, "XPRSgetintcontrol"); + xpress_dynamic_library->GetFunction(&XPRSgetintattrib, "XPRSgetintattrib"); + xpress_dynamic_library->GetFunction(&XPRSgetobj, "XPRSgetobj"); + xpress_dynamic_library->GetFunction(&XPRSgetrowtype, "XPRSgetrowtype"); + xpress_dynamic_library->GetFunction(&XPRSgetrhsrange, "XPRSgetrhsrange"); + xpress_dynamic_library->GetFunction(&XPRSgetrhs, "XPRSgetrhs"); + xpress_dynamic_library->GetFunction(&XPRSgetcoltype, "XPRSgetcoltype"); + xpress_dynamic_library->GetFunction(&XPRSgetlb, "XPRSgetlb"); + xpress_dynamic_library->GetFunction(&XPRSgetub, "XPRSgetub"); + xpress_dynamic_library->GetFunction(&XPRSdelrows, "XPRSdelrows"); + xpress_dynamic_library->GetFunction(&XPRSaddrows, "XPRSaddrows"); + xpress_dynamic_library->GetFunction(&XPRSchgobj, "XPRSchgobj"); + xpress_dynamic_library->GetFunction(&XPRSaddcols, "XPRSaddcols"); + xpress_dynamic_library->GetFunction(&XPRSchgobjsense, "XPRSchgobjsense"); + xpress_dynamic_library->GetFunction(&XPRSchgbounds, "XPRSchgbounds"); + xpress_dynamic_library->GetFunction(&XPRSchgcoltype, "XPRSchgcoltype"); + xpress_dynamic_library->GetFunction(&XPRSchgrhs, "XPRSchgrhs"); + xpress_dynamic_library->GetFunction(&XPRSchgcoef, "XPRSchgcoef"); + xpress_dynamic_library->GetFunction(&XPRSgetbasis, "XPRSgetbasis"); + xpress_dynamic_library->GetFunction(&XPRSgetlpsol, "XPRSgetlpsol"); + xpress_dynamic_library->GetFunction(&XPRSgetdblattrib, "XPRSgetdblattrib"); + xpress_dynamic_library->GetFunction(&XPRSgetmipsol, "XPRSgetmipsol"); + xpress_dynamic_library->GetFunction(&XPRSsetcbmessage, "XPRSsetcbmessage"); + xpress_dynamic_library->GetFunction(&XPRSsetintcontrol, "XPRSsetintcontrol"); + xpress_dynamic_library->GetFunction(&XPRSsetdblcontrol, "XPRSsetdblcontrol"); + xpress_dynamic_library->GetFunction(&XPRSgetbanner, "XPRSgetbanner"); + xpress_dynamic_library->GetFunction(&XPRSgetlicerrmsg, "XPRSgetlicerrmsg"); + xpress_dynamic_library->GetFunction(&XPRSlicense, "XPRSlicense"); + xpress_dynamic_library->GetFunction(&XPRSgetversion, "XPRSgetversion"); + + auto notFound = xpress_dynamic_library->FunctionsNotFound(); + if (!notFound.empty()) { + std::string msg( + "Could not find the following functions (list may not be " + "exhaustive). [" + + StringJoin(notFound) + + "]. Please make sure that your XPRESS install is " + "up-to-date (>= 8.13.0)."); + std::cout << msg << std::endl; + return false; + } + return true; +} + +void printXpressBanner(bool error) { + char banner[XPRS_MAXBANNERLENGTH]; + XPRSgetbanner(banner); + + if (error) { + std::cerr << "Xpress banner :\n" << banner << "\n"; + } else { + std::cout << "Xpress banner :\n" << banner << "\n"; + } +} + +std::string GetXpressVarFromEnvironmentVariables(const char* XPRESS_var) { + // Look for libraries pointed by XPRESSDIR first. + std::string xpress_home_from_env = ""; +#ifdef _MSC_VER + size_t requiredSize; + + getenv_s(&requiredSize, NULL, 0, XPRESS_var); + if (requiredSize == 0) { + std::cerr << "[Windows getenv_s function]: " << XPRESS_var + << " doesn't exist!\n"; + } + + xpress_home_from_env.resize(requiredSize); + + // Get the value of the LIB environment variable. + getenv_s(&requiredSize, xpress_home_from_env.data(), requiredSize, + XPRESS_var); + +#else + char* path = nullptr; + path = getenv(XPRESS_var); + if (path) { + xpress_home_from_env = path; + } +#endif + return xpress_home_from_env; +} + +std::vector XpressDynamicLibraryPotentialPaths() { + std::vector potential_paths; + + const char* XPRESSDIR = "XPRESSDIR"; + std::string xpress_home_from_env = + GetXpressVarFromEnvironmentVariables(XPRESSDIR); + + if (xpress_home_from_env != "") { + std::filesystem::path prefix(xpress_home_from_env); +#if defined(_MSC_VER) // Windows + potential_paths.push_back((prefix / "bin" / "xprs.dll").string()); +#elif defined(__APPLE__) // OS X + potential_paths.push_back((prefix / "/lib/libxprs.dylib").string()); +#elif defined(__GNUC__) // Linux + potential_paths.push_back((prefix / "/lib/libxprs.so").string()); +#else + std::cerr << "OS Not recognized by xpress/environment.cc." + << " You won't be able to use Xpress."; +#endif + } else { + std::cerr << "Warning: " + << "Environment variable " << XPRESSDIR << " undefined.\n"; + } + + // Search for canonical places. +#if defined(_MSC_VER) // Windows + potential_paths.push_back("C:\\xpressmp\\bin\\xprs.dll"); + potential_paths.push_back("C:\\Program Files\\xpressmp\\bin\\xprs.dll"); +#elif defined(__APPLE__) // OS X + potential_paths.push_back("/Library/xpressmp/lib/libxprs.dylib"); +#elif defined(__GNUC__) // Linux + potential_paths.push_back("/opt/xpressmp/lib/libxprs.so"); +#else + std::cerr << "OS Not recognized by environment.cc." + << " You won't be able to use Xpress."; +#endif + return potential_paths; +} + +bool LoadXpressDynamicLibrary(std::string& xpresspath) { + static std::string xpress_lib_path; + static std::once_flag xpress_loading_done; + static bool ret; + static DynamicLibrary xpress_library; + // static std::mutex mutex; + + // mutex.lock(); + + std::call_once(xpress_loading_done, []() { + const std::vector canonical_paths = + XpressDynamicLibraryPotentialPaths(); + for (const std::string& path : canonical_paths) { + if (xpress_library.TryToLoad(path)) { + std::cout << "Info: " + << "Found the Xpress library in " << path << "."; + xpress_lib_path.clear(); + std::filesystem::path p(path); + p.remove_filename(); + xpress_lib_path.append(p.string()); + break; + } + } + + if (xpress_library.LibraryIsLoaded()) { + ret = LoadXpressFunctions(&xpress_library); + } else { + std::string msg("Could not find the Xpress shared library. Looked in: [" + + StringJoin(canonical_paths) + + "]. Please check environment variable XPRESSDIR\n"); + std::cout << msg << std::endl; + ret = false; + } + }); + xpresspath.clear(); + xpresspath.append(xpress_lib_path); + return ret; +} + +/** init XPRESS environment */ +bool initXpressEnv(bool verbose, int xpress_oem_license_key) { + std::string xpresspath; + bool status = LoadXpressDynamicLibrary(xpresspath); + if (!status) { + std::cout << "Warning: " << status << "\n"; + return false; + } + + std::string xpress_from_env = GetXpressVarFromEnvironmentVariables("XPRESS"); + if (xpress_from_env == "") { + if (verbose) { + std::cout << "Warning: Environment variable XPRESS undefined.\n"; + } + if (xpresspath.empty()) { + return false; + } + } else { + xpresspath = xpress_from_env; + } + + int code; + + // if not an OEM key + if (xpress_oem_license_key == 0) { + if (verbose) { + std::cout << "Initialising xpress-MP with parameter " << xpresspath + << "\n"; + } + + code = XPRSinit(xpresspath.c_str()); + + if (!code) { + // XPRSbanner informs about Xpress version, options and error messages + if (verbose) { + printXpressBanner(false); + char version[16]; + XPRSgetversion(version); + std::cout << "Warning: " + << "Optimizer version: " << version + << " (Antares-Xpansion was compiled with version " + << XPVERSION << ").\n"; + } + return true; + } else { + std::cerr << "XpressInterface: Xpress found at " << xpresspath << "\n"; + char errmsg[256]; + XPRSgetlicerrmsg(errmsg, 256); + + std::cerr << "Xpress License error : " << errmsg + << " (XPRSinit returned code " << code << "). Please check" + << " environment variable XPRESS.\n"; + + return false; + } + } else { + // if OEM key + if (verbose) { + std::cout << "Warning: " + << "Initialising xpress-MP with OEM key " + << xpress_oem_license_key << "\n"; + } + + int nvalue = 0; + int ierr; + char slicmsg[256] = ""; + char errmsg[256]; + + XPRSlicense(&nvalue, slicmsg); + if (verbose) { + std::cout << "First message from XPRSLicense : " << slicmsg << "\n"; + } + + nvalue = xpress_oem_license_key - ((nvalue * nvalue) / 19); + ierr = XPRSlicense(&nvalue, slicmsg); + + if (verbose) { + std::cout << "Second message from XPRSLicense : " << slicmsg << "\n"; + } + if (ierr == 16) { + if (verbose) { + std::cout << "Optimizer development software detected\n"; + } + } else if (ierr != 0) { + // get the license error message + XPRSgetlicerrmsg(errmsg, 256); + + std::cerr << "Xpress Error Message: " << errmsg << "\n"; + return false; + } + + code = XPRSinit(NULL); + + if (!code) { + return true; + } else { + std::cerr << "XPRSinit returned code : " << code << "\n"; + return false; + } + } +} + +bool XpressIsCorrectlyInstalled() { + bool correctlyInstalled = initXpressEnv(false); + if (correctlyInstalled) { + XPRSfree(); + } + return correctlyInstalled; +} + +} // namespace LoadXpress diff --git a/src/cpp/multisolver_interface/include/multisolver_interface/SolverFactory.h b/src/cpp/multisolver_interface/include/multisolver_interface/SolverFactory.h index 20cdfe57e..332eedb71 100644 --- a/src/cpp/multisolver_interface/include/multisolver_interface/SolverFactory.h +++ b/src/cpp/multisolver_interface/include/multisolver_interface/SolverFactory.h @@ -8,6 +8,15 @@ enum class SOLVER_TYPE { INTEGER, CONTINUOUS }; const std::string UNKNOWN_STR("UNKNOWN"), COIN_STR("COIN"), CBC_STR("CBC"), CLP_STR("CLP"), XPRESS_STR("XPRESS"); +/*! + * \class class SolverLoader + * \brief Class to check if supported solvers are available + */ +class SolverLoader { + public: + static std::vector GetAvailableSolvers(); +}; + /*! * \class class SolverFactory * \brief Class to manage the creation of solvers from the different @@ -31,9 +40,8 @@ class SolverFactory { * @param solver_name : Name of the solver to use */ SolverAbstract::Ptr create_solver(const std::string &solver_name) const; - SolverAbstract::Ptr create_solver( - const std::string &solver_name, - SolverLogManager&log_manager) const; + SolverAbstract::Ptr create_solver(const std::string &solver_name, + SolverLogManager &log_manager) const; /** * @brief Creates and returns to an object solver from the wanted @@ -44,9 +52,9 @@ class SolverFactory { */ SolverAbstract::Ptr create_solver(const std::string &solver_name, const SOLVER_TYPE solver_type) const; - SolverAbstract::Ptr create_solver( - const std::string &solver_name, const SOLVER_TYPE solver_type, - SolverLogManager&log_manager) const; + SolverAbstract::Ptr create_solver(const std::string &solver_name, + const SOLVER_TYPE solver_type, + SolverLogManager &log_manager) const; /** * @brief Copy constructor : Creates and returns to an object solver from the @@ -62,4 +70,6 @@ class SolverFactory { * @brief Returns a reference to the list of available solvers */ const std::vector &get_solvers_list() const; + + bool isXpress_available_ = false; }; diff --git a/src/cpp/multisolver_interface/include/multisolver_interface/dynamic_library.h b/src/cpp/multisolver_interface/include/multisolver_interface/dynamic_library.h new file mode 100644 index 000000000..fd5909995 --- /dev/null +++ b/src/cpp/multisolver_interface/include/multisolver_interface/dynamic_library.h @@ -0,0 +1,115 @@ +// Copyright 2010-2022 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef OR_TOOLS_BASE_DYNAMIC_LIBRARY_H_ +#define OR_TOOLS_BASE_DYNAMIC_LIBRARY_H_ + +#include +#include +#include +#include + +#if defined(_MSC_VER) +#define WIN32_LEAN_AND_MEAN // disables several conflicting macros +#include +#elif defined(__GNUC__) +#include +#endif + +class DynamicLibrary { + static constexpr size_t kMaxFunctionsNotFound = 10; + + public: + DynamicLibrary() : library_handle_(nullptr) {} + + ~DynamicLibrary() { + if (library_handle_ == nullptr) { + return; + } + +#if defined(_MSC_VER) + FreeLibrary(static_cast(library_handle_)); +#elif defined(__GNUC__) + dlclose(library_handle_); +#endif + } + + bool TryToLoad(const std::string& library_name) { + library_name_ = std::string(library_name); +#if defined(_MSC_VER) + library_handle_ = static_cast(LoadLibraryA(library_name.c_str())); +#elif defined(__GNUC__) + library_handle_ = dlopen(library_name.c_str(), RTLD_NOW); +#endif + return library_handle_ != nullptr; + } + + bool LibraryIsLoaded() const { return library_handle_ != nullptr; } + + const std::vector& FunctionsNotFound() const { + return functions_not_found_; + } + + template + std::function GetFunction(const char* function_name) { + const void* function_address = +#if defined(_MSC_VER) + static_cast(GetProcAddress( + static_cast(library_handle_), function_name)); +#else + dlsym(library_handle_, function_name); +#endif + // We don't really need the full list of missing functions, + // just a few are enough. + if (!function_address && + functions_not_found_.size() < kMaxFunctionsNotFound) + functions_not_found_.push_back(function_name); + + return TypeParser::CreateFunction(function_address); + } + + template + std::function GetFunction(const std::string& function_name) { + return GetFunction(function_name.c_str()); + } + + template + void GetFunction(std::function* function, const char* function_name) { + *function = GetFunction(function_name); + } + + template + void GetFunction(std::function* function, + const std::string function_name) { + GetFunction(function, function_name.c_str()); + } + + private: + void* library_handle_ = nullptr; + std::string library_name_; + std::vector functions_not_found_; + + template + struct TypeParser {}; + + template + struct TypeParser { + static std::function CreateFunction( + const void* function_address) { + return std::function(reinterpret_cast( + const_cast(function_address))); + } + }; +}; + +#endif // OR_TOOLS_BASE_DYNAMIC_LIBRARY_H_ diff --git a/src/cpp/multisolver_interface/include/multisolver_interface/environment.h b/src/cpp/multisolver_interface/include/multisolver_interface/environment.h new file mode 100644 index 000000000..003130ee9 --- /dev/null +++ b/src/cpp/multisolver_interface/include/multisolver_interface/environment.h @@ -0,0 +1,458 @@ + +// This this file is an adaptation of OR-Tools for Antares-Xpansion needs +// see orginal at https://github.com/google/or-tools +// Copyright 2010-2021 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once +#include + +#include "dynamic_library.h" +extern "C" { +typedef struct xo_prob_struct* XPRSprob; +} + +namespace LoadXpress { + +void printXpressBanner(bool error); + +bool initXpressEnv(bool verbose = true, int xpress_oem_license_key = 0); + +bool XpressIsCorrectlyInstalled(); +// clang-format off +// Force the loading of the xpress dynamic library. It returns true if the +// library was successfully loaded. This method can only be called once. +// Successive calls are no-op. +// +// Note that it does not check if a token license can be grabbed. +bool LoadXpressDynamicLibrary(std::string &xpresspath); + +// The list of #define and extern std::function<> below is generated directly +// from xprs.h via parse_header_xpress.py +// See the top comment on the parse_header_xpress.py file. +// This is the header section +#if defined(_WIN32) +#define XPRSint64 __int64 +#elif defined(__LP64__) || defined(_LP64) || defined(__ILP64__) || defined(_ILP64) +#define XPRSint64 long +#else +#define XPRSint64 long long +#endif + +#if defined(_MSC_VER) +#define XPRS_CC __stdcall +#else +#define XPRS_CC +#endif +#define XPRS_PLUSINFINITY 1.0e+20 +#define XPRS_MINUSINFINITY -1.0e+20 +#define XPRS_MAXBANNERLENGTH 512 +#define XPVERSION 41 +#define XPRS_MPSRHSNAME 6001 +#define XPRS_MPSOBJNAME 6002 +#define XPRS_MPSRANGENAME 6003 +#define XPRS_MPSBOUNDNAME 6004 +#define XPRS_OUTPUTMASK 6005 +#define XPRS_TUNERMETHODFILE 6017 +#define XPRS_TUNEROUTPUTPATH 6018 +#define XPRS_TUNERSESSIONNAME 6019 +#define XPRS_COMPUTEEXECSERVICE 6022 +#define XPRS_MAXCUTTIME 8149 +#define XPRS_MAXSTALLTIME 8443 +#define XPRS_TUNERMAXTIME 8364 +#define XPRS_MATRIXTOL 7001 +#define XPRS_PIVOTTOL 7002 +#define XPRS_FEASTOL 7003 +#define XPRS_OUTPUTTOL 7004 +#define XPRS_SOSREFTOL 7005 +#define XPRS_OPTIMALITYTOL 7006 +#define XPRS_ETATOL 7007 +#define XPRS_RELPIVOTTOL 7008 +#define XPRS_MIPTOL 7009 +#define XPRS_MIPTOLTARGET 7010 +#define XPRS_BARPERTURB 7011 +#define XPRS_MIPADDCUTOFF 7012 +#define XPRS_MIPABSCUTOFF 7013 +#define XPRS_MIPRELCUTOFF 7014 +#define XPRS_PSEUDOCOST 7015 +#define XPRS_PENALTY 7016 +#define XPRS_BIGM 7018 +#define XPRS_MIPABSSTOP 7019 +#define XPRS_MIPRELSTOP 7020 +#define XPRS_CROSSOVERACCURACYTOL 7023 +#define XPRS_PRIMALPERTURB 7024 +#define XPRS_DUALPERTURB 7025 +#define XPRS_BAROBJSCALE 7026 +#define XPRS_BARRHSSCALE 7027 +#define XPRS_CHOLESKYTOL 7032 +#define XPRS_BARGAPSTOP 7033 +#define XPRS_BARDUALSTOP 7034 +#define XPRS_BARPRIMALSTOP 7035 +#define XPRS_BARSTEPSTOP 7036 +#define XPRS_ELIMTOL 7042 +#define XPRS_MARKOWITZTOL 7047 +#define XPRS_MIPABSGAPNOTIFY 7064 +#define XPRS_MIPRELGAPNOTIFY 7065 +#define XPRS_BARLARGEBOUND 7067 +#define XPRS_PPFACTOR 7069 +#define XPRS_REPAIRINDEFINITEQMAX 7071 +#define XPRS_BARGAPTARGET 7073 +#define XPRS_DUMMYCONTROL 7075 +#define XPRS_BARSTARTWEIGHT 7076 +#define XPRS_BARFREESCALE 7077 +#define XPRS_SBEFFORT 7086 +#define XPRS_HEURDIVERANDOMIZE 7089 +#define XPRS_HEURSEARCHEFFORT 7090 +#define XPRS_CUTFACTOR 7091 +#define XPRS_EIGENVALUETOL 7097 +#define XPRS_INDLINBIGM 7099 +#define XPRS_TREEMEMORYSAVINGTARGET 7100 +#define XPRS_INDPRELINBIGM 7102 +#define XPRS_RELAXTREEMEMORYLIMIT 7105 +#define XPRS_MIPABSGAPNOTIFYOBJ 7108 +#define XPRS_MIPABSGAPNOTIFYBOUND 7109 +#define XPRS_PRESOLVEMAXGROW 7110 +#define XPRS_HEURSEARCHTARGETSIZE 7112 +#define XPRS_CROSSOVERRELPIVOTTOL 7113 +#define XPRS_CROSSOVERRELPIVOTTOLSAFE 7114 +#define XPRS_DETLOGFREQ 7116 +#define XPRS_MAXIMPLIEDBOUND 7120 +#define XPRS_FEASTOLTARGET 7121 +#define XPRS_OPTIMALITYTOLTARGET 7122 +#define XPRS_PRECOMPONENTSEFFORT 7124 +#define XPRS_LPLOGDELAY 7127 +#define XPRS_HEURDIVEITERLIMIT 7128 +#define XPRS_BARKERNEL 7130 +#define XPRS_FEASTOLPERTURB 7132 +#define XPRS_CROSSOVERFEASWEIGHT 7133 +#define XPRS_LUPIVOTTOL 7139 +#define XPRS_MIPRESTARTGAPTHRESHOLD 7140 +#define XPRS_NODEPROBINGEFFORT 7141 +#define XPRS_INPUTTOL 7143 +#define XPRS_MIPRESTARTFACTOR 7145 +#define XPRS_BAROBJPERTURB 7146 +#define XPRS_CPIALPHA 7149 +#define XPRS_GLOBALBOUNDINGBOX 7154 +#define XPRS_TIMELIMIT 7158 +#define XPRS_SOLTIMELIMIT 7159 +#define XPRS_REPAIRINFEASTIMELIMIT 7160 +#define XPRS_EXTRAROWS 8004 +#define XPRS_EXTRACOLS 8005 +#define XPRS_LPITERLIMIT 8007 +#define XPRS_LPLOG 8009 +#define XPRS_SCALING 8010 +#define XPRS_PRESOLVE 8011 +#define XPRS_CRASH 8012 +#define XPRS_PRICINGALG 8013 +#define XPRS_INVERTFREQ 8014 +#define XPRS_INVERTMIN 8015 +#define XPRS_MAXNODE 8018 +#define XPRS_MAXTIME 8020 +#define XPRS_MAXMIPSOL 8021 +#define XPRS_SIFTPASSES 8022 +#define XPRS_DEFAULTALG 8023 +#define XPRS_VARSELECTION 8025 +#define XPRS_NODESELECTION 8026 +#define XPRS_BACKTRACK 8027 +#define XPRS_MIPLOG 8028 +#define XPRS_KEEPNROWS 8030 +#define XPRS_MPSECHO 8032 +#define XPRS_MAXPAGELINES 8034 +#define XPRS_OUTPUTLOG 8035 +#define XPRS_BARSOLUTION 8038 +#define XPRS_CACHESIZE 8043 +#define XPRS_CROSSOVER 8044 +#define XPRS_BARITERLIMIT 8045 +#define XPRS_CHOLESKYALG 8046 +#define XPRS_BAROUTPUT 8047 +#define XPRS_EXTRAMIPENTS 8051 +#define XPRS_REFACTOR 8052 +#define XPRS_BARTHREADS 8053 +#define XPRS_KEEPBASIS 8054 +#define XPRS_CROSSOVEROPS 8060 +#define XPRS_VERSION 8061 +#define XPRS_CROSSOVERTHREADS 8065 +#define XPRS_BIGMMETHOD 8068 +#define XPRS_MPSNAMELENGTH 8071 +#define XPRS_ELIMFILLIN 8073 +#define XPRS_PRESOLVEOPS 8077 +#define XPRS_MIPPRESOLVE 8078 +#define XPRS_MIPTHREADS 8079 +#define XPRS_BARORDER 8080 +#define XPRS_BREADTHFIRST 8082 +#define XPRS_AUTOPERTURB 8084 +#define XPRS_DENSECOLLIMIT 8086 +#define XPRS_CALLBACKFROMMASTERTHREAD 8090 +#define XPRS_MAXMCOEFFBUFFERELEMS 8091 +#define XPRS_REFINEOPS 8093 +#define XPRS_LPREFINEITERLIMIT 8094 +#define XPRS_MIPREFINEITERLIMIT 8095 +#define XPRS_DUALIZEOPS 8097 +#define XPRS_CROSSOVERITERLIMIT 8104 +#define XPRS_PREBASISRED 8106 +#define XPRS_PRESORT 8107 +#define XPRS_PREPERMUTE 8108 +#define XPRS_PREPERMUTESEED 8109 +#define XPRS_MAXMEMORYSOFT 8112 +#define XPRS_CUTFREQ 8116 +#define XPRS_SYMSELECT 8117 +#define XPRS_SYMMETRY 8118 +#define XPRS_MAXMEMORYHARD 8119 +#define XPRS_MIQCPALG 8125 +#define XPRS_QCCUTS 8126 +#define XPRS_QCROOTALG 8127 +#define XPRS_PRECONVERTSEPARABLE 8128 +#define XPRS_ALGAFTERNETWORK 8129 +#define XPRS_TRACE 8130 +#define XPRS_MAXIIS 8131 +#define XPRS_CPUTIME 8133 +#define XPRS_COVERCUTS 8134 +#define XPRS_GOMCUTS 8135 +#define XPRS_LPFOLDING 8136 +#define XPRS_MPSFORMAT 8137 +#define XPRS_CUTSTRATEGY 8138 +#define XPRS_CUTDEPTH 8139 +#define XPRS_TREECOVERCUTS 8140 +#define XPRS_TREEGOMCUTS 8141 +#define XPRS_CUTSELECT 8142 +#define XPRS_TREECUTSELECT 8143 +#define XPRS_DUALIZE 8144 +#define XPRS_DUALGRADIENT 8145 +#define XPRS_SBITERLIMIT 8146 +#define XPRS_SBBEST 8147 +#define XPRS_BARINDEFLIMIT 8153 +#define XPRS_HEURFREQ 8155 +#define XPRS_HEURDEPTH 8156 +#define XPRS_HEURMAXSOL 8157 +#define XPRS_HEURNODES 8158 +#define XPRS_LNPBEST 8160 +#define XPRS_LNPITERLIMIT 8161 +#define XPRS_BRANCHCHOICE 8162 +#define XPRS_BARREGULARIZE 8163 +#define XPRS_SBSELECT 8164 +#define XPRS_LOCALCHOICE 8170 +#define XPRS_LOCALBACKTRACK 8171 +#define XPRS_DUALSTRATEGY 8174 +#define XPRS_L1CACHE 8175 +#define XPRS_HEURDIVESTRATEGY 8177 +#define XPRS_HEURSELECT 8178 +#define XPRS_BARSTART 8180 +#define XPRS_PRESOLVEPASSES 8183 +#define XPRS_BARNUMSTABILITY 8186 +#define XPRS_BARORDERTHREADS 8187 +#define XPRS_EXTRASETS 8190 +#define XPRS_FEASIBILITYPUMP 8193 +#define XPRS_PRECOEFELIM 8194 +#define XPRS_PREDOMCOL 8195 +#define XPRS_HEURSEARCHFREQ 8196 +#define XPRS_HEURDIVESPEEDUP 8197 +#define XPRS_SBESTIMATE 8198 +#define XPRS_BARCORES 8202 +#define XPRS_MAXCHECKSONMAXTIME 8203 +#define XPRS_MAXCHECKSONMAXCUTTIME 8204 +#define XPRS_HISTORYCOSTS 8206 +#define XPRS_ALGAFTERCROSSOVER 8208 +#define XPRS_MUTEXCALLBACKS 8210 +#define XPRS_BARCRASH 8211 +#define XPRS_HEURDIVESOFTROUNDING 8215 +#define XPRS_HEURSEARCHROOTSELECT 8216 +#define XPRS_HEURSEARCHTREESELECT 8217 +#define XPRS_MPS18COMPATIBLE 8223 +#define XPRS_ROOTPRESOLVE 8224 +#define XPRS_CROSSOVERDRP 8227 +#define XPRS_FORCEOUTPUT 8229 +#define XPRS_PRIMALOPS 8231 +#define XPRS_DETERMINISTIC 8232 +#define XPRS_PREPROBING 8238 +#define XPRS_TREEMEMORYLIMIT 8242 +#define XPRS_TREECOMPRESSION 8243 +#define XPRS_TREEDIAGNOSTICS 8244 +#define XPRS_MAXTREEFILESIZE 8245 +#define XPRS_PRECLIQUESTRATEGY 8247 +#define XPRS_REPAIRINFEASMAXTIME 8250 +#define XPRS_IFCHECKCONVEXITY 8251 +#define XPRS_PRIMALUNSHIFT 8252 +#define XPRS_REPAIRINDEFINITEQ 8254 +#define XPRS_MIPRAMPUP 8255 +#define XPRS_MAXLOCALBACKTRACK 8257 +#define XPRS_USERSOLHEURISTIC 8258 +#define XPRS_FORCEPARALLELDUAL 8265 +#define XPRS_BACKTRACKTIE 8266 +#define XPRS_BRANCHDISJ 8267 +#define XPRS_MIPFRACREDUCE 8270 +#define XPRS_CONCURRENTTHREADS 8274 +#define XPRS_MAXSCALEFACTOR 8275 +#define XPRS_HEURTHREADS 8276 +#define XPRS_THREADS 8278 +#define XPRS_HEURBEFORELP 8280 +#define XPRS_PREDOMROW 8281 +#define XPRS_BRANCHSTRUCTURAL 8282 +#define XPRS_QUADRATICUNSHIFT 8284 +#define XPRS_BARPRESOLVEOPS 8286 +#define XPRS_QSIMPLEXOPS 8288 +#define XPRS_MIPRESTART 8290 +#define XPRS_CONFLICTCUTS 8292 +#define XPRS_PREPROTECTDUAL 8293 +#define XPRS_CORESPERCPU 8296 +#define XPRS_RESOURCESTRATEGY 8297 +#define XPRS_CLAMPING 8301 +#define XPRS_SLEEPONTHREADWAIT 8302 +#define XPRS_PREDUPROW 8307 +#define XPRS_CPUPLATFORM 8312 +#define XPRS_BARALG 8315 +#define XPRS_SIFTING 8319 +#define XPRS_LPLOGSTYLE 8326 +#define XPRS_RANDOMSEED 8328 +#define XPRS_TREEQCCUTS 8331 +#define XPRS_PRELINDEP 8333 +#define XPRS_DUALTHREADS 8334 +#define XPRS_PREOBJCUTDETECT 8336 +#define XPRS_PREBNDREDQUAD 8337 +#define XPRS_PREBNDREDCONE 8338 +#define XPRS_PRECOMPONENTS 8339 +#define XPRS_MAXMIPTASKS 8347 +#define XPRS_MIPTERMINATIONMETHOD 8348 +#define XPRS_PRECONEDECOMP 8349 +#define XPRS_HEURFORCESPECIALOBJ 8350 +#define XPRS_HEURSEARCHROOTCUTFREQ 8351 +#define XPRS_PREELIMQUAD 8353 +#define XPRS_PREIMPLICATIONS 8356 +#define XPRS_TUNERMODE 8359 +#define XPRS_TUNERMETHOD 8360 +#define XPRS_TUNERTARGET 8362 +#define XPRS_TUNERTHREADS 8363 +#define XPRS_TUNERHISTORY 8365 +#define XPRS_TUNERPERMUTE 8366 +#define XPRS_TUNERVERBOSE 8370 +#define XPRS_TUNEROUTPUT 8372 +#define XPRS_PREANALYTICCENTER 8374 +#define XPRS_NETCUTS 8382 +#define XPRS_LPFLAGS 8385 +#define XPRS_MIPKAPPAFREQ 8386 +#define XPRS_OBJSCALEFACTOR 8387 +#define XPRS_TREEFILELOGINTERVAL 8389 +#define XPRS_IGNORECONTAINERCPULIMIT 8390 +#define XPRS_IGNORECONTAINERMEMORYLIMIT 8391 +#define XPRS_MIPDUALREDUCTIONS 8392 +#define XPRS_GENCONSDUALREDUCTIONS 8395 +#define XPRS_PWLDUALREDUCTIONS 8396 +#define XPRS_BARFAILITERLIMIT 8398 +#define XPRS_AUTOSCALING 8406 +#define XPRS_GENCONSABSTRANSFORMATION 8408 +#define XPRS_COMPUTEJOBPRIORITY 8409 +#define XPRS_PREFOLDING 8410 +#define XPRS_NETSTALLLIMIT 8412 +#define XPRS_SERIALIZEPREINTSOL 8413 +#define XPRS_NUMERICALEMPHASIS 8416 +#define XPRS_PWLNONCONVEXTRANSFORMATION 8420 +#define XPRS_MIPCOMPONENTS 8421 +#define XPRS_MIPCONCURRENTNODES 8422 +#define XPRS_MIPCONCURRENTSOLVES 8423 +#define XPRS_OUTPUTCONTROLS 8424 +#define XPRS_SIFTSWITCH 8425 +#define XPRS_HEUREMPHASIS 8427 +#define XPRS_COMPUTEMATX 8428 +#define XPRS_COMPUTEMATX_IIS 8429 +#define XPRS_COMPUTEMATX_IISMAXTIME 8430 +#define XPRS_BARREFITER 8431 +#define XPRS_COMPUTELOG 8434 +#define XPRS_SIFTPRESOLVEOPS 8435 +#define XPRS_CHECKINPUTDATA 8436 +#define XPRS_ESCAPENAMES 8440 +#define XPRS_IOTIMEOUT 8442 +#define XPRS_AUTOCUTTING 8446 +#define XPRS_CALLBACKCHECKTIMEDELAY 8451 +#define XPRS_MULTIOBJOPS 8457 +#define XPRS_MULTIOBJLOG 8458 +#define XPRS_GLOBALSPATIALBRANCHIFPREFERORIG 8465 +#define XPRS_PRECONFIGURATION 8470 +#define XPRS_FEASIBILITYJUMP 8471 +#define XPRS_EXTRAELEMS 8006 +#define XPRS_EXTRASETELEMS 8191 +#define XPRS_LPOBJVAL 2001 +#define XPRS_MIPOBJVAL 2003 +#define XPRS_BESTBOUND 2004 +#define XPRS_OBJRHS 2005 +#define XPRS_OBJSENSE 2008 +#define XPRS_ROWS 1001 +#define XPRS_SIMPLEXITER 1009 +#define XPRS_LPSTATUS 1010 +#define XPRS_MIPSTATUS 1011 +#define XPRS_NODES 1013 +#define XPRS_COLS 1018 +#define XPRS_LP_OPTIMAL 1 +#define XPRS_LP_INFEAS 2 +#define XPRS_LP_UNBOUNDED 5 +#define XPRS_MIP_SOLUTION 4 +#define XPRS_MIP_INFEAS 5 +#define XPRS_MIP_OPTIMAL 6 +#define XPRS_MIP_UNBOUNDED 7 +#define XPRS_OBJ_MINIMIZE 1 +#define XPRS_OBJ_MAXIMIZE -1 + +#define XPRS_ELEMS 1006 +#define XPRS_MIPENTS 1032 +#define XPRS_NAMELENGTH 1028 +#define XPRS_OUTPUTLOG_FULL_OUTPUT 1 +#define XPRS_ERRORCODE 1023 +#define XPRS_OUTPUTLOG_NO_OUTPUT 0 + +extern std::function XPRSinit; +extern std::function XPRScreateprob; +extern std::function XPRScopyprob; +extern std::function XPRSwritebasis; +extern std::function XPRSreadprob; +extern std::function XPRSreadbasis; +extern std::function XPRSgetrows; +extern std::function XPRSgetindex; +extern std::function XPRSgetnames; +extern std::function XPRSaddnames; +extern std::function XPRSlpoptimize; +extern std::function XPRSmipoptimize; +extern std::function XPRSfree; +extern std::function XPRSloadlp; +extern std::function XPRSdestroyprob; +extern std::function XPRSwriteprob; +extern std::function XPRSgetintcontrol; +extern std::function XPRSgetintattrib; +extern std::function XPRSgetobj; +extern std::function XPRSgetrowtype; +extern std::function XPRSgetrhs; +extern std::function XPRSgetrhsrange; +extern std::function XPRSgetcoltype; +extern std::function XPRSgetlb; +extern std::function XPRSgetub; +extern std::function XPRSdelrows; +extern std::function XPRSaddrows; +extern std::function XPRSaddcols; +extern std::function XPRSchgobj; +extern std::function XPRSchgobjsense; +extern std::function XPRSchgbounds; +extern std::function XPRSchgcoltype; +extern std::function XPRSchgrhs; +extern std::function XPRSchgcoef; +extern std::function XPRSgetbasis; +extern std::function XPRSgetdblattrib; +extern std::function XPRSgetlpsol; +extern std::function XPRSgetmipsol; +extern std::function XPRSsetcbmessage; +extern std::function XPRSsetintcontrol; +extern std::function XPRSsetdblcontrol; +extern std::function XPRSgetbanner; + +extern std::function XPRSgetlicerrmsg; +extern std::function XPRSlicense; +extern std::function XPRSgetversion; + + +} // namespace LoadXpress + diff --git a/tests/cpp/sensitivity/SensitivityStudyTest.cpp b/tests/cpp/sensitivity/SensitivityStudyTest.cpp index 6559f5b9b..e19758083 100644 --- a/tests/cpp/sensitivity/SensitivityStudyTest.cpp +++ b/tests/cpp/sensitivity/SensitivityStudyTest.cpp @@ -2,6 +2,7 @@ #include "SensitivityStudy.h" #include "gtest/gtest.h" #include "multisolver_interface/SolverFactory.h" +#include "multisolver_interface/environment.h" class SensitivityStudyTest : public ::testing::Test { public: @@ -106,9 +107,10 @@ class SensitivityStudyTest : public ::testing::Test { std::string mps_path, std::map> expec_output_data_map) { std::vector solvers_name = {coin_name}; -#ifdef XPRESS - solvers_name.push_back(xpress_name); -#endif + if (LoadXpress::XpressIsCorrectlyInstalled()) { + solvers_name.push_back(xpress_name); + } + for (auto solver_name : solvers_name) { init_solver(solver_name, mps_path); input_data.last_master = math_problem;