16 #if defined(USE_XPRESS)
23 #include "absl/strings/str_format.h"
33 #define XPRS_INTEGER 'I'
34 #define XPRS_CONTINUOUS 'C'
35 #define STRINGIFY2(X) #X
36 #define STRINGIFY(X) STRINGIFY2(X)
38 void printError(
const XPRSprob& mLp,
int line) {
40 XPRSgetlasterror(mLp, errmsg);
41 VLOG(0) << absl::StrFormat(
"Function line %d did not execute correctly: %s\n",
46 int XPRSgetnumcols(
const XPRSprob& mLp) {
48 XPRSgetintattrib(mLp, XPRS_COLS, &nCols);
52 int XPRSgetnumrows(
const XPRSprob& mLp) {
54 XPRSgetintattrib(mLp, XPRS_ROWS, &nRows);
58 int XPRSgetitcnt(
const XPRSprob& mLp) {
60 XPRSgetintattrib(mLp, XPRS_SIMPLEXITER, &nIters);
64 int XPRSgetnodecnt(
const XPRSprob& mLp) {
66 XPRSgetintattrib(mLp, XPRS_NODES, &nNodes);
70 int XPRSsetobjoffset(
const XPRSprob& mLp,
double value) {
71 XPRSsetdblcontrol(mLp, XPRS_OBJRHS,
value);
75 enum XPRS_BASIS_STATUS {
85 #define XPRS_NAN std::numeric_limits<double>::quiet_NaN()
91 #define CHECK_STATUS(s) \
93 int const status_ = s; \
94 CHECK_EQ(0, status_); \
99 using std::unique_ptr;
106 class XpressInterface :
public MPSolverInterface {
111 explicit XpressInterface(MPSolver*
const solver,
bool mip);
115 virtual void SetOptimizationDirection(
bool maximize);
123 virtual void Reset();
125 virtual void SetVariableBounds(
int var_index,
double lb,
double ub);
126 virtual void SetVariableInteger(
int var_index,
bool integer);
127 virtual void SetConstraintBounds(
int row_index,
double lb,
double ub);
129 virtual void AddRowConstraint(MPConstraint*
const ct);
130 virtual void AddVariable(MPVariable*
const var);
131 virtual void SetCoefficient(MPConstraint*
const constraint,
132 MPVariable
const*
const variable,
133 double new_value,
double old_value);
136 virtual void ClearConstraint(MPConstraint*
const constraint);
138 virtual void SetObjectiveCoefficient(MPVariable
const*
const variable,
141 virtual void SetObjectiveOffset(
double value);
143 virtual void ClearObjective();
147 virtual int64 iterations()
const;
149 virtual int64 nodes()
const;
151 virtual double best_objective_bound()
const;
163 virtual bool IsContinuous()
const {
return IsLP(); }
164 virtual bool IsLP()
const {
return !mMip; }
165 virtual bool IsMIP()
const {
return mMip; }
167 virtual void ExtractNewVariables();
168 virtual void ExtractNewConstraints();
169 virtual void ExtractObjective();
171 virtual std::string SolverVersion()
const;
173 virtual void* underlying_solver() {
return reinterpret_cast<void*
>(mLp); }
175 virtual double ComputeExactConditionNumber()
const {
176 if (!IsContinuous()) {
177 LOG(DFATAL) <<
"ComputeExactConditionNumber not implemented for"
178 <<
" XPRESS_MIXED_INTEGER_PROGRAMMING";
183 LOG(DFATAL) <<
"ComputeExactConditionNumber not implemented for"
184 <<
" XPRESS_LINEAR_PROGRAMMING";
190 virtual void SetParameters(MPSolverParameters
const& param);
192 virtual void SetRelativeMipGap(
double value);
193 virtual void SetPrimalTolerance(
double value);
194 virtual void SetDualTolerance(
double value);
195 virtual void SetPresolveMode(
int value);
196 virtual void SetScalingMode(
int value);
197 virtual void SetLpAlgorithm(
int value);
199 virtual bool ReadParameterFile(std::string
const& filename);
200 virtual std::string ValidFileExtensionForParameterFile()
const;
206 void InvalidateModelSynchronization() {
209 sync_status_ = MUST_RELOAD;
229 bool const supportIncrementalExtraction;
237 SlowSetCoefficient = 0x0001,
238 SlowClearConstraint = 0x0002,
239 SlowSetObjectiveCoefficient = 0x0004,
240 SlowClearObjective = 0x0008,
241 SlowSetConstraintBounds = 0x0010,
242 SlowSetVariableInteger = 0x0020,
243 SlowSetVariableBounds = 0x0040,
244 SlowUpdatesAll = 0xffff
250 unique_ptr<int[]>
mutable mCstat;
251 unique_ptr<int[]>
mutable mRstat;
254 static void MakeRhs(
double lb,
double ub,
double& rhs,
char& sense,
259 int init_xpress_env(
int xpress_oem_license_key = 0) {
262 const char* xpress_from_env = getenv(
"XPRESS");
263 std::string xpresspath;
265 if (xpress_from_env ==
nullptr) {
266 #if defined(XPRESS_PATH)
267 std::string path(STRINGIFY(XPRESS_PATH));
269 <<
"Environment variable XPRESS undefined. Trying compile path "
270 <<
"'" << path <<
"'";
271 #if defined(_MSC_VER)
273 path.erase(std::remove(path.begin(), path.end(),
'\"'), path.end());
274 xpresspath = path +
"\\bin";
276 xpresspath = path +
"/bin";
280 <<
"XpressInterface Error : Environment variable XPRESS undefined.\n";
284 xpresspath = xpress_from_env;
288 if (xpress_oem_license_key == 0) {
289 LOG(
WARNING) <<
"XpressInterface : Initialising xpress-MP with parameter "
290 << xpresspath << std::endl;
292 code = XPRSinit(xpresspath.c_str());
297 XPRSgetbanner(banner);
299 LOG(
WARNING) <<
"XpressInterface : Xpress banner :\n"
300 << banner << std::endl;
304 XPRSgetlicerrmsg(errmsg, 256);
306 VLOG(0) <<
"XpressInterface : License error : " << errmsg << std::endl;
307 VLOG(0) <<
"XpressInterface : XPRSinit returned code : " << code <<
"\n";
310 XPRSgetbanner(banner);
312 LOG(
ERROR) <<
"XpressInterface : Xpress banner :\n" << banner <<
"\n";
317 LOG(
WARNING) <<
"XpressInterface : Initialising xpress-MP with OEM key "
318 << xpress_oem_license_key <<
"\n";
322 char slicmsg[256] =
"";
325 XPRSlicense(&nvalue, slicmsg);
326 VLOG(0) <<
"XpressInterface : First message from XPRSLicense : " << slicmsg
329 nvalue = xpress_oem_license_key - ((nvalue * nvalue) / 19);
330 ierr = XPRSlicense(&nvalue, slicmsg);
332 VLOG(0) <<
"XpressInterface : Second message from XPRSLicense : " << slicmsg
335 VLOG(0) <<
"XpressInterface : Optimizer development software detected\n";
336 }
else if (ierr != 0) {
338 XPRSgetlicerrmsg(errmsg, 256);
340 LOG(
ERROR) <<
"XpressInterface : " << errmsg <<
"\n";
344 code = XPRSinit(NULL);
349 LOG(
ERROR) <<
"XPRSinit returned code : " << code <<
"\n";
356 XpressInterface::XpressInterface(MPSolver*
const solver,
bool mip)
357 : MPSolverInterface(solver),
360 supportIncrementalExtraction(false),
361 slowUpdates(static_cast<SlowUpdates>(SlowSetObjectiveCoefficient |
362 SlowClearObjective)),
365 int status = init_xpress_env();
366 CHECK_STATUS(status);
367 status = XPRScreateprob(&mLp);
368 CHECK_STATUS(status);
370 CHECK_STATUS(XPRSloadlp(mLp,
"newProb", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
373 XPRSchgobjsense(mLp,
maximize_ ? XPRS_OBJ_MAXIMIZE : XPRS_OBJ_MINIMIZE));
376 XpressInterface::~XpressInterface() {
377 CHECK_STATUS(XPRSdestroyprob(mLp));
381 std::string XpressInterface::SolverVersion()
const {
385 CHECK_STATUS(XPRSgetintcontrol(mLp, XPRS_VERSION, &version));
387 int const major = version / 1000000;
388 version -= major * 1000000;
389 int const release = version / 10000;
390 version -= release * 10000;
391 int const mod = version / 100;
392 version -= mod * 100;
393 int const fix = version;
395 return absl::StrFormat(
"XPRESS library version %d.%02d.%02d.%02d", major,
401 void XpressInterface::Reset() {
404 CHECK_STATUS(XPRSdestroyprob(mLp));
407 status = XPRScreateprob(&mLp);
408 CHECK_STATUS(status);
410 CHECK_STATUS(XPRSloadlp(mLp,
"newProb", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
413 XPRSchgobjsense(mLp,
maximize_ ? XPRS_OBJ_MAXIMIZE : XPRS_OBJ_MINIMIZE));
415 ResetExtractionInformation();
420 void XpressInterface::SetOptimizationDirection(
bool maximize) {
421 InvalidateSolutionSynchronization();
422 XPRSchgobjsense(mLp, maximize ? XPRS_OBJ_MAXIMIZE : XPRS_OBJ_MINIMIZE);
425 void XpressInterface::SetVariableBounds(
int var_index,
double lb,
double ub) {
426 InvalidateSolutionSynchronization();
434 if (!supportIncrementalExtraction && !(slowUpdates & SlowSetVariableBounds)) {
435 InvalidateModelSynchronization();
437 if (variable_is_extracted(var_index)) {
440 DCHECK_LT(var_index, last_variable_index_);
441 char const lu[2] = {
'L',
'U'};
442 double const bd[2] = {lb, ub};
443 int const idx[2] = {var_index, var_index};
444 CHECK_STATUS(XPRSchgbounds(mLp, 2, idx, lu, bd));
448 InvalidateModelSynchronization();
454 void XpressInterface::SetVariableInteger(
int var_index,
bool integer) {
455 InvalidateSolutionSynchronization();
467 if (!supportIncrementalExtraction && !slowUpdates &&
468 !SlowSetVariableInteger) {
469 InvalidateModelSynchronization();
472 if (variable_is_extracted(var_index)) {
476 DCHECK_LE(var_index, XPRSgetnumcols(mLp));
477 char const type = integer ? XPRS_INTEGER : XPRS_CONTINUOUS;
478 CHECK_STATUS(XPRSchgcoltype(mLp, 1, &var_index, &type));
480 InvalidateModelSynchronization();
484 <<
"Attempt to change variable to integer in non-MIP problem!";
490 void XpressInterface::MakeRhs(
double lb,
double ub,
double& rhs,
char& sense,
497 }
else if (lb > XPRS_MINUSINFINITY && ub < XPRS_PLUSINFINITY) {
517 }
else if (ub < XPRS_PLUSINFINITY || (std::abs(ub) == XPRS_PLUSINFINITY &&
518 std::abs(lb) > XPRS_PLUSINFINITY)) {
523 }
else if (lb > XPRS_MINUSINFINITY || (std::abs(lb) == XPRS_PLUSINFINITY &&
524 std::abs(ub) > XPRS_PLUSINFINITY)) {
538 DCHECK_GT(std::abs(lb), XPRS_PLUSINFINITY);
539 DCHECK_GT(std::abs(ub), XPRS_PLUSINFINITY);
540 if (std::abs(lb) > std::abs(ub)) {
541 rhs = (lb < 0) ? -XPRS_PLUSINFINITY : XPRS_PLUSINFINITY;
544 rhs = (ub < 0) ? -XPRS_PLUSINFINITY : XPRS_PLUSINFINITY;
551 void XpressInterface::SetConstraintBounds(
int index,
double lb,
double ub) {
552 InvalidateSolutionSynchronization();
560 if (!supportIncrementalExtraction &&
561 !(slowUpdates & SlowSetConstraintBounds)) {
562 InvalidateModelSynchronization();
564 if (constraint_is_extracted(
index)) {
570 MakeRhs(lb, ub, rhs, sense, range);
571 CHECK_STATUS(XPRSchgrhs(mLp, 1, &
index, &lb));
572 CHECK_STATUS(XPRSchgrowtype(mLp, 1, &
index, &sense));
573 CHECK_STATUS(XPRSchgrhsrange(mLp, 1, &
index, &range));
577 InvalidateModelSynchronization();
582 void XpressInterface::AddRowConstraint(MPConstraint*
const ct) {
589 InvalidateModelSynchronization();
592 void XpressInterface::AddVariable(MPVariable*
const ct) {
599 InvalidateModelSynchronization();
602 void XpressInterface::SetCoefficient(MPConstraint*
const constraint,
603 MPVariable
const*
const variable,
604 double new_value,
double) {
605 InvalidateSolutionSynchronization();
614 if (!supportIncrementalExtraction && !(slowUpdates & SlowSetCoefficient)) {
615 InvalidateModelSynchronization();
617 int const row = constraint->index();
618 int const col = variable->index();
619 if (constraint_is_extracted(
row) && variable_is_extracted(
col)) {
624 CHECK_STATUS(XPRSchgcoef(mLp,
row,
col, new_value));
628 InvalidateModelSynchronization();
633 void XpressInterface::ClearConstraint(MPConstraint*
const constraint) {
634 int const row = constraint->index();
635 if (!constraint_is_extracted(
row))
647 if (!(slowUpdates & SlowClearConstraint)) {
648 InvalidateModelSynchronization();
650 InvalidateSolutionSynchronization();
652 int const len = constraint->coefficients_.size();
653 unique_ptr<int[]> rowind(
new int[len]);
654 unique_ptr<int[]> colind(
new int[len]);
655 unique_ptr<double[]> val(
new double[len]);
657 const auto& coeffs = constraint->coefficients_;
658 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
659 int const col = it->first->index();
660 if (variable_is_extracted(
col)) {
668 CHECK_STATUS(XPRSchgmcoef(mLp, j, rowind.get(), colind.get(), val.get()));
672 void XpressInterface::SetObjectiveCoefficient(MPVariable
const*
const variable,
674 int const col = variable->index();
675 if (!variable_is_extracted(
col))
679 InvalidateSolutionSynchronization();
687 if (supportIncrementalExtraction ||
688 (slowUpdates & SlowSetObjectiveCoefficient)) {
691 InvalidateModelSynchronization();
695 void XpressInterface::SetObjectiveOffset(
double value) {
697 InvalidateSolutionSynchronization();
698 CHECK_STATUS(XPRSsetobjoffset(mLp,
value));
701 void XpressInterface::ClearObjective() {
702 InvalidateSolutionSynchronization();
709 if (supportIncrementalExtraction || (slowUpdates & SlowClearObjective)) {
710 int const cols = XPRSgetnumcols(mLp);
711 unique_ptr<int[]> ind(
new int[cols]);
712 unique_ptr<double[]> zero(
new double[cols]);
714 const auto& coeffs = solver_->objective_->coefficients_;
715 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
716 int const idx = it->first->index();
718 if (variable_is_extracted(idx)) {
725 if (j > 0) CHECK_STATUS(XPRSchgobj(mLp, j, ind.get(), zero.get()));
726 CHECK_STATUS(XPRSsetobjoffset(mLp, 0.0));
728 InvalidateModelSynchronization();
734 int64 XpressInterface::iterations()
const {
735 if (!CheckSolutionIsSynchronized())
return kUnknownNumberOfIterations;
736 return static_cast<int64>(XPRSgetitcnt(mLp));
739 int64 XpressInterface::nodes()
const {
741 if (!CheckSolutionIsSynchronized())
return kUnknownNumberOfNodes;
742 return static_cast<int64>(XPRSgetnodecnt(mLp));
744 LOG(DFATAL) <<
"Number of nodes only available for discrete problems";
745 return kUnknownNumberOfNodes;
750 double XpressInterface::best_objective_bound()
const {
752 if (!CheckSolutionIsSynchronized() || !CheckBestObjectiveBoundExists())
755 return trivial_worst_objective_bound();
756 if (solver_->variables_.size() == 0 && solver_->constraints_.size() == 0) {
758 return solver_->Objective().offset();
760 double value = XPRS_NAN;
761 CHECK_STATUS(XPRSgetdblattrib(mLp, XPRS_BESTBOUND, &
value));
765 LOG(DFATAL) <<
"Best objective bound only available for discrete problems";
766 return trivial_worst_objective_bound();
771 MPSolver::BasisStatus XpressInterface::xformBasisStatus(
772 int xpress_basis_status) {
773 switch (xpress_basis_status) {
775 return MPSolver::AT_LOWER_BOUND;
777 return MPSolver::BASIC;
779 return MPSolver::AT_UPPER_BOUND;
780 case XPRS_FREE_SUPER:
781 return MPSolver::FREE;
783 LOG(DFATAL) <<
"Unknown XPRESS basis status";
784 return MPSolver::FREE;
789 MPSolver::BasisStatus XpressInterface::row_status(
int constraint_index)
const {
791 LOG(
FATAL) <<
"Basis status only available for continuous problems";
792 return MPSolver::FREE;
795 if (CheckSolutionIsSynchronized()) {
797 int const rows = XPRSgetnumrows(mLp);
798 unique_ptr<int[]> data(
new int[rows]);
800 CHECK_STATUS(XPRSgetbasis(mLp, 0, mRstat.get()));
807 return xformBasisStatus(mRstat[constraint_index]);
809 LOG(
FATAL) <<
"Row basis status not available";
810 return MPSolver::FREE;
815 MPSolver::BasisStatus XpressInterface::column_status(
int variable_index)
const {
817 LOG(
FATAL) <<
"Basis status only available for continuous problems";
818 return MPSolver::FREE;
821 if (CheckSolutionIsSynchronized()) {
823 int const cols = XPRSgetnumcols(mLp);
824 unique_ptr<int[]> data(
new int[cols]);
826 CHECK_STATUS(XPRSgetbasis(mLp, mCstat.get(), 0));
833 return xformBasisStatus(mCstat[variable_index]);
835 LOG(
FATAL) <<
"Column basis status not available";
836 return MPSolver::FREE;
841 void XpressInterface::ExtractNewVariables() {
845 InvalidateSolutionSynchronization();
847 if (!supportIncrementalExtraction) {
850 CHECK(last_variable_index_ == 0 ||
851 last_variable_index_ == solver_->variables_.size());
852 CHECK(last_constraint_index_ == 0 ||
853 last_constraint_index_ == solver_->constraints_.size());
856 int const last_extracted = last_variable_index_;
857 int const var_count = solver_->variables_.size();
858 int newcols = var_count - last_extracted;
862 unique_ptr<double[]> obj(
new double[newcols]);
863 unique_ptr<double[]> lb(
new double[newcols]);
864 unique_ptr<double[]> ub(
new double[newcols]);
865 unique_ptr<char[]> ctype(
new char[newcols]);
866 unique_ptr<const char*[]> colname(
new const char*[newcols]);
868 bool have_names =
false;
869 for (
int j = 0, varidx = last_extracted; j < newcols; ++j, ++varidx) {
870 MPVariable
const*
const var = solver_->variables_[varidx];
873 ctype[j] =
var->integer() ? XPRS_INTEGER : XPRS_CONTINUOUS;
874 colname[j] =
var->name().empty() ? 0 :
var->name().c_str();
875 have_names = have_names ||
var->name().empty();
876 obj[j] = solver_->objective_->GetCoefficient(
var);
884 std::vector<MPVariable*>
const& variables = solver_->variables();
885 for (
int j = last_extracted; j < var_count; ++j) {
886 CHECK(!variable_is_extracted(variables[j]->
index()));
887 set_variable_as_extracted(variables[j]->
index(),
true);
891 bool use_newcols =
true;
893 if (supportIncrementalExtraction) {
902 unique_ptr<int[]> collen(
new int[newcols]);
903 for (
int j = 0; j < newcols; ++j) collen[j] = 0;
907 for (
int i = 0; i < last_constraint_index_; ++i) {
908 MPConstraint
const*
const ct = solver_->constraints_[i];
909 CHECK(constraint_is_extracted(
ct->index()));
910 const auto& coeffs =
ct->coefficients_;
911 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
912 int const idx = it->first->index();
913 if (variable_is_extracted(idx) && idx > last_variable_index_) {
914 collen[idx - last_variable_index_]++;
925 unique_ptr<int[]> begin(
new int[newcols + 2]);
926 unique_ptr<int[]> cmatind(
new int[nonzeros]);
927 unique_ptr<double[]> cmatval(
new double[nonzeros]);
938 int* cmatbeg = begin.get();
942 for (
int j = 0; j < newcols; ++j)
943 cmatbeg[j + 1] = cmatbeg[j] + collen[j];
945 for (
int i = 0; i < last_constraint_index_; ++i) {
946 MPConstraint
const*
const ct = solver_->constraints_[i];
947 int const row =
ct->index();
948 const auto& coeffs =
ct->coefficients_;
949 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
950 int const idx = it->first->index();
951 if (variable_is_extracted(idx) && idx > last_variable_index_) {
952 int const nz = cmatbeg[idx]++;
954 cmatval[nz] = it->second;
959 CHECK_STATUS(XPRSaddcols(mLp, newcols, nonzeros, obj.get(), cmatbeg,
960 cmatind.get(), cmatval.get(), lb.get(),
969 std::vector<int> collen(newcols, 0);
970 std::vector<int> cmatbeg(newcols, 0);
971 unique_ptr<int[]> cmatind(
new int[1]);
972 unique_ptr<double[]> cmatval(
new double[1]);
976 CHECK_STATUS(XPRSaddcols(mLp, newcols, 0, obj.get(), cmatbeg.data(),
977 cmatind.get(), cmatval.get(), lb.get(),
979 int const cols = XPRSgetnumcols(mLp);
980 unique_ptr<int[]> ind(
new int[newcols]);
981 for (
int j = 0; j < cols; ++j) ind[j] = j;
983 XPRSchgcoltype(mLp, cols - last_extracted, ind.get(), ctype.get()));
988 if (mMip && XPRSgetnumcols(mLp) > 0) {
991 int const cols = XPRSgetnumcols(mLp);
992 unique_ptr<int[]> ind(
new int[newcols]);
993 for (
int j = last_extracted; j < cols; ++j)
994 ind[j - last_extracted] = j;
995 CHECK_STATUS(XPRSchgcoltype(mLp, cols - last_extracted, ind.get(),
1001 int const cols = XPRSgetnumcols(mLp);
1002 if (cols > last_extracted) {
1003 std::vector<int> colsToDelete;
1004 for (
int i = last_extracted; i < cols; ++i) colsToDelete.push_back(i);
1005 (void)XPRSdelcols(mLp, colsToDelete.size(), colsToDelete.data());
1007 std::vector<MPVariable*>
const& variables = solver_->variables();
1008 int const size = variables.size();
1009 for (
int j = last_extracted; j < size; ++j)
1010 set_variable_as_extracted(j,
false);
1017 void XpressInterface::ExtractNewConstraints() {
1020 if (!supportIncrementalExtraction) {
1023 CHECK(last_variable_index_ == 0 ||
1024 last_variable_index_ == solver_->variables_.size());
1025 CHECK(last_constraint_index_ == 0 ||
1026 last_constraint_index_ == solver_->constraints_.size());
1029 int const offset = last_constraint_index_;
1030 int const total = solver_->constraints_.size();
1032 if (total > offset) {
1035 InvalidateSolutionSynchronization();
1037 int newCons = total - offset;
1038 int const cols = XPRSgetnumcols(mLp);
1040 int const chunk = newCons;
1044 for (
int c = offset; c < total; ++c) set_constraint_as_extracted(c,
true);
1047 unique_ptr<int[]> rmatind(
new int[cols]);
1048 unique_ptr<double[]> rmatval(
new double[cols]);
1049 unique_ptr<int[]> rmatbeg(
new int[chunk]);
1050 unique_ptr<char[]> sense(
new char[chunk]);
1051 unique_ptr<double[]> rhs(
new double[chunk]);
1052 unique_ptr<char const*[]>
name(
new char const*[chunk]);
1053 unique_ptr<double[]> rngval(
new double[chunk]);
1054 unique_ptr<int[]> rngind(
new int[chunk]);
1055 bool haveRanges =
false;
1060 for (
int c = 0; c < newCons; ) {
1064 for (; c < newCons && nextRow < chunk; ++c, ++nextRow) {
1065 MPConstraint
const*
const ct = solver_->constraints_[offset + c];
1069 if (nextNz +
ct->coefficients_.size() > cols) {
1075 MakeRhs(
ct->lb(),
ct->ub(), rhs[nextRow], sense[nextRow],
1077 haveRanges = haveRanges || (rngval[nextRow] != 0.0);
1078 rngind[nextRow] = offset + c;
1081 rmatbeg[nextRow] = nextNz;
1082 const auto& coeffs =
ct->coefficients_;
1083 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
1084 int const idx = it->first->index();
1085 if (variable_is_extracted(idx)) {
1088 rmatind[nextNz] = idx;
1089 rmatval[nextNz] = it->second;
1095 name[nextRow] =
ct->name().empty() ? 0 :
ct->name().c_str();
1098 CHECK_STATUS(XPRSaddrows(mLp, nextRow, nextNz, sense.get(), rhs.get(),
1099 rngval.get(), rmatbeg.get(), rmatind.get(),
1103 XPRSchgrhsrange(mLp, nextRow, rngind.get(), rngval.get()));
1109 int const rows = XPRSgetnumrows(mLp);
1110 std::vector<int> rowsToDelete;
1111 for (
int i = offset; i < rows; ++i) rowsToDelete.push_back(i);
1113 (void)XPRSdelrows(mLp, rowsToDelete.size(), rowsToDelete.data());
1114 std::vector<MPConstraint*>
const& constraints = solver_->constraints();
1115 int const size = constraints.size();
1116 for (
int i = offset; i < size; ++i) set_constraint_as_extracted(i,
false);
1123 void XpressInterface::ExtractObjective() {
1127 int const cols = XPRSgetnumcols(mLp);
1130 unique_ptr<int[]> ind(
new int[cols]);
1131 unique_ptr<double[]> val(
new double[cols]);
1132 for (
int j = 0; j < cols; ++j) {
1137 const auto& coeffs = solver_->objective_->coefficients_;
1138 for (
auto it = coeffs.begin(); it != coeffs.end(); ++it) {
1139 int const idx = it->first->index();
1140 if (variable_is_extracted(idx)) {
1142 val[idx] = it->second;
1146 CHECK_STATUS(XPRSchgobj(mLp, cols, ind.get(), val.get()));
1147 CHECK_STATUS(XPRSsetobjoffset(mLp, solver_->Objective().offset()));
1152 void XpressInterface::SetParameters(
const MPSolverParameters& param) {
1153 SetCommonParameters(param);
1154 if (mMip) SetMIPParameters(param);
1157 void XpressInterface::SetRelativeMipGap(
double value) {
1159 CHECK_STATUS(XPRSsetdblcontrol(mLp, XPRS_MIPRELSTOP,
value));
1161 LOG(
WARNING) <<
"The relative MIP gap is only available "
1162 <<
"for discrete problems.";
1166 void XpressInterface::SetPrimalTolerance(
double value) {
1167 CHECK_STATUS(XPRSsetdblcontrol(mLp, XPRS_FEASTOL,
value));
1170 void XpressInterface::SetDualTolerance(
double value) {
1171 CHECK_STATUS(XPRSsetdblcontrol(mLp, XPRS_OPTIMALITYTOL,
value));
1174 void XpressInterface::SetPresolveMode(
int value) {
1175 MPSolverParameters::PresolveValues
const presolve =
1176 static_cast<MPSolverParameters::PresolveValues
>(
value);
1179 case MPSolverParameters::PRESOLVE_OFF:
1180 CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_PRESOLVE, 0));
1182 case MPSolverParameters::PRESOLVE_ON:
1183 CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_PRESOLVE, 1));
1186 SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE,
value);
1190 void XpressInterface::SetScalingMode(
int value) {
1191 MPSolverParameters::ScalingValues
const scaling =
1192 static_cast<MPSolverParameters::ScalingValues
>(
value);
1195 case MPSolverParameters::SCALING_OFF:
1196 CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_SCALING, 0));
1198 case MPSolverParameters::SCALING_ON:
1199 CHECK_STATUS(XPRSsetdefaultcontrol(mLp, XPRS_SCALING));
1210 void XpressInterface::SetLpAlgorithm(
int value) {
1211 MPSolverParameters::LpAlgorithmValues
const algorithm =
1212 static_cast<MPSolverParameters::LpAlgorithmValues
>(
value);
1216 switch (algorithm) {
1217 case MPSolverParameters::DUAL:
1220 case MPSolverParameters::PRIMAL:
1223 case MPSolverParameters::BARRIER:
1228 if (alg == XPRS_DEFAULTALG) {
1229 SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM,
value);
1231 CHECK_STATUS(XPRSsetintcontrol(mLp, XPRS_DEFAULTALG, alg));
1235 bool XpressInterface::ReadParameterFile(std::string
const& filename) {
1237 LOG(DFATAL) <<
"ReadParameterFile not implemented for XPRESS interface";
1241 std::string XpressInterface::ValidFileExtensionForParameterFile()
const {
1256 MPSolverParameters::IncrementalityValues
const inc =
1257 static_cast<MPSolverParameters::IncrementalityValues
>(
1258 param.GetIntegerParam(MPSolverParameters::INCREMENTALITY));
1260 case MPSolverParameters::INCREMENTALITY_OFF: {
1265 case MPSolverParameters::INCREMENTALITY_ON: {
1266 XPRSsetintcontrol(mLp, XPRS_CRASH, 0);
1276 if (!supportIncrementalExtraction && sync_status_ == MUST_RELOAD) Reset();
1278 VLOG(1) << absl::StrFormat(
"Model build in %.3f seconds.", timer.
Get());
1281 XPRSsetintcontrol(mLp, XPRS_OUTPUTLOG, quiet() ? 0 : 1);
1287 solver_->SetSolverSpecificParametersAsString(
1288 solver_->solver_specific_parameter_string_);
1289 SetParameters(param);
1290 if (solver_->time_limit()) {
1291 VLOG(1) <<
"Setting time limit = " << solver_->time_limit() <<
" ms.";
1294 CHECK_STATUS(XPRSsetdblcontrol(mLp, XPRS_MAXTIME,
1295 -1.0 * solver_->time_limit_in_secs()));
1306 status = XPRSmaxim(mLp,
"g");
1308 status = XPRSminim(mLp,
"g");
1309 XPRSgetintattrib(mLp, XPRS_MIPSTATUS, &xpressstat);
1312 status = XPRSmaxim(mLp,
"");
1314 status = XPRSminim(mLp,
"");
1315 XPRSgetintattrib(mLp, XPRS_LPSTATUS, &xpressstat);
1319 XPRSsetintcontrol(mLp, XPRS_OUTPUTLOG, 0);
1322 VLOG(1) << absl::StrFormat(
"Failed to optimize MIP. Error %d", status);
1326 VLOG(1) << absl::StrFormat(
"Solved in %.3f seconds.", timer.
Get());
1329 VLOG(1) << absl::StrFormat(
"XPRESS solution status %d.", xpressstat);
1332 bool const feasible = (mMip && (xpressstat == XPRS_MIP_OPTIMAL ||
1333 xpressstat == XPRS_MIP_SOLUTION)) ||
1334 (!mMip && xpressstat == XPRS_LP_OPTIMAL);
1337 int const rows = XPRSgetnumrows(mLp);
1338 int const cols = XPRSgetnumcols(mLp);
1339 DCHECK_EQ(rows, solver_->constraints_.size());
1340 DCHECK_EQ(cols, solver_->variables_.size());
1343 objective_value_ = XPRS_NAN;
1346 CHECK_STATUS(XPRSgetdblattrib(mLp, XPRS_MIPOBJVAL, &objective_value_));
1348 CHECK_STATUS(XPRSgetdblattrib(mLp, XPRS_LPOBJVAL, &objective_value_));
1351 VLOG(1) <<
"objective = " << objective_value_;
1358 unique_ptr<double[]> x(
new double[cols]);
1359 CHECK_STATUS(XPRSgetmipsol(mLp, x.get(), 0));
1360 for (
int i = 0; i < solver_->variables_.size(); ++i) {
1361 MPVariable*
const var = solver_->variables_[i];
1362 var->set_solution_value(x[i]);
1363 VLOG(3) <<
var->name() <<
": value =" << x[i];
1367 for (
int i = 0; i < solver_->variables_.size(); ++i)
1368 solver_->variables_[i]->set_solution_value(XPRS_NAN);
1372 for (
int i = 0; i < solver_->variables_.size(); ++i)
1373 solver_->variables_[i]->set_reduced_cost(XPRS_NAN);
1374 for (
int i = 0; i < solver_->constraints_.size(); ++i)
1375 solver_->constraints_[i]->set_dual_value(XPRS_NAN);
1379 unique_ptr<double[]> x(
new double[cols]);
1380 unique_ptr<double[]> dj(
new double[cols]);
1381 if (feasible) CHECK_STATUS(XPRSgetlpsol(mLp, x.get(), 0, 0, dj.get()));
1382 for (
int i = 0; i < solver_->variables_.size(); ++i) {
1383 MPVariable*
const var = solver_->variables_[i];
1384 var->set_solution_value(x[i]);
1385 bool value =
false, dual =
false;
1388 var->set_solution_value(x[i]);
1391 var->set_solution_value(XPRS_NAN);
1394 var->set_reduced_cost(dj[i]);
1397 var->set_reduced_cost(XPRS_NAN);
1400 << (
value ? absl::StrFormat(
" value = %f", x[i]) :
"")
1401 << (dual ?
absl::StrFormat(
" reduced cost = %f", dj[i]) :
"");
1406 unique_ptr<double[]> pi(
new double[rows]);
1408 CHECK_STATUS(XPRSgetlpsol(mLp, 0, 0, pi.get(), 0));
1410 for (
int i = 0; i < solver_->constraints_.size(); ++i) {
1411 MPConstraint*
const ct = solver_->constraints_[i];
1414 ct->set_dual_value(pi[i]);
1417 ct->set_dual_value(XPRS_NAN);
1419 VLOG(4) <<
"row " <<
ct->index() <<
":"
1420 << (dual ? absl::StrFormat(
" dual = %f", pi[i]) :
"");
1427 switch (xpressstat) {
1428 case XPRS_MIP_OPTIMAL:
1431 case XPRS_MIP_INFEAS:
1434 case XPRS_MIP_UNBOUNDED:
1435 result_status_ = MPSolver::UNBOUNDED;
1442 switch (xpressstat) {
1443 case XPRS_LP_OPTIMAL:
1446 case XPRS_LP_INFEAS:
1449 case XPRS_LP_UNBOUNDED:
1450 result_status_ = MPSolver::UNBOUNDED;
1458 sync_status_ = SOLUTION_SYNCHRONIZED;
1459 return result_status_;
1462 MPSolverInterface* BuildXpressInterface(
bool mip, MPSolver*
const solver) {
1463 return new XpressInterface(solver, mip);
1467 #endif // #if defined(USE_XPRESS)