OR-Tools  9.1
pack.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 // Packing constraints
15 
16 #include <algorithm>
17 #include <cstddef>
18 #include <cstdint>
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/strings/str_format.h"
25 #include "absl/strings/str_join.h"
27 #include "ortools/base/logging.h"
30 
31 namespace operations_research {
32 
33 // ---------- Dimension ----------
34 
35 class Dimension : public BaseObject {
36  public:
37  explicit Dimension(Solver* const s, Pack* const pack)
38  : solver_(s), pack_(pack) {}
39  ~Dimension() override {}
40 
41  virtual void Post() = 0;
42  virtual void InitialPropagate(int bin_index, const std::vector<int>& forced,
43  const std::vector<int>& undecided) = 0;
44  virtual void InitialPropagateUnassigned(
45  const std::vector<int>& assigned, const std::vector<int>& unassigned) = 0;
46  virtual void EndInitialPropagate() = 0;
47  virtual void Propagate(int bin_index, const std::vector<int>& forced,
48  const std::vector<int>& removed) = 0;
49  virtual void PropagateUnassigned(const std::vector<int>& assigned,
50  const std::vector<int>& unassigned) = 0;
51  virtual void EndPropagate() = 0;
52  std::string DebugString() const override { return "Dimension"; }
53  virtual void Accept(ModelVisitor* const visitor) const = 0;
54 
55  Solver* solver() const { return solver_; }
56 
57  bool IsUndecided(int var_index, int bin_index) const {
58  return pack_->IsUndecided(var_index, bin_index);
59  }
60 
61  bool IsPossible(int var_index, int bin_index) const {
62  return pack_->IsPossible(var_index, bin_index);
63  }
64 
65  IntVar* AssignVar(int var_index, int bin_index) const {
66  return pack_->AssignVar(var_index, bin_index);
67  }
68 
69  void SetImpossible(int var_index, int bin_index) {
70  pack_->SetImpossible(var_index, bin_index);
71  }
72 
73  void Assign(int var_index, int bin_index) {
74  pack_->Assign(var_index, bin_index);
75  }
76 
77  bool IsAssignedStatusKnown(int var_index) const {
78  return pack_->IsAssignedStatusKnown(var_index);
79  }
80 
81  void SetAssigned(int var_index) { pack_->SetAssigned(var_index); }
82 
83  void SetUnassigned(int var_index) { pack_->SetUnassigned(var_index); }
84 
85  void RemoveAllPossibleFromBin(int bin_index) {
86  pack_->RemoveAllPossibleFromBin(bin_index);
87  }
88 
89  void AssignAllPossibleToBin(int bin_index) {
90  pack_->AssignAllPossibleToBin(bin_index);
91  }
92 
93  void AssignFirstPossibleToBin(int bin_index) {
94  pack_->AssignFirstPossibleToBin(bin_index);
95  }
96 
98 
100 
101  private:
102  Solver* const solver_;
103  Pack* const pack_;
104 };
105 
106 // ----- Pack -----
107 
108 Pack::Pack(Solver* const s, const std::vector<IntVar*>& vars,
109  int number_of_bins)
110  : Constraint(s),
111  vars_(vars),
112  bins_(number_of_bins),
113  unprocessed_(new RevBitMatrix(bins_ + 1, vars_.size())),
114  forced_(bins_ + 1),
115  removed_(bins_ + 1),
116  holes_(vars_.size()),
117  stamp_(uint64_t{0}),
118  demon_(nullptr),
119  in_process_(false) {
120  for (int i = 0; i < vars_.size(); ++i) {
121  holes_[i] = vars_[i]->MakeHoleIterator(true);
122  }
123 }
124 
126 
127 void Pack::Post() {
128  for (int i = 0; i < vars_.size(); ++i) {
129  IntVar* const var = vars_[i];
130  if (!var->Bound()) {
131  Demon* const d = MakeConstraintDemon1(solver(), this, &Pack::OneDomain,
132  "OneDomain", i);
133  var->WhenDomain(d);
134  }
135  }
136  for (int i = 0; i < dims_.size(); ++i) {
137  dims_[i]->Post();
138  }
140  solver(), this, &Pack::Propagate, "Propagate"));
141 }
142 
144  for (int bin_index = 0; bin_index <= bins_; ++bin_index) {
145  forced_[bin_index].clear();
146  removed_[bin_index].clear();
147  }
148  to_set_.clear();
149  to_unset_.clear();
150  in_process_ = false;
151  stamp_ = solver()->fail_stamp();
152 }
153 
155  for (int i = 0; i < to_set_.size(); ++i) {
156  vars_[to_set_[i].first]->SetValue(to_set_[i].second);
157  }
158  for (int i = 0; i < to_unset_.size(); ++i) {
159  vars_[to_unset_[i].first]->RemoveValue(to_unset_[i].second);
160  }
161 }
162 
163 // A reversibly-allocable container for the data needed in
164 // Pack::InitialPropagate()
165 namespace {
166 class InitialPropagateData : public BaseObject {
167  public:
168  explicit InitialPropagateData(size_t num_bins)
169  : BaseObject(), undecided_(num_bins) {}
170  void PushAssigned(int index) { assigned_.push_back(index); }
171  void PushUnassigned(int index) { unassigned_.push_back(index); }
172  void PushUndecided(int bin, int index) {
173  undecided_.at(bin).push_back(index);
174  }
175  const std::vector<int>& undecided(int bin) const {
176  return undecided_.at(bin);
177  }
178  const std::vector<int>& assigned() const { return assigned_; }
179  const std::vector<int>& unassigned() const { return unassigned_; }
180 
181  std::string DebugString() const override { return "InitialPropagateData"; }
182 
183  private:
184  std::vector<std::vector<int>> undecided_;
185  std::vector<int> unassigned_;
186  std::vector<int> assigned_;
187 };
188 } // namespace
189 
191  const bool need_context = solver()->InstrumentsVariables();
192  ClearAll();
193  Solver* const s = solver();
194  in_process_ = true;
195  InitialPropagateData* data = s->RevAlloc(new InitialPropagateData(bins_));
196  for (int var_index = 0; var_index < vars_.size(); ++var_index) {
197  IntVar* const var = vars_[var_index];
198  var->SetRange(0, bins_); // bins_ -> item is not assigned to a bin.
199  if (var->Bound()) {
200  const int64_t value = var->Min();
201  if (value < bins_) {
202  forced_[value].push_back(var_index);
203  data->PushAssigned(var_index);
204  } else {
205  data->PushUnassigned(var_index);
206  }
207  } else {
208  DCHECK_GT(bins_, var->Min())
209  << "The variable maximum should be at most " << bins_
210  << ", and it should be unbound, so its min is expected to be less "
211  << "than " << bins_;
212  if (var->Max() < bins_) {
213  data->PushAssigned(var_index);
214  }
215  std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(false));
216  for (const int64_t value : InitAndGetValues(it.get())) {
217  if (value >= 0 && value <= bins_) {
218  unprocessed_->SetToOne(s, value, var_index);
219  if (value != bins_) {
220  data->PushUndecided(value, var_index);
221  }
222  }
223  }
224  }
225  }
226  for (int bin_index = 0; bin_index < bins_; ++bin_index) {
227  if (need_context) {
229  absl::StrFormat("Pack(bin %d, forced = [%s], undecided = [%s])",
230  bin_index, absl::StrJoin(forced_[bin_index], ", "),
231  absl::StrJoin(data->undecided(bin_index), ", ")));
232  }
233 
234  for (int dim_index = 0; dim_index < dims_.size(); ++dim_index) {
235  if (need_context) {
236  solver()->GetPropagationMonitor()->PushContext(absl::StrFormat(
237  "InitialProgateDimension(%s)", dims_[dim_index]->DebugString()));
238  }
239  dims_[dim_index]->InitialPropagate(bin_index, forced_[bin_index],
240  data->undecided(bin_index));
241  if (need_context) {
243  }
244  }
245  if (need_context) {
247  }
248  }
249  if (need_context) {
251  absl::StrFormat("Pack(assigned = [%s], unassigned = [%s])",
252  absl::StrJoin(data->assigned(), ", "),
253  absl::StrJoin(data->unassigned(), ", ")));
254  }
255  for (int dim_index = 0; dim_index < dims_.size(); ++dim_index) {
256  if (need_context) {
257  solver()->GetPropagationMonitor()->PushContext(absl::StrFormat(
258  "InitialProgateDimension(%s)", dims_[dim_index]->DebugString()));
259  }
260  dims_[dim_index]->InitialPropagateUnassigned(data->assigned(),
261  data->unassigned());
262  dims_[dim_index]->EndInitialPropagate();
263  if (need_context) {
265  }
266  }
267  if (need_context) {
269  }
270 
272  ClearAll();
273 }
274 
276  const bool need_context = solver()->InstrumentsVariables();
277  in_process_ = true;
278  DCHECK_EQ(stamp_, solver()->fail_stamp());
279  for (int bin_index = 0; bin_index < bins_; ++bin_index) {
280  if (!removed_[bin_index].empty() || !forced_[bin_index].empty()) {
281  if (need_context) {
283  absl::StrFormat("Pack(bin %d, forced = [%s], removed = [%s])",
284  bin_index, absl::StrJoin(forced_[bin_index], ", "),
285  absl::StrJoin(removed_[bin_index], ", ")));
286  }
287 
288  for (int dim_index = 0; dim_index < dims_.size(); ++dim_index) {
289  if (need_context) {
290  solver()->GetPropagationMonitor()->PushContext(absl::StrFormat(
291  "ProgateDimension(%s)", dims_[dim_index]->DebugString()));
292  }
293  dims_[dim_index]->Propagate(bin_index, forced_[bin_index],
294  removed_[bin_index]);
295  if (need_context) {
297  }
298  }
299  if (need_context) {
301  }
302  }
303  }
304  if (!removed_[bins_].empty() || !forced_[bins_].empty()) {
305  if (need_context) {
307  absl::StrFormat("Pack(removed = [%s], forced = [%s])",
308  absl::StrJoin(removed_[bins_], ", "),
309  absl::StrJoin(forced_[bins_], ", ")));
310  }
311 
312  for (int dim_index = 0; dim_index < dims_.size(); ++dim_index) {
313  if (need_context) {
314  solver()->GetPropagationMonitor()->PushContext(absl::StrFormat(
315  "ProgateDimension(%s)", dims_[dim_index]->DebugString()));
316  }
317  dims_[dim_index]->PropagateUnassigned(removed_[bins_], forced_[bins_]);
318  if (need_context) {
320  }
321  }
322  if (need_context) {
324  }
325  }
326  for (int dim_index = 0; dim_index < dims_.size(); ++dim_index) {
327  dims_[dim_index]->EndPropagate();
328  }
329 
331  ClearAll();
332 }
333 
334 void Pack::OneDomain(int var_index) {
335  // TODO(user): We know var ranges from 0 to bins_. There are lots
336  // of simplifications possible.
337  Solver* const s = solver();
338  const uint64_t current_stamp = s->fail_stamp();
339  if (stamp_ < current_stamp) {
340  stamp_ = current_stamp;
341  ClearAll();
342  }
343  IntVar* const var = vars_[var_index];
344  bool bound = var->Bound();
345  const int64_t oldmin = var->OldMin();
346  const int64_t oldmax = var->OldMax();
347  const int64_t vmin = var->Min();
348  const int64_t vmax = var->Max();
349  for (int64_t value = std::max(oldmin, int64_t{0});
350  value < std::min(vmin, bins_ + int64_t{1}); ++value) {
351  if (unprocessed_->IsSet(value, var_index)) {
352  unprocessed_->SetToZero(s, value, var_index);
353  removed_[value].push_back(var_index);
354  }
355  }
356  if (!bound) {
357  for (const int64_t value : InitAndGetValues(holes_[var_index])) {
358  if (value >= std::max(int64_t{0}, vmin) &&
359  value <= std::min(static_cast<int64_t>(bins_), vmax)) {
360  DCHECK(unprocessed_->IsSet(value, var_index));
361  unprocessed_->SetToZero(s, value, var_index);
362  removed_[value].push_back(var_index);
363  }
364  }
365  }
366  for (int64_t value = std::max(vmax + 1, int64_t{0});
367  value <= std::min(oldmax, static_cast<int64_t>(bins_)); ++value) {
368  if (unprocessed_->IsSet(value, var_index)) {
369  unprocessed_->SetToZero(s, value, var_index);
370  removed_[value].push_back(var_index);
371  }
372  }
373  if (bound) {
374  unprocessed_->SetToZero(s, var->Min(), var_index);
375  forced_[var->Min()].push_back(var_index);
376  }
377  EnqueueDelayedDemon(demon_);
378 }
379 
380 std::string Pack::DebugString() const {
381  std::string result = "Pack([";
382  for (int i = 0; i < vars_.size(); ++i) {
383  result += vars_[i]->DebugString() + " ";
384  }
385  result += "], dimensions = [";
386  for (int i = 0; i < dims_.size(); ++i) {
387  result += dims_[i]->DebugString() + " ";
388  }
389  absl::StrAppendFormat(&result, "], bins = %d)", bins_);
390  return result;
391 }
392 
393 void Pack::Accept(ModelVisitor* const visitor) const {
396  vars_);
398  for (int i = 0; i < dims_.size(); ++i) {
399  dims_[i]->Accept(visitor);
400  }
401  visitor->EndVisitConstraint(ModelVisitor::kPack, this);
402 }
403 
404 bool Pack::IsUndecided(int var_index, int bin_index) const {
405  return unprocessed_->IsSet(bin_index, var_index);
406 }
407 
408 void Pack::SetImpossible(int var_index, int bin_index) {
409  if (IsInProcess()) {
410  to_unset_.push_back(std::make_pair(var_index, bin_index));
411  } else {
412  vars_[var_index]->RemoveValue(bin_index);
413  }
414 }
415 
416 void Pack::Assign(int var_index, int bin_index) {
417  if (IsInProcess()) {
418  to_set_.push_back(std::make_pair(var_index, bin_index));
419  } else {
420  vars_[var_index]->SetValue(bin_index);
421  }
422 }
423 
424 bool Pack::IsAssignedStatusKnown(int var_index) const {
425  return !unprocessed_->IsSet(bins_, var_index);
426 }
427 
428 bool Pack::IsPossible(int var_index, int bin_index) const {
429  return vars_[var_index]->Contains(bin_index);
430 }
431 
432 IntVar* Pack::AssignVar(int var_index, int bin_index) const {
433  return solver()->MakeIsEqualCstVar(vars_[var_index], bin_index);
434 }
435 
436 void Pack::SetAssigned(int var_index) {
437  if (IsInProcess()) {
438  to_unset_.push_back(std::make_pair(var_index, bins_));
439  } else {
440  vars_[var_index]->RemoveValue(bins_);
441  }
442 }
443 
444 void Pack::SetUnassigned(int var_index) {
445  if (IsInProcess()) {
446  to_set_.push_back(std::make_pair(var_index, bins_));
447  } else {
448  vars_[var_index]->SetValue(bins_);
449  }
450 }
451 
452 bool Pack::IsInProcess() const {
453  return in_process_ && (solver()->fail_stamp() == stamp_);
454 }
455 
456 void Pack::RemoveAllPossibleFromBin(int bin_index) {
457  int var_index = unprocessed_->GetFirstBit(bin_index, 0);
458  while (var_index != -1 && var_index < vars_.size()) {
459  SetImpossible(var_index, bin_index);
460  var_index = var_index == vars_.size() - 1
461  ? -1
462  : unprocessed_->GetFirstBit(bin_index, var_index + 1);
463  }
464 }
465 
466 void Pack::AssignAllPossibleToBin(int bin_index) {
467  int var_index = unprocessed_->GetFirstBit(bin_index, 0);
468  while (var_index != -1 && var_index < vars_.size()) {
469  Assign(var_index, bin_index);
470  var_index = var_index == vars_.size() - 1
471  ? -1
472  : unprocessed_->GetFirstBit(bin_index, var_index + 1);
473  }
474 }
475 
476 void Pack::AssignFirstPossibleToBin(int bin_index) {
477  int var_index = unprocessed_->GetFirstBit(bin_index, 0);
478  if (var_index != -1 && var_index < vars_.size()) {
479  Assign(var_index, bin_index);
480  }
481 }
482 
484  int var_index = unprocessed_->GetFirstBit(bins_, 0);
485  while (var_index != -1 && var_index < vars_.size()) {
486  SetAssigned(var_index);
487  var_index = var_index == vars_.size() - 1
488  ? -1
489  : unprocessed_->GetFirstBit(bins_, var_index + 1);
490  }
491 }
492 
494  int var_index = unprocessed_->GetFirstBit(bins_, 0);
495  while (var_index != -1 && var_index < vars_.size()) {
496  SetUnassigned(var_index);
497  var_index = var_index == vars_.size() - 1
498  ? -1
499  : unprocessed_->GetFirstBit(bins_, var_index + 1);
500  }
501 }
502 
503 // ----- Dimension -----
504 
505 // ----- Class Dimension Less Than Constant -----
506 
507 namespace {
508 struct WeightContainer {
509  int index;
510  int64_t weight;
511  WeightContainer(int i, int64_t w) : index(i), weight(w) {}
512  bool operator<(const WeightContainer& c) const { return (weight < c.weight); }
513 };
514 
515 void SortWeightVector(std::vector<int>* const indices,
516  std::vector<WeightContainer>* const to_sort) {
517  std::sort(to_sort->begin(), to_sort->end());
518  for (int index = 0; index < to_sort->size(); ++index) {
519  (*indices)[index] = (*to_sort)[index].index;
520  }
521  indices->resize(to_sort->size());
522 }
523 
524 void SortIndexByWeight(std::vector<int>* const indices,
525  const std::vector<int64_t>& weights) {
526  std::vector<WeightContainer> to_sort;
527  for (int index = 0; index < indices->size(); ++index) {
528  if (weights[index] != 0) {
529  to_sort.push_back(WeightContainer((*indices)[index], weights[index]));
530  }
531  }
532  SortWeightVector(indices, &to_sort);
533 }
534 
535 void SortIndexByWeight(std::vector<int>* const indices,
536  const Solver::IndexEvaluator1& weights) {
537  std::vector<WeightContainer> to_sort;
538  for (int index = 0; index < indices->size(); ++index) {
539  const int w = weights(index);
540  if (w != 0) {
541  to_sort.push_back(WeightContainer((*indices)[index], w));
542  }
543  }
544  SortWeightVector(indices, &to_sort);
545 }
546 
547 void SortIndexByWeight(std::vector<int>* const indices,
548  const Solver::IndexEvaluator2& weights, int bin_index) {
549  std::vector<WeightContainer> to_sort;
550  for (int index = 0; index < indices->size(); ++index) {
551  const int w = weights(index, bin_index);
552  if (w != 0) {
553  to_sort.push_back(WeightContainer((*indices)[index], w));
554  }
555  }
556  SortWeightVector(indices, &to_sort);
557 }
558 
559 class DimensionLessThanConstant : public Dimension {
560  public:
561  DimensionLessThanConstant(Solver* const s, Pack* const p,
562  const std::vector<int64_t>& weights,
563  const std::vector<int64_t>& upper_bounds)
564  : Dimension(s, p),
565  vars_count_(weights.size()),
566  weights_(weights),
567  bins_count_(upper_bounds.size()),
568  upper_bounds_(upper_bounds),
569  first_unbound_backward_vector_(bins_count_, 0),
570  sum_of_bound_variables_vector_(bins_count_, 0LL),
571  ranked_(vars_count_) {
572  for (int i = 0; i < vars_count_; ++i) {
573  ranked_[i] = i;
574  }
575  SortIndexByWeight(&ranked_, weights_);
576  }
577 
578  ~DimensionLessThanConstant() override {}
579 
580  void Post() override {}
581 
582  void PushFromTop(int bin_index) {
583  const int64_t slack =
584  upper_bounds_[bin_index] - sum_of_bound_variables_vector_[bin_index];
585  if (slack < 0) {
586  solver()->Fail();
587  }
588  int last_unbound = first_unbound_backward_vector_[bin_index];
589  for (; last_unbound >= 0; --last_unbound) {
590  const int var_index = ranked_[last_unbound];
591  if (IsUndecided(var_index, bin_index)) {
592  if (weights_[var_index] > slack) {
593  SetImpossible(var_index, bin_index);
594  } else {
595  break;
596  }
597  }
598  }
599  first_unbound_backward_vector_.SetValue(solver(), bin_index, last_unbound);
600  }
601 
602  void InitialPropagate(int bin_index, const std::vector<int>& forced,
603  const std::vector<int>& undecided) override {
604  Solver* const s = solver();
605  int64_t sum = 0LL;
606  for (const int value : forced) {
607  sum += weights_[value];
608  }
609  sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
610  first_unbound_backward_vector_.SetValue(s, bin_index, ranked_.size() - 1);
611  PushFromTop(bin_index);
612  }
613 
614  void EndInitialPropagate() override {}
615 
616  void Propagate(int bin_index, const std::vector<int>& forced,
617  const std::vector<int>& removed) override {
618  if (!forced.empty()) {
619  Solver* const s = solver();
620  int64_t sum = sum_of_bound_variables_vector_[bin_index];
621  for (const int value : forced) {
622  sum += weights_[value];
623  }
624  sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
625  PushFromTop(bin_index);
626  }
627  }
628  void InitialPropagateUnassigned(const std::vector<int>& assigned,
629  const std::vector<int>& unassigned) override {
630  }
631  void PropagateUnassigned(const std::vector<int>& assigned,
632  const std::vector<int>& unassigned) override {}
633 
634  void EndPropagate() override {}
635 
636  void Accept(ModelVisitor* const visitor) const override {
637  visitor->BeginVisitExtension(ModelVisitor::kUsageLessConstantExtension);
638  visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
639  weights_);
640  visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument,
641  upper_bounds_);
642  visitor->EndVisitExtension(ModelVisitor::kUsageLessConstantExtension);
643  }
644 
645  private:
646  const int vars_count_;
647  const std::vector<int64_t> weights_;
648  const int bins_count_;
649  const std::vector<int64_t> upper_bounds_;
650  RevArray<int> first_unbound_backward_vector_;
651  RevArray<int64_t> sum_of_bound_variables_vector_;
652  std::vector<int> ranked_;
653 };
654 
655 class DimensionSumCallbackLessThanConstant : public Dimension {
656  public:
657  DimensionSumCallbackLessThanConstant(Solver* const s, Pack* const p,
658  const Solver::IndexEvaluator1& weights,
659  int vars_count,
660  const std::vector<int64_t>& upper_bounds)
661  : Dimension(s, p),
662  vars_count_(vars_count),
663  weights_(weights),
664  bins_count_(upper_bounds.size()),
665  upper_bounds_(upper_bounds),
666  first_unbound_backward_vector_(bins_count_, 0),
667  sum_of_bound_variables_vector_(bins_count_, 0LL),
668  ranked_(vars_count_) {
669  DCHECK(weights);
670  DCHECK_GT(vars_count, 0);
671  for (int i = 0; i < vars_count_; ++i) {
672  ranked_[i] = i;
673  }
674  SortIndexByWeight(&ranked_, weights_);
675  }
676 
677  ~DimensionSumCallbackLessThanConstant() override {}
678 
679  void Post() override {}
680 
681  void PushFromTop(int bin_index) {
682  const int64_t slack =
683  upper_bounds_[bin_index] - sum_of_bound_variables_vector_[bin_index];
684  if (slack < 0) {
685  solver()->Fail();
686  }
687  int last_unbound = first_unbound_backward_vector_[bin_index];
688  for (; last_unbound >= 0; --last_unbound) {
689  const int var_index = ranked_[last_unbound];
690  if (IsUndecided(var_index, bin_index)) {
691  if (weights_(var_index) > slack) {
692  SetImpossible(var_index, bin_index);
693  } else {
694  break;
695  }
696  }
697  }
698  first_unbound_backward_vector_.SetValue(solver(), bin_index, last_unbound);
699  }
700 
701  void InitialPropagate(int bin_index, const std::vector<int>& forced,
702  const std::vector<int>& undecided) override {
703  Solver* const s = solver();
704  int64_t sum = 0LL;
705  for (const int value : forced) {
706  sum += weights_(value);
707  }
708  sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
709  first_unbound_backward_vector_.SetValue(s, bin_index, ranked_.size() - 1);
710  PushFromTop(bin_index);
711  }
712 
713  void EndInitialPropagate() override {}
714 
715  void Propagate(int bin_index, const std::vector<int>& forced,
716  const std::vector<int>& removed) override {
717  if (!forced.empty()) {
718  Solver* const s = solver();
719  int64_t sum = sum_of_bound_variables_vector_[bin_index];
720  for (const int value : forced) {
721  sum += weights_(value);
722  }
723  sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
724  PushFromTop(bin_index);
725  }
726  }
727  void InitialPropagateUnassigned(const std::vector<int>& assigned,
728  const std::vector<int>& unassigned) override {
729  }
730  void PropagateUnassigned(const std::vector<int>& assigned,
731  const std::vector<int>& unassigned) override {}
732 
733  void EndPropagate() override {}
734 
735  void Accept(ModelVisitor* const visitor) const override {
736  visitor->BeginVisitExtension(ModelVisitor::kUsageLessConstantExtension);
737  // TODO(user) : Visit weight correctly.
738  // visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
739  // weights_);
740  visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument,
741  upper_bounds_);
742  visitor->EndVisitExtension(ModelVisitor::kUsageLessConstantExtension);
743  }
744 
745  private:
746  const int vars_count_;
747  Solver::IndexEvaluator1 weights_;
748  const int bins_count_;
749  const std::vector<int64_t> upper_bounds_;
750  RevArray<int> first_unbound_backward_vector_;
751  RevArray<int64_t> sum_of_bound_variables_vector_;
752  std::vector<int> ranked_;
753 };
754 
755 class DimensionLessThanConstantCallback2 : public Dimension {
756  public:
757  DimensionLessThanConstantCallback2(Solver* const s, Pack* const p,
758  const Solver::IndexEvaluator2& weights,
759  int vars_count,
760  const std::vector<int64_t>& upper_bounds)
761  : Dimension(s, p),
762  vars_count_(vars_count),
763  weights_(weights),
764  bins_count_(upper_bounds.size()),
765  upper_bounds_(upper_bounds),
766  first_unbound_backward_vector_(bins_count_, 0),
767  sum_of_bound_variables_vector_(bins_count_, 0LL),
768  ranked_(bins_count_) {
769  DCHECK(weights);
770  DCHECK_GT(vars_count, 0);
771  for (int b = 0; b < bins_count_; ++b) {
772  ranked_[b].resize(vars_count);
773  for (int i = 0; i < vars_count_; ++i) {
774  ranked_[b][i] = i;
775  }
776  SortIndexByWeight(&ranked_[b], weights_, b);
777  }
778  }
779 
780  ~DimensionLessThanConstantCallback2() override {}
781 
782  void Post() override {}
783 
784  void PushFromTop(int bin_index) {
785  const int64_t slack =
786  upper_bounds_[bin_index] - sum_of_bound_variables_vector_[bin_index];
787  if (slack < 0) {
788  solver()->Fail();
789  }
790  int last_unbound = first_unbound_backward_vector_[bin_index];
791  for (; last_unbound >= 0; --last_unbound) {
792  const int var_index = ranked_[bin_index][last_unbound];
793  if (IsUndecided(var_index, bin_index)) {
794  if (weights_(var_index, bin_index) > slack) {
795  SetImpossible(var_index, bin_index);
796  } else {
797  break;
798  }
799  }
800  }
801  first_unbound_backward_vector_.SetValue(solver(), bin_index, last_unbound);
802  }
803 
804  void InitialPropagate(int bin_index, const std::vector<int>& forced,
805  const std::vector<int>& undecided) override {
806  Solver* const s = solver();
807  int64_t sum = 0LL;
808  for (const int value : forced) {
809  sum += weights_(value, bin_index);
810  }
811  sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
812  first_unbound_backward_vector_.SetValue(s, bin_index,
813  ranked_[bin_index].size() - 1);
814  PushFromTop(bin_index);
815  }
816 
817  void EndInitialPropagate() override {}
818 
819  void Propagate(int bin_index, const std::vector<int>& forced,
820  const std::vector<int>& removed) override {
821  if (!forced.empty()) {
822  Solver* const s = solver();
823  int64_t sum = sum_of_bound_variables_vector_[bin_index];
824  for (const int value : forced) {
825  sum += weights_(value, bin_index);
826  }
827  sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
828  PushFromTop(bin_index);
829  }
830  }
831  void InitialPropagateUnassigned(const std::vector<int>& assigned,
832  const std::vector<int>& unassigned) override {
833  }
834  void PropagateUnassigned(const std::vector<int>& assigned,
835  const std::vector<int>& unassigned) override {}
836 
837  void EndPropagate() override {}
838 
839  void Accept(ModelVisitor* const visitor) const override {
840  visitor->BeginVisitExtension(ModelVisitor::kUsageLessConstantExtension);
841  // TODO(user): Visit weight correctly
842  // visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
843  // weights_);
844  visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument,
845  upper_bounds_);
846  visitor->EndVisitExtension(ModelVisitor::kUsageLessConstantExtension);
847  }
848 
849  private:
850  const int vars_count_;
851  Solver::IndexEvaluator2 weights_;
852  const int bins_count_;
853  const std::vector<int64_t> upper_bounds_;
854  RevArray<int> first_unbound_backward_vector_;
855  RevArray<int64_t> sum_of_bound_variables_vector_;
856  std::vector<std::vector<int>> ranked_;
857 };
858 
859 class DimensionWeightedSumEqVar : public Dimension {
860  public:
861  class VarDemon : public Demon {
862  public:
863  VarDemon(DimensionWeightedSumEqVar* const dim, int index)
864  : dim_(dim), index_(index) {}
865  ~VarDemon() override {}
866 
867  void Run(Solver* const s) override { dim_->PushFromTop(index_); }
868 
869  private:
870  DimensionWeightedSumEqVar* const dim_;
871  const int index_;
872  };
873 
874  DimensionWeightedSumEqVar(Solver* const s, Pack* const p,
875  const std::vector<int64_t>& weights,
876  const std::vector<IntVar*>& loads)
877  : Dimension(s, p),
878  vars_count_(weights.size()),
879  weights_(weights),
880  bins_count_(loads.size()),
881  loads_(loads),
882  first_unbound_backward_vector_(bins_count_, 0),
883  sum_of_bound_variables_vector_(bins_count_, 0LL),
884  sum_of_all_variables_vector_(bins_count_, 0LL),
885  ranked_(vars_count_) {
886  DCHECK_GT(vars_count_, 0);
887  DCHECK_GT(bins_count_, 0);
888  for (int i = 0; i < vars_count_; ++i) {
889  ranked_[i] = i;
890  }
891  SortIndexByWeight(&ranked_, weights_);
892  }
893 
894  ~DimensionWeightedSumEqVar() override {}
895 
896  std::string DebugString() const override {
897  return "DimensionWeightedSumEqVar";
898  }
899 
900  void Post() override {
901  for (int i = 0; i < bins_count_; ++i) {
902  Demon* const d = solver()->RevAlloc(new VarDemon(this, i));
903  loads_[i]->WhenRange(d);
904  }
905  }
906 
907  void PushFromTop(int bin_index) {
908  IntVar* const load = loads_[bin_index];
909  const int64_t sum_min = sum_of_bound_variables_vector_[bin_index];
910  const int64_t sum_max = sum_of_all_variables_vector_[bin_index];
911  load->SetRange(sum_min, sum_max);
912  const int64_t slack_up = load->Max() - sum_min;
913  const int64_t slack_down = sum_max - load->Min();
914  DCHECK_GE(slack_down, 0);
915  DCHECK_GE(slack_up, 0);
916  int last_unbound = first_unbound_backward_vector_[bin_index];
917  for (; last_unbound >= 0; --last_unbound) {
918  const int var_index = ranked_[last_unbound];
919  const int64_t weight = weights_[var_index];
920  if (IsUndecided(var_index, bin_index)) {
921  if (weight > slack_up) {
922  SetImpossible(var_index, bin_index);
923  } else if (weight > slack_down) {
924  Assign(var_index, bin_index);
925  } else {
926  break;
927  }
928  }
929  }
930  first_unbound_backward_vector_.SetValue(solver(), bin_index, last_unbound);
931  }
932 
933  void InitialPropagate(int bin_index, const std::vector<int>& forced,
934  const std::vector<int>& undecided) override {
935  Solver* const s = solver();
936  int64_t sum = 0LL;
937  for (const int value : forced) {
938  sum += weights_[value];
939  }
940  sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
941  for (const int value : undecided) {
942  sum += weights_[value];
943  }
944  sum_of_all_variables_vector_.SetValue(s, bin_index, sum);
945  first_unbound_backward_vector_.SetValue(s, bin_index, ranked_.size() - 1);
946  PushFromTop(bin_index);
947  }
948 
949  void EndInitialPropagate() override {}
950 
951  void Propagate(int bin_index, const std::vector<int>& forced,
952  const std::vector<int>& removed) override {
953  Solver* const s = solver();
954  int64_t down = sum_of_bound_variables_vector_[bin_index];
955  for (const int value : forced) {
956  down += weights_[value];
957  }
958  sum_of_bound_variables_vector_.SetValue(s, bin_index, down);
959  int64_t up = sum_of_all_variables_vector_[bin_index];
960  for (const int value : removed) {
961  up -= weights_[value];
962  }
963  sum_of_all_variables_vector_.SetValue(s, bin_index, up);
964  PushFromTop(bin_index);
965  }
966  void InitialPropagateUnassigned(const std::vector<int>& assigned,
967  const std::vector<int>& unassigned) override {
968  }
969  void PropagateUnassigned(const std::vector<int>& assigned,
970  const std::vector<int>& unassigned) override {}
971 
972  void EndPropagate() override {}
973 
974  void Accept(ModelVisitor* const visitor) const override {
975  visitor->BeginVisitExtension(ModelVisitor::kUsageEqualVariableExtension);
976  visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
977  weights_);
978  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
979  loads_);
980  visitor->EndVisitExtension(ModelVisitor::kUsageEqualVariableExtension);
981  }
982 
983  private:
984  const int vars_count_;
985  const std::vector<int64_t> weights_;
986  const int bins_count_;
987  const std::vector<IntVar*> loads_;
988  RevArray<int> first_unbound_backward_vector_;
989  RevArray<int64_t> sum_of_bound_variables_vector_;
990  RevArray<int64_t> sum_of_all_variables_vector_;
991  std::vector<int> ranked_;
992 };
993 
994 class DimensionWeightedCallback2SumEqVar : public Dimension {
995  public:
996  class VarDemon : public Demon {
997  public:
998  VarDemon(DimensionWeightedCallback2SumEqVar* const dim, int index)
999  : dim_(dim), index_(index) {}
1000  ~VarDemon() override {}
1001 
1002  void Run(Solver* const s) override { dim_->PushFromTop(index_); }
1003 
1004  private:
1005  DimensionWeightedCallback2SumEqVar* const dim_;
1006  const int index_;
1007  };
1008 
1009  DimensionWeightedCallback2SumEqVar(Solver* const s, Pack* const p,
1010  const Solver::IndexEvaluator2& weights,
1011  int vars_count,
1012  const std::vector<IntVar*>& loads)
1013  : Dimension(s, p),
1014  vars_count_(vars_count),
1015  weights_(weights),
1016  bins_count_(loads.size()),
1017  loads_(loads),
1018  first_unbound_backward_vector_(bins_count_, 0),
1019  sum_of_bound_variables_vector_(bins_count_, 0LL),
1020  sum_of_all_variables_vector_(bins_count_, 0LL),
1021  ranked_(bins_count_) {
1022  DCHECK(weights);
1023  DCHECK_GT(vars_count_, 0);
1024  DCHECK_GT(bins_count_, 0);
1025  for (int b = 0; b < bins_count_; ++b) {
1026  ranked_[b].resize(vars_count);
1027  for (int i = 0; i < vars_count_; ++i) {
1028  ranked_[b][i] = i;
1029  }
1030  SortIndexByWeight(&ranked_[b], weights_, b);
1031  }
1032  }
1033 
1034  ~DimensionWeightedCallback2SumEqVar() override {}
1035 
1036  std::string DebugString() const override {
1037  return "DimensionWeightedCallback2SumEqVar";
1038  }
1039 
1040  void Post() override {
1041  for (int i = 0; i < bins_count_; ++i) {
1042  Demon* const d = solver()->RevAlloc(new VarDemon(this, i));
1043  loads_[i]->WhenRange(d);
1044  }
1045  }
1046 
1047  void PushFromTop(int bin_index) {
1048  IntVar* const load = loads_[bin_index];
1049  const int64_t sum_min = sum_of_bound_variables_vector_[bin_index];
1050  const int64_t sum_max = sum_of_all_variables_vector_[bin_index];
1051  load->SetRange(sum_min, sum_max);
1052  const int64_t slack_up = load->Max() - sum_min;
1053  const int64_t slack_down = sum_max - load->Min();
1054  DCHECK_GE(slack_down, 0);
1055  DCHECK_GE(slack_up, 0);
1056  int last_unbound = first_unbound_backward_vector_[bin_index];
1057  for (; last_unbound >= 0; --last_unbound) {
1058  const int var_index = ranked_[bin_index][last_unbound];
1059  const int64_t weight = weights_(var_index, bin_index);
1060  if (IsUndecided(var_index, bin_index)) {
1061  if (weight > slack_up) {
1062  SetImpossible(var_index, bin_index);
1063  } else if (weight > slack_down) {
1064  Assign(var_index, bin_index);
1065  } else {
1066  break;
1067  }
1068  }
1069  }
1070  first_unbound_backward_vector_.SetValue(solver(), bin_index, last_unbound);
1071  }
1072 
1073  void InitialPropagate(int bin_index, const std::vector<int>& forced,
1074  const std::vector<int>& undecided) override {
1075  Solver* const s = solver();
1076  int64_t sum = 0LL;
1077  for (const int value : forced) {
1078  sum += weights_(value, bin_index);
1079  }
1080  sum_of_bound_variables_vector_.SetValue(s, bin_index, sum);
1081  for (const int value : undecided) {
1082  sum += weights_(value, bin_index);
1083  }
1084  sum_of_all_variables_vector_.SetValue(s, bin_index, sum);
1085  first_unbound_backward_vector_.SetValue(s, bin_index,
1086  ranked_[bin_index].size() - 1);
1087  PushFromTop(bin_index);
1088  }
1089 
1090  void EndInitialPropagate() override {}
1091 
1092  void Propagate(int bin_index, const std::vector<int>& forced,
1093  const std::vector<int>& removed) override {
1094  Solver* const s = solver();
1095  int64_t down = sum_of_bound_variables_vector_[bin_index];
1096  for (const int value : forced) {
1097  down += weights_(value, bin_index);
1098  }
1099  sum_of_bound_variables_vector_.SetValue(s, bin_index, down);
1100  int64_t up = sum_of_all_variables_vector_[bin_index];
1101  for (const int value : removed) {
1102  up -= weights_(value, bin_index);
1103  }
1104  sum_of_all_variables_vector_.SetValue(s, bin_index, up);
1105  PushFromTop(bin_index);
1106  }
1107  void InitialPropagateUnassigned(const std::vector<int>& assigned,
1108  const std::vector<int>& unassigned) override {
1109  }
1110  void PropagateUnassigned(const std::vector<int>& assigned,
1111  const std::vector<int>& unassigned) override {}
1112 
1113  void EndPropagate() override {}
1114 
1115  void Accept(ModelVisitor* const visitor) const override {
1116  visitor->BeginVisitExtension(ModelVisitor::kUsageEqualVariableExtension);
1117  // TODO(user): Visit weight correctly
1118  // visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
1119  // weights_);
1120  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1121  loads_);
1122  visitor->EndVisitExtension(ModelVisitor::kUsageEqualVariableExtension);
1123  }
1124 
1125  private:
1126  const int vars_count_;
1127  Solver::IndexEvaluator2 weights_;
1128  const int bins_count_;
1129  const std::vector<IntVar*> loads_;
1130  RevArray<int> first_unbound_backward_vector_;
1131  RevArray<int64_t> sum_of_bound_variables_vector_;
1132  RevArray<int64_t> sum_of_all_variables_vector_;
1133  std::vector<std::vector<int>> ranked_;
1134 };
1135 
1136 class AssignedWeightedSumDimension : public Dimension {
1137  public:
1138  class VarDemon : public Demon {
1139  public:
1140  explicit VarDemon(AssignedWeightedSumDimension* const dim) : dim_(dim) {}
1141  ~VarDemon() override {}
1142 
1143  void Run(Solver* const s) override { dim_->PropagateAll(); }
1144 
1145  private:
1146  AssignedWeightedSumDimension* const dim_;
1147  };
1148 
1149  AssignedWeightedSumDimension(Solver* const s, Pack* const p,
1150  const std::vector<int64_t>& weights,
1151  int bins_count, IntVar* const cost_var)
1152  : Dimension(s, p),
1153  vars_count_(weights.size()),
1154  weights_(weights),
1155  bins_count_(bins_count),
1156  cost_var_(cost_var),
1157  first_unbound_backward_(0),
1158  sum_of_assigned_items_(0LL),
1159  sum_of_unassigned_items_(0LL),
1160  ranked_(vars_count_),
1161  sum_all_weights_(0LL) {
1162  DCHECK(cost_var);
1163  DCHECK_GT(vars_count_, 0);
1164  DCHECK_GT(bins_count_, 0);
1165  for (int i = 0; i < vars_count_; ++i) {
1166  ranked_[i] = i;
1167  }
1168  SortIndexByWeight(&ranked_, weights_);
1169  first_unbound_backward_.SetValue(s, ranked_.size() - 1);
1170  }
1171 
1172  ~AssignedWeightedSumDimension() override {}
1173 
1174  void Post() override {
1175  Demon* const uv = solver()->RevAlloc(new VarDemon(this));
1176  cost_var_->WhenRange(uv);
1177  }
1178 
1179  void PropagateAll() {
1180  cost_var_->SetRange(sum_of_assigned_items_.Value(),
1181  sum_all_weights_ - sum_of_unassigned_items_.Value());
1182  const int64_t slack_up = cost_var_->Max() - sum_of_assigned_items_.Value();
1183  const int64_t slack_down = sum_all_weights_ - cost_var_->Min();
1184  int last_unbound = first_unbound_backward_.Value();
1185  for (; last_unbound >= 0; --last_unbound) {
1186  const int var_index = ranked_[last_unbound];
1187  if (!IsAssignedStatusKnown(var_index)) {
1188  const int64_t coefficient = weights_[var_index];
1189  if (coefficient > slack_up) {
1190  SetUnassigned(var_index);
1191  } else if (coefficient > slack_down) {
1192  SetAssigned(var_index);
1193  } else {
1194  break;
1195  }
1196  }
1197  }
1198  first_unbound_backward_.SetValue(solver(), last_unbound);
1199  }
1200 
1201  void InitialPropagate(int bin_index, const std::vector<int>& forced,
1202  const std::vector<int>& undecided) override {}
1203 
1204  void EndInitialPropagate() override {}
1205 
1206  void InitialPropagateUnassigned(const std::vector<int>& assigned,
1207  const std::vector<int>& unassigned) override {
1208  for (int index = 0; index < vars_count_; ++index) {
1209  sum_all_weights_ += weights_[index];
1210  }
1211 
1212  PropagateUnassigned(assigned, unassigned);
1213  }
1214 
1215  void Propagate(int bin_index, const std::vector<int>& forced,
1216  const std::vector<int>& removed) override {}
1217 
1218  void PropagateUnassigned(const std::vector<int>& assigned,
1219  const std::vector<int>& unassigned) override {
1220  int64_t sum_assigned = sum_of_assigned_items_.Value();
1221  for (int index = 0; index < assigned.size(); ++index) {
1222  const int var_index = assigned[index];
1223  sum_assigned += weights_[var_index];
1224  }
1225 
1226  int64_t sum_unassigned = sum_of_unassigned_items_.Value();
1227  for (int index = 0; index < unassigned.size(); ++index) {
1228  const int var_index = unassigned[index];
1229  sum_unassigned += weights_[var_index];
1230  }
1231 
1232  Solver* const s = solver();
1233  sum_of_assigned_items_.SetValue(s, sum_assigned);
1234  sum_of_unassigned_items_.SetValue(s, sum_unassigned);
1235  PropagateAll();
1236  }
1237 
1238  void EndPropagate() override {}
1239 
1240  void Accept(ModelVisitor* const visitor) const override {
1241  visitor->BeginVisitExtension(
1243  visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
1244  weights_);
1245  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1246  cost_var_);
1247  visitor->EndVisitExtension(
1249  }
1250 
1251  private:
1252  const int vars_count_;
1253  const std::vector<int64_t> weights_;
1254  const int bins_count_;
1255  IntVar* const cost_var_;
1256  Rev<int> first_unbound_backward_;
1257  Rev<int64_t> sum_of_assigned_items_;
1258  Rev<int64_t> sum_of_unassigned_items_;
1259  std::vector<int> ranked_;
1260  int64_t sum_all_weights_;
1261 };
1262 
1263 // ----- Count unassigned jobs dimension -----
1264 
1265 class CountAssignedItemsDimension : public Dimension {
1266  public:
1267  class VarDemon : public Demon {
1268  public:
1269  explicit VarDemon(CountAssignedItemsDimension* const dim) : dim_(dim) {}
1270  ~VarDemon() override {}
1271 
1272  void Run(Solver* const s) override { dim_->PropagateAll(); }
1273 
1274  private:
1275  CountAssignedItemsDimension* const dim_;
1276  };
1277 
1278  CountAssignedItemsDimension(Solver* const s, Pack* const p, int vars_count,
1279  int bins_count, IntVar* const cost_var)
1280  : Dimension(s, p),
1281  vars_count_(vars_count),
1282  bins_count_(bins_count),
1283  cost_var_(cost_var),
1284  first_unbound_backward_(0),
1285  assigned_count_(0),
1286  unassigned_count_(0) {
1287  DCHECK(cost_var);
1288  DCHECK_GT(vars_count, 0);
1289  DCHECK_GT(bins_count, 0);
1290  }
1291 
1292  ~CountAssignedItemsDimension() override {}
1293 
1294  void Post() override {
1295  Demon* const uv = solver()->RevAlloc(new VarDemon(this));
1296  cost_var_->WhenRange(uv);
1297  }
1298 
1299  void PropagateAll() {
1300  cost_var_->SetRange(assigned_count_.Value(),
1301  vars_count_ - unassigned_count_.Value());
1302  if (assigned_count_.Value() == cost_var_->Max()) {
1303  UnassignAllRemainingItems();
1304  } else if (cost_var_->Min() == vars_count_ - unassigned_count_.Value()) {
1305  AssignAllRemainingItems();
1306  }
1307  }
1308 
1309  void InitialPropagate(int bin_index, const std::vector<int>& forced,
1310  const std::vector<int>& undecided) override {}
1311 
1312  void EndInitialPropagate() override {}
1313 
1314  void InitialPropagateUnassigned(const std::vector<int>& assigned,
1315  const std::vector<int>& unassigned) override {
1316  PropagateUnassigned(assigned, unassigned);
1317  }
1318 
1319  void Propagate(int bin_index, const std::vector<int>& forced,
1320  const std::vector<int>& removed) override {}
1321 
1322  void PropagateUnassigned(const std::vector<int>& assigned,
1323  const std::vector<int>& unassigned) override {
1324  Solver* const s = solver();
1325  assigned_count_.SetValue(s, assigned_count_.Value() + assigned.size());
1326  unassigned_count_.SetValue(s,
1327  unassigned_count_.Value() + unassigned.size());
1328  PropagateAll();
1329  }
1330 
1331  void EndPropagate() override {}
1332 
1333  void Accept(ModelVisitor* const visitor) const override {
1334  visitor->BeginVisitExtension(ModelVisitor::kCountAssignedItemsExtension);
1335  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1336  cost_var_);
1337  visitor->EndVisitExtension(ModelVisitor::kCountAssignedItemsExtension);
1338  }
1339 
1340  private:
1341  const int vars_count_;
1342  const int bins_count_;
1343  IntVar* const cost_var_;
1344  Rev<int> first_unbound_backward_;
1345  Rev<int> assigned_count_;
1346  Rev<int> unassigned_count_;
1347 };
1348 
1349 // ----- Count used bin dimension -----
1350 
1351 class CountUsedBinDimension : public Dimension {
1352  public:
1353  class VarDemon : public Demon {
1354  public:
1355  explicit VarDemon(CountUsedBinDimension* const dim) : dim_(dim) {}
1356  ~VarDemon() override {}
1357 
1358  void Run(Solver* const s) override { dim_->PropagateAll(); }
1359 
1360  private:
1361  CountUsedBinDimension* const dim_;
1362  };
1363 
1364  CountUsedBinDimension(Solver* const s, Pack* const p, int vars_count,
1365  int bins_count, IntVar* const count_var)
1366  : Dimension(s, p),
1367  vars_count_(vars_count),
1368  bins_count_(bins_count),
1369  count_var_(count_var),
1370  used_(bins_count_),
1371  candidates_(bins_count_, 0),
1372  card_min_(0),
1373  card_max_(bins_count_),
1374  initial_min_(0),
1375  initial_max_(0) {
1376  DCHECK(count_var);
1377  DCHECK_GT(vars_count, 0);
1378  DCHECK_GT(bins_count, 0);
1379  }
1380 
1381  ~CountUsedBinDimension() override {}
1382 
1383  void Post() override {
1384  Demon* const uv = solver()->RevAlloc(new VarDemon(this));
1385  count_var_->WhenRange(uv);
1386  initial_min_ = 0;
1387  initial_max_ = bins_count_;
1388  }
1389 
1390  void PropagateAll() {
1391  count_var_->SetRange(card_min_.Value(), card_max_.Value());
1392  if (card_min_.Value() == count_var_->Max()) {
1393  for (int bin_index = 0; bin_index < bins_count_; ++bin_index) {
1394  if (!used_.IsSet(bin_index) && candidates_[bin_index] > 0) {
1395  RemoveAllPossibleFromBin(bin_index);
1396  }
1397  }
1398  } else if (card_max_.Value() == count_var_->Min()) {
1399  for (int bin_index = 0; bin_index < bins_count_; ++bin_index) {
1400  if (candidates_[bin_index] == 1) {
1401  AssignFirstPossibleToBin(bin_index);
1402  }
1403  }
1404  }
1405  }
1406 
1407  void InitialPropagate(int bin_index, const std::vector<int>& forced,
1408  const std::vector<int>& undecided) override {
1409  if (!forced.empty()) {
1410  used_.SetToOne(solver(), bin_index);
1411  initial_min_++;
1412  } else if (!undecided.empty()) {
1413  candidates_.SetValue(solver(), bin_index, undecided.size());
1414  } else {
1415  initial_max_--;
1416  }
1417  }
1418 
1419  void EndInitialPropagate() override {
1420  card_min_.SetValue(solver(), initial_min_);
1421  card_max_.SetValue(solver(), initial_max_);
1422  PropagateAll();
1423  }
1424 
1425  void InitialPropagateUnassigned(const std::vector<int>& assigned,
1426  const std::vector<int>& unassigned) override {
1427  }
1428 
1429  void Propagate(int bin_index, const std::vector<int>& forced,
1430  const std::vector<int>& removed) override {
1431  if (!used_.IsSet(bin_index)) {
1432  if (!forced.empty()) {
1433  used_.SetToOne(solver(), bin_index);
1434  card_min_.SetValue(solver(), card_min_.Value() + 1);
1435  } else if (!removed.empty()) {
1436  candidates_.SetValue(solver(), bin_index,
1437  candidates_.Value(bin_index) - removed.size());
1438  if (candidates_[bin_index] == 0) {
1439  card_max_.SetValue(solver(), card_max_.Value() - 1);
1440  }
1441  }
1442  }
1443  }
1444 
1445  void PropagateUnassigned(const std::vector<int>& assigned,
1446  const std::vector<int>& unassigned) override {}
1447 
1448  void EndPropagate() override { PropagateAll(); }
1449 
1450  void Accept(ModelVisitor* const visitor) const override {
1451  visitor->BeginVisitExtension(ModelVisitor::kCountUsedBinsExtension);
1452  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1453  count_var_);
1454  visitor->EndVisitExtension(ModelVisitor::kCountUsedBinsExtension);
1455  }
1456 
1457  private:
1458  const int vars_count_;
1459  const int bins_count_;
1460  IntVar* const count_var_;
1461  RevBitSet used_;
1462  RevArray<int> candidates_;
1463  Rev<int> card_min_;
1464  Rev<int> card_max_;
1465  int initial_min_;
1466  int initial_max_;
1467 };
1468 
1469 // ---------- Variable Usage Dimension ----------
1470 
1471 // This is a very naive, but correct implementation of the constraint.
1472 class VariableUsageDimension : public Dimension {
1473  public:
1474  VariableUsageDimension(Solver* const solver, Pack* const pack,
1475  const std::vector<int64_t>& capacities,
1476  const std::vector<IntVar*>& weights)
1477  : Dimension(solver, pack), capacities_(capacities), weights_(weights) {}
1478 
1479  ~VariableUsageDimension() override {}
1480 
1481  void Post() override {
1482  Solver* const s = solver();
1483  const int num_bins = capacities_.size();
1484  const int num_items = weights_.size();
1485 
1486  for (int bin_index = 0; bin_index < num_bins; ++bin_index) {
1487  std::vector<IntVar*> terms;
1488  for (int item_index = 0; item_index < num_items; ++item_index) {
1489  IntVar* const assign_var = AssignVar(item_index, bin_index);
1490  terms.push_back(s->MakeProd(assign_var, weights_[item_index])->Var());
1491  }
1492  s->AddConstraint(s->MakeSumLessOrEqual(terms, capacities_[bin_index]));
1493  }
1494  }
1495 
1496  void InitialPropagate(int bin_index, const std::vector<int>& forced,
1497  const std::vector<int>& undecided) override {}
1498  void InitialPropagateUnassigned(const std::vector<int>& assigned,
1499  const std::vector<int>& unassigned) override {
1500  }
1501  void EndInitialPropagate() override {}
1502  void Propagate(int bin_index, const std::vector<int>& forced,
1503  const std::vector<int>& removed) override {}
1504  void PropagateUnassigned(const std::vector<int>& assigned,
1505  const std::vector<int>& unassigned) override {}
1506  void EndPropagate() override {}
1507 
1508  std::string DebugString() const override { return "VariableUsageDimension"; }
1509 
1510  void Accept(ModelVisitor* const visitor) const override {
1511  visitor->BeginVisitExtension(
1513  visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument,
1514  capacities_);
1515  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1516  weights_);
1517  visitor->EndVisitExtension(
1519  }
1520 
1521  private:
1522  const std::vector<int64_t> capacities_;
1523  const std::vector<IntVar*> weights_;
1524 };
1525 } // namespace
1526 
1527 // ---------- API ----------
1528 
1530  const std::vector<int64_t>& weights, const std::vector<int64_t>& bounds) {
1531  CHECK_EQ(weights.size(), vars_.size());
1532  CHECK_EQ(bounds.size(), bins_);
1533  Solver* const s = solver();
1534  Dimension* const dim =
1535  s->RevAlloc(new DimensionLessThanConstant(s, this, weights, bounds));
1536  dims_.push_back(dim);
1537 }
1538 
1540  Solver::IndexEvaluator1 weights, const std::vector<int64_t>& bounds) {
1541  CHECK(weights != nullptr);
1542  CHECK_EQ(bounds.size(), bins_);
1543  Solver* const s = solver();
1544  Dimension* const dim = s->RevAlloc(new DimensionSumCallbackLessThanConstant(
1545  s, this, weights, vars_.size(), bounds));
1546  dims_.push_back(dim);
1547 }
1548 
1550  Solver::IndexEvaluator2 weights, const std::vector<int64_t>& bounds) {
1551  CHECK(weights != nullptr);
1552  CHECK_EQ(bounds.size(), bins_);
1553  Solver* const s = solver();
1554  Dimension* const dim = s->RevAlloc(new DimensionLessThanConstantCallback2(
1555  s, this, weights, vars_.size(), bounds));
1556  dims_.push_back(dim);
1557 }
1558 
1559 void Pack::AddWeightedSumEqualVarDimension(const std::vector<int64_t>& weights,
1560  const std::vector<IntVar*>& loads) {
1561  CHECK_EQ(weights.size(), vars_.size());
1562  CHECK_EQ(loads.size(), bins_);
1563  Solver* const s = solver();
1564  Dimension* const dim =
1565  s->RevAlloc(new DimensionWeightedSumEqVar(s, this, weights, loads));
1566  dims_.push_back(dim);
1567 }
1568 
1570  const std::vector<IntVar*>& loads) {
1571  CHECK(weights != nullptr);
1572  CHECK_EQ(loads.size(), bins_);
1573  Solver* const s = solver();
1574  Dimension* const dim = s->RevAlloc(new DimensionWeightedCallback2SumEqVar(
1575  s, this, weights, vars_.size(), loads));
1576  dims_.push_back(dim);
1577 }
1578 
1580  const std::vector<int64_t>& weights, IntVar* const cost_var) {
1581  CHECK_EQ(weights.size(), vars_.size());
1582  Solver* const s = solver();
1583  Dimension* const dim = s->RevAlloc(
1584  new AssignedWeightedSumDimension(s, this, weights, bins_, cost_var));
1585  dims_.push_back(dim);
1586 }
1587 
1589  const std::vector<IntVar*>& usage, const std::vector<int64_t>& capacity) {
1590  CHECK_EQ(usage.size(), vars_.size());
1591  CHECK_EQ(capacity.size(), bins_);
1592  Solver* const s = solver();
1593  Dimension* const dim =
1594  s->RevAlloc(new VariableUsageDimension(s, this, capacity, usage));
1595  dims_.push_back(dim);
1596 }
1597 
1598 void Pack::AddCountUsedBinDimension(IntVar* const count_var) {
1599  Solver* const s = solver();
1600  Dimension* const dim = s->RevAlloc(
1601  new CountUsedBinDimension(s, this, vars_.size(), bins_, count_var));
1602  dims_.push_back(dim);
1603 }
1604 
1606  Solver* const s = solver();
1607  Dimension* const dim = s->RevAlloc(
1608  new CountAssignedItemsDimension(s, this, vars_.size(), bins_, count_var));
1609  dims_.push_back(dim);
1610 }
1611 
1612 Pack* Solver::MakePack(const std::vector<IntVar*>& vars, int number_of_bins) {
1613  return RevAlloc(new Pack(this, vars, number_of_bins));
1614 }
1615 } // namespace operations_research
#define CHECK(condition)
Definition: base/logging.h:491
IntVar * MakeIsEqualCstVar(IntExpr *const var, int64_t value)
status var of (var == value)
Definition: expr_cst.cc:462
void Assign(int var_index, int bin_index)
Definition: pack.cc:416
int64_t bound
virtual void PropagateUnassigned(const std::vector< int > &assigned, const std::vector< int > &unassigned)=0
void Assign(int var_index, int bin_index)
Definition: pack.cc:73
int64_t min
Definition: alldiff_cst.cc:139
void AddWeightedSumOfAssignedDimension(const std::vector< int64_t > &weights, IntVar *const cost_var)
This dimension enforces that cost_var == sum of weights[i] for all objects 'i' assigned to a bin.
Definition: pack.cc:1579
void RemoveAllPossibleFromBin(int bin_index)
Definition: pack.cc:456
std::vector< IntVarIterator * > holes_
virtual void VisitIntegerVariableArrayArgument(const std::string &arg_name, const std::vector< IntVar * > &arguments)
Matrix version of the RevBitSet class.
std::function< int64_t(int64_t)> IndexEvaluator1
Callback typedefs.
virtual void BeginVisitConstraint(const std::string &type_name, const Constraint *const constraint)
void AssignAllRemainingItems()
Definition: pack.cc:483
void AddSumVariableWeightsLessOrEqualConstantDimension(const std::vector< IntVar * > &usage, const std::vector< int64_t > &capacity)
This dimension imposes: forall b in bins, sum (i in items: usage[i] * is_assigned(i,...
Definition: pack.cc:1588
A Demon is the base element of a propagation queue.
void OneDomain(int var_index)
Definition: pack.cc:334
Dimension(Solver *const s, Pack *const pack)
Definition: pack.cc:37
void AddWeightedSumLessOrEqualConstantDimension(const std::vector< int64_t > &weights, const std::vector< int64_t > &bounds)
Dimensions are additional constraints than can restrict what is possible with the pack constraint.
Definition: pack.cc:1529
virtual void InitialPropagate(int bin_index, const std::vector< int > &forced, const std::vector< int > &undecided)=0
bool InstrumentsVariables() const
Returns whether we are tracing variables.
void AssignFirstPossibleToBin(int bin_index)
Definition: pack.cc:476
A constraint is the main modeling object.
#define DCHECK_GT(val1, val2)
Definition: base/logging.h:891
int64_t coefficient
std::string DebugString() const override
Definition: pack.cc:52
Solver * solver() const
Definition: pack.cc:55
void SetImpossible(int var_index, int bin_index)
Definition: pack.cc:408
void AddCountAssignedItemsDimension(IntVar *const count_var)
This dimension links 'count_var' to the actual number of items assigned to a bin in the pack.
Definition: pack.cc:1605
void SetAssigned(int var_index)
Definition: pack.cc:81
int64_t b
virtual void Accept(ModelVisitor *const visitor) const =0
const int64_t stamp_
Definition: search.cc:3054
PropagationMonitor * GetPropagationMonitor() const
Returns the propagation monitor.
virtual void PushContext(const std::string &context)=0
bool IsAssignedStatusKnown(int var_index) const
Definition: pack.cc:77
int64_t max
Definition: alldiff_cst.cc:140
bool in_process_
Definition: interval.cc:428
bool IsUndecided(int var_index, int bin_index) const
Definition: pack.cc:404
static const char kCountUsedBinsExtension[]
int64_t weight
Definition: pack.cc:510
void AssignAllPossibleToBin(int bin_index)
Definition: pack.cc:89
std::string DebugString() const override
Definition: pack.cc:380
void AddWeightedSumEqualVarDimension(const std::vector< int64_t > &weights, const std::vector< IntVar * > &loads)
This dimension imposes that for all bins b, the weighted sum (weights[i]) of all objects i assigned t...
Definition: pack.cc:1559
bool IsPossible(int var_index, int bin_index) const
Definition: pack.cc:61
Pack(Solver *const s, const std::vector< IntVar * > &vars, int number_of_bins)
Definition: pack.cc:108
static const char kUsageLessConstantExtension[]
Pack * MakePack(const std::vector< IntVar * > &vars, int number_of_bins)
This constraint packs all variables onto 'number_of_bins' variables.
Definition: pack.cc:1612
static const char kCountAssignedItemsExtension[]
Extension names:
Demon * RegisterDemon(Demon *const demon)
Adds a new demon and wraps it inside a DemonProfiler if necessary.
void SetUnassigned(int var_index)
Definition: pack.cc:444
void AddCountUsedBinDimension(IntVar *const count_var)
This dimension links 'count_var' to the actual number of bins used in the pack.
Definition: pack.cc:1598
bool IsUndecided(int var_index, int bin_index) const
Definition: pack.cc:57
int64_t capacity
virtual void EndInitialPropagate()=0
void UnassignAllRemainingItems()
Definition: pack.cc:493
bool IsPossible(int var_index, int bin_index) const
Definition: pack.cc:428
void SetAssigned(int var_index)
Definition: pack.cc:436
int index
Definition: pack.cc:509
static const char kUsageEqualVariableExtension[]
void SetImpossible(int var_index, int bin_index)
Definition: pack.cc:69
A BaseObject is the root of all reversibly allocated objects.
The class IntVar is a subset of IntExpr.
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:890
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:698
const std::vector< IntVar * > vars_
Definition: alldiff_cst.cc:44
virtual void VisitIntegerArgument(const std::string &arg_name, int64_t value)
Visit integer arguments.
std::function< int64_t(int64_t, int64_t)> IndexEvaluator2
T * RevAlloc(T *object)
Registers the given object as being reversible.
static const char kWeightedSumOfAssignedEqualVariableExtension[]
#define DCHECK(condition)
Definition: base/logging.h:885
void Post() override
This method is called when the constraint is processed by the solver.
Definition: pack.cc:127
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:886
void InitialPropagate() override
This method performs the initial propagation of the constraint.
Definition: pack.cc:190
void SetValue(Solver *const s, const T &val)
uint64_t fail_stamp() const
The fail_stamp() is incremented after each backtrack.
SharedBoundsManager * bounds
Collection of objects used to extend the Constraint Solver library.
virtual void EndVisitConstraint(const std::string &type_name, const Constraint *const constraint)
IntVar * AssignVar(int var_index, int bin_index) const
Definition: pack.cc:432
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
std::vector< double > upper_bounds
IntVar * var
Definition: expr_array.cc:1874
virtual void Propagate(int bin_index, const std::vector< int > &forced, const std::vector< int > &removed)=0
void EnqueueDelayedDemon(Demon *const d)
This method pushes the demon onto the propagation queue.
void RemoveAllPossibleFromBin(int bin_index)
Definition: pack.cc:85
void Accept(ModelVisitor *const visitor) const override
Accepts the given visitor.
Definition: pack.cc:393
virtual void InitialPropagateUnassigned(const std::vector< int > &assigned, const std::vector< int > &unassigned)=0
IntVar * AssignVar(int var_index, int bin_index) const
Definition: pack.cc:65
void AssignFirstPossibleToBin(int bin_index)
Definition: pack.cc:93
void AssignAllPossibleToBin(int bin_index)
Definition: pack.cc:466
bool IsAssignedStatusKnown(int var_index) const
Definition: pack.cc:424
int64_t value
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
void SetUnassigned(int var_index)
Definition: pack.cc:83
Utility class to encapsulate an IntVarIterator and use it in a range-based loop.
static const char kVariableUsageLessConstantExtension[]