OR-Tools  9.0
expr_array.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 //
15 // Array Expression constraints
16 
17 #include <algorithm>
18 #include <cmath>
19 #include <cstdint>
20 #include <limits>
21 #include <string>
22 #include <vector>
23 
24 #include "absl/strings/str_format.h"
25 #include "absl/strings/str_join.h"
27 #include "ortools/base/logging.h"
28 #include "ortools/base/mathutil.h"
33 
34 namespace operations_research {
35 namespace {
36 // ----- Tree Array Constraint -----
37 
38 class TreeArrayConstraint : public CastConstraint {
39  public:
40  TreeArrayConstraint(Solver* const solver, const std::vector<IntVar*>& vars,
41  IntVar* const sum_var)
42  : CastConstraint(solver, sum_var),
43  vars_(vars),
44  block_size_(solver->parameters().array_split_size()) {
45  std::vector<int> lengths;
46  lengths.push_back(vars_.size());
47  while (lengths.back() > 1) {
48  const int current = lengths.back();
49  lengths.push_back((current + block_size_ - 1) / block_size_);
50  }
51  tree_.resize(lengths.size());
52  for (int i = 0; i < lengths.size(); ++i) {
53  tree_[i].resize(lengths[lengths.size() - i - 1]);
54  }
55  DCHECK_GE(tree_.size(), 1);
56  DCHECK_EQ(1, tree_[0].size());
57  root_node_ = &tree_[0][0];
58  }
59 
60  std::string DebugStringInternal(const std::string& name) const {
61  return absl::StrFormat("%s(%s) == %s", name,
63  target_var_->DebugString());
64  }
65 
66  void AcceptInternal(const std::string& name,
67  ModelVisitor* const visitor) const {
68  visitor->BeginVisitConstraint(name, this);
69  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
70  vars_);
71  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
72  target_var_);
73  visitor->EndVisitConstraint(name, this);
74  }
75 
76  // Increases min by delta_min, reduces max by delta_max.
77  void ReduceRange(int depth, int position, int64_t delta_min,
78  int64_t delta_max) {
79  NodeInfo* const info = &tree_[depth][position];
80  if (delta_min > 0) {
81  info->node_min.SetValue(solver(),
82  CapAdd(info->node_min.Value(), delta_min));
83  }
84  if (delta_max > 0) {
85  info->node_max.SetValue(solver(),
86  CapSub(info->node_max.Value(), delta_max));
87  }
88  }
89 
90  // Sets the range on the given node.
91  void SetRange(int depth, int position, int64_t new_min, int64_t new_max) {
92  NodeInfo* const info = &tree_[depth][position];
93  if (new_min > info->node_min.Value()) {
94  info->node_min.SetValue(solver(), new_min);
95  }
96  if (new_max < info->node_max.Value()) {
97  info->node_max.SetValue(solver(), new_max);
98  }
99  }
100 
101  void InitLeaf(int position, int64_t var_min, int64_t var_max) {
102  InitNode(MaxDepth(), position, var_min, var_max);
103  }
104 
105  void InitNode(int depth, int position, int64_t node_min, int64_t node_max) {
106  tree_[depth][position].node_min.SetValue(solver(), node_min);
107  tree_[depth][position].node_max.SetValue(solver(), node_max);
108  }
109 
110  int64_t Min(int depth, int position) const {
111  return tree_[depth][position].node_min.Value();
112  }
113 
114  int64_t Max(int depth, int position) const {
115  return tree_[depth][position].node_max.Value();
116  }
117 
118  int64_t RootMin() const { return root_node_->node_min.Value(); }
119 
120  int64_t RootMax() const { return root_node_->node_max.Value(); }
121 
122  int Parent(int position) const { return position / block_size_; }
123 
124  int ChildStart(int position) const { return position * block_size_; }
125 
126  int ChildEnd(int depth, int position) const {
127  DCHECK_LT(depth + 1, tree_.size());
128  return std::min((position + 1) * block_size_ - 1, Width(depth + 1) - 1);
129  }
130 
131  bool IsLeaf(int depth) const { return depth == MaxDepth(); }
132 
133  int MaxDepth() const { return tree_.size() - 1; }
134 
135  int Width(int depth) const { return tree_[depth].size(); }
136 
137  protected:
138  const std::vector<IntVar*> vars_;
139 
140  private:
141  struct NodeInfo {
142  NodeInfo() : node_min(0), node_max(0) {}
143  Rev<int64_t> node_min;
144  Rev<int64_t> node_max;
145  };
146 
147  std::vector<std::vector<NodeInfo> > tree_;
148  const int block_size_;
149  NodeInfo* root_node_;
150 };
151 
152 // ---------- Sum Array ----------
153 
154 // Some of these optimizations here are described in:
155 // "Bounds consistency techniques for long linear constraints". In
156 // Workshop on Techniques for Implementing Constraint Programming
157 // Systems (TRICS), a workshop of CP 2002, N. Beldiceanu, W. Harvey,
158 // Martin Henz, Francois Laburthe, Eric Monfroy, Tobias Müller,
159 // Laurent Perron and Christian Schulte editors, pages 39-46, 2002.
160 
161 // ----- SumConstraint -----
162 
163 // This constraint implements sum(vars) == sum_var.
164 class SumConstraint : public TreeArrayConstraint {
165  public:
166  SumConstraint(Solver* const solver, const std::vector<IntVar*>& vars,
167  IntVar* const sum_var)
168  : TreeArrayConstraint(solver, vars, sum_var), sum_demon_(nullptr) {}
169 
170  ~SumConstraint() override {}
171 
172  void Post() override {
173  for (int i = 0; i < vars_.size(); ++i) {
174  Demon* const demon = MakeConstraintDemon1(
175  solver(), this, &SumConstraint::LeafChanged, "LeafChanged", i);
176  vars_[i]->WhenRange(demon);
177  }
178  sum_demon_ = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
179  solver(), this, &SumConstraint::SumChanged, "SumChanged"));
180  target_var_->WhenRange(sum_demon_);
181  }
182 
183  void InitialPropagate() override {
184  // Copy vars to leaf nodes.
185  for (int i = 0; i < vars_.size(); ++i) {
186  InitLeaf(i, vars_[i]->Min(), vars_[i]->Max());
187  }
188  // Compute up.
189  for (int i = MaxDepth() - 1; i >= 0; --i) {
190  for (int j = 0; j < Width(i); ++j) {
191  int64_t sum_min = 0;
192  int64_t sum_max = 0;
193  const int block_start = ChildStart(j);
194  const int block_end = ChildEnd(i, j);
195  for (int k = block_start; k <= block_end; ++k) {
196  sum_min = CapAdd(sum_min, Min(i + 1, k));
197  sum_max = CapAdd(sum_max, Max(i + 1, k));
198  }
199  InitNode(i, j, sum_min, sum_max);
200  }
201  }
202  // Propagate to sum_var.
203  target_var_->SetRange(RootMin(), RootMax());
204 
205  // Push down.
206  SumChanged();
207  }
208 
209  void SumChanged() {
210  if (target_var_->Max() == RootMin() &&
212  // We can fix all terms to min.
213  for (int i = 0; i < vars_.size(); ++i) {
214  vars_[i]->SetValue(vars_[i]->Min());
215  }
216  } else if (target_var_->Min() == RootMax() &&
218  // We can fix all terms to max.
219  for (int i = 0; i < vars_.size(); ++i) {
220  vars_[i]->SetValue(vars_[i]->Max());
221  }
222  } else {
223  PushDown(0, 0, target_var_->Min(), target_var_->Max());
224  }
225  }
226 
227  void PushDown(int depth, int position, int64_t new_min, int64_t new_max) {
228  // Nothing to do?
229  if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
230  return;
231  }
232 
233  // Leaf node -> push to leaf var.
234  if (IsLeaf(depth)) {
235  vars_[position]->SetRange(new_min, new_max);
236  return;
237  }
238 
239  // Standard propagation from the bounds of the sum to the
240  // individuals terms.
241 
242  // These are maintained automatically in the tree structure.
243  const int64_t sum_min = Min(depth, position);
244  const int64_t sum_max = Max(depth, position);
245 
246  // Intersect the new bounds with the computed bounds.
247  new_max = std::min(sum_max, new_max);
248  new_min = std::max(sum_min, new_min);
249 
250  // Detect failure early.
251  if (new_max < sum_min || new_min > sum_max) {
252  solver()->Fail();
253  }
254 
255  // Push to children nodes.
256  const int block_start = ChildStart(position);
257  const int block_end = ChildEnd(depth, position);
258  for (int i = block_start; i <= block_end; ++i) {
259  const int64_t target_var_min = Min(depth + 1, i);
260  const int64_t target_var_max = Max(depth + 1, i);
261  const int64_t residual_min = CapSub(sum_min, target_var_min);
262  const int64_t residual_max = CapSub(sum_max, target_var_max);
263  PushDown(depth + 1, i, CapSub(new_min, residual_max),
264  CapSub(new_max, residual_min));
265  }
266  // TODO(user) : Is the diameter optimization (see reference
267  // above, rule 5) useful?
268  }
269 
270  void LeafChanged(int term_index) {
271  IntVar* const var = vars_[term_index];
272  PushUp(term_index, CapSub(var->Min(), var->OldMin()),
273  CapSub(var->OldMax(), var->Max()));
274  EnqueueDelayedDemon(sum_demon_); // TODO(user): Is this needed?
275  }
276 
277  void PushUp(int position, int64_t delta_min, int64_t delta_max) {
278  DCHECK_GE(delta_max, 0);
279  DCHECK_GE(delta_min, 0);
280  DCHECK_GT(CapAdd(delta_min, delta_max), 0);
281  for (int depth = MaxDepth(); depth >= 0; --depth) {
282  ReduceRange(depth, position, delta_min, delta_max);
283  position = Parent(position);
284  }
285  DCHECK_EQ(0, position);
286  target_var_->SetRange(RootMin(), RootMax());
287  }
288 
289  std::string DebugString() const override {
290  return DebugStringInternal("Sum");
291  }
292 
293  void Accept(ModelVisitor* const visitor) const override {
294  AcceptInternal(ModelVisitor::kSumEqual, visitor);
295  }
296 
297  private:
298  Demon* sum_demon_;
299 };
300 
301 // This constraint implements sum(vars) == target_var.
302 class SmallSumConstraint : public Constraint {
303  public:
304  SmallSumConstraint(Solver* const solver, const std::vector<IntVar*>& vars,
305  IntVar* const target_var)
306  : Constraint(solver),
307  vars_(vars),
308  target_var_(target_var),
309  computed_min_(0),
310  computed_max_(0),
311  sum_demon_(nullptr) {}
312 
313  ~SmallSumConstraint() override {}
314 
315  void Post() override {
316  for (int i = 0; i < vars_.size(); ++i) {
317  if (!vars_[i]->Bound()) {
318  Demon* const demon = MakeConstraintDemon1(
319  solver(), this, &SmallSumConstraint::VarChanged, "VarChanged",
320  vars_[i]);
321  vars_[i]->WhenRange(demon);
322  }
323  }
324  sum_demon_ = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
325  solver(), this, &SmallSumConstraint::SumChanged, "SumChanged"));
326  target_var_->WhenRange(sum_demon_);
327  }
328 
329  void InitialPropagate() override {
330  // Compute up.
331  int64_t sum_min = 0;
332  int64_t sum_max = 0;
333  for (IntVar* const var : vars_) {
334  sum_min = CapAdd(sum_min, var->Min());
335  sum_max = CapAdd(sum_max, var->Max());
336  }
337 
338  // Propagate to sum_var.
339  computed_min_.SetValue(solver(), sum_min);
340  computed_max_.SetValue(solver(), sum_max);
341  target_var_->SetRange(sum_min, sum_max);
342 
343  // Push down.
344  SumChanged();
345  }
346 
347  void SumChanged() {
348  int64_t new_min = target_var_->Min();
349  int64_t new_max = target_var_->Max();
350  const int64_t sum_min = computed_min_.Value();
351  const int64_t sum_max = computed_max_.Value();
352  if (new_max == sum_min && new_max != std::numeric_limits<int64_t>::max()) {
353  // We can fix all terms to min.
354  for (int i = 0; i < vars_.size(); ++i) {
355  vars_[i]->SetValue(vars_[i]->Min());
356  }
357  } else if (new_min == sum_max &&
358  new_min != std::numeric_limits<int64_t>::min()) {
359  // We can fix all terms to max.
360  for (int i = 0; i < vars_.size(); ++i) {
361  vars_[i]->SetValue(vars_[i]->Max());
362  }
363  } else {
364  if (new_min > sum_min || new_max < sum_max) { // something to do.
365  // Intersect the new bounds with the computed bounds.
366  new_max = std::min(sum_max, new_max);
367  new_min = std::max(sum_min, new_min);
368 
369  // Detect failure early.
370  if (new_max < sum_min || new_min > sum_max) {
371  solver()->Fail();
372  }
373 
374  // Push to variables.
375  for (IntVar* const var : vars_) {
376  const int64_t var_min = var->Min();
377  const int64_t var_max = var->Max();
378  const int64_t residual_min = CapSub(sum_min, var_min);
379  const int64_t residual_max = CapSub(sum_max, var_max);
380  var->SetRange(CapSub(new_min, residual_max),
381  CapSub(new_max, residual_min));
382  }
383  }
384  }
385  }
386 
387  void VarChanged(IntVar* var) {
388  const int64_t delta_min = CapSub(var->Min(), var->OldMin());
389  const int64_t delta_max = CapSub(var->OldMax(), var->Max());
390  computed_min_.Add(solver(), delta_min);
391  computed_max_.Add(solver(), -delta_max);
392  if (computed_max_.Value() < target_var_->Max() ||
393  computed_min_.Value() > target_var_->Min()) {
394  target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
395  } else {
396  EnqueueDelayedDemon(sum_demon_);
397  }
398  }
399 
400  std::string DebugString() const override {
401  return absl::StrFormat("SmallSum(%s) == %s",
402  JoinDebugStringPtr(vars_, ", "),
403  target_var_->DebugString());
404  }
405 
406  void Accept(ModelVisitor* const visitor) const override {
407  visitor->BeginVisitConstraint(ModelVisitor::kSumEqual, this);
408  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
409  vars_);
410  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
411  target_var_);
412  visitor->EndVisitConstraint(ModelVisitor::kSumEqual, this);
413  }
414 
415  private:
416  const std::vector<IntVar*> vars_;
417  IntVar* target_var_;
418  NumericalRev<int64_t> computed_min_;
419  NumericalRev<int64_t> computed_max_;
420  Demon* sum_demon_;
421 };
422 // ----- SafeSumConstraint -----
423 
424 bool DetectSumOverflow(const std::vector<IntVar*>& vars) {
425  int64_t sum_min = 0;
426  int64_t sum_max = 0;
427  for (int i = 0; i < vars.size(); ++i) {
428  sum_min = CapAdd(sum_min, vars[i]->Min());
429  sum_max = CapAdd(sum_max, vars[i]->Max());
430  if (sum_min == std::numeric_limits<int64_t>::min() ||
431  sum_max == std::numeric_limits<int64_t>::max()) {
432  return true;
433  }
434  }
435  return false;
436 }
437 
438 // This constraint implements sum(vars) == sum_var.
439 class SafeSumConstraint : public TreeArrayConstraint {
440  public:
441  SafeSumConstraint(Solver* const solver, const std::vector<IntVar*>& vars,
442  IntVar* const sum_var)
443  : TreeArrayConstraint(solver, vars, sum_var), sum_demon_(nullptr) {}
444 
445  ~SafeSumConstraint() override {}
446 
447  void Post() override {
448  for (int i = 0; i < vars_.size(); ++i) {
449  Demon* const demon = MakeConstraintDemon1(
450  solver(), this, &SafeSumConstraint::LeafChanged, "LeafChanged", i);
451  vars_[i]->WhenRange(demon);
452  }
453  sum_demon_ = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
454  solver(), this, &SafeSumConstraint::SumChanged, "SumChanged"));
455  target_var_->WhenRange(sum_demon_);
456  }
457 
458  void SafeComputeNode(int depth, int position, int64_t* const sum_min,
459  int64_t* const sum_max) {
460  DCHECK_LT(depth, MaxDepth());
461  const int block_start = ChildStart(position);
462  const int block_end = ChildEnd(depth, position);
463  for (int k = block_start; k <= block_end; ++k) {
464  if (*sum_min != std::numeric_limits<int64_t>::min()) {
465  *sum_min = CapAdd(*sum_min, Min(depth + 1, k));
466  }
467  if (*sum_max != std::numeric_limits<int64_t>::max()) {
468  *sum_max = CapAdd(*sum_max, Max(depth + 1, k));
469  }
470  if (*sum_min == std::numeric_limits<int64_t>::min() &&
471  *sum_max == std::numeric_limits<int64_t>::max()) {
472  break;
473  }
474  }
475  }
476 
477  void InitialPropagate() override {
478  // Copy vars to leaf nodes.
479  for (int i = 0; i < vars_.size(); ++i) {
480  InitLeaf(i, vars_[i]->Min(), vars_[i]->Max());
481  }
482  // Compute up.
483  for (int i = MaxDepth() - 1; i >= 0; --i) {
484  for (int j = 0; j < Width(i); ++j) {
485  int64_t sum_min = 0;
486  int64_t sum_max = 0;
487  SafeComputeNode(i, j, &sum_min, &sum_max);
488  InitNode(i, j, sum_min, sum_max);
489  }
490  }
491  // Propagate to sum_var.
492  target_var_->SetRange(RootMin(), RootMax());
493 
494  // Push down.
495  SumChanged();
496  }
497 
498  void SumChanged() {
499  DCHECK(CheckInternalState());
500  if (target_var_->Max() == RootMin()) {
501  // We can fix all terms to min.
502  for (int i = 0; i < vars_.size(); ++i) {
503  vars_[i]->SetValue(vars_[i]->Min());
504  }
505  } else if (target_var_->Min() == RootMax()) {
506  // We can fix all terms to max.
507  for (int i = 0; i < vars_.size(); ++i) {
508  vars_[i]->SetValue(vars_[i]->Max());
509  }
510  } else {
511  PushDown(0, 0, target_var_->Min(), target_var_->Max());
512  }
513  }
514 
515  void PushDown(int depth, int position, int64_t new_min, int64_t new_max) {
516  // Nothing to do?
517  if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
518  return;
519  }
520 
521  // Leaf node -> push to leaf var.
522  if (IsLeaf(depth)) {
523  vars_[position]->SetRange(new_min, new_max);
524  return;
525  }
526 
527  // Standard propagation from the bounds of the sum to the
528  // individuals terms.
529 
530  // These are maintained automatically in the tree structure.
531  const int64_t sum_min = Min(depth, position);
532  const int64_t sum_max = Max(depth, position);
533 
534  // Intersect the new bounds with the computed bounds.
535  new_max = std::min(sum_max, new_max);
536  new_min = std::max(sum_min, new_min);
537 
538  // Detect failure early.
539  if (new_max < sum_min || new_min > sum_max) {
540  solver()->Fail();
541  }
542 
543  // Push to children nodes.
544  const int block_start = ChildStart(position);
545  const int block_end = ChildEnd(depth, position);
546  for (int pos = block_start; pos <= block_end; ++pos) {
547  const int64_t target_var_min = Min(depth + 1, pos);
548  const int64_t residual_min =
550  ? CapSub(sum_min, target_var_min)
551  : std::numeric_limits<int64_t>::min();
552  const int64_t target_var_max = Max(depth + 1, pos);
553  const int64_t residual_max =
555  ? CapSub(sum_max, target_var_max)
556  : std::numeric_limits<int64_t>::max();
557  PushDown(depth + 1, pos,
558  (residual_max == std::numeric_limits<int64_t>::min()
560  : CapSub(new_min, residual_max)),
561  (residual_min == std::numeric_limits<int64_t>::max()
563  : CapSub(new_max, residual_min)));
564  }
565  // TODO(user) : Is the diameter optimization (see reference
566  // above, rule 5) useful?
567  }
568 
569  void LeafChanged(int term_index) {
570  IntVar* const var = vars_[term_index];
571  PushUp(term_index, CapSub(var->Min(), var->OldMin()),
572  CapSub(var->OldMax(), var->Max()));
573  EnqueueDelayedDemon(sum_demon_); // TODO(user): Is this needed?
574  }
575 
576  void PushUp(int position, int64_t delta_min, int64_t delta_max) {
577  DCHECK_GE(delta_max, 0);
578  DCHECK_GE(delta_min, 0);
579  if (CapAdd(delta_min, delta_max) == 0) {
580  // This may happen if the computation of old min/max has under/overflowed
581  // resulting in no actual change in min and max.
582  return;
583  }
584  bool delta_corrupted = false;
585  for (int depth = MaxDepth(); depth >= 0; --depth) {
586  if (Min(depth, position) != std::numeric_limits<int64_t>::min() &&
587  Max(depth, position) != std::numeric_limits<int64_t>::max() &&
588  delta_min != std::numeric_limits<int64_t>::max() &&
589  delta_max != std::numeric_limits<int64_t>::max() &&
590  !delta_corrupted) { // No overflow.
591  ReduceRange(depth, position, delta_min, delta_max);
592  } else if (depth == MaxDepth()) { // Leaf.
593  SetRange(depth, position, vars_[position]->Min(),
594  vars_[position]->Max());
595  delta_corrupted = true;
596  } else { // Recompute.
597  int64_t sum_min = 0;
598  int64_t sum_max = 0;
599  SafeComputeNode(depth, position, &sum_min, &sum_max);
600  if (sum_min == std::numeric_limits<int64_t>::min() &&
601  sum_max == std::numeric_limits<int64_t>::max()) {
602  return; // Nothing to do upward.
603  }
604  SetRange(depth, position, sum_min, sum_max);
605  delta_corrupted = true;
606  }
607  position = Parent(position);
608  }
609  DCHECK_EQ(0, position);
610  target_var_->SetRange(RootMin(), RootMax());
611  }
612 
613  std::string DebugString() const override {
614  return DebugStringInternal("Sum");
615  }
616 
617  void Accept(ModelVisitor* const visitor) const override {
618  AcceptInternal(ModelVisitor::kSumEqual, visitor);
619  }
620 
621  private:
622  bool CheckInternalState() {
623  for (int i = 0; i < vars_.size(); ++i) {
624  CheckLeaf(i, vars_[i]->Min(), vars_[i]->Max());
625  }
626  // Check up.
627  for (int i = MaxDepth() - 1; i >= 0; --i) {
628  for (int j = 0; j < Width(i); ++j) {
629  int64_t sum_min = 0;
630  int64_t sum_max = 0;
631  SafeComputeNode(i, j, &sum_min, &sum_max);
632  CheckNode(i, j, sum_min, sum_max);
633  }
634  }
635  return true;
636  }
637 
638  void CheckLeaf(int position, int64_t var_min, int64_t var_max) {
639  CheckNode(MaxDepth(), position, var_min, var_max);
640  }
641 
642  void CheckNode(int depth, int position, int64_t node_min, int64_t node_max) {
643  DCHECK_EQ(Min(depth, position), node_min);
644  DCHECK_EQ(Max(depth, position), node_max);
645  }
646 
647  Demon* sum_demon_;
648 };
649 
650 // ---------- Min Array ----------
651 
652 // This constraint implements min(vars) == min_var.
653 class MinConstraint : public TreeArrayConstraint {
654  public:
655  MinConstraint(Solver* const solver, const std::vector<IntVar*>& vars,
656  IntVar* const min_var)
657  : TreeArrayConstraint(solver, vars, min_var), min_demon_(nullptr) {}
658 
659  ~MinConstraint() override {}
660 
661  void Post() override {
662  for (int i = 0; i < vars_.size(); ++i) {
663  Demon* const demon = MakeConstraintDemon1(
664  solver(), this, &MinConstraint::LeafChanged, "LeafChanged", i);
665  vars_[i]->WhenRange(demon);
666  }
667  min_demon_ = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
668  solver(), this, &MinConstraint::MinVarChanged, "MinVarChanged"));
669  target_var_->WhenRange(min_demon_);
670  }
671 
672  void InitialPropagate() override {
673  // Copy vars to leaf nodes.
674  for (int i = 0; i < vars_.size(); ++i) {
675  InitLeaf(i, vars_[i]->Min(), vars_[i]->Max());
676  }
677 
678  // Compute up.
679  for (int i = MaxDepth() - 1; i >= 0; --i) {
680  for (int j = 0; j < Width(i); ++j) {
681  int64_t min_min = std::numeric_limits<int64_t>::max();
682  int64_t min_max = std::numeric_limits<int64_t>::max();
683  const int block_start = ChildStart(j);
684  const int block_end = ChildEnd(i, j);
685  for (int k = block_start; k <= block_end; ++k) {
686  min_min = std::min(min_min, Min(i + 1, k));
687  min_max = std::min(min_max, Max(i + 1, k));
688  }
689  InitNode(i, j, min_min, min_max);
690  }
691  }
692  // Propagate to min_var.
693  target_var_->SetRange(RootMin(), RootMax());
694 
695  // Push down.
696  MinVarChanged();
697  }
698 
699  void MinVarChanged() {
700  PushDown(0, 0, target_var_->Min(), target_var_->Max());
701  }
702 
703  void PushDown(int depth, int position, int64_t new_min, int64_t new_max) {
704  // Nothing to do?
705  if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
706  return;
707  }
708 
709  // Leaf node -> push to leaf var.
710  if (IsLeaf(depth)) {
711  vars_[position]->SetRange(new_min, new_max);
712  return;
713  }
714 
715  const int64_t node_min = Min(depth, position);
716  const int64_t node_max = Max(depth, position);
717 
718  int candidate = -1;
719  int active = 0;
720  const int block_start = ChildStart(position);
721  const int block_end = ChildEnd(depth, position);
722 
723  if (new_max < node_max) {
724  // Look if only one candidat to push the max down.
725  for (int i = block_start; i <= block_end; ++i) {
726  if (Min(depth + 1, i) <= new_max) {
727  if (active++ >= 1) {
728  break;
729  }
730  candidate = i;
731  }
732  }
733  if (active == 0) {
734  solver()->Fail();
735  }
736  }
737 
738  if (node_min < new_min) {
739  for (int i = block_start; i <= block_end; ++i) {
740  if (i == candidate && active == 1) {
741  PushDown(depth + 1, i, new_min, new_max);
742  } else {
743  PushDown(depth + 1, i, new_min, Max(depth + 1, i));
744  }
745  }
746  } else if (active == 1) {
747  PushDown(depth + 1, candidate, Min(depth + 1, candidate), new_max);
748  }
749  }
750 
751  // TODO(user): Regroup code between Min and Max constraints.
752  void LeafChanged(int term_index) {
753  IntVar* const var = vars_[term_index];
754  SetRange(MaxDepth(), term_index, var->Min(), var->Max());
755  const int parent_depth = MaxDepth() - 1;
756  const int parent = Parent(term_index);
757  const int64_t old_min = var->OldMin();
758  const int64_t var_min = var->Min();
759  const int64_t var_max = var->Max();
760  if ((old_min == Min(parent_depth, parent) && old_min != var_min) ||
761  var_max < Max(parent_depth, parent)) {
762  // Can influence the parent bounds.
763  PushUp(term_index);
764  }
765  }
766 
767  void PushUp(int position) {
768  int depth = MaxDepth();
769  while (depth > 0) {
770  const int parent = Parent(position);
771  const int parent_depth = depth - 1;
772  int64_t min_min = std::numeric_limits<int64_t>::max();
773  int64_t min_max = std::numeric_limits<int64_t>::max();
774  const int block_start = ChildStart(parent);
775  const int block_end = ChildEnd(parent_depth, parent);
776  for (int k = block_start; k <= block_end; ++k) {
777  min_min = std::min(min_min, Min(depth, k));
778  min_max = std::min(min_max, Max(depth, k));
779  }
780  if (min_min > Min(parent_depth, parent) ||
781  min_max < Max(parent_depth, parent)) {
782  SetRange(parent_depth, parent, min_min, min_max);
783  } else {
784  break;
785  }
786  depth = parent_depth;
787  position = parent;
788  }
789  if (depth == 0) { // We have pushed all the way up.
790  target_var_->SetRange(RootMin(), RootMax());
791  }
792  MinVarChanged();
793  }
794 
795  std::string DebugString() const override {
796  return DebugStringInternal("Min");
797  }
798 
799  void Accept(ModelVisitor* const visitor) const override {
800  AcceptInternal(ModelVisitor::kMinEqual, visitor);
801  }
802 
803  private:
804  Demon* min_demon_;
805 };
806 
807 class SmallMinConstraint : public Constraint {
808  public:
809  SmallMinConstraint(Solver* const solver, const std::vector<IntVar*>& vars,
810  IntVar* const target_var)
811  : Constraint(solver),
812  vars_(vars),
813  target_var_(target_var),
814  computed_min_(0),
815  computed_max_(0) {}
816 
817  ~SmallMinConstraint() override {}
818 
819  void Post() override {
820  for (int i = 0; i < vars_.size(); ++i) {
821  if (!vars_[i]->Bound()) {
822  Demon* const demon = MakeConstraintDemon1(
823  solver(), this, &SmallMinConstraint::VarChanged, "VarChanged",
824  vars_[i]);
825  vars_[i]->WhenRange(demon);
826  }
827  }
828  Demon* const mdemon = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
829  solver(), this, &SmallMinConstraint::MinVarChanged, "MinVarChanged"));
830  target_var_->WhenRange(mdemon);
831  }
832 
833  void InitialPropagate() override {
834  int64_t min_min = std::numeric_limits<int64_t>::max();
835  int64_t min_max = std::numeric_limits<int64_t>::max();
836  for (IntVar* const var : vars_) {
837  min_min = std::min(min_min, var->Min());
838  min_max = std::min(min_max, var->Max());
839  }
840  computed_min_.SetValue(solver(), min_min);
841  computed_max_.SetValue(solver(), min_max);
842  // Propagate to min_var.
843  target_var_->SetRange(min_min, min_max);
844 
845  // Push down.
846  MinVarChanged();
847  }
848 
849  std::string DebugString() const override {
850  return absl::StrFormat("SmallMin(%s) == %s",
851  JoinDebugStringPtr(vars_, ", "),
852  target_var_->DebugString());
853  }
854 
855  void Accept(ModelVisitor* const visitor) const override {
856  visitor->BeginVisitConstraint(ModelVisitor::kMinEqual, this);
857  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
858  vars_);
859  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
860  target_var_);
861  visitor->EndVisitConstraint(ModelVisitor::kMinEqual, this);
862  }
863 
864  private:
865  void VarChanged(IntVar* var) {
866  const int64_t old_min = var->OldMin();
867  const int64_t var_min = var->Min();
868  const int64_t var_max = var->Max();
869  if ((old_min == computed_min_.Value() && old_min != var_min) ||
870  var_max < computed_max_.Value()) {
871  // Can influence the min var bounds.
872  int64_t min_min = std::numeric_limits<int64_t>::max();
873  int64_t min_max = std::numeric_limits<int64_t>::max();
874  for (IntVar* const var : vars_) {
875  min_min = std::min(min_min, var->Min());
876  min_max = std::min(min_max, var->Max());
877  }
878  if (min_min > computed_min_.Value() || min_max < computed_max_.Value()) {
879  computed_min_.SetValue(solver(), min_min);
880  computed_max_.SetValue(solver(), min_max);
881  target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
882  }
883  }
884  MinVarChanged();
885  }
886 
887  void MinVarChanged() {
888  const int64_t new_min = target_var_->Min();
889  const int64_t new_max = target_var_->Max();
890  // Nothing to do?
891  if (new_min <= computed_min_.Value() && new_max >= computed_max_.Value()) {
892  return;
893  }
894 
895  IntVar* candidate = nullptr;
896  int active = 0;
897 
898  if (new_max < computed_max_.Value()) {
899  // Look if only one candidate to push the max down.
900  for (IntVar* const var : vars_) {
901  if (var->Min() <= new_max) {
902  if (active++ >= 1) {
903  break;
904  }
905  candidate = var;
906  }
907  }
908  if (active == 0) {
909  solver()->Fail();
910  }
911  }
912  if (computed_min_.Value() < new_min) {
913  if (active == 1) {
914  candidate->SetRange(new_min, new_max);
915  } else {
916  for (IntVar* const var : vars_) {
917  var->SetMin(new_min);
918  }
919  }
920  } else if (active == 1) {
921  candidate->SetMax(new_max);
922  }
923  }
924 
925  std::vector<IntVar*> vars_;
926  IntVar* const target_var_;
927  Rev<int64_t> computed_min_;
928  Rev<int64_t> computed_max_;
929 };
930 
931 // ---------- Max Array ----------
932 
933 // This constraint implements max(vars) == max_var.
934 class MaxConstraint : public TreeArrayConstraint {
935  public:
936  MaxConstraint(Solver* const solver, const std::vector<IntVar*>& vars,
937  IntVar* const max_var)
938  : TreeArrayConstraint(solver, vars, max_var), max_demon_(nullptr) {}
939 
940  ~MaxConstraint() override {}
941 
942  void Post() override {
943  for (int i = 0; i < vars_.size(); ++i) {
944  Demon* const demon = MakeConstraintDemon1(
945  solver(), this, &MaxConstraint::LeafChanged, "LeafChanged", i);
946  vars_[i]->WhenRange(demon);
947  }
948  max_demon_ = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
949  solver(), this, &MaxConstraint::MaxVarChanged, "MaxVarChanged"));
950  target_var_->WhenRange(max_demon_);
951  }
952 
953  void InitialPropagate() override {
954  // Copy vars to leaf nodes.
955  for (int i = 0; i < vars_.size(); ++i) {
956  InitLeaf(i, vars_[i]->Min(), vars_[i]->Max());
957  }
958 
959  // Compute up.
960  for (int i = MaxDepth() - 1; i >= 0; --i) {
961  for (int j = 0; j < Width(i); ++j) {
962  int64_t max_min = std::numeric_limits<int64_t>::min();
963  int64_t max_max = std::numeric_limits<int64_t>::min();
964  const int block_start = ChildStart(j);
965  const int block_end = ChildEnd(i, j);
966  for (int k = block_start; k <= block_end; ++k) {
967  max_min = std::max(max_min, Min(i + 1, k));
968  max_max = std::max(max_max, Max(i + 1, k));
969  }
970  InitNode(i, j, max_min, max_max);
971  }
972  }
973  // Propagate to min_var.
974  target_var_->SetRange(RootMin(), RootMax());
975 
976  // Push down.
977  MaxVarChanged();
978  }
979 
980  void MaxVarChanged() {
981  PushDown(0, 0, target_var_->Min(), target_var_->Max());
982  }
983 
984  void PushDown(int depth, int position, int64_t new_min, int64_t new_max) {
985  // Nothing to do?
986  if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
987  return;
988  }
989 
990  // Leaf node -> push to leaf var.
991  if (IsLeaf(depth)) {
992  vars_[position]->SetRange(new_min, new_max);
993  return;
994  }
995 
996  const int64_t node_min = Min(depth, position);
997  const int64_t node_max = Max(depth, position);
998 
999  int candidate = -1;
1000  int active = 0;
1001  const int block_start = ChildStart(position);
1002  const int block_end = ChildEnd(depth, position);
1003 
1004  if (node_min < new_min) {
1005  // Look if only one candidat to push the max down.
1006  for (int i = block_start; i <= block_end; ++i) {
1007  if (Max(depth + 1, i) >= new_min) {
1008  if (active++ >= 1) {
1009  break;
1010  }
1011  candidate = i;
1012  }
1013  }
1014  if (active == 0) {
1015  solver()->Fail();
1016  }
1017  }
1018 
1019  if (node_max > new_max) {
1020  for (int i = block_start; i <= block_end; ++i) {
1021  if (i == candidate && active == 1) {
1022  PushDown(depth + 1, i, new_min, new_max);
1023  } else {
1024  PushDown(depth + 1, i, Min(depth + 1, i), new_max);
1025  }
1026  }
1027  } else if (active == 1) {
1028  PushDown(depth + 1, candidate, new_min, Max(depth + 1, candidate));
1029  }
1030  }
1031 
1032  void LeafChanged(int term_index) {
1033  IntVar* const var = vars_[term_index];
1034  SetRange(MaxDepth(), term_index, var->Min(), var->Max());
1035  const int parent_depth = MaxDepth() - 1;
1036  const int parent = Parent(term_index);
1037  const int64_t old_max = var->OldMax();
1038  const int64_t var_min = var->Min();
1039  const int64_t var_max = var->Max();
1040  if ((old_max == Max(parent_depth, parent) && old_max != var_max) ||
1041  var_min > Min(parent_depth, parent)) {
1042  // Can influence the parent bounds.
1043  PushUp(term_index);
1044  }
1045  }
1046 
1047  void PushUp(int position) {
1048  int depth = MaxDepth();
1049  while (depth > 0) {
1050  const int parent = Parent(position);
1051  const int parent_depth = depth - 1;
1052  int64_t max_min = std::numeric_limits<int64_t>::min();
1053  int64_t max_max = std::numeric_limits<int64_t>::min();
1054  const int block_start = ChildStart(parent);
1055  const int block_end = ChildEnd(parent_depth, parent);
1056  for (int k = block_start; k <= block_end; ++k) {
1057  max_min = std::max(max_min, Min(depth, k));
1058  max_max = std::max(max_max, Max(depth, k));
1059  }
1060  if (max_min > Min(parent_depth, parent) ||
1061  max_max < Max(parent_depth, parent)) {
1062  SetRange(parent_depth, parent, max_min, max_max);
1063  } else {
1064  break;
1065  }
1066  depth = parent_depth;
1067  position = parent;
1068  }
1069  if (depth == 0) { // We have pushed all the way up.
1070  target_var_->SetRange(RootMin(), RootMax());
1071  }
1072  MaxVarChanged();
1073  }
1074 
1075  std::string DebugString() const override {
1076  return DebugStringInternal("Max");
1077  }
1078 
1079  void Accept(ModelVisitor* const visitor) const override {
1080  AcceptInternal(ModelVisitor::kMaxEqual, visitor);
1081  }
1082 
1083  private:
1084  Demon* max_demon_;
1085 };
1086 
1087 class SmallMaxConstraint : public Constraint {
1088  public:
1089  SmallMaxConstraint(Solver* const solver, const std::vector<IntVar*>& vars,
1090  IntVar* const target_var)
1091  : Constraint(solver),
1092  vars_(vars),
1093  target_var_(target_var),
1094  computed_min_(0),
1095  computed_max_(0) {}
1096 
1097  ~SmallMaxConstraint() override {}
1098 
1099  void Post() override {
1100  for (int i = 0; i < vars_.size(); ++i) {
1101  if (!vars_[i]->Bound()) {
1102  Demon* const demon = MakeConstraintDemon1(
1103  solver(), this, &SmallMaxConstraint::VarChanged, "VarChanged",
1104  vars_[i]);
1105  vars_[i]->WhenRange(demon);
1106  }
1107  }
1108  Demon* const mdemon = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
1109  solver(), this, &SmallMaxConstraint::MaxVarChanged, "MinVarChanged"));
1110  target_var_->WhenRange(mdemon);
1111  }
1112 
1113  void InitialPropagate() override {
1114  int64_t max_min = std::numeric_limits<int64_t>::min();
1115  int64_t max_max = std::numeric_limits<int64_t>::min();
1116  for (IntVar* const var : vars_) {
1117  max_min = std::max(max_min, var->Min());
1118  max_max = std::max(max_max, var->Max());
1119  }
1120  computed_min_.SetValue(solver(), max_min);
1121  computed_max_.SetValue(solver(), max_max);
1122  // Propagate to min_var.
1123  target_var_->SetRange(max_min, max_max);
1124 
1125  // Push down.
1126  MaxVarChanged();
1127  }
1128 
1129  std::string DebugString() const override {
1130  return absl::StrFormat("SmallMax(%s) == %s",
1131  JoinDebugStringPtr(vars_, ", "),
1132  target_var_->DebugString());
1133  }
1134 
1135  void Accept(ModelVisitor* const visitor) const override {
1136  visitor->BeginVisitConstraint(ModelVisitor::kMaxEqual, this);
1137  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1138  vars_);
1139  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1140  target_var_);
1141  visitor->EndVisitConstraint(ModelVisitor::kMaxEqual, this);
1142  }
1143 
1144  private:
1145  void VarChanged(IntVar* var) {
1146  const int64_t old_max = var->OldMax();
1147  const int64_t var_min = var->Min();
1148  const int64_t var_max = var->Max();
1149  if ((old_max == computed_max_.Value() && old_max != var_max) ||
1150  var_min > computed_min_.Value()) { // REWRITE
1151  // Can influence the min var bounds.
1152  int64_t max_min = std::numeric_limits<int64_t>::min();
1153  int64_t max_max = std::numeric_limits<int64_t>::min();
1154  for (IntVar* const var : vars_) {
1155  max_min = std::max(max_min, var->Min());
1156  max_max = std::max(max_max, var->Max());
1157  }
1158  if (max_min > computed_min_.Value() || max_max < computed_max_.Value()) {
1159  computed_min_.SetValue(solver(), max_min);
1160  computed_max_.SetValue(solver(), max_max);
1161  target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
1162  }
1163  }
1164  MaxVarChanged();
1165  }
1166 
1167  void MaxVarChanged() {
1168  const int64_t new_min = target_var_->Min();
1169  const int64_t new_max = target_var_->Max();
1170  // Nothing to do?
1171  if (new_min <= computed_min_.Value() && new_max >= computed_max_.Value()) {
1172  return;
1173  }
1174 
1175  IntVar* candidate = nullptr;
1176  int active = 0;
1177 
1178  if (new_min > computed_min_.Value()) {
1179  // Look if only one candidate to push the max down.
1180  for (IntVar* const var : vars_) {
1181  if (var->Max() >= new_min) {
1182  if (active++ >= 1) {
1183  break;
1184  }
1185  candidate = var;
1186  }
1187  }
1188  if (active == 0) {
1189  solver()->Fail();
1190  }
1191  }
1192  if (computed_max_.Value() > new_max) {
1193  if (active == 1) {
1194  candidate->SetRange(new_min, new_max);
1195  } else {
1196  for (IntVar* const var : vars_) {
1197  var->SetMax(new_max);
1198  }
1199  }
1200  } else if (active == 1) {
1201  candidate->SetMin(new_min);
1202  }
1203  }
1204 
1205  std::vector<IntVar*> vars_;
1206  IntVar* const target_var_;
1207  Rev<int64_t> computed_min_;
1208  Rev<int64_t> computed_max_;
1209 };
1210 
1211 // Boolean And and Ors
1212 
1213 class ArrayBoolAndEq : public CastConstraint {
1214  public:
1215  ArrayBoolAndEq(Solver* const s, const std::vector<IntVar*>& vars,
1216  IntVar* const target)
1217  : CastConstraint(s, target),
1218  vars_(vars),
1219  demons_(vars.size()),
1220  unbounded_(0) {}
1221 
1222  ~ArrayBoolAndEq() override {}
1223 
1224  void Post() override {
1225  for (int i = 0; i < vars_.size(); ++i) {
1226  if (!vars_[i]->Bound()) {
1227  demons_[i] =
1228  MakeConstraintDemon1(solver(), this, &ArrayBoolAndEq::PropagateVar,
1229  "PropagateVar", vars_[i]);
1230  vars_[i]->WhenBound(demons_[i]);
1231  }
1232  }
1233  if (!target_var_->Bound()) {
1234  Demon* const target_demon = MakeConstraintDemon0(
1235  solver(), this, &ArrayBoolAndEq::PropagateTarget, "PropagateTarget");
1236  target_var_->WhenBound(target_demon);
1237  }
1238  }
1239 
1240  void InitialPropagate() override {
1241  target_var_->SetRange(0, 1);
1242  if (target_var_->Min() == 1) {
1243  for (int i = 0; i < vars_.size(); ++i) {
1244  vars_[i]->SetMin(1);
1245  }
1246  } else {
1247  int possible_zero = -1;
1248  int ones = 0;
1249  int unbounded = 0;
1250  for (int i = 0; i < vars_.size(); ++i) {
1251  if (!vars_[i]->Bound()) {
1252  unbounded++;
1253  possible_zero = i;
1254  } else if (vars_[i]->Max() == 0) {
1255  InhibitAll();
1256  target_var_->SetMax(0);
1257  return;
1258  } else {
1259  DCHECK_EQ(1, vars_[i]->Min());
1260  ones++;
1261  }
1262  }
1263  if (unbounded == 0) {
1264  target_var_->SetMin(1);
1265  } else if (target_var_->Max() == 0 && unbounded == 1) {
1266  CHECK_NE(-1, possible_zero);
1267  vars_[possible_zero]->SetMax(0);
1268  } else {
1269  unbounded_.SetValue(solver(), unbounded);
1270  }
1271  }
1272  }
1273 
1274  void PropagateVar(IntVar* var) {
1275  if (var->Min() == 1) {
1276  unbounded_.Decr(solver());
1277  if (unbounded_.Value() == 0 && !decided_.Switched()) {
1278  target_var_->SetMin(1);
1279  decided_.Switch(solver());
1280  } else if (target_var_->Max() == 0 && unbounded_.Value() == 1 &&
1281  !decided_.Switched()) {
1282  ForceToZero();
1283  }
1284  } else {
1285  InhibitAll();
1286  target_var_->SetMax(0);
1287  }
1288  }
1289 
1290  void PropagateTarget() {
1291  if (target_var_->Min() == 1) {
1292  for (int i = 0; i < vars_.size(); ++i) {
1293  vars_[i]->SetMin(1);
1294  }
1295  } else {
1296  if (unbounded_.Value() == 1 && !decided_.Switched()) {
1297  ForceToZero();
1298  }
1299  }
1300  }
1301 
1302  std::string DebugString() const override {
1303  return absl::StrFormat("And(%s) == %s", JoinDebugStringPtr(vars_, ", "),
1304  target_var_->DebugString());
1305  }
1306 
1307  void Accept(ModelVisitor* const visitor) const override {
1308  visitor->BeginVisitConstraint(ModelVisitor::kMinEqual, this);
1309  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1310  vars_);
1311  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1312  target_var_);
1313  visitor->EndVisitConstraint(ModelVisitor::kMinEqual, this);
1314  }
1315 
1316  private:
1317  void InhibitAll() {
1318  for (int i = 0; i < demons_.size(); ++i) {
1319  if (demons_[i] != nullptr) {
1320  demons_[i]->inhibit(solver());
1321  }
1322  }
1323  }
1324 
1325  void ForceToZero() {
1326  for (int i = 0; i < vars_.size(); ++i) {
1327  if (vars_[i]->Min() == 0) {
1328  vars_[i]->SetValue(0);
1329  decided_.Switch(solver());
1330  return;
1331  }
1332  }
1333  solver()->Fail();
1334  }
1335 
1336  const std::vector<IntVar*> vars_;
1337  std::vector<Demon*> demons_;
1338  NumericalRev<int> unbounded_;
1339  RevSwitch decided_;
1340 };
1341 
1342 class ArrayBoolOrEq : public CastConstraint {
1343  public:
1344  ArrayBoolOrEq(Solver* const s, const std::vector<IntVar*>& vars,
1345  IntVar* const target)
1346  : CastConstraint(s, target),
1347  vars_(vars),
1348  demons_(vars.size()),
1349  unbounded_(0) {}
1350 
1351  ~ArrayBoolOrEq() override {}
1352 
1353  void Post() override {
1354  for (int i = 0; i < vars_.size(); ++i) {
1355  if (!vars_[i]->Bound()) {
1356  demons_[i] =
1357  MakeConstraintDemon1(solver(), this, &ArrayBoolOrEq::PropagateVar,
1358  "PropagateVar", vars_[i]);
1359  vars_[i]->WhenBound(demons_[i]);
1360  }
1361  }
1362  if (!target_var_->Bound()) {
1363  Demon* const target_demon = MakeConstraintDemon0(
1364  solver(), this, &ArrayBoolOrEq::PropagateTarget, "PropagateTarget");
1365  target_var_->WhenBound(target_demon);
1366  }
1367  }
1368 
1369  void InitialPropagate() override {
1370  target_var_->SetRange(0, 1);
1371  if (target_var_->Max() == 0) {
1372  for (int i = 0; i < vars_.size(); ++i) {
1373  vars_[i]->SetMax(0);
1374  }
1375  } else {
1376  int zeros = 0;
1377  int possible_one = -1;
1378  int unbounded = 0;
1379  for (int i = 0; i < vars_.size(); ++i) {
1380  if (!vars_[i]->Bound()) {
1381  unbounded++;
1382  possible_one = i;
1383  } else if (vars_[i]->Min() == 1) {
1384  InhibitAll();
1385  target_var_->SetMin(1);
1386  return;
1387  } else {
1388  DCHECK_EQ(0, vars_[i]->Max());
1389  zeros++;
1390  }
1391  }
1392  if (unbounded == 0) {
1393  target_var_->SetMax(0);
1394  } else if (target_var_->Min() == 1 && unbounded == 1) {
1395  CHECK_NE(-1, possible_one);
1396  vars_[possible_one]->SetMin(1);
1397  } else {
1398  unbounded_.SetValue(solver(), unbounded);
1399  }
1400  }
1401  }
1402 
1403  void PropagateVar(IntVar* var) {
1404  if (var->Min() == 0) {
1405  unbounded_.Decr(solver());
1406  if (unbounded_.Value() == 0 && !decided_.Switched()) {
1407  target_var_->SetMax(0);
1408  decided_.Switch(solver());
1409  }
1410  if (target_var_->Min() == 1 && unbounded_.Value() == 1 &&
1411  !decided_.Switched()) {
1412  ForceToOne();
1413  }
1414  } else {
1415  InhibitAll();
1416  target_var_->SetMin(1);
1417  }
1418  }
1419 
1420  void PropagateTarget() {
1421  if (target_var_->Max() == 0) {
1422  for (int i = 0; i < vars_.size(); ++i) {
1423  vars_[i]->SetMax(0);
1424  }
1425  } else {
1426  if (unbounded_.Value() == 1 && !decided_.Switched()) {
1427  ForceToOne();
1428  }
1429  }
1430  }
1431 
1432  std::string DebugString() const override {
1433  return absl::StrFormat("Or(%s) == %s", JoinDebugStringPtr(vars_, ", "),
1434  target_var_->DebugString());
1435  }
1436 
1437  void Accept(ModelVisitor* const visitor) const override {
1438  visitor->BeginVisitConstraint(ModelVisitor::kMaxEqual, this);
1439  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1440  vars_);
1441  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1442  target_var_);
1443  visitor->EndVisitConstraint(ModelVisitor::kMaxEqual, this);
1444  }
1445 
1446  private:
1447  void InhibitAll() {
1448  for (int i = 0; i < demons_.size(); ++i) {
1449  if (demons_[i] != nullptr) {
1450  demons_[i]->inhibit(solver());
1451  }
1452  }
1453  }
1454 
1455  void ForceToOne() {
1456  for (int i = 0; i < vars_.size(); ++i) {
1457  if (vars_[i]->Max() == 1) {
1458  vars_[i]->SetValue(1);
1459  decided_.Switch(solver());
1460  return;
1461  }
1462  }
1463  solver()->Fail();
1464  }
1465 
1466  const std::vector<IntVar*> vars_;
1467  std::vector<Demon*> demons_;
1468  NumericalRev<int> unbounded_;
1469  RevSwitch decided_;
1470 };
1471 
1472 // ---------- Specialized cases ----------
1473 
1474 class BaseSumBooleanConstraint : public Constraint {
1475  public:
1476  BaseSumBooleanConstraint(Solver* const s, const std::vector<IntVar*>& vars)
1477  : Constraint(s), vars_(vars) {}
1478 
1479  ~BaseSumBooleanConstraint() override {}
1480 
1481  protected:
1482  std::string DebugStringInternal(const std::string& name) const {
1483  return absl::StrFormat("%s(%s)", name, JoinDebugStringPtr(vars_, ", "));
1484  }
1485 
1486  const std::vector<IntVar*> vars_;
1487  RevSwitch inactive_;
1488 };
1489 
1490 // ----- Sum of Boolean <= 1 -----
1491 
1492 class SumBooleanLessOrEqualToOne : public BaseSumBooleanConstraint {
1493  public:
1494  SumBooleanLessOrEqualToOne(Solver* const s, const std::vector<IntVar*>& vars)
1495  : BaseSumBooleanConstraint(s, vars) {}
1496 
1497  ~SumBooleanLessOrEqualToOne() override {}
1498 
1499  void Post() override {
1500  for (int i = 0; i < vars_.size(); ++i) {
1501  if (!vars_[i]->Bound()) {
1502  Demon* u = MakeConstraintDemon1(solver(), this,
1503  &SumBooleanLessOrEqualToOne::Update,
1504  "Update", vars_[i]);
1505  vars_[i]->WhenBound(u);
1506  }
1507  }
1508  }
1509 
1510  void InitialPropagate() override {
1511  for (int i = 0; i < vars_.size(); ++i) {
1512  if (vars_[i]->Min() == 1) {
1513  PushAllToZeroExcept(vars_[i]);
1514  return;
1515  }
1516  }
1517  }
1518 
1519  void Update(IntVar* var) {
1520  if (!inactive_.Switched()) {
1521  DCHECK(var->Bound());
1522  if (var->Min() == 1) {
1523  PushAllToZeroExcept(var);
1524  }
1525  }
1526  }
1527 
1528  void PushAllToZeroExcept(IntVar* var) {
1529  inactive_.Switch(solver());
1530  for (int i = 0; i < vars_.size(); ++i) {
1531  IntVar* const other = vars_[i];
1532  if (other != var && other->Max() != 0) {
1533  other->SetMax(0);
1534  }
1535  }
1536  }
1537 
1538  std::string DebugString() const override {
1539  return DebugStringInternal("SumBooleanLessOrEqualToOne");
1540  }
1541 
1542  void Accept(ModelVisitor* const visitor) const override {
1543  visitor->BeginVisitConstraint(ModelVisitor::kSumLessOrEqual, this);
1544  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1545  vars_);
1546  visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, 1);
1547  visitor->EndVisitConstraint(ModelVisitor::kSumLessOrEqual, this);
1548  }
1549 };
1550 
1551 // ----- Sum of Boolean >= 1 -----
1552 
1553 // We implement this one as a Max(array) == 1.
1554 
1555 class SumBooleanGreaterOrEqualToOne : public BaseSumBooleanConstraint {
1556  public:
1557  SumBooleanGreaterOrEqualToOne(Solver* const s,
1558  const std::vector<IntVar*>& vars);
1559  ~SumBooleanGreaterOrEqualToOne() override {}
1560 
1561  void Post() override;
1562  void InitialPropagate() override;
1563 
1564  void Update(int index);
1565  void UpdateVar();
1566 
1567  std::string DebugString() const override;
1568 
1569  void Accept(ModelVisitor* const visitor) const override {
1570  visitor->BeginVisitConstraint(ModelVisitor::kSumGreaterOrEqual, this);
1571  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1572  vars_);
1573  visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, 1);
1574  visitor->EndVisitConstraint(ModelVisitor::kSumGreaterOrEqual, this);
1575  }
1576 
1577  private:
1578  RevBitSet bits_;
1579 };
1580 
1581 SumBooleanGreaterOrEqualToOne::SumBooleanGreaterOrEqualToOne(
1582  Solver* const s, const std::vector<IntVar*>& vars)
1583  : BaseSumBooleanConstraint(s, vars), bits_(vars.size()) {}
1584 
1585 void SumBooleanGreaterOrEqualToOne::Post() {
1586  for (int i = 0; i < vars_.size(); ++i) {
1587  Demon* d = MakeConstraintDemon1(
1588  solver(), this, &SumBooleanGreaterOrEqualToOne::Update, "Update", i);
1589  vars_[i]->WhenRange(d);
1590  }
1591 }
1592 
1593 void SumBooleanGreaterOrEqualToOne::InitialPropagate() {
1594  for (int i = 0; i < vars_.size(); ++i) {
1595  IntVar* const var = vars_[i];
1596  if (var->Min() == 1LL) {
1597  inactive_.Switch(solver());
1598  return;
1599  }
1600  if (var->Max() == 1LL) {
1601  bits_.SetToOne(solver(), i);
1602  }
1603  }
1604  if (bits_.IsCardinalityZero()) {
1605  solver()->Fail();
1606  } else if (bits_.IsCardinalityOne()) {
1607  vars_[bits_.GetFirstBit(0)]->SetValue(int64_t{1});
1608  inactive_.Switch(solver());
1609  }
1610 }
1611 
1612 void SumBooleanGreaterOrEqualToOne::Update(int index) {
1613  if (!inactive_.Switched()) {
1614  if (vars_[index]->Min() == 1LL) { // Bound to 1.
1615  inactive_.Switch(solver());
1616  } else {
1617  bits_.SetToZero(solver(), index);
1618  if (bits_.IsCardinalityZero()) {
1619  solver()->Fail();
1620  } else if (bits_.IsCardinalityOne()) {
1621  vars_[bits_.GetFirstBit(0)]->SetValue(int64_t{1});
1622  inactive_.Switch(solver());
1623  }
1624  }
1625  }
1626 }
1627 
1628 std::string SumBooleanGreaterOrEqualToOne::DebugString() const {
1629  return DebugStringInternal("SumBooleanGreaterOrEqualToOne");
1630 }
1631 
1632 // ----- Sum of Boolean == 1 -----
1633 
1634 class SumBooleanEqualToOne : public BaseSumBooleanConstraint {
1635  public:
1636  SumBooleanEqualToOne(Solver* const s, const std::vector<IntVar*>& vars)
1637  : BaseSumBooleanConstraint(s, vars), active_vars_(0) {}
1638 
1639  ~SumBooleanEqualToOne() override {}
1640 
1641  void Post() override {
1642  for (int i = 0; i < vars_.size(); ++i) {
1643  Demon* u = MakeConstraintDemon1(
1644  solver(), this, &SumBooleanEqualToOne::Update, "Update", i);
1645  vars_[i]->WhenBound(u);
1646  }
1647  }
1648 
1649  void InitialPropagate() override {
1650  int min1 = 0;
1651  int max1 = 0;
1652  int index_min = -1;
1653  int index_max = -1;
1654  for (int i = 0; i < vars_.size(); ++i) {
1655  const IntVar* const var = vars_[i];
1656  if (var->Min() == 1) {
1657  min1++;
1658  index_min = i;
1659  }
1660  if (var->Max() == 1) {
1661  max1++;
1662  index_max = i;
1663  }
1664  }
1665  if (min1 > 1 || max1 == 0) {
1666  solver()->Fail();
1667  } else if (min1 == 1) {
1668  DCHECK_NE(-1, index_min);
1669  PushAllToZeroExcept(index_min);
1670  } else if (max1 == 1) {
1671  DCHECK_NE(-1, index_max);
1672  vars_[index_max]->SetValue(1);
1673  inactive_.Switch(solver());
1674  } else {
1675  active_vars_.SetValue(solver(), max1);
1676  }
1677  }
1678 
1679  void Update(int index) {
1680  if (!inactive_.Switched()) {
1681  DCHECK(vars_[index]->Bound());
1682  const int64_t value = vars_[index]->Min(); // Faster than Value().
1683  if (value == 0) {
1684  active_vars_.Decr(solver());
1685  DCHECK_GE(active_vars_.Value(), 0);
1686  if (active_vars_.Value() == 0) {
1687  solver()->Fail();
1688  } else if (active_vars_.Value() == 1) {
1689  bool found = false;
1690  for (int i = 0; i < vars_.size(); ++i) {
1691  IntVar* const var = vars_[i];
1692  if (var->Max() == 1) {
1693  var->SetValue(1);
1694  PushAllToZeroExcept(i);
1695  found = true;
1696  break;
1697  }
1698  }
1699  if (!found) {
1700  solver()->Fail();
1701  }
1702  }
1703  } else {
1704  PushAllToZeroExcept(index);
1705  }
1706  }
1707  }
1708 
1709  void PushAllToZeroExcept(int index) {
1710  inactive_.Switch(solver());
1711  for (int i = 0; i < vars_.size(); ++i) {
1712  if (i != index && vars_[i]->Max() != 0) {
1713  vars_[i]->SetMax(0);
1714  }
1715  }
1716  }
1717 
1718  std::string DebugString() const override {
1719  return DebugStringInternal("SumBooleanEqualToOne");
1720  }
1721 
1722  void Accept(ModelVisitor* const visitor) const override {
1723  visitor->BeginVisitConstraint(ModelVisitor::kSumEqual, this);
1724  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1725  vars_);
1726  visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, 1);
1727  visitor->EndVisitConstraint(ModelVisitor::kSumEqual, this);
1728  }
1729 
1730  private:
1731  NumericalRev<int> active_vars_;
1732 };
1733 
1734 // ----- Sum of Boolean Equal To Var -----
1735 
1736 class SumBooleanEqualToVar : public BaseSumBooleanConstraint {
1737  public:
1738  SumBooleanEqualToVar(Solver* const s, const std::vector<IntVar*>& bool_vars,
1739  IntVar* const sum_var)
1740  : BaseSumBooleanConstraint(s, bool_vars),
1741  num_possible_true_vars_(0),
1742  num_always_true_vars_(0),
1743  sum_var_(sum_var) {}
1744 
1745  ~SumBooleanEqualToVar() override {}
1746 
1747  void Post() override {
1748  for (int i = 0; i < vars_.size(); ++i) {
1749  Demon* const u = MakeConstraintDemon1(
1750  solver(), this, &SumBooleanEqualToVar::Update, "Update", i);
1751  vars_[i]->WhenBound(u);
1752  }
1753  if (!sum_var_->Bound()) {
1754  Demon* const u = MakeConstraintDemon0(
1755  solver(), this, &SumBooleanEqualToVar::UpdateVar, "UpdateVar");
1756  sum_var_->WhenRange(u);
1757  }
1758  }
1759 
1760  void InitialPropagate() override {
1761  int num_always_true_vars = 0;
1762  int possible_true = 0;
1763  for (int i = 0; i < vars_.size(); ++i) {
1764  const IntVar* const var = vars_[i];
1765  if (var->Min() == 1) {
1766  num_always_true_vars++;
1767  }
1768  if (var->Max() == 1) {
1769  possible_true++;
1770  }
1771  }
1772  sum_var_->SetRange(num_always_true_vars, possible_true);
1773  const int64_t var_min = sum_var_->Min();
1774  const int64_t var_max = sum_var_->Max();
1775  if (num_always_true_vars == var_max && possible_true > var_max) {
1776  PushAllUnboundToZero();
1777  } else if (possible_true == var_min && num_always_true_vars < var_min) {
1778  PushAllUnboundToOne();
1779  } else {
1780  num_possible_true_vars_.SetValue(solver(), possible_true);
1781  num_always_true_vars_.SetValue(solver(), num_always_true_vars);
1782  }
1783  }
1784 
1785  void UpdateVar() {
1786  if (!inactive_.Switched()) {
1787  if (num_possible_true_vars_.Value() == sum_var_->Min()) {
1788  PushAllUnboundToOne();
1789  sum_var_->SetValue(num_possible_true_vars_.Value());
1790  } else if (num_always_true_vars_.Value() == sum_var_->Max()) {
1791  PushAllUnboundToZero();
1792  sum_var_->SetValue(num_always_true_vars_.Value());
1793  }
1794  }
1795  }
1796 
1797  void Update(int index) {
1798  if (!inactive_.Switched()) {
1799  DCHECK(vars_[index]->Bound());
1800  const int64_t value = vars_[index]->Min(); // Faster than Value().
1801  if (value == 0) {
1802  num_possible_true_vars_.Decr(solver());
1803  sum_var_->SetRange(num_always_true_vars_.Value(),
1804  num_possible_true_vars_.Value());
1805  if (num_possible_true_vars_.Value() == sum_var_->Min()) {
1806  PushAllUnboundToOne();
1807  }
1808  } else {
1809  DCHECK_EQ(1, value);
1810  num_always_true_vars_.Incr(solver());
1811  sum_var_->SetRange(num_always_true_vars_.Value(),
1812  num_possible_true_vars_.Value());
1813  if (num_always_true_vars_.Value() == sum_var_->Max()) {
1814  PushAllUnboundToZero();
1815  }
1816  }
1817  }
1818  }
1819 
1820  void PushAllUnboundToZero() {
1821  int64_t counter = 0;
1822  inactive_.Switch(solver());
1823  for (int i = 0; i < vars_.size(); ++i) {
1824  if (vars_[i]->Min() == 0) {
1825  vars_[i]->SetValue(0);
1826  } else {
1827  counter++;
1828  }
1829  }
1830  if (counter < sum_var_->Min() || counter > sum_var_->Max()) {
1831  solver()->Fail();
1832  }
1833  }
1834 
1835  void PushAllUnboundToOne() {
1836  int64_t counter = 0;
1837  inactive_.Switch(solver());
1838  for (int i = 0; i < vars_.size(); ++i) {
1839  if (vars_[i]->Max() == 1) {
1840  vars_[i]->SetValue(1);
1841  counter++;
1842  }
1843  }
1844  if (counter < sum_var_->Min() || counter > sum_var_->Max()) {
1845  solver()->Fail();
1846  }
1847  }
1848 
1849  std::string DebugString() const override {
1850  return absl::StrFormat("%s == %s", DebugStringInternal("SumBoolean"),
1851  sum_var_->DebugString());
1852  }
1853 
1854  void Accept(ModelVisitor* const visitor) const override {
1855  visitor->BeginVisitConstraint(ModelVisitor::kSumEqual, this);
1856  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1857  vars_);
1858  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1859  sum_var_);
1860  visitor->EndVisitConstraint(ModelVisitor::kSumEqual, this);
1861  }
1862 
1863  private:
1864  NumericalRev<int> num_possible_true_vars_;
1865  NumericalRev<int> num_always_true_vars_;
1866  IntVar* const sum_var_;
1867 };
1868 
1869 // ---------- ScalProd ----------
1870 
1871 // ----- Boolean Scal Prod -----
1872 
1873 struct Container {
1874  IntVar* var;
1875  int64_t coef;
1876  Container(IntVar* v, int64_t c) : var(v), coef(c) {}
1877  bool operator<(const Container& c) const { return (coef < c.coef); }
1878 };
1879 
1880 // This method will sort both vars and coefficients in increasing
1881 // coefficient order. Vars with null coefficients will be
1882 // removed. Bound vars will be collected and the sum of the
1883 // corresponding products (when the var is bound to 1) is returned by
1884 // this method.
1885 // If keep_inside is true, the constant will be added back into the
1886 // scalprod as IntConst(1) * constant.
1887 int64_t SortBothChangeConstant(std::vector<IntVar*>* const vars,
1888  std::vector<int64_t>* const coefs,
1889  bool keep_inside) {
1890  CHECK(vars != nullptr);
1891  CHECK(coefs != nullptr);
1892  if (vars->empty()) {
1893  return 0;
1894  }
1895  int64_t cst = 0;
1896  std::vector<Container> to_sort;
1897  for (int index = 0; index < vars->size(); ++index) {
1898  if ((*vars)[index]->Bound()) {
1899  cst = CapAdd(cst, CapProd((*coefs)[index], (*vars)[index]->Min()));
1900  } else if ((*coefs)[index] != 0) {
1901  to_sort.push_back(Container((*vars)[index], (*coefs)[index]));
1902  }
1903  }
1904  if (keep_inside && cst != 0) {
1905  CHECK_LT(to_sort.size(), vars->size());
1906  Solver* const solver = (*vars)[0]->solver();
1907  to_sort.push_back(Container(solver->MakeIntConst(1), cst));
1908  cst = 0;
1909  }
1910  std::sort(to_sort.begin(), to_sort.end());
1911  for (int index = 0; index < to_sort.size(); ++index) {
1912  (*vars)[index] = to_sort[index].var;
1913  (*coefs)[index] = to_sort[index].coef;
1914  }
1915  vars->resize(to_sort.size());
1916  coefs->resize(to_sort.size());
1917  return cst;
1918 }
1919 
1920 // This constraint implements sum(vars) == var. It is delayed such
1921 // that propagation only occurs when all variables have been touched.
1922 class BooleanScalProdLessConstant : public Constraint {
1923  public:
1924  BooleanScalProdLessConstant(Solver* const s, const std::vector<IntVar*>& vars,
1925  const std::vector<int64_t>& coefs,
1926  int64_t upper_bound)
1927  : Constraint(s),
1928  vars_(vars),
1929  coefs_(coefs),
1930  upper_bound_(upper_bound),
1931  first_unbound_backward_(vars.size() - 1),
1932  sum_of_bound_variables_(0LL),
1933  max_coefficient_(0) {
1934  CHECK(!vars.empty());
1935  for (int i = 0; i < vars_.size(); ++i) {
1936  DCHECK_GE(coefs_[i], 0);
1937  }
1938  upper_bound_ =
1939  CapSub(upper_bound, SortBothChangeConstant(&vars_, &coefs_, false));
1940  max_coefficient_.SetValue(s, coefs_[vars_.size() - 1]);
1941  }
1942 
1943  ~BooleanScalProdLessConstant() override {}
1944 
1945  void Post() override {
1946  for (int var_index = 0; var_index < vars_.size(); ++var_index) {
1947  if (vars_[var_index]->Bound()) {
1948  continue;
1949  }
1950  Demon* d = MakeConstraintDemon1(solver(), this,
1951  &BooleanScalProdLessConstant::Update,
1952  "InitialPropagate", var_index);
1953  vars_[var_index]->WhenRange(d);
1954  }
1955  }
1956 
1957  void PushFromTop() {
1958  const int64_t slack = CapSub(upper_bound_, sum_of_bound_variables_.Value());
1959  if (slack < 0) {
1960  solver()->Fail();
1961  }
1962  if (slack < max_coefficient_.Value()) {
1963  int64_t last_unbound = first_unbound_backward_.Value();
1964  for (; last_unbound >= 0; --last_unbound) {
1965  if (!vars_[last_unbound]->Bound()) {
1966  if (coefs_[last_unbound] <= slack) {
1967  max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
1968  break;
1969  } else {
1970  vars_[last_unbound]->SetValue(0);
1971  }
1972  }
1973  }
1974  first_unbound_backward_.SetValue(solver(), last_unbound);
1975  }
1976  }
1977 
1978  void InitialPropagate() override {
1979  Solver* const s = solver();
1980  int last_unbound = -1;
1981  int64_t sum = 0LL;
1982  for (int index = 0; index < vars_.size(); ++index) {
1983  if (vars_[index]->Bound()) {
1984  const int64_t value = vars_[index]->Min();
1985  sum = CapAdd(sum, CapProd(value, coefs_[index]));
1986  } else {
1987  last_unbound = index;
1988  }
1989  }
1990  sum_of_bound_variables_.SetValue(s, sum);
1991  first_unbound_backward_.SetValue(s, last_unbound);
1992  PushFromTop();
1993  }
1994 
1995  void Update(int var_index) {
1996  if (vars_[var_index]->Min() == 1) {
1997  sum_of_bound_variables_.SetValue(
1998  solver(), CapAdd(sum_of_bound_variables_.Value(), coefs_[var_index]));
1999  PushFromTop();
2000  }
2001  }
2002 
2003  std::string DebugString() const override {
2004  return absl::StrFormat("BooleanScalProd([%s], [%s]) <= %d)",
2005  JoinDebugStringPtr(vars_, ", "),
2006  absl::StrJoin(coefs_, ", "), upper_bound_);
2007  }
2008 
2009  void Accept(ModelVisitor* const visitor) const override {
2010  visitor->BeginVisitConstraint(ModelVisitor::kScalProdLessOrEqual, this);
2011  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2012  vars_);
2013  visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2014  coefs_);
2015  visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, upper_bound_);
2016  visitor->EndVisitConstraint(ModelVisitor::kScalProdLessOrEqual, this);
2017  }
2018 
2019  private:
2020  std::vector<IntVar*> vars_;
2021  std::vector<int64_t> coefs_;
2022  int64_t upper_bound_;
2023  Rev<int> first_unbound_backward_;
2024  Rev<int64_t> sum_of_bound_variables_;
2025  Rev<int64_t> max_coefficient_;
2026 };
2027 
2028 // ----- PositiveBooleanScalProdEqVar -----
2029 
2030 class PositiveBooleanScalProdEqVar : public CastConstraint {
2031  public:
2032  PositiveBooleanScalProdEqVar(Solver* const s,
2033  const std::vector<IntVar*>& vars,
2034  const std::vector<int64_t>& coefs,
2035  IntVar* const var)
2036  : CastConstraint(s, var),
2037  vars_(vars),
2038  coefs_(coefs),
2039  first_unbound_backward_(vars.size() - 1),
2040  sum_of_bound_variables_(0LL),
2041  sum_of_all_variables_(0LL),
2042  max_coefficient_(0) {
2043  SortBothChangeConstant(&vars_, &coefs_, true);
2044  max_coefficient_.SetValue(s, coefs_[vars_.size() - 1]);
2045  }
2046 
2047  ~PositiveBooleanScalProdEqVar() override {}
2048 
2049  void Post() override {
2050  for (int var_index = 0; var_index < vars_.size(); ++var_index) {
2051  if (vars_[var_index]->Bound()) {
2052  continue;
2053  }
2054  Demon* const d = MakeConstraintDemon1(
2055  solver(), this, &PositiveBooleanScalProdEqVar::Update, "Update",
2056  var_index);
2057  vars_[var_index]->WhenRange(d);
2058  }
2059  if (!target_var_->Bound()) {
2060  Demon* const uv = MakeConstraintDemon0(
2061  solver(), this, &PositiveBooleanScalProdEqVar::Propagate,
2062  "Propagate");
2063  target_var_->WhenRange(uv);
2064  }
2065  }
2066 
2067  void Propagate() {
2068  target_var_->SetRange(sum_of_bound_variables_.Value(),
2069  sum_of_all_variables_.Value());
2070  const int64_t slack_up =
2071  CapSub(target_var_->Max(), sum_of_bound_variables_.Value());
2072  const int64_t slack_down =
2073  CapSub(sum_of_all_variables_.Value(), target_var_->Min());
2074  const int64_t max_coeff = max_coefficient_.Value();
2075  if (slack_down < max_coeff || slack_up < max_coeff) {
2076  int64_t last_unbound = first_unbound_backward_.Value();
2077  for (; last_unbound >= 0; --last_unbound) {
2078  if (!vars_[last_unbound]->Bound()) {
2079  if (coefs_[last_unbound] > slack_up) {
2080  vars_[last_unbound]->SetValue(0);
2081  } else if (coefs_[last_unbound] > slack_down) {
2082  vars_[last_unbound]->SetValue(1);
2083  } else {
2084  max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
2085  break;
2086  }
2087  }
2088  }
2089  first_unbound_backward_.SetValue(solver(), last_unbound);
2090  }
2091  }
2092 
2093  void InitialPropagate() override {
2094  Solver* const s = solver();
2095  int last_unbound = -1;
2096  int64_t sum_bound = 0;
2097  int64_t sum_all = 0;
2098  for (int index = 0; index < vars_.size(); ++index) {
2099  const int64_t value = CapProd(vars_[index]->Max(), coefs_[index]);
2100  sum_all = CapAdd(sum_all, value);
2101  if (vars_[index]->Bound()) {
2102  sum_bound = CapAdd(sum_bound, value);
2103  } else {
2104  last_unbound = index;
2105  }
2106  }
2107  sum_of_bound_variables_.SetValue(s, sum_bound);
2108  sum_of_all_variables_.SetValue(s, sum_all);
2109  first_unbound_backward_.SetValue(s, last_unbound);
2110  Propagate();
2111  }
2112 
2113  void Update(int var_index) {
2114  if (vars_[var_index]->Min() == 1) {
2115  sum_of_bound_variables_.SetValue(
2116  solver(), CapAdd(sum_of_bound_variables_.Value(), coefs_[var_index]));
2117  } else {
2118  sum_of_all_variables_.SetValue(
2119  solver(), CapSub(sum_of_all_variables_.Value(), coefs_[var_index]));
2120  }
2121  Propagate();
2122  }
2123 
2124  std::string DebugString() const override {
2125  return absl::StrFormat("PositiveBooleanScal([%s], [%s]) == %s",
2126  JoinDebugStringPtr(vars_, ", "),
2127  absl::StrJoin(coefs_, ", "),
2128  target_var_->DebugString());
2129  }
2130 
2131  void Accept(ModelVisitor* const visitor) const override {
2132  visitor->BeginVisitConstraint(ModelVisitor::kScalProdEqual, this);
2133  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2134  vars_);
2135  visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2136  coefs_);
2137  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
2138  target_var_);
2139  visitor->EndVisitConstraint(ModelVisitor::kScalProdEqual, this);
2140  }
2141 
2142  private:
2143  std::vector<IntVar*> vars_;
2144  std::vector<int64_t> coefs_;
2145  Rev<int> first_unbound_backward_;
2146  Rev<int64_t> sum_of_bound_variables_;
2147  Rev<int64_t> sum_of_all_variables_;
2148  Rev<int64_t> max_coefficient_;
2149 };
2150 
2151 // ----- PositiveBooleanScalProd -----
2152 
2153 class PositiveBooleanScalProd : public BaseIntExpr {
2154  public:
2155  // this constructor will copy the array. The caller can safely delete the
2156  // exprs array himself
2157  PositiveBooleanScalProd(Solver* const s, const std::vector<IntVar*>& vars,
2158  const std::vector<int64_t>& coefs)
2159  : BaseIntExpr(s), vars_(vars), coefs_(coefs) {
2160  CHECK(!vars.empty());
2161  SortBothChangeConstant(&vars_, &coefs_, true);
2162  for (int i = 0; i < vars_.size(); ++i) {
2163  DCHECK_GE(coefs_[i], 0);
2164  }
2165  }
2166 
2167  ~PositiveBooleanScalProd() override {}
2168 
2169  int64_t Min() const override {
2170  int64_t min = 0;
2171  for (int i = 0; i < vars_.size(); ++i) {
2172  if (vars_[i]->Min()) {
2173  min = CapAdd(min, coefs_[i]);
2174  }
2175  }
2176  return min;
2177  }
2178 
2179  void SetMin(int64_t m) override {
2180  SetRange(m, std::numeric_limits<int64_t>::max());
2181  }
2182 
2183  int64_t Max() const override {
2184  int64_t max = 0;
2185  for (int i = 0; i < vars_.size(); ++i) {
2186  if (vars_[i]->Max()) {
2187  max = CapAdd(max, coefs_[i]);
2188  }
2189  }
2190  return max;
2191  }
2192 
2193  void SetMax(int64_t m) override {
2194  SetRange(std::numeric_limits<int64_t>::min(), m);
2195  }
2196 
2197  void SetRange(int64_t l, int64_t u) override {
2198  int64_t current_min = 0;
2199  int64_t current_max = 0;
2200  int64_t diameter = -1;
2201  for (int i = 0; i < vars_.size(); ++i) {
2202  const int64_t coefficient = coefs_[i];
2203  const int64_t var_min = CapProd(vars_[i]->Min(), coefficient);
2204  const int64_t var_max = CapProd(vars_[i]->Max(), coefficient);
2205  current_min = CapAdd(current_min, var_min);
2206  current_max = CapAdd(current_max, var_max);
2207  if (var_min != var_max) { // Coefficients are increasing.
2208  diameter = CapSub(var_max, var_min);
2209  }
2210  }
2211  if (u >= current_max && l <= current_min) {
2212  return;
2213  }
2214  if (u < current_min || l > current_max) {
2215  solver()->Fail();
2216  }
2217 
2218  u = std::min(current_max, u);
2219  l = std::max(l, current_min);
2220 
2221  if (CapSub(u, l) > diameter) {
2222  return;
2223  }
2224 
2225  for (int i = 0; i < vars_.size(); ++i) {
2226  const int64_t coefficient = coefs_[i];
2227  IntVar* const var = vars_[i];
2228  const int64_t new_min =
2229  CapAdd(CapSub(l, current_max), CapProd(var->Max(), coefficient));
2230  const int64_t new_max =
2231  CapAdd(CapSub(u, current_min), CapProd(var->Min(), coefficient));
2232  if (new_max < 0 || new_min > coefficient || new_min > new_max) {
2233  solver()->Fail();
2234  }
2235  if (new_min > 0LL) {
2236  var->SetMin(int64_t{1});
2237  } else if (new_max < coefficient) {
2238  var->SetMax(int64_t{0});
2239  }
2240  }
2241  }
2242 
2243  std::string DebugString() const override {
2244  return absl::StrFormat("PositiveBooleanScalProd([%s], [%s])",
2245  JoinDebugStringPtr(vars_, ", "),
2246  absl::StrJoin(coefs_, ", "));
2247  }
2248 
2249  void WhenRange(Demon* d) override {
2250  for (int i = 0; i < vars_.size(); ++i) {
2251  vars_[i]->WhenRange(d);
2252  }
2253  }
2254  IntVar* CastToVar() override {
2255  Solver* const s = solver();
2256  int64_t vmin = 0LL;
2257  int64_t vmax = 0LL;
2258  Range(&vmin, &vmax);
2259  IntVar* const var = solver()->MakeIntVar(vmin, vmax);
2260  if (!vars_.empty()) {
2261  CastConstraint* const ct =
2262  s->RevAlloc(new PositiveBooleanScalProdEqVar(s, vars_, coefs_, var));
2263  s->AddCastConstraint(ct, var, this);
2264  }
2265  return var;
2266  }
2267 
2268  void Accept(ModelVisitor* const visitor) const override {
2269  visitor->BeginVisitIntegerExpression(ModelVisitor::kScalProd, this);
2270  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2271  vars_);
2272  visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2273  coefs_);
2274  visitor->EndVisitIntegerExpression(ModelVisitor::kScalProd, this);
2275  }
2276 
2277  private:
2278  std::vector<IntVar*> vars_;
2279  std::vector<int64_t> coefs_;
2280 };
2281 
2282 // ----- PositiveBooleanScalProdEqCst ----- (all constants >= 0)
2283 
2284 class PositiveBooleanScalProdEqCst : public Constraint {
2285  public:
2286  PositiveBooleanScalProdEqCst(Solver* const s,
2287  const std::vector<IntVar*>& vars,
2288  const std::vector<int64_t>& coefs,
2289  int64_t constant)
2290  : Constraint(s),
2291  vars_(vars),
2292  coefs_(coefs),
2293  first_unbound_backward_(vars.size() - 1),
2294  sum_of_bound_variables_(0LL),
2295  sum_of_all_variables_(0LL),
2296  constant_(constant),
2297  max_coefficient_(0) {
2298  CHECK(!vars.empty());
2299  constant_ =
2300  CapSub(constant_, SortBothChangeConstant(&vars_, &coefs_, false));
2301  max_coefficient_.SetValue(s, coefs_[vars_.size() - 1]);
2302  }
2303 
2304  ~PositiveBooleanScalProdEqCst() override {}
2305 
2306  void Post() override {
2307  for (int var_index = 0; var_index < vars_.size(); ++var_index) {
2308  if (!vars_[var_index]->Bound()) {
2309  Demon* const d = MakeConstraintDemon1(
2310  solver(), this, &PositiveBooleanScalProdEqCst::Update, "Update",
2311  var_index);
2312  vars_[var_index]->WhenRange(d);
2313  }
2314  }
2315  }
2316 
2317  void Propagate() {
2318  if (sum_of_bound_variables_.Value() > constant_ ||
2319  sum_of_all_variables_.Value() < constant_) {
2320  solver()->Fail();
2321  }
2322  const int64_t slack_up = CapSub(constant_, sum_of_bound_variables_.Value());
2323  const int64_t slack_down = CapSub(sum_of_all_variables_.Value(), constant_);
2324  const int64_t max_coeff = max_coefficient_.Value();
2325  if (slack_down < max_coeff || slack_up < max_coeff) {
2326  int64_t last_unbound = first_unbound_backward_.Value();
2327  for (; last_unbound >= 0; --last_unbound) {
2328  if (!vars_[last_unbound]->Bound()) {
2329  if (coefs_[last_unbound] > slack_up) {
2330  vars_[last_unbound]->SetValue(0);
2331  } else if (coefs_[last_unbound] > slack_down) {
2332  vars_[last_unbound]->SetValue(1);
2333  } else {
2334  max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
2335  break;
2336  }
2337  }
2338  }
2339  first_unbound_backward_.SetValue(solver(), last_unbound);
2340  }
2341  }
2342 
2343  void InitialPropagate() override {
2344  Solver* const s = solver();
2345  int last_unbound = -1;
2346  int64_t sum_bound = 0LL;
2347  int64_t sum_all = 0LL;
2348  for (int index = 0; index < vars_.size(); ++index) {
2349  const int64_t value = CapProd(vars_[index]->Max(), coefs_[index]);
2350  sum_all = CapAdd(sum_all, value);
2351  if (vars_[index]->Bound()) {
2352  sum_bound = CapAdd(sum_bound, value);
2353  } else {
2354  last_unbound = index;
2355  }
2356  }
2357  sum_of_bound_variables_.SetValue(s, sum_bound);
2358  sum_of_all_variables_.SetValue(s, sum_all);
2359  first_unbound_backward_.SetValue(s, last_unbound);
2360  Propagate();
2361  }
2362 
2363  void Update(int var_index) {
2364  if (vars_[var_index]->Min() == 1) {
2365  sum_of_bound_variables_.SetValue(
2366  solver(), CapAdd(sum_of_bound_variables_.Value(), coefs_[var_index]));
2367  } else {
2368  sum_of_all_variables_.SetValue(
2369  solver(), CapSub(sum_of_all_variables_.Value(), coefs_[var_index]));
2370  }
2371  Propagate();
2372  }
2373 
2374  std::string DebugString() const override {
2375  return absl::StrFormat("PositiveBooleanScalProd([%s], [%s]) == %d",
2376  JoinDebugStringPtr(vars_, ", "),
2377  absl::StrJoin(coefs_, ", "), constant_);
2378  }
2379 
2380  void Accept(ModelVisitor* const visitor) const override {
2381  visitor->BeginVisitConstraint(ModelVisitor::kScalProdEqual, this);
2382  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2383  vars_);
2384  visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2385  coefs_);
2386  visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, constant_);
2387  visitor->EndVisitConstraint(ModelVisitor::kScalProdEqual, this);
2388  }
2389 
2390  private:
2391  std::vector<IntVar*> vars_;
2392  std::vector<int64_t> coefs_;
2393  Rev<int> first_unbound_backward_;
2394  Rev<int64_t> sum_of_bound_variables_;
2395  Rev<int64_t> sum_of_all_variables_;
2396  int64_t constant_;
2397  Rev<int64_t> max_coefficient_;
2398 };
2399 
2400 // ----- Linearizer -----
2401 
2402 #define IS_TYPE(type, tag) type.compare(ModelVisitor::tag) == 0
2403 
2404 class ExprLinearizer : public ModelParser {
2405  public:
2406  explicit ExprLinearizer(
2407  absl::flat_hash_map<IntVar*, int64_t>* const variables_to_coefficients)
2408  : variables_to_coefficients_(variables_to_coefficients), constant_(0) {}
2409 
2410  ~ExprLinearizer() override {}
2411 
2412  // Begin/End visit element.
2413  void BeginVisitModel(const std::string& solver_name) override {
2414  LOG(FATAL) << "Should not be here";
2415  }
2416 
2417  void EndVisitModel(const std::string& solver_name) override {
2418  LOG(FATAL) << "Should not be here";
2419  }
2420 
2421  void BeginVisitConstraint(const std::string& type_name,
2422  const Constraint* const constraint) override {
2423  LOG(FATAL) << "Should not be here";
2424  }
2425 
2426  void EndVisitConstraint(const std::string& type_name,
2427  const Constraint* const constraint) override {
2428  LOG(FATAL) << "Should not be here";
2429  }
2430 
2431  void BeginVisitExtension(const std::string& type) override {}
2432 
2433  void EndVisitExtension(const std::string& type) override {}
2434  void BeginVisitIntegerExpression(const std::string& type_name,
2435  const IntExpr* const expr) override {
2436  BeginVisit(true);
2437  }
2438 
2439  void EndVisitIntegerExpression(const std::string& type_name,
2440  const IntExpr* const expr) override {
2441  if (IS_TYPE(type_name, kSum)) {
2442  VisitSum(expr);
2443  } else if (IS_TYPE(type_name, kScalProd)) {
2444  VisitScalProd(expr);
2445  } else if (IS_TYPE(type_name, kDifference)) {
2446  VisitDifference(expr);
2447  } else if (IS_TYPE(type_name, kOpposite)) {
2448  VisitOpposite(expr);
2449  } else if (IS_TYPE(type_name, kProduct)) {
2450  VisitProduct(expr);
2451  } else if (IS_TYPE(type_name, kTrace)) {
2452  VisitTrace(expr);
2453  } else {
2454  VisitIntegerExpression(expr);
2455  }
2456  EndVisit();
2457  }
2458 
2459  void VisitIntegerVariable(const IntVar* const variable,
2460  const std::string& operation, int64_t value,
2461  IntVar* const delegate) override {
2462  if (operation == ModelVisitor::kSumOperation) {
2463  AddConstant(value);
2464  VisitSubExpression(delegate);
2465  } else if (operation == ModelVisitor::kDifferenceOperation) {
2466  AddConstant(value);
2467  PushMultiplier(-1);
2468  VisitSubExpression(delegate);
2469  PopMultiplier();
2470  } else if (operation == ModelVisitor::kProductOperation) {
2471  PushMultiplier(value);
2472  VisitSubExpression(delegate);
2473  PopMultiplier();
2474  } else if (operation == ModelVisitor::kTraceOperation) {
2475  VisitSubExpression(delegate);
2476  }
2477  }
2478 
2479  void VisitIntegerVariable(const IntVar* const variable,
2480  IntExpr* const delegate) override {
2481  if (delegate != nullptr) {
2482  VisitSubExpression(delegate);
2483  } else {
2484  if (variable->Bound()) {
2485  AddConstant(variable->Min());
2486  } else {
2487  RegisterExpression(variable, 1);
2488  }
2489  }
2490  }
2491 
2492  // Visit integer arguments.
2493  void VisitIntegerArgument(const std::string& arg_name,
2494  int64_t value) override {
2495  Top()->SetIntegerArgument(arg_name, value);
2496  }
2497 
2498  void VisitIntegerArrayArgument(const std::string& arg_name,
2499  const std::vector<int64_t>& values) override {
2500  Top()->SetIntegerArrayArgument(arg_name, values);
2501  }
2502 
2503  void VisitIntegerMatrixArgument(const std::string& arg_name,
2504  const IntTupleSet& values) override {
2505  Top()->SetIntegerMatrixArgument(arg_name, values);
2506  }
2507 
2508  // Visit integer expression argument.
2509  void VisitIntegerExpressionArgument(const std::string& arg_name,
2510  IntExpr* const argument) override {
2511  Top()->SetIntegerExpressionArgument(arg_name, argument);
2512  }
2513 
2514  void VisitIntegerVariableArrayArgument(
2515  const std::string& arg_name,
2516  const std::vector<IntVar*>& arguments) override {
2517  Top()->SetIntegerVariableArrayArgument(arg_name, arguments);
2518  }
2519 
2520  // Visit interval argument.
2521  void VisitIntervalArgument(const std::string& arg_name,
2522  IntervalVar* const argument) override {}
2523 
2524  void VisitIntervalArrayArgument(
2525  const std::string& arg_name,
2526  const std::vector<IntervalVar*>& argument) override {}
2527 
2528  void Visit(const IntExpr* const expr, int64_t multiplier) {
2529  if (expr->Min() == expr->Max()) {
2530  constant_ = CapAdd(constant_, CapProd(expr->Min(), multiplier));
2531  } else {
2532  PushMultiplier(multiplier);
2533  expr->Accept(this);
2534  PopMultiplier();
2535  }
2536  }
2537 
2538  int64_t Constant() const { return constant_; }
2539 
2540  std::string DebugString() const override { return "ExprLinearizer"; }
2541 
2542  private:
2543  void BeginVisit(bool active) { PushArgumentHolder(); }
2544 
2545  void EndVisit() { PopArgumentHolder(); }
2546 
2547  void VisitSubExpression(const IntExpr* const cp_expr) {
2548  cp_expr->Accept(this);
2549  }
2550 
2551  void VisitSum(const IntExpr* const cp_expr) {
2552  if (Top()->HasIntegerVariableArrayArgument(ModelVisitor::kVarsArgument)) {
2553  const std::vector<IntVar*>& cp_vars =
2554  Top()->FindIntegerVariableArrayArgumentOrDie(
2555  ModelVisitor::kVarsArgument);
2556  for (int i = 0; i < cp_vars.size(); ++i) {
2557  VisitSubExpression(cp_vars[i]);
2558  }
2559  } else if (Top()->HasIntegerExpressionArgument(
2560  ModelVisitor::kLeftArgument)) {
2561  const IntExpr* const left = Top()->FindIntegerExpressionArgumentOrDie(
2562  ModelVisitor::kLeftArgument);
2563  const IntExpr* const right = Top()->FindIntegerExpressionArgumentOrDie(
2564  ModelVisitor::kRightArgument);
2565  VisitSubExpression(left);
2566  VisitSubExpression(right);
2567  } else {
2568  const IntExpr* const expr = Top()->FindIntegerExpressionArgumentOrDie(
2569  ModelVisitor::kExpressionArgument);
2570  const int64_t value =
2571  Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2572  VisitSubExpression(expr);
2573  AddConstant(value);
2574  }
2575  }
2576 
2577  void VisitScalProd(const IntExpr* const cp_expr) {
2578  const std::vector<IntVar*>& cp_vars =
2579  Top()->FindIntegerVariableArrayArgumentOrDie(
2580  ModelVisitor::kVarsArgument);
2581  const std::vector<int64_t>& cp_coefficients =
2582  Top()->FindIntegerArrayArgumentOrDie(
2583  ModelVisitor::kCoefficientsArgument);
2584  CHECK_EQ(cp_vars.size(), cp_coefficients.size());
2585  for (int i = 0; i < cp_vars.size(); ++i) {
2586  const int64_t coefficient = cp_coefficients[i];
2587  PushMultiplier(coefficient);
2588  VisitSubExpression(cp_vars[i]);
2589  PopMultiplier();
2590  }
2591  }
2592 
2593  void VisitDifference(const IntExpr* const cp_expr) {
2594  if (Top()->HasIntegerExpressionArgument(ModelVisitor::kLeftArgument)) {
2595  const IntExpr* const left = Top()->FindIntegerExpressionArgumentOrDie(
2596  ModelVisitor::kLeftArgument);
2597  const IntExpr* const right = Top()->FindIntegerExpressionArgumentOrDie(
2598  ModelVisitor::kRightArgument);
2599  VisitSubExpression(left);
2600  PushMultiplier(-1);
2601  VisitSubExpression(right);
2602  PopMultiplier();
2603  } else {
2604  const IntExpr* const expr = Top()->FindIntegerExpressionArgumentOrDie(
2605  ModelVisitor::kExpressionArgument);
2606  const int64_t value =
2607  Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2608  AddConstant(value);
2609  PushMultiplier(-1);
2610  VisitSubExpression(expr);
2611  PopMultiplier();
2612  }
2613  }
2614 
2615  void VisitOpposite(const IntExpr* const cp_expr) {
2616  const IntExpr* const expr = Top()->FindIntegerExpressionArgumentOrDie(
2617  ModelVisitor::kExpressionArgument);
2618  PushMultiplier(-1);
2619  VisitSubExpression(expr);
2620  PopMultiplier();
2621  }
2622 
2623  void VisitProduct(const IntExpr* const cp_expr) {
2624  if (Top()->HasIntegerExpressionArgument(
2625  ModelVisitor::kExpressionArgument)) {
2626  const IntExpr* const expr = Top()->FindIntegerExpressionArgumentOrDie(
2627  ModelVisitor::kExpressionArgument);
2628  const int64_t value =
2629  Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2630  PushMultiplier(value);
2631  VisitSubExpression(expr);
2632  PopMultiplier();
2633  } else {
2634  RegisterExpression(cp_expr, 1);
2635  }
2636  }
2637 
2638  void VisitTrace(const IntExpr* const cp_expr) {
2639  const IntExpr* const expr = Top()->FindIntegerExpressionArgumentOrDie(
2640  ModelVisitor::kExpressionArgument);
2641  VisitSubExpression(expr);
2642  }
2643 
2644  void VisitIntegerExpression(const IntExpr* const cp_expr) {
2645  RegisterExpression(cp_expr, 1);
2646  }
2647 
2648  void RegisterExpression(const IntExpr* const expr, int64_t coef) {
2649  int64_t& value =
2650  (*variables_to_coefficients_)[const_cast<IntExpr*>(expr)->Var()];
2651  value = CapAdd(value, CapProd(coef, multipliers_.back()));
2652  }
2653 
2654  void AddConstant(int64_t constant) {
2655  constant_ = CapAdd(constant_, CapProd(constant, multipliers_.back()));
2656  }
2657 
2658  void PushMultiplier(int64_t multiplier) {
2659  if (multipliers_.empty()) {
2660  multipliers_.push_back(multiplier);
2661  } else {
2662  multipliers_.push_back(CapProd(multiplier, multipliers_.back()));
2663  }
2664  }
2665 
2666  void PopMultiplier() { multipliers_.pop_back(); }
2667 
2668  // We do need a IntVar* as key, and not const IntVar*, because clients of this
2669  // class typically iterate over the map keys and use them as mutable IntVar*.
2670  absl::flat_hash_map<IntVar*, int64_t>* const variables_to_coefficients_;
2671  std::vector<int64_t> multipliers_;
2672  int64_t constant_;
2673 };
2674 #undef IS_TYPE
2675 
2676 // ----- Factory functions -----
2677 
2678 void DeepLinearize(Solver* const solver, const std::vector<IntVar*>& pre_vars,
2679  const std::vector<int64_t>& pre_coefs,
2680  std::vector<IntVar*>* vars, std::vector<int64_t>* coefs,
2681  int64_t* constant) {
2682  CHECK(solver != nullptr);
2683  CHECK(vars != nullptr);
2684  CHECK(coefs != nullptr);
2685  CHECK(constant != nullptr);
2686  *constant = 0;
2687  vars->reserve(pre_vars.size());
2688  coefs->reserve(pre_coefs.size());
2689  // Try linear scan of the variables to check if there is nothing to do.
2690  bool need_linearization = false;
2691  for (int i = 0; i < pre_vars.size(); ++i) {
2692  IntVar* const variable = pre_vars[i];
2693  const int64_t coefficient = pre_coefs[i];
2694  if (variable->Bound()) {
2695  *constant = CapAdd(*constant, CapProd(coefficient, variable->Min()));
2696  } else if (solver->CastExpression(variable) == nullptr) {
2697  vars->push_back(variable);
2698  coefs->push_back(coefficient);
2699  } else {
2700  need_linearization = true;
2701  vars->clear();
2702  coefs->clear();
2703  break;
2704  }
2705  }
2706  if (need_linearization) {
2707  // Instrospect the variables to simplify the sum.
2708  absl::flat_hash_map<IntVar*, int64_t> variables_to_coefficients;
2709  ExprLinearizer linearizer(&variables_to_coefficients);
2710  for (int i = 0; i < pre_vars.size(); ++i) {
2711  linearizer.Visit(pre_vars[i], pre_coefs[i]);
2712  }
2713  *constant = linearizer.Constant();
2714  for (const auto& variable_to_coefficient : variables_to_coefficients) {
2715  if (variable_to_coefficient.second != 0) {
2716  vars->push_back(variable_to_coefficient.first);
2717  coefs->push_back(variable_to_coefficient.second);
2718  }
2719  }
2720  }
2721 }
2722 
2723 Constraint* MakeScalProdEqualityFct(Solver* const solver,
2724  const std::vector<IntVar*>& pre_vars,
2725  const std::vector<int64_t>& pre_coefs,
2726  int64_t cst) {
2727  int64_t constant = 0;
2728  std::vector<IntVar*> vars;
2729  std::vector<int64_t> coefs;
2730  DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2731  cst = CapSub(cst, constant);
2732 
2733  const int size = vars.size();
2734  if (size == 0 || AreAllNull(coefs)) {
2735  return cst == 0 ? solver->MakeTrueConstraint()
2736  : solver->MakeFalseConstraint();
2737  }
2738  if (AreAllBoundOrNull(vars, coefs)) {
2739  int64_t sum = 0;
2740  for (int i = 0; i < size; ++i) {
2741  sum = CapAdd(sum, CapProd(coefs[i], vars[i]->Min()));
2742  }
2743  return sum == cst ? solver->MakeTrueConstraint()
2744  : solver->MakeFalseConstraint();
2745  }
2746  if (AreAllOnes(coefs)) {
2747  return solver->MakeSumEquality(vars, cst);
2748  }
2749  if (AreAllBooleans(vars) && size > 2) {
2750  if (AreAllPositive(coefs)) {
2751  return solver->RevAlloc(
2752  new PositiveBooleanScalProdEqCst(solver, vars, coefs, cst));
2753  }
2754  if (AreAllNegative(coefs)) {
2755  std::vector<int64_t> opp_coefs(coefs.size());
2756  for (int i = 0; i < coefs.size(); ++i) {
2757  opp_coefs[i] = -coefs[i];
2758  }
2759  return solver->RevAlloc(
2760  new PositiveBooleanScalProdEqCst(solver, vars, opp_coefs, -cst));
2761  }
2762  }
2763 
2764  // Simplications.
2765  int constants = 0;
2766  int positives = 0;
2767  int negatives = 0;
2768  for (int i = 0; i < size; ++i) {
2769  if (coefs[i] == 0 || vars[i]->Bound()) {
2770  constants++;
2771  } else if (coefs[i] > 0) {
2772  positives++;
2773  } else {
2774  negatives++;
2775  }
2776  }
2777  if (positives > 0 && negatives > 0) {
2778  std::vector<IntVar*> pos_terms;
2779  std::vector<IntVar*> neg_terms;
2780  int64_t rhs = cst;
2781  for (int i = 0; i < size; ++i) {
2782  if (coefs[i] == 0 || vars[i]->Bound()) {
2783  rhs = CapSub(rhs, CapProd(coefs[i], vars[i]->Min()));
2784  } else if (coefs[i] > 0) {
2785  pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2786  } else {
2787  neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2788  }
2789  }
2790  if (negatives == 1) {
2791  if (rhs != 0) {
2792  pos_terms.push_back(solver->MakeIntConst(-rhs));
2793  }
2794  return solver->MakeSumEquality(pos_terms, neg_terms[0]);
2795  } else if (positives == 1) {
2796  if (rhs != 0) {
2797  neg_terms.push_back(solver->MakeIntConst(rhs));
2798  }
2799  return solver->MakeSumEquality(neg_terms, pos_terms[0]);
2800  } else {
2801  if (rhs != 0) {
2802  neg_terms.push_back(solver->MakeIntConst(rhs));
2803  }
2804  return solver->MakeEquality(solver->MakeSum(pos_terms),
2805  solver->MakeSum(neg_terms));
2806  }
2807  } else if (positives == 1) {
2808  IntExpr* pos_term = nullptr;
2809  int64_t rhs = cst;
2810  for (int i = 0; i < size; ++i) {
2811  if (coefs[i] == 0 || vars[i]->Bound()) {
2812  rhs = CapSub(rhs, CapProd(coefs[i], vars[i]->Min()));
2813  } else if (coefs[i] > 0) {
2814  pos_term = solver->MakeProd(vars[i], coefs[i]);
2815  } else {
2816  LOG(FATAL) << "Should not be here";
2817  }
2818  }
2819  return solver->MakeEquality(pos_term, rhs);
2820  } else if (negatives == 1) {
2821  IntExpr* neg_term = nullptr;
2822  int64_t rhs = cst;
2823  for (int i = 0; i < size; ++i) {
2824  if (coefs[i] == 0 || vars[i]->Bound()) {
2825  rhs = CapSub(rhs, CapProd(coefs[i], vars[i]->Min()));
2826  } else if (coefs[i] > 0) {
2827  LOG(FATAL) << "Should not be here";
2828  } else {
2829  neg_term = solver->MakeProd(vars[i], -coefs[i]);
2830  }
2831  }
2832  return solver->MakeEquality(neg_term, -rhs);
2833  } else if (positives > 1) {
2834  std::vector<IntVar*> pos_terms;
2835  int64_t rhs = cst;
2836  for (int i = 0; i < size; ++i) {
2837  if (coefs[i] == 0 || vars[i]->Bound()) {
2838  rhs = CapSub(rhs, CapProd(coefs[i], vars[i]->Min()));
2839  } else if (coefs[i] > 0) {
2840  pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2841  } else {
2842  LOG(FATAL) << "Should not be here";
2843  }
2844  }
2845  return solver->MakeSumEquality(pos_terms, rhs);
2846  } else if (negatives > 1) {
2847  std::vector<IntVar*> neg_terms;
2848  int64_t rhs = cst;
2849  for (int i = 0; i < size; ++i) {
2850  if (coefs[i] == 0 || vars[i]->Bound()) {
2851  rhs = CapSub(rhs, CapProd(coefs[i], vars[i]->Min()));
2852  } else if (coefs[i] > 0) {
2853  LOG(FATAL) << "Should not be here";
2854  } else {
2855  neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2856  }
2857  }
2858  return solver->MakeSumEquality(neg_terms, -rhs);
2859  }
2860  std::vector<IntVar*> terms;
2861  for (int i = 0; i < size; ++i) {
2862  terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2863  }
2864  return solver->MakeSumEquality(terms, solver->MakeIntConst(cst));
2865 }
2866 
2867 Constraint* MakeScalProdEqualityVarFct(Solver* const solver,
2868  const std::vector<IntVar*>& pre_vars,
2869  const std::vector<int64_t>& pre_coefs,
2870  IntVar* const target) {
2871  int64_t constant = 0;
2872  std::vector<IntVar*> vars;
2873  std::vector<int64_t> coefs;
2874  DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2875 
2876  const int size = vars.size();
2877  if (size == 0 || AreAllNull<int64_t>(coefs)) {
2878  return solver->MakeEquality(target, constant);
2879  }
2880  if (AreAllOnes(coefs)) {
2881  return solver->MakeSumEquality(vars,
2882  solver->MakeSum(target, -constant)->Var());
2883  }
2884  if (AreAllBooleans(vars) && AreAllPositive<int64_t>(coefs)) {
2885  // TODO(user) : bench BooleanScalProdEqVar with IntConst.
2886  return solver->RevAlloc(new PositiveBooleanScalProdEqVar(
2887  solver, vars, coefs, solver->MakeSum(target, -constant)->Var()));
2888  }
2889  std::vector<IntVar*> terms;
2890  for (int i = 0; i < size; ++i) {
2891  terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2892  }
2893  return solver->MakeSumEquality(terms,
2894  solver->MakeSum(target, -constant)->Var());
2895 }
2896 
2897 Constraint* MakeScalProdGreaterOrEqualFct(Solver* solver,
2898  const std::vector<IntVar*>& pre_vars,
2899  const std::vector<int64_t>& pre_coefs,
2900  int64_t cst) {
2901  int64_t constant = 0;
2902  std::vector<IntVar*> vars;
2903  std::vector<int64_t> coefs;
2904  DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2905  cst = CapSub(cst, constant);
2906 
2907  const int size = vars.size();
2908  if (size == 0 || AreAllNull<int64_t>(coefs)) {
2909  return cst <= 0 ? solver->MakeTrueConstraint()
2910  : solver->MakeFalseConstraint();
2911  }
2912  if (AreAllOnes(coefs)) {
2913  return solver->MakeSumGreaterOrEqual(vars, cst);
2914  }
2915  if (cst == 1 && AreAllBooleans(vars) && AreAllPositive(coefs)) {
2916  // can move all coefs to 1.
2917  std::vector<IntVar*> terms;
2918  for (int i = 0; i < size; ++i) {
2919  if (coefs[i] > 0) {
2920  terms.push_back(vars[i]);
2921  }
2922  }
2923  return solver->MakeSumGreaterOrEqual(terms, 1);
2924  }
2925  std::vector<IntVar*> terms;
2926  for (int i = 0; i < size; ++i) {
2927  terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2928  }
2929  return solver->MakeSumGreaterOrEqual(terms, cst);
2930 }
2931 
2932 Constraint* MakeScalProdLessOrEqualFct(Solver* solver,
2933  const std::vector<IntVar*>& pre_vars,
2934  const std::vector<int64_t>& pre_coefs,
2935  int64_t upper_bound) {
2936  int64_t constant = 0;
2937  std::vector<IntVar*> vars;
2938  std::vector<int64_t> coefs;
2939  DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2940  upper_bound = CapSub(upper_bound, constant);
2941 
2942  const int size = vars.size();
2943  if (size == 0 || AreAllNull<int64_t>(coefs)) {
2944  return upper_bound >= 0 ? solver->MakeTrueConstraint()
2945  : solver->MakeFalseConstraint();
2946  }
2947  // TODO(user) : compute constant on the fly.
2948  if (AreAllBoundOrNull(vars, coefs)) {
2949  int64_t cst = 0;
2950  for (int i = 0; i < size; ++i) {
2951  cst = CapAdd(cst, CapProd(vars[i]->Min(), coefs[i]));
2952  }
2953  return cst <= upper_bound ? solver->MakeTrueConstraint()
2954  : solver->MakeFalseConstraint();
2955  }
2956  if (AreAllOnes(coefs)) {
2957  return solver->MakeSumLessOrEqual(vars, upper_bound);
2958  }
2959  if (AreAllBooleans(vars) && AreAllPositive<int64_t>(coefs)) {
2960  return solver->RevAlloc(
2961  new BooleanScalProdLessConstant(solver, vars, coefs, upper_bound));
2962  }
2963  // Some simplications
2964  int constants = 0;
2965  int positives = 0;
2966  int negatives = 0;
2967  for (int i = 0; i < size; ++i) {
2968  if (coefs[i] == 0 || vars[i]->Bound()) {
2969  constants++;
2970  } else if (coefs[i] > 0) {
2971  positives++;
2972  } else {
2973  negatives++;
2974  }
2975  }
2976  if (positives > 0 && negatives > 0) {
2977  std::vector<IntVar*> pos_terms;
2978  std::vector<IntVar*> neg_terms;
2979  int64_t rhs = upper_bound;
2980  for (int i = 0; i < size; ++i) {
2981  if (coefs[i] == 0 || vars[i]->Bound()) {
2982  rhs = CapSub(rhs, CapProd(coefs[i], vars[i]->Min()));
2983  } else if (coefs[i] > 0) {
2984  pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2985  } else {
2986  neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2987  }
2988  }
2989  if (negatives == 1) {
2990  IntExpr* const neg_term = solver->MakeSum(neg_terms[0], rhs);
2991  return solver->MakeLessOrEqual(solver->MakeSum(pos_terms), neg_term);
2992  } else if (positives == 1) {
2993  IntExpr* const pos_term = solver->MakeSum(pos_terms[0], -rhs);
2994  return solver->MakeGreaterOrEqual(solver->MakeSum(neg_terms), pos_term);
2995  } else {
2996  if (rhs != 0) {
2997  neg_terms.push_back(solver->MakeIntConst(rhs));
2998  }
2999  return solver->MakeLessOrEqual(solver->MakeSum(pos_terms),
3000  solver->MakeSum(neg_terms));
3001  }
3002  } else if (positives == 1) {
3003  IntExpr* pos_term = nullptr;
3004  int64_t rhs = upper_bound;
3005  for (int i = 0; i < size; ++i) {
3006  if (coefs[i] == 0 || vars[i]->Bound()) {
3007  rhs = CapSub(rhs, CapProd(coefs[i], vars[i]->Min()));
3008  } else if (coefs[i] > 0) {
3009  pos_term = solver->MakeProd(vars[i], coefs[i]);
3010  } else {
3011  LOG(FATAL) << "Should not be here";
3012  }
3013  }
3014  return solver->MakeLessOrEqual(pos_term, rhs);
3015  } else if (negatives == 1) {
3016  IntExpr* neg_term = nullptr;
3017  int64_t rhs = upper_bound;
3018  for (int i = 0; i < size; ++i) {
3019  if (coefs[i] == 0 || vars[i]->Bound()) {
3020  rhs = CapSub(rhs, CapProd(coefs[i], vars[i]->Min()));
3021  } else if (coefs[i] > 0) {
3022  LOG(FATAL) << "Should not be here";
3023  } else {
3024  neg_term = solver->MakeProd(vars[i], -coefs[i]);
3025  }
3026  }
3027  return solver->MakeGreaterOrEqual(neg_term, -rhs);
3028  } else if (positives > 1) {
3029  std::vector<IntVar*> pos_terms;
3030  int64_t rhs = upper_bound;
3031  for (int i = 0; i < size; ++i) {
3032  if (coefs[i] == 0 || vars[i]->Bound()) {
3033  rhs = CapSub(rhs, CapProd(coefs[i], vars[i]->Min()));
3034  } else if (coefs[i] > 0) {
3035  pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3036  } else {
3037  LOG(FATAL) << "Should not be here";
3038  }
3039  }
3040  return solver->MakeSumLessOrEqual(pos_terms, rhs);
3041  } else if (negatives > 1) {
3042  std::vector<IntVar*> neg_terms;
3043  int64_t rhs = upper_bound;
3044  for (int i = 0; i < size; ++i) {
3045  if (coefs[i] == 0 || vars[i]->Bound()) {
3046  rhs = CapSub(rhs, CapProd(coefs[i], vars[i]->Min()));
3047  } else if (coefs[i] > 0) {
3048  LOG(FATAL) << "Should not be here";
3049  } else {
3050  neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
3051  }
3052  }
3053  return solver->MakeSumGreaterOrEqual(neg_terms, -rhs);
3054  }
3055  std::vector<IntVar*> terms;
3056  for (int i = 0; i < size; ++i) {
3057  terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3058  }
3059  return solver->MakeLessOrEqual(solver->MakeSum(terms), upper_bound);
3060 }
3061 
3062 IntExpr* MakeSumArrayAux(Solver* const solver, const std::vector<IntVar*>& vars,
3063  int64_t constant) {
3064  const int size = vars.size();
3065  DCHECK_GT(size, 2);
3066  int64_t new_min = 0;
3067  int64_t new_max = 0;
3068  for (int i = 0; i < size; ++i) {
3069  if (new_min != std::numeric_limits<int64_t>::min()) {
3070  new_min = CapAdd(vars[i]->Min(), new_min);
3071  }
3072  if (new_max != std::numeric_limits<int64_t>::max()) {
3073  new_max = CapAdd(vars[i]->Max(), new_max);
3074  }
3075  }
3076  IntExpr* const cache =
3077  solver->Cache()->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_SUM);
3078  if (cache != nullptr) {
3079  return solver->MakeSum(cache, constant);
3080  } else {
3081  const std::string name =
3082  absl::StrFormat("Sum([%s])", JoinNamePtr(vars, ", "));
3083  IntVar* const sum_var = solver->MakeIntVar(new_min, new_max, name);
3084  if (AreAllBooleans(vars)) {
3085  solver->AddConstraint(
3086  solver->RevAlloc(new SumBooleanEqualToVar(solver, vars, sum_var)));
3087  } else if (size <= solver->parameters().array_split_size()) {
3088  solver->AddConstraint(
3089  solver->RevAlloc(new SmallSumConstraint(solver, vars, sum_var)));
3090  } else {
3091  solver->AddConstraint(
3092  solver->RevAlloc(new SumConstraint(solver, vars, sum_var)));
3093  }
3094  solver->Cache()->InsertVarArrayExpression(sum_var, vars,
3095  ModelCache::VAR_ARRAY_SUM);
3096  return solver->MakeSum(sum_var, constant);
3097  }
3098 }
3099 
3100 IntExpr* MakeSumAux(Solver* const solver, const std::vector<IntVar*>& vars,
3101  int64_t constant) {
3102  const int size = vars.size();
3103  if (size == 0) {
3104  return solver->MakeIntConst(constant);
3105  } else if (size == 1) {
3106  return solver->MakeSum(vars[0], constant);
3107  } else if (size == 2) {
3108  return solver->MakeSum(solver->MakeSum(vars[0], vars[1]), constant);
3109  } else {
3110  return MakeSumArrayAux(solver, vars, constant);
3111  }
3112 }
3113 
3114 IntExpr* MakeScalProdAux(Solver* solver, const std::vector<IntVar*>& vars,
3115  const std::vector<int64_t>& coefs, int64_t constant) {
3116  if (AreAllOnes(coefs)) {
3117  return MakeSumAux(solver, vars, constant);
3118  }
3119 
3120  const int size = vars.size();
3121  if (size == 0) {
3122  return solver->MakeIntConst(constant);
3123  } else if (size == 1) {
3124  return solver->MakeSum(solver->MakeProd(vars[0], coefs[0]), constant);
3125  } else if (size == 2) {
3126  if (coefs[0] > 0 && coefs[1] < 0) {
3127  return solver->MakeSum(
3128  solver->MakeDifference(solver->MakeProd(vars[0], coefs[0]),
3129  solver->MakeProd(vars[1], -coefs[1])),
3130  constant);
3131  } else if (coefs[0] < 0 && coefs[1] > 0) {
3132  return solver->MakeSum(
3133  solver->MakeDifference(solver->MakeProd(vars[1], coefs[1]),
3134  solver->MakeProd(vars[0], -coefs[0])),
3135  constant);
3136  } else {
3137  return solver->MakeSum(
3138  solver->MakeSum(solver->MakeProd(vars[0], coefs[0]),
3139  solver->MakeProd(vars[1], coefs[1])),
3140  constant);
3141  }
3142  } else {
3143  if (AreAllBooleans(vars)) {
3144  if (AreAllPositive(coefs)) {
3145  if (vars.size() > 8) {
3146  return solver->MakeSum(
3147  solver
3148  ->RegisterIntExpr(solver->RevAlloc(
3149  new PositiveBooleanScalProd(solver, vars, coefs)))
3150  ->Var(),
3151  constant);
3152  } else {
3153  return solver->MakeSum(
3154  solver->RegisterIntExpr(solver->RevAlloc(
3155  new PositiveBooleanScalProd(solver, vars, coefs))),
3156  constant);
3157  }
3158  } else {
3159  // If some coefficients are non-positive, partition coefficients in two
3160  // sets, one for the positive coefficients P and one for the negative
3161  // ones N.
3162  // Create two PositiveBooleanScalProd expressions, one on P (s1), the
3163  // other on Opposite(N) (s2).
3164  // The final expression is then s1 - s2.
3165  // If P is empty, the expression is Opposite(s2).
3166  std::vector<int64_t> positive_coefs;
3167  std::vector<int64_t> negative_coefs;
3168  std::vector<IntVar*> positive_coef_vars;
3169  std::vector<IntVar*> negative_coef_vars;
3170  for (int i = 0; i < size; ++i) {
3171  const int coef = coefs[i];
3172  if (coef > 0) {
3173  positive_coefs.push_back(coef);
3174  positive_coef_vars.push_back(vars[i]);
3175  } else if (coef < 0) {
3176  negative_coefs.push_back(-coef);
3177  negative_coef_vars.push_back(vars[i]);
3178  }
3179  }
3180  CHECK_GT(negative_coef_vars.size(), 0);
3181  IntExpr* const negatives =
3182  MakeScalProdAux(solver, negative_coef_vars, negative_coefs, 0);
3183  if (!positive_coef_vars.empty()) {
3184  IntExpr* const positives = MakeScalProdAux(solver, positive_coef_vars,
3185  positive_coefs, constant);
3186  return solver->MakeDifference(positives, negatives);
3187  } else {
3188  return solver->MakeDifference(constant, negatives);
3189  }
3190  }
3191  }
3192  }
3193  std::vector<IntVar*> terms;
3194  for (int i = 0; i < size; ++i) {
3195  terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3196  }
3197  return MakeSumArrayAux(solver, terms, constant);
3198 }
3199 
3200 IntExpr* MakeScalProdFct(Solver* solver, const std::vector<IntVar*>& pre_vars,
3201  const std::vector<int64_t>& pre_coefs) {
3202  int64_t constant = 0;
3203  std::vector<IntVar*> vars;
3204  std::vector<int64_t> coefs;
3205  DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
3206 
3207  if (vars.empty()) {
3208  return solver->MakeIntConst(constant);
3209  }
3210  // Can we simplify using some gcd computation.
3211  int64_t gcd = std::abs(coefs[0]);
3212  for (int i = 1; i < coefs.size(); ++i) {
3213  gcd = MathUtil::GCD64(gcd, std::abs(coefs[i]));
3214  if (gcd == 1) {
3215  break;
3216  }
3217  }
3218  if (constant != 0 && gcd != 1) {
3219  gcd = MathUtil::GCD64(gcd, std::abs(constant));
3220  }
3221  if (gcd > 1) {
3222  for (int i = 0; i < coefs.size(); ++i) {
3223  coefs[i] /= gcd;
3224  }
3225  return solver->MakeProd(
3226  MakeScalProdAux(solver, vars, coefs, constant / gcd), gcd);
3227  }
3228  return MakeScalProdAux(solver, vars, coefs, constant);
3229 }
3230 
3231 IntExpr* MakeSumFct(Solver* solver, const std::vector<IntVar*>& pre_vars) {
3232  absl::flat_hash_map<IntVar*, int64_t> variables_to_coefficients;
3233  ExprLinearizer linearizer(&variables_to_coefficients);
3234  for (int i = 0; i < pre_vars.size(); ++i) {
3235  linearizer.Visit(pre_vars[i], 1);
3236  }
3237  const int64_t constant = linearizer.Constant();
3238  std::vector<IntVar*> vars;
3239  std::vector<int64_t> coefs;
3240  for (const auto& variable_to_coefficient : variables_to_coefficients) {
3241  if (variable_to_coefficient.second != 0) {
3242  vars.push_back(variable_to_coefficient.first);
3243  coefs.push_back(variable_to_coefficient.second);
3244  }
3245  }
3246  return MakeScalProdAux(solver, vars, coefs, constant);
3247 }
3248 } // namespace
3249 
3250 // ----- API -----
3251 
3252 IntExpr* Solver::MakeSum(const std::vector<IntVar*>& vars) {
3253  const int size = vars.size();
3254  if (size == 0) {
3255  return MakeIntConst(int64_t{0});
3256  } else if (size == 1) {
3257  return vars[0];
3258  } else if (size == 2) {
3259  return MakeSum(vars[0], vars[1]);
3260  } else {
3261  IntExpr* const cache =
3262  model_cache_->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_SUM);
3263  if (cache != nullptr) {
3264  return cache;
3265  } else {
3266  int64_t new_min = 0;
3267  int64_t new_max = 0;
3268  for (int i = 0; i < size; ++i) {
3269  if (new_min != std::numeric_limits<int64_t>::min()) {
3270  new_min = CapAdd(vars[i]->Min(), new_min);
3271  }
3272  if (new_max != std::numeric_limits<int64_t>::max()) {
3273  new_max = CapAdd(vars[i]->Max(), new_max);
3274  }
3275  }
3276  IntExpr* sum_expr = nullptr;
3277  const bool all_booleans = AreAllBooleans(vars);
3278  if (all_booleans) {
3279  const std::string name =
3280  absl::StrFormat("BooleanSum([%s])", JoinNamePtr(vars, ", "));
3281  sum_expr = MakeIntVar(new_min, new_max, name);
3282  AddConstraint(
3283  RevAlloc(new SumBooleanEqualToVar(this, vars, sum_expr->Var())));
3284  } else if (new_min != std::numeric_limits<int64_t>::min() &&
3285  new_max != std::numeric_limits<int64_t>::max()) {
3286  sum_expr = MakeSumFct(this, vars);
3287  } else {
3288  const std::string name =
3289  absl::StrFormat("Sum([%s])", JoinNamePtr(vars, ", "));
3290  sum_expr = MakeIntVar(new_min, new_max, name);
3291  AddConstraint(
3292  RevAlloc(new SafeSumConstraint(this, vars, sum_expr->Var())));
3293  }
3294  model_cache_->InsertVarArrayExpression(sum_expr, vars,
3295  ModelCache::VAR_ARRAY_SUM);
3296  return sum_expr;
3297  }
3298  }
3299 }
3300 
3301 IntExpr* Solver::MakeMin(const std::vector<IntVar*>& vars) {
3302  const int size = vars.size();
3303  if (size == 0) {
3304  LOG(WARNING) << "operations_research::Solver::MakeMin() was called with an "
3305  "empty list of variables. Was this intentional?";
3306  return MakeIntConst(std::numeric_limits<int64_t>::max());
3307  } else if (size == 1) {
3308  return vars[0];
3309  } else if (size == 2) {
3310  return MakeMin(vars[0], vars[1]);
3311  } else {
3312  IntExpr* const cache =
3313  model_cache_->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_MIN);
3314  if (cache != nullptr) {
3315  return cache;
3316  } else {
3317  if (AreAllBooleans(vars)) {
3318  IntVar* const new_var = MakeBoolVar();
3319  AddConstraint(RevAlloc(new ArrayBoolAndEq(this, vars, new_var)));
3320  model_cache_->InsertVarArrayExpression(new_var, vars,
3321  ModelCache::VAR_ARRAY_MIN);
3322  return new_var;
3323  } else {
3324  int64_t new_min = std::numeric_limits<int64_t>::max();
3325  int64_t new_max = std::numeric_limits<int64_t>::max();
3326  for (int i = 0; i < size; ++i) {
3327  new_min = std::min(new_min, vars[i]->Min());
3328  new_max = std::min(new_max, vars[i]->Max());
3329  }
3330  IntVar* const new_var = MakeIntVar(new_min, new_max);
3331  if (size <= parameters_.array_split_size()) {
3332  AddConstraint(RevAlloc(new SmallMinConstraint(this, vars, new_var)));
3333  } else {
3334  AddConstraint(RevAlloc(new MinConstraint(this, vars, new_var)));
3335  }
3336  model_cache_->InsertVarArrayExpression(new_var, vars,
3337  ModelCache::VAR_ARRAY_MIN);
3338  return new_var;
3339  }
3340  }
3341  }
3342 }
3343 
3344 IntExpr* Solver::MakeMax(const std::vector<IntVar*>& vars) {
3345  const int size = vars.size();
3346  if (size == 0) {
3347  LOG(WARNING) << "operations_research::Solver::MakeMax() was called with an "
3348  "empty list of variables. Was this intentional?";
3349  return MakeIntConst(std::numeric_limits<int64_t>::min());
3350  } else if (size == 1) {
3351  return vars[0];
3352  } else if (size == 2) {
3353  return MakeMax(vars[0], vars[1]);
3354  } else {
3355  IntExpr* const cache =
3356  model_cache_->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_MAX);
3357  if (cache != nullptr) {
3358  return cache;
3359  } else {
3360  if (AreAllBooleans(vars)) {
3361  IntVar* const new_var = MakeBoolVar();
3362  AddConstraint(RevAlloc(new ArrayBoolOrEq(this, vars, new_var)));
3363  model_cache_->InsertVarArrayExpression(new_var, vars,
3364  ModelCache::VAR_ARRAY_MIN);
3365  return new_var;
3366  } else {
3367  int64_t new_min = std::numeric_limits<int64_t>::min();
3368  int64_t new_max = std::numeric_limits<int64_t>::min();
3369  for (int i = 0; i < size; ++i) {
3370  new_min = std::max(new_min, vars[i]->Min());
3371  new_max = std::max(new_max, vars[i]->Max());
3372  }
3373  IntVar* const new_var = MakeIntVar(new_min, new_max);
3374  if (size <= parameters_.array_split_size()) {
3375  AddConstraint(RevAlloc(new SmallMaxConstraint(this, vars, new_var)));
3376  } else {
3377  AddConstraint(RevAlloc(new MaxConstraint(this, vars, new_var)));
3378  }
3379  model_cache_->InsertVarArrayExpression(new_var, vars,
3380  ModelCache::VAR_ARRAY_MAX);
3381  return new_var;
3382  }
3383  }
3384  }
3385 }
3386 
3387 Constraint* Solver::MakeMinEquality(const std::vector<IntVar*>& vars,
3388  IntVar* const min_var) {
3389  const int size = vars.size();
3390  if (size > 2) {
3391  if (AreAllBooleans(vars)) {
3392  return RevAlloc(new ArrayBoolAndEq(this, vars, min_var));
3393  } else if (size <= parameters_.array_split_size()) {
3394  return RevAlloc(new SmallMinConstraint(this, vars, min_var));
3395  } else {
3396  return RevAlloc(new MinConstraint(this, vars, min_var));
3397  }
3398  } else if (size == 2) {
3399  return MakeEquality(MakeMin(vars[0], vars[1]), min_var);
3400  } else if (size == 1) {
3401  return MakeEquality(vars[0], min_var);
3402  } else {
3403  LOG(WARNING) << "operations_research::Solver::MakeMinEquality() was called "
3404  "with an empty list of variables. Was this intentional?";
3405  return MakeEquality(min_var, std::numeric_limits<int64_t>::max());
3406  }
3407 }
3408 
3409 Constraint* Solver::MakeMaxEquality(const std::vector<IntVar*>& vars,
3410  IntVar* const max_var) {
3411  const int size = vars.size();
3412  if (size > 2) {
3413  if (AreAllBooleans(vars)) {
3414  return RevAlloc(new ArrayBoolOrEq(this, vars, max_var));
3415  } else if (size <= parameters_.array_split_size()) {
3416  return RevAlloc(new SmallMaxConstraint(this, vars, max_var));
3417  } else {
3418  return RevAlloc(new MaxConstraint(this, vars, max_var));
3419  }
3420  } else if (size == 2) {
3421  return MakeEquality(MakeMax(vars[0], vars[1]), max_var);
3422  } else if (size == 1) {
3423  return MakeEquality(vars[0], max_var);
3424  } else {
3425  LOG(WARNING) << "operations_research::Solver::MakeMaxEquality() was called "
3426  "with an empty list of variables. Was this intentional?";
3427  return MakeEquality(max_var, std::numeric_limits<int64_t>::min());
3428  }
3429 }
3430 
3431 Constraint* Solver::MakeSumLessOrEqual(const std::vector<IntVar*>& vars,
3432  int64_t cst) {
3433  const int size = vars.size();
3434  if (cst == 1LL && AreAllBooleans(vars) && size > 2) {
3435  return RevAlloc(new SumBooleanLessOrEqualToOne(this, vars));
3436  } else {
3437  return MakeLessOrEqual(MakeSum(vars), cst);
3438  }
3439 }
3440 
3441 Constraint* Solver::MakeSumGreaterOrEqual(const std::vector<IntVar*>& vars,
3442  int64_t cst) {
3443  const int size = vars.size();
3444  if (cst == 1LL && AreAllBooleans(vars) && size > 2) {
3445  return RevAlloc(new SumBooleanGreaterOrEqualToOne(this, vars));
3446  } else {
3447  return MakeGreaterOrEqual(MakeSum(vars), cst);
3448  }
3449 }
3450 
3451 Constraint* Solver::MakeSumEquality(const std::vector<IntVar*>& vars,
3452  int64_t cst) {
3453  const int size = vars.size();
3454  if (size == 0) {
3455  return cst == 0 ? MakeTrueConstraint() : MakeFalseConstraint();
3456  }
3457  if (AreAllBooleans(vars) && size > 2) {
3458  if (cst == 1) {
3459  return RevAlloc(new SumBooleanEqualToOne(this, vars));
3460  } else if (cst < 0 || cst > size) {
3461  return MakeFalseConstraint();
3462  } else {
3463  return RevAlloc(new SumBooleanEqualToVar(this, vars, MakeIntConst(cst)));
3464  }
3465  } else {
3466  if (vars.size() == 1) {
3467  return MakeEquality(vars[0], cst);
3468  } else if (vars.size() == 2) {
3469  return MakeEquality(vars[0], MakeDifference(cst, vars[1]));
3470  }
3471  if (DetectSumOverflow(vars)) {
3472  return RevAlloc(new SafeSumConstraint(this, vars, MakeIntConst(cst)));
3473  } else if (size <= parameters_.array_split_size()) {
3474  return RevAlloc(new SmallSumConstraint(this, vars, MakeIntConst(cst)));
3475  } else {
3476  return RevAlloc(new SumConstraint(this, vars, MakeIntConst(cst)));
3477  }
3478  }
3479 }
3480 
3481 Constraint* Solver::MakeSumEquality(const std::vector<IntVar*>& vars,
3482  IntVar* const var) {
3483  const int size = vars.size();
3484  if (size == 0) {
3485  return MakeEquality(var, Zero());
3486  }
3487  if (AreAllBooleans(vars) && size > 2) {
3488  return RevAlloc(new SumBooleanEqualToVar(this, vars, var));
3489  } else if (size == 0) {
3490  return MakeEquality(var, Zero());
3491  } else if (size == 1) {
3492  return MakeEquality(vars[0], var);
3493  } else if (size == 2) {
3494  return MakeEquality(MakeSum(vars[0], vars[1]), var);
3495  } else {
3496  if (DetectSumOverflow(vars)) {
3497  return RevAlloc(new SafeSumConstraint(this, vars, var));
3498  } else if (size <= parameters_.array_split_size()) {
3499  return RevAlloc(new SmallSumConstraint(this, vars, var));
3500  } else {
3501  return RevAlloc(new SumConstraint(this, vars, var));
3502  }
3503  }
3504 }
3505 
3506 Constraint* Solver::MakeScalProdEquality(
3507  const std::vector<IntVar*>& vars, const std::vector<int64_t>& coefficients,
3508  int64_t cst) {
3509  DCHECK_EQ(vars.size(), coefficients.size());
3510  return MakeScalProdEqualityFct(this, vars, coefficients, cst);
3511 }
3512 
3513 Constraint* Solver::MakeScalProdEquality(const std::vector<IntVar*>& vars,
3514  const std::vector<int>& coefficients,
3515  int64_t cst) {
3516  DCHECK_EQ(vars.size(), coefficients.size());
3517  return MakeScalProdEqualityFct(this, vars, ToInt64Vector(coefficients), cst);
3518 }
3519 
3520 Constraint* Solver::MakeScalProdEquality(
3521  const std::vector<IntVar*>& vars, const std::vector<int64_t>& coefficients,
3522  IntVar* const target) {
3523  DCHECK_EQ(vars.size(), coefficients.size());
3524  return MakeScalProdEqualityVarFct(this, vars, coefficients, target);
3525 }
3526 
3527 Constraint* Solver::MakeScalProdEquality(const std::vector<IntVar*>& vars,
3528  const std::vector<int>& coefficients,
3529  IntVar* const target) {
3530  DCHECK_EQ(vars.size(), coefficients.size());
3531  return MakeScalProdEqualityVarFct(this, vars, ToInt64Vector(coefficients),
3532  target);
3533 }
3534 
3535 Constraint* Solver::MakeScalProdGreaterOrEqual(
3536  const std::vector<IntVar*>& vars, const std::vector<int64_t>& coeffs,
3537  int64_t cst) {
3538  DCHECK_EQ(vars.size(), coeffs.size());
3539  return MakeScalProdGreaterOrEqualFct(this, vars, coeffs, cst);
3540 }
3541 
3542 Constraint* Solver::MakeScalProdGreaterOrEqual(const std::vector<IntVar*>& vars,
3543  const std::vector<int>& coeffs,
3544  int64_t cst) {
3545  DCHECK_EQ(vars.size(), coeffs.size());
3546  return MakeScalProdGreaterOrEqualFct(this, vars, ToInt64Vector(coeffs), cst);
3547 }
3548 
3549 Constraint* Solver::MakeScalProdLessOrEqual(
3550  const std::vector<IntVar*>& vars, const std::vector<int64_t>& coefficients,
3551  int64_t cst) {
3552  DCHECK_EQ(vars.size(), coefficients.size());
3553  return MakeScalProdLessOrEqualFct(this, vars, coefficients, cst);
3554 }
3555 
3556 Constraint* Solver::MakeScalProdLessOrEqual(
3557  const std::vector<IntVar*>& vars, const std::vector<int>& coefficients,
3558  int64_t cst) {
3559  DCHECK_EQ(vars.size(), coefficients.size());
3560  return MakeScalProdLessOrEqualFct(this, vars, ToInt64Vector(coefficients),
3561  cst);
3562 }
3563 
3564 IntExpr* Solver::MakeScalProd(const std::vector<IntVar*>& vars,
3565  const std::vector<int64_t>& coefs) {
3566  DCHECK_EQ(vars.size(), coefs.size());
3567  return MakeScalProdFct(this, vars, coefs);
3568 }
3569 
3570 IntExpr* Solver::MakeScalProd(const std::vector<IntVar*>& vars,
3571  const std::vector<int>& coefs) {
3572  DCHECK_EQ(vars.size(), coefs.size());
3573  return MakeScalProdFct(this, vars, ToInt64Vector(coefs));
3574 }
3575 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK(condition)
Definition: base/logging.h:498
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:894
#define CHECK_LT(val1, val2)
Definition: base/logging.h:708
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:705
#define CHECK_GT(val1, val2)
Definition: base/logging.h:710
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:897
#define CHECK_NE(val1, val2)
Definition: base/logging.h:706
#define DCHECK_GT(val1, val2)
Definition: base/logging.h:898
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:896
#define LOG(severity)
Definition: base/logging.h:423
#define DCHECK(condition)
Definition: base/logging.h:892
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:893
A constraint is the main modeling object.
The class IntExpr is the base of all integer expressions in constraint programming.
virtual IntVar * Var()=0
Creates a variable from the expression.
The class IntVar is a subset of IntExpr.
void SetValue(Solver *const s, const T &val)
SatParameters parameters
const std::string name
const Constraint * ct
int64_t value
const std::vector< IntVar * > vars_
Definition: expr_array.cc:138
IntVar * var
Definition: expr_array.cc:1874
Rev< int64_t > node_max
Definition: expr_array.cc:144
#define IS_TYPE(type, tag)
Definition: expr_array.cc:2402
int64_t coef
Definition: expr_array.cc:1875
RevSwitch inactive_
Definition: expr_array.cc:1487
Rev< int64_t > node_min
Definition: expr_array.cc:143
double upper_bound
absl::Span< const double > coefficients
const int WARNING
Definition: log_severity.h:31
const int FATAL
Definition: log_severity.h:32
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
bool AreAllNegative(const std::vector< T > &values)
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
int64_t CapSub(int64_t x, int64_t y)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
bool AreAllBoundOrNull(const std::vector< IntVar * > &vars, const std::vector< T > &values)
Returns true if all the variables are assigned to a single value, or if their corresponding value is ...
int64_t Zero()
NOLINT.
bool AreAllBooleans(const std::vector< IntVar * > &vars)
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
Definition: string_array.h:45
int64_t CapProd(int64_t x, int64_t y)
bool AreAllNull(const std::vector< T > &values)
bool AreAllPositive(const std::vector< T > &values)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
Definition: utilities.cc:828
bool AreAllOnes(const std::vector< T > &values)
std::string JoinNamePtr(const std::vector< T > &v, const std::string &separator)
Definition: string_array.h:52
int index
Definition: pack.cc:509
int64_t coefficient
IntervalVar *const target_var_