22#include "absl/log/check.h"
23#include "absl/log/die_if_null.h"
24#include "absl/memory/memory.h"
25#include "absl/status/status.h"
26#include "absl/status/statusor.h"
27#include "absl/strings/str_format.h"
28#include "absl/types/span.h"
38bool checkInt32Overflow(
const unsigned int value) {
return value >
INT32_MAX; }
43absl::Status Xpress::ToStatus(
const int xprs_err,
44 const absl::StatusCode code)
const {
46 return absl::OkStatus();
52 <<
"Xpress error code: " << xprs_err <<
", message: " << errmsg;
55 <<
" (message could not be fetched)";
59 initIntControlDefaults();
63 const std::string& model_name) {
65 CHECK(correctlyLoaded);
69 return absl::WrapUnique(
new Xpress(model));
73 std::string truncated = name;
75 if (truncated.length() > maxLength.value_or(INT_MAX)) {
76 truncated = truncated.substr(0, maxLength.value_or(INT_MAX));
82 const char* sMsg,
int nLen,
85 std::cout << sMsg << std::endl;
94void Xpress::initIntControlDefaults() {
96 for (
auto control : controls) {
97 int_control_defaults_[control] = GetIntControl(control).value();
102 const absl::Span<const double> lb,
103 const absl::Span<const double> ub,
104 const absl::Span<const char> vtype) {
105 return AddVars({}, {}, {}, obj, lb, ub, vtype);
109 const absl::Span<const int> vind,
110 const absl::Span<const double> vval,
111 const absl::Span<const double> obj,
112 const absl::Span<const double> lb,
113 const absl::Span<const double> ub,
114 const absl::Span<const char> vtype) {
115 if (checkInt32Overflow(lb.size())) {
116 return absl::InvalidArgumentError(
117 "XPRESS cannot handle more than 2^31 variables");
119 const int num_vars =
static_cast<int>(lb.size());
120 if (vind.size() != vval.size() || ub.size() != num_vars ||
121 vtype.size() != num_vars || (!obj.empty() && obj.size() != num_vars) ||
122 (!vbegin.empty() && vbegin.size() != num_vars)) {
123 return absl::InvalidArgumentError(
124 "Xpress::AddVars arguments are of inconsistent sizes");
126 double* c_obj =
nullptr;
128 c_obj =
const_cast<double*
>(obj.data());
131 return ToStatus(
XPRSaddcols(xpress_model_, num_vars, 0, c_obj,
nullptr,
132 nullptr,
nullptr, lb.data(), ub.data()));
136 const absl::Span<const double> rhs,
137 const absl::Span<const double> rng) {
138 const int num_cons =
static_cast<int>(sense.size());
139 if (rhs.size() != num_cons) {
140 return absl::InvalidArgumentError(
141 "RHS must have one element per constraint.");
143 return ToStatus(
XPRSaddrows(xpress_model_, num_cons, 0, sense.data(),
144 rhs.data(), rng.data(), NULL, NULL, NULL));
148 const absl::Span<const double> rhs,
149 const absl::Span<const double> rng,
150 const absl::Span<const int> start,
151 const absl::Span<const int> colind,
152 const absl::Span<const double> rowcoef) {
153 const int num_cons =
static_cast<int>(rowtype.size());
154 if (rhs.size() != num_cons) {
155 return absl::InvalidArgumentError(
156 "RHS must have one element per constraint.");
158 if (start.size() != num_cons) {
159 return absl::InvalidArgumentError(
160 "START must have one element per constraint.");
162 if (colind.size() != rowcoef.size()) {
163 return absl::InvalidArgumentError(
164 "COLIND and ROWCOEF must be of the same size.");
166 return ToStatus(
XPRSaddrows(xpress_model_, num_cons, 0, rowtype.data(),
167 rhs.data(), rng.data(), start.data(),
168 colind.data(), rowcoef.data()));
177 double offset,
const absl::Span<const int> colind,
178 const absl::Span<const double> coefficients) {
179 static int indexes[1] = {-1};
180 double xprs_values[1] = {-offset};
182 <<
"Failed to set objective offset in XPRESS";
184 const int n_cols =
static_cast<int>(colind.size());
186 XPRSchgobj(xpress_model_, n_cols, colind.data(), coefficients.data()));
190 const absl::Span<const int> colind1,
const absl::Span<const int> colind2,
191 const absl::Span<const double> coefficients) {
192 const int ncoefs =
static_cast<int>(coefficients.size());
193 return ToStatus(
XPRSchgmqobj(xpress_model_, ncoefs, colind1.data(),
194 colind2.data(), coefficients.data()));
198 absl::Span<const int> colind,
199 absl::Span<const double> values) {
200 const long n_coefs =
static_cast<long>(rowind.size());
201 return ToStatus(
XPRSchgmcoef64(xpress_model_, n_coefs, rowind.data(),
202 colind.data(), values.data()));
210 absl::Span<double> duals,
211 absl::Span<double> reducedCosts) {
212 return ToStatus(
XPRSgetlpsol(xpress_model_, primals.data(),
nullptr,
213 duals.data(), reducedCosts.data()));
229 <<
"Error getting Xpress int control: " << control;
238 if (int_control_defaults_.count(control)) {
240 int_control_defaults_[control]));
242 return absl::InvalidArgumentError(
243 "Default value unknown for control " + std::to_string(control) +
244 ", consider adding it to Xpress::initIntControlDefaults");
250 <<
"Error getting Xpress int attribute: " << attribute;
257 <<
"Error getting Xpress double attribute: " << attribute;
279 <<
"Failed to retrieve dual status from XPRESS";
284 std::vector<int>& colBasis)
const {
288 XPRSgetbasis(xpress_model_, rowBasis.data(), colBasis.data()));
292 std::vector<int>& colBasis)
const {
293 if (rowBasis.size() != colBasis.size()) {
294 return absl::InvalidArgumentError(
295 "Row basis and column basis must be of same size.");
298 XPRSloadbasis(xpress_model_, rowBasis.data(), colBasis.data()));
303 std::vector<double> bounds;
304 bounds.reserve(nVars);
306 ToStatus(
XPRSgetlb(xpress_model_, bounds.data(), 0, nVars - 1)))
307 <<
"Failed to retrieve variable LB from XPRESS";
312 std::vector<double> bounds;
313 bounds.reserve(nVars);
315 ToStatus(
XPRSgetub(xpress_model_, bounds.data(), 0, nVars - 1)))
316 <<
"Failed to retrieve variable UB from XPRESS";
#define RETURN_IF_ERROR(expr)
absl::Status MipOptimize()
int GetNumberOfConstraints() const
static absl::StatusOr< std::unique_ptr< Xpress > > New(const std::string &model_name)
Creates a new Xpress.
int GetNumberOfVariables() const
absl::StatusOr< std::vector< double > > GetVarUb() const
absl::Status SetLinearObjective(double offset, absl::Span< const int > colind, absl::Span< const double > values)
absl::Status SetIntControl(int control, int value)
absl::Status SetStartingBasis(std::vector< int > &rowBasis, std::vector< int > &colBasis) const
absl::StatusOr< int > GetDualStatus() const
absl::StatusOr< int > GetIntAttr(int attribute) const
absl::Status GetLpSol(absl::Span< double > primals, absl::Span< double > duals, absl::Span< double > reducedCosts)
absl::Status AddConstrs(absl::Span< const char > sense, absl::Span< const double > rhs, absl::Span< const double > rng)
absl::Status AddVars(absl::Span< const double > obj, absl::Span< const double > lb, absl::Span< const double > ub, absl::Span< const char > vtype)
absl::Status ResetIntControl(int control)
absl::Status LpOptimize(std::string flags)
absl::Status SetQuadraticObjective(absl::Span< const int > colind1, absl::Span< const int > colind2, absl::Span< const double > coefficients)
absl::StatusOr< int > GetIntControl(int control) const
absl::StatusOr< double > GetDoubleAttr(int attribute) const
static void XPRS_CC printXpressMessage(XPRSprob prob, void *data, const char *sMsg, int nLen, int nMsgLvl)
absl::Status SetProbName(const std::string &name)
absl::Status GetBasis(std::vector< int > &rowBasis, std::vector< int > &colBasis) const
absl::Status SetObjectiveSense(bool maximize)
absl::StatusOr< std::vector< double > > GetVarLb() const
absl::Status ChgCoeffs(absl::Span< const int > cind, absl::Span< const int > vind, absl::Span< const double > val)
An object oriented wrapper for quadratic constraints in ModelStorage.
std::function< int(XPRSprob prob, int attrib, int *p_value)> XPRSgetintattrib
std::function< int(XPRSprob prob, int ncoefs, const int objqcol1[], const int objqcol2[], const double objqcoef[])> XPRSchgmqobj
std::function< int(XPRSprob prob, int attrib, double *p_value)> XPRSgetdblattrib
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
bool initXpressEnv(bool verbose, int xpress_oem_license_key)
! init XPRESS environment.
std::function< int(XPRSprob prob, const int rowstat[], const int colstat[])> XPRSloadbasis
std::function< int(XPRSprob prob, double lb[], int first, int last)> XPRSgetlb
std::function< int(XPRSprob prob, int control, int *p_value)> XPRSgetintcontrol
std::function< int(XPRSprob prob, double x[], double slack[], double duals[], double djs[])> XPRSgetlpsol
std::function< int(XPRSprob prob)> XPRSpostsolve
std::function< int(void)> XPRSfree
std::function< int(XPRSprob prob, int reason)> XPRSinterrupt
std::function< int(XPRSprob prob, int control, int value)> XPRSsetintcontrol
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
std::function< int(XPRSprob prob, char *errmsg)> XPRSgetlasterror
std::function< int(XPRSprob prob)> XPRSdestroyprob
std::function< int(XPRSprob prob, XPRSint64 ncoefs, const int rowind[], const int colind[], const double rowcoef[])> XPRSchgmcoef64
std::function< int(XPRSprob prob, double ub[], int first, int last)> XPRSgetub
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
std::function< int(XPRSprob prob, const char *flags)> XPRSmipoptimize
std::function< int(XPRSprob prob, int ncols, const int colind[], const double objcoef[])> XPRSchgobj
std::function< int(XPRSprob prob, int *status, double duals[], int first, int last)> XPRSgetduals
std::function< int(XPRSprob *p_prob)> XPRScreateprob
This is the 'define' section.
std::function< int(XPRSprob prob, const char *flags)> XPRSlpoptimize
std::function< int(XPRSprob prob, int objsense)> XPRSchgobjsense
std::function< int(XPRSprob prob, const char *probname)> XPRSsetprobname
std::function< int(XPRSprob prob, int rowstat[], int colstat[])> XPRSgetbasis
#define XPRS_OBJ_MAXIMIZE
struct xo_prob_struct * XPRSprob
Initial version of this code was provided by RTE.
#define XPRS_MAXPROBNAMELENGTH
#define XPRS_BARITERLIMIT
#define XPRS_OBJ_MINIMIZE