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;
114 virtual bool IsContinuous()
const {
return IsLP(); }
115 virtual bool IsLP()
const {
return !mMip; }
116 virtual bool IsMIP()
const {
return mMip; }
118 virtual void ExtractNewVariables();
119 virtual void ExtractNewConstraints();
120 virtual void ExtractObjective();
122 virtual std::string SolverVersion()
const;
124 virtual void* underlying_solver() {
return reinterpret_cast<void*
>(mLp); }
126 virtual double ComputeExactConditionNumber()
const {
127 if (!IsContinuous()) {
128 LOG(DFATAL) <<
"ComputeExactConditionNumber not implemented for"
129 <<
" CPLEX_MIXED_INTEGER_PROGRAMMING";
133 if (CheckSolutionIsSynchronized()) {
134 double kappa = CPX_NAN;
135 CHECK_STATUS(CPXXgetdblquality(mEnv, mLp, &kappa, CPX_EXACT_KAPPA));
138 LOG(DFATAL) <<
"Cannot get exact condition number without solution";
144 virtual void SetParameters(MPSolverParameters
const& param);
146 virtual void SetRelativeMipGap(
double value);
147 virtual void SetPrimalTolerance(
double value);
148 virtual void SetDualTolerance(
double value);
149 virtual void SetPresolveMode(
int value);
150 virtual void SetScalingMode(
int value);
151 virtual void SetLpAlgorithm(
int value);
153 virtual bool ReadParameterFile(std::string
const& filename);
154 virtual std::string ValidFileExtensionForParameterFile()
const;
160 void InvalidateModelSynchronization() {
163 sync_status_ = MUST_RELOAD;
184 bool const supportIncrementalExtraction;
192 SlowSetCoefficient = 0x0001,
193 SlowClearConstraint = 0x0002,
194 SlowSetObjectiveCoefficient = 0x0004,
195 SlowClearObjective = 0x0008,
196 SlowSetConstraintBounds = 0x0010,
197 SlowSetVariableInteger = 0x0020,
198 SlowSetVariableBounds = 0x0040,
199 SlowUpdatesAll = 0xffff
205 unique_ptr<int[]>
mutable mCstat;
206 unique_ptr<int[]>
mutable mRstat;
209 static void MakeRhs(
double lb,
double ub,
double& rhs,
char& sense,
214 CplexInterface::CplexInterface(MPSolver*
const solver,
bool mip)
215 : MPSolverInterface(solver),
219 slowUpdates(static_cast<SlowUpdates>(SlowSetObjectiveCoefficient |
220 SlowClearObjective)),
221 supportIncrementalExtraction(false),
226 mEnv = CPXXopenCPLEX(&status);
227 CHECK_STATUS(status);
230 char const*
name = solver_->name_.c_str();
231 mLp = CPXXcreateprob(mEnv, &status,
name);
232 CHECK_STATUS(status);
235 CHECK_STATUS(CPXXchgobjsen(mEnv, mLp,
maximize_ ? CPX_MAX : CPX_MIN));
236 if (mMip) CHECK_STATUS(CPXXchgprobtype(mEnv, mLp, CPXPROB_MILP));
239 CplexInterface::~CplexInterface() {
240 CHECK_STATUS(CPXXfreeprob(mEnv, &mLp));
241 CHECK_STATUS(CPXXcloseCPLEX(&mEnv));
244 std::string CplexInterface::SolverVersion()
const {
248 CHECK_STATUS(CPXXversionnumber(mEnv, &version));
250 int const major = version / 1000000;
251 version -= major * 1000000;
252 int const release = version / 10000;
253 version -= release * 10000;
254 int const mod = version / 100;
255 version -= mod * 100;
256 int const fix = version;
258 return absl::StrFormat(
"CPLEX library version %d.%02d.%02d.%02d", major,
264 void CplexInterface::Reset() {
267 CHECK_STATUS(CPXXfreeprob(mEnv, &mLp));
270 const char*
const name = solver_->name_.c_str();
271 mLp = CPXXcreateprob(mEnv, &status,
name);
272 CHECK_STATUS(status);
275 CHECK_STATUS(CPXXchgobjsen(mEnv, mLp,
maximize_ ? CPX_MAX : CPX_MIN));
276 if (mMip) CHECK_STATUS(CPXXchgprobtype(mEnv, mLp, CPXPROB_MILP));
278 ResetExtractionInformation();
283 void CplexInterface::SetOptimizationDirection(
bool maximize) {
284 InvalidateSolutionSynchronization();
285 CPXXchgobjsen(mEnv, mLp, maximize ? CPX_MAX : CPX_MIN);
288 void CplexInterface::SetVariableBounds(
int var_index,
double lb,
double ub) {
289 InvalidateSolutionSynchronization();
297 if (!supportIncrementalExtraction && !(slowUpdates & SlowSetVariableBounds)) {
298 InvalidateModelSynchronization();
300 if (variable_is_extracted(var_index)) {
303 DCHECK_LT(var_index, last_variable_index_);
304 char const lu[2] = {
'L',
'U'};
305 double const bd[2] = {lb, ub};
306 CPXDIM
const idx[2] = {var_index, var_index};
307 CHECK_STATUS(CPXXchgbds(mEnv, mLp, 2, idx, lu, bd));
311 InvalidateModelSynchronization();
317 void CplexInterface::SetVariableInteger(
int var_index,
bool integer) {
318 InvalidateSolutionSynchronization();
330 if (!supportIncrementalExtraction &&
331 !(slowUpdates && SlowSetVariableInteger)) {
332 InvalidateModelSynchronization();
335 if (variable_is_extracted(var_index)) {
339 DCHECK_LE(var_index, CPXXgetnumcols(mEnv, mLp));
340 char const type = integer ? CPX_INTEGER : CPX_CONTINUOUS;
341 CHECK_STATUS(CPXXchgctype(mEnv, mLp, 1, &var_index, &type));
343 InvalidateModelSynchronization();
346 <<
"Attempt to change variable to integer in non-MIP problem!";
352 void CplexInterface::MakeRhs(
double lb,
double ub,
double& rhs,
char& sense,
359 }
else if (lb > -CPX_INFBOUND && ub < CPX_INFBOUND) {
374 CHECK_STATUS(CPXERR_BAD_ARGUMENT);
379 }
else if (ub < CPX_INFBOUND ||
380 (std::abs(ub) == CPX_INFBOUND && std::abs(lb) > CPX_INFBOUND)) {
385 }
else if (lb > -CPX_INFBOUND ||
386 (std::abs(lb) == CPX_INFBOUND && std::abs(ub) > CPX_INFBOUND)) {
402 if (std::abs(lb) > std::abs(ub)) {
403 rhs = (lb < 0) ? -CPX_INFBOUND : CPX_INFBOUND;
406 rhs = (ub < 0) ? -CPX_INFBOUND : CPX_INFBOUND;
413 void CplexInterface::SetConstraintBounds(
int index,
double lb,
double ub) {
414 InvalidateSolutionSynchronization();
422 if (!supportIncrementalExtraction &&
423 !(slowUpdates & SlowSetConstraintBounds)) {
424 InvalidateModelSynchronization();
426 if (constraint_is_extracted(
index)) {
432 MakeRhs(lb, ub, rhs, sense, range);
433 CHECK_STATUS(CPXXchgrhs(mEnv, mLp, 1, &
index, &lb));
434 CHECK_STATUS(CPXXchgsense(mEnv, mLp, 1, &
index, &sense));
435 CHECK_STATUS(CPXXchgrngval(mEnv, mLp, 1, &
index, &range));
439 InvalidateModelSynchronization();
444 void CplexInterface::AddRowConstraint(MPConstraint*
const ct) {
451 InvalidateModelSynchronization();
454 void CplexInterface::AddVariable(MPVariable*
const ct) {
461 InvalidateModelSynchronization();
464 void CplexInterface::SetCoefficient(MPConstraint*
const constraint,
465 MPVariable
const*
const variable,
466 double new_value,
double) {
467 InvalidateSolutionSynchronization();
476 if (!supportIncrementalExtraction && !(slowUpdates & SlowSetCoefficient)) {
477 InvalidateModelSynchronization();
479 int const row = constraint->index();
480 int const col = variable->index();
481 if (constraint_is_extracted(
row) && variable_is_extracted(
col)) {
486 CHECK_STATUS(CPXXchgcoef(mEnv, mLp,
row,
col, new_value));
490 InvalidateModelSynchronization();
495 void CplexInterface::ClearConstraint(MPConstraint*
const constraint) {
496 CPXDIM
const row = constraint->index();
497 if (!constraint_is_extracted(
row))
509 if (!(slowUpdates & SlowClearConstraint)) {
510 InvalidateModelSynchronization();
512 InvalidateSolutionSynchronization();
514 CPXDIM
const len = constraint->coefficients_.size();
515 unique_ptr<CPXDIM[]> rowind(
new CPXDIM[len]);
516 unique_ptr<CPXDIM[]> colind(
new CPXDIM[len]);
517 unique_ptr<double[]> val(
new double[len]);
519 const auto& coeffs = constraint->coefficients_;
520 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
521 CPXDIM
const col = it->first->index();
522 if (variable_is_extracted(
col)) {
531 CPXXchgcoeflist(mEnv, mLp, j, rowind.get(), colind.get(), val.get()));
535 void CplexInterface::SetObjectiveCoefficient(MPVariable
const*
const variable,
537 CPXDIM
const col = variable->index();
538 if (!variable_is_extracted(
col))
542 InvalidateSolutionSynchronization();
550 if (supportIncrementalExtraction ||
551 (slowUpdates & SlowSetObjectiveCoefficient)) {
554 InvalidateModelSynchronization();
557 void CplexInterface::SetObjectiveOffset(
double value) {
559 InvalidateSolutionSynchronization();
560 CHECK_STATUS(CPXEsetobjoffset(mEnv, mLp,
value));
563 void CplexInterface::ClearObjective() {
564 InvalidateSolutionSynchronization();
571 if (supportIncrementalExtraction || (slowUpdates & SlowClearObjective)) {
572 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
573 unique_ptr<CPXDIM[]> ind(
new CPXDIM[cols]);
574 unique_ptr<double[]> zero(
new double[cols]);
576 const auto& coeffs = solver_->objective_->coefficients_;
577 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
578 CPXDIM
const idx = it->first->index();
580 if (variable_is_extracted(idx)) {
587 if (j > 0) CHECK_STATUS(CPXXchgobj(mEnv, mLp, j, ind.get(), zero.get()));
588 CHECK_STATUS(CPXEsetobjoffset(mEnv, mLp, 0.0));
590 InvalidateModelSynchronization();
595 int64 CplexInterface::iterations()
const {
597 if (!CheckSolutionIsSynchronized())
return kUnknownNumberOfIterations;
599 return static_cast<int64>(CPXXgetmipitcnt(mEnv, mLp));
601 return static_cast<int64>(CPXXgetitcnt(mEnv, mLp));
604 int64 CplexInterface::nodes()
const {
606 if (!CheckSolutionIsSynchronized())
return kUnknownNumberOfNodes;
607 return static_cast<int64>(CPXXgetnodecnt(mEnv, mLp));
609 LOG(DFATAL) <<
"Number of nodes only available for discrete problems";
610 return kUnknownNumberOfNodes;
615 MPSolver::BasisStatus CplexInterface::xformBasisStatus(
int cplex_basis_status) {
616 switch (cplex_basis_status) {
618 return MPSolver::AT_LOWER_BOUND;
620 return MPSolver::BASIC;
622 return MPSolver::AT_UPPER_BOUND;
624 return MPSolver::FREE;
626 LOG(DFATAL) <<
"Unknown CPLEX basis status";
627 return MPSolver::FREE;
632 MPSolver::BasisStatus CplexInterface::row_status(
int constraint_index)
const {
634 LOG(
FATAL) <<
"Basis status only available for continuous problems";
635 return MPSolver::FREE;
638 if (CheckSolutionIsSynchronized()) {
640 CPXDIM
const rows = CPXXgetnumrows(mEnv, mLp);
641 unique_ptr<int[]> data(
new int[rows]);
643 CHECK_STATUS(CPXXgetbase(mEnv, mLp, 0, mRstat.get()));
649 return xformBasisStatus(mRstat[constraint_index]);
651 LOG(
FATAL) <<
"Row basis status not available";
652 return MPSolver::FREE;
657 MPSolver::BasisStatus CplexInterface::column_status(
int variable_index)
const {
659 LOG(
FATAL) <<
"Basis status only available for continuous problems";
660 return MPSolver::FREE;
663 if (CheckSolutionIsSynchronized()) {
665 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
666 unique_ptr<int[]> data(
new int[cols]);
668 CHECK_STATUS(CPXXgetbase(mEnv, mLp, mCstat.get(), 0));
674 return xformBasisStatus(mCstat[variable_index]);
676 LOG(
FATAL) <<
"Column basis status not available";
677 return MPSolver::FREE;
682 void CplexInterface::ExtractNewVariables() {
686 InvalidateSolutionSynchronization();
688 if (!supportIncrementalExtraction) {
691 CHECK(last_variable_index_ == 0 ||
692 last_variable_index_ == solver_->variables_.size());
693 CHECK(last_constraint_index_ == 0 ||
694 last_constraint_index_ == solver_->constraints_.size());
697 int const last_extracted = last_variable_index_;
698 int const var_count = solver_->variables_.size();
699 CPXDIM newcols = var_count - last_extracted;
703 unique_ptr<double[]> obj(
new double[newcols]);
704 unique_ptr<double[]> lb(
new double[newcols]);
705 unique_ptr<double[]> ub(
new double[newcols]);
706 unique_ptr<char[]> ctype(
new char[newcols]);
707 unique_ptr<const char*[]> colname(
new const char*[newcols]);
709 bool have_names =
false;
710 for (
int j = 0, varidx = last_extracted; j < newcols; ++j, ++varidx) {
711 MPVariable
const*
const var = solver_->variables_[varidx];
714 ctype[j] =
var->integer() ? CPX_INTEGER : CPX_CONTINUOUS;
715 colname[j] =
var->name().empty() ? 0 :
var->name().c_str();
716 have_names = have_names ||
var->name().empty();
717 obj[j] = solver_->objective_->GetCoefficient(
var);
725 std::vector<MPVariable*>
const& variables = solver_->variables();
726 for (
int j = last_extracted; j < var_count; ++j) {
727 CHECK(!variable_is_extracted(variables[j]->
index()));
728 set_variable_as_extracted(variables[j]->
index(),
true);
732 bool use_newcols =
true;
734 if (supportIncrementalExtraction) {
743 unique_ptr<CPXDIM[]> collen(
new CPXDIM[newcols]);
744 for (CPXDIM j = 0; j < newcols; ++j) collen[j] = 0;
748 for (
int i = 0; i < last_constraint_index_; ++i) {
749 MPConstraint
const*
const ct = solver_->constraints_[i];
750 CHECK(constraint_is_extracted(
ct->index()));
751 const auto& coeffs =
ct->coefficients_;
752 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
753 int const idx = it->first->index();
754 if (variable_is_extracted(idx) && idx > last_variable_index_) {
755 collen[idx - last_variable_index_]++;
766 unique_ptr<CPXNNZ[]> begin(
new CPXNNZ[newcols + 2]);
767 unique_ptr<CPXDIM[]> cmatind(
new CPXDIM[nonzeros]);
768 unique_ptr<double[]> cmatval(
new double[nonzeros]);
779 CPXNNZ* cmatbeg = begin.get();
783 for (CPXDIM j = 0; j < newcols; ++j)
784 cmatbeg[j + 1] = cmatbeg[j] + collen[j];
786 for (
int i = 0; i < last_constraint_index_; ++i) {
787 MPConstraint
const*
const ct = solver_->constraints_[i];
788 CPXDIM
const row =
ct->index();
789 const auto& coeffs =
ct->coefficients_;
790 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
791 int const idx = it->first->index();
792 if (variable_is_extracted(idx) && idx > last_variable_index_) {
793 CPXNNZ
const nz = cmatbeg[idx]++;
795 cmatval[nz] = it->second;
800 CHECK_STATUS(CPXXaddcols(mEnv, mLp, newcols, nonzeros, obj.get(),
801 cmatbeg, cmatind.get(), cmatval.get(),
803 have_names ? colname.get() : 0));
810 CHECK_STATUS(CPXXnewcols(mEnv, mLp, newcols, obj.get(), lb.get(),
811 ub.get(), mMip ? ctype.get() : 0,
812 have_names ? colname.get() : 0));
820 int const cols = CPXXgetnumcols(mEnv, mLp);
821 unique_ptr<CPXDIM[]> ind(
new CPXDIM[newcols]);
822 for (
int j = last_extracted; j < cols; ++j)
823 ind[j - last_extracted] = j;
824 CHECK_STATUS(CPXXchgctype(mEnv, mLp, cols - last_extracted, ind.get(),
830 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
831 if (cols > last_extracted)
832 (void)CPXXdelcols(mEnv, mLp, last_extracted, cols - 1);
833 std::vector<MPVariable*>
const& variables = solver_->variables();
834 int const size = variables.size();
835 for (
int j = last_extracted; j < size; ++j)
836 set_variable_as_extracted(j,
false);
843 void CplexInterface::ExtractNewConstraints() {
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 CPXDIM
const offset = last_constraint_index_;
857 CPXDIM
const total = solver_->constraints_.size();
859 if (total > offset) {
862 InvalidateSolutionSynchronization();
864 CPXDIM newCons = total - offset;
865 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
867 CPXDIM
const chunk = 10;
871 for (CPXDIM c = offset; c < total; ++c)
872 set_constraint_as_extracted(c,
true);
875 unique_ptr<CPXDIM[]> rmatind(
new CPXDIM[cols]);
876 unique_ptr<double[]> rmatval(
new double[cols]);
877 unique_ptr<CPXNNZ[]> rmatbeg(
new CPXNNZ[chunk]);
878 unique_ptr<char[]> sense(
new char[chunk]);
879 unique_ptr<double[]> rhs(
new double[chunk]);
880 unique_ptr<char const*[]>
name(
new char const*[chunk]);
881 unique_ptr<double[]> rngval(
new double[chunk]);
882 unique_ptr<CPXDIM[]> rngind(
new CPXDIM[chunk]);
883 bool haveRanges =
false;
888 for (CPXDIM c = 0; c < newCons; ) {
892 for (; c < newCons && nextRow < chunk; ++c, ++nextRow) {
893 MPConstraint
const*
const ct = solver_->constraints_[offset + c];
897 if (nextNz +
ct->coefficients_.size() > cols) {
903 MakeRhs(
ct->lb(),
ct->ub(), rhs[nextRow], sense[nextRow],
905 haveRanges = haveRanges || (rngval[nextRow] != 0.0);
906 rngind[nextRow] = offset + c;
909 rmatbeg[nextRow] = nextNz;
910 const auto& coeffs =
ct->coefficients_;
911 for (
auto it(coeffs.begin()); it != coeffs.end(); ++it) {
912 CPXDIM
const idx = it->first->index();
913 if (variable_is_extracted(idx)) {
916 rmatind[nextNz] = idx;
917 rmatval[nextNz] = it->second;
923 name[nextRow] =
ct->name().empty() ? 0 :
ct->name().c_str();
926 CHECK_STATUS(CPXXaddrows(mEnv, mLp, 0, nextRow, nextNz, rhs.get(),
927 sense.get(), rmatbeg.get(), rmatind.get(),
928 rmatval.get(), 0,
name.get()));
931 CPXXchgrngval(mEnv, mLp, nextRow, rngind.get(), rngval.get()));
937 CPXDIM
const rows = CPXXgetnumrows(mEnv, mLp);
938 if (rows > offset) (void)CPXXdelrows(mEnv, mLp, offset, rows - 1);
939 std::vector<MPConstraint*>
const& constraints = solver_->constraints();
940 int const size = constraints.size();
941 for (
int i = offset; i < size; ++i) set_constraint_as_extracted(i,
false);
948 void CplexInterface::ExtractObjective() {
952 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
955 unique_ptr<CPXDIM[]> ind(
new CPXDIM[cols]);
956 unique_ptr<double[]> val(
new double[cols]);
957 for (CPXDIM j = 0; j < cols; ++j) {
962 const auto& coeffs = solver_->objective_->coefficients_;
963 for (
auto it = coeffs.begin(); it != coeffs.end(); ++it) {
964 CPXDIM
const idx = it->first->index();
965 if (variable_is_extracted(idx)) {
967 val[idx] = it->second;
971 CHECK_STATUS(CPXXchgobj(mEnv, mLp, cols, ind.get(), val.get()));
972 CHECK_STATUS(CPXEsetobjoffset(mEnv, mLp, solver_->Objective().offset()));
977 void CplexInterface::SetParameters(
const MPSolverParameters& param) {
978 SetCommonParameters(param);
979 if (mMip) SetMIPParameters(param);
982 void CplexInterface::SetRelativeMipGap(
double value) {
984 CHECK_STATUS(CPXXsetdblparam(mEnv, CPX_PARAM_EPGAP,
value));
986 LOG(
WARNING) <<
"The relative MIP gap is only available "
987 <<
"for discrete problems.";
991 void CplexInterface::SetPrimalTolerance(
double value) {
992 CHECK_STATUS(CPXXsetdblparam(mEnv, CPX_PARAM_EPRHS,
value));
995 void CplexInterface::SetDualTolerance(
double value) {
996 CHECK_STATUS(CPXXsetdblparam(mEnv, CPX_PARAM_EPOPT,
value));
999 void CplexInterface::SetPresolveMode(
int value) {
1000 MPSolverParameters::PresolveValues
const presolve =
1001 static_cast<MPSolverParameters::PresolveValues
>(
value);
1004 case MPSolverParameters::PRESOLVE_OFF:
1005 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_OFF));
1007 case MPSolverParameters::PRESOLVE_ON:
1008 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_ON));
1011 SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE,
value);
1015 void CplexInterface::SetScalingMode(
int value) {
1016 MPSolverParameters::ScalingValues
const scaling =
1017 static_cast<MPSolverParameters::ScalingValues
>(
value);
1020 case MPSolverParameters::SCALING_OFF:
1021 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, -1));
1023 case MPSolverParameters::SCALING_ON:
1026 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, 0));
1033 void CplexInterface::SetLpAlgorithm(
int value) {
1034 MPSolverParameters::LpAlgorithmValues
const algorithm =
1035 static_cast<MPSolverParameters::LpAlgorithmValues
>(
value);
1037 int alg = CPX_ALG_NONE;
1039 switch (algorithm) {
1040 case MPSolverParameters::DUAL:
1043 case MPSolverParameters::PRIMAL:
1044 alg = CPX_ALG_PRIMAL;
1046 case MPSolverParameters::BARRIER:
1047 alg = CPX_ALG_BARRIER;
1051 if (alg == CPX_ALG_NONE)
1052 SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM,
value);
1054 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_LPMETHOD, alg));
1058 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_STARTALG, alg));
1059 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SUBALG, alg));
1064 bool CplexInterface::ReadParameterFile(std::string
const& filename) {
1066 return CPXXreadcopyparam(mEnv, filename.c_str()) == 0;
1069 std::string CplexInterface::ValidFileExtensionForParameterFile()
const {
1084 MPSolverParameters::IncrementalityValues
const inc =
1085 static_cast<MPSolverParameters::IncrementalityValues
>(
1086 param.GetIntegerParam(MPSolverParameters::INCREMENTALITY));
1088 case MPSolverParameters::INCREMENTALITY_OFF:
1091 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_ADVIND, 0));
1093 case MPSolverParameters::INCREMENTALITY_ON:
1094 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_ADVIND, 2));
1103 if (!supportIncrementalExtraction && sync_status_ == MUST_RELOAD) Reset();
1105 VLOG(1) << absl::StrFormat(
"Model build in %.3f seconds.", timer.
Get());
1109 CPXXsetintparam(mEnv, CPX_PARAM_SCRIND, quiet() ? CPX_OFF : CPX_ON));
1116 solver_->SetSolverSpecificParametersAsString(
1117 solver_->solver_specific_parameter_string_);
1118 SetParameters(param);
1119 if (solver_->time_limit()) {
1120 VLOG(1) <<
"Setting time limit = " << solver_->time_limit() <<
" ms.";
1122 CPXXsetdblparam(mEnv, CPX_PARAM_TILIM, solver_->time_limit() * 1e-3));
1130 status = CPXXmipopt(mEnv, mLp);
1132 status = CPXXlpopt(mEnv, mLp);
1136 (void)CPXXsetintparam(mEnv, CPX_PARAM_SCRIND, CPX_OFF);
1139 VLOG(1) << absl::StrFormat(
"Failed to optimize MIP. Error %d", status);
1143 VLOG(1) << absl::StrFormat(
"Solved in %.3f seconds.", timer.
Get());
1146 int const cpxstat = CPXXgetstat(mEnv, mLp);
1147 VLOG(1) << absl::StrFormat(
"CPLEX solution status %d.", cpxstat);
1150 int solnmethod, solntype, pfeas, dfeas;
1151 CHECK_STATUS(CPXXsolninfo(mEnv, mLp, &solnmethod, &solntype, &pfeas, &dfeas));
1152 bool const feasible = pfeas != 0;
1155 CPXDIM
const rows = CPXXgetnumrows(mEnv, mLp);
1156 CPXDIM
const cols = CPXXgetnumcols(mEnv, mLp);
1157 DCHECK_EQ(rows, solver_->constraints_.size());
1158 DCHECK_EQ(cols, solver_->variables_.size());
1161 objective_value_ = CPX_NAN;
1162 best_objective_bound_ = CPX_NAN;
1164 CHECK_STATUS(CPXXgetobjval(mEnv, mLp, &objective_value_));
1166 CHECK_STATUS(CPXXgetbestobjval(mEnv, mLp, &best_objective_bound_));
1169 VLOG(1) <<
"objective=" << objective_value_
1170 <<
", bound=" << best_objective_bound_;
1177 unique_ptr<double[]> x(
new double[cols]);
1178 CHECK_STATUS(CPXXgetx(mEnv, mLp, x.get(), 0, cols - 1));
1179 for (
int i = 0; i < solver_->variables_.size(); ++i) {
1180 MPVariable*
const var = solver_->variables_[i];
1181 var->set_solution_value(x[i]);
1182 VLOG(3) <<
var->name() <<
": value =" << x[i];
1186 for (
int i = 0; i < solver_->variables_.size(); ++i)
1187 solver_->variables_[i]->set_solution_value(CPX_NAN);
1191 for (
int i = 0; i < solver_->variables_.size(); ++i)
1192 solver_->variables_[i]->set_reduced_cost(CPX_NAN);
1193 for (
int i = 0; i < solver_->constraints_.size(); ++i)
1194 solver_->constraints_[i]->set_dual_value(CPX_NAN);
1198 unique_ptr<double[]> x(
new double[cols]);
1199 unique_ptr<double[]> dj(
new double[cols]);
1200 if (feasible) CHECK_STATUS(CPXXgetx(mEnv, mLp, x.get(), 0, cols - 1));
1201 if (dfeas) CHECK_STATUS(CPXXgetdj(mEnv, mLp, dj.get(), 0, cols - 1));
1202 for (
int i = 0; i < solver_->variables_.size(); ++i) {
1203 MPVariable*
const var = solver_->variables_[i];
1204 var->set_solution_value(x[i]);
1205 bool value =
false, dual =
false;
1208 var->set_solution_value(x[i]);
1211 var->set_solution_value(CPX_NAN);
1213 var->set_reduced_cost(dj[i]);
1216 var->set_reduced_cost(CPX_NAN);
1218 << (
value ? absl::StrFormat(
" value = %f", x[i]) :
"")
1219 << (dual ?
absl::StrFormat(
" reduced cost = %f", dj[i]) :
"");
1224 unique_ptr<double[]> pi(
new double[rows]);
1225 if (dfeas) CHECK_STATUS(CPXXgetpi(mEnv, mLp, pi.get(), 0, rows - 1));
1226 for (
int i = 0; i < solver_->constraints_.size(); ++i) {
1227 MPConstraint*
const ct = solver_->constraints_[i];
1230 ct->set_dual_value(pi[i]);
1233 ct->set_dual_value(CPX_NAN);
1234 VLOG(4) <<
"row " <<
ct->index() <<
":"
1235 << (dual ? absl::StrFormat(
" dual = %f", pi[i]) :
"");
1242 case CPX_STAT_OPTIMAL:
1243 case CPXMIP_OPTIMAL:
1244 result_status_ = MPSolver::OPTIMAL;
1246 case CPXMIP_OPTIMAL_TOL:
1248 result_status_ = MPSolver::OPTIMAL;
1250 case CPX_STAT_INFEASIBLE:
1251 case CPXMIP_INFEASIBLE:
1252 result_status_ = MPSolver::INFEASIBLE;
1254 case CPX_STAT_UNBOUNDED:
1255 case CPXMIP_UNBOUNDED:
1256 result_status_ = MPSolver::UNBOUNDED;
1258 case CPX_STAT_INForUNBD:
1259 case CPXMIP_INForUNBD:
1260 result_status_ = MPSolver::INFEASIBLE;
1263 result_status_ = feasible ? MPSolver::FEASIBLE : MPSolver::ABNORMAL;
1267 sync_status_ = SOLUTION_SYNCHRONIZED;
1268 return result_status_;
1271 MPSolverInterface* BuildCplexInterface(
bool mip, MPSolver*
const solver) {
1272 return new CplexInterface(solver, mip);
#define DCHECK_LE(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
#define VLOG(verboselevel)
ResultStatus
The status of solving the problem.
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
CpSolverResponse Solve(const CpModelProto &model_proto)
Solves the given CpModelProto and returns an instance of CpSolverResponse.
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...