19 #include "absl/strings/str_format.h"
25 #if defined(USE_CPLEX)
28 #include "ilcplex/cplexx.h"
32 CPXLIBAPI
int CPXPUBLIC CPXEsetobjoffset(CPXCENVptr, CPXLPptr,
double);
38 #define CPX_NAN std::numeric_limits<double>::quiet_NaN()
44 #define CHECK_STATUS(s) \
46 int const status_ = s; \
47 CHECK_EQ(0, status_); \
52 using std::unique_ptr;
59 class CplexInterface :
public MPSolverInterface {
64 explicit CplexInterface(MPSolver*
const solver,
bool mip);
68 virtual void SetOptimizationDirection(
bool maximize);
78 virtual void SetVariableBounds(
int var_index,
double lb,
double ub);
79 virtual void SetVariableInteger(
int var_index,
bool integer);
80 virtual void SetConstraintBounds(
int row_index,
double lb,
double ub);
82 virtual void AddRowConstraint(MPConstraint*
const ct);
83 virtual void AddVariable(MPVariable*
const var);
84 virtual void SetCoefficient(MPConstraint*
const constraint,
85 MPVariable
const*
const variable,
86 double new_value,
double old_value);
89 virtual void ClearConstraint(MPConstraint*
const constraint);
91 virtual void SetObjectiveCoefficient(MPVariable
const*
const variable,
94 virtual void SetObjectiveOffset(
double value);
96 virtual void ClearObjective();
100 virtual int64 iterations()
const;
102 virtual int64 nodes()
const;
104 virtual double best_objective_bound()
const;
116 virtual bool IsContinuous()
const {
return IsLP(); }
117 virtual bool IsLP()
const {
return !mMip; }
118 virtual bool IsMIP()
const {
return mMip; }
120 virtual void ExtractNewVariables();
121 virtual void ExtractNewConstraints();
122 virtual void ExtractObjective();
124 virtual std::string SolverVersion()
const;
126 virtual void* underlying_solver() {
return reinterpret_cast<void*
>(mLp); }
128 virtual double ComputeExactConditionNumber()
const {
129 if (!IsContinuous()) {
130 LOG(DFATAL) <<
"ComputeExactConditionNumber not implemented for"
131 <<
" CPLEX_MIXED_INTEGER_PROGRAMMING";
135 if (CheckSolutionIsSynchronized()) {
136 double kappa = CPX_NAN;
137 CHECK_STATUS(CPXXgetdblquality(mEnv, mLp, &kappa, CPX_EXACT_KAPPA));
140 LOG(DFATAL) <<
"Cannot get exact condition number without solution";
146 virtual void SetParameters(MPSolverParameters
const& param);
148 virtual void SetRelativeMipGap(
double value);
149 virtual void SetPrimalTolerance(
double value);
150 virtual void SetDualTolerance(
double value);
151 virtual void SetPresolveMode(
int value);
152 virtual void SetScalingMode(
int value);
153 virtual void SetLpAlgorithm(
int value);
155 virtual bool ReadParameterFile(std::string
const& filename);
156 virtual std::string ValidFileExtensionForParameterFile()
const;
162 void InvalidateModelSynchronization() {
165 sync_status_ = MUST_RELOAD;
186 bool const supportIncrementalExtraction;
194 SlowSetCoefficient = 0x0001,
195 SlowClearConstraint = 0x0002,
196 SlowSetObjectiveCoefficient = 0x0004,
197 SlowClearObjective = 0x0008,
198 SlowSetConstraintBounds = 0x0010,
199 SlowSetVariableInteger = 0x0020,
200 SlowSetVariableBounds = 0x0040,
201 SlowUpdatesAll = 0xffff
207 unique_ptr<int[]>
mutable mCstat;
208 unique_ptr<int[]>
mutable mRstat;
211 static void MakeRhs(
double lb,
double ub,
double& rhs,
char& sense,
216 CplexInterface::CplexInterface(MPSolver*
const solver,
bool mip)
217 : MPSolverInterface(solver),
221 slowUpdates(static_cast<SlowUpdates>(SlowSetObjectiveCoefficient |
222 SlowClearObjective)),
223 supportIncrementalExtraction(false),
228 mEnv = CPXXopenCPLEX(&status);
229 CHECK_STATUS(status);
232 char const*
name = solver_->name_.c_str();
233 mLp = CPXXcreateprob(mEnv, &status,
name);
234 CHECK_STATUS(status);
237 CHECK_STATUS(CPXXchgobjsen(mEnv, mLp,
maximize_ ? CPX_MAX : CPX_MIN));
238 if (mMip) CHECK_STATUS(CPXXchgprobtype(mEnv, mLp, CPXPROB_MILP));
241 CplexInterface::~CplexInterface() {
242 CHECK_STATUS(CPXXfreeprob(mEnv, &mLp));
243 CHECK_STATUS(CPXXcloseCPLEX(&mEnv));
246 std::string CplexInterface::SolverVersion()
const {
250 CHECK_STATUS(CPXXversionnumber(mEnv, &version));
252 int const major = version / 1000000;
253 version -= major * 1000000;
254 int const release = version / 10000;
255 version -= release * 10000;
256 int const mod = version / 100;
257 version -= mod * 100;
258 int const fix = version;
260 return absl::StrFormat(
"CPLEX library version %d.%02d.%02d.%02d", major,
266 void CplexInterface::Reset() {
269 CHECK_STATUS(CPXXfreeprob(mEnv, &mLp));
272 const char*
const name = solver_->name_.c_str();
273 mLp = CPXXcreateprob(mEnv, &status,
name);
274 CHECK_STATUS(status);
277 CHECK_STATUS(CPXXchgobjsen(mEnv, mLp,
maximize_ ? CPX_MAX : CPX_MIN));
278 if (mMip) CHECK_STATUS(CPXXchgprobtype(mEnv, mLp, CPXPROB_MILP));
280 ResetExtractionInformation();
285 void CplexInterface::SetOptimizationDirection(
bool maximize) {
286 InvalidateSolutionSynchronization();
287 CPXXchgobjsen(mEnv, mLp, maximize ? CPX_MAX : CPX_MIN);
290 void CplexInterface::SetVariableBounds(
int var_index,
double lb,
double ub) {
291 InvalidateSolutionSynchronization();
299 if (!supportIncrementalExtraction && !(slowUpdates & SlowSetVariableBounds)) {
300 InvalidateModelSynchronization();
302 if (variable_is_extracted(var_index)) {
305 DCHECK_LT(var_index, last_variable_index_);
306 char const lu[2] = {
'L',
'U'};
307 double const bd[2] = {lb, ub};
308 CPXDIM
const idx[2] = {var_index, var_index};
309 CHECK_STATUS(CPXXchgbds(mEnv, mLp, 2, idx, lu, bd));
313 InvalidateModelSynchronization();
319 void CplexInterface::SetVariableInteger(
int var_index,
bool integer) {
320 InvalidateSolutionSynchronization();
332 if (!supportIncrementalExtraction &&
333 !(slowUpdates && SlowSetVariableInteger)) {
334 InvalidateModelSynchronization();
337 if (variable_is_extracted(var_index)) {
341 DCHECK_LE(var_index, CPXXgetnumcols(mEnv, mLp));
342 char const type = integer ? CPX_INTEGER : CPX_CONTINUOUS;
343 CHECK_STATUS(CPXXchgctype(mEnv, mLp, 1, &var_index, &type));
345 InvalidateModelSynchronization();
348 <<
"Attempt to change variable to integer in non-MIP problem!";
354 void CplexInterface::MakeRhs(
double lb,
double ub,
double& rhs,
char& sense,
361 }
else if (lb > -CPX_INFBOUND && ub < CPX_INFBOUND) {
376 CHECK_STATUS(CPXERR_BAD_ARGUMENT);
381 }
else if (ub < CPX_INFBOUND ||
382 (std::abs(ub) == CPX_INFBOUND && std::abs(lb) > CPX_INFBOUND)) {
387 }
else if (lb > -CPX_INFBOUND ||
388 (std::abs(lb) == CPX_INFBOUND && std::abs(ub) > CPX_INFBOUND)) {
404 if (std::abs(lb) > std::abs(ub)) {
405 rhs = (lb < 0) ? -CPX_INFBOUND : CPX_INFBOUND;
408 rhs = (ub < 0) ? -CPX_INFBOUND : CPX_INFBOUND;
415 void CplexInterface::SetConstraintBounds(
int index,
double lb,
double ub) {
416 InvalidateSolutionSynchronization();
424 if (!supportIncrementalExtraction &&
425 !(slowUpdates & SlowSetConstraintBounds)) {
426 InvalidateModelSynchronization();
428 if (constraint_is_extracted(
index)) {
434 MakeRhs(lb, ub, rhs, sense, range);
435 CHECK_STATUS(CPXXchgrhs(mEnv, mLp, 1, &
index, &lb));
436 CHECK_STATUS(CPXXchgsense(mEnv, mLp, 1, &
index, &sense));
437 CHECK_STATUS(CPXXchgrngval(mEnv, mLp, 1, &
index, &range));
441 InvalidateModelSynchronization();
446 void CplexInterface::AddRowConstraint(MPConstraint*
const ct) {
453 InvalidateModelSynchronization();
456 void CplexInterface::AddVariable(MPVariable*
const ct) {
463 InvalidateModelSynchronization();
466 void CplexInterface::SetCoefficient(MPConstraint*
const constraint,
467 MPVariable
const*
const variable,
468 double new_value,
double) {
469 InvalidateSolutionSynchronization();
478 if (!supportIncrementalExtraction && !(slowUpdates & SlowSetCoefficient)) {
479 InvalidateModelSynchronization();
481 int const row = constraint->index();
482 int const col = variable->index();
483 if (constraint_is_extracted(
row) && variable_is_extracted(
col)) {
488 CHECK_STATUS(CPXXchgcoef(mEnv, mLp,
row,
col, new_value));
492 InvalidateModelSynchronization();
497 void CplexInterface::ClearConstraint(MPConstraint*
const constraint) {
498 CPXDIM
const row = constraint->index();
499 if (!constraint_is_extracted(
row))
511 if (!(slowUpdates & SlowClearConstraint)) {
512 InvalidateModelSynchronization();
514 InvalidateSolutionSynchronization();
516 CPXDIM
const len = constraint->coefficients_.size();
517 unique_ptr<CPXDIM[]> rowind(
new CPXDIM[len]);
518 unique_ptr<CPXDIM[]> colind(
new CPXDIM[len]);
519 unique_ptr<double[]> val(
new double[len]);
521 const auto& coeffs = constraint->coefficients_;
522 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
523 CPXDIM
const col = it->first->index();
524 if (variable_is_extracted(
col)) {
533 CPXXchgcoeflist(mEnv, mLp, j, rowind.get(), colind.get(), val.get()));
537 void CplexInterface::SetObjectiveCoefficient(MPVariable
const*
const variable,
539 CPXDIM
const col = variable->index();
540 if (!variable_is_extracted(
col))
544 InvalidateSolutionSynchronization();
552 if (supportIncrementalExtraction ||
553 (slowUpdates & SlowSetObjectiveCoefficient)) {
556 InvalidateModelSynchronization();
559 void CplexInterface::SetObjectiveOffset(
double value) {
561 InvalidateSolutionSynchronization();
562 CHECK_STATUS(CPXEsetobjoffset(mEnv, mLp,
value));
565 void CplexInterface::ClearObjective() {
566 InvalidateSolutionSynchronization();
573 if (supportIncrementalExtraction || (slowUpdates & SlowClearObjective)) {
574 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
575 unique_ptr<CPXDIM[]> ind(
new CPXDIM[cols]);
576 unique_ptr<double[]> zero(
new double[cols]);
578 const auto& coeffs = solver_->objective_->coefficients_;
579 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
580 CPXDIM
const idx = it->first->index();
582 if (variable_is_extracted(idx)) {
589 if (j > 0) CHECK_STATUS(CPXXchgobj(mEnv, mLp, j, ind.get(), zero.get()));
590 CHECK_STATUS(CPXEsetobjoffset(mEnv, mLp, 0.0));
592 InvalidateModelSynchronization();
597 int64 CplexInterface::iterations()
const {
599 if (!CheckSolutionIsSynchronized())
return kUnknownNumberOfIterations;
601 return static_cast<int64>(CPXXgetmipitcnt(mEnv, mLp));
603 return static_cast<int64>(CPXXgetitcnt(mEnv, mLp));
606 int64 CplexInterface::nodes()
const {
608 if (!CheckSolutionIsSynchronized())
return kUnknownNumberOfNodes;
609 return static_cast<int64>(CPXXgetnodecnt(mEnv, mLp));
611 LOG(DFATAL) <<
"Number of nodes only available for discrete problems";
612 return kUnknownNumberOfNodes;
617 double CplexInterface::best_objective_bound()
const {
619 if (!CheckSolutionIsSynchronized() || !CheckBestObjectiveBoundExists())
622 return trivial_worst_objective_bound();
623 if (solver_->variables_.size() == 0 && solver_->constraints_.size() == 0) {
625 return solver_->Objective().offset();
627 double value = CPX_NAN;
628 CHECK_STATUS(CPXXgetbestobjval(mEnv, mLp, &
value));
632 LOG(DFATAL) <<
"Best objective bound only available for discrete problems";
633 return trivial_worst_objective_bound();
639 switch (cplex_basis_status) {
649 LOG(DFATAL) <<
"Unknown CPLEX basis status";
657 LOG(
FATAL) <<
"Basis status only available for continuous problems";
661 if (CheckSolutionIsSynchronized()) {
663 CPXDIM
const rows = CPXXgetnumrows(mEnv, mLp);
664 unique_ptr<int[]> data(
new int[rows]);
666 CHECK_STATUS(CPXXgetbase(mEnv, mLp, 0, mRstat.get()));
672 return xformBasisStatus(mRstat[constraint_index]);
674 LOG(
FATAL) <<
"Row basis status not available";
682 LOG(
FATAL) <<
"Basis status only available for continuous problems";
686 if (CheckSolutionIsSynchronized()) {
688 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
689 unique_ptr<int[]> data(
new int[cols]);
691 CHECK_STATUS(CPXXgetbase(mEnv, mLp, mCstat.get(), 0));
697 return xformBasisStatus(mCstat[variable_index]);
699 LOG(
FATAL) <<
"Column basis status not available";
705 void CplexInterface::ExtractNewVariables() {
709 InvalidateSolutionSynchronization();
711 if (!supportIncrementalExtraction) {
714 CHECK(last_variable_index_ == 0 ||
715 last_variable_index_ == solver_->variables_.size());
716 CHECK(last_constraint_index_ == 0 ||
717 last_constraint_index_ == solver_->constraints_.size());
720 int const last_extracted = last_variable_index_;
721 int const var_count = solver_->variables_.size();
722 CPXDIM newcols = var_count - last_extracted;
726 unique_ptr<double[]> obj(
new double[newcols]);
727 unique_ptr<double[]> lb(
new double[newcols]);
728 unique_ptr<double[]> ub(
new double[newcols]);
729 unique_ptr<char[]> ctype(
new char[newcols]);
730 unique_ptr<const char*[]> colname(
new const char*[newcols]);
732 bool have_names =
false;
733 for (
int j = 0, varidx = last_extracted; j < newcols; ++j, ++varidx) {
734 MPVariable
const*
const var = solver_->variables_[varidx];
737 ctype[j] =
var->integer() ? CPX_INTEGER : CPX_CONTINUOUS;
739 have_names = have_names ||
var->
name().empty();
740 obj[j] = solver_->objective_->GetCoefficient(
var);
748 std::vector<MPVariable*>
const& variables = solver_->variables();
749 for (
int j = last_extracted; j < var_count; ++j) {
750 CHECK(!variable_is_extracted(variables[j]->
index()));
751 set_variable_as_extracted(variables[j]->
index(),
true);
755 bool use_newcols =
true;
757 if (supportIncrementalExtraction) {
766 unique_ptr<CPXDIM[]> collen(
new CPXDIM[newcols]);
767 for (CPXDIM j = 0; j < newcols; ++j) collen[j] = 0;
771 for (
int i = 0; i < last_constraint_index_; ++i) {
772 MPConstraint
const*
const ct = solver_->constraints_[i];
773 CHECK(constraint_is_extracted(
ct->index()));
774 const auto& coeffs =
ct->coefficients_;
775 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
776 int const idx = it->first->index();
777 if (variable_is_extracted(idx) && idx > last_variable_index_) {
778 collen[idx - last_variable_index_]++;
789 unique_ptr<CPXNNZ[]> begin(
new CPXNNZ[newcols + 2]);
790 unique_ptr<CPXDIM[]> cmatind(
new CPXDIM[nonzeros]);
791 unique_ptr<double[]> cmatval(
new double[nonzeros]);
802 CPXNNZ* cmatbeg = begin.get();
806 for (CPXDIM j = 0; j < newcols; ++j)
807 cmatbeg[j + 1] = cmatbeg[j] + collen[j];
809 for (
int i = 0; i < last_constraint_index_; ++i) {
810 MPConstraint
const*
const ct = solver_->constraints_[i];
811 CPXDIM
const row =
ct->index();
812 const auto& coeffs =
ct->coefficients_;
813 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
814 int const idx = it->first->index();
815 if (variable_is_extracted(idx) && idx > last_variable_index_) {
816 CPXNNZ
const nz = cmatbeg[idx]++;
818 cmatval[nz] = it->second;
823 CHECK_STATUS(CPXXaddcols(mEnv, mLp, newcols, nonzeros, obj.get(),
824 cmatbeg, cmatind.get(), cmatval.get(),
826 have_names ? colname.get() : 0));
833 CHECK_STATUS(CPXXnewcols(mEnv, mLp, newcols, obj.get(), lb.get(),
834 ub.get(), mMip ? ctype.get() : 0,
835 have_names ? colname.get() : 0));
843 int const cols = CPXXgetnumcols(mEnv, mLp);
844 unique_ptr<CPXDIM[]> ind(
new CPXDIM[newcols]);
845 for (
int j = last_extracted; j < cols; ++j)
846 ind[j - last_extracted] = j;
847 CHECK_STATUS(CPXXchgctype(mEnv, mLp, cols - last_extracted, ind.get(),
853 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
854 if (cols > last_extracted)
855 (void)CPXXdelcols(mEnv, mLp, last_extracted, cols - 1);
856 std::vector<MPVariable*>
const& variables = solver_->variables();
857 int const size = variables.size();
858 for (
int j = last_extracted; j < size; ++j)
859 set_variable_as_extracted(j,
false);
866 void CplexInterface::ExtractNewConstraints() {
870 if (!supportIncrementalExtraction) {
873 CHECK(last_variable_index_ == 0 ||
874 last_variable_index_ == solver_->variables_.size());
875 CHECK(last_constraint_index_ == 0 ||
876 last_constraint_index_ == solver_->constraints_.size());
879 CPXDIM
const offset = last_constraint_index_;
880 CPXDIM
const total = solver_->constraints_.size();
882 if (total > offset) {
885 InvalidateSolutionSynchronization();
887 CPXDIM newCons = total - offset;
888 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
890 CPXDIM
const chunk = 10;
894 for (CPXDIM c = offset; c < total; ++c)
895 set_constraint_as_extracted(c,
true);
898 unique_ptr<CPXDIM[]> rmatind(
new CPXDIM[cols]);
899 unique_ptr<double[]> rmatval(
new double[cols]);
900 unique_ptr<CPXNNZ[]> rmatbeg(
new CPXNNZ[chunk]);
901 unique_ptr<char[]> sense(
new char[chunk]);
902 unique_ptr<double[]> rhs(
new double[chunk]);
903 unique_ptr<char const*[]>
name(
new char const*[chunk]);
904 unique_ptr<double[]> rngval(
new double[chunk]);
905 unique_ptr<CPXDIM[]> rngind(
new CPXDIM[chunk]);
906 bool haveRanges =
false;
911 for (CPXDIM c = 0; c < newCons; ) {
915 for (; c < newCons && nextRow < chunk; ++c, ++nextRow) {
916 MPConstraint
const*
const ct = solver_->constraints_[offset + c];
920 if (nextNz +
ct->coefficients_.size() > cols) {
926 MakeRhs(
ct->lb(),
ct->ub(), rhs[nextRow], sense[nextRow],
928 haveRanges = haveRanges || (rngval[nextRow] != 0.0);
929 rngind[nextRow] = offset + c;
932 rmatbeg[nextRow] = nextNz;
933 const auto& coeffs =
ct->coefficients_;
934 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
935 CPXDIM
const idx = it->first->index();
936 if (variable_is_extracted(idx)) {
939 rmatind[nextNz] = idx;
940 rmatval[nextNz] = it->second;
949 CHECK_STATUS(CPXXaddrows(mEnv, mLp, 0, nextRow, nextNz, rhs.get(),
950 sense.get(), rmatbeg.get(), rmatind.get(),
951 rmatval.get(), 0,
name.get()));
954 CPXXchgrngval(mEnv, mLp, nextRow, rngind.get(), rngval.get()));
960 CPXDIM
const rows = CPXXgetnumrows(mEnv, mLp);
961 if (rows > offset) (void)CPXXdelrows(mEnv, mLp, offset, rows - 1);
962 std::vector<MPConstraint*>
const& constraints = solver_->
constraints();
963 int const size = constraints.size();
964 for (
int i = offset; i < size; ++i) set_constraint_as_extracted(i,
false);
971 void CplexInterface::ExtractObjective() {
975 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
978 unique_ptr<CPXDIM[]> ind(
new CPXDIM[cols]);
979 unique_ptr<double[]> val(
new double[cols]);
980 for (CPXDIM j = 0; j < cols; ++j) {
985 const auto& coeffs = solver_->objective_->coefficients_;
986 for (
auto it = coeffs.begin(); it != coeffs.end(); ++it) {
987 CPXDIM
const idx = it->first->index();
988 if (variable_is_extracted(idx)) {
990 val[idx] = it->second;
994 CHECK_STATUS(CPXXchgobj(mEnv, mLp, cols, ind.get(), val.get()));
995 CHECK_STATUS(CPXEsetobjoffset(mEnv, mLp, solver_->Objective().offset()));
1000 void CplexInterface::SetParameters(
const MPSolverParameters& param) {
1001 SetCommonParameters(param);
1002 if (mMip) SetMIPParameters(param);
1005 void CplexInterface::SetRelativeMipGap(
double value) {
1007 CHECK_STATUS(CPXXsetdblparam(mEnv, CPX_PARAM_EPGAP,
value));
1009 LOG(
WARNING) <<
"The relative MIP gap is only available "
1010 <<
"for discrete problems.";
1014 void CplexInterface::SetPrimalTolerance(
double value) {
1015 CHECK_STATUS(CPXXsetdblparam(mEnv, CPX_PARAM_EPRHS,
value));
1018 void CplexInterface::SetDualTolerance(
double value) {
1019 CHECK_STATUS(CPXXsetdblparam(mEnv, CPX_PARAM_EPOPT,
value));
1022 void CplexInterface::SetPresolveMode(
int value) {
1028 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_OFF));
1031 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_ON));
1038 void CplexInterface::SetScalingMode(
int value) {
1044 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, -1));
1049 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, 0));
1056 void CplexInterface::SetLpAlgorithm(
int value) {
1060 int alg = CPX_ALG_NONE;
1062 switch (algorithm) {
1067 alg = CPX_ALG_PRIMAL;
1070 alg = CPX_ALG_BARRIER;
1074 if (alg == CPX_ALG_NONE)
1077 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_LPMETHOD, alg));
1081 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_STARTALG, alg));
1082 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SUBALG, alg));
1087 bool CplexInterface::ReadParameterFile(std::string
const& filename) {
1089 return CPXXreadcopyparam(mEnv, filename.c_str()) == 0;
1092 std::string CplexInterface::ValidFileExtensionForParameterFile()
const {
1114 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_ADVIND, 0));
1117 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_ADVIND, 2));
1126 if (!supportIncrementalExtraction && sync_status_ == MUST_RELOAD) Reset();
1128 VLOG(1) << absl::StrFormat(
"Model build in %.3f seconds.", timer.
Get());
1132 CPXXsetintparam(mEnv, CPX_PARAM_SCRIND, quiet() ? CPX_OFF : CPX_ON));
1139 solver_->SetSolverSpecificParametersAsString(
1140 solver_->solver_specific_parameter_string_);
1141 SetParameters(param);
1142 if (solver_->time_limit()) {
1143 VLOG(1) <<
"Setting time limit = " << solver_->time_limit() <<
" ms.";
1145 CPXXsetdblparam(mEnv, CPX_PARAM_TILIM, solver_->time_limit() * 1e-3));
1153 status = CPXXmipopt(mEnv, mLp);
1155 status = CPXXlpopt(mEnv, mLp);
1159 (void)CPXXsetintparam(mEnv, CPX_PARAM_SCRIND, CPX_OFF);
1162 VLOG(1) << absl::StrFormat(
"Failed to optimize MIP. Error %d", status);
1166 VLOG(1) << absl::StrFormat(
"Solved in %.3f seconds.", timer.
Get());
1169 int const cpxstat = CPXXgetstat(mEnv, mLp);
1170 VLOG(1) << absl::StrFormat(
"CPLEX solution status %d.", cpxstat);
1173 int solnmethod, solntype, pfeas, dfeas;
1174 CHECK_STATUS(CPXXsolninfo(mEnv, mLp, &solnmethod, &solntype, &pfeas, &dfeas));
1175 bool const feasible = pfeas != 0;
1178 CPXDIM
const rows = CPXXgetnumrows(mEnv, mLp);
1179 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
1180 DCHECK_EQ(rows, solver_->constraints_.size());
1181 DCHECK_EQ(cols, solver_->variables_.size());
1184 objective_value_ = CPX_NAN;
1185 if (pfeas) CHECK_STATUS(CPXXgetobjval(mEnv, mLp, &objective_value_));
1186 VLOG(1) <<
"objective = " << objective_value_;
1193 unique_ptr<double[]> x(
new double[cols]);
1194 CHECK_STATUS(CPXXgetx(mEnv, mLp, x.get(), 0, cols - 1));
1195 for (
int i = 0; i < solver_->variables_.size(); ++i) {
1196 MPVariable*
const var = solver_->variables_[i];
1197 var->set_solution_value(x[i]);
1202 for (
int i = 0; i < solver_->variables_.size(); ++i)
1203 solver_->variables_[i]->set_solution_value(CPX_NAN);
1207 for (
int i = 0; i < solver_->variables_.size(); ++i)
1208 solver_->variables_[i]->set_reduced_cost(CPX_NAN);
1209 for (
int i = 0; i < solver_->constraints_.size(); ++i)
1210 solver_->constraints_[i]->set_dual_value(CPX_NAN);
1214 unique_ptr<double[]> x(
new double[cols]);
1215 unique_ptr<double[]> dj(
new double[cols]);
1216 if (pfeas) CHECK_STATUS(CPXXgetx(mEnv, mLp, x.get(), 0, cols - 1));
1217 if (dfeas) CHECK_STATUS(CPXXgetdj(mEnv, mLp, dj.get(), 0, cols - 1));
1218 for (
int i = 0; i < solver_->variables_.size(); ++i) {
1219 MPVariable*
const var = solver_->variables_[i];
1220 var->set_solution_value(x[i]);
1221 bool value =
false, dual =
false;
1224 var->set_solution_value(x[i]);
1227 var->set_solution_value(CPX_NAN);
1229 var->set_reduced_cost(dj[i]);
1232 var->set_reduced_cost(CPX_NAN);
1234 << (
value ? absl::StrFormat(
" value = %f", x[i]) :
"")
1235 << (dual ?
absl::StrFormat(
" reduced cost = %f", dj[i]) :
"");
1240 unique_ptr<double[]> pi(
new double[rows]);
1241 if (dfeas) CHECK_STATUS(CPXXgetpi(mEnv, mLp, pi.get(), 0, rows - 1));
1242 for (
int i = 0; i < solver_->constraints_.size(); ++i) {
1243 MPConstraint*
const ct = solver_->constraints_[i];
1246 ct->set_dual_value(pi[i]);
1249 ct->set_dual_value(CPX_NAN);
1250 VLOG(4) <<
"row " <<
ct->index() <<
":"
1251 << (dual ? absl::StrFormat(
" dual = %f", pi[i]) :
"");
1258 case CPX_STAT_OPTIMAL:
1259 case CPXMIP_OPTIMAL:
1262 case CPXMIP_OPTIMAL_TOL:
1266 case CPX_STAT_INFEASIBLE:
1267 case CPXMIP_INFEASIBLE:
1270 case CPX_STAT_UNBOUNDED:
1271 case CPXMIP_UNBOUNDED:
1274 case CPX_STAT_INForUNBD:
1275 case CPXMIP_INForUNBD:
1283 sync_status_ = SOLUTION_SYNCHRONIZED;
1284 return result_status_;
1287 MPSolverInterface* BuildCplexInterface(
bool mip, MPSolver*
const solver) {
1288 return new CplexInterface(solver, mip);
1292 #endif // #if defined(USE_CPLEX)