Google OR-Tools: ortools/linear_solver/cplex_interface.cc Source File

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15#include <cstdint>

16#include <limits>

17#include <memory>

18

19#include "absl/strings/str_format.h"

20#include "absl/strings/str_split.h"

24

25extern "C" {

26#include "ilcplex/cplexx.h"

27

28

29

30CPXLIBAPI int CPXPUBLIC CPXEsetobjoffset(CPXCENVptr, CPXLPptr, double);

31}

32

33

34

35#if !defined(CPX_NAN)

36#define CPX_NAN std::numeric_limits<double>::quiet_NaN()

37#endif

38

39

40

41

42#define CHECK_STATUS(s) \

43 do { \

44 int const status_ = s; \

45 CHECK_EQ(0, status_); \

46 } while (0)

47

49

50using std::unique_ptr;

51

52

53

54

55

56

58 public:

59

60

61

64

65

67

68

69

71

72

73

74 virtual void Reset();

75

76 virtual void SetVariableBounds(int var_index, double lb, double ub);

79

84 double new_value, double old_value);

85

86

88

90 double coefficient);

91

93

95

96

97

99

100 virtual int64_t nodes() const;

101

102

104

106

107

108

109

110

111

113 virtual bool IsLP() const { return !mMip; }

114 virtual bool IsMIP() const { return mMip; }

115

117 const std::string& parameters) override;

121

123

125

128 LOG(DFATAL) << "ComputeExactConditionNumber not implemented for"

129 << " CPLEX_MIXED_INTEGER_PROGRAMMING";

131 }

132

135 CHECK_STATUS(CPXXgetdblquality(mEnv, mLp, &kappa, CPX_EXACT_KAPPA));

136 return kappa;

137 }

138 LOG(DFATAL) << "Cannot get exact condition number without solution";

140 }

141

142 protected:

143

145

152

155

156 private:

157

158

159

160 void InvalidateModelSynchronization() {

161 mCstat = 0;

162 mRstat = 0;

164 }

165

166

168

169 private:

170 CPXLPptr mLp;

171 CPXENVptr mEnv;

172 bool const mMip;

173

174

175

176

177

178

179

180

181

182

183

184 bool const supportIncrementalExtraction;

185

186

187

188

189

190

191 enum SlowUpdates {

192 SlowSetCoefficient = 0x0001,

193 SlowClearConstraint = 0x0002,

194 SlowSetObjectiveCoefficient = 0x0004,

195 SlowClearObjective = 0x0008,

196 SlowSetConstraintBounds = 0x0010,

197 SlowSetVariableInteger = 0x0020,

198 SlowSetVariableBounds = 0x0040,

199 SlowUpdatesAll = 0xffff

200 } const slowUpdates;

201

202

203

204

205 unique_ptr<int[]> mutable mCstat;

206 unique_ptr<int[]> mutable mRstat;

207

208

209 static void MakeRhs(double lb, double ub, double& rhs, char& sense,

210 double& range);

211};

212

213

216 mEnv(0),

217 mLp(0),

218 mMip(mip),

219 slowUpdates(static_cast<SlowUpdates>(SlowSetObjectiveCoefficient |

220 SlowClearObjective)),

221 supportIncrementalExtraction(false),

222 mCstat(),

223 mRstat() {

224 int status;

225

226 mEnv = CPXXopenCPLEX(&status);

228 DCHECK(mEnv != nullptr);

229

230 char const* name = solver_->name_.c_str();

231 mLp = CPXXcreateprob(mEnv, &status, name);

233 DCHECK(mLp != nullptr);

234

236 if (mMip) CHECK_STATUS(CPXXchgprobtype(mEnv, mLp, CPXPROB_MILP));

237}

238

243

245

246

247 int version = 0;

248 CHECK_STATUS(CPXXversionnumber(mEnv, &version));

249

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;

257

258 return absl::StrFormat("CPLEX library version %d.%02d.%02d.%02d", major,

259 release, mod, fix);

260}

261

262

263

265

266

268

269 int status;

270 const char* const name = solver_->name_.c_str();

271 mLp = CPXXcreateprob(mEnv, &status, name);

273 DCHECK(mLp != nullptr);

274

276 if (mMip) CHECK_STATUS(CPXXchgprobtype(mEnv, mLp, CPXPROB_MILP));

277

279 mCstat = 0;

280 mRstat = 0;

281}

282

285 CPXXchgobjsen(mEnv, mLp, maximize ? CPX_MAX : CPX_MIN);

286}

287

290

291

292

293

294

295

296

297 if (!supportIncrementalExtraction && !(slowUpdates & SlowSetVariableBounds)) {

298 InvalidateModelSynchronization();

299 } else {

301

302

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));

308 } else {

309

310

311 InvalidateModelSynchronization();

312 }

313 }

314}

315

316

319

320

321

322

323

324

325

326

327

328

329

330 if (!supportIncrementalExtraction &&

331 !(slowUpdates && SlowSetVariableInteger)) {

332 InvalidateModelSynchronization();

333 } else {

334 if (mMip) {

336

337

338

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));

342 } else

343 InvalidateModelSynchronization();

344 } else {

345 LOG(DFATAL)

346 << "Attempt to change variable to integer in non-MIP problem!";

347 }

348 }

349}

350

351

352void CplexInterface::MakeRhs(double lb, double ub, double& rhs, char& sense,

353 double& range) {

354 if (lb == ub) {

355

356 rhs = lb;

357 range = 0.0;

358 sense = 'E';

359 } else if (lb > -CPX_INFBOUND && ub < CPX_INFBOUND) {

360

361

362

363

364 if (ub < lb) {

365

366

367

368

369

370

371

372

373

375 }

376 rhs = lb;

377 range = ub - lb;

378 sense = 'R';

379 } else if (ub < CPX_INFBOUND ||

380 (std::abs(ub) == CPX_INFBOUND && std::abs(lb) > CPX_INFBOUND)) {

381

382 rhs = ub;

383 range = 0.0;

384 sense = 'L';

385 } else if (lb > -CPX_INFBOUND ||

386 (std::abs(lb) == CPX_INFBOUND && std::abs(ub) > CPX_INFBOUND)) {

387

388 rhs = lb;

389 range = 0.0;

390 sense = 'G';

391 } else {

392

393

394

395

396

397

398

399

400 DCHECK_GT(std::abs(lb), CPX_INFBOUND);

401 DCHECK_GT(std::abs(ub), CPX_INFBOUND);

402 if (std::abs(lb) > std::abs(ub)) {

403 rhs = (lb < 0) ? -CPX_INFBOUND : CPX_INFBOUND;

404 sense = 'G';

405 } else {

406 rhs = (ub < 0) ? -CPX_INFBOUND : CPX_INFBOUND;

407 sense = 'L';

408 }

409 range = 0.0;

410 }

411}

412

415

416

417

418

419

420

421

422 if (!supportIncrementalExtraction &&

423 !(slowUpdates & SlowSetConstraintBounds)) {

424 InvalidateModelSynchronization();

425 } else {

427

428

429 DCHECK(mLp != NULL);

430 char sense;

431 double range, rhs;

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));

436 } else {

437

438

439 InvalidateModelSynchronization();

440 }

441 }

442}

443

445

446

447

448

449

450

451 InvalidateModelSynchronization();

452}

453

455

456

457

458

459

460

461 InvalidateModelSynchronization();

462}

463

466 double new_value, double) {

468

469

470

471

472

473

474

475

476 if (!supportIncrementalExtraction && !(slowUpdates & SlowSetCoefficient)) {

477 InvalidateModelSynchronization();

478 } else {

479 int const row = constraint->index();

480 int const col = variable->index();

482

483

486 CHECK_STATUS(CPXXchgcoef(mEnv, mLp, row, col, new_value));

487 } else {

488

489

490 InvalidateModelSynchronization();

491 }

492 }

493}

494

496 CPXDIM const row = constraint->index();

498

499 return;

500

501

502

503

504

505

506

507

508

509 if (!(slowUpdates & SlowClearConstraint)) {

510 InvalidateModelSynchronization();

511 } else {

513

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]);

518 CPXDIM j = 0;

519 const auto& coeffs = constraint->coefficients_;

520 for (auto it(coeffs.begin()); it != coeffs.end(); ++it) {

521 CPXDIM const col = it->first->index();

523 rowind[j] = row;

524 colind[j] = col;

525 val[j] = 0.0;

526 ++j;

527 }

528 }

529 if (j)

531 CPXXchgcoeflist(mEnv, mLp, j, rowind.get(), colind.get(), val.get()));

532 }

533}

534

536 double coefficient) {

537 CPXDIM const col = variable->index();

539

540 return;

541

543

544

545

546

547

548

549

550 if (supportIncrementalExtraction ||

551 (slowUpdates & SlowSetObjectiveCoefficient)) {

552 CHECK_STATUS(CPXXchgobj(mEnv, mLp, 1, &col, &coefficient));

553 } else

554 InvalidateModelSynchronization();

555}

556

562

565

566

567

568

569

570

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]);

575 CPXDIM j = 0;

576 const auto& coeffs = solver_->objective_->coefficients_;

577 for (auto it(coeffs.begin()); it != coeffs.end(); ++it) {

578 CPXDIM const idx = it->first->index();

579

581 DCHECK_LT(idx, cols);

582 ind[j] = idx;

583 zero[j] = 0.0;

584 ++j;

585 }

586 }

587 if (j > 0) CHECK_STATUS(CPXXchgobj(mEnv, mLp, j, ind.get(), zero.get()));

589 } else

590 InvalidateModelSynchronization();

591}

592

593

594

596 int iter;

598 if (mMip)

599 return static_cast<int64_t>(CPXXgetmipitcnt(mEnv, mLp));

600 else

601 return static_cast<int64_t>(CPXXgetitcnt(mEnv, mLp));

602}

603

605 if (mMip) {

607 return static_cast<int64_t>(CPXXgetnodecnt(mEnv, mLp));

608 } else {

609 LOG(DFATAL) << "Number of nodes only available for discrete problems";

611 }

612}

613

614

616 switch (cplex_basis_status) {

617 case CPX_AT_LOWER:

619 case CPX_BASIC:

621 case CPX_AT_UPPER:

623 case CPX_FREE_SUPER:

625 default:

626 LOG(DFATAL) << "Unknown CPLEX basis status";

628 }

629}

630

631

633 if (mMip) {

634 LOG(FATAL) << "Basis status only available for continuous problems";

636 }

637

639 if (!mRstat) {

640 CPXDIM const rows = CPXXgetnumrows(mEnv, mLp);

641 unique_ptr<int[]> data(new int[rows]);

642 mRstat.swap(data);

643 CHECK_STATUS(CPXXgetbase(mEnv, mLp, 0, mRstat.get()));

644 }

645 } else

646 mRstat = 0;

647

648 if (mRstat)

649 return xformBasisStatus(mRstat[constraint_index]);

650 else {

651 LOG(FATAL) << "Row basis status not available";

653 }

654}

655

656

658 if (mMip) {

659 LOG(FATAL) << "Basis status only available for continuous problems";

661 }

662

664 if (!mCstat) {

665 CPXDIM const cols = CPXXgetnumcols(mEnv, mLp);

666 unique_ptr<int[]> data(new int[cols]);

667 mCstat.swap(data);

668 CHECK_STATUS(CPXXgetbase(mEnv, mLp, mCstat.get(), 0));

669 }

670 } else

671 mCstat = 0;

672

673 if (mCstat)

674 return xformBasisStatus(mCstat[variable_index]);

675 else {

676 LOG(FATAL) << "Column basis status not available";

678 }

679}

680

681

683

684

685

687

688 if (!supportIncrementalExtraction) {

689

690

695 }

696

698 int const var_count = solver_->variables_.size();

699 CPXDIM newcols = var_count - last_extracted;

700 if (newcols > 0) {

701

702

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]);

708

709 bool have_names = false;

710 for (int j = 0, varidx = last_extracted; j < newcols; ++j, ++varidx) {

712 lb[j] = var->lb();

713 ub[j] = var->ub();

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);

718 }

719

720

721

722

723

724

725 std::vector<MPVariable*> const& variables = solver_->variables();

726 for (int j = last_extracted; j < var_count; ++j) {

729 }

730

731 try {

732 bool use_newcols = true;

733

734 if (supportIncrementalExtraction) {

735

736

737

738

739

740

741

742

743 unique_ptr<CPXDIM[]> collen(new CPXDIM[newcols]);

744 for (CPXDIM j = 0; j < newcols; ++j) collen[j] = 0;

745 CPXNNZ nonzeros = 0;

746

747

751 const auto& coeffs = ct->coefficients_;

752 for (auto it(coeffs.begin()); it != coeffs.end(); ++it) {

753 int const idx = it->first->index();

756 ++nonzeros;

757 }

758 }

759 }

760

761 if (nonzeros > 0) {

762

763

764

765 use_newcols = false;

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]);

769

770

771

772

773

774

775

776

777

778

779 CPXNNZ* cmatbeg = begin.get();

780 cmatbeg[0] = 0;

781 cmatbeg[1] = 0;

782 ++cmatbeg;

783 for (CPXDIM j = 0; j < newcols; ++j)

784 cmatbeg[j + 1] = cmatbeg[j] + collen[j];

785

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();

793 CPXNNZ const nz = cmatbeg[idx]++;

794 cmatind[nz] = idx;

795 cmatval[nz] = it->second;

796 }

797 }

798 }

799 --cmatbeg;

800 CHECK_STATUS(CPXXaddcols(mEnv, mLp, newcols, nonzeros, obj.get(),

801 cmatbeg, cmatind.get(), cmatval.get(),

802 lb.get(), ub.get(),

803 have_names ? colname.get() : 0));

804 }

805 }

806 if (use_newcols) {

807

808

809

810 CHECK_STATUS(CPXXnewcols(mEnv, mLp, newcols, obj.get(), lb.get(),

811 ub.get(), mMip ? ctype.get() : 0,

812 have_names ? colname.get() : 0));

813 } else {

814

815

816

817 if (mMip) {

818

819

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(),

825 ctype.get()));

826 }

827 }

828 } catch (...) {

829

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)

837 throw;

838 }

839 }

840}

841

842

844

845

846

847 if (!supportIncrementalExtraction) {

848

849

854 }

855

857 CPXDIM const total = solver_->constraints_.size();

858

859 if (total > offset) {

860

861

863

864 CPXDIM newCons = total - offset;

865 CPXDIM const cols = CPXXgetnumcols(mEnv, mLp);

867 CPXDIM const chunk = 10;

868

869

870

871 for (CPXDIM c = offset; c < total; ++c)

873

874 try {

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;

884

885

886

887

888 for (CPXDIM c = 0; c < newCons; ) {

889

890 CPXDIM nextRow = 0;

891 CPXNNZ nextNz = 0;

892 for (; c < newCons && nextRow < chunk; ++c, ++nextRow) {

894

895

896

897 if (nextNz + ct->coefficients_.size() > cols) {

898 DCHECK_GT(nextRow, 0);

899 break;

900 }

901

902

903 MakeRhs(ct->lb(), ct->ub(), rhs[nextRow], sense[nextRow],

904 rngval[nextRow]);

905 haveRanges = haveRanges || (rngval[nextRow] != 0.0);

906 rngind[nextRow] = offset + c;

907

908

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();

914 DCHECK_LT(nextNz, cols);

915 DCHECK_LT(idx, cols);

916 rmatind[nextNz] = idx;

917 rmatval[nextNz] = it->second;

918 ++nextNz;

919 }

920 }

921

922

923 name[nextRow] = ct->name().empty() ? 0 : ct->name().c_str();

924 }

925 if (nextRow > 0) {

926 CHECK_STATUS(CPXXaddrows(mEnv, mLp, 0, nextRow, nextNz, rhs.get(),

927 sense.get(), rmatbeg.get(), rmatind.get(),

928 rmatval.get(), 0, name.get()));

929 if (haveRanges) {

931 CPXXchgrngval(mEnv, mLp, nextRow, rngind.get(), rngval.get()));

932 }

933 }

934 }

935 } catch (...) {

936

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();

942 throw;

943 }

944 }

945}

946

947

949

950

951

952 CPXDIM const cols = CPXXgetnumcols(mEnv, mLp);

954

955 unique_ptr<CPXDIM[]> ind(new CPXDIM[cols]);

956 unique_ptr<double[]> val(new double[cols]);

957 for (CPXDIM j = 0; j < cols; ++j) {

958 ind[j] = j;

959 val[j] = 0.0;

960 }

961

962 const auto& coeffs = solver_->objective_->coefficients_;

963 for (auto it = coeffs.begin(); it != coeffs.end(); ++it) {

964 CPXDIM const idx = it->first->index();

966 DCHECK_LT(idx, cols);

967 val[idx] = it->second;

968 }

969 }

970

971 CHECK_STATUS(CPXXchgobj(mEnv, mLp, cols, ind.get(), val.get()));

973}

974

975

976

981

983 if (mMip) {

984 CHECK_STATUS(CPXXsetdblparam(mEnv, CPX_PARAM_EPGAP, value));

985 } else {

986 LOG(WARNING) << "The relative MIP gap is only available "

987 << "for discrete problems.";

988 }

989}

990

992 CHECK_STATUS(CPXXsetdblparam(mEnv, CPX_PARAM_EPRHS, value));

993}

994

996 CHECK_STATUS(CPXXsetdblparam(mEnv, CPX_PARAM_EPOPT, value));

997}

998

1002

1003 switch (presolve) {

1005 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_OFF));

1006 return;

1008 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_PREIND, CPX_ON));

1009 return;

1010 }

1012}

1013

1014

1018

1019 switch (scaling) {

1021 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, -1));

1022 break;

1024

1025

1026 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SCAIND, 0));

1027 break;

1028 }

1029}

1030

1031

1032

1036

1037 int alg = CPX_ALG_NONE;

1038

1039 switch (algorithm) {

1041 alg = CPX_ALG_DUAL;

1042 break;

1044 alg = CPX_ALG_PRIMAL;

1045 break;

1047 alg = CPX_ALG_BARRIER;

1048 break;

1049 }

1050

1051 if (alg == CPX_ALG_NONE)

1053 else {

1054 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_LPMETHOD, alg));

1055 if (mMip) {

1056

1057

1058 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_STARTALG, alg));

1059 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_SUBALG, alg));

1060 }

1061 }

1062}

1063

1065

1066 return CPXXreadcopyparam(mEnv, filename.c_str()) == 0;

1067}

1068

1070 return ".prm";

1071}

1072

1074 int status;

1075

1076

1077 mCstat = 0;

1078 mRstat = 0;

1079

1082

1083

1087 switch (inc) {

1089 Reset();

1090

1091 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_ADVIND, 0));

1092 break;

1094 CHECK_STATUS(CPXXsetintparam(mEnv, CPX_PARAM_ADVIND, 2));

1095 break;

1096 }

1097

1098

1099

1100

1101

1102

1105 VLOG(1) << absl::StrFormat("Model build in %.3f seconds.", timer.Get());

1106

1107

1109 CPXXsetintparam(mEnv, CPX_PARAM_SCRIND, quiet() ? CPX_OFF : CPX_ON));

1110

1111 if (!solver_->solution_hint_.empty()) {

1112 int const sol_count = solver_->solution_hint_.size();

1113 long long int beg[1] = {0};

1114 int* varindices = new int[sol_count];

1115 double* values = new double[sol_count];

1116

1117 for (int i = 0; i < sol_count; ++i) {

1118 varindices[i] = solver_->solution_hint_[i].first->index();

1119 values[i] = solver_->solution_hint_[i].second;

1120 }

1121 CPXXaddmipstarts(mEnv, mLp, 1, sol_count, beg, varindices, values, NULL,

1122 NULL);

1123 }

1124

1125

1126

1127

1128

1129 solver_->SetSolverSpecificParametersAsString(

1130 solver_->solver_specific_parameter_string_);

1132 if (solver_->time_limit()) {

1133 VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";

1135 CPXXsetdblparam(mEnv, CPX_PARAM_TILIM, solver_->time_limit() * 1e-3));

1136 }

1137

1138

1139

1140

1142 if (mMip) {

1143 status = CPXXmipopt(mEnv, mLp);

1144 } else {

1145 status = CPXXlpopt(mEnv, mLp);

1146 }

1147

1148

1149 (void)CPXXsetintparam(mEnv, CPX_PARAM_SCRIND, CPX_OFF);

1150

1151 if (status) {

1152 VLOG(1) << absl::StrFormat("Failed to optimize MIP. Error %d", status);

1153

1154

1155 } else {

1156 VLOG(1) << absl::StrFormat("Solved in %.3f seconds.", timer.Get());

1157 }

1158

1159 int const cpxstat = CPXXgetstat(mEnv, mLp);

1160 VLOG(1) << absl::StrFormat("CPLEX solution status %d.", cpxstat);

1161

1162

1163 int solnmethod, solntype, pfeas, dfeas;

1164 CHECK_STATUS(CPXXsolninfo(mEnv, mLp, &solnmethod, &solntype, &pfeas, &dfeas));

1165 bool const feasible = pfeas != 0;

1166

1167

1168 CPXDIM const rows = CPXXgetnumrows(mEnv, mLp);

1169 CPXDIM const cols = CPXXgetnumcols(mEnv, mLp);

1170 DCHECK_EQ(rows, solver_->constraints_.size());

1171 DCHECK_EQ(cols, solver_->variables_.size());

1172

1173

1176 if (feasible) {

1178 if (mMip) {

1180 }

1181 }

1184

1185

1186 if (mMip) {

1187

1188 if (feasible) {

1189 if (cols > 0) {

1190 unique_ptr<double[]> x(new double[cols]);

1191 CHECK_STATUS(CPXXgetx(mEnv, mLp, x.get(), 0, cols - 1));

1192 for (int i = 0; i < solver_->variables_.size(); ++i) {

1195 VLOG(3) << var->name() << ": value =" << x[i];

1196 }

1197 }

1198 } else {

1199 for (int i = 0; i < solver_->variables_.size(); ++i)

1200 solver_->variables_[i]->set_solution_value(CPX_NAN);

1201 }

1202

1203

1204 for (int i = 0; i < solver_->variables_.size(); ++i)

1206 for (int i = 0; i < solver_->constraints_.size(); ++i)

1208 } else {

1209

1210 if (cols > 0) {

1211 unique_ptr<double[]> x(new double[cols]);

1212 unique_ptr<double[]> dj(new double[cols]);

1213 if (feasible) CHECK_STATUS(CPXXgetx(mEnv, mLp, x.get(), 0, cols - 1));

1214 if (dfeas) CHECK_STATUS(CPXXgetdj(mEnv, mLp, dj.get(), 0, cols - 1));

1215 for (int i = 0; i < solver_->variables_.size(); ++i) {

1218 bool value = false, dual = false;

1219

1220 if (feasible) {

1222 value = true;

1223 } else

1225 if (dfeas) {

1227 dual = true;

1228 } else

1230 VLOG(3) << var->name() << ":"

1231 << (value ? absl::StrFormat(" value = %f", x[i]) : "")

1232 << (dual ? absl::StrFormat(" reduced cost = %f", dj[i]) : "");

1233 }

1234 }

1235

1236 if (rows > 0) {

1237 unique_ptr<double[]> pi(new double[rows]);

1238 if (dfeas) CHECK_STATUS(CPXXgetpi(mEnv, mLp, pi.get(), 0, rows - 1));

1239 for (int i = 0; i < solver_->constraints_.size(); ++i) {

1241 bool dual = false;

1242 if (dfeas) {

1244 dual = true;

1245 } else

1247 VLOG(4) << "row " << ct->index() << ":"

1248 << (dual ? absl::StrFormat(" dual = %f", pi[i]) : "");

1249 }

1250 }

1251 }

1252

1253

1254 switch (cpxstat) {

1255 case CPX_STAT_OPTIMAL:

1256 case CPXMIP_OPTIMAL:

1258 break;

1259 case CPXMIP_OPTIMAL_TOL:

1260

1262 break;

1263 case CPX_STAT_INFEASIBLE:

1264 case CPXMIP_INFEASIBLE:

1266 break;

1267 case CPX_STAT_UNBOUNDED:

1268 case CPXMIP_UNBOUNDED:

1270 break;

1271 case CPX_STAT_INForUNBD:

1272 case CPXMIP_INForUNBD:

1274 break;

1275 default:

1277 break;

1278 }

1279

1282}

1284 const std::string& parameters) {

1285 if (parameters.empty()) return true;

1286 for (const auto parameter : absl::StrSplit(parameters, absl::ByAnyChar(","),

1287 absl::SkipWhitespace())) {

1288 std::vector<std::string> key_value =

1289 absl::StrSplit(parameter, absl::ByAnyChar("="), absl::SkipWhitespace());

1290 if (key_value.size() != 2) {

1291 LOG(WARNING) << absl::StrFormat(

1292 "Cannot parse parameter '%s'. Expected format is 'parameter/name = "

1293 "value'",

1294 parameter);

1295 continue;

1296 }

1297 std::string identifier = key_value[0];

1298 absl::RemoveExtraAsciiWhitespace(&identifier);

1299

1300 std::string value = key_value[1];

1301 absl::RemoveExtraAsciiWhitespace(&value);

1302

1303 try {

1304 if (identifier.find("LogFile") != std::string::npos) {

1305 CPXXsetlogfilename(mEnv, value.c_str(), "w");

1306 } else {

1307 std::string delimiter = ".";

1308 if (value.find(delimiter) == std::string::npos) {

1309 (void)CPXXsetintparam(mEnv, std::stoi(identifier), std::stoi(value));

1310 } else {

1311 (void)CPXXsetdblparam(mEnv, std::stoi(identifier), std::stod(value));

1312 }

1313 VLOG(2) << absl::StrFormat("Set parameter %s to %s", identifier, value);

1314 }

1315 } catch (...) {

1316 LOG(WARNING) << absl::StrFormat(

1317 "Cannot parse parameter '%s'. Expected format is 'parameter/name = "

1318 "value'",

1319 identifier);

1320 }

1321 }

1322 return true;

1323}

1324

1325namespace {

1326

1327

1328const void* const kRegisterCplex ABSL_ATTRIBUTE_UNUSED = [] {

1332 return nullptr;

1333}();

1334

1335

1336const void* const kRegisterCplexMip ABSL_ATTRIBUTE_UNUSED = [] {

1340 return nullptr;

1341}();

1342

1343}

1344

1345}

virtual MPSolver::BasisStatus row_status(int constraint_index) const

Definition cplex_interface.cc:632

virtual void SetOptimizationDirection(bool maximize)

Definition cplex_interface.cc:283

~CplexInterface()

Definition cplex_interface.cc:239

virtual MPSolver::BasisStatus column_status(int variable_index) const

Definition cplex_interface.cc:657

virtual int64_t iterations() const

Definition cplex_interface.cc:595

bool SetSolverSpecificParametersAsString(const std::string &parameters) override

Definition cplex_interface.cc:1283

virtual double ComputeExactConditionNumber() const

Definition cplex_interface.cc:126

virtual void SetVariableBounds(int var_index, double lb, double ub)

Definition cplex_interface.cc:288

virtual void * underlying_solver()

Definition cplex_interface.cc:124

virtual void ClearObjective()

Definition cplex_interface.cc:563

virtual void Reset()

Definition cplex_interface.cc:264

virtual void AddRowConstraint(MPConstraint *const ct)

Definition cplex_interface.cc:444

virtual void ClearConstraint(MPConstraint *const constraint)

Definition cplex_interface.cc:495

virtual void ExtractNewVariables()

Definition cplex_interface.cc:682

virtual void SetVariableInteger(int var_index, bool integer)

Definition cplex_interface.cc:317

virtual MPSolver::ResultStatus Solve(MPSolverParameters const &param)

Definition cplex_interface.cc:1073

virtual void SetCoefficient(MPConstraint *const constraint, MPVariable const *const variable, double new_value, double old_value)

Definition cplex_interface.cc:464

virtual std::string SolverVersion() const

Definition cplex_interface.cc:244

virtual void SetPresolveMode(int value)

Definition cplex_interface.cc:999

virtual int64_t nodes() const

Definition cplex_interface.cc:604

virtual bool ReadParameterFile(std::string const &filename)

Definition cplex_interface.cc:1064

virtual void SetParameters(MPSolverParameters const &param)

Definition cplex_interface.cc:977

virtual bool IsContinuous() const

Definition cplex_interface.cc:112

virtual void SetObjectiveOffset(double value)

Definition cplex_interface.cc:557

virtual void AddVariable(MPVariable *const var)

Definition cplex_interface.cc:454

virtual void ExtractNewConstraints()

Definition cplex_interface.cc:843

virtual bool IsLP() const

Definition cplex_interface.cc:113

virtual void SetConstraintBounds(int row_index, double lb, double ub)

Definition cplex_interface.cc:413

virtual void SetLpAlgorithm(int value)

Definition cplex_interface.cc:1033

virtual bool IsMIP() const

Definition cplex_interface.cc:114

virtual void SetScalingMode(int value)

Definition cplex_interface.cc:1015

virtual void ExtractObjective()

Definition cplex_interface.cc:948

virtual void SetObjectiveCoefficient(MPVariable const *const variable, double coefficient)

Definition cplex_interface.cc:535

virtual void SetDualTolerance(double value)

Definition cplex_interface.cc:995

CplexInterface(MPSolver *const solver, bool mip)

Definition cplex_interface.cc:214

virtual std::string ValidFileExtensionForParameterFile() const

Definition cplex_interface.cc:1069

virtual void SetRelativeMipGap(double value)

Definition cplex_interface.cc:982

virtual void SetPrimalTolerance(double value)

Definition cplex_interface.cc:991

void set_dual_value(double dual_value)

double lb() const

Returns the lower bound.

double ub() const

Returns the upper bound.

const std::string & name() const

Returns the name of the constraint.

int index() const

Returns the index of the constraint in the MPSolver::constraints_.

static MPSolverInterfaceFactoryRepository * GetInstance()

void Register(MPSolverInterfaceFactory factory, MPSolver::OptimizationProblemType problem_type, std::function< bool()> is_runtime_ready={})

void set_variable_as_extracted(int var_index, bool extracted)

bool CheckSolutionIsSynchronized() const

static constexpr int64_t kUnknownNumberOfIterations

friend class MPConstraint

void InvalidateSolutionSynchronization()

void set_constraint_as_extracted(int ct_index, bool extracted)

void ResetExtractionInformation()

virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)

int last_constraint_index_

bool variable_is_extracted(int var_index) const

bool constraint_is_extracted(int ct_index) const

static constexpr int64_t kUnknownNumberOfNodes

double best_objective_bound_

void SetMIPParameters(const MPSolverParameters &param)

MPSolverInterface(MPSolver *solver)

void SetCommonParameters(const MPSolverParameters &param)

MPSolver::ResultStatus result_status_

SynchronizationStatus sync_status_

PresolveValues

For each categorical parameter, enumeration of possible values.

@ PRESOLVE_OFF

Presolve is off.

@ PRESOLVE_ON

Presolve is on.

LpAlgorithmValues

LP algorithm to use.

@ BARRIER

Barrier algorithm.

@ INCREMENTALITY

Advanced usage: incrementality from one solve to the next.

@ PRESOLVE

Advanced usage: presolve mode.

@ LP_ALGORITHM

Algorithm to solve linear programs.

IncrementalityValues

Advanced usage: Incrementality options.

@ INCREMENTALITY_OFF

Start solve from scratch.

ScalingValues

Advanced usage: Scaling options.

@ SCALING_ON

Scaling is on.

@ SCALING_OFF

Scaling is off.

int GetIntegerParam(MPSolverParameters::IntegerParam param) const

Returns the value of an integer parameter.

@ FEASIBLE

feasible, or stopped by limit.

@ INFEASIBLE

proven infeasible.

@ UNBOUNDED

proven unbounded.

@ ABNORMAL

abnormal, i.e., error of some kind.

@ CPLEX_LINEAR_PROGRAMMING

@ CPLEX_MIXED_INTEGER_PROGRAMMING

The class for variables of a Mathematical Programming (MP) model.

bool integer() const

Returns the integrality requirement of the variable.

double lb() const

Returns the lower bound.

double ub() const

Returns the upper bound.

const std::string & name() const

Returns the name of the variable.

void set_reduced_cost(double reduced_cost)

void set_solution_value(double value)

int index() const

Returns the index of the variable in the MPSolver::variables_.

#define CPX_NAN

Definition cplex_interface.cc:36

CPXLIBAPI int CPXPUBLIC CPXEsetobjoffset(CPXCENVptr, CPXLPptr, double)

#define CHECK_STATUS(s)

Definition cplex_interface.cc:42

ClosedInterval::Iterator begin(ClosedInterval interval)