2025-03-26 10:54:54 +01:00
|
|
|
// Copyright 2010-2025 Google LLC
|
2023-10-17 10:09:20 +02:00
|
|
|
// 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.
|
|
|
|
|
|
2023-10-26 10:04:42 +02:00
|
|
|
// Initial version of this code was provided by RTE
|
|
|
|
|
|
2025-07-23 15:07:49 +02:00
|
|
|
#include "ortools/third_party_solvers/xpress_environment.h"
|
2023-10-17 10:09:20 +02:00
|
|
|
|
2023-12-28 21:41:55 +01:00
|
|
|
#include <cstdlib>
|
2025-03-26 10:54:54 +01:00
|
|
|
// NOLINTNEXTLINE(build/c++17)
|
2023-10-17 10:09:20 +02:00
|
|
|
#include <filesystem>
|
2023-12-28 21:41:55 +01:00
|
|
|
#include <functional>
|
2023-10-17 10:09:20 +02:00
|
|
|
#include <string>
|
2023-12-28 21:41:55 +01:00
|
|
|
#include <vector>
|
2023-10-17 10:09:20 +02:00
|
|
|
|
2025-03-26 10:54:54 +01:00
|
|
|
#include "absl/base/call_once.h"
|
|
|
|
|
#include "absl/base/const_init.h"
|
2023-10-17 10:09:20 +02:00
|
|
|
#include "absl/status/status.h"
|
|
|
|
|
#include "absl/strings/str_cat.h"
|
|
|
|
|
#include "absl/strings/str_join.h"
|
|
|
|
|
#include "absl/synchronization/mutex.h"
|
|
|
|
|
#include "ortools/base/logging.h"
|
2025-12-09 22:50:01 +01:00
|
|
|
#include "ortools/base/status_builder.h"
|
2025-07-23 15:07:49 +02:00
|
|
|
#include "ortools/third_party_solvers/dynamic_library.h"
|
2023-10-17 10:09:20 +02:00
|
|
|
|
|
|
|
|
namespace operations_research {
|
|
|
|
|
|
|
|
|
|
#define STRINGIFY2(X) #X
|
|
|
|
|
#define STRINGIFY(X) STRINGIFY2(X)
|
|
|
|
|
|
2023-12-28 21:41:55 +01:00
|
|
|
// Let's not reformat for rest of the file.
|
2023-10-17 10:09:20 +02:00
|
|
|
// This was generated with the parse_header_xpress.py script.
|
|
|
|
|
// See the comment at the top of the script.
|
|
|
|
|
|
|
|
|
|
// This is the 'define' section.
|
2025-03-26 10:54:54 +01:00
|
|
|
// NOLINTBEGIN(whitespace/line_length)
|
|
|
|
|
// NOLINTBEGIN(google3-runtime-global-variables)
|
|
|
|
|
// clang-format off
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob* p_prob)> XPRScreateprob = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob)> XPRSdestroyprob = nullptr;
|
|
|
|
|
std::function<int(const char* path)> XPRSinit = nullptr;
|
|
|
|
|
std::function<int(void)> XPRSfree = nullptr;
|
|
|
|
|
std::function<int(char* buffer, int maxbytes)> XPRSgetlicerrmsg = nullptr;
|
|
|
|
|
std::function<int(int* p_i, char* p_c)> XPRSlicense = nullptr;
|
|
|
|
|
std::function<int(char* banner)> XPRSgetbanner = nullptr;
|
|
|
|
|
std::function<int(char* version)> XPRSgetversion = nullptr;
|
2025-12-09 22:50:01 +01:00
|
|
|
std::function<int(int *p_major, int *p_minor, int *p_build)> XPRSgetversionnumbers = nullptr;
|
2025-01-29 13:24:15 +01:00
|
|
|
std::function<int(XPRSprob prob, const char* probname)> XPRSsetprobname = nullptr;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, int control)> XPRSsetdefaultcontrol = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int reason)> XPRSinterrupt = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int control, int value)> XPRSsetintcontrol = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int control, XPRSint64 value)> XPRSsetintcontrol64 = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int control, double value)> XPRSsetdblcontrol = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int control, const char* value)> XPRSsetstrcontrol = nullptr;
|
2025-12-09 22:50:01 +01:00
|
|
|
std::function<int(XPRSprob prob, int objidx, int control, int value)> XPRSsetobjintcontrol = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int objidx, int control, double value)> XPRSsetobjdblcontrol = nullptr;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, int control, int* p_value)> XPRSgetintcontrol = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int control, XPRSint64* p_value)> XPRSgetintcontrol64 = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int control, double* p_value)> XPRSgetdblcontrol = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int control, char* value, int maxbytes, int* p_nbytes)> XPRSgetstringcontrol = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int attrib, int* p_value)> XPRSgetintattrib = nullptr;
|
2025-06-02 13:44:31 +02:00
|
|
|
std::function<int(XPRSprob prob, int attrib, char* value, int maxbytes, int* p_nbytes)> XPRSgetstringattrib = nullptr;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, int attrib, double* p_value)> XPRSgetdblattrib = nullptr;
|
2025-12-09 22:50:01 +01:00
|
|
|
std::function<int(XPRSprob prob, int objidx, int attrib, double* p_value)> XPRSgetobjdblattrib = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int objidx, const double solution[], double* p_objval)> XPRScalcobjn = nullptr;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, const char* name, int* p_id, int* p_type)> XPRSgetcontrolinfo = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, double objcoef[], int first, int last)> XPRSgetobj = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, double rhs[], int first, int last)> XPRSgetrhs = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, double rng[], int first, int last)> XPRSgetrhsrange = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, double lb[], int first, int last)> XPRSgetlb = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, double ub[], int first, int last)> XPRSgetub = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int row, int col, double* p_coef)> XPRSgetcoef = nullptr;
|
2025-12-09 22:50:01 +01:00
|
|
|
std::function<int(XPRSprob prob, int* status, double x[], int first, int last)> XPRSgetsolution = nullptr;
|
2025-01-29 13:24:15 +01:00
|
|
|
std::function<int(XPRSprob prob, int* status, double duals[], int first, int last)> XPRSgetduals = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int* status, double djs[], int first, int last)> XPRSgetredcosts = nullptr;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, int nrows, int ncoefs, const char rowtype[], const double rhs[], const double rng[], const int start[], const int colind[], const double rowcoef[])> XPRSaddrows = nullptr;
|
2025-12-09 22:50:01 +01:00
|
|
|
std::function<int(XPRSprob prob, int nrows, int ncoefs, const char rowtype[], const double rhs[], const double rng[], const XPRSint64 start[], const int colind[], const double rowcoef[])> XPRSaddrows64 = nullptr;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, int nrows, const int rowind[])> XPRSdelrows = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int ncols, int ncoefs, const double objcoef[], const int start[], const int rowind[], const double rowcoef[], const double lb[], const double ub[])> XPRSaddcols = nullptr;
|
2025-12-09 22:50:01 +01:00
|
|
|
std::function<int(XPRSprob prob, int ncols, const int colind[], const double objcoef[], int priority, double weight)> XPRSaddobj = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int row, int ncoefs, const int rowqcol1[], int const rowqcol2[], const double rowqcoef[])> XPRSaddqmatrix64 = nullptr;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, int type, const char names[], int first, int last)> XPRSaddnames = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int type, char names[], int first, int last)> XPRSgetnames = nullptr;
|
2025-12-09 22:50:01 +01:00
|
|
|
std::function<int(XPRSprob prob, int nsets, XPRSint64 nelems, const char settype[], const XPRSint64 start[], const int colind[], const double refval[])> XPRSaddsets64 = nullptr;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, int ncols, const int colind[])> XPRSdelcols = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int ncols, const int colind[], const char coltype[])> XPRSchgcoltype = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, const int rowstat[], const int colstat[])> XPRSloadbasis = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob)> XPRSpostsolve = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int objsense)> XPRSchgobjsense = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, char* errmsg)> XPRSgetlasterror = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int rowstat[], int colstat[])> XPRSgetbasis = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, const char* filename, const char* flags)> XPRSwriteprob = nullptr;
|
2025-12-09 22:50:01 +01:00
|
|
|
std::function<int(XPRSprob prob, const char* filename)> XPRSsaveas = nullptr;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, char rowtype[], int first, int last)> XPRSgetrowtype = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, char coltype[], int first, int last)> XPRSgetcoltype = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int nbounds, const int colind[], const char bndtype[], const double bndval[])> XPRSchgbounds = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int length, const double solval[], const int colind[], const char* name)> XPRSaddmipsol = nullptr;
|
2025-11-06 09:46:41 +01:00
|
|
|
std::function<int(XPRSprob prob, int nrows, const int rowind[])> XPRSloaddelayedrows = nullptr;
|
2025-12-09 22:50:01 +01:00
|
|
|
std::function<int(XPRSprob prob, int nrows, const int rowind[], const int colind[], const int complement[])> XPRSsetindicators = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int ndirs, const int colind[], const int priority[], const char dir[], const double uppseudo[], const double downpseudo[])> XPRSloaddirs;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, double x[], double slack[], double duals[], double djs[])> XPRSgetlpsol = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, double x[], double slack[])> XPRSgetmipsol = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int ncols, const int colind[], const double objcoef[])> XPRSchgobj = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int row, int col, double coef)> XPRSchgcoef = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int ncoefs, const int rowind[], const int colind[], const double rowcoef[])> XPRSchgmcoef = nullptr;
|
2025-01-29 13:24:15 +01:00
|
|
|
std::function<int(XPRSprob prob, XPRSint64 ncoefs, const int rowind[], const int colind[], const double rowcoef[])> XPRSchgmcoef64 = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int ncoefs, const int objqcol1[], const int objqcol2[], const double objqcoef[])> XPRSchgmqobj = nullptr;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, int nrows, const int rowind[], const double rhs[])> XPRSchgrhs = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int nrows, const int rowind[], const double rng[])> XPRSchgrhsrange = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int nrows, const int rowind[], const char rowtype[])> XPRSchgrowtype = nullptr;
|
2025-06-02 13:44:31 +02:00
|
|
|
std::function<int(XPRSprob prob, int objidx)> XPRSdelobj = nullptr;
|
2023-10-17 10:09:20 +02:00
|
|
|
std::function<int(XPRSprob prob, void (XPRS_CC *f_intsol)(XPRSprob cbprob, void* cbdata), void* p, int priority)> XPRSaddcbintsol = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, void (XPRS_CC *f_intsol)(XPRSprob cbprob, void* cbdata), void* p)> XPRSremovecbintsol = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, void (XPRS_CC *f_message)(XPRSprob cbprob, void* cbdata, const char* msg, int msglen, int msgtype), void* p, int priority)> XPRSaddcbmessage = nullptr;
|
2025-12-09 22:50:01 +01:00
|
|
|
std::function<int(XPRSprob prob, void (XPRS_CC *f_message)(XPRSprob cbprob, void* cbdata, const char* msg, int msglen, int msgtype), void* p)> XPRSremovecbmessage = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int (XPRS_CC *f_checktime)(XPRSprob cbprob, void* cbdata), void* p, int priority)> XPRSaddcbchecktime = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, int (XPRS_CC *f_checktime)(XPRSprob cbprob, void* cbdata), void* p)> XPRSremovecbchecktime = nullptr;
|
2023-11-16 14:51:32 +01:00
|
|
|
std::function<int(XPRSprob prob, const char* flags)> XPRSlpoptimize = nullptr;
|
|
|
|
|
std::function<int(XPRSprob prob, const char* flags)> XPRSmipoptimize = nullptr;
|
2025-01-29 13:24:15 +01:00
|
|
|
std::function<int(XPRSprob prob, const char* flags, int* solvestatus, int* solstatus)> XPRSoptimize = nullptr;
|
2025-03-26 10:54:54 +01:00
|
|
|
// clang-format on
|
|
|
|
|
// NOLINTEND(google3-runtime-global-variables)
|
|
|
|
|
// NOLINTEND(whitespace/line_length)
|
2023-10-17 10:09:20 +02:00
|
|
|
|
2023-11-21 17:15:33 +01:00
|
|
|
void LoadXpressFunctions(DynamicLibrary* xpress_dynamic_library) {
|
2023-10-17 10:09:20 +02:00
|
|
|
// This was generated with the parse_header_xpress.py script.
|
|
|
|
|
// See the comment at the top of the script.
|
|
|
|
|
|
|
|
|
|
// This is the 'assign' section.
|
2025-03-26 10:54:54 +01:00
|
|
|
// NOLINTBEGIN(whitespace/line_length)
|
|
|
|
|
// clang-format off
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRScreateprob, "XPRScreateprob");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSdestroyprob, "XPRSdestroyprob");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSinit, "XPRSinit");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSfree, "XPRSfree");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetlicerrmsg, "XPRSgetlicerrmsg");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSlicense, "XPRSlicense");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetbanner, "XPRSgetbanner");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetversion, "XPRSgetversion");
|
2025-12-09 22:50:01 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetversionnumbers, "XPRSgetversionnumbers");
|
2025-01-29 13:24:15 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSsetprobname, "XPRSsetprobname");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSsetdefaultcontrol, "XPRSsetdefaultcontrol");
|
2023-10-20 09:41:16 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSinterrupt, "XPRSinterrupt");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSsetintcontrol, "XPRSsetintcontrol");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSsetintcontrol64, "XPRSsetintcontrol64");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSsetdblcontrol, "XPRSsetdblcontrol");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSsetstrcontrol, "XPRSsetstrcontrol");
|
2025-12-09 22:50:01 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSsetobjintcontrol, "XPRSsetobjintcontrol");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSsetobjdblcontrol, "XPRSsetobjdblcontrol");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetintcontrol, "XPRSgetintcontrol");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetintcontrol64, "XPRSgetintcontrol64");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetdblcontrol, "XPRSgetdblcontrol");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetstringcontrol, "XPRSgetstringcontrol");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetintattrib, "XPRSgetintattrib");
|
2025-06-02 13:44:31 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetstringattrib, "XPRSgetstringattrib");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetdblattrib, "XPRSgetdblattrib");
|
2025-12-09 22:50:01 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetobjdblattrib, "XPRSgetobjdblattrib");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRScalcobjn, "XPRScalcobjn");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetcontrolinfo, "XPRSgetcontrolinfo");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetobj, "XPRSgetobj");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetrhs, "XPRSgetrhs");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetrhsrange, "XPRSgetrhsrange");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetlb, "XPRSgetlb");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetub, "XPRSgetub");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetcoef, "XPRSgetcoef");
|
2025-12-09 22:50:01 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetsolution, "XPRSgetsolution");
|
2025-01-29 13:24:15 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetduals, "XPRSgetduals");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetredcosts, "XPRSgetredcosts");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSaddrows, "XPRSaddrows");
|
2025-12-09 22:50:01 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSaddrows64, "XPRSaddrows64");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSdelrows, "XPRSdelrows");
|
2025-12-09 22:50:01 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSdelobj, "XPRSdelobj");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSaddcols, "XPRSaddcols");
|
2025-12-09 22:50:01 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSaddobj, "XPRSaddobj");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSaddqmatrix64, "XPRSaddqmatrix64");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSaddnames, "XPRSaddnames");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetnames, "XPRSgetnames");
|
2025-12-09 22:50:01 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSaddsets64, "XPRSaddsets64");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSdelcols, "XPRSdelcols");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSchgcoltype, "XPRSchgcoltype");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSloadbasis, "XPRSloadbasis");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSpostsolve, "XPRSpostsolve");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSchgobjsense, "XPRSchgobjsense");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetlasterror, "XPRSgetlasterror");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetbasis, "XPRSgetbasis");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSwriteprob, "XPRSwriteprob");
|
2025-12-09 22:50:01 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSsaveas, "XPRSsaveas");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetrowtype, "XPRSgetrowtype");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetcoltype, "XPRSgetcoltype");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSchgbounds, "XPRSchgbounds");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSaddmipsol, "XPRSaddmipsol");
|
2025-11-06 09:46:41 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSloaddelayedrows, "XPRSloaddelayedrows");
|
2025-12-09 22:50:01 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSsetindicators, "XPRSsetindicators");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSloaddirs, "XPRSloaddirs");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetlpsol, "XPRSgetlpsol");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSgetmipsol, "XPRSgetmipsol");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSchgobj, "XPRSchgobj");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSchgcoef, "XPRSchgcoef");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSchgmcoef, "XPRSchgmcoef");
|
2025-01-29 13:24:15 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSchgmcoef64, "XPRSchgmcoef64");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSchgmqobj, "XPRSchgmqobj");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSchgrhs, "XPRSchgrhs");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSchgrhsrange, "XPRSchgrhsrange");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSchgrowtype, "XPRSchgrowtype");
|
2025-06-02 13:44:31 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSdelobj, "XPRSdelobj");
|
2023-10-17 10:09:20 +02:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSaddcbintsol, "XPRSaddcbintsol");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSremovecbintsol, "XPRSremovecbintsol");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSaddcbmessage, "XPRSaddcbmessage");
|
2025-12-09 22:50:01 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSremovecbmessage, "XPRSremovecbmessage");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSaddcbchecktime, "XPRSaddcbchecktime");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSremovecbchecktime, "XPRSremovecbchecktime");
|
2023-11-16 14:51:32 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSlpoptimize, "XPRSlpoptimize");
|
|
|
|
|
xpress_dynamic_library->GetFunction(&XPRSmipoptimize, "XPRSmipoptimize");
|
2025-01-29 13:24:15 +01:00
|
|
|
xpress_dynamic_library->GetFunction(&XPRSoptimize, "XPRSoptimize");
|
2025-03-26 10:54:54 +01:00
|
|
|
// clang-format on
|
|
|
|
|
// NOLINTEND(whitespace/line_length)
|
2023-10-17 10:09:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void printXpressBanner(bool error) {
|
|
|
|
|
char banner[XPRS_MAXBANNERLENGTH];
|
|
|
|
|
XPRSgetbanner(banner);
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
LOG(ERROR) << "XpressInterface : Xpress banner :\n" << banner << "\n";
|
|
|
|
|
} else {
|
|
|
|
|
LOG(WARNING) << "XpressInterface : Xpress banner :\n" << banner << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> XpressDynamicLibraryPotentialPaths() {
|
|
|
|
|
std::vector<std::string> potential_paths;
|
|
|
|
|
|
|
|
|
|
// Look for libraries pointed by XPRESSDIR first.
|
2023-11-21 17:15:33 +01:00
|
|
|
const char* xpressdir_from_env = getenv("XPRESSDIR");
|
|
|
|
|
if (xpressdir_from_env != nullptr) {
|
|
|
|
|
LOG(INFO) << "Environment variable XPRESSDIR = " << xpressdir_from_env;
|
2023-10-17 10:09:20 +02:00
|
|
|
#if defined(_MSC_VER) // Windows
|
|
|
|
|
potential_paths.push_back(
|
2023-11-21 17:15:33 +01:00
|
|
|
absl::StrCat(xpressdir_from_env, "\\bin\\xprs.dll"));
|
2025-03-26 10:54:54 +01:00
|
|
|
#elif defined(__APPLE__) // macOS
|
2023-10-17 10:09:20 +02:00
|
|
|
potential_paths.push_back(
|
2023-11-21 17:15:33 +01:00
|
|
|
absl::StrCat(xpressdir_from_env, "/lib/libxprs.dylib"));
|
2023-10-17 10:09:20 +02:00
|
|
|
#elif defined(__GNUC__) // Linux
|
|
|
|
|
potential_paths.push_back(
|
2023-11-21 17:15:33 +01:00
|
|
|
absl::StrCat(xpressdir_from_env, "/lib/libxprs.so"));
|
2023-10-17 10:09:20 +02:00
|
|
|
#else
|
2025-07-23 15:07:49 +02:00
|
|
|
LOG(ERROR) << "OS Not recognized by xpress_environment.cc."
|
2023-10-17 10:09:20 +02:00
|
|
|
<< " You won't be able to use Xpress.";
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
2023-10-18 11:22:46 +02:00
|
|
|
LOG(WARNING) << "Environment variable XPRESSDIR undefined.";
|
2023-10-17 10:09:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Search for canonical places.
|
|
|
|
|
#if defined(_MSC_VER) // Windows
|
|
|
|
|
potential_paths.push_back(absl::StrCat("C:\\xpressmp\\bin\\xprs.dll"));
|
|
|
|
|
potential_paths.push_back(
|
|
|
|
|
absl::StrCat("C:\\Program Files\\xpressmp\\bin\\xprs.dll"));
|
2025-03-26 10:54:54 +01:00
|
|
|
#elif defined(__APPLE__) // macOS
|
2023-10-17 10:09:20 +02:00
|
|
|
potential_paths.push_back(
|
|
|
|
|
absl::StrCat("/Library/xpressmp/lib/libxprs.dylib"));
|
|
|
|
|
#elif defined(__GNUC__) // Linux
|
|
|
|
|
potential_paths.push_back(absl::StrCat("/opt/xpressmp/lib/libxprs.so"));
|
|
|
|
|
#else
|
2025-07-23 15:07:49 +02:00
|
|
|
LOG(ERROR) << "OS Not recognized by xpress_environment.cc."
|
2023-10-17 10:09:20 +02:00
|
|
|
<< " You won't be able to use Xpress.";
|
|
|
|
|
#endif
|
|
|
|
|
return potential_paths;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
absl::Status LoadXpressDynamicLibrary(std::string& xpresspath) {
|
2025-03-26 10:54:54 +01:00
|
|
|
static std::string* xpress_lib_path = new std::string;
|
|
|
|
|
static absl::once_flag xpress_loading_done;
|
|
|
|
|
static absl::Status* xpress_load_status = new absl::Status;
|
|
|
|
|
static DynamicLibrary* xpress_library = new DynamicLibrary;
|
2023-12-28 21:41:55 +01:00
|
|
|
static absl::Mutex mutex(absl::kConstInit);
|
2023-10-17 10:09:20 +02:00
|
|
|
|
2025-09-16 16:25:04 +02:00
|
|
|
absl::MutexLock lock(mutex);
|
2023-10-17 10:09:20 +02:00
|
|
|
|
2025-03-26 10:54:54 +01:00
|
|
|
absl::call_once(xpress_loading_done, []() {
|
2023-10-17 10:09:20 +02:00
|
|
|
const std::vector<std::string> canonical_paths =
|
|
|
|
|
XpressDynamicLibraryPotentialPaths();
|
|
|
|
|
for (const std::string& path : canonical_paths) {
|
2025-03-26 10:54:54 +01:00
|
|
|
if (xpress_library->TryToLoad(path)) {
|
2023-10-17 10:09:20 +02:00
|
|
|
LOG(INFO) << "Found the Xpress library in " << path << ".";
|
2025-03-26 10:54:54 +01:00
|
|
|
xpress_lib_path->clear();
|
2023-10-17 10:09:20 +02:00
|
|
|
std::filesystem::path p(path);
|
|
|
|
|
p.remove_filename();
|
2025-03-26 10:54:54 +01:00
|
|
|
xpress_lib_path->append(p.string());
|
2023-10-17 10:09:20 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-26 10:54:54 +01:00
|
|
|
if (xpress_library->LibraryIsLoaded()) {
|
2023-11-21 17:15:33 +01:00
|
|
|
LOG(INFO) << "Loading all Xpress functions";
|
2025-03-26 10:54:54 +01:00
|
|
|
LoadXpressFunctions(xpress_library);
|
2025-12-09 22:50:01 +01:00
|
|
|
// Make sure the library we just loaded is recent enough.
|
|
|
|
|
int major = -1, minor = -1, build = -1;
|
|
|
|
|
if (!XPRSgetversionnumbers ||
|
|
|
|
|
XPRSgetversionnumbers(&major, &minor, &build) != 0)
|
|
|
|
|
*xpress_load_status =
|
|
|
|
|
util::StatusBuilder(absl::StatusCode::kNotFound)
|
|
|
|
|
<< "Xpress optimizer library too old, need at least version "
|
|
|
|
|
<< XPVERSION;
|
|
|
|
|
else if (major < XPVERSION)
|
|
|
|
|
*xpress_load_status = util::StatusBuilder(absl::StatusCode::kNotFound)
|
|
|
|
|
<< "Xpress optimizer library version " << major
|
|
|
|
|
<< " too old, need at least version "
|
|
|
|
|
<< XPVERSION;
|
|
|
|
|
else
|
|
|
|
|
*xpress_load_status = absl::OkStatus();
|
2023-10-17 10:09:20 +02:00
|
|
|
} else {
|
2025-03-26 10:54:54 +01:00
|
|
|
*xpress_load_status = absl::NotFoundError(
|
2023-10-31 14:47:14 +01:00
|
|
|
absl::StrCat("Could not find the Xpress shared library. Looked in: [",
|
|
|
|
|
absl::StrJoin(canonical_paths, "', '"),
|
|
|
|
|
"]. Please check environment variable XPRESSDIR"));
|
2023-10-17 10:09:20 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
xpresspath.clear();
|
2025-03-26 10:54:54 +01:00
|
|
|
xpresspath.append(*xpress_lib_path);
|
|
|
|
|
return *xpress_load_status;
|
2023-10-17 10:09:20 +02:00
|
|
|
}
|
|
|
|
|
|
2023-11-07 18:36:23 +01:00
|
|
|
void log_message_about_XPRSinit_argument();
|
|
|
|
|
void log_full_license_error(int code, const std::string& xpress_lib_dir);
|
2023-12-28 21:41:55 +01:00
|
|
|
//! init XPRESS environment.
|
2023-10-17 10:09:20 +02:00
|
|
|
bool initXpressEnv(bool verbose, int xpress_oem_license_key) {
|
2023-11-07 18:36:23 +01:00
|
|
|
std::string xpress_lib_dir;
|
|
|
|
|
absl::Status status = LoadXpressDynamicLibrary(xpress_lib_dir);
|
2023-10-17 10:09:20 +02:00
|
|
|
if (!status.ok()) {
|
|
|
|
|
LOG(WARNING) << status << "\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int code;
|
|
|
|
|
// if not an OEM key
|
|
|
|
|
if (xpress_oem_license_key == 0) {
|
|
|
|
|
if (verbose) {
|
2023-11-07 18:36:23 +01:00
|
|
|
log_message_about_XPRSinit_argument();
|
2023-10-17 10:09:20 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-31 14:47:14 +01:00
|
|
|
code = XPRSinit(nullptr);
|
2023-10-17 10:09:20 +02:00
|
|
|
|
|
|
|
|
if (!code) {
|
|
|
|
|
// XPRSbanner informs about Xpress version, options and error messages
|
|
|
|
|
if (verbose) {
|
|
|
|
|
printXpressBanner(false);
|
|
|
|
|
char version[16];
|
|
|
|
|
XPRSgetversion(version);
|
|
|
|
|
LOG(WARNING) << "Optimizer version: " << version
|
|
|
|
|
<< " (OR-Tools was compiled with version " << XPVERSION
|
2025-03-26 10:54:54 +01:00
|
|
|
<< ").";
|
2023-10-17 10:09:20 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
2023-11-07 18:36:23 +01:00
|
|
|
log_full_license_error(code, xpress_lib_dir);
|
2023-10-17 10:09:20 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// if OEM key
|
|
|
|
|
if (verbose) {
|
|
|
|
|
LOG(WARNING) << "XpressInterface : Initialising xpress-MP with OEM key "
|
2025-03-26 10:54:54 +01:00
|
|
|
<< xpress_oem_license_key;
|
2023-10-17 10:09:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nvalue = 0;
|
|
|
|
|
int ierr;
|
|
|
|
|
char slicmsg[256] = "";
|
|
|
|
|
char errmsg[256];
|
|
|
|
|
|
|
|
|
|
XPRSlicense(&nvalue, slicmsg);
|
|
|
|
|
if (verbose) {
|
2025-03-26 10:54:54 +01:00
|
|
|
DLOG(INFO) << "XpressInterface : First message from XPRSLicense : "
|
|
|
|
|
<< slicmsg;
|
2023-10-17 10:09:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nvalue = xpress_oem_license_key - ((nvalue * nvalue) / 19);
|
|
|
|
|
ierr = XPRSlicense(&nvalue, slicmsg);
|
|
|
|
|
|
|
|
|
|
if (verbose) {
|
2025-03-26 10:54:54 +01:00
|
|
|
DLOG(INFO) << "XpressInterface : Second message from XPRSLicense : "
|
|
|
|
|
<< slicmsg;
|
2023-10-17 10:09:20 +02:00
|
|
|
}
|
|
|
|
|
if (ierr == 16) {
|
|
|
|
|
if (verbose) {
|
2025-03-26 10:54:54 +01:00
|
|
|
DLOG(INFO)
|
|
|
|
|
<< "XpressInterface : Optimizer development software detected";
|
2023-10-17 10:09:20 +02:00
|
|
|
}
|
|
|
|
|
} else if (ierr != 0) {
|
|
|
|
|
// get the license error message
|
|
|
|
|
XPRSgetlicerrmsg(errmsg, 256);
|
|
|
|
|
|
2025-03-26 10:54:54 +01:00
|
|
|
LOG(ERROR) << "XpressInterface : " << errmsg;
|
2023-10-17 10:09:20 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-26 10:54:54 +01:00
|
|
|
code = XPRSinit(nullptr);
|
2023-10-17 10:09:20 +02:00
|
|
|
|
|
|
|
|
if (!code) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
LOG(ERROR) << "XPRSinit returned code : " << code << "\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-07 18:36:23 +01:00
|
|
|
void log_full_license_error(int code, const std::string& xpress_lib_dir) {
|
2023-12-28 21:41:55 +01:00
|
|
|
LOG(WARNING) << "XpressInterface: Xpress found at " << xpress_lib_dir << "\n";
|
2023-11-07 18:36:23 +01:00
|
|
|
char errmsg[256];
|
|
|
|
|
XPRSgetlicerrmsg(errmsg, 256);
|
|
|
|
|
|
|
|
|
|
LOG(ERROR) << "XpressInterface : License error : " << errmsg
|
2023-12-28 21:41:55 +01:00
|
|
|
<< " (XPRSinit returned code " << code << "). \n";
|
2023-11-07 18:36:23 +01:00
|
|
|
LOG(ERROR)
|
|
|
|
|
<< "|_Your Xpress installation should have set the env var XPAUTH_PATH"
|
|
|
|
|
" to the full path of your licence file\n";
|
|
|
|
|
}
|
|
|
|
|
void log_message_about_XPRSinit_argument() {
|
|
|
|
|
LOG(WARNING)
|
|
|
|
|
<< "XpressInterface : Initialising xpress-MP with default parameters";
|
|
|
|
|
}
|
2023-10-17 10:09:20 +02:00
|
|
|
|
|
|
|
|
bool XpressIsCorrectlyInstalled() {
|
|
|
|
|
bool correctlyInstalled = initXpressEnv(false);
|
|
|
|
|
if (correctlyInstalled) {
|
|
|
|
|
XPRSfree();
|
|
|
|
|
}
|
|
|
|
|
return correctlyInstalled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace operations_research
|