Skip to content

Commit

Permalink
add more function
Browse files Browse the repository at this point in the history
  • Loading branch information
a-zakir committed Oct 19, 2023
1 parent 1cd9fa2 commit d9f7126
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 35 deletions.
3 changes: 3 additions & 0 deletions src/cpp/multisolver_interface/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ list(APPEND Solver_sources
#IF( XPRESS )
list(APPEND Solver_sources
${CMAKE_CURRENT_LIST_DIR}/SolverXpress.cpp
${CMAKE_CURRENT_LIST_DIR}/environment.h
${CMAKE_CURRENT_LIST_DIR}/environment.cc
)
#ENDIF( XPRESS )

Expand Down Expand Up @@ -68,5 +70,6 @@ if(COIN_OR)
Coin::CoinUtils
Coin::Osi
Coin::Cbc
${CMAKE_DL_LIBS}
)
endif()
115 changes: 115 additions & 0 deletions src/cpp/multisolver_interface/dynamic_library.h
Original file line number Diff line number Diff line change
@@ -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 <functional>
#include <stdexcept>
#include <string>
#include <vector>

#if defined(_MSC_VER)
#define WIN32_LEAN_AND_MEAN // disables several conflicting macros
#include <windows.h>
#elif defined(__GNUC__)
#include <dlfcn.h>
#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<HINSTANCE>(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<void*>(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<std::string>& FunctionsNotFound() const {
return functions_not_found_;
}

template <typename T>
std::function<T> GetFunction(const char* function_name) {
const void* function_address =
#if defined(_MSC_VER)
static_cast<void*>(GetProcAddress(
static_cast<HINSTANCE>(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<T>::CreateFunction(function_address);
}

template <typename T>
std::function<T> GetFunction(const std::string& function_name) {
return GetFunction<T>(function_name.c_str());
}

template <typename T>
void GetFunction(std::function<T>* function, const char* function_name) {
*function = GetFunction<T>(function_name);
}

template <typename T>
void GetFunction(std::function<T>* function,
const std::string function_name) {
GetFunction<T>(function, function_name.c_str());
}

private:
void* library_handle_ = nullptr;
std::string library_name_;
std::vector<std::string> functions_not_found_;

template <typename T>
struct TypeParser {};

template <typename Ret, typename... Args>
struct TypeParser<Ret(Args...)> {
static std::function<Ret(Args...)> CreateFunction(
const void* function_address) {
return std::function<Ret(Args...)>(reinterpret_cast<Ret (*)(Args...)>(
const_cast<void*>(function_address)));
}
};
};

#endif // OR_TOOLS_BASE_DYNAMIC_LIBRARY_H_
111 changes: 76 additions & 35 deletions src/cpp/multisolver_interface/environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "environment.h"

#include <filesystem>
#include <iostream>
#include <mutex>
#include <string>

Expand All @@ -25,7 +26,33 @@ namespace operations_research_Xpansion {
// 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<std::string>& vec) {
std::string ret;
for (const auto& str : vec) ret += str + "', '";
return ret;
}
// This is the 'define' section.
std::function<int(XPRSprob dest, XPRSprob src, const char* name)> XPRScopyprob =
nullptr;
std::function<int(XPRSprob prob, const char* filename, const char* flags)>
XPRSwritebasis = nullptr;
std::function<int(XPRSprob prob, const char* filename, const char* flags)>
XPRSreadprob = nullptr;
std::function<int(XPRSprob prob, const char* filename, const char* flags)>
XPRSreadbasis = nullptr;
std::function<int(XPRSprob prob, int start[], int colind[], double colcoef[],
int maxcoefs, int* p_ncoefs, int first, int last)>
XPRSgetrows = nullptr;
std::function<int(XPRSprob prob, int type, const char* name, int* p_index)>
XPRSgetindex = nullptr;
std::function<int(XPRSprob prob, int type, char names[], int first, int last)>
XPRSgetnames = nullptr;
std::function<int(XPRSprob prob, int type, const char names[], int first,
int last)>
XPRSaddnames = nullptr;
std::function<int(XPRSprob prob, const char* flags)> XPRSlpoptimize = nullptr;
std::function<int(XPRSprob prob, const char* flags)> XPRSmipoptimize = nullptr;

std::function<int(XPRSprob* p_prob)> XPRScreateprob = nullptr;
std::function<int(XPRSprob prob)> XPRSdestroyprob = nullptr;
std::function<int(const char* path)> XPRSinit = nullptr;
Expand Down Expand Up @@ -147,6 +174,17 @@ bool LoadXpressFunctions(DynamicLibrary* xpress_dynamic_library) {
// See the comment at the top of the script.

// This is the 'assign' section.
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(&XPRScreateprob, "XPRScreateprob");
xpress_dynamic_library->GetFunction(&XPRSdestroyprob, "XPRSdestroyprob");
xpress_dynamic_library->GetFunction(&XPRSinit, "XPRSinit");
Expand Down Expand Up @@ -218,19 +256,16 @@ bool LoadXpressFunctions(DynamicLibrary* xpress_dynamic_library) {
return true;
}

std::string StringJoin(const std::vector<std::string>& vec) {
std::string ret;
for (const auto& str : vec) ret += str + "', '";
return ret;
}
void printXpressBanner(bool error) {
char banner[XPRS_MAXBANNERLENGTH];
XPRSgetbanner(banner);

if (error) {
LOG(ERROR) << "XpressInterface : Xpress banner :\n" << banner << "\n";
std::cerr << "XpressInterface : Xpress banner :\n" << banner << "\n";
} else {
LOG(WARNING) << "XpressInterface : Xpress banner :\n" << banner << "\n";
std::cout << "Warning: "
<< "XpressInterface : Xpress banner :\n"
<< banner << "\n";
}
}

Expand All @@ -248,11 +283,12 @@ std::vector<std::string> XpressDynamicLibraryPotentialPaths() {
#elif defined(__GNUC__) // Linux
potential_paths.push_back(prefix / "/lib/libxprs.so");
#else
LOG(ERROR) << "OS Not recognized by xpress/environment.cc."
<< " You won't be able to use Xpress.";
std::cerr << "OS Not recognized by xpress/environment.cc."
<< " You won't be able to use Xpress.";
#endif
} else {
LOG(WARNING) << "Environment variable XPRESSDIR undefined.\n";
std::cout << "Warning: "
<< "Environment variable XPRESSDIR undefined.\n";
}

// Search for canonical places.
Expand All @@ -264,8 +300,8 @@ std::vector<std::string> XpressDynamicLibraryPotentialPaths() {
#elif defined(__GNUC__) // Linux
potential_paths.push_back("/opt/xpressmp/lib/libxprs.so");
#else
LOG(ERROR) << "OS Not recognized by xpress/environment.cc."
<< " You won't be able to use Xpress.";
std::cerr << "OS Not recognized by xpress/environment.cc."
<< " You won't be able to use Xpress.";
#endif
return potential_paths;
}
Expand All @@ -275,16 +311,17 @@ bool LoadXpressDynamicLibrary(std::string& xpresspath) {
static std::once_flag xpress_loading_done;
static bool ret;
static DynamicLibrary xpress_library;
static absl::Mutex mutex;
static std::mutex mutex;

absl::MutexLock lock(&mutex);
mutex.lock();

std::call_once(xpress_loading_done, []() {
const std::vector<std::string> canonical_paths =
XpressDynamicLibraryPotentialPaths();
for (const std::string& path : canonical_paths) {
if (xpress_library.TryToLoad(path)) {
LOG(INFO) << "Found the Xpress library in " << path << ".";
std::cout << "Info: "
<< "Found the Xpress library in " << path << ".";
xpress_lib_path.clear();
std::filesystem::path p(path);
p.remove_filename();
Expand Down Expand Up @@ -313,14 +350,15 @@ bool initXpressEnv(bool verbose, int xpress_oem_license_key) {
std::string xpresspath;
bool status = LoadXpressDynamicLibrary(xpresspath);
if (!status) {
LOG(WARNING) << status << "\n";
std::cout << "Warning: " << status << "\n";
return false;
}

const char* xpress_from_env = getenv("XPRESS");
if (xpress_from_env == nullptr) {
if (verbose) {
LOG(WARNING)
std::cout
<< "Warning: "
<< "XpressInterface Error : Environment variable XPRESS undefined.\n";
}
if (xpresspath.empty()) {
Expand All @@ -335,8 +373,9 @@ bool initXpressEnv(bool verbose, int xpress_oem_license_key) {
// if not an OEM key
if (xpress_oem_license_key == 0) {
if (verbose) {
LOG(WARNING) << "XpressInterface : Initialising xpress-MP with parameter "
<< xpresspath << "\n";
std::cout << "Warning: "
<< "XpressInterface : Initialising xpress-MP with parameter "
<< xpresspath << "\n";
}

code = XPRSinit(xpresspath.c_str());
Expand All @@ -347,27 +386,29 @@ bool initXpressEnv(bool verbose, int xpress_oem_license_key) {
printXpressBanner(false);
char version[16];
XPRSgetversion(version);
LOG(WARNING) << "Optimizer version: " << version
<< " (OR-Tools was compiled with version " << XPVERSION
<< ").\n";
std::cout << "Warning: "
<< "Optimizer version: " << version
<< " (OR-Tools was compiled with version " << XPVERSION
<< ").\n";
}
return true;
} else {
LOG(ERROR) << "XpressInterface: Xpress found at " << xpresspath << "\n";
std::cerr << "XpressInterface: Xpress found at " << xpresspath << "\n";
char errmsg[256];
XPRSgetlicerrmsg(errmsg, 256);

LOG(ERROR) << "XpressInterface : License error : " << errmsg
<< " (XPRSinit returned code " << code << "). Please check"
<< " environment variable XPRESS.\n";
std::cerr << "XpressInterface : License error : " << errmsg
<< " (XPRSinit returned code " << code << "). Please check"
<< " environment variable XPRESS.\n";

return false;
}
} else {
// if OEM key
if (verbose) {
LOG(WARNING) << "XpressInterface : Initialising xpress-MP with OEM key "
<< xpress_oem_license_key << "\n";
std::cout << "Warning: "
<< "XpressInterface : Initialising xpress-MP with OEM key "
<< xpress_oem_license_key << "\n";
}

int nvalue = 0;
Expand All @@ -377,27 +418,27 @@ bool initXpressEnv(bool verbose, int xpress_oem_license_key) {

XPRSlicense(&nvalue, slicmsg);
if (verbose) {
VLOG(0) << "XpressInterface : First message from XPRSLicense : "
<< slicmsg << "\n";
std::cout << "XpressInterface : First message from XPRSLicense : "
<< slicmsg << "\n";
}

nvalue = xpress_oem_license_key - ((nvalue * nvalue) / 19);
ierr = XPRSlicense(&nvalue, slicmsg);

if (verbose) {
VLOG(0) << "XpressInterface : Second message from XPRSLicense : "
<< slicmsg << "\n";
std::cout << "XpressInterface : Second message from XPRSLicense : "
<< slicmsg << "\n";
}
if (ierr == 16) {
if (verbose) {
VLOG(0)
std::cout
<< "XpressInterface : Optimizer development software detected\n";
}
} else if (ierr != 0) {
// get the license error message
XPRSgetlicerrmsg(errmsg, 256);

LOG(ERROR) << "XpressInterface : " << errmsg << "\n";
std::cerr << "XpressInterface : " << errmsg << "\n";
return false;
}

Expand All @@ -406,7 +447,7 @@ bool initXpressEnv(bool verbose, int xpress_oem_license_key) {
if (!code) {
return true;
} else {
LOG(ERROR) << "XPRSinit returned code : " << code << "\n";
std::cerr << "XPRSinit returned code : " << code << "\n";
return false;
}
}
Expand Down
Loading

0 comments on commit d9f7126

Please sign in to comment.