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_t iterations()
const;
102 virtual int64_t
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_t CplexInterface::iterations()
const {
597 if (!CheckSolutionIsSynchronized())
return kUnknownNumberOfIterations;
599 return static_cast<int64_t>(CPXXgetmipitcnt(mEnv, mLp));
601 return static_cast<int64_t>(CPXXgetitcnt(mEnv, mLp));
606 if (!CheckSolutionIsSynchronized())
return kUnknownNumberOfNodes;
607 return static_cast<int64_t>(CPXXgetnodecnt(mEnv, mLp));
609 LOG(DFATAL) <<
"Number of nodes only available for discrete problems";
610 return kUnknownNumberOfNodes;
616 switch (cplex_basis_status) {
626 LOG(DFATAL) <<
"Unknown CPLEX basis status";
634 LOG(
FATAL) <<
"Basis status only available for continuous problems";
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";
659 LOG(
FATAL) <<
"Basis status only available for continuous problems";
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";
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) {
1001 static_cast<MPSolverParameters::PresolveValues>(
value);
1005 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_OFF));
1008 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_ON));
1015 void CplexInterface::SetScalingMode(
int value) {
1017 static_cast<MPSolverParameters::ScalingValues>(
value);
1021 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, -1));
1026 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, 0));
1033 void CplexInterface::SetLpAlgorithm(
int value) {
1035 static_cast<MPSolverParameters::LpAlgorithmValues>(
value);
1037 int alg = CPX_ALG_NONE;
1039 switch (algorithm) {
1044 alg = CPX_ALG_PRIMAL;
1047 alg = CPX_ALG_BARRIER;
1051 if (alg == CPX_ALG_NONE)
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 {
1085 static_cast<MPSolverParameters::IncrementalityValues>(
1091 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_ADVIND, 0));
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:
1246 case CPXMIP_OPTIMAL_TOL:
1250 case CPX_STAT_INFEASIBLE:
1251 case CPXMIP_INFEASIBLE:
1254 case CPX_STAT_UNBOUNDED:
1255 case CPXMIP_UNBOUNDED:
1258 case CPX_STAT_INForUNBD:
1259 case CPXMIP_INForUNBD:
1267 sync_status_ = SOLUTION_SYNCHRONIZED;
1268 return result_status_;
1271 MPSolverInterface* BuildCplexInterface(
bool mip, MPSolver*
const solver) {
1272 return new CplexInterface(solver, mip);
1276 #endif // #if defined(USE_CPLEX) ResultStatus
The status of solving the problem.
Advanced usage: incrementality from one solve to the next.
ScalingValues
Advanced usage: Scaling options.
#define VLOG(verboselevel)
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.
Advanced usage: presolve mode.
#define DCHECK_GT(val1, val2)
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
LpAlgorithmValues
LP algorithm to use.
feasible, or stopped by limit.
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
#define DCHECK_LE(val1, val2)
Reuse results from previous solve as much as the underlying solver allows.
IncrementalityValues
Advanced usage: Incrementality options.
Collection of objects used to extend the Constraint Solver library.
abnormal, i.e., error of some kind.
Start solve from scratch.
Algorithm to solve linear programs.
PresolveValues
For each categorical parameter, enumeration of possible values.
#define DCHECK_LT(val1, val2)