Google OR-Tools: ortools/constraint_solver/search.cc Source File

1

2

3

4

5

6

7

8

9

10

11

12

13

14#include <algorithm>

15#include <cstdint>

16#include <functional>

17#include <limits>

18#include <list>

19#include <memory>

20#include <queue>

21#include <random>

22#include <string>

23#include <tuple>

24#include <utility>

25#include <vector>

26

27#include "absl/container/flat_hash_map.h"

28#include "absl/flags/flag.h"

29#include "absl/log/check.h"

30#include "absl/log/log.h"

31#include "absl/log/vlog_is_on.h"

32#include "absl/random/distributions.h"

33#include "absl/strings/str_cat.h"

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

35#include "absl/strings/str_join.h"

36#include "absl/strings/string_view.h"

37#include "absl/time/time.h"

38#include "absl/types/span.h"

50

51ABSL_FLAG(bool, cp_use_sparse_gls_penalties, false,

52 "Use sparse implementation to store Guided Local Search penalties");

54 "Whether search related logging should be "

55 "vlog or info.");

56ABSL_FLAG(int64_t, cp_large_domain_no_splitting_limit, 0xFFFFF,

57 "Size limit to allow holes in variables from the strategy.");

59

60

61

63 std::string vars_name, std::vector<double> scaling_factors,

64 std::vector<double> offsets,

65 std::function<std::string()> display_callback,

66 bool display_on_new_solutions_only, int period)

68 period_(period),

70 vars_(std::move(vars)),

71 vars_name_(std::move(vars_name)),

72 scaling_factors_(std::move(scaling_factors)),

73 offsets_(std::move(offsets)),

74 display_callback_(std::move(display_callback)),

75 display_on_new_solutions_only_(display_on_new_solutions_only),

76 nsol_(0),

77 objective_min_(vars_.size(), std::numeric_limits<int64_t>::max()),

78 objective_max_(vars_.size(), std::numeric_limits<int64_t>::min()),

79 min_right_depth_(std::numeric_limits<int32_t>::max()),

80 max_depth_(0),

81 sliding_min_depth_(0),

82 sliding_max_depth_(0) {}

83

85

87

89 const std::string buffer =

90 (!display_on_new_solutions_only_ && display_callback_ != nullptr)

91 ? absl::StrFormat("Start search (%s, %s)", MemoryUsage(),

92 display_callback_())

93 : absl::StrFormat("Start search (%s)", MemoryUsage());

95 timer_->Restart();

96 min_right_depth_ = std::numeric_limits<int32_t>::max();

98 nsol_ = 0;

99 last_objective_value_.clear();

100 last_objective_timestamp_ = timer_->GetDuration();

101}

102

105 int64_t ms = absl::ToInt64Milliseconds(timer_->GetDuration());

106 if (ms == 0) {

107 ms = 1;

108 }

109 const std::string buffer = absl::StrFormat(

110 "End search (time = %d ms, branches = %d, failures = %d, %s, speed = %d "

111 "branches/s)",

112 ms, branches, solver()->failures(), MemoryUsage(), branches * 1000 / ms);

114}

115

119 std::string obj_str = "";

120 std::vector<int64_t> current;

121 bool objective_updated = false;

122 const auto scaled_str = [this](absl::Span<const int64_t> values) {

123 std::vector<std::string> value_strings(values.size());

124 for (int i = 0; i < values.size(); ++i) {

125 if (scaling_factors_[i] != 1.0 || offsets_[i] != 0.0) {

126 value_strings[i] =

127 absl::StrFormat("%d (%.8lf)", values[i],

128 scaling_factors_[i] * (values[i] + offsets_[i]));

129 } else {

130 value_strings[i] = absl::StrCat(values[i]);

131 }

132 }

133 return absl::StrJoin(value_strings, ", ");

134 };

135 bool all_vars_bound = !vars_.empty();

136 for (IntVar* var : vars_) {

137 all_vars_bound &= var->Bound();

138 }

139 if (all_vars_bound) {

140 for (IntVar* var : vars_) {

141 current.push_back(var->Value());

142 objective_updated = true;

143 }

144 absl::StrAppend(&obj_str,

145 vars_name_.empty() ? "" : absl::StrCat(vars_name_, " = "),

146 scaled_str(current), ", ");

147 } else {

148 current.push_back(solver()->GetOrCreateLocalSearchState()->ObjectiveMin());

149 absl::StrAppend(&obj_str, "objective = ", scaled_str(current), ", ");

150 objective_updated = true;

151 }

152 const absl::Duration now = timer_->GetDuration();

153 if (objective_updated) {

154 if (!last_objective_value_.empty()) {

155 const int64_t elapsed_ms =

156 absl::ToInt64Milliseconds(now - last_objective_timestamp_);

157 for (int i = 0; i < current.size(); ++i) {

158 const double improvement_rate =

159 100.0 * 1000.0 * (current[i] - last_objective_value_[i]) /

160 std::max<int64_t>(1, last_objective_value_[i] * elapsed_ms);

161 absl::StrAppend(&obj_str, "improvement rate = ", improvement_rate,

162 "%/s, ");

163 last_objective_value_[i] = current[i];

164 }

165 } else {

166 last_objective_value_ = current;

167 }

168 last_objective_timestamp_ = now;

169 if (!objective_min_.empty() &&

170 std::lexicographical_compare(objective_min_.begin(),

171 objective_min_.end(), current.begin(),

172 current.end())) {

173 absl::StrAppend(&obj_str,

174 vars_name_.empty() ? "" : absl::StrCat(vars_name_, " "),

175 "minimum = ", scaled_str(objective_min_), ", ");

176

177 } else {

178 objective_min_ = current;

179 }

180 if (!objective_max_.empty() &&

181 std::lexicographical_compare(current.begin(), current.end(),

182 objective_max_.begin(),

183 objective_max_.end())) {

184 absl::StrAppend(&obj_str,

185 vars_name_.empty() ? "" : absl::StrCat(vars_name_, " "),

186 "maximum = ", scaled_str(objective_max_), ", ");

187 } else {

188 objective_max_ = current;

189 }

190 }

191 std::string log;

192 absl::StrAppendFormat(&log,

193 "Solution #%d (%stime = %d ms, branches = %d,"

194 " failures = %d, depth = %d",

195 nsol_++, obj_str, absl::ToInt64Milliseconds(now),

196 solver()->branches(), solver()->failures(), depth);

197 if (!solver()->SearchContext().empty()) {

198 absl::StrAppendFormat(&log, ", %s", solver()->SearchContext());

199 }

200 if (solver()->accepted_neighbors() != neighbors_offset_) {

201 absl::StrAppendFormat(&log,

202 ", neighbors = %d, filtered neighbors = %d,"

203 " accepted neighbors = %d",

204 solver()->neighbors(), solver()->filtered_neighbors(),

205 solver()->accepted_neighbors());

206 }

207 absl::StrAppendFormat(&log, ", %s", MemoryUsage());

210 absl::StrAppendFormat(&log, ", limit = %d%%", progress);

211 }

212 if (display_callback_) {

213 absl::StrAppendFormat(&log, ", %s", display_callback_());

214 }

215 log.append(")");

217 return false;

218}

219

221

223

225 std::string buffer = absl::StrFormat(

226 "Finished search tree (time = %d ms, branches = %d,"

227 " failures = %d",

228 absl::ToInt64Milliseconds(timer_->GetDuration()), solver()->branches(),

229 solver()->failures());

230 if (solver()->neighbors() != 0) {

231 absl::StrAppendFormat(&buffer,

232 ", neighbors = %d, filtered neighbors = %d,"

233 " accepted neigbors = %d",

234 solver()->neighbors(), solver()->filtered_neighbors(),

235 solver()->accepted_neighbors());

236 }

237 absl::StrAppendFormat(&buffer, ", %s", MemoryUsage());

238 if (!display_on_new_solutions_only_ && display_callback_) {

239 absl::StrAppendFormat(&buffer, ", %s", display_callback_());

240 }

241 buffer.append(")");

243}

244

248 if (b % period_ == 0 && b > 0) {

250 }

251}

252

254 min_right_depth_ = std::min(min_right_depth_, solver()->SearchDepth());

256}

257

259 std::string buffer = absl::StrFormat(

260 "%d branches, %d ms, %d failures", solver()->branches(),

261 absl::ToInt64Milliseconds(timer_->GetDuration()), solver()->failures());

262 if (min_right_depth_ != std::numeric_limits<int32_t>::max() &&

263 max_depth_ != 0) {

265 absl::StrAppendFormat(&buffer, ", tree pos=%d/%d/%d minref=%d max=%d",

266 sliding_min_depth_, depth, sliding_max_depth_,

267 min_right_depth_, max_depth_);

268 sliding_min_depth_ = depth;

269 sliding_max_depth_ = depth;

270 }

271 if (!objective_min_.empty() &&

272 objective_min_[0] != std::numeric_limits<int64_t>::max() &&

273 objective_max_[0] != std::numeric_limits<int64_t>::min()) {

274 const std::string name =

275 vars_name_.empty() ? "" : absl::StrCat(" ", vars_name_);

276 absl::StrAppendFormat(&buffer,

277 ",%s minimum = %d"

278 ",%s maximum = %d",

279 name, objective_min_[0], name, objective_max_[0]);

280 }

283 absl::StrAppendFormat(&buffer, ", limit = %d%%", progress);

284 }

286}

287

290 sliding_min_depth_ = std::min(current_depth, sliding_min_depth_);

291 sliding_max_depth_ = std::max(current_depth, sliding_max_depth_);

292 max_depth_ = std::max(current_depth, max_depth_);

293}

294

296

298 const int64_t delta = std::max<int64_t>(

299 absl::ToInt64Milliseconds(timer_->GetDuration() - tick_), 0);

300 const std::string buffer = absl::StrFormat(

301 "Root node processed (time = %d ms, constraints = %d, %s)", delta,

304}

305

307 if (absl::GetFlag(FLAGS_cp_log_to_vlog)) {

308 VLOG(1) << line;

309 } else {

310 LOG(INFO) << line;

311 }

312}

313

314std::string SearchLog::MemoryUsage() {

315 static const int64_t kDisplayThreshold = 2;

316 static const int64_t kKiloByte = 1024;

317 static const int64_t kMegaByte = kKiloByte * kKiloByte;

318 static const int64_t kGigaByte = kMegaByte * kKiloByte;

320 if (memory_usage > kDisplayThreshold * kGigaByte) {

321 return absl::StrFormat("memory used = %.2lf GB",

322 memory_usage * 1.0 / kGigaByte);

323 } else if (memory_usage > kDisplayThreshold * kMegaByte) {

324 return absl::StrFormat("memory used = %.2lf MB",

325 memory_usage * 1.0 / kMegaByte);

326 } else if (memory_usage > kDisplayThreshold * kKiloByte) {

327 return absl::StrFormat("memory used = %2lf KB",

328 memory_usage * 1.0 / kKiloByte);

329 } else {

330 return absl::StrFormat("memory used = %d", memory_usage);

331 }

332}

333

335 return MakeSearchLog(branch_period, std::vector<IntVar*>{}, nullptr);

336}

337

339 return MakeSearchLog(branch_period, std::vector<IntVar*>{var}, nullptr);

340}

341

343 int branch_period, std::function<std::string()> display_callback) {

344 return MakeSearchLog(branch_period, std::vector<IntVar*>{},

345 std::move(display_callback));

346}

347

349 int branch_period, IntVar* var,

350 std::function<std::string()> display_callback) {

351 return MakeSearchLog(branch_period, std::vector<IntVar*>{var},

352 std::move(display_callback));

353}

354

356 int branch_period, std::vector<IntVar*> vars,

357 std::function<std::string()> display_callback) {

358 return RevAlloc(new SearchLog(this, std::move(vars), "", {1.0}, {0.0},

359 std::move(display_callback), true,

360 branch_period));

361}

362

366

369 std::function<std::string()> display_callback) {

370 std::vector<IntVar*> vars = opt_var->objective_vars();

371 std::vector<double> scaling_factors(vars.size(), 1.0);

372 std::vector<double> offsets(vars.size(), 0.0);

374 this, std::move(vars), opt_var->Name(), std::move(scaling_factors),

375 std::move(offsets), std::move(display_callback),

376 true, branch_period));

377}

378

381 << "Either variables are empty or objective is nullptr.";

382 std::vector<IntVar*> vars = parameters.objective != nullptr

383 ? parameters.objective->objective_vars()

385 std::vector<double> scaling_factors = std::move(parameters.scaling_factors);

386 scaling_factors.resize(vars.size(), 1.0);

387 std::vector<double> offsets = std::move(parameters.offsets);

388 offsets.resize(vars.size(), 0.0);

390 this, std::move(vars), "", std::move(scaling_factors), std::move(offsets),

391 std::move(parameters.display_callback),

393}

394

395

396namespace {

398 public:

399 SearchTrace(Solver* const s, const std::string& prefix)

401 ~SearchTrace() override {}

402

403 void EnterSearch() override {

404 LOG(INFO) << prefix_ << " EnterSearch(" << solver()->SolveDepth() << ")";

405 }

406 void RestartSearch() override {

407 LOG(INFO) << prefix_ << " RestartSearch(" << solver()->SolveDepth() << ")";

408 }

409 void ExitSearch() override {

410 LOG(INFO) << prefix_ << " ExitSearch(" << solver()->SolveDepth() << ")";

411 }

412 void BeginNextDecision(DecisionBuilder* const b) override {

413 LOG(INFO) << prefix_ << " BeginNextDecision(" << b << ") ";

414 }

415 void EndNextDecision(DecisionBuilder* const b, Decision* const d) override {

416 if (d) {

417 LOG(INFO) << prefix_ << " EndNextDecision(" << b << ", " << d << ") ";

418 } else {

419 LOG(INFO) << prefix_ << " EndNextDecision(" << b << ") ";

420 }

421 }

422 void ApplyDecision(Decision* const d) override {

423 LOG(INFO) << prefix_ << " ApplyDecision(" << d << ") ";

424 }

425 void RefuteDecision(Decision* const d) override {

426 LOG(INFO) << prefix_ << " RefuteDecision(" << d << ") ";

427 }

428 void AfterDecision(Decision* const d, bool apply) override {

429 LOG(INFO) << prefix_ << " AfterDecision(" << d << ", " << apply << ") ";

430 }

431 void BeginFail() override {

432 LOG(INFO) << prefix_ << " BeginFail(" << solver()->SearchDepth() << ")";

433 }

434 void EndFail() override {

435 LOG(INFO) << prefix_ << " EndFail(" << solver()->SearchDepth() << ")";

436 }

437 void BeginInitialPropagation() override {

438 LOG(INFO) << prefix_ << " BeginInitialPropagation()";

439 }

440 void EndInitialPropagation() override {

441 LOG(INFO) << prefix_ << " EndInitialPropagation()";

442 }

443 bool AtSolution() override {

444 LOG(INFO) << prefix_ << " AtSolution()";

445 return false;

446 }

447 bool AcceptSolution() override {

448 LOG(INFO) << prefix_ << " AcceptSolution()";

449 return true;

450 }

451 void NoMoreSolutions() override {

452 LOG(INFO) << prefix_ << " NoMoreSolutions()";

453 }

454

455 std::string DebugString() const override { return "SearchTrace"; }

456

457 private:

458 const std::string prefix_;

459};

460}

461

463 return RevAlloc(new SearchTrace(this, prefix));

464}

465

466

467namespace {

469 public:

470 AtSolutionCallback(Solver* const solver, std::function<void()> callback)

472 ~AtSolutionCallback() override {}

473 bool AtSolution() override;

474 void Install() override;

475

476 private:

477 const std::function<void()> callback_;

478};

479

480bool AtSolutionCallback::AtSolution() {

481 callback_();

482 return false;

483}

484

485void AtSolutionCallback::Install() {

486 ListenToEvent(Solver::MonitorEvent::kAtSolution);

487}

488

489}

490

492 return RevAlloc(new AtSolutionCallback(this, std::move(callback)));

493}

494

495namespace {

496class EnterSearchCallback : public SearchMonitor {

497 public:

498 EnterSearchCallback(Solver* const solver, std::function<void()> callback)

500 ~EnterSearchCallback() override {}

501 void EnterSearch() override;

502 void Install() override;

503

504 private:

505 const std::function<void()> callback_;

506};

507

508void EnterSearchCallback::EnterSearch() { callback_(); }

509

510void EnterSearchCallback::Install() {

511 ListenToEvent(Solver::MonitorEvent::kEnterSearch);

512}

513

514}

515

517 return RevAlloc(new EnterSearchCallback(this, std::move(callback)));

518}

519

520namespace {

522 public:

523 ExitSearchCallback(Solver* const solver, std::function<void()> callback)

525 ~ExitSearchCallback() override {}

526 void ExitSearch() override;

527 void Install() override;

528

529 private:

530 const std::function<void()> callback_;

531};

532

533void ExitSearchCallback::ExitSearch() { callback_(); }

534

535void ExitSearchCallback::Install() {

536 ListenToEvent(Solver::MonitorEvent::kExitSearch);

537}

538

539}

540

542 return RevAlloc(new ExitSearchCallback(this, std::move(callback)));

543}

544

545

546

547namespace {

549 public:

550 CompositeDecisionBuilder();

551 explicit CompositeDecisionBuilder(const std::vector<DecisionBuilder*>& dbs);

552 ~CompositeDecisionBuilder() override;

554 void AppendMonitors(Solver* solver,

555 std::vector<SearchMonitor*>* monitors) override;

556 void Accept(ModelVisitor* visitor) const override;

557

558 protected:

559 std::vector<DecisionBuilder*> builders_;

560};

561

562CompositeDecisionBuilder::CompositeDecisionBuilder() {}

563

564CompositeDecisionBuilder::CompositeDecisionBuilder(

565 const std::vector<DecisionBuilder*>& dbs) {

566 for (int i = 0; i < dbs.size(); ++i) {

567 Add(dbs[i]);

568 }

569}

570

571CompositeDecisionBuilder::~CompositeDecisionBuilder() {}

572

573void CompositeDecisionBuilder::Add(DecisionBuilder* const db) {

574 if (db != nullptr) {

575 builders_.push_back(db);

576 }

577}

578

579void CompositeDecisionBuilder::AppendMonitors(

580 Solver* const solver, std::vector<SearchMonitor*>* const monitors) {

581 for (DecisionBuilder* const db : builders_) {

582 db->AppendMonitors(solver, monitors);

583 }

584}

585

586void CompositeDecisionBuilder::Accept(ModelVisitor* const visitor) const {

587 for (DecisionBuilder* const db : builders_) {

588 db->Accept(visitor);

589 }

590}

591}

592

593

594

595namespace {

596class ComposeDecisionBuilder : public CompositeDecisionBuilder {

597 public:

598 ComposeDecisionBuilder();

599 explicit ComposeDecisionBuilder(const std::vector<DecisionBuilder*>& dbs);

600 ~ComposeDecisionBuilder() override;

601 Decision* Next(Solver* s) override;

602 std::string DebugString() const override;

603

604 private:

605 int start_index_;

606};

607

608ComposeDecisionBuilder::ComposeDecisionBuilder() : start_index_(0) {}

609

610ComposeDecisionBuilder::ComposeDecisionBuilder(

611 const std::vector<DecisionBuilder*>& dbs)

612 : CompositeDecisionBuilder(dbs), start_index_(0) {}

613

614ComposeDecisionBuilder::~ComposeDecisionBuilder() {}

615

616Decision* ComposeDecisionBuilder::Next(Solver* const s) {

617 const int size = builders_.size();

618 for (int i = start_index_; i < size; ++i) {

619 Decision* d = builders_[i]->Next(s);

620 if (d != nullptr) {

621 s->SaveAndSetValue(&start_index_, i);

622 return d;

623 }

624 }

625 s->SaveAndSetValue(&start_index_, size);

626 return nullptr;

627}

628

629std::string ComposeDecisionBuilder::DebugString() const {

630 return absl::StrFormat("ComposeDecisionBuilder(%s)",

632}

633}

634

637 ComposeDecisionBuilder* c = RevAlloc(new ComposeDecisionBuilder());

638 c->Add(db1);

639 c->Add(db2);

640 return c;

641}

642

646 ComposeDecisionBuilder* c = RevAlloc(new ComposeDecisionBuilder());

647 c->Add(db1);

648 c->Add(db2);

649 c->Add(db3);

650 return c;

651}

652

657 ComposeDecisionBuilder* c = RevAlloc(new ComposeDecisionBuilder());

658 c->Add(db1);

659 c->Add(db2);

660 c->Add(db3);

661 c->Add(db4);

662 return c;

663}

664

666 if (dbs.size() == 1) {

667 return dbs[0];

668 }

669 return RevAlloc(new ComposeDecisionBuilder(dbs));

670}

671

672

673

674namespace {

675class ClosureDecision : public Decision {

676 public:

678 : apply_(std::move(apply)), refute_(std::move(refute)) {}

679 ~ClosureDecision() override {}

680

681 void Apply(Solver* const s) override { apply_(s); }

682

683 void Refute(Solver* const s) override { refute_(s); }

684

685 std::string DebugString() const override { return "ClosureDecision"; }

686

687 private:

688 Solver::Action apply_;

689 Solver::Action refute_;

690};

691}

692

694 return RevAlloc(new ClosureDecision(std::move(apply), std::move(refute)));

695}

696

697

698

699namespace {

700

701class TryDecisionBuilder;

702

703class TryDecision : public Decision {

704 public:

705 explicit TryDecision(TryDecisionBuilder* try_builder);

706 ~TryDecision() override;

707 void Apply(Solver* solver) override;

708 void Refute(Solver* solver) override;

709 std::string DebugString() const override { return "TryDecision"; }

710

711 private:

712 TryDecisionBuilder* const try_builder_;

713};

714

715class TryDecisionBuilder : public CompositeDecisionBuilder {

716 public:

717 TryDecisionBuilder();

718 explicit TryDecisionBuilder(const std::vector<DecisionBuilder*>& dbs);

719 ~TryDecisionBuilder() override;

720 Decision* Next(Solver* solver) override;

721 std::string DebugString() const override;

722 void AdvanceToNextBuilder(Solver* solver);

723

724 private:

725 TryDecision try_decision_;

726 int current_builder_;

727 bool start_new_builder_;

728};

729

730TryDecision::TryDecision(TryDecisionBuilder* const try_builder)

731 : try_builder_(try_builder) {}

732

733TryDecision::~TryDecision() {}

734

735void TryDecision::Apply(Solver* const) {}

736

737void TryDecision::Refute(Solver* const solver) {

738 try_builder_->AdvanceToNextBuilder(solver);

739}

740

741TryDecisionBuilder::TryDecisionBuilder()

742 : CompositeDecisionBuilder(),

743 try_decision_(this),

744 current_builder_(-1),

745 start_new_builder_(true) {}

746

747TryDecisionBuilder::TryDecisionBuilder(const std::vector<DecisionBuilder*>& dbs)

748 : CompositeDecisionBuilder(dbs),

749 try_decision_(this),

750 current_builder_(-1),

751 start_new_builder_(true) {}

752

753TryDecisionBuilder::~TryDecisionBuilder() {}

754

755Decision* TryDecisionBuilder::Next(Solver* const solver) {

756 if (current_builder_ < 0) {

757 solver->SaveAndSetValue(&current_builder_, 0);

758 start_new_builder_ = true;

759 }

760 if (start_new_builder_) {

761 start_new_builder_ = false;

762 return &try_decision_;

763 } else {

764 return builders_[current_builder_]->Next(solver);

765 }

766}

767

768std::string TryDecisionBuilder::DebugString() const {

769 return absl::StrFormat("TryDecisionBuilder(%s)",

771}

772

773void TryDecisionBuilder::AdvanceToNextBuilder(Solver* const solver) {

774 ++current_builder_;

775 start_new_builder_ = true;

776 if (current_builder_ >= builders_.size()) {

777 solver->Fail();

778 }

779}

780

781}

782

785 TryDecisionBuilder* try_db = RevAlloc(new TryDecisionBuilder());

786 try_db->Add(db1);

787 try_db->Add(db2);

788 return try_db;

789}

790

794 TryDecisionBuilder* try_db = RevAlloc(new TryDecisionBuilder());

795 try_db->Add(db1);

796 try_db->Add(db2);

797 try_db->Add(db3);

798 return try_db;

799}

800

805 TryDecisionBuilder* try_db = RevAlloc(new TryDecisionBuilder());

806 try_db->Add(db1);

807 try_db->Add(db2);

808 try_db->Add(db3);

809 try_db->Add(db4);

810 return try_db;

811}

812

814 return RevAlloc(new TryDecisionBuilder(dbs));

815}

816

817

818

819

820

821namespace {

822class BaseVariableAssignmentSelector : public BaseObject {

823 public:

824 BaseVariableAssignmentSelector(Solver* solver,

825 const std::vector<IntVar*>& vars)

826 : solver_(solver),

827 vars_(vars),

828 first_unbound_(0),

829 last_unbound_(vars.size() - 1) {}

830

831 ~BaseVariableAssignmentSelector() override {}

832

833 virtual int64_t SelectValue(const IntVar* v, int64_t id) = 0;

834

835

836 virtual int64_t ChooseVariable() = 0;

837

838 int64_t ChooseVariableWrapper() {

839 int64_t i;

840 for (i = first_unbound_.Value(); i <= last_unbound_.Value(); ++i) {

841 if (!vars_[i]->Bound()) {

842 break;

843 }

844 }

845 first_unbound_.SetValue(solver_, i);

846 if (i > last_unbound_.Value()) {

847 return -1;

848 }

849 for (i = last_unbound_.Value(); i >= first_unbound_.Value(); --i) {

850 if (!vars_[i]->Bound()) {

851 break;

852 }

853 }

854 last_unbound_.SetValue(solver_, i);

855 return ChooseVariable();

856 }

857

858 void Accept(ModelVisitor* const visitor) const {

859 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);

860 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,

861 vars_);

862 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);

863 }

864

865 const std::vector<IntVar*>& vars() const { return vars_; }

866

867 protected:

868 Solver* const solver_;

869 std::vector<IntVar*> vars_;

870 Rev<int64_t> first_unbound_;

871 Rev<int64_t> last_unbound_;

872};

873

874

875

876int64_t ChooseFirstUnbound(Solver*, const std::vector<IntVar*>& vars,

877 int64_t first_unbound, int64_t last_unbound) {

878 for (int64_t i = first_unbound; i <= last_unbound; ++i) {

879 if (!vars[i]->Bound()) {

880 return i;

881 }

882 }

883 return -1;

884}

885

886

887

888int64_t ChooseMinSizeLowestMin(Solver*, const std::vector<IntVar*>& vars,

889 int64_t first_unbound, int64_t last_unbound) {

890 uint64_t best_size = std::numeric_limits<uint64_t>::max();

891 int64_t best_min = std::numeric_limits<int64_t>::max();

892 int64_t best_index = -1;

893 for (int64_t i = first_unbound; i <= last_unbound; ++i) {

894 IntVar* const var = vars[i];

895 if (!var->Bound()) {

896 if (var->Size() < best_size ||

897 (var->Size() == best_size && var->Min() < best_min)) {

898 best_size = var->Size();

899 best_min = var->Min();

900 best_index = i;

901 }

902 }

903 }

904 return best_index;

905}

906

907

908

909int64_t ChooseMinSizeHighestMin(Solver*, const std::vector<IntVar*>& vars,

910 int64_t first_unbound, int64_t last_unbound) {

911 uint64_t best_size = std::numeric_limits<uint64_t>::max();

912 int64_t best_min = std::numeric_limits<int64_t>::min();

913 int64_t best_index = -1;

914 for (int64_t i = first_unbound; i <= last_unbound; ++i) {

915 IntVar* const var = vars[i];

916 if (!var->Bound()) {

917 if (var->Size() < best_size ||

918 (var->Size() == best_size && var->Min() > best_min)) {

919 best_size = var->Size();

920 best_min = var->Min();

921 best_index = i;

922 }

923 }

924 }

925 return best_index;

926}

927

928

929

930int64_t ChooseMinSizeLowestMax(Solver*, const std::vector<IntVar*>& vars,

931 int64_t first_unbound, int64_t last_unbound) {

932 uint64_t best_size = std::numeric_limits<uint64_t>::max();

933 int64_t best_max = std::numeric_limits<int64_t>::max();

934 int64_t best_index = -1;

935 for (int64_t i = first_unbound; i <= last_unbound; ++i) {

936 IntVar* const var = vars[i];

937 if (!var->Bound()) {

938 if (var->Size() < best_size ||

939 (var->Size() == best_size && var->Max() < best_max)) {

940 best_size = var->Size();

941 best_max = var->Max();

942 best_index = i;

943 }

944 }

945 }

946 return best_index;

947}

948

949

950

951int64_t ChooseMinSizeHighestMax(Solver*, const std::vector<IntVar*>& vars,

952 int64_t first_unbound, int64_t last_unbound) {

953 uint64_t best_size = std::numeric_limits<uint64_t>::max();

954 int64_t best_max = std::numeric_limits<int64_t>::min();

955 int64_t best_index = -1;

956 for (int64_t i = first_unbound; i <= last_unbound; ++i) {

957 IntVar* const var = vars[i];

958 if (!var->Bound()) {

959 if (var->Size() < best_size ||

960 (var->Size() == best_size && var->Max() > best_max)) {

961 best_size = var->Size();

962 best_max = var->Max();

963 best_index = i;

964 }

965 }

966 }

967 return best_index;

968}

969

970

971

972int64_t ChooseLowestMin(Solver*, const std::vector<IntVar*>& vars,

973 int64_t first_unbound, int64_t last_unbound) {

974 int64_t best_min = std::numeric_limits<int64_t>::max();

975 int64_t best_index = -1;

976 for (int64_t i = first_unbound; i <= last_unbound; ++i) {

977 IntVar* const var = vars[i];

978 if (!var->Bound()) {

979 if (var->Min() < best_min) {

980 best_min = var->Min();

981 best_index = i;

982 }

983 }

984 }

985 return best_index;

986}

987

988

989

990int64_t ChooseHighestMax(Solver*, const std::vector<IntVar*>& vars,

991 int64_t first_unbound, int64_t last_unbound) {

992 int64_t best_max = std::numeric_limits<int64_t>::min();

993 int64_t best_index = -1;

994 for (int64_t i = first_unbound; i <= last_unbound; ++i) {

995 IntVar* const var = vars[i];

996 if (!var->Bound()) {

997 if (var->Max() > best_max) {

998 best_max = var->Max();

999 best_index = i;

1000 }

1001 }

1002 }

1003 return best_index;

1004}

1005

1006

1007

1008int64_t ChooseMinSize(Solver*, const std::vector<IntVar*>& vars,

1009 int64_t first_unbound, int64_t last_unbound) {

1010 uint64_t best_size = std::numeric_limits<uint64_t>::max();

1011 int64_t best_index = -1;

1012 for (int64_t i = first_unbound; i <= last_unbound; ++i) {

1013 IntVar* const var = vars[i];

1014 if (!var->Bound()) {

1015 if (var->Size() < best_size) {

1016 best_size = var->Size();

1017 best_index = i;

1018 }

1019 }

1020 }

1021 return best_index;

1022}

1023

1024

1025

1026int64_t ChooseMaxSize(Solver*, const std::vector<IntVar*>& vars,

1027 int64_t first_unbound, int64_t last_unbound) {

1028 uint64_t best_size = 0;

1029 int64_t best_index = -1;

1030 for (int64_t i = first_unbound; i <= last_unbound; ++i) {

1031 IntVar* const var = vars[i];

1032 if (!var->Bound()) {

1033 if (var->Size() > best_size) {

1034 best_size = var->Size();

1035 best_index = i;

1036 }

1037 }

1038 }

1039 return best_index;

1040}

1041

1042

1043

1044class HighestRegretSelectorOnMin : public BaseObject {

1045 public:

1046 explicit HighestRegretSelectorOnMin(const std::vector<IntVar*>& vars)

1047 : iterators_(vars.size()) {

1048 for (int64_t i = 0; i < vars.size(); ++i) {

1049 iterators_[i] = vars[i]->MakeDomainIterator(true);

1050 }

1051 }

1052 ~HighestRegretSelectorOnMin() override {};

1053 int64_t Choose(Solver* s, const std::vector<IntVar*>& vars,

1054 int64_t first_unbound, int64_t last_unbound);

1055 std::string DebugString() const override { return "MaxRegretSelector"; }

1056

1057 int64_t ComputeRegret(IntVar* var, int64_t index) const {

1058 DCHECK(!var->Bound());

1059 const int64_t vmin = var->Min();

1060 IntVarIterator* const iterator = iterators_[index];

1061 iterator->Init();

1062 iterator->Next();

1063 return iterator->Value() - vmin;

1064 }

1065

1066 private:

1067 std::vector<IntVarIterator*> iterators_;

1068};

1069

1070int64_t HighestRegretSelectorOnMin::Choose(Solver* const,

1071 const std::vector<IntVar*>& vars,

1072 int64_t first_unbound,

1073 int64_t last_unbound) {

1074 int64_t best_regret = 0;

1075 int64_t index = -1;

1076 for (int64_t i = first_unbound; i <= last_unbound; ++i) {

1077 IntVar* const var = vars[i];

1078 if (!var->Bound()) {

1079 const int64_t regret = ComputeRegret(var, i);

1080 if (regret > best_regret) {

1081 best_regret = regret;

1082 index = i;

1083 }

1084 }

1085 }

1086 return index;

1087}

1088

1089

1090

1091int64_t ChooseRandom(Solver* solver, const std::vector<IntVar*>& vars,

1092 int64_t first_unbound, int64_t last_unbound) {

1093 const int64_t span = last_unbound - first_unbound + 1;

1094 const int64_t shift = solver->Rand32(span);

1095 for (int64_t i = 0; i < span; ++i) {

1096 const int64_t index = (i + shift) % span + first_unbound;

1097 if (!vars[index]->Bound()) {

1098 return index;

1099 }

1100 }

1101 return -1;

1102}

1103

1104

1105

1106class CheapestVarSelector : public BaseObject {

1107 public:

1108 explicit CheapestVarSelector(std::function<int64_t(int64_t)> var_evaluator)

1109 : var_evaluator_(std::move(var_evaluator)) {}

1110 ~CheapestVarSelector() override {};

1111 int64_t Choose(Solver* s, const std::vector<IntVar*>& vars,

1112 int64_t first_unbound, int64_t last_unbound);

1113 std::string DebugString() const override { return "CheapestVarSelector"; }

1114

1115 private:

1116 std::function<int64_t(int64_t)> var_evaluator_;

1117};

1118

1119int64_t CheapestVarSelector::Choose(Solver* const,

1120 const std::vector<IntVar*>& vars,

1121 int64_t first_unbound,

1122 int64_t last_unbound) {

1123 int64_t best_eval = std::numeric_limits<int64_t>::max();

1124 int64_t index = -1;

1125 for (int64_t i = first_unbound; i <= last_unbound; ++i) {

1126 if (!vars[i]->Bound()) {

1127 const int64_t eval = var_evaluator_(i);

1128 if (eval < best_eval) {

1129 best_eval = eval;

1130 index = i;

1131 }

1132 }

1133 }

1134 return index;

1135}

1136

1137

1138

1139

1140class PathSelector : public BaseObject {

1141 public:

1142 PathSelector() : first_(std::numeric_limits<int64_t>::max()) {}

1143 ~PathSelector() override {};

1144 int64_t Choose(Solver* s, const std::vector<IntVar*>& vars);

1145 std::string DebugString() const override { return "ChooseNextOnPath"; }

1146

1147 private:

1148 bool UpdateIndex(const std::vector<IntVar*>& vars, int64_t* index) const;

1149 bool FindPathStart(const std::vector<IntVar*>& vars, int64_t* index) const;

1150

1151 Rev<int64_t> first_;

1152};

1153

1154int64_t PathSelector::Choose(Solver* const s,

1155 const std::vector<IntVar*>& vars) {

1156 int64_t index = first_.Value();

1157 if (!UpdateIndex(vars, &index)) {

1158 return -1;

1159 }

1160 int64_t count = 0;

1161 while (vars[index]->Bound()) {

1162 index = vars[index]->Value();

1163 if (!UpdateIndex(vars, &index)) {

1164 return -1;

1165 }

1166 ++count;

1167 if (count >= vars.size() &&

1168 !FindPathStart(vars, &index)) {

1169 return -1;

1170 }

1171 }

1172 first_.SetValue(s, index);

1173 return index;

1174}

1175

1176bool PathSelector::UpdateIndex(const std::vector<IntVar*>& vars,

1177 int64_t* index) const {

1178 if (*index >= vars.size()) {

1179 if (!FindPathStart(vars, index)) {

1180 return false;

1181 }

1182 }

1183 return true;

1184}

1185

1186

1187

1188

1189

1190

1191

1192bool PathSelector::FindPathStart(const std::vector<IntVar*>& vars,

1193 int64_t* index) const {

1194

1195 for (int64_t i = vars.size() - 1; i >= 0; --i) {

1196 if (vars[i]->Bound()) {

1197 const int64_t next = vars[i]->Value();

1198 if (next < vars.size() && !vars[next]->Bound()) {

1199 *index = next;

1200 return true;

1201 }

1202 }

1203 }

1204

1205 for (int64_t i = vars.size() - 1; i >= 0; --i) {

1206 if (!vars[i]->Bound()) {

1207 bool has_possible_prev = false;

1208 for (int64_t j = 0; j < vars.size(); ++j) {

1209 if (vars[j]->Contains(i)) {

1210 has_possible_prev = true;

1211 break;

1212 }

1213 }

1214 if (!has_possible_prev) {

1215 *index = i;

1216 return true;

1217 }

1218 }

1219 }

1220

1221 for (int64_t i = 0; i < vars.size(); ++i) {

1222 if (!vars[i]->Bound()) {

1223 *index = i;

1224 return true;

1225 }

1226 }

1227 return false;

1228}

1229

1230

1231

1232int64_t SelectMinValue(const IntVar* v, int64_t) { return v->Min(); }

1233

1234

1235

1236int64_t SelectMaxValue(const IntVar* v, int64_t) { return v->Max(); }

1237

1238

1239

1240int64_t SelectRandomValue(const IntVar* v, int64_t) {

1241 const uint64_t span = v->Max() - v->Min() + 1;

1242 if (span > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {

1243

1244 return v->Min();

1245 }

1246 const uint64_t size = v->Size();

1247 Solver* const s = v->solver();

1248 if (size > span / 4) {

1249

1250 for (;;) {

1251 const int64_t value = v->Min() + s->Rand64(span);

1252 if (v->Contains(value)) {

1253 return value;

1254 }

1255 }

1256 } else {

1257 int64_t index = s->Rand64(size);

1258 if (index <= size / 2) {

1259 for (int64_t i = v->Min(); i <= v->Max(); ++i) {

1260 if (v->Contains(i)) {

1261 if (--index == 0) {

1262 return i;

1263 }

1264 }

1265 }

1266 CHECK_LE(index, 0);

1267 } else {

1268 for (int64_t i = v->Max(); i > v->Min(); --i) {

1269 if (v->Contains(i)) {

1270 if (--index == 0) {

1271 return i;

1272 }

1273 }

1274 }

1275 CHECK_LE(index, 0);

1276 }

1277 }

1278 return 0;

1279}

1280

1281

1282

1283int64_t SelectCenterValue(const IntVar* v, int64_t) {

1284 const int64_t vmin = v->Min();

1285 const int64_t vmax = v->Max();

1286 if (vmax - vmin > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {

1287

1288 return vmin;

1289 }

1290 const int64_t mid = (vmin + vmax) / 2;

1291 if (v->Contains(mid)) {

1292 return mid;

1293 }

1294 const int64_t diameter = vmax - mid;

1295 for (int64_t i = 1; i <= diameter; ++i) {

1296 if (v->Contains(mid - i)) {

1297 return mid - i;

1298 }

1299 if (v->Contains(mid + i)) {

1300 return mid + i;

1301 }

1302 }

1303 return 0;

1304}

1305

1306

1307

1308int64_t SelectSplitValue(const IntVar* v, int64_t) {

1309 const int64_t vmin = v->Min();

1310 const int64_t vmax = v->Max();

1311 const uint64_t delta = vmax - vmin;

1312 const int64_t mid = vmin + delta / 2;

1313 return mid;

1314}

1315

1316

1317

1318class CheapestValueSelector : public BaseObject {

1319 public:

1320 CheapestValueSelector(std::function<int64_t(int64_t, int64_t)> eval,

1321 std::function<int64_t(int64_t)> tie_breaker)

1322 : eval_(std::move(eval)), tie_breaker_(std::move(tie_breaker)) {}

1323 ~CheapestValueSelector() override {}

1324 int64_t Select(const IntVar* v, int64_t id);

1325 std::string DebugString() const override { return "CheapestValue"; }

1326

1327 private:

1328 std::function<int64_t(int64_t, int64_t)> eval_;

1329 std::function<int64_t(int64_t)> tie_breaker_;

1330 std::vector<int64_t> cache_;

1331};

1332

1333int64_t CheapestValueSelector::Select(const IntVar* v, int64_t id) {

1334 cache_.clear();

1335 int64_t best = std::numeric_limits<int64_t>::max();

1336 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(false));

1337 for (const int64_t i : InitAndGetValues(it.get())) {

1338 int64_t eval = eval_(id, i);

1339 if (eval < best) {

1340 best = eval;

1341 cache_.clear();

1342 cache_.push_back(i);

1343 } else if (eval == best) {

1344 cache_.push_back(i);

1345 }

1346 }

1347 DCHECK_GT(cache_.size(), 0);

1348 if (tie_breaker_ == nullptr || cache_.size() == 1) {

1349 return cache_.back();

1350 } else {

1351 return cache_[tie_breaker_(cache_.size())];

1352 }

1353}

1354

1355

1356

1357

1358

1359

1360

1361

1362

1363class BestValueByComparisonSelector : public BaseObject {

1364 public:

1365 explicit BestValueByComparisonSelector(

1366 Solver::VariableValueComparator comparator)

1367 : comparator_(std::move(comparator)) {}

1368 ~BestValueByComparisonSelector() override {}

1369 int64_t Select(const IntVar* v, int64_t id);

1370 std::string DebugString() const override {

1371 return "BestValueByComparisonSelector";

1372 }

1373

1374 private:

1375 Solver::VariableValueComparator comparator_;

1376};

1377

1378int64_t BestValueByComparisonSelector::Select(const IntVar* v, int64_t id) {

1379 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(false));

1380 it->Init();

1381 DCHECK(it->Ok());

1382 int64_t best_value = it->Value();

1383 for (it->Next(); it->Ok(); it->Next()) {

1384 const int64_t candidate_value = it->Value();

1385 if (comparator_(id, candidate_value, best_value)) {

1386 best_value = candidate_value;

1387 }

1388 }

1389 return best_value;

1390}

1391

1392

1393

1394class VariableAssignmentSelector : public BaseVariableAssignmentSelector {

1395 public:

1396 VariableAssignmentSelector(Solver* solver, const std::vector<IntVar*>& vars,

1397 Solver::VariableIndexSelector var_selector,

1398 Solver::VariableValueSelector value_selector,

1399 const std::string& name)

1400 : BaseVariableAssignmentSelector(solver, vars),

1401 var_selector_(std::move(var_selector)),

1402 value_selector_(std::move(value_selector)),

1403 name_(name) {}

1404 ~VariableAssignmentSelector() override {}

1405 int64_t SelectValue(const IntVar* var, int64_t id) override {

1406 return value_selector_(var, id);

1407 }

1408 int64_t ChooseVariable() override {

1409 return var_selector_(solver_, vars_, first_unbound_.Value(),

1410 last_unbound_.Value());

1411 }

1412 std::string DebugString() const override;

1413

1414 private:

1415 Solver::VariableIndexSelector var_selector_;

1416 Solver::VariableValueSelector value_selector_;

1417 const std::string name_;

1418};

1419

1420std::string VariableAssignmentSelector::DebugString() const {

1421 return absl::StrFormat("%s(%s)", name_, JoinDebugStringPtr(vars_, ", "));

1422}

1423

1424

1425

1426class BaseEvaluatorSelector : public BaseVariableAssignmentSelector {

1427 public:

1428 BaseEvaluatorSelector(Solver* solver, const std::vector<IntVar*>& vars,

1429 std::function<int64_t(int64_t, int64_t)> evaluator);

1430 ~BaseEvaluatorSelector() override {}

1431

1432 protected:

1433 struct Element {

1434 Element() : var(0), value(0) {}

1435 Element(int64_t i, int64_t j) : var(i), value(j) {}

1436 int64_t var;

1437 int64_t value;

1438 };

1439

1440 std::string DebugStringInternal(absl::string_view name) const {

1441 return absl::StrFormat("%s(%s)", name, JoinDebugStringPtr(vars_, ", "));

1442 }

1443

1444 std::function<int64_t(int64_t, int64_t)> evaluator_;

1445};

1446

1447BaseEvaluatorSelector::BaseEvaluatorSelector(

1448 Solver* solver, const std::vector<IntVar*>& vars,

1449 std::function<int64_t(int64_t, int64_t)> evaluator)

1450 : BaseVariableAssignmentSelector(solver, vars),

1451 evaluator_(std::move(evaluator)) {}

1452

1453

1454

1455class DynamicEvaluatorSelector : public BaseEvaluatorSelector {

1456 public:

1457 DynamicEvaluatorSelector(Solver* solver, const std::vector<IntVar*>& vars,

1458 std::function<int64_t(int64_t, int64_t)> evaluator,

1459 std::function<int64_t(int64_t)> tie_breaker);

1460 ~DynamicEvaluatorSelector() override {}

1461 int64_t SelectValue(const IntVar* var, int64_t id) override;

1462 int64_t ChooseVariable() override;

1463 std::string DebugString() const override;

1464

1465 private:

1466 int64_t first_;

1467 std::function<int64_t(int64_t)> tie_breaker_;

1468 std::vector<Element> cache_;

1469};

1470

1471DynamicEvaluatorSelector::DynamicEvaluatorSelector(

1472 Solver* solver, const std::vector<IntVar*>& vars,

1473 std::function<int64_t(int64_t, int64_t)> evaluator,

1474 std::function<int64_t(int64_t)> tie_breaker)

1475 : BaseEvaluatorSelector(solver, vars, std::move(evaluator)),

1476 first_(-1),

1477 tie_breaker_(std::move(tie_breaker)) {}

1478

1479int64_t DynamicEvaluatorSelector::SelectValue(const IntVar*, int64_t) {

1480 return cache_[first_].value;

1481}

1482

1483int64_t DynamicEvaluatorSelector::ChooseVariable() {

1484 int64_t best_evaluation = std::numeric_limits<int64_t>::max();

1485 cache_.clear();

1486 for (int64_t i = 0; i < vars_.size(); ++i) {

1487 const IntVar* const var = vars_[i];

1488 if (!var->Bound()) {

1489 std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(false));

1490 for (const int64_t j : InitAndGetValues(it.get())) {

1491 const int64_t value = evaluator_(i, j);

1492 if (value < best_evaluation) {

1493 best_evaluation = value;

1494 cache_.clear();

1495 cache_.push_back(Element(i, j));

1496 } else if (value == best_evaluation && tie_breaker_) {

1497 cache_.push_back(Element(i, j));

1498 }

1499 }

1500 }

1501 }

1502

1503 if (cache_.empty()) {

1504 return -1;

1505 }

1506

1507 if (tie_breaker_ == nullptr || cache_.size() == 1) {

1508 first_ = 0;

1509 return cache_.front().var;

1510 } else {

1511 first_ = tie_breaker_(cache_.size());

1512 return cache_[first_].var;

1513 }

1514}

1515

1516std::string DynamicEvaluatorSelector::DebugString() const {

1517 return DebugStringInternal("AssignVariablesOnDynamicEvaluator");

1518}

1519

1520

1521

1522class StaticEvaluatorSelector : public BaseEvaluatorSelector {

1523 public:

1524 StaticEvaluatorSelector(

1525 Solver* solver, const std::vector<IntVar*>& vars,

1526 const std::function<int64_t(int64_t, int64_t)>& evaluator);

1527 ~StaticEvaluatorSelector() override {}

1528 int64_t SelectValue(const IntVar* var, int64_t id) override;

1529 int64_t ChooseVariable() override;

1530 std::string DebugString() const override;

1531

1532 private:

1533 class Compare {

1534 public:

1535 explicit Compare(std::function<int64_t(int64_t, int64_t)> evaluator)

1536 : evaluator_(std::move(evaluator)) {}

1537 bool operator()(const Element& lhs, const Element& rhs) const {

1538 const int64_t value_lhs = Value(lhs);

1539 const int64_t value_rhs = Value(rhs);

1540 return value_lhs < value_rhs ||

1541 (value_lhs == value_rhs &&

1542 (lhs.var < rhs.var ||

1543 (lhs.var == rhs.var && lhs.value < rhs.value)));

1544 }

1545 int64_t Value(const Element& element) const {

1546 return evaluator_(element.var, element.value);

1547 }

1548

1549 private:

1550 std::function<int64_t(int64_t, int64_t)> evaluator_;

1551 };

1552

1553 Compare comp_;

1554 std::vector<Element> elements_;

1555 int64_t first_;

1556};

1557

1558StaticEvaluatorSelector::StaticEvaluatorSelector(

1559 Solver* solver, const std::vector<IntVar*>& vars,

1560 const std::function<int64_t(int64_t, int64_t)>& evaluator)

1561 : BaseEvaluatorSelector(solver, vars, evaluator),

1562 comp_(evaluator),

1563 first_(-1) {}

1564

1565int64_t StaticEvaluatorSelector::SelectValue(const IntVar*, int64_t) {

1566 return elements_[first_].value;

1567}

1568

1569int64_t StaticEvaluatorSelector::ChooseVariable() {

1570 if (first_ == -1) {

1571

1572 int64_t element_size = 0;

1573 for (int64_t i = 0; i < vars_.size(); ++i) {

1574 if (!vars_[i]->Bound()) {

1575 element_size += vars_[i]->Size();

1576 }

1577 }

1578 elements_.resize(element_size);

1579 int count = 0;

1580 for (int i = 0; i < vars_.size(); ++i) {

1581 const IntVar* const var = vars_[i];

1582 if (!var->Bound()) {

1583 std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(false));

1584 for (const int64_t value : InitAndGetValues(it.get())) {

1585 elements_[count++] = Element(i, value);

1586 }

1587 }

1588 }

1589

1590 std::sort(elements_.begin(), elements_.end(), comp_);

1591 solver_->SaveAndSetValue<int64_t>(&first_, 0);

1592 }

1593 for (int64_t i = first_; i < elements_.size(); ++i) {

1594 const Element& element = elements_[i];

1595 IntVar* const var = vars_[element.var];

1596 if (!var->Bound() && var->Contains(element.value)) {

1597 solver_->SaveAndSetValue(&first_, i);

1598 return element.var;

1599 }

1600 }

1601 solver_->SaveAndSetValue(&first_, static_cast<int64_t>(elements_.size()));

1602 return -1;

1603}

1604

1605std::string StaticEvaluatorSelector::DebugString() const {

1606 return DebugStringInternal("AssignVariablesOnStaticEvaluator");

1607}

1608

1609

1610

1611class AssignOneVariableValue : public Decision {

1612 public:

1613 AssignOneVariableValue(IntVar* v, int64_t val);

1614 ~AssignOneVariableValue() override {}

1615 void Apply(Solver* s) override;

1616 void Refute(Solver* s) override;

1617 std::string DebugString() const override;

1618 void Accept(DecisionVisitor* const visitor) const override {

1619 visitor->VisitSetVariableValue(var_, value_);

1620 }

1621

1622 private:

1623 IntVar* const var_;

1624 int64_t value_;

1625};

1626

1627AssignOneVariableValue::AssignOneVariableValue(IntVar* const v, int64_t val)

1628 : var_(v), value_(val) {}

1629

1630std::string AssignOneVariableValue::DebugString() const {

1631 return absl::StrFormat("[%s == %d] or [%s != %d]", var_->DebugString(),

1633}

1634

1635void AssignOneVariableValue::Apply(Solver* const) { var_->SetValue(value_); }

1636

1637void AssignOneVariableValue::Refute(Solver* const) {

1639}

1640}

1641

1643 return RevAlloc(new AssignOneVariableValue(var, val));

1644}

1645

1646

1647

1648namespace {

1649class AssignOneVariableValueOrFail : public Decision {

1650 public:

1651 AssignOneVariableValueOrFail(IntVar* v, int64_t value);

1652 ~AssignOneVariableValueOrFail() override {}

1653 void Apply(Solver* s) override;

1654 void Refute(Solver* s) override;

1655 std::string DebugString() const override;

1656 void Accept(DecisionVisitor* const visitor) const override {

1657 visitor->VisitSetVariableValue(var_, value_);

1658 }

1659

1660 private:

1661 IntVar* const var_;

1662 const int64_t value_;

1663};

1664

1665AssignOneVariableValueOrFail::AssignOneVariableValueOrFail(IntVar* const v,

1666 int64_t value)

1667 : var_(v), value_(value) {}

1668

1669std::string AssignOneVariableValueOrFail::DebugString() const {

1670 return absl::StrFormat("[%s == %d] or fail", var_->DebugString(), value_);

1671}

1672

1673void AssignOneVariableValueOrFail::Apply(Solver* const) {

1675}

1676

1677void AssignOneVariableValueOrFail::Refute(Solver* const s) { s->Fail(); }

1678}

1679

1681 int64_t value) {

1682 return RevAlloc(new AssignOneVariableValueOrFail(var, value));

1683}

1684

1685

1686

1687namespace {

1688class AssignOneVariableValueDoNothing : public Decision {

1689 public:

1690 AssignOneVariableValueDoNothing(IntVar* const v, int64_t value)

1691 : var_(v), value_(value) {}

1692 ~AssignOneVariableValueDoNothing() override {}

1693 void Apply(Solver* const) override { var_->SetValue(value_); }

1694 void Refute(Solver* const) override {}

1695 std::string DebugString() const override {

1696 return absl::StrFormat("[%s == %d] or []", var_->DebugString(), value_);

1697 }

1698 void Accept(DecisionVisitor* const visitor) const override {

1699 visitor->VisitSetVariableValue(var_, value_);

1700 }

1701

1702 private:

1703 IntVar* const var_;

1704 const int64_t value_;

1705};

1706

1707}

1708

1710 int64_t value) {

1711 return RevAlloc(new AssignOneVariableValueDoNothing(var, value));

1712}

1713

1714

1715

1716namespace {

1717class SplitOneVariable : public Decision {

1718 public:

1719 SplitOneVariable(IntVar* v, int64_t val, bool start_with_lower_half);

1720 ~SplitOneVariable() override {}

1721 void Apply(Solver* s) override;

1722 void Refute(Solver* s) override;

1723 std::string DebugString() const override;

1724 void Accept(DecisionVisitor* const visitor) const override {

1725 visitor->VisitSplitVariableDomain(var_, value_, start_with_lower_half_);

1726 }

1727

1728 private:

1729 IntVar* const var_;

1730 const int64_t value_;

1731 const bool start_with_lower_half_;

1732};

1733

1734SplitOneVariable::SplitOneVariable(IntVar* const v, int64_t val,

1735 bool start_with_lower_half)

1736 : var_(v), value_(val), start_with_lower_half_(start_with_lower_half) {}

1737

1738std::string SplitOneVariable::DebugString() const {

1739 if (start_with_lower_half_) {

1740 return absl::StrFormat("[%s <= %d]", var_->DebugString(), value_);

1741 } else {

1742 return absl::StrFormat("[%s >= %d]", var_->DebugString(), value_);

1743 }

1744}

1745

1746void SplitOneVariable::Apply(Solver* const) {

1747 if (start_with_lower_half_) {

1748 var_->SetMax(value_);

1749 } else {

1750 var_->SetMin(value_ + 1);

1751 }

1752}

1753

1754void SplitOneVariable::Refute(Solver* const) {

1755 if (start_with_lower_half_) {

1756 var_->SetMin(value_ + 1);

1757 } else {

1758 var_->SetMax(value_);

1759 }

1760}

1761}

1762

1764 bool start_with_lower_half) {

1765 return RevAlloc(new SplitOneVariable(var, val, start_with_lower_half));

1766}

1767

1769 int64_t value) {

1771}

1772

1774 int64_t value) {

1776}

1777

1778

1779

1780namespace {

1781class AssignVariablesValues : public Decision {

1782 public:

1783

1784

1785

1786

1787 enum class RefutationBehavior { kForbidAssignment, kDoNothing, kFail };

1788 AssignVariablesValues(

1789 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values,

1790 RefutationBehavior refutation = RefutationBehavior::kForbidAssignment);

1791 ~AssignVariablesValues() override {}

1792 void Apply(Solver* s) override;

1793 void Refute(Solver* s) override;

1794 std::string DebugString() const override;

1795 void Accept(DecisionVisitor* const visitor) const override {

1796 for (int i = 0; i < vars_.size(); ++i) {

1797 visitor->VisitSetVariableValue(vars_[i], values_[i]);

1798 }

1799 }

1800

1801 virtual void Accept(ModelVisitor* const visitor) const {

1802 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);

1803 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,

1804 vars_);

1805 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);

1806 }

1807

1808 private:

1809 const std::vector<IntVar*> vars_;

1810 const std::vector<int64_t> values_;

1811 const RefutationBehavior refutation_;

1812};

1813

1814AssignVariablesValues::AssignVariablesValues(const std::vector<IntVar*>& vars,

1815 const std::vector<int64_t>& values,

1816 RefutationBehavior refutation)

1817 : vars_(vars), values_(values), refutation_(refutation) {}

1818

1819std::string AssignVariablesValues::DebugString() const {

1820 std::string out;

1821 if (vars_.empty()) out += "do nothing";

1822 for (int i = 0; i < vars_.size(); ++i) {

1823 absl::StrAppendFormat(&out, "[%s == %d]", vars_[i]->DebugString(),

1824 values_[i]);

1825 }

1826 switch (refutation_) {

1827 case RefutationBehavior::kForbidAssignment:

1828 out += " or forbid assignment";

1829 break;

1830 case RefutationBehavior::kDoNothing:

1831 out += " or do nothing";

1832 break;

1833 case RefutationBehavior::kFail:

1834 out += " or fail";

1835 break;

1836 }

1837 return out;

1838}

1839

1840void AssignVariablesValues::Apply(Solver* const) {

1841 if (vars_.empty()) return;

1842 vars_[0]->FreezeQueue();

1843 for (int i = 0; i < vars_.size(); ++i) {

1844 vars_[i]->SetValue(values_[i]);

1845 }

1846 vars_[0]->UnfreezeQueue();

1847}

1848

1849void AssignVariablesValues::Refute(Solver* const s) {

1850 switch (refutation_) {

1851 case RefutationBehavior::kForbidAssignment: {

1852 std::vector<IntVar*> terms;

1853 for (int i = 0; i < vars_.size(); ++i) {

1854 IntVar* term = s->MakeBoolVar();

1855 s->AddConstraint(s->MakeIsDifferentCstCt(vars_[i], values_[i], term));

1856 terms.push_back(term);

1857 }

1858 s->AddConstraint(s->MakeSumGreaterOrEqual(terms, 1));

1859 break;

1860 }

1861 case RefutationBehavior::kDoNothing: {

1862 break;

1863 }

1864 case RefutationBehavior::kFail: {

1865 s->Fail();

1866 break;

1867 }

1868 }

1869}

1870}

1871

1873 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values) {

1874 CHECK_EQ(vars.size(), values.size());

1875 return RevAlloc(new AssignVariablesValues(

1876 vars, values,

1877 AssignVariablesValues::RefutationBehavior::kForbidAssignment));

1878}

1879

1881 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values) {

1882 CHECK_EQ(vars.size(), values.size());

1883 return RevAlloc(new AssignVariablesValues(

1884 vars, values, AssignVariablesValues::RefutationBehavior::kDoNothing));

1885}

1886

1888 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values) {

1889 CHECK_EQ(vars.size(), values.size());

1890 return RevAlloc(new AssignVariablesValues(

1891 vars, values, AssignVariablesValues::RefutationBehavior::kFail));

1892}

1893

1894

1895

1896namespace {

1898 public:

1899 enum Mode {

1900 ASSIGN,

1901 SPLIT_LOWER,

1902 SPLIT_UPPER,

1903 };

1904

1905 BaseAssignVariables(BaseVariableAssignmentSelector* const selector, Mode mode)

1906 : selector_(selector), mode_(mode) {}

1907

1908 ~BaseAssignVariables() override;

1909 Decision* Next(Solver* s) override;

1910 std::string DebugString() const override;

1911 static BaseAssignVariables* MakePhase(

1912 Solver* s, const std::vector<IntVar*>& vars,

1913 Solver::VariableIndexSelector var_selector,

1914 Solver::VariableValueSelector value_selector,

1915 const std::string& value_selector_name, BaseAssignVariables::Mode mode);

1916

1917 static Solver::VariableIndexSelector MakeVariableSelector(

1918 Solver* const s, const std::vector<IntVar*>& vars,

1919 Solver::IntVarStrategy str) {

1920 switch (str) {

1921 case Solver::INT_VAR_DEFAULT:

1922 case Solver::INT_VAR_SIMPLE:

1923 case Solver::CHOOSE_FIRST_UNBOUND:

1924 return ChooseFirstUnbound;

1925 case Solver::CHOOSE_RANDOM:

1926 return ChooseRandom;

1927 case Solver::CHOOSE_MIN_SIZE_LOWEST_MIN:

1928 return ChooseMinSizeLowestMin;

1929 case Solver::CHOOSE_MIN_SIZE_HIGHEST_MIN:

1930 return ChooseMinSizeHighestMin;

1931 case Solver::CHOOSE_MIN_SIZE_LOWEST_MAX:

1932 return ChooseMinSizeLowestMax;

1933 case Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX:

1934 return ChooseMinSizeHighestMax;

1935 case Solver::CHOOSE_LOWEST_MIN:

1936 return ChooseLowestMin;

1937 case Solver::CHOOSE_HIGHEST_MAX:

1938 return ChooseHighestMax;

1939 case Solver::CHOOSE_MIN_SIZE:

1940 return ChooseMinSize;

1941 case Solver::CHOOSE_MAX_SIZE:

1942 return ChooseMaxSize;

1943 case Solver::CHOOSE_MAX_REGRET_ON_MIN: {

1944 HighestRegretSelectorOnMin* const selector =

1945 s->RevAlloc(new HighestRegretSelectorOnMin(vars));

1946 return [selector](Solver* solver, const std::vector<IntVar*>& vars,

1947 int first_unbound, int last_unbound) {

1948 return selector->Choose(solver, vars, first_unbound, last_unbound);

1949 };

1950 }

1951 case Solver::CHOOSE_PATH: {

1952 PathSelector* const selector = s->RevAlloc(new PathSelector());

1953 return [selector](Solver* solver, const std::vector<IntVar*>& vars, int,

1954 int) { return selector->Choose(solver, vars); };

1955 }

1956 default:

1957 LOG(FATAL) << "Unknown int var strategy " << str;

1958 return nullptr;

1959 }

1960 }

1961

1962 static Solver::VariableValueSelector MakeValueSelector(

1963 Solver* const, Solver::IntValueStrategy val_str) {

1964 switch (val_str) {

1965 case Solver::INT_VALUE_DEFAULT:

1966 case Solver::INT_VALUE_SIMPLE:

1967 case Solver::ASSIGN_MIN_VALUE:

1968 return SelectMinValue;

1969 case Solver::ASSIGN_MAX_VALUE:

1970 return SelectMaxValue;

1971 case Solver::ASSIGN_RANDOM_VALUE:

1972 return SelectRandomValue;

1973 case Solver::ASSIGN_CENTER_VALUE:

1974 return SelectCenterValue;

1975 case Solver::SPLIT_LOWER_HALF:

1976 return SelectSplitValue;

1977 case Solver::SPLIT_UPPER_HALF:

1978 return SelectSplitValue;

1979 default:

1980 LOG(FATAL) << "Unknown int value strategy " << val_str;

1981 return nullptr;

1982 }

1983 }

1984

1985 void Accept(ModelVisitor* const visitor) const override {

1986 selector_->Accept(visitor);

1987 }

1988

1989 protected:

1990 BaseVariableAssignmentSelector* const selector_;

1991 const Mode mode_;

1992};

1993

1994BaseAssignVariables::~BaseAssignVariables() {}

1995

1996Decision* BaseAssignVariables::Next(Solver* const s) {

1997 const std::vector<IntVar*>& vars = selector_->vars();

1998 int id = selector_->ChooseVariableWrapper();

1999 if (id >= 0 && id < vars.size()) {

2000 IntVar* const var = vars[id];

2001 const int64_t value = selector_->SelectValue(var, id);

2002 switch (mode_) {

2003 case ASSIGN:

2004 return s->RevAlloc(new AssignOneVariableValue(var, value));

2005 case SPLIT_LOWER:

2006 return s->RevAlloc(new SplitOneVariable(var, value, true));

2007 case SPLIT_UPPER:

2008 return s->RevAlloc(new SplitOneVariable(var, value, false));

2009 }

2010 }

2011 return nullptr;

2012}

2013

2014std::string BaseAssignVariables::DebugString() const {

2015 return selector_->DebugString();

2016}

2017

2018BaseAssignVariables* BaseAssignVariables::MakePhase(

2019 Solver* const s, const std::vector<IntVar*>& vars,

2022 const std::string& value_selector_name, BaseAssignVariables::Mode mode) {

2023 BaseVariableAssignmentSelector* const selector =

2024 s->RevAlloc(new VariableAssignmentSelector(

2025 s, vars, std::move(var_selector), std::move(value_selector),

2026 value_selector_name));

2027 return s->RevAlloc(new BaseAssignVariables(selector, mode));

2028}

2029

2031 switch (var_str) {

2035 return "ChooseFirstUnbound";

2037 return "ChooseRandom";

2039 return "ChooseMinSizeLowestMin";

2041 return "ChooseMinSizeHighestMin";

2043 return "ChooseMinSizeLowestMax";

2045 return "ChooseMinSizeHighestMax";

2047 return "ChooseLowestMin";

2049 return "ChooseHighestMax";

2051 return "ChooseMinSize";

2053 return "ChooseMaxSize;";

2055 return "HighestRegretSelectorOnMin";

2057 return "PathSelector";

2058 default:

2059 LOG(FATAL) << "Unknown int var strategy " << var_str;

2060 return "";

2061 }

2062}

2063

2065 switch (val_str) {

2069 return "SelectMinValue";

2071 return "SelectMaxValue";

2073 return "SelectRandomValue";

2075 return "SelectCenterValue";

2077 return "SelectSplitValue";

2079 return "SelectSplitValue";

2080 default:

2081 LOG(FATAL) << "Unknown int value strategy " << val_str;

2082 return "";

2083 }

2084}

2085

2088 return ChooseVariableName(var_str) + "_" + SelectValueName(val_str);

2089}

2090}

2091

2095 std::vector<IntVar*> vars(1);

2096 vars[0] = v0;

2097 return MakePhase(vars, var_str, val_str);

2098}

2099

2103 std::vector<IntVar*> vars(2);

2104 vars[0] = v0;

2105 vars[1] = v1;

2106 return MakePhase(vars, var_str, val_str);

2107}

2108

2113 std::vector<IntVar*> vars(3);

2114 vars[0] = v0;

2115 vars[1] = v1;

2116 vars[2] = v2;

2117 return MakePhase(vars, var_str, val_str);

2118}

2119

2124 std::vector<IntVar*> vars(4);

2125 vars[0] = v0;

2126 vars[1] = v1;

2127 vars[2] = v2;

2128 vars[3] = v3;

2129 return MakePhase(vars, var_str, val_str);

2130}

2131

2133 BaseAssignVariables::Mode mode = BaseAssignVariables::ASSIGN;

2135 mode = BaseAssignVariables::SPLIT_LOWER;

2137 mode = BaseAssignVariables::SPLIT_UPPER;

2138 }

2139 return mode;

2140}

2141

2145 return BaseAssignVariables::MakePhase(

2146 this, vars,

2147 BaseAssignVariables::MakeVariableSelector(this, vars, var_str),

2148 BaseAssignVariables::MakeValueSelector(this, val_str),

2149 BuildHeuristicsName(var_str, val_str),

2151}

2152

2156 CHECK(var_evaluator != nullptr);

2157 CheapestVarSelector* const var_selector =

2158 RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));

2159 return BaseAssignVariables::MakePhase(

2160 this, vars,

2161

2162 [var_selector](Solver* solver, const std::vector<IntVar*>& vars,

2163 int first_unbound, int last_unbound) {

2164 return var_selector->Choose(solver, vars, first_unbound, last_unbound);

2165 },

2166 BaseAssignVariables::MakeValueSelector(this, val_str),

2167 "ChooseCheapestVariable_" +

2168 SelectValueName(val_str),

2170}

2171

2175 CheapestValueSelector* const value_selector =

2176 RevAlloc(new CheapestValueSelector(std::move(value_evaluator), nullptr));

2177 return BaseAssignVariables::MakePhase(

2178 this, vars,

2179

2180 BaseAssignVariables::MakeVariableSelector(this, vars, var_str),

2181

2182 [value_selector](const IntVar* var, int64_t id) {

2183 return value_selector->Select(var, id);

2184 },

2185 ChooseVariableName(var_str) +

2186 "_SelectCheapestValue",

2187 BaseAssignVariables::ASSIGN);

2188}

2189

2191 const std::vector<IntVar*>& vars, IntVarStrategy var_str,

2193 BestValueByComparisonSelector* const value_selector = RevAlloc(

2194 new BestValueByComparisonSelector(std::move(var_val1_val2_comparator)));

2195 return BaseAssignVariables::MakePhase(

2196 this, vars,

2197 BaseAssignVariables::MakeVariableSelector(this, vars, var_str),

2198

2199 [value_selector](const IntVar* var, int64_t id) {

2200 return value_selector->Select(var, id);

2201 },

2202 "CheapestValue", BaseAssignVariables::ASSIGN);

2203}

2204

2208 CheapestVarSelector* const var_selector =

2209 RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));

2210 CheapestValueSelector* value_selector =

2211 RevAlloc(new CheapestValueSelector(std::move(value_evaluator), nullptr));

2212 return BaseAssignVariables::MakePhase(

2213 this, vars,

2214 [var_selector](Solver* solver, const std::vector<IntVar*>& vars,

2215 int first_unbound, int last_unbound) {

2216 return var_selector->Choose(solver, vars, first_unbound, last_unbound);

2217 },

2218

2219 [value_selector](const IntVar* var, int64_t id) {

2220 return value_selector->Select(var, id);

2221 },

2222 "CheapestValue", BaseAssignVariables::ASSIGN);

2223}

2224

2229 CheapestValueSelector* value_selector = RevAlloc(new CheapestValueSelector(

2230 std::move(value_evaluator), std::move(tie_breaker)));

2231 return BaseAssignVariables::MakePhase(

2232 this, vars,

2233 BaseAssignVariables::MakeVariableSelector(this, vars, var_str),

2234

2235 [value_selector](const IntVar* var, int64_t id) {

2236 return value_selector->Select(var, id);

2237 },

2238 "CheapestValue", BaseAssignVariables::ASSIGN);

2239}

2240

2245 CheapestVarSelector* const var_selector =

2246 RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));

2247 CheapestValueSelector* value_selector = RevAlloc(new CheapestValueSelector(

2248 std::move(value_evaluator), std::move(tie_breaker)));

2249 return BaseAssignVariables::MakePhase(

2250 this, vars,

2251 [var_selector](Solver* solver, const std::vector<IntVar*>& vars,

2252 int first_unbound, int last_unbound) {

2253 return var_selector->Choose(solver, vars, first_unbound, last_unbound);

2254 },

2255

2256 [value_selector](const IntVar* var, int64_t id) {

2257 return value_selector->Select(var, id);

2258 },

2259 "CheapestValue", BaseAssignVariables::ASSIGN);

2260}

2261

2265 return MakePhase(vars, std::move(eval), nullptr, str);

2266}

2267

2272 BaseVariableAssignmentSelector* selector = nullptr;

2273 switch (str) {

2275

2276 selector =

2277 RevAlloc(new StaticEvaluatorSelector(this, vars, std::move(eval)));

2278 break;

2279 }

2281 selector = RevAlloc(new DynamicEvaluatorSelector(

2282 this, vars, std::move(eval), std::move(tie_breaker)));

2283 break;

2284 }

2285 }

2287 new BaseAssignVariables(selector, BaseAssignVariables::ASSIGN));

2288}

2289

2290

2291

2292namespace {

2293class AssignVariablesFromAssignment : public DecisionBuilder {

2294 public:

2295 AssignVariablesFromAssignment(const Assignment* const assignment,

2297 const std::vector<IntVar*>& vars)

2298 : assignment_(assignment), db_(db), vars_(vars), iter_(0) {}

2299

2300 ~AssignVariablesFromAssignment() override {}

2301

2302 Decision* Next(Solver* const s) override {

2303 if (iter_ < vars_.size()) {

2304 IntVar* const var = vars_[iter_++];

2305 return s->RevAlloc(

2306 new AssignOneVariableValue(var, assignment_->Value(var)));

2307 } else {

2308 return db_->Next(s);

2309 }

2310 }

2311

2312 void Accept(ModelVisitor* const visitor) const override {

2313 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);

2314 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,

2315 vars_);

2316 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);

2317 }

2318

2319 private:

2320 const Assignment* const assignment_;

2321 DecisionBuilder* const db_;

2322 const std::vector<IntVar*> vars_;

2323 int iter_;

2324};

2325}

2326

2329 const std::vector<IntVar*>& vars) {

2330 return RevAlloc(new AssignVariablesFromAssignment(assignment, db, vars));

2331}

2332

2333

2334

2335

2336

2342

2345

2347

2351

2353 int index) const {

2354 return solution != nullptr ? solution->ObjectiveValueFromIndex(index) : 0;

2355}

2356

2360 const auto other_fields =

2362 if (fields != other_fields) return fields < other_fields;

2364 DCHECK_EQ(other.solution, nullptr);

2365 return false;

2366 }

2367 for (int i = 0; i < solution->NumObjectives(); ++i) {

2368 const int64_t value = solution->ObjectiveValueFromIndex(i);

2370 if (value != other_value) return value < other_value;

2371 }

2372 return false;

2373}

2374

2378

2384

2390

2396

2402

2408

2414

2416 if (prototype_ != nullptr && objective != nullptr) {

2417 prototype_->AddObjective(objective);

2418 }

2419}

2420

2423 prototype_->AddObjectives(objectives);

2424 }

2425}

2426

2431

2435

2442

2449 DCHECK(solution != nullptr);

2451 } else {

2454 }

2456 }

2462 return data;

2463}

2464

2470

2472 CHECK_GE(n, 0) << "wrong index in solution getter";

2473 CHECK_LT(n, solution_data_.size()) << "wrong index in solution getter";

2474}

2475

2480

2484

2486

2488

2493

2498

2503

2508

2513

2517

2521

2525

2529

2533

2538

2543

2548

2549namespace {

2550

2551

2552

2554 public:

2556 explicit FirstSolutionCollector(Solver* s);

2557 ~FirstSolutionCollector() override;

2558 void EnterSearch() override;

2559 bool AtSolution() override;

2560 void Install() override;

2561 std::string DebugString() const override;

2562

2563 private:

2564 bool done_;

2565};

2566

2567FirstSolutionCollector::FirstSolutionCollector(Solver* const s,

2568 const Assignment* const a)

2570

2571FirstSolutionCollector::FirstSolutionCollector(Solver* const s)

2573

2574FirstSolutionCollector::~FirstSolutionCollector() {}

2575

2576void FirstSolutionCollector::EnterSearch() {

2577 SolutionCollector::EnterSearch();

2578 done_ = false;

2579}

2580

2581bool FirstSolutionCollector::AtSolution() {

2582 if (!done_) {

2583 PushSolution();

2584 done_ = true;

2585 }

2586 return false;

2587}

2588

2589void FirstSolutionCollector::Install() {

2590 SolutionCollector::Install();

2591 ListenToEvent(Solver::MonitorEvent::kAtSolution);

2592}

2593

2594std::string FirstSolutionCollector::DebugString() const {

2595 if (prototype_ == nullptr) {

2596 return "FirstSolutionCollector()";

2597 } else {

2598 return "FirstSolutionCollector(" + prototype_->DebugString() + ")";

2599 }

2600}

2601}

2602

2604 const Assignment* const assignment) {

2605 return RevAlloc(new FirstSolutionCollector(this, assignment));

2606}

2607

2609 return RevAlloc(new FirstSolutionCollector(this));

2610}

2611

2612

2613

2614

2615namespace {

2617 public:

2619 explicit LastSolutionCollector(Solver* s);

2620 ~LastSolutionCollector() override;

2621 bool AtSolution() override;

2622 void Install() override;

2623 std::string DebugString() const override;

2624};

2625

2626LastSolutionCollector::LastSolutionCollector(Solver* const s,

2627 const Assignment* const a)

2628 : SolutionCollector(s, a) {}

2629

2630LastSolutionCollector::LastSolutionCollector(Solver* const s)

2632

2633LastSolutionCollector::~LastSolutionCollector() {}

2634

2635bool LastSolutionCollector::AtSolution() {

2636 PopSolution();

2637 PushSolution();

2638 return true;

2639}

2640

2641void LastSolutionCollector::Install() {

2642 SolutionCollector::Install();

2643 ListenToEvent(Solver::MonitorEvent::kAtSolution);

2644}

2645

2646std::string LastSolutionCollector::DebugString() const {

2647 if (prototype_ == nullptr) {

2648 return "LastSolutionCollector()";

2649 } else {

2650 return "LastSolutionCollector(" + prototype_->DebugString() + ")";

2651 }

2652}

2653}

2654

2656 const Assignment* const assignment) {

2657 return RevAlloc(new LastSolutionCollector(this, assignment));

2658}

2659

2661 return RevAlloc(new LastSolutionCollector(this));

2662}

2663

2664

2665

2666namespace {

2668 public:

2669 BestValueSolutionCollector(Solver* solver, const Assignment* assignment,

2670 std::vector<bool> maximize);

2671 BestValueSolutionCollector(Solver* solver, std::vector<bool> maximize);

2672 ~BestValueSolutionCollector() override {}

2673 void EnterSearch() override;

2674 bool AtSolution() override;

2675 void Install() override;

2676 std::string DebugString() const override;

2677

2678 private:

2679 void ResetBestObjective() {

2680 for (int i = 0; i < maximize_.size(); ++i) {

2681 best_[i] = maximize_[i] ? std::numeric_limits<int64_t>::min()

2682 : std::numeric_limits<int64_t>::max();

2683 }

2684 }

2685

2686 const std::vector<bool> maximize_;

2687 std::vector<int64_t> best_;

2688};

2689

2690BestValueSolutionCollector::BestValueSolutionCollector(

2691 Solver* solver, const Assignment* assignment, std::vector<bool> maximize)

2692 : SolutionCollector(solver, assignment),

2693 maximize_(std::move(maximize)),

2694 best_(maximize_.size()) {

2695 ResetBestObjective();

2696}

2697

2698BestValueSolutionCollector::BestValueSolutionCollector(

2699 Solver* solver, std::vector<bool> maximize)

2701 maximize_(std::move(maximize)),

2702 best_(maximize_.size()) {

2703 ResetBestObjective();

2704}

2705

2706void BestValueSolutionCollector::EnterSearch() {

2707 SolutionCollector::EnterSearch();

2708 ResetBestObjective();

2709}

2710

2711bool BestValueSolutionCollector::AtSolution() {

2712 if (prototype_ != nullptr && prototype_->HasObjective()) {

2713 const int size = std::min(prototype_->NumObjectives(),

2714 static_cast<int>(maximize_.size()));

2715

2716

2717 bool is_improvement = false;

2718 for (int i = 0; i < size; ++i) {

2719 const IntVar* objective = prototype_->ObjectiveFromIndex(i);

2720 const int64_t objective_value =

2721 maximize_[i] ? CapOpp(objective->Max()) : objective->Min();

2722 if (objective_value < best_[i]) {

2723 is_improvement = true;

2724 break;

2725 } else if (objective_value > best_[i]) {

2726 break;

2727 }

2728 }

2729 if (solution_count() == 0 || is_improvement) {

2730 PopSolution();

2731 PushSolution();

2732 for (int i = 0; i < size; ++i) {

2733 best_[i] = maximize_[i]

2734 ? CapOpp(prototype_->ObjectiveFromIndex(i)->Max())

2735 : prototype_->ObjectiveFromIndex(i)->Min();

2736 }

2737 }

2738 }

2739 return true;

2740}

2741

2742void BestValueSolutionCollector::Install() {

2743 SolutionCollector::Install();

2744 ListenToEvent(Solver::MonitorEvent::kAtSolution);

2745}

2746

2747std::string BestValueSolutionCollector::DebugString() const {

2748 if (prototype_ == nullptr) {

2749 return "BestValueSolutionCollector()";

2750 } else {

2751 return "BestValueSolutionCollector(" + prototype_->DebugString() + ")";

2752 }

2753}

2754}

2755

2757 const Assignment* const assignment, bool maximize) {

2758 return RevAlloc(new BestValueSolutionCollector(this, assignment, {maximize}));

2759}

2760

2762 const Assignment* assignment, std::vector<bool> maximize) {

2764 new BestValueSolutionCollector(this, assignment, std::move(maximize)));

2765}

2766

2768 return RevAlloc(new BestValueSolutionCollector(this, {maximize}));

2769}

2770

2772 std::vector<bool> maximize) {

2773 return RevAlloc(new BestValueSolutionCollector(this, std::move(maximize)));

2774}

2775

2776

2777

2778namespace {

2780 public:

2781 NBestValueSolutionCollector(Solver* solver, const Assignment* assignment,

2782 int solution_count, std::vector<bool> maximize);

2783 NBestValueSolutionCollector(Solver* solver, int solution_count,

2784 std::vector<bool> maximize);

2785 ~NBestValueSolutionCollector() override { Clear(); }

2786 void EnterSearch() override;

2787 void ExitSearch() override;

2788 bool AtSolution() override;

2789 void Install() override;

2790 std::string DebugString() const override;

2791

2792 private:

2793 void Clear();

2794

2795 const std::vector<bool> maximize_;

2796 std::priority_queue<std::pair<std::vector<int64_t>, SolutionData>>

2797 solutions_pq_;

2798 const int solution_count_;

2799};

2800

2801NBestValueSolutionCollector::NBestValueSolutionCollector(

2802 Solver* solver, const Assignment* assignment, int solution_count,

2803 std::vector<bool> maximize)

2804 : SolutionCollector(solver, assignment),

2805 maximize_(std::move(maximize)),

2806 solution_count_(solution_count) {}

2807

2808NBestValueSolutionCollector::NBestValueSolutionCollector(

2809 Solver* solver, int solution_count, std::vector<bool> maximize)

2811 maximize_(std::move(maximize)),

2812 solution_count_(solution_count) {}

2813

2814void NBestValueSolutionCollector::EnterSearch() {

2815 SolutionCollector::EnterSearch();

2816

2817

2818 if (solution_count_ > 1) {

2819 solver()->SetUseFastLocalSearch(false);

2820 }

2821 Clear();

2822}

2823

2824void NBestValueSolutionCollector::ExitSearch() {

2825 while (!solutions_pq_.empty()) {

2826 Push(solutions_pq_.top().second);

2827 solutions_pq_.pop();

2828 }

2829}

2830

2831bool NBestValueSolutionCollector::AtSolution() {

2832 if (prototype_ != nullptr && prototype_->HasObjective()) {

2833 const int size = std::min(prototype_->NumObjectives(),

2834 static_cast<int>(maximize_.size()));

2835 std::vector<int64_t> objective_values(size);

2836 for (int i = 0; i < size; ++i) {

2837 objective_values[i] =

2838 maximize_[i] ? CapOpp(prototype_->ObjectiveFromIndex(i)->Max())

2839 : prototype_->ObjectiveFromIndex(i)->Min();

2840 }

2841 if (solutions_pq_.size() < solution_count_) {

2842 solutions_pq_.push(

2843 {std::move(objective_values), BuildSolutionDataForCurrentState()});

2844 } else if (!solutions_pq_.empty()) {

2845 const auto& [top_obj_value, top_sol_data] = solutions_pq_.top();

2846 if (std::lexicographical_compare(

2847 objective_values.begin(), objective_values.end(),

2848 top_obj_value.begin(), top_obj_value.end())) {

2849 FreeSolution(top_sol_data.solution);

2850 solutions_pq_.pop();

2851 solutions_pq_.push(

2852 {std::move(objective_values), BuildSolutionDataForCurrentState()});

2853 }

2854 }

2855 }

2856 return true;

2857}

2858

2859void NBestValueSolutionCollector::Install() {

2860 SolutionCollector::Install();

2861 ListenToEvent(Solver::MonitorEvent::kExitSearch);

2862 ListenToEvent(Solver::MonitorEvent::kAtSolution);

2863}

2864

2865std::string NBestValueSolutionCollector::DebugString() const {

2866 if (prototype_ == nullptr) {

2867 return "NBestValueSolutionCollector()";

2868 } else {

2869 return "NBestValueSolutionCollector(" + prototype_->DebugString() + ")";

2870 }

2871}

2872

2873void NBestValueSolutionCollector::Clear() {

2874 while (!solutions_pq_.empty()) {

2875 delete solutions_pq_.top().second.solution;

2876 solutions_pq_.pop();

2877 }

2878}

2879

2880}

2881

2883 const Assignment* assignment, int solution_count, bool maximize) {

2884 if (solution_count == 1) {

2886 }

2887 return RevAlloc(new NBestValueSolutionCollector(this, assignment,

2888 solution_count, {maximize}));

2889}

2890

2892 bool maximize) {

2893 if (solution_count == 1) {

2895 }

2897 new NBestValueSolutionCollector(this, solution_count, {maximize}));

2898}

2899

2901 const Assignment* assignment, int solution_count,

2902 std::vector<bool> maximize) {

2903 if (solution_count == 1) {

2905 std::move(maximize));

2906 }

2907 return RevAlloc(new NBestValueSolutionCollector(

2908 this, assignment, solution_count, std::move(maximize)));

2909}

2910

2912 int solution_count, std::vector<bool> maximize) {

2913 if (solution_count == 1) {

2915 }

2916 return RevAlloc(new NBestValueSolutionCollector(this, solution_count,

2917 std::move(maximize)));

2918}

2919

2920

2921

2922namespace {

2924 public:

2926 explicit AllSolutionCollector(Solver* s);

2927 ~AllSolutionCollector() override;

2928 bool AtSolution() override;

2929 void Install() override;

2930 std::string DebugString() const override;

2931};

2932

2933AllSolutionCollector::AllSolutionCollector(Solver* const s,

2934 const Assignment* const a)

2935 : SolutionCollector(s, a) {}

2936

2937AllSolutionCollector::AllSolutionCollector(Solver* const s)

2939

2940AllSolutionCollector::~AllSolutionCollector() {}

2941

2942bool AllSolutionCollector::AtSolution() {

2943 PushSolution();

2944 return true;

2945}

2946

2947void AllSolutionCollector::Install() {

2948 SolutionCollector::Install();

2949 ListenToEvent(Solver::MonitorEvent::kAtSolution);

2950}

2951

2952std::string AllSolutionCollector::DebugString() const {

2953 if (prototype_ == nullptr) {

2954 return "AllSolutionCollector()";

2955 } else {

2956 return "AllSolutionCollector(" + prototype_->DebugString() + ")";

2957 }

2958}

2959}

2960

2962 const Assignment* const assignment) {

2963 return RevAlloc(new AllSolutionCollector(this, assignment));

2964}

2965

2967 return RevAlloc(new AllSolutionCollector(this));

2968}

2969

2970

2971

2973 public:

2975 std::vector<BaseObjectiveMonitor*> monitors,

2976 int num_max_local_optima_before_metaheuristic_switch)

2978 monitors_(std::move(monitors)),

2979 enabled_monitors_(monitors_.size(), true),

2980 local_optimum_limit_(num_max_local_optima_before_metaheuristic_switch) {

2981 }

2983 active_monitor_ = 0;

2984 num_local_optimum_ = 0;

2985 enabled_monitors_.assign(monitors_.size(), true);

2986 for (auto& monitor : monitors_) {

2987 monitor->set_active(monitor == monitors_[active_monitor_]);

2988 monitor->EnterSearch();

2989 }

2990 }

2992 monitors_[active_monitor_]->ApplyDecision(d);

2993 }

2995 monitors_[active_monitor_]->AcceptNeighbor();

2996 }

2998 bool ok = true;

2999 for (auto& monitor : monitors_) {

3000 ok &= monitor->AtSolution();

3001 }

3002 return ok;

3003 }

3005 return monitors_[active_monitor_]->AcceptDelta(delta, deltadelta);

3006 }

3008 monitors_[active_monitor_]->BeginNextDecision(db);

3009 }

3011 monitors_[active_monitor_]->RefuteDecision(d);

3012 }

3014 return monitors_[active_monitor_]->AcceptSolution();

3015 }

3017 const bool ok = monitors_[active_monitor_]->AtLocalOptimum();

3018 if (!ok) {

3019 enabled_monitors_[active_monitor_] = false;

3020 }

3021 if (++num_local_optimum_ >= local_optimum_limit_ || !ok) {

3022 monitors_[active_monitor_]->set_active(false);

3023 int next_active_monitor = (active_monitor_ + 1) % monitors_.size();

3024 while (!enabled_monitors_[next_active_monitor]) {

3025 if (next_active_monitor == active_monitor_) return false;

3026 next_active_monitor = (active_monitor_ + 1) % monitors_.size();

3027 }

3028 active_monitor_ = next_active_monitor;

3029 monitors_[active_monitor_]->set_active(true);

3030 num_local_optimum_ = 0;

3031 VLOG(2) << "Switching to monitor " << active_monitor_ << " "

3032 << monitors_[active_monitor_]->DebugString();

3033 }

3034 return true;

3035 }

3037 return monitors_[active_monitor_]->ObjectiveVar(index);

3038 }

3040 return monitors_[active_monitor_]->MinimizationVar(index);

3041 }

3042 int64_t Step(int index) const override {

3043 return monitors_[active_monitor_]->Step(index);

3044 }

3046 return monitors_[active_monitor_]->Maximize(index);

3047 }

3049 return monitors_[active_monitor_]->BestValue(index);

3050 }

3051 int Size() const override { return monitors_[active_monitor_]->Size(); }

3053 return monitors_[active_monitor_]->DebugString();

3054 }

3056

3057 for (auto& monitor : monitors_) {

3058 monitor->Accept(visitor);

3059 }

3060 }

3061

3062 private:

3063 const std::vector<BaseObjectiveMonitor*> monitors_;

3064 std::vector<bool> enabled_monitors_;

3065 int active_monitor_ = 0;

3066 int num_local_optimum_ = 0;

3067 const int local_optimum_limit_;

3068};

3069

3071 std::vector<BaseObjectiveMonitor*> monitors,

3072 int num_max_local_optima_before_metaheuristic_switch) {

3074 std::move(monitors), num_max_local_optima_before_metaheuristic_switch));

3075}

3076

3078 const std::vector<bool>& maximize,

3079 std::vector<IntVar*> vars,

3080 std::vector<int64_t> steps)

3083 objective_vars_(std::move(vars)),

3084 minimization_vars_(objective_vars_),

3085 upper_bounds_(Size() + 1, nullptr),

3086 steps_(std::move(steps)),

3087 best_values_(Size(), std::numeric_limits<int64_t>::max()),

3088 current_values_(Size(), std::numeric_limits<int64_t>::max()) {

3089 DCHECK_GT(Size(), 0);

3090 DCHECK_EQ(objective_vars_.size(), steps_.size());

3091 DCHECK_EQ(objective_vars_.size(), maximize.size());

3092 DCHECK(std::all_of(steps_.begin(), steps_.end(),

3093 [](int64_t step) { return step > 0; }));

3094 for (int i = 0; i < Size(); ++i) {

3095 if (maximize[i]) {

3096 minimization_vars_[i] = solver->MakeOpposite(objective_vars_[i])->Var();

3097 }

3098 }

3099

3100 minimization_vars_.push_back(solver->MakeIntConst(1));

3101 upper_bounds_.back() = solver->MakeIntConst(0);

3102 steps_.push_back(1);

3103

3104

3105

3106

3109}

3110

3113 best_values_.assign(Size(), std::numeric_limits<int64_t>::max());

3114 current_values_ = best_values_;

3116}

3117

3119 for (int i = 0; i < Size(); ++i) {

3120 if (VLOG_IS_ON(2) && !ObjectiveVar(i)->Bound()) {

3122 << ".";

3123 }

3125 }

3126 if (std::lexicographical_compare(current_values_.begin(),

3127 current_values_.end(), best_values_.begin(),

3128 best_values_.end())) {

3129 best_values_ = current_values_;

3130 }

3132 return true;

3133}

3134

3136 if (delta == nullptr) return true;

3137 const bool delta_has_objective = delta->HasObjective();

3138 if (!delta_has_objective) {

3140 }

3141 const Assignment* const local_search_state =

3143 for (int i = 0; i < Size(); ++i) {

3147 if (delta_has_objective) {

3149 }

3150 if (solver()->UseFastLocalSearch() &&

3151 i < local_search_state->NumObjectives()) {

3152 obj_min = std::max(

3153 obj_min,

3155 }

3157 } else {

3159 if (delta_has_objective) {

3161 }

3162 if (solver()->UseFastLocalSearch() &&

3163 i < local_search_state->NumObjectives()) {

3164 obj_max = std::min(

3165 obj_max,

3167 }

3169 }

3170 }

3171 }

3172 return true;

3173}

3174

3179 objective_vars_);

3181 minimization_vars_);

3183}

3184

3186 int num_values_at_max = 0;

3187 for (int i = 0; i < Size(); ++i) {

3189 DCHECK_EQ(num_values_at_max, 0);

3190 } else {

3191 ++num_values_at_max;

3192 }

3193 }

3194 DCHECK(num_values_at_max == 0 || num_values_at_max == Size());

3195 return num_values_at_max < Size();

3196}

3197

3199 int64_t step)

3201 std::vector<IntVar*>{var}, {step}) {}

3202

3204 std::vector<IntVar*> vars, std::vector<int64_t> steps)

3206

3208 if (solver()->SearchDepth() == 0) {

3210 }

3211}

3212

3219

3220namespace {

3221class ApplyBoundDecisionBuilder : public DecisionBuilder {

3222 public:

3223 explicit ApplyBoundDecisionBuilder(OptimizeVar* optimize_var)

3224 : optimize_var_(optimize_var) {}

3225 ~ApplyBoundDecisionBuilder() override = default;

3226 Decision* Next(Solver*) override {

3227 optimize_var_->ApplyBound();

3228 return nullptr;

3229 }

3230

3231 private:

3232 OptimizeVar* optimize_var_;

3233};

3234}

3235

3237 if (!solver()->SolveAndCommit(

3238 solver()->RevAlloc(new ApplyBoundDecisionBuilder(this)))) {

3239 if (on_optimal_found_) {

3240

3243 ? value

3245 }

3247 }

3248}

3249

3252 return true;

3253 } else {

3254

3255

3256

3257 for (int i = 0; i < Size(); ++i) {

3259

3260

3261 if (!minimization_var->Bound()) return true;

3262 const int64_t value = minimization_var->Value();

3265 }

3266 return false;

3267 }

3268}

3269

3274

3276

3278 std::string out;

3279 for (int i = 0; i < Size(); ++i) {

3280 absl::StrAppendFormat(

3281 &out, "%s%s(%s, step = %d, best = %d)", i == 0 ? "" : "; ",

3282 Maximize(i) ? "MaximizeVar" : "MinimizeVar",

3284 }

3285 return out;

3286}

3287

3291

3295

3297 int64_t step) {

3299}

3300

3302 std::vector<IntVar*> variables,

3303 std::vector<int64_t> steps) {

3305 std::move(variables), std::move(steps)));

3306}

3307

3308namespace {

3309class WeightedOptimizeVar : public OptimizeVar {

3310 public:

3311 WeightedOptimizeVar(Solver* solver, bool maximize,

3312 const std::vector<IntVar*>& sub_objectives,

3313 const std::vector<int64_t>& weights, int64_t step)

3315 solver->MakeScalProd(sub_objectives, weights)->Var(), step),

3316 sub_objectives_(sub_objectives),

3317 weights_(weights) {

3318 CHECK_EQ(sub_objectives.size(), weights.size());

3319 }

3320

3321 ~WeightedOptimizeVar() override {}

3322 std::string Name() const override;

3323

3324 private:

3325 const std::vector<IntVar*> sub_objectives_;

3326 const std::vector<int64_t> weights_;

3327};

3328

3329std::string WeightedOptimizeVar::Name() const { return "weighted objective"; }

3330}

3331

3333 bool maximize, const std::vector<IntVar*>& sub_objectives,

3334 const std::vector<int64_t>& weights, int64_t step) {

3336 new WeightedOptimizeVar(this, maximize, sub_objectives, weights, step));

3337}

3338

3340 const std::vector<IntVar*>& sub_objectives,

3341 const std::vector<int64_t>& weights, int64_t step) {

3343 new WeightedOptimizeVar(this, false, sub_objectives, weights, step));

3344}

3345

3347 const std::vector<IntVar*>& sub_objectives,

3348 const std::vector<int64_t>& weights, int64_t step) {

3350 new WeightedOptimizeVar(this, true, sub_objectives, weights, step));

3351}

3352

3354 bool maximize, const std::vector<IntVar*>& sub_objectives,

3355 const std::vector<int>& weights, int64_t step) {

3357 step);

3358}

3359

3361 const std::vector<IntVar*>& sub_objectives, const std::vector<int>& weights,

3362 int64_t step) {

3364}

3365

3367 const std::vector<IntVar*>& sub_objectives, const std::vector<int>& weights,

3368 int64_t step) {

3370}

3371

3372

3373

3374namespace {

3376 public:

3377 Metaheuristic(Solver* solver, const std::vector<bool>& maximize,

3378 std::vector<IntVar*> objectives, std::vector<int64_t> steps);

3379 ~Metaheuristic() override {}

3380

3381 void EnterSearch() override;

3382 void RefuteDecision(Decision* d) override;

3383};

3384

3385Metaheuristic::Metaheuristic(Solver* solver, const std::vector<bool>& maximize,

3386 std::vector<IntVar*> objectives,

3387 std::vector<int64_t> steps)

3388 : ObjectiveMonitor(solver, maximize, std::move(objectives),

3389 std::move(steps)) {}

3390

3391void Metaheuristic::EnterSearch() {

3392 ObjectiveMonitor::EnterSearch();

3393

3394

3395 solver()->SetUseFastLocalSearch(false);

3396}

3397

3398void Metaheuristic::RefuteDecision(Decision*) {

3399 for (int i = 0; i < Size(); ++i) {

3400 const int64_t objective_value = MinimizationVar(i)->Min();

3401 if (objective_value > BestInternalValue(i)) break;

3402 if (objective_value <= CapSub(BestInternalValue(i), Step(i))) return;

3403 }

3404 solver()->Fail();

3405}

3406

3407

3408

3409class TabuSearch : public Metaheuristic {

3410 public:

3411 TabuSearch(Solver* solver, const std::vector<bool>& maximize,

3412 std::vector<IntVar*> objectives, std::vector<int64_t> steps,

3413 const std::vector<IntVar*>& vars, int64_t keep_tenure,

3414 int64_t forbid_tenure, double tabu_factor);

3415 ~TabuSearch() override {}

3416 void EnterSearch() override;

3417 void ApplyDecision(Decision* d) override;

3418 bool AtSolution() override;

3419 bool AcceptSolution() override;

3420 bool AtLocalOptimum() override;

3421 bool AcceptDelta(Assignment* delta, Assignment* deltadelta) override;

3423 void BeginNextDecision(DecisionBuilder* const) override {

3424 if (stop_search_) solver()->Fail();

3425 }

3426 void RefuteDecision(Decision* const d) override {

3427 Metaheuristic::RefuteDecision(d);

3428 if (stop_search_) solver()->Fail();

3429 }

3430 std::string DebugString() const override { return "Tabu Search"; }

3431

3432 protected:

3433 struct VarValue {

3434 int var_index;

3435 int64_t value;

3436 int64_t stamp;

3437 };

3438 typedef std::list<VarValue> TabuList;

3439

3440 virtual std::vector<IntVar*> CreateTabuVars();

3441 const TabuList& forbid_tabu_list() { return forbid_tabu_list_; }

3442 IntVar* vars(int index) const { return vars_[index]; }

3443

3444 private:

3445 void AgeList(int64_t tenure, TabuList* list);

3446 void AgeLists();

3447 int64_t TabuLimit() const {

3448 return (synced_keep_tabu_list_.size() + synced_forbid_tabu_list_.size()) *

3449 tabu_factor_;

3450 }

3451

3452 const std::vector<IntVar*> vars_;

3453 Assignment::IntContainer assignment_container_;

3454 bool has_stored_assignment_ = false;

3455 std::vector<int64_t> last_values_;

3456 TabuList keep_tabu_list_;

3457 TabuList synced_keep_tabu_list_;

3458 int64_t keep_tenure_;

3459 TabuList forbid_tabu_list_;

3460 TabuList synced_forbid_tabu_list_;

3461 int64_t forbid_tenure_;

3462 double tabu_factor_;

3463 int64_t stamp_;

3464 int64_t solution_count_ = 0;

3465 bool stop_search_ = false;

3466 std::vector<int64_t> delta_values_;

3467 SparseBitset<> delta_vars_;

3468 std::vector<int> var_index_to_index_;

3469};

3470

3471TabuSearch::TabuSearch(Solver* solver, const std::vector<bool>& maximize,

3472 std::vector<IntVar*> objectives,

3473 std::vector<int64_t> steps,

3474 const std::vector<IntVar*>& vars, int64_t keep_tenure,

3475 int64_t forbid_tenure, double tabu_factor)

3476 : Metaheuristic(solver, maximize, std::move(objectives), std::move(steps)),

3477 vars_(vars),

3478 last_values_(Size(), std::numeric_limits<int64_t>::max()),

3479 keep_tenure_(keep_tenure),

3480 forbid_tenure_(forbid_tenure),

3481 tabu_factor_(tabu_factor),

3482 stamp_(0),

3483 delta_values_(vars.size(), 0),

3484 delta_vars_(vars.size()) {

3485 for (int index = 0; index < vars_.size(); ++index) {

3486 assignment_container_.FastAdd(vars_[index]);

3487 DCHECK_EQ(vars_[index], assignment_container_.Element(index).Var());

3488 const int var_index = vars_[index]->index();

3489 if (var_index >= var_index_to_index_.size()) {

3490 var_index_to_index_.resize(var_index + 1, -1);

3491 }

3492 var_index_to_index_[var_index] = index;

3493 }

3494}

3495

3496void TabuSearch::EnterSearch() {

3497 Metaheuristic::EnterSearch();

3498 solver()->SetUseFastLocalSearch(true);

3499 stamp_ = 0;

3500 has_stored_assignment_ = false;

3501 solution_count_ = 0;

3502 stop_search_ = false;

3503}

3504

3505void TabuSearch::ApplyDecision(Decision* const d) {

3506 Solver* const s = solver();

3507 if (d == s->balancing_decision()) {

3508 return;

3509 }

3510

3511 synced_keep_tabu_list_ = keep_tabu_list_;

3512 synced_forbid_tabu_list_ = forbid_tabu_list_;

3513 Constraint* tabu_ct = nullptr;

3514 {

3515

3516

3517 const std::vector<IntVar*> tabu_vars = CreateTabuVars();

3518 if (!tabu_vars.empty()) {

3519 IntVar* tabu_var = s->MakeIsGreaterOrEqualCstVar(

3520 s->MakeSum(tabu_vars)->Var(), TabuLimit());

3521

3522

3523 IntVar* aspiration = MakeMinimizationVarsLessOrEqualWithStepsStatus(

3524 [this](int i) { return BestInternalValue(i); });

3525 tabu_ct = s->MakeSumGreaterOrEqual({aspiration, tabu_var}, int64_t{1});

3526 }

3527 }

3528 if (tabu_ct != nullptr) s->AddConstraint(tabu_ct);

3529

3530

3531 if (CurrentInternalValuesAreConstraining()) {

3532 MakeMinimizationVarsLessOrEqualWithSteps(

3533 [this](int i) { return CurrentInternalValue(i); });

3534 }

3535}

3536

3537bool TabuSearch::AcceptSolution() {

3538

3539 if (found_initial_solution_) {

3540 for (int i = 0; i < Size(); ++i) {

3541 if (last_values_[i] != MinimizationVar(i)->Min()) {

3542 return true;

3543 }

3544 }

3545 return false;

3546 }

3547 return true;

3548}

3549

3550std::vector<IntVar*> TabuSearch::CreateTabuVars() {

3551 Solver* const s = solver();

3552

3553

3554

3555

3556

3557

3558

3559 std::vector<IntVar*> tabu_vars;

3560 for (const auto [var_index, value, unused_stamp] : keep_tabu_list_) {

3561 tabu_vars.push_back(s->MakeIsEqualCstVar(vars(var_index), value));

3562 }

3563 for (const auto [var_index, value, unused_stamp] : forbid_tabu_list_) {

3564 tabu_vars.push_back(s->MakeIsDifferentCstVar(vars(var_index), value));

3565 }

3566 return tabu_vars;

3567}

3568

3569bool TabuSearch::AtSolution() {

3570 ++solution_count_;

3571 if (!ObjectiveMonitor::AtSolution()) {

3572 return false;

3573 }

3574 for (int i = 0; i < Size(); ++i) {

3575 last_values_[i] = CurrentInternalValue(i);

3576 }

3577

3578

3579

3580 if (0 != stamp_ && has_stored_assignment_) {

3581 for (int index = 0; index < vars_.size(); ++index) {

3582 IntVar* var = vars(index);

3583 const int64_t old_value = assignment_container_.Element(index).Value();

3584 const int64_t new_value = var->Value();

3585 if (old_value != new_value) {

3586 if (keep_tenure_ > 0) {

3587 keep_tabu_list_.push_front({index, new_value, stamp_});

3588 }

3589 if (forbid_tenure_ > 0) {

3590 forbid_tabu_list_.push_front({index, old_value, stamp_});

3591 }

3592 }

3593 }

3594 }

3595 assignment_container_.Store();

3596 has_stored_assignment_ = true;

3597

3598 return true;

3599}

3600

3601bool TabuSearch::AtLocalOptimum() {

3602 solver()->SetUseFastLocalSearch(false);

3603

3604

3605 if (stamp_ > 0 && solution_count_ == 0 && keep_tabu_list_.empty() &&

3606 forbid_tabu_list_.empty()) {

3607 stop_search_ = true;

3608 }

3609 solution_count_ = 0;

3610 AgeLists();

3611 for (int i = 0; i < Size(); ++i) {

3612 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());

3613 }

3614 return found_initial_solution_;

3615}

3616

3617bool TabuSearch::AcceptDelta(Assignment* delta, Assignment* deltadelta) {

3618 if (delta == nullptr) return true;

3619 if (!Metaheuristic::AcceptDelta(delta, deltadelta)) return false;

3620 if (synced_keep_tabu_list_.empty() && synced_forbid_tabu_list_.empty()) {

3621 return true;

3622 }

3623 const Assignment::IntContainer& delta_container = delta->IntVarContainer();

3624

3625 for (const IntVarElement& element : delta_container.elements()) {

3626 if (!element.Bound()) return true;

3627 }

3629 for (const IntVarElement& element : delta_container.elements()) {

3630 const int var_index = element.Var()->index();

3631 if (var_index >= var_index_to_index_.size()) continue;

3632 const int index = var_index_to_index_[var_index];

3633 if (index == -1) continue;

3634 delta_values_[index] = element.Value();

3635 delta_vars_.Set(index);

3636 }

3637 int num_respected = 0;

3638 auto get_value = [this](int var_index) {

3639 return delta_vars_[var_index]

3640 ? delta_values_[var_index]

3641 : assignment_container_.Element(var_index).Value();

3642 };

3643 const int64_t tabu_limit = TabuLimit();

3644 for (const auto [var_index, value, unused_stamp] : synced_keep_tabu_list_) {

3645 if (get_value(var_index) == value) {

3646 if (++num_respected >= tabu_limit) return true;

3647 }

3648 }

3649 for (const auto [var_index, value, unused_stamp] : synced_forbid_tabu_list_) {

3650 if (get_value(var_index) != value) {

3651 if (++num_respected >= tabu_limit) return true;

3652 }

3653 }

3654 if (num_respected >= tabu_limit) return true;

3655

3656

3657 if (Size() == 1) {

3658 if (Maximize(0)) {

3659 delta->SetObjectiveMinFromIndex(0, CapAdd(BestInternalValue(0), Step(0)));

3660 } else {

3661 delta->SetObjectiveMaxFromIndex(0, CapSub(BestInternalValue(0), Step(0)));

3662 }

3663 } else {

3664 for (int i = 0; i < Size(); ++i) {

3665 if (Maximize(i)) {

3666 delta->SetObjectiveMinFromIndex(i, BestInternalValue(i));

3667 } else {

3668 delta->SetObjectiveMaxFromIndex(i, BestInternalValue(i));

3669 }

3670 }

3671 }

3672

3673 return true;

3674}

3675

3676void TabuSearch::AcceptNeighbor() {

3677 if (0 != stamp_) {

3678 AgeLists();

3679 }

3680}

3681

3682void TabuSearch::AgeList(int64_t tenure, TabuList* list) {

3683 while (!list->empty() && list->back().stamp < stamp_ - tenure) {

3684 list->pop_back();

3685 }

3686}

3687

3688void TabuSearch::AgeLists() {

3689 AgeList(keep_tenure_, &keep_tabu_list_);

3690 AgeList(forbid_tenure_, &forbid_tabu_list_);

3691 ++stamp_;

3692}

3693

3694class GenericTabuSearch : public TabuSearch {

3695 public:

3696 GenericTabuSearch(Solver* solver, bool maximize, IntVar* objective,

3697 int64_t step, const std::vector<IntVar*>& vars,

3698 int64_t forbid_tenure)

3699 : TabuSearch(solver, {maximize}, {objective}, {step}, vars, 0,

3700 forbid_tenure, 1) {}

3701 std::string DebugString() const override { return "Generic Tabu Search"; }

3702

3703 protected:

3704 std::vector<IntVar*> CreateTabuVars() override;

3705};

3706

3707std::vector<IntVar*> GenericTabuSearch::CreateTabuVars() {

3708 Solver* const s = solver();

3709

3710

3711

3712 std::vector<IntVar*> forbid_values;

3713 for (const auto [var_index, value, unused_stamp] : forbid_tabu_list()) {

3714 forbid_values.push_back(s->MakeIsDifferentCstVar(vars(var_index), value));

3715 }

3716 std::vector<IntVar*> tabu_vars;

3717 if (!forbid_values.empty()) {

3718 tabu_vars.push_back(s->MakeIsGreaterCstVar(s->MakeSum(forbid_values), 0));

3719 }

3720 return tabu_vars;

3721}

3722

3723}

3724

3726 int64_t step,

3727 const std::vector<IntVar*>& vars,

3728 int64_t keep_tenure,

3729 int64_t forbid_tenure,

3730 double tabu_factor) {

3731 return RevAlloc(new TabuSearch(this, {maximize}, {objective}, {step}, vars,

3732 keep_tenure, forbid_tenure, tabu_factor));

3733}

3734

3736 const std::vector<bool>& maximize, std::vector<IntVar*> objectives,

3737 std::vector<int64_t> steps, const std::vector<IntVar*>& vars,

3738 int64_t keep_tenure, int64_t forbid_tenure, double tabu_factor) {

3739 return RevAlloc(new TabuSearch(this, maximize, std::move(objectives),

3740 std::move(steps), vars, keep_tenure,

3741 forbid_tenure, tabu_factor));

3742}

3743

3745 bool maximize, IntVar* const v, int64_t step,

3746 const std::vector<IntVar*>& tabu_vars, int64_t forbid_tenure) {

3748 new GenericTabuSearch(this, maximize, v, step, tabu_vars, forbid_tenure));

3749}

3750

3751

3752

3753namespace {

3754class SimulatedAnnealing : public Metaheuristic {

3755 public:

3756 SimulatedAnnealing(Solver* solver, const std::vector<bool>& maximize,

3757 std::vector<IntVar*> objectives,

3758 std::vector<int64_t> steps,

3759 std::vector<int64_t> initial_temperatures);

3760 ~SimulatedAnnealing() override {}

3761 void ApplyDecision(Decision* d) override;

3762 bool AtLocalOptimum() override;

3763 void AcceptNeighbor() override;

3764 std::string DebugString() const override { return "Simulated Annealing"; }

3765

3766 private:

3767 double Temperature(int index) const {

3768 return iteration_ > 0

3769 ? (1.0 * temperature0_[index]) / iteration_

3770 : 0;

3771 }

3772

3773 const std::vector<int64_t> temperature0_;

3774 int64_t iteration_;

3775 std::mt19937 rand_;

3776};

3777

3778SimulatedAnnealing::SimulatedAnnealing(

3779 Solver* solver, const std::vector<bool>& maximize,

3780 std::vector<IntVar*> objectives, std::vector<int64_t> steps,

3781 std::vector<int64_t> initial_temperatures)

3782 : Metaheuristic(solver, maximize, std::move(objectives), std::move(steps)),

3783 temperature0_(std::move(initial_temperatures)),

3784 iteration_(0),

3786

3787

3788

3789

3790

3791

3792

3793

3794

3795

3796

3797

3798

3799

3800void SimulatedAnnealing::ApplyDecision(Decision* const d) {

3801 Solver* const s = solver();

3802 if (d == s->balancing_decision()) {

3803 return;

3804 }

3805 if (CurrentInternalValuesAreConstraining()) {

3806 MakeMinimizationVarsLessOrEqualWithSteps([this](int i) {

3807 const double rand_double = absl::Uniform<double>(rand_, 0.0, 1.0);

3808#if defined(_MSC_VER) || defined(__ANDROID__)

3809 const double rand_log2_double = log(rand_double) / log(2.0L);

3810#else

3811 const double rand_log2_double = log2(rand_double);

3812#endif

3813 const int64_t energy_bound = Temperature(i) * rand_log2_double;

3814

3815

3816 return CapSub(CurrentInternalValue(i), energy_bound);

3817 });

3818 }

3819}

3820

3821bool SimulatedAnnealing::AtLocalOptimum() {

3822 for (int i = 0; i < Size(); ++i) {

3823 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());

3824 }

3825 ++iteration_;

3826 if (!found_initial_solution_) return false;

3827 for (int i = 0; i < Size(); ++i) {

3828 if (Temperature(i) <= 0) return false;

3829 }

3830 return true;

3831}

3832

3833void SimulatedAnnealing::AcceptNeighbor() {

3834 if (iteration_ > 0) {

3835 ++iteration_;

3836 }

3837}

3838}

3839

3841 int64_t step,

3842 int64_t initial_temperature) {

3843 return RevAlloc(new SimulatedAnnealing(this, {maximize}, {v}, {step},

3844 {initial_temperature}));

3845}

3846

3848 const std::vector<bool>& maximize, std::vector<IntVar*> vars,

3849 std::vector<int64_t> steps, std::vector<int64_t> initial_temperatures) {

3850 return RevAlloc(new SimulatedAnnealing(this, maximize, std::move(vars),

3851 std::move(steps),

3852 std::move(initial_temperatures)));

3853}

3854

3855

3856

3857namespace {

3858

3859

3860

3861

3862class GuidedLocalSearchPenaltiesTable {

3863 public:

3864 struct VarValue {

3865 int64_t var;

3866 int64_t value;

3867 };

3868 explicit GuidedLocalSearchPenaltiesTable(int num_vars);

3869 bool HasPenalties() const { return has_values_; }

3870 void IncrementPenalty(const VarValue& var_value);

3871 int64_t GetPenalty(const VarValue& var_value) const;

3872 void Reset();

3873

3874 private:

3875 std::vector<std::vector<int64_t>> penalties_;

3876 bool has_values_;

3877};

3878

3879GuidedLocalSearchPenaltiesTable::GuidedLocalSearchPenaltiesTable(int num_vars)

3880 : penalties_(num_vars), has_values_(false) {}

3881

3882void GuidedLocalSearchPenaltiesTable::IncrementPenalty(

3883 const VarValue& var_value) {

3884 std::vector<int64_t>& var_penalties = penalties_[var_value.var];

3885 const int64_t value = var_value.value;

3886 if (value >= var_penalties.size()) {

3887 var_penalties.resize(value + 1, 0);

3888 }

3889 ++var_penalties[value];

3890 has_values_ = true;

3891}

3892

3893void GuidedLocalSearchPenaltiesTable::Reset() {

3894 has_values_ = false;

3895 for (int i = 0; i < penalties_.size(); ++i) {

3896 penalties_[i].clear();

3897 }

3898}

3899

3900int64_t GuidedLocalSearchPenaltiesTable::GetPenalty(

3901 const VarValue& var_value) const {

3902 const std::vector<int64_t>& var_penalties = penalties_[var_value.var];

3903 const int64_t value = var_value.value;

3904 return (value >= var_penalties.size()) ? 0 : var_penalties[value];

3905}

3906

3907

3908class GuidedLocalSearchPenaltiesMap {

3909 public:

3910 struct VarValue {

3911 int64_t var;

3912 int64_t value;

3913

3914 friend bool operator==(const VarValue& lhs, const VarValue& rhs) {

3915 return lhs.var == rhs.var && lhs.value == rhs.value;

3916 }

3917 template <typename H>

3918 friend H AbslHashValue(H h, const VarValue& var_value) {

3919 return H::combine(std::move(h), var_value.var, var_value.value);

3920 }

3921 };

3922 explicit GuidedLocalSearchPenaltiesMap(int num_vars);

3923 bool HasPenalties() const { return (!penalties_.empty()); }

3924 void IncrementPenalty(const VarValue& var_value);

3925 int64_t GetPenalty(const VarValue& var_value) const;

3926 void Reset();

3927

3928 private:

3929 Bitmap penalized_;

3930 absl::flat_hash_map<VarValue, int64_t> penalties_;

3931};

3932

3933GuidedLocalSearchPenaltiesMap::GuidedLocalSearchPenaltiesMap(int num_vars)

3934 : penalized_(num_vars, false) {}

3935

3936void GuidedLocalSearchPenaltiesMap::IncrementPenalty(

3937 const VarValue& var_value) {

3938 ++penalties_[var_value];

3939 penalized_.Set(var_value.var, true);

3940}

3941

3942void GuidedLocalSearchPenaltiesMap::Reset() {

3943 penalties_.clear();

3944 penalized_.Clear();

3945}

3946

3947int64_t GuidedLocalSearchPenaltiesMap::GetPenalty(

3948 const VarValue& var_value) const {

3949 return (penalized_.Get(var_value.var))

3951 : 0;

3952}

3953

3954template <typename P>

3955class GuidedLocalSearch : public Metaheuristic {

3956 public:

3957 GuidedLocalSearch(

3958 Solver* solver, IntVar* objective, bool maximize, int64_t step,

3959 const std::vector<IntVar*>& vars, double penalty_factor,

3960 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>

3961 get_equivalent_pairs,

3962 bool reset_penalties_on_new_best_solution);

3963 ~GuidedLocalSearch() override {}

3964 bool AcceptDelta(Assignment* delta, Assignment* deltadelta) override;

3965 void ApplyDecision(Decision* d) override;

3966 bool AtSolution() override;

3967 void EnterSearch() override;

3968 bool AtLocalOptimum() override;

3969 virtual int64_t AssignmentElementPenalty(int index) const = 0;

3970 virtual int64_t AssignmentPenalty(int64_t var, int64_t value) const = 0;

3971 virtual int64_t Evaluate(const Assignment* delta, int64_t current_penalty,

3972 bool incremental) = 0;

3973 virtual IntExpr* MakeElementPenalty(int index) = 0;

3974 std::string DebugString() const override { return "Guided Local Search"; }

3975

3976 protected:

3977

3978

3979

3980 template <typename T, typename IndexType = int64_t>

3981 class DirtyArray {

3982 public:

3983 explicit DirtyArray(IndexType size)

3984 : base_data_(size), modified_data_(size), touched_(size) {}

3985

3986

3987 void Set(IndexType i, const T& value) {

3988 modified_data_[i] = value;

3989 touched_.Set(i);

3990 }

3991

3992 void SetAll(const T& value) {

3993 for (IndexType i = 0; i < modified_data_.size(); ++i) {

3994 Set(i, value);

3995 }

3996 }

3997

3998 T Get(IndexType i) const { return modified_data_[i]; }

3999

4000

4001 void Commit() {

4002 for (const IndexType index : touched_.PositionsSetAtLeastOnce()) {

4003 base_data_[index] = modified_data_[index];

4004 }

4005 touched_.ResetAllToFalse();

4006 }

4007

4008 void Revert() {

4009 for (const IndexType index : touched_.PositionsSetAtLeastOnce()) {

4010 modified_data_[index] = base_data_[index];

4011 }

4012 touched_.ResetAllToFalse();

4013 }

4014

4015

4016 int NumSetValues() const {

4017 return touched_.NumberOfSetCallsWithDifferentArguments();

4018 }

4019

4020 private:

4021 std::vector<T> base_data_;

4022 std::vector<T> modified_data_;

4023 SparseBitset<IndexType> touched_;

4024 };

4025

4026 int64_t GetValue(int64_t index) const {

4028 }

4029 IntVar* GetVar(int64_t index) const {

4030 return assignment_.Element(index).Var();

4031 }

4032 void AddVars(const std::vector<IntVar*>& vars);

4033 int NumPrimaryVars() const { return num_vars_; }

4034 int GetLocalIndexFromVar(IntVar* var) const {

4035 const int var_index = var->index();

4036 return (var_index < var_index_to_local_index_.size())

4037 ? var_index_to_local_index_[var_index]

4038 : -1;

4039 }

4040 void ResetPenalties();

4041

4042 IntVar* penalized_objective_;

4043 Assignment::IntContainer assignment_;

4044 int64_t assignment_penalized_value_;

4045 int64_t old_penalized_value_;

4046 const int num_vars_;

4047 std::vector<int> var_index_to_local_index_;

4048 const double penalty_factor_;

4049 P penalties_;

4050 DirtyArray<int64_t> penalized_values_;

4051 bool incremental_;

4052 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>

4053 get_equivalent_pairs_;

4054 const bool reset_penalties_on_new_best_solution_;

4055};

4056

4057template <typename P>

4058GuidedLocalSearch<P>::GuidedLocalSearch(

4059 Solver* solver, IntVar* objective, bool maximize, int64_t step,

4060 const std::vector<IntVar*>& vars, double penalty_factor,

4061 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>

4062 get_equivalent_pairs,

4063 bool reset_penalties_on_new_best_solution)

4064 : Metaheuristic(solver, {maximize}, {objective}, {step}),

4065 penalized_objective_(nullptr),

4066 assignment_penalized_value_(0),

4067 old_penalized_value_(0),

4068 num_vars_(vars.size()),

4069 penalty_factor_(penalty_factor),

4070 penalties_(vars.size()),

4071 penalized_values_(vars.size()),

4072 incremental_(false),

4073 get_equivalent_pairs_(std::move(get_equivalent_pairs)),

4074 reset_penalties_on_new_best_solution_(

4075 reset_penalties_on_new_best_solution) {

4076 AddVars(vars);

4077}

4078

4079template <typename P>

4080void GuidedLocalSearch<P>::AddVars(const std::vector<IntVar*>& vars) {

4081 const int offset = assignment_.Size();

4082 if (vars.empty()) return;

4083 assignment_.Resize(offset + vars.size());

4084 for (int i = 0; i < vars.size(); ++i) {

4085 assignment_.AddAtPosition(vars[i], offset + i);

4086 }

4087 const int max_var_index =

4088 (*std::max_element(vars.begin(), vars.end(), [](IntVar* a, IntVar* b) {

4089 return a->index() < b->index();

4090 }))->index();

4091 if (max_var_index >= var_index_to_local_index_.size()) {

4092 var_index_to_local_index_.resize(max_var_index + 1, -1);

4093 }

4094 for (int i = 0; i < vars.size(); ++i) {

4095 var_index_to_local_index_[vars[i]->index()] = offset + i;

4096 }

4097}

4098

4099

4100

4101

4102

4103

4104

4105

4106template <typename P>

4107void GuidedLocalSearch<P>::ApplyDecision(Decision* const d) {

4108 if (d == solver()->balancing_decision()) {

4109 return;

4110 }

4111 assignment_penalized_value_ = 0;

4112 if (penalties_.HasPenalties()) {

4113

4114

4115 {

4116 std::vector<IntVar*> elements;

4117 for (int i = 0; i < num_vars_; ++i) {

4118 elements.push_back(MakeElementPenalty(i)->Var());

4119 const int64_t penalty = AssignmentElementPenalty(i);

4120 penalized_values_.Set(i, penalty);

4121 assignment_penalized_value_ =

4122 CapAdd(assignment_penalized_value_, penalty);

4123 }

4124 solver()->SaveAndSetValue(

4125 reinterpret_cast<void**>(&penalized_objective_),

4126 reinterpret_cast<void*>(solver()->MakeSum(elements)->Var()));

4127 }

4128 penalized_values_.Commit();

4129 old_penalized_value_ = assignment_penalized_value_;

4130 incremental_ = false;

4131 IntExpr* max_pen_exp = solver()->MakeDifference(

4132 CapSub(CurrentInternalValue(0), Step(0)), penalized_objective_);

4134 solver()

4135 ->MakeMax(max_pen_exp, CapSub(BestInternalValue(0), Step(0)))

4136 ->Var();

4137 solver()->AddConstraint(

4138 solver()->MakeLessOrEqual(MinimizationVar(0), max_exp));

4139 } else {

4140 penalized_objective_ = nullptr;

4141 const int64_t bound =

4142 (CurrentInternalValue(0) < std::numeric_limits<int64_t>::max())

4143 ? CapSub(CurrentInternalValue(0), Step(0))

4144 : CurrentInternalValue(0);

4145 MinimizationVar(0)->SetMax(bound);

4146 }

4147}

4148

4149template <typename P>

4150void GuidedLocalSearch<P>::ResetPenalties() {

4151 assignment_penalized_value_ = 0;

4152 old_penalized_value_ = 0;

4153 penalized_values_.SetAll(0);

4154 penalized_values_.Commit();

4155 penalties_.Reset();

4156}

4157

4158template <typename P>

4159bool GuidedLocalSearch<P>::AtSolution() {

4160 const int64_t old_best = BestInternalValue(0);

4162 return false;

4163 }

4164 if (penalized_objective_ != nullptr && penalized_objective_->Bound()) {

4165

4166

4167

4168

4169 if (reset_penalties_on_new_best_solution_ &&

4170 old_best != BestInternalValue(0)) {

4171 ResetPenalties();

4172 DCHECK_EQ(CurrentInternalValue(0), BestInternalValue(0));

4173 } else {

4174

4175 SetCurrentInternalValue(

4176 0, CapAdd(CurrentInternalValue(0), penalized_objective_->Value()));

4177 }

4178 }

4179 assignment_.Store();

4180 return true;

4181}

4182

4183template <typename P>

4184void GuidedLocalSearch<P>::EnterSearch() {

4185 Metaheuristic::EnterSearch();

4186 solver()->SetUseFastLocalSearch(true);

4187 penalized_objective_ = nullptr;

4188 ResetPenalties();

4189}

4190

4191

4192

4193template <typename P>

4194bool GuidedLocalSearch<P>::AcceptDelta(Assignment* delta,

4196 if (delta == nullptr && deltadelta == nullptr) return true;

4197 if (!penalties_.HasPenalties()) {

4198 return Metaheuristic::AcceptDelta(delta, deltadelta);

4199 }

4200 int64_t penalty = 0;

4201 if (!deltadelta->Empty()) {

4202 if (!incremental_) {

4203 DCHECK_EQ(penalized_values_.NumSetValues(), 0);

4204 penalty = Evaluate(delta, assignment_penalized_value_, true);

4205 } else {

4206 penalty = Evaluate(deltadelta, old_penalized_value_, true);

4207 }

4208 incremental_ = true;

4209 } else {

4210 if (incremental_) {

4211 penalized_values_.Revert();

4212 }

4213 incremental_ = false;

4214 DCHECK_EQ(penalized_values_.NumSetValues(), 0);

4215 penalty = Evaluate(delta, assignment_penalized_value_, false);

4216 }

4217 old_penalized_value_ = penalty;

4218 if (!delta->HasObjective()) {

4219 delta->AddObjective(ObjectiveVar(0));

4220 }

4221 if (delta->Objective() == ObjectiveVar(0)) {

4222 const int64_t bound =

4223 std::max(CapSub(CapSub(CurrentInternalValue(0), Step(0)), penalty),

4224 CapSub(BestInternalValue(0), Step(0)));

4225 if (Maximize(0)) {

4226 delta->SetObjectiveMin(std::max(CapOpp(bound), delta->ObjectiveMin()));

4227 } else {

4228 delta->SetObjectiveMax(std::min(bound, delta->ObjectiveMax()));

4229 }

4230 }

4231 return true;

4232}

4233

4234

4235

4236template <typename P>

4237bool GuidedLocalSearch<P>::AtLocalOptimum() {

4238 solver()->SetUseFastLocalSearch(false);

4239 std::vector<double> utilities(num_vars_);

4240 double max_utility = -std::numeric_limits<double>::infinity();

4241 for (int var = 0; var < num_vars_; ++var) {

4242 const IntVarElement& element = assignment_.Element(var);

4243 if (!element.Bound()) {

4244

4245 return false;

4246 }

4247 const int64_t value = element.Value();

4248

4249

4250 const int64_t cost = (value != var) ? AssignmentPenalty(var, value) : 0;

4251 const double utility = cost / (penalties_.GetPenalty({var, value}) + 1.0);

4252 utilities[var] = utility;

4253 if (utility > max_utility) max_utility = utility;

4254 }

4255 for (int var = 0; var < num_vars_; ++var) {

4256 if (utilities[var] == max_utility) {

4257 const IntVarElement& element = assignment_.Element(var);

4258 DCHECK(element.Bound());

4259 const int64_t value = element.Value();

4260 if (get_equivalent_pairs_ == nullptr) {

4261 penalties_.IncrementPenalty({var, value});

4262 } else {

4263 for (const auto [other_var, other_value] :

4264 get_equivalent_pairs_(var, value)) {

4265 penalties_.IncrementPenalty({other_var, other_value});

4266 }

4267 }

4268 }

4269 }

4270 SetCurrentInternalValue(0, std::numeric_limits<int64_t>::max());

4271 return true;

4272}

4273

4274template <typename P>

4275class BinaryGuidedLocalSearch : public GuidedLocalSearch<P> {

4276 public:

4277 BinaryGuidedLocalSearch(

4278 Solver* solver, IntVar* objective,

4279 std::function<int64_t(int64_t, int64_t)> objective_function,

4280 bool maximize, int64_t step, const std::vector<IntVar*>& vars,

4281 double penalty_factor,

4282 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>

4283 get_equivalent_pairs,

4284 bool reset_penalties_on_new_best_solution);

4285 ~BinaryGuidedLocalSearch() override {}

4286 IntExpr* MakeElementPenalty(int index) override;

4287 int64_t AssignmentElementPenalty(int index) const override;

4288 int64_t AssignmentPenalty(int64_t var, int64_t value) const override;

4289 int64_t Evaluate(const Assignment* delta, int64_t current_penalty,

4290 bool incremental) override;

4291

4292 private:

4293 int64_t PenalizedValue(int64_t i, int64_t j) const;

4294 std::function<int64_t(int64_t, int64_t)> objective_function_;

4295};

4296

4297template <typename P>

4298BinaryGuidedLocalSearch<P>::BinaryGuidedLocalSearch(

4299 Solver* const solver, IntVar* const objective,

4300 std::function<int64_t(int64_t, int64_t)> objective_function, bool maximize,

4301 int64_t step, const std::vector<IntVar*>& vars, double penalty_factor,

4302 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>

4303 get_equivalent_pairs,

4304 bool reset_penalties_on_new_best_solution)

4305 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,

4306 penalty_factor, std::move(get_equivalent_pairs),

4307 reset_penalties_on_new_best_solution),

4308 objective_function_(std::move(objective_function)) {

4309 solver->SetGuidedLocalSearchPenaltyCallback(

4310 [this](int64_t i, int64_t j, int64_t) { return PenalizedValue(i, j); });

4311}

4312

4313template <typename P>

4314IntExpr* BinaryGuidedLocalSearch<P>::MakeElementPenalty(int index) {

4315 return this->solver()->MakeElement(

4316 [this, index](int64_t i) { return PenalizedValue(index, i); },

4317 this->GetVar(index));

4318}

4319

4320template <typename P>

4321int64_t BinaryGuidedLocalSearch<P>::AssignmentElementPenalty(int index) const {

4322 return PenalizedValue(index, this->GetValue(index));

4323}

4324

4325template <typename P>

4326int64_t BinaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t var,

4327 int64_t value) const {

4328 return objective_function_(var, value);

4329}

4330

4331template <typename P>

4332int64_t BinaryGuidedLocalSearch<P>::Evaluate(const Assignment* delta,

4333 int64_t current_penalty,

4334 bool incremental) {

4335 int64_t penalty = current_penalty;

4337 for (const IntVarElement& new_element : container.elements()) {

4338 const int index = this->GetLocalIndexFromVar(new_element.Var());

4339 if (index == -1) continue;

4340 penalty = CapSub(penalty, this->penalized_values_.Get(index));

4341 if (new_element.Activated()) {

4342 const int64_t new_penalty = PenalizedValue(index, new_element.Value());

4343 penalty = CapAdd(penalty, new_penalty);

4344 if (incremental) {

4345 this->penalized_values_.Set(index, new_penalty);

4346 }

4347 }

4348 }

4349 return penalty;

4350}

4351

4352

4353template <typename P>

4354int64_t BinaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j) const {

4355 const int64_t penalty = this->penalties_.GetPenalty({i, j});

4356

4357 if (penalty == 0) return 0;

4358 const double penalized_value_fp =

4359 this->penalty_factor_ * penalty * objective_function_(i, j);

4360 const int64_t penalized_value =

4361 (penalized_value_fp <= std::numeric_limits<int64_t>::max())

4362 ? static_cast<int64_t>(penalized_value_fp)

4363 : std::numeric_limits<int64_t>::max();

4364 return penalized_value;

4365}

4366

4367template <typename P>

4368class TernaryGuidedLocalSearch : public GuidedLocalSearch<P> {

4369 public:

4370 TernaryGuidedLocalSearch(

4371 Solver* solver, IntVar* objective,

4372 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,

4373 bool maximize, int64_t step, const std::vector<IntVar*>& vars,

4374 const std::vector<IntVar*>& secondary_vars, double penalty_factor,

4375 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>

4376 get_equivalent_pairs,

4377 bool reset_penalties_on_new_best_solution);

4378 ~TernaryGuidedLocalSearch() override {}

4379 IntExpr* MakeElementPenalty(int index) override;

4380 int64_t AssignmentElementPenalty(int index) const override;

4381 int64_t AssignmentPenalty(int64_t var, int64_t value) const override;

4382 int64_t Evaluate(const Assignment* delta, int64_t current_penalty,

4383 bool incremental) override;

4384

4385 private:

4386 int64_t PenalizedValue(int64_t i, int64_t j, int64_t k) const;

4387

4388 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function_;

4389 std::vector<int> secondary_values_;

4390};

4391

4392template <typename P>

4393TernaryGuidedLocalSearch<P>::TernaryGuidedLocalSearch(

4394 Solver* const solver, IntVar* const objective,

4395 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,

4396 bool maximize, int64_t step, const std::vector<IntVar*>& vars,

4397 const std::vector<IntVar*>& secondary_vars, double penalty_factor,

4398 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>

4399 get_equivalent_pairs,

4400 bool reset_penalties_on_new_best_solution)

4401 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,

4402 penalty_factor, std::move(get_equivalent_pairs),

4403 reset_penalties_on_new_best_solution),

4404 objective_function_(std::move(objective_function)),

4405 secondary_values_(this->NumPrimaryVars(), -1) {

4406 this->AddVars(secondary_vars);

4407 solver->SetGuidedLocalSearchPenaltyCallback(

4408 [this](int64_t i, int64_t j, int64_t k) {

4409 return PenalizedValue(i, j, k);

4410 });

4411}

4412

4413template <typename P>

4414IntExpr* TernaryGuidedLocalSearch<P>::MakeElementPenalty(int index) {

4415 Solver* const solver = this->solver();

4417 solver->AddConstraint(solver->MakeLightElement(

4418 [this, index](int64_t j, int64_t k) {

4419 return PenalizedValue(index, j, k);

4420 },

4421 var, this->GetVar(index), this->GetVar(this->NumPrimaryVars() + index)));

4422 return var;

4423}

4424

4425template <typename P>

4426int64_t TernaryGuidedLocalSearch<P>::AssignmentElementPenalty(int index) const {

4427 return PenalizedValue(index, this->GetValue(index),

4428 this->GetValue(this->NumPrimaryVars() + index));

4429}

4430

4431template <typename P>

4432int64_t TernaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t var,

4433 int64_t value) const {

4434 return objective_function_(var, value,

4435 this->GetValue(this->NumPrimaryVars() + var));

4436}

4437

4438template <typename P>

4439int64_t TernaryGuidedLocalSearch<P>::Evaluate(const Assignment* delta,

4440 int64_t current_penalty,

4441 bool incremental) {

4442 int64_t penalty = current_penalty;

4444

4445

4446

4447 for (const IntVarElement& new_element : container.elements()) {

4448 const int index = this->GetLocalIndexFromVar(new_element.Var());

4449 if (index != -1 && index < this->NumPrimaryVars()) {

4450 secondary_values_[index] = -1;

4451 }

4452 }

4453 for (const IntVarElement& new_element : container.elements()) {

4454 const int index = this->GetLocalIndexFromVar(new_element.Var());

4455 if (!new_element.Activated()) continue;

4456 if (index != -1 && index >= this->NumPrimaryVars()) {

4457 secondary_values_[index - this->NumPrimaryVars()] = new_element.Value();

4458 }

4459 }

4460 for (const IntVarElement& new_element : container.elements()) {

4461 const int index = this->GetLocalIndexFromVar(new_element.Var());

4462

4463 if (index == -1 || index >= this->NumPrimaryVars()) {

4464 continue;

4465 }

4466 penalty = CapSub(penalty, this->penalized_values_.Get(index));

4467

4468 if (new_element.Activated() && secondary_values_[index] != -1) {

4469 const int64_t new_penalty =

4470 PenalizedValue(index, new_element.Value(), secondary_values_[index]);

4471 penalty = CapAdd(penalty, new_penalty);

4472 if (incremental) {

4473 this->penalized_values_.Set(index, new_penalty);

4474 }

4475 }

4476 }

4477 return penalty;

4478}

4479

4480

4481template <typename P>

4482int64_t TernaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j,

4483 int64_t k) const {

4484 const int64_t penalty = this->penalties_.GetPenalty({i, j});

4485

4486 if (penalty == 0) return 0;

4487 const double penalized_value_fp =

4488 this->penalty_factor_ * penalty * objective_function_(i, j, k);

4489 const int64_t penalized_value =

4490 (penalized_value_fp < std::numeric_limits<int64_t>::max())

4491 ? static_cast<int64_t>(penalized_value_fp)

4492 : std::numeric_limits<int64_t>::max();

4493 return penalized_value;

4494}

4495}

4496

4498 bool maximize, IntVar* const objective,

4500 const std::vector<IntVar*>& vars, double penalty_factor,

4501 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>

4502 get_equivalent_pairs,

4503 bool reset_penalties_on_new_best_solution) {

4504 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {

4505 return RevAlloc(new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(

4506 this, objective, std::move(objective_function), maximize, step, vars,

4507 penalty_factor, std::move(get_equivalent_pairs),

4508 reset_penalties_on_new_best_solution));

4509 } else {

4511 new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(

4512 this, objective, std::move(objective_function), maximize, step,

4513 vars, penalty_factor, std::move(get_equivalent_pairs),

4514 reset_penalties_on_new_best_solution));

4515 }

4516}

4517

4519 bool maximize, IntVar* const objective,

4521 const std::vector<IntVar*>& vars,

4522 const std::vector<IntVar*>& secondary_vars, double penalty_factor,

4523 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>

4524 get_equivalent_pairs,

4525 bool reset_penalties_on_new_best_solution) {

4526 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {

4527 return RevAlloc(new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(

4528 this, objective, std::move(objective_function), maximize, step, vars,

4529 secondary_vars, penalty_factor, std::move(get_equivalent_pairs),

4530 reset_penalties_on_new_best_solution));

4531 } else {

4533 new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(

4534 this, objective, std::move(objective_function), maximize, step,

4535 vars, secondary_vars, penalty_factor,

4536 std::move(get_equivalent_pairs),

4537 reset_penalties_on_new_best_solution));

4538 }

4539}

4540

4541

4542

4543

4544

4546

4553

4555 crossed_ = false;

4557}

4558

4561 TopPeriodicCheck();

4562}

4563

4566 TopPeriodicCheck();

4567}

4568

4570 if (crossed_ || Check()) {

4571 crossed_ = true;

4573 }

4574}

4575

4576void SearchLimit::TopPeriodicCheck() {

4577 if (solver()->TopLevelSearch() != solver()->ActiveSearch()) {

4579 }

4580}

4581

4582

4583

4586 int64_t solutions, bool smart_time_check,

4587 bool cumulative)

4589 duration_limit_(time),

4590 solver_time_at_limit_start_(s->Now()),

4591 last_time_elapsed_(absl::ZeroDuration()),

4592 check_count_(0),

4593 next_check_(0),

4594 smart_time_check_(smart_time_check),

4596 branches_offset_(0),

4598 failures_offset_(0),

4600 solutions_offset_(0),

4601 cumulative_(cumulative) {}

4602

4604

4612

4615 reinterpret_cast<const RegularLimit* const>(limit);

4616 duration_limit_ = regular->duration_limit_;

4617 branches_ = regular->branches_;

4618 failures_ = regular->failures_;

4619 solutions_ = regular->solutions_;

4620 smart_time_check_ = regular->smart_time_check_;

4621 cumulative_ = regular->cumulative_;

4622}

4623

4625

4629 smart_time_check_);

4630}

4631

4634

4635 return s->branches() - branches_offset_ >= branches_ ||

4636 s->failures() - failures_offset_ >= failures_ || CheckTime(offset) ||

4637 s->solutions() - solutions_offset_ >= solutions_;

4638}

4639

4642 int64_t progress = GetPercent(s->branches(), branches_offset_, branches_);

4643 progress = std::max(progress,

4644 GetPercent(s->failures(), failures_offset_, failures_));

4645 progress = std::max(

4646 progress, GetPercent(s->solutions(), solutions_offset_, solutions_));

4648 progress = std::max(progress, (100 * TimeElapsed()) / duration_limit());

4649 }

4650 return progress;

4651}

4652

4655 branches_offset_ = s->branches();

4656 failures_offset_ = s->failures();

4657 solver_time_at_limit_start_ = s->Now();

4658 last_time_elapsed_ = absl::ZeroDuration();

4659 solutions_offset_ = s->solutions();

4660 check_count_ = 0;

4661 next_check_ = 0;

4662}

4663

4665 if (cumulative_) {

4666

4668 branches_ -= s->branches() - branches_offset_;

4669 failures_ -= s->failures() - failures_offset_;

4670 duration_limit_ -= s->Now() - solver_time_at_limit_start_;

4671 solutions_ -= s->solutions() - solutions_offset_;

4672 }

4673}

4674

4678 duration_limit_ = time;

4682}

4683

4689

4691 return absl::StrFormat(

4692 "RegularLimit(crossed = %i, duration_limit = %s, "

4693 "branches = %d, failures = %d, solutions = %d cumulative = %s",

4695 solutions_, (cumulative_ ? "true" : "false"));

4696}

4697

4702 branches_);

4704 failures_);

4706 solutions_);

4708 smart_time_check_);

4711}

4712

4713bool RegularLimit::CheckTime(absl::Duration offset) {

4715}

4716

4717absl::Duration RegularLimit::TimeElapsed() {

4718 const int64_t kMaxSkip = 100;

4719 const int64_t kCheckWarmupIterations = 100;

4720 ++check_count_;

4722 next_check_ <= check_count_) {

4723 Solver* const s = solver();

4724 absl::Duration elapsed = s->Now() - solver_time_at_limit_start_;

4725 if (smart_time_check_ && check_count_ > kCheckWarmupIterations &&

4726 elapsed > absl::ZeroDuration()) {

4728 check_count_ * absl::FDivDuration(duration_limit_, elapsed));

4729 next_check_ =

4730 std::min(check_count_ + kMaxSkip, estimated_check_count_at_limit);

4731 }

4732 last_time_elapsed_ = elapsed;

4733 }

4734 return last_time_elapsed_;

4735}

4736

4738 return MakeLimit(time, std::numeric_limits<int64_t>::max(),

4739 std::numeric_limits<int64_t>::max(),

4740 std::numeric_limits<int64_t>::max(),

4741 false, false);

4742}

4743

4746 std::numeric_limits<int64_t>::max(),

4747 std::numeric_limits<int64_t>::max(),

4748 false, false);

4749}

4750

4752 return MakeLimit(absl::InfiniteDuration(),

4753 std::numeric_limits<int64_t>::max(), failures,

4754 std::numeric_limits<int64_t>::max(),

4755 false, false);

4756}

4757

4759 return MakeLimit(absl::InfiniteDuration(),

4760 std::numeric_limits<int64_t>::max(),

4761 std::numeric_limits<int64_t>::max(), solutions,

4762 false, false);

4763}

4764

4767 bool smart_time_check, bool cumulative) {

4769 smart_time_check, cumulative);

4770}

4771

4774 bool smart_time_check, bool cumulative) {

4776 smart_time_check, cumulative));

4777}

4778

4780 return MakeLimit(proto.time() == std::numeric_limits<int64_t>::max()

4781 ? absl::InfiniteDuration()

4782 : absl::Milliseconds(proto.time()),

4785}

4786

4789 proto.set_time(std::numeric_limits<int64_t>::max());

4790 proto.set_branches(std::numeric_limits<int64_t>::max());

4791 proto.set_failures(std::numeric_limits<int64_t>::max());

4792 proto.set_solutions(std::numeric_limits<int64_t>::max());

4795 return proto;

4796}

4797

4798

4799

4802 double objective_scaling_factor, double objective_offset,

4803 double improvement_rate_coefficient,

4804 int improvement_rate_solutions_distance)

4806 std::vector<bool>{maximize},

4807 std::vector<double>{objective_scaling_factor},

4808 std::vector<double>{objective_offset},

4809 improvement_rate_coefficient,

4810 improvement_rate_solutions_distance) {}

4811

4813 Solver* solver, std::vector<IntVar*> objective_vars,

4814 std::vector<bool> maximize, std::vector<double> objective_scaling_factors,

4815 std::vector<double> objective_offsets, double improvement_rate_coefficient,

4816 int improvement_rate_solutions_distance)

4818 objective_vars_(std::move(objective_vars)),

4819 maximize_(std::move(maximize)),

4820 objective_scaling_factors_(std::move(objective_scaling_factors)),

4821 objective_offsets_(std::move(objective_offsets)),

4822 improvement_rate_coefficient_(improvement_rate_coefficient),

4823 improvement_rate_solutions_distance_(improvement_rate_solutions_distance),

4824 best_objectives_(objective_vars_.size()),

4825 improvements_(objective_vars_.size()),

4826 thresholds_(objective_vars_.size(),

4827 std::numeric_limits<double>::infinity()) {

4829}

4830

4832

4837

4839 for (int i = 0; i < objective_vars_.size(); ++i) {

4840 best_objectives_[i] = std::numeric_limits<double>::infinity();

4841 improvements_[i].clear();

4842 thresholds_[i] = std::numeric_limits<double>::infinity();

4843 }

4844 objective_updated_ = false;

4845 gradient_stage_ = true;

4846}

4847

4851 objective_vars_ = improv->objective_vars_;

4852 maximize_ = improv->maximize_;

4853 objective_scaling_factors_ = improv->objective_scaling_factors_;

4854 objective_offsets_ = improv->objective_offsets_;

4855 improvement_rate_coefficient_ = improv->improvement_rate_coefficient_;

4856 improvement_rate_solutions_distance_ =

4857 improv->improvement_rate_solutions_distance_;

4858 improvements_ = improv->improvements_;

4859 thresholds_ = improv->thresholds_;

4860 best_objectives_ = improv->best_objectives_;

4861 objective_updated_ = improv->objective_updated_;

4862 gradient_stage_ = improv->gradient_stage_;

4863}

4864

4867 solver(), objective_vars_, maximize_, objective_scaling_factors_,

4868 objective_offsets_, improvement_rate_coefficient_,

4869 improvement_rate_solutions_distance_));

4870}

4871

4873 if (!objective_updated_) {

4874 return false;

4875 }

4876 objective_updated_ = false;

4877

4878 std::vector<double> improvement_rates(improvements_.size());

4879 for (int i = 0; i < improvements_.size(); ++i) {

4880 if (improvements_[i].size() <= improvement_rate_solutions_distance_) {

4881 return false;

4882 }

4883

4884 const auto [cur_obj, cur_neighbors] = improvements_[i].back();

4885 const auto [prev_obj, prev_neighbors] = improvements_[i].front();

4886 DCHECK_GT(cur_neighbors, prev_neighbors);

4887 improvement_rates[i] =

4888 (prev_obj - cur_obj) / (cur_neighbors - prev_neighbors);

4889 if (gradient_stage_) continue;

4890 const double scaled_improvement_rate =

4891 improvement_rate_coefficient_ * improvement_rates[i];

4892 if (scaled_improvement_rate < thresholds_[i]) {

4893 return true;

4894 } else if (scaled_improvement_rate > thresholds_[i]) {

4895 return false;

4896 }

4897 }

4898 if (gradient_stage_ && std::lexicographical_compare(

4899 improvement_rates.begin(), improvement_rates.end(),

4900 thresholds_.begin(), thresholds_.end())) {

4901 thresholds_ = std::move(improvement_rates);

4902 }

4903 return false;

4904}

4905

4907 std::vector<double> scaled_new_objectives(objective_vars_.size());

4908 for (int i = 0; i < objective_vars_.size(); ++i) {

4909 const int64_t new_objective =

4910 objective_vars_[i] != nullptr && objective_vars_[i]->Bound()

4911 ? objective_vars_[i]->Min()

4912 : (maximize_[i] ? solver()

4918

4919

4920 scaled_new_objectives[i] = (maximize_[i] ? -objective_scaling_factors_[i]

4921 : objective_scaling_factors_[i]) *

4922 (new_objective + objective_offsets_[i]);

4923 }

4924 const bool is_improvement = std::lexicographical_compare(

4925 scaled_new_objectives.begin(), scaled_new_objectives.end(),

4926 best_objectives_.begin(), best_objectives_.end());

4927 if (gradient_stage_ && !is_improvement) {

4928 gradient_stage_ = false;

4929

4930

4931 for (int i = 0; i < objective_vars_.size(); ++i) {

4932 if (thresholds_[i] == std::numeric_limits<double>::infinity()) {

4933 thresholds_[i] = -1;

4934 }

4935 }

4936 }

4937

4938 if (is_improvement) {

4939 objective_updated_ = true;

4940 for (int i = 0; i < objective_vars_.size(); ++i) {

4941 improvements_[i].push_back(

4942 std::make_pair(scaled_new_objectives[i], solver()->neighbors()));

4943

4944

4945

4946 if (improvements_[i].size() - 1 > improvement_rate_solutions_distance_) {

4947 improvements_[i].pop_front();

4948 }

4949 DCHECK_LE(improvements_[i].size() - 1,

4950 improvement_rate_solutions_distance_);

4951 }

4952 best_objectives_ = std::move(scaled_new_objectives);

4953 }

4954 return true;

4955}

4956

4958 IntVar* objective_var, bool maximize, double objective_scaling_factor,

4959 double objective_offset, double improvement_rate_coefficient,

4960 int improvement_rate_solutions_distance) {

4962 this, objective_var, maximize, objective_scaling_factor, objective_offset,

4963 improvement_rate_coefficient, improvement_rate_solutions_distance));

4964}

4965

4967 std::vector<IntVar*> objective_vars, std::vector<bool> maximize,

4968 std::vector<double> objective_scaling_factors,

4969 std::vector<double> objective_offsets, double improvement_rate_coefficient,

4970 int improvement_rate_solutions_distance) {

4972 this, std::move(objective_vars), std::move(maximize),

4973 std::move(objective_scaling_factors), std::move(objective_offsets),

4974 improvement_rate_coefficient, improvement_rate_solutions_distance));

4975}

4976

4977

4978namespace {

4980 public:

4982 : SearchLimit(limit_1->solver()), limit_1_(limit_1), limit_2_(limit_2) {

4983 CHECK(limit_1 != nullptr);

4984 CHECK(limit_2 != nullptr);

4985 CHECK_EQ(limit_1->solver(), limit_2->solver())

4986 << "Illegal arguments: cannot combines limits that belong to different "

4987 << "solvers, because the reversible allocations could delete one and "

4988 << "not the other.";

4989 }

4990

4991 bool CheckWithOffset(absl::Duration offset) override {

4992

4993

4994 const bool check_1 = limit_1_->CheckWithOffset(offset);

4995 const bool check_2 = limit_2_->CheckWithOffset(offset);

4996 return check_1 || check_2;

4997 }

4998

4999 void Init() override {

5000 limit_1_->Init();

5001 limit_2_->Init();

5002 }

5003

5004 void Copy(const SearchLimit* const) override {

5005 LOG(FATAL) << "Not implemented.";

5006 }

5007

5008 SearchLimit* MakeClone() const override {

5009

5010 return solver()->MakeLimit(limit_1_->MakeClone(), limit_2_->MakeClone());

5011 }

5012

5013 void EnterSearch() override {

5014 limit_1_->EnterSearch();

5015 limit_2_->EnterSearch();

5016 }

5017 void BeginNextDecision(DecisionBuilder* const b) override {

5018 limit_1_->BeginNextDecision(b);

5019 limit_2_->BeginNextDecision(b);

5020 }

5021 void PeriodicCheck() override {

5022 limit_1_->PeriodicCheck();

5023 limit_2_->PeriodicCheck();

5024 }

5025 void RefuteDecision(Decision* const d) override {

5026 limit_1_->RefuteDecision(d);

5027 limit_2_->RefuteDecision(d);

5028 }

5029 std::string DebugString() const override {

5030 return absl::StrCat("OR limit (", limit_1_->DebugString(), " OR ",

5031 limit_2_->DebugString(), ")");

5032 }

5033

5034 private:

5035 SearchLimit* const limit_1_;

5036 SearchLimit* const limit_2_;

5037};

5038}

5039

5042 return RevAlloc(new ORLimit(limit_1, limit_2));

5043}

5044

5045namespace {

5047 public:

5048 CustomLimit(Solver* s, std::function<bool()> limiter);

5049 bool CheckWithOffset(absl::Duration offset) override;

5050 void Init() override;

5051 void Copy(const SearchLimit* limit) override;

5052 SearchLimit* MakeClone() const override;

5053

5054 private:

5055 std::function<bool()> limiter_;

5056};

5057

5058CustomLimit::CustomLimit(Solver* const s, std::function<bool()> limiter)

5059 : SearchLimit(s), limiter_(std::move(limiter)) {}

5060

5061bool CustomLimit::CheckWithOffset(absl::Duration) {

5062

5063 if (limiter_) return limiter_();

5064 return false;

5065}

5066

5067void CustomLimit::Init() {}

5068

5069void CustomLimit::Copy(const SearchLimit* const limit) {

5070 const CustomLimit* const custom =

5071 reinterpret_cast<const CustomLimit* const>(limit);

5072 limiter_ = custom->limiter_;

5073}

5074

5075SearchLimit* CustomLimit::MakeClone() const {

5076 return solver()->RevAlloc(new CustomLimit(solver(), limiter_));

5077}

5078}

5079

5081 return RevAlloc(new CustomLimit(this, std::move(limiter)));

5082}

5083

5084

5085

5086namespace {

5088 public:

5089 explicit SolveOnce(DecisionBuilder* const db) : db_(db) {

5090 CHECK(db != nullptr);

5091 }

5092

5093 SolveOnce(DecisionBuilder* const db,

5094 const std::vector<SearchMonitor*>& monitors)

5095 : db_(db), monitors_(monitors) {

5096 CHECK(db != nullptr);

5097 }

5098

5099 ~SolveOnce() override {}

5100

5101 Decision* Next(Solver* s) override {

5102 bool res = s->SolveAndCommit(db_, monitors_);

5103 if (!res) {

5104 s->Fail();

5105 }

5106 return nullptr;

5107 }

5108

5109 std::string DebugString() const override {

5110 return absl::StrFormat("SolveOnce(%s)", db_->DebugString());

5111 }

5112

5113 void Accept(ModelVisitor* const visitor) const override {

5114 db_->Accept(visitor);

5115 }

5116

5117 private:

5118 DecisionBuilder* const db_;

5119 std::vector<SearchMonitor*> monitors_;

5120};

5121}

5122

5124 return RevAlloc(new SolveOnce(db));

5125}

5126

5129 std::vector<SearchMonitor*> monitors;

5130 monitors.push_back(monitor1);

5131 return RevAlloc(new SolveOnce(db, monitors));

5132}

5133

5137 std::vector<SearchMonitor*> monitors;

5138 monitors.push_back(monitor1);

5139 monitors.push_back(monitor2);

5140 return RevAlloc(new SolveOnce(db, monitors));

5141}

5142

5147 std::vector<SearchMonitor*> monitors;

5148 monitors.push_back(monitor1);

5149 monitors.push_back(monitor2);

5150 monitors.push_back(monitor3);

5151 return RevAlloc(new SolveOnce(db, monitors));

5152}

5153

5159 std::vector<SearchMonitor*> monitors;

5160 monitors.push_back(monitor1);

5161 monitors.push_back(monitor2);

5162 monitors.push_back(monitor3);

5163 monitors.push_back(monitor4);

5164 return RevAlloc(new SolveOnce(db, monitors));

5165}

5166

5168 DecisionBuilder* const db, const std::vector<SearchMonitor*>& monitors) {

5169 return RevAlloc(new SolveOnce(db, monitors));

5170}

5171

5172

5173

5174namespace {

5176 public:

5178 bool maximize, int64_t step)

5179 : db_(db),

5181 maximize_(maximize),

5182 step_(step),

5183 collector_(nullptr) {

5184 CHECK(db != nullptr);

5186 CHECK(solution->HasObjective());

5187 AddMonitors();

5188 }

5189

5190 NestedOptimize(DecisionBuilder* const db, Assignment* const solution,

5191 bool maximize, int64_t step,

5192 const std::vector<SearchMonitor*>& monitors)

5193 : db_(db),

5194 solution_(solution),

5195 maximize_(maximize),

5196 step_(step),

5197 monitors_(monitors),

5198 collector_(nullptr) {

5199 CHECK(db != nullptr);

5200 CHECK(solution != nullptr);

5201 CHECK(solution->HasObjective());

5202 AddMonitors();

5203 }

5204

5205 void AddMonitors() {

5206 Solver* const solver = solution_->solver();

5207 collector_ = solver->MakeLastSolutionCollector(solution_);

5208 monitors_.push_back(collector_);

5209 OptimizeVar* const optimize =

5210 solver->MakeOptimize(maximize_, solution_->Objective(), step_);

5211 monitors_.push_back(optimize);

5212 }

5213

5214 Decision* Next(Solver* solver) override {

5215 solver->Solve(db_, monitors_);

5217 solver->Fail();

5218 }

5220 return nullptr;

5221 }

5222

5223 std::string DebugString() const override {

5224 return absl::StrFormat("NestedOptimize(db = %s, maximize = %d, step = %d)",

5226 }

5227

5228 void Accept(ModelVisitor* const visitor) const override {

5229 db_->Accept(visitor);

5230 }

5231

5232 private:

5233 DecisionBuilder* const db_;

5234 Assignment* const solution_;

5235 const bool maximize_;

5236 const int64_t step_;

5237 std::vector<SearchMonitor*> monitors_;

5238 SolutionCollector* collector_;

5239};

5240}

5241

5244 bool maximize, int64_t step) {

5245 return RevAlloc(new NestedOptimize(db, solution, maximize, step));

5246}

5247

5250 bool maximize, int64_t step,

5252 std::vector<SearchMonitor*> monitors;

5253 monitors.push_back(monitor1);

5254 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));

5255}

5256

5259 bool maximize, int64_t step,

5262 std::vector<SearchMonitor*> monitors;

5263 monitors.push_back(monitor1);

5264 monitors.push_back(monitor2);

5265 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));

5266}

5267

5270 bool maximize, int64_t step,

5274 std::vector<SearchMonitor*> monitors;

5275 monitors.push_back(monitor1);

5276 monitors.push_back(monitor2);

5277 monitors.push_back(monitor3);

5278 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));

5279}

5280

5285 std::vector<SearchMonitor*> monitors;

5286 monitors.push_back(monitor1);

5287 monitors.push_back(monitor2);

5288 monitors.push_back(monitor3);

5289 monitors.push_back(monitor4);

5290 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));

5291}

5292

5295 int64_t step, const std::vector<SearchMonitor*>& monitors) {

5296 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));

5297}

5298

5299

5300

5301namespace {

5302

5303int64_t NextLuby(int i) {

5304 DCHECK_GT(i, 0);

5305 DCHECK_LT(i, std::numeric_limits<int32_t>::max());

5306 int64_t power;

5307

5308

5309 power = 2;

5310

5311 while (power < (i + 1)) {

5312 power <<= 1;

5313 }

5314 if (power == i + 1) {

5315 return (power / 2);

5316 }

5317 return NextLuby(i - (power / 2) + 1);

5318}

5319

5320class LubyRestart : public SearchMonitor {

5321 public:

5322 LubyRestart(Solver* const s, int scale_factor)

5323 : SearchMonitor(s),

5324 scale_factor_(scale_factor),

5325 iteration_(1),

5326 current_fails_(0),

5327 next_step_(scale_factor) {

5328 CHECK_GE(scale_factor, 1);

5329 }

5330

5331 ~LubyRestart() override {}

5332

5333 void BeginFail() override {

5334 if (++current_fails_ >= next_step_) {

5335 current_fails_ = 0;

5336 next_step_ = NextLuby(++iteration_) * scale_factor_;

5337 solver()->RestartCurrentSearch();

5338 }

5339 }

5340

5341 void Install() override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }

5342

5343 std::string DebugString() const override {

5344 return absl::StrFormat("LubyRestart(%i)", scale_factor_);

5345 }

5346

5347 private:

5348 const int scale_factor_;

5349 int iteration_;

5350 int64_t current_fails_;

5351 int64_t next_step_;

5352};

5353}

5354

5356 return RevAlloc(new LubyRestart(this, scale_factor));

5357}

5358

5359

5360

5361namespace {

5363 public:

5364 ConstantRestart(Solver* const s, int frequency)

5365 : SearchMonitor(s), frequency_(frequency), current_fails_(0) {

5366 CHECK_GE(frequency, 1);

5367 }

5368

5369 ~ConstantRestart() override {}

5370

5371 void BeginFail() override {

5372 if (++current_fails_ >= frequency_) {

5373 current_fails_ = 0;

5374 solver()->RestartCurrentSearch();

5375 }

5376 }

5377

5378 void Install() override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }

5379

5380 std::string DebugString() const override {

5381 return absl::StrFormat("ConstantRestart(%i)", frequency_);

5382 }

5383

5384 private:

5385 const int frequency_;

5386 int64_t current_fails_;

5387};

5388}

5389

5391 return RevAlloc(new ConstantRestart(this, frequency));

5392}

5393

5394

5395

5396

5397

5398

5399

5400

5401

5402

5403

5404

5405

5406

5407

5408

5409

5410

5412 public:

5414 const std::vector<SymmetryBreaker*>& visitors)

5416 visitors_(visitors),

5417 clauses_(visitors.size()),

5418 decisions_(visitors.size()),

5419 directions_(visitors.size()) {

5420 for (int i = 0; i < visitors_.size(); ++i) {

5421 visitors_[i]->set_symmetry_manager_and_index(this, i);

5422 }

5423 }

5424

5426

5428 if (d) {

5429 for (int i = 0; i < visitors_.size(); ++i) {

5430 const void* const last = clauses_[i].Last();

5431 d->Accept(visitors_[i]);

5432 if (last != clauses_[i].Last()) {

5433

5434 decisions_[i].Push(solver(), d);

5435 directions_[i].Push(solver(), false);

5436 }

5437 }

5438 }

5439 }

5440

5442 for (int i = 0; i < visitors_.size(); ++i) {

5443 if (decisions_[i].Last() != nullptr && decisions_[i].LastValue() == d) {

5445 }

5446 }

5447 }

5448

5449

5450

5455 {

5456 std::vector<IntVar*> guard;

5457

5458 ++tmp;

5459 ++tmp_dir;

5460 while (tmp.ok()) {

5461 IntVar* const term = *tmp;

5462 if (!*tmp_dir) {

5463 if (term->Max() == 0) {

5464

5465 return;

5466 }

5467 if (term->Min() == 0) {

5468 DCHECK_EQ(1, term->Max());

5469

5470 guard.push_back(term);

5471 }

5472 }

5473 ++tmp;

5474 ++tmp_dir;

5475 }

5476 guard.push_back(clauses_[index].LastValue());

5477 directions_[index].SetLastValue(true);

5478

5479

5480

5481

5482 ct = solver()->MakeEquality(solver()->MakeMin(guard), Zero());

5483 }

5484 DCHECK(ct != nullptr);

5485 solver()->AddConstraint(ct);

5486 }

5487

5489 clauses_[visitor->index_in_symmetry_manager()].Push(solver(), term);

5490 }

5491

5492 std::string DebugString() const override { return "SymmetryManager"; }

5493

5494 private:

5495 const std::vector<SymmetryBreaker*> visitors_;

5496 std::vector<SimpleRevFIFO<IntVar*>> clauses_;

5497 std::vector<SimpleRevFIFO<Decision*>> decisions_;

5498 std::vector<SimpleRevFIFO<bool>> directions_;

5499};

5500

5501

5502

5504 int64_t value) {

5505 CHECK(var != nullptr);

5508 symmetry_manager()->AddTermToClause(this, term);

5509}

5510

5512 IntVar* const var, int64_t value) {

5513 CHECK(var != nullptr);

5516 symmetry_manager()->AddTermToClause(this, term);

5517}

5518

5520 IntVar* const var, int64_t value) {

5521 CHECK(var != nullptr);

5524 symmetry_manager()->AddTermToClause(this, term);

5525}

5526

5527

5528

5530 const std::vector<SymmetryBreaker*>& visitors) {

5532}

5533

5535 std::vector<SymmetryBreaker*> visitors;

5536 visitors.push_back(v1);

5538}

5539

5542 std::vector<SymmetryBreaker*> visitors;

5543 visitors.push_back(v1);

5544 visitors.push_back(v2);

5546}

5547

5551 std::vector<SymmetryBreaker*> visitors;

5552 visitors.push_back(v1);

5553 visitors.push_back(v2);

5554 visitors.push_back(v3);

5556}

5557

5562 std::vector<SymmetryBreaker*> visitors;

5563 visitors.push_back(v1);

5564 visitors.push_back(v2);

5565 visitors.push_back(v3);

5566 visitors.push_back(v4);

5568}

5569}

const E & Element(const V *const var) const

int64_t Value(const IntVar *var) const

int64_t ObjectiveValueFromIndex(int index) const

bool HasObjective() const

void AddObjectives(const std::vector< IntVar * > &vars)

int64_t EndValue(const IntervalVar *var) const

const std::vector< int > & Unperformed(const SequenceVar *var) const

int64_t PerformedValue(const IntervalVar *var) const

int64_t StartValue(const IntervalVar *var) const

int64_t ObjectiveMinFromIndex(int index) const

void SetObjectiveMinFromIndex(int index, int64_t m)

const std::vector< int > & ForwardSequence(const SequenceVar *var) const

AssignmentContainer< IntVar, IntVarElement > IntContainer

IntVar * Objective() const

int64_t ObjectiveMaxFromIndex(int index) const

void SetObjectiveMaxFromIndex(int index, int64_t m)

int64_t DurationValue(const IntervalVar *var) const

IntVar * ObjectiveFromIndex(int index) const

const std::vector< int > & BackwardSequence(const SequenceVar *var) const

BaseObjectiveMonitor(Solver *solver)

bool Get(uint32_t index) const

void Set(uint32_t index, bool value)

virtual Decision * Next(Solver *s)=0

virtual void Accept(ModelVisitor *visitor) const

std::string DebugString() const override

virtual void Accept(DecisionVisitor *visitor) const

Accepts the given visitor.

bool CheckWithOffset(absl::Duration offset) override

Definition search.cc:4872

~ImprovementSearchLimit() override

Definition search.cc:4831

ImprovementSearchLimit(Solver *solver, IntVar *objective_var, bool maximize, double objective_scaling_factor, double objective_offset, double improvement_rate_coefficient, int improvement_rate_solutions_distance)

Definition search.cc:4800

void Init() override

This method is called when the search limit is initialized.

Definition search.cc:4838

void Install() override

Definition search.cc:4833

void Copy(const SearchLimit *limit) override

Definition search.cc:4848

bool AtSolution() override

Definition search.cc:4906

SearchLimit * MakeClone() const override

Allocates a clone of the limit.

Definition search.cc:4865

virtual void SetValue(int64_t v)

This method sets the value of the expression.

virtual bool Bound() const

Returns true if the min and the max of the expression are equal.

virtual void SetMax(int64_t m)=0

virtual int64_t Min() const =0

virtual void SetMin(int64_t m)=0

virtual int64_t Max() const =0

IntVar * Var() override

Creates a variable from the expression.

virtual int64_t Value() const =0

virtual void RemoveValue(int64_t v)=0

This method removes the value 'v' from the domain of the variable.

static int64_t FastInt64Round(double x)

static const char kStepArgument[]

static const char kSolutionLimitArgument[]

static const char kSearchLimitExtension[]

static const char kFailuresLimitArgument[]

static const char kObjectiveExtension[]

virtual void VisitIntegerArgument(const std::string &arg_name, int64_t value)

Visit integer arguments.

static const char kExpressionArgument[]

virtual void VisitIntegerVariableArrayArgument(const std::string &arg_name, const std::vector< IntVar * > &arguments)

virtual void VisitIntegerArrayArgument(const std::string &arg_name, const std::vector< int64_t > &values)

static const char kCumulativeArgument[]

static const char kBranchesLimitArgument[]

virtual void EndVisitExtension(const std::string &type)

virtual void BeginVisitExtension(const std::string &type)

static const char kSmartTimeCheckArgument[]

static const char kTimeLimitArgument[]

bool CurrentInternalValuesAreConstraining() const

Definition search.cc:3185

const std::vector< IntVar * > & minimization_vars() const

const std::vector< IntVar * > & objective_vars() const

int64_t Step(int index) const override

int Size() const override

void MakeMinimizationVarsLessOrEqualWithSteps(const T &upper_bounds)

bool found_initial_solution_

int64_t CurrentInternalValue(int index) const

bool Maximize(int index) const override

bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override

Definition search.cc:3135

void Accept(ModelVisitor *visitor) const override

Accepts the given model visitor.

Definition search.cc:3175

int64_t BestValue(int index) const override

bool AtSolution() override

Definition search.cc:3118

ObjectiveMonitor(Solver *solver, const std::vector< bool > &maximize, std::vector< IntVar * > vars, std::vector< int64_t > steps)

Definition search.cc:3077

void EnterSearch() override

Beginning of the search.

Definition search.cc:3111

IntVar * ObjectiveVar(int index) const override

IntVar * MinimizationVar(int index) const override

void ApplyBound()

Definition search.cc:3213

void BeginNextDecision(DecisionBuilder *db) override

Internal methods.

Definition search.cc:3207

void RefuteDecision(Decision *d) override

Before refuting the decision.

Definition search.cc:3236

bool AtSolution() override

Definition search.cc:3270

IntVar * var() const

Returns the variable that is optimized.

OptimizeVar(Solver *solver, bool maximize, IntVar *var, int64_t step)

Definition search.cc:3198

std::string DebugString() const override

Definition search.cc:3277

bool AcceptSolution() override

Definition search.cc:3250

virtual std::string Name() const

Definition search.cc:3275

std::string DebugString() const override

void set_branches(::int64_t value)

void set_failures(::int64_t value)

::int64_t branches() const

bool smart_time_check() const

void set_solutions(::int64_t value)

void set_smart_time_check(bool value)

void set_time(::int64_t value)

void set_cumulative(bool value)

::int64_t failures() const

::int64_t solutions() const

absl::Duration duration_limit() const

SearchLimit * MakeClone() const override

Allocates a clone of the limit.

Definition search.cc:4624

bool IsUncheckedSolutionLimitReached() override

Definition search.cc:4684

void Install() override

Definition search.cc:4605

bool CheckWithOffset(absl::Duration offset) override

Definition search.cc:4632

~RegularLimit() override

Definition search.cc:4603

int64_t wall_time() const

void Init() override

This method is called when the search limit is initialized.

Definition search.cc:4653

int64_t solutions() const

int ProgressPercent() override

Definition search.cc:4640

std::string DebugString() const override

Definition search.cc:4690

void Accept(ModelVisitor *visitor) const override

Accepts the given model visitor.

Definition search.cc:4698

void ExitSearch() override

End of the search.

Definition search.cc:4664

RegularLimit(Solver *s, absl::Duration time, int64_t branches, int64_t failures, int64_t solutions, bool smart_time_check, bool cumulative)

Definition search.cc:4584

void Copy(const SearchLimit *limit) override

Definition search.cc:4613

void UpdateLimits(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions)

Definition search.cc:4675

RegularLimit * MakeIdenticalClone() const

Definition search.cc:4626

Definition search.cc:2972

bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override

Definition search.cc:3004

void EnterSearch() override

Beginning of the search.

Definition search.cc:2982

bool Maximize(int index) const override

Definition search.cc:3045

void BeginNextDecision(DecisionBuilder *db) override

Before calling DecisionBuilder::Next.

Definition search.cc:3007

void ApplyDecision(Decision *d) override

Before applying the decision.

Definition search.cc:2991

void AcceptNeighbor() override

After accepting a neighbor during local search.

Definition search.cc:2994

int64_t BestValue(int index) const override

Definition search.cc:3048

bool AcceptSolution() override

Definition search.cc:3013

IntVar * MinimizationVar(int index) const override

Definition search.cc:3039

std::string DebugString() const override

Definition search.cc:3052

void RefuteDecision(Decision *d) override

Before refuting the decision.

Definition search.cc:3010

IntVar * ObjectiveVar(int index) const override

Definition search.cc:3036

int64_t Step(int index) const override

Definition search.cc:3042

int Size() const override

Definition search.cc:3051

bool AtLocalOptimum() override

Definition search.cc:3016

bool AtSolution() override

Definition search.cc:2997

void Accept(ModelVisitor *visitor) const override

Accepts the given model visitor.

Definition search.cc:3055

RoundRobinCompoundObjectiveMonitor(std::vector< BaseObjectiveMonitor * > monitors, int num_max_local_optima_before_metaheuristic_switch)

Definition search.cc:2974

Base class of all search limits.

~SearchLimit() override

Definition search.cc:4545

void BeginNextDecision(DecisionBuilder *b) override

Before calling DecisionBuilder::Next.

Definition search.cc:4559

void PeriodicCheck() override

Periodic call to check limits in long running methods.

Definition search.cc:4569

bool crossed() const

Returns true if the limit has been crossed.

void EnterSearch() override

Internal methods.

Definition search.cc:4554

virtual void Init()=0

This method is called when the search limit is initialized.

void Install() override

Definition search.cc:4547

SearchLimit(Solver *const s)

void RefuteDecision(Decision *d) override

Before refuting the decision.

Definition search.cc:4564

void BeginFail() override

Just when the failure occurs.

Definition search.cc:222

void NoMoreSolutions() override

When the search tree is finished.

Definition search.cc:224

void OutputDecision()

Definition search.cc:258

virtual void OutputLine(const std::string &line)

Definition search.cc:306

bool AtSolution() override

Definition search.cc:116

void AcceptUncheckedNeighbor() override

After accepting an unchecked neighbor during local search.

Definition search.cc:220

SearchLog(Solver *solver, std::vector< IntVar * > vars, std::string vars_name, std::vector< double > scaling_factors, std::vector< double > offsets, std::function< std::string()> display_callback, bool display_on_new_solutions_only, int period)

Definition search.cc:62

void EndInitialPropagation() override

After the initial propagation.

Definition search.cc:297

void BeginInitialPropagation() override

Before the initial propagation.

Definition search.cc:295

void RefuteDecision(Decision *decision) override

Before refuting the decision.

Definition search.cc:253

void ExitSearch() override

End of the search.

Definition search.cc:103

std::string DebugString() const override

Definition search.cc:86

void EnterSearch() override

Beginning of the search.

Definition search.cc:88

~SearchLog() override

Definition search.cc:84

void ApplyDecision(Decision *decision) override

Before applying the decision.

Definition search.cc:245

void Maintain()

Definition search.cc:288

A search monitor is a simple set of callbacks to monitor all search events.

static constexpr int kNoProgress

SearchMonitor(Solver *const s)

void ListenToEvent(Solver::MonitorEvent event)

This iterator is not stable with respect to deletion.

int64_t branches(int n) const

Returns the number of branches when the nth solution was found.

Definition search.cc:2494

SolutionData BuildSolutionDataForCurrentState()

Definition search.cc:2444

void AddObjectives(const std::vector< IntVar * > &objectives)

Definition search.cc:2421

const std::vector< int > & ForwardSequence(int n, SequenceVar *var) const

Definition search.cc:2534

int64_t objective_value(int n) const

Returns the objective value of the nth solution.

Definition search.cc:2504

~SolutionCollector() override

Definition search.cc:2346

void Add(IntVar *var)

Add API.

Definition search.cc:2379

std::vector< std::unique_ptr< Assignment > > solution_pool_

int64_t PerformedValue(int n, IntervalVar *var) const

This is a shortcut to get the PerformedValue of 'var' in the nth solution.

Definition search.cc:2530

void EnterSearch() override

Beginning of the search.

Definition search.cc:2427

void FreeSolution(Assignment *solution)

Definition search.cc:2465

void Push(const SolutionData &data)

void PopSolution()

Remove and delete the last popped solution.

Definition search.cc:2436

const std::vector< int > & Unperformed(int n, SequenceVar *var) const

Definition search.cc:2544

void AddObjective(IntVar *objective)

Definition search.cc:2415

bool has_solution() const

Returns whether any solutions were stored during the search.

Definition search.cc:2487

void check_index(int n) const

Definition search.cc:2471

int solution_count() const

Returns how many solutions were stored during the search.

Definition search.cc:2485

void Install() override

Definition search.cc:2375

int64_t wall_time(int n) const

Returns the wall time in ms for the nth solution.

Definition search.cc:2489

void PushSolution()

Push the current state as a new solution.

Definition search.cc:2432

int64_t DurationValue(int n, IntervalVar *var) const

This is a shortcut to get the DurationValue of 'var' in the nth solution.

Definition search.cc:2522

int64_t ObjectiveValueFromIndex(int n, int index) const

Returns the value of the index-th objective of the nth solution.

Definition search.cc:2509

int64_t failures(int n) const

Definition search.cc:2499

const std::vector< int > & BackwardSequence(int n, SequenceVar *var) const

Definition search.cc:2539

int64_t StartValue(int n, IntervalVar *var) const

This is a shortcut to get the StartValue of 'var' in the nth solution.

Definition search.cc:2518

SolutionCollector(Solver *solver, const Assignment *assignment)

Definition search.cc:2337

Assignment * solution(int n) const

Returns the nth solution.

Definition search.cc:2476

int64_t Value(int n, IntVar *var) const

This is a shortcut to get the Value of 'var' in the nth solution.

Definition search.cc:2514

std::vector< Assignment * > recycle_solutions_

std::vector< SolutionData > solution_data_

std::unique_ptr< Assignment > prototype_

Assignment * last_solution_or_null() const

Returns the last solution if there are any, nullptr otherwise.

Definition search.cc:2481

int64_t EndValue(int n, IntervalVar *var) const

This is a shortcut to get the EndValue of 'var' in the nth solution.

Definition search.cc:2526

std::function< int64_t(Solver *solver, const std::vector< IntVar * > &vars, int64_t first_unbound, int64_t last_unbound)> VariableIndexSelector

Decision * MakeAssignVariablesValuesOrDoNothing(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)

Definition search.cc:1880

DecisionBuilder * MakeSolveOnce(DecisionBuilder *db)

Definition search.cc:5123

int64_t accepted_neighbors() const

The number of accepted neighbors.

SearchMonitor * MakeEnterSearchCallback(std::function< void()> callback)

--— Callback-based search monitors --—

Definition search.cc:516

Decision * MakeAssignVariableValueOrFail(IntVar *var, int64_t value)

Definition search.cc:1680

IntVar * MakeIsEqualCstVar(IntExpr *var, int64_t value)

status var of (var == value)

Decision * MakeVariableLessOrEqualValue(IntVar *var, int64_t value)

Definition search.cc:1768

SearchMonitor * MakeLubyRestart(int scale_factor)

Definition search.cc:5355

int64_t branches() const

The number of branches explored since the creation of the solver.

OptimizeVar * MakeWeightedOptimize(bool maximize, const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)

Creates a weighted objective with a given sense (true = maximization).

Definition search.cc:3332

SearchMonitor * MakeConstantRestart(int frequency)

Definition search.cc:5390

int64_t solutions() const

The number of solutions found since the start of the search.

DecisionBuilder * MakeNestedOptimize(DecisionBuilder *db, Assignment *solution, bool maximize, int64_t step)

Definition search.cc:5242

ABSL_MUST_USE_RESULT RegularLimit * MakeSolutionsLimit(int64_t solutions)

Definition search.cc:4758

SolutionCollector * MakeBestValueSolutionCollector(const Assignment *assignment, bool maximize)

Definition search.cc:2756

IntVar * MakeIsLessOrEqualCstVar(IntExpr *var, int64_t value)

status var of (var <= value)

ABSL_MUST_USE_RESULT SearchLimit * MakeCustomLimit(std::function< bool()> limiter)

Definition search.cc:5080

void Fail()

Abandon the current branch in the search tree. A backtrack will follow.

ABSL_MUST_USE_RESULT RegularLimit * MakeFailuresLimit(int64_t failures)

Definition search.cc:4751

OptimizeVar * MakeWeightedMinimize(const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)

Definition search.cc:3339

Decision * MakeVariableGreaterOrEqualValue(IntVar *var, int64_t value)

Definition search.cc:1773

ABSL_MUST_USE_RESULT RegularLimit * MakeTimeLimit(absl::Duration time)

Creates a search limit that constrains the running time.

Definition search.cc:4737

std::function< int64_t(int64_t)> IndexEvaluator1

Callback typedefs.

std::function< int64_t(int64_t, int64_t, int64_t)> IndexEvaluator3

DecisionBuilder * Compose(DecisionBuilder *db1, DecisionBuilder *db2)

Definition search.cc:635

ObjectiveMonitor * MakeTabuSearch(bool maximize, IntVar *objective, int64_t step, const std::vector< IntVar * > &vars, int64_t keep_tenure, int64_t forbid_tenure, double tabu_factor)

MetaHeuristics which try to get the search out of local optima.

Definition search.cc:3725

DecisionBuilder * MakePhase(const std::vector< IntVar * > &vars, IntVarStrategy var_str, IntValueStrategy val_str)

Phases on IntVar arrays.

Definition search.cc:2142

Decision * MakeAssignVariableValue(IntVar *var, int64_t val)

Decisions.

Definition search.cc:1642

Decision * MakeAssignVariablesValuesOrFail(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)

Definition search.cc:1887

Decision * MakeSplitVariableDomain(IntVar *var, int64_t val, bool start_with_lower_half)

Definition search.cc:1763

ABSL_MUST_USE_RESULT ImprovementSearchLimit * MakeLexicographicImprovementLimit(std::vector< IntVar * > objective_vars, std::vector< bool > maximize, std::vector< double > objective_scaling_factors, std::vector< double > objective_offsets, double improvement_rate_coefficient, int improvement_rate_solutions_distance)

Definition search.cc:4966

OptimizeVar * MakeOptimize(bool maximize, IntVar *v, int64_t step)

Creates a objective with a given sense (true = maximization).

Definition search.cc:3296

std::function< void(Solver *)> Action

SearchMonitor * MakeAtSolutionCallback(std::function< void()> callback)

Definition search.cc:491

@ CHOOSE_MIN_SIZE_LOWEST_MIN

@ CHOOSE_RANDOM

Randomly select one of the remaining unbound variables.

@ CHOOSE_MIN_SIZE_LOWEST_MAX

@ INT_VAR_DEFAULT

The default behavior is CHOOSE_FIRST_UNBOUND.

@ INT_VAR_SIMPLE

The simple selection is CHOOSE_FIRST_UNBOUND.

@ CHOOSE_MIN_SIZE_HIGHEST_MAX

@ CHOOSE_MAX_REGRET_ON_MIN

@ CHOOSE_MIN_SIZE_HIGHEST_MIN

DecisionBuilder * Try(DecisionBuilder *db1, DecisionBuilder *db2)

Definition search.cc:783

std::function< int64_t(int64_t, int64_t)> IndexEvaluator2

SolutionCollector * MakeAllSolutionCollector()

Definition search.cc:2966

int64_t unchecked_solutions() const

The number of unchecked solutions found by local search.

IntVar * MakeIsGreaterOrEqualCstVar(IntExpr *var, int64_t value)

status var of (var >= value)

Decision * MakeDecision(Action apply, Action refute)

Definition search.cc:693

ObjectiveMonitor * MakeLexicographicSimulatedAnnealing(const std::vector< bool > &maximize, std::vector< IntVar * > vars, std::vector< int64_t > steps, std::vector< int64_t > initial_temperatures)

Definition search.cc:3847

SolutionCollector * MakeFirstSolutionCollector()

Definition search.cc:2608

SolutionCollector * MakeLastSolutionCollector()

Definition search.cc:2660

@ kIsUncheckedSolutionLimitReached

friend class SearchMonitor

SolutionCollector * MakeBestLexicographicValueSolutionCollector(const Assignment *assignment, std::vector< bool > maximize)

Definition search.cc:2761

SearchMonitor * MakeExitSearchCallback(std::function< void()> callback)

Definition search.cc:541

SearchMonitor * MakeSearchTrace(const std::string &prefix)

Definition search.cc:462

Decision * MakeAssignVariablesValues(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)

Definition search.cc:1872

SolutionCollector * MakeNBestValueSolutionCollector(const Assignment *assignment, int solution_count, bool maximize)

Definition search.cc:2882

ObjectiveMonitor * MakeLexicographicTabuSearch(const std::vector< bool > &maximize, std::vector< IntVar * > objectives, std::vector< int64_t > steps, const std::vector< IntVar * > &vars, int64_t keep_tenure, int64_t forbid_tenure, double tabu_factor)

Definition search.cc:3735

DecisionBuilder * MakeDecisionBuilderFromAssignment(Assignment *assignment, DecisionBuilder *db, const std::vector< IntVar * > &vars)

Definition search.cc:2327

int64_t wall_time() const

ABSL_MUST_USE_RESULT RegularLimit * MakeBranchesLimit(int64_t branches)

Definition search.cc:4744

SearchMonitor * MakeSearchLog(int branch_period)

Definition search.cc:334

ObjectiveMonitor * MakeSimulatedAnnealing(bool maximize, IntVar *v, int64_t step, int64_t initial_temperature)

Creates a Simulated Annealing monitor.

Definition search.cc:3840

OptimizeVar * MakeMinimize(IntVar *v, int64_t step)

Creates a minimization objective.

Definition search.cc:3288

ObjectiveMonitor * MakeGuidedLocalSearch(bool maximize, IntVar *objective, IndexEvaluator2 objective_function, int64_t step, const std::vector< IntVar * > &vars, double penalty_factor, std::function< std::vector< std::pair< int64_t, int64_t > >(int64_t, int64_t)> get_equivalent_pairs=nullptr, bool reset_penalties_on_new_best_solution=false)

Definition search.cc:4497

ABSL_MUST_USE_RESULT RegularLimit * MakeLimit(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions, bool smart_time_check=false, bool cumulative=false)

Definition search.cc:4772

OptimizeVar * MakeWeightedMaximize(const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)

Creates a maximization weigthed objective.

Definition search.cc:3346

Decision * MakeAssignVariableValueOrDoNothing(IntVar *var, int64_t value)

Definition search.cc:1709

SolutionCollector * MakeNBestLexicographicValueSolutionCollector(const Assignment *assignment, int solution_count, std::vector< bool > maximize)

Definition search.cc:2900

ConstraintSolverParameters parameters() const

Stored Parameters.

std::function< bool(int64_t, int64_t, int64_t)> VariableValueComparator

ObjectiveMonitor * MakeGenericTabuSearch(bool maximize, IntVar *v, int64_t step, const std::vector< IntVar * > &tabu_vars, int64_t forbid_tenure)

Definition search.cc:3744

Assignment * GetOrCreateLocalSearchState()

Returns (or creates) an assignment representing the state of local search.

@ ASSIGN_MAX_VALUE

Selects the max value of the selected variable.

@ INT_VALUE_DEFAULT

The default behavior is ASSIGN_MIN_VALUE.

@ INT_VALUE_SIMPLE

The simple selection is ASSIGN_MIN_VALUE.

@ ASSIGN_MIN_VALUE

Selects the min value of the selected variable.

@ ASSIGN_RANDOM_VALUE

Selects randomly one of the possible values of the selected variable.

OptimizeVar * MakeLexicographicOptimize(std::vector< bool > maximize, std::vector< IntVar * > variables, std::vector< int64_t > steps)

Definition search.cc:3301

SearchMonitor * MakeSymmetryManager(const std::vector< SymmetryBreaker * > &visitors)

Symmetry Breaking.

Definition search.cc:5529

int64_t failures() const

The number of failures encountered since the creation of the solver.

RegularLimitParameters MakeDefaultRegularLimitParameters() const

Creates a regular limit proto containing default values.

Definition search.cc:4787

Solver(const std::string &name)

Solver API.

BaseObjectiveMonitor * MakeRoundRobinCompoundObjectiveMonitor(std::vector< BaseObjectiveMonitor * > monitors, int num_max_local_optima_before_metaheuristic_switch)

Definition search.cc:3070

static int64_t MemoryUsage()

Current memory usage in bytes.

void SetUseFastLocalSearch(bool use_fast_local_search)

OptimizeVar * MakeMaximize(IntVar *v, int64_t step)

Creates a maximization objective.

Definition search.cc:3292

@ CHOOSE_DYNAMIC_GLOBAL_BEST

@ CHOOSE_STATIC_GLOBAL_BEST

ABSL_MUST_USE_RESULT ImprovementSearchLimit * MakeImprovementLimit(IntVar *objective_var, bool maximize, double objective_scaling_factor, double objective_offset, double improvement_rate_coefficient, int improvement_rate_solutions_distance)

Definition search.cc:4957

std::function< int64_t(const IntVar *v, int64_t id)> VariableValueSelector

void Set(IntegerType index)

void AddIntegerVariableGreaterOrEqualValueClause(IntVar *var, int64_t value)

Definition search.cc:5511

void AddIntegerVariableLessOrEqualValueClause(IntVar *var, int64_t value)

Definition search.cc:5519

void AddIntegerVariableEqualValueClause(IntVar *var, int64_t value)

Definition search.cc:5503

Definition search.cc:5411

void EndNextDecision(DecisionBuilder *const, Decision *const d) override

After calling DecisionBuilder::Next, along with the returned decision.

Definition search.cc:5427

void CheckSymmetries(int index)

Definition search.cc:5451

void RefuteDecision(Decision *d) override

Before refuting the decision.

Definition search.cc:5441

void AddTermToClause(SymmetryBreaker *const visitor, IntVar *const term)

Definition search.cc:5488

~SymmetryManager() override

Definition search.cc:5425

SymmetryManager(Solver *const s, const std::vector< SymmetryBreaker * > &visitors)

Definition search.cc:5413

std::string DebugString() const override

Definition search.cc:5492

bool operator==(const ProtoEnumIterator< E > &a, const ProtoEnumIterator< E > &b)

const MapUtilMappedT< Collection > & FindWithDefault(const Collection &collection, const KeyType &key, const MapUtilMappedT< Collection > &value)

For infeasible and unbounded see Not checked if options check_solutions_if_inf_or_unbounded and the If options first_solution_only is false

H AbslHashValue(H h, std::shared_ptr< Variable > i)

dual_gradient T(y - `dual_solution`) class DiagonalTrustRegionProblemFromQp

std::function< int64_t(const Model &)> Value(IntegerVariable v)

int64_t CapAdd(int64_t x, int64_t y)

std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)

Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid

void AcceptNeighbor(Search *search)

int64_t CapSub(int64_t x, int64_t y)

std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)

std::string MemoryUsage()

BaseAssignVariables::Mode ChooseMode(Solver::IntValueStrategy val_str)

Definition search.cc:2132

int64_t CapOpp(int64_t v)

bool AcceptDelta(Search *search, Assignment *delta, Assignment *deltadelta)

ABSL_FLAG(bool, cp_use_sparse_gls_penalties, false, "Use sparse implementation to store Guided Local Search penalties")

int64_t ObjectiveValue() const

Definition search.cc:2348

bool operator<(const SolutionData &other) const

Definition search.cc:2357

int64_t ObjectiveValueFromIndex(int index) const

Definition search.cc:2352

Creates a search monitor from logging parameters.

static const int64_t kint64max