24#include "absl/strings/str_format.h"
25#include "absl/strings/str_join.h"
26#include "absl/strings/string_view.h"
27#include "absl/types/span.h"
42 TreeArrayConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
43 IntVar*
const sum_var)
44 : CastConstraint(solver, sum_var),
46 block_size_(solver->parameters().array_split_size()) {
47 std::vector<int> lengths;
48 lengths.push_back(vars_.size());
49 while (lengths.back() > 1) {
50 const int current = lengths.back();
51 lengths.push_back((current + block_size_ - 1) / block_size_);
53 tree_.resize(lengths.size());
54 for (
int i = 0;
i < lengths.size(); ++
i) {
55 tree_[
i].resize(lengths[lengths.size() - i - 1]);
57 DCHECK_GE(tree_.size(), 1);
58 DCHECK_EQ(1, tree_[0].size());
59 root_node_ = &tree_[0][0];
62 std::string DebugStringInternal(absl::string_view name)
const {
63 return absl::StrFormat(
"%s(%s) == %s", name,
65 target_var_->DebugString());
68 void AcceptInternal(
const std::string& name,
69 ModelVisitor*
const visitor)
const {
70 visitor->BeginVisitConstraint(name,
this);
75 visitor->EndVisitConstraint(name,
this);
79 void ReduceRange(
int depth,
int position, int64_t delta_min,
81 NodeInfo*
const info = &tree_[depth][position];
83 info->node_min.SetValue(solver(),
84 CapAdd(info->node_min.Value(), delta_min));
87 info->node_max.SetValue(solver(),
88 CapSub(info->node_max.Value(), delta_max));
93 void SetRange(
int depth,
int position, int64_t new_min, int64_t new_max) {
94 NodeInfo*
const info = &tree_[depth][position];
95 if (new_min > info->node_min.Value()) {
96 info->node_min.SetValue(solver(), new_min);
98 if (new_max < info->node_max.Value()) {
99 info->node_max.SetValue(solver(), new_max);
103 void InitLeaf(
int position, int64_t var_min, int64_t var_max) {
104 InitNode(MaxDepth(), position, var_min, var_max);
107 void InitNode(
int depth,
int position, int64_t node_min, int64_t node_max) {
108 tree_[depth][position].node_min.SetValue(solver(), node_min);
109 tree_[depth][position].node_max.SetValue(solver(), node_max);
112 int64_t Min(
int depth,
int position)
const {
113 return tree_[depth][position].node_min.Value();
116 int64_t Max(
int depth,
int position)
const {
117 return tree_[depth][position].node_max.Value();
120 int64_t RootMin()
const {
return root_node_->node_min.Value(); }
122 int64_t RootMax()
const {
return root_node_->node_max.Value(); }
124 int Parent(
int position)
const {
return position / block_size_; }
126 int ChildStart(
int position)
const {
return position * block_size_; }
128 int ChildEnd(
int depth,
int position)
const {
129 DCHECK_LT(depth + 1, tree_.size());
130 return std::min((position + 1) * block_size_ - 1, Width(depth + 1) - 1);
133 bool IsLeaf(
int depth)
const {
return depth == MaxDepth(); }
135 int MaxDepth()
const {
return tree_.size() - 1; }
137 int Width(
int depth)
const {
return tree_[depth].size(); }
140 const std::vector<IntVar*> vars_;
144 NodeInfo() : node_min(0), node_max(0) {}
145 Rev<int64_t> node_min;
146 Rev<int64_t> node_max;
149 std::vector<std::vector<NodeInfo> > tree_;
150 const int block_size_;
151 NodeInfo* root_node_;
166class SumConstraint :
public TreeArrayConstraint {
168 SumConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
169 IntVar*
const sum_var)
170 : TreeArrayConstraint(solver, vars, sum_var), sum_demon_(nullptr) {}
172 ~SumConstraint()
override {}
174 void Post()
override {
175 for (
int i = 0;
i < vars_.size(); ++
i) {
177 solver(),
this, &SumConstraint::LeafChanged,
"LeafChanged", i);
178 vars_[
i]->WhenRange(demon);
181 solver(),
this, &SumConstraint::SumChanged,
"SumChanged"));
182 target_var_->WhenRange(sum_demon_);
185 void InitialPropagate()
override {
187 for (
int i = 0;
i < vars_.size(); ++
i) {
188 InitLeaf(i, vars_[i]->Min(), vars_[i]->Max());
191 for (
int i = MaxDepth() - 1;
i >= 0; --
i) {
192 for (
int j = 0; j < Width(i); ++j) {
195 const int block_start = ChildStart(j);
196 const int block_end = ChildEnd(i, j);
197 for (
int k = block_start; k <= block_end; ++k) {
198 sum_min =
CapAdd(sum_min, Min(i + 1, k));
199 sum_max =
CapAdd(sum_max, Max(i + 1, k));
201 InitNode(i, j, sum_min, sum_max);
205 target_var_->SetRange(RootMin(), RootMax());
212 if (target_var_->Max() == RootMin() &&
213 target_var_->Max() != std::numeric_limits<int64_t>::max()) {
215 for (
int i = 0;
i < vars_.size(); ++
i) {
216 vars_[
i]->SetValue(vars_[i]->Min());
218 }
else if (target_var_->Min() == RootMax() &&
219 target_var_->Min() != std::numeric_limits<int64_t>::min()) {
221 for (
int i = 0;
i < vars_.size(); ++
i) {
222 vars_[
i]->SetValue(vars_[i]->Max());
225 PushDown(0, 0, target_var_->Min(), target_var_->Max());
229 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
231 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
237 vars_[position]->SetRange(new_min, new_max);
245 const int64_t sum_min = Min(depth, position);
246 const int64_t sum_max = Max(depth, position);
249 new_max = std::min(sum_max, new_max);
250 new_min = std::max(sum_min, new_min);
253 if (new_max < sum_min || new_min > sum_max) {
258 const int block_start = ChildStart(position);
259 const int block_end = ChildEnd(depth, position);
260 for (
int i = block_start;
i <= block_end; ++
i) {
261 const int64_t target_var_min = Min(depth + 1, i);
262 const int64_t target_var_max = Max(depth + 1, i);
263 const int64_t residual_min =
CapSub(sum_min, target_var_min);
264 const int64_t residual_max =
CapSub(sum_max, target_var_max);
265 PushDown(depth + 1, i,
CapSub(new_min, residual_max),
266 CapSub(new_max, residual_min));
272 void LeafChanged(
int term_index) {
273 IntVar*
const var = vars_[term_index];
274 PushUp(term_index,
CapSub(var->Min(), var->OldMin()),
275 CapSub(var->OldMax(), var->Max()));
276 EnqueueDelayedDemon(sum_demon_);
279 void PushUp(
int position, int64_t delta_min, int64_t delta_max) {
280 DCHECK_GE(delta_max, 0);
281 DCHECK_GE(delta_min, 0);
282 DCHECK_GT(
CapAdd(delta_min, delta_max), 0);
283 for (
int depth = MaxDepth(); depth >= 0; --depth) {
284 ReduceRange(depth, position, delta_min, delta_max);
285 position = Parent(position);
287 DCHECK_EQ(0, position);
288 target_var_->SetRange(RootMin(), RootMax());
291 std::string DebugString()
const override {
292 return DebugStringInternal(
"Sum");
295 void Accept(ModelVisitor*
const visitor)
const override {
306 SmallSumConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
307 IntVar*
const target_var)
308 : Constraint(solver),
310 target_var_(target_var),
313 sum_demon_(nullptr) {}
315 ~SmallSumConstraint()
override {}
317 void Post()
override {
318 for (
int i = 0;
i < vars_.size(); ++
i) {
319 if (!vars_[i]->Bound()) {
321 solver(),
this, &SmallSumConstraint::VarChanged,
"VarChanged",
323 vars_[
i]->WhenRange(demon);
327 solver(),
this, &SmallSumConstraint::SumChanged,
"SumChanged"));
328 target_var_->WhenRange(sum_demon_);
331 void InitialPropagate()
override {
335 for (IntVar*
const var : vars_) {
336 sum_min =
CapAdd(sum_min, var->Min());
337 sum_max =
CapAdd(sum_max, var->Max());
341 computed_min_.SetValue(solver(), sum_min);
342 computed_max_.SetValue(solver(), sum_max);
343 target_var_->SetRange(sum_min, sum_max);
350 int64_t new_min = target_var_->Min();
351 int64_t new_max = target_var_->Max();
352 const int64_t sum_min = computed_min_.Value();
353 const int64_t sum_max = computed_max_.Value();
354 if (new_max == sum_min && new_max != std::numeric_limits<int64_t>::max()) {
356 for (
int i = 0;
i < vars_.size(); ++
i) {
357 vars_[
i]->SetValue(vars_[i]->Min());
359 }
else if (new_min == sum_max &&
360 new_min != std::numeric_limits<int64_t>::min()) {
362 for (
int i = 0;
i < vars_.size(); ++
i) {
363 vars_[
i]->SetValue(vars_[i]->Max());
366 if (new_min > sum_min || new_max < sum_max) {
368 new_max = std::min(sum_max, new_max);
369 new_min = std::max(sum_min, new_min);
372 if (new_max < sum_min || new_min > sum_max) {
377 for (IntVar*
const var : vars_) {
378 const int64_t var_min = var->Min();
379 const int64_t var_max = var->Max();
380 const int64_t residual_min =
CapSub(sum_min, var_min);
381 const int64_t residual_max =
CapSub(sum_max, var_max);
382 var->SetRange(
CapSub(new_min, residual_max),
383 CapSub(new_max, residual_min));
389 void VarChanged(IntVar* var) {
390 const int64_t delta_min =
CapSub(var->Min(), var->OldMin());
391 const int64_t delta_max =
CapSub(var->OldMax(), var->Max());
392 computed_min_.Add(solver(), delta_min);
393 computed_max_.Add(solver(), -delta_max);
394 if (computed_max_.Value() < target_var_->Max() ||
395 computed_min_.Value() > target_var_->Min()) {
396 target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
398 EnqueueDelayedDemon(sum_demon_);
402 std::string DebugString()
const override {
403 return absl::StrFormat(
"SmallSum(%s) == %s",
405 target_var_->DebugString());
408 void Accept(ModelVisitor*
const visitor)
const override {
418 const std::vector<IntVar*> vars_;
420 NumericalRev<int64_t> computed_min_;
421 NumericalRev<int64_t> computed_max_;
426bool DetectSumOverflow(
const std::vector<IntVar*>& vars) {
429 for (
int i = 0;
i < vars.size(); ++
i) {
430 sum_min =
CapAdd(sum_min, vars[i]->Min());
431 sum_max =
CapAdd(sum_max, vars[i]->Max());
432 if (sum_min == std::numeric_limits<int64_t>::min() ||
433 sum_max == std::numeric_limits<int64_t>::max()) {
441class SafeSumConstraint :
public TreeArrayConstraint {
443 SafeSumConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
444 IntVar*
const sum_var)
445 : TreeArrayConstraint(solver, vars, sum_var), sum_demon_(nullptr) {}
447 ~SafeSumConstraint()
override {}
449 void Post()
override {
450 for (
int i = 0;
i < vars_.size(); ++
i) {
452 solver(),
this, &SafeSumConstraint::LeafChanged,
"LeafChanged", i);
453 vars_[
i]->WhenRange(demon);
456 solver(),
this, &SafeSumConstraint::SumChanged,
"SumChanged"));
457 target_var_->WhenRange(sum_demon_);
460 void SafeComputeNode(
int depth,
int position, int64_t*
const sum_min,
461 int64_t*
const sum_max) {
462 DCHECK_LT(depth, MaxDepth());
463 const int block_start = ChildStart(position);
464 const int block_end = ChildEnd(depth, position);
465 for (
int k = block_start; k <= block_end; ++k) {
466 if (*sum_min != std::numeric_limits<int64_t>::min()) {
467 *sum_min =
CapAdd(*sum_min, Min(depth + 1, k));
469 if (*sum_max != std::numeric_limits<int64_t>::max()) {
470 *sum_max =
CapAdd(*sum_max, Max(depth + 1, k));
472 if (*sum_min == std::numeric_limits<int64_t>::min() &&
473 *sum_max == std::numeric_limits<int64_t>::max()) {
479 void InitialPropagate()
override {
481 for (
int i = 0;
i < vars_.size(); ++
i) {
482 InitLeaf(i, vars_[i]->Min(), vars_[i]->Max());
485 for (
int i = MaxDepth() - 1;
i >= 0; --
i) {
486 for (
int j = 0; j < Width(i); ++j) {
489 SafeComputeNode(i, j, &sum_min, &sum_max);
490 InitNode(i, j, sum_min, sum_max);
494 target_var_->SetRange(RootMin(), RootMax());
501 DCHECK(CheckInternalState());
502 if (target_var_->Max() == RootMin()) {
504 for (
int i = 0;
i < vars_.size(); ++
i) {
505 vars_[
i]->SetValue(vars_[i]->Min());
507 }
else if (target_var_->Min() == RootMax()) {
509 for (
int i = 0;
i < vars_.size(); ++
i) {
510 vars_[
i]->SetValue(vars_[i]->Max());
513 PushDown(0, 0, target_var_->Min(), target_var_->Max());
517 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
519 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
525 vars_[position]->SetRange(new_min, new_max);
533 const int64_t sum_min = Min(depth, position);
534 const int64_t sum_max = Max(depth, position);
537 new_max = std::min(sum_max, new_max);
538 new_min = std::max(sum_min, new_min);
541 if (new_max < sum_min || new_min > sum_max) {
546 const int block_start = ChildStart(position);
547 const int block_end = ChildEnd(depth, position);
548 for (
int pos = block_start; pos <= block_end; ++pos) {
549 const int64_t target_var_min = Min(depth + 1, pos);
550 const int64_t residual_min =
551 sum_min != std::numeric_limits<int64_t>::min()
552 ?
CapSub(sum_min, target_var_min)
553 : std::numeric_limits<int64_t>::min();
554 const int64_t target_var_max = Max(depth + 1, pos);
555 const int64_t residual_max =
556 sum_max != std::numeric_limits<int64_t>::max()
557 ?
CapSub(sum_max, target_var_max)
558 : std::numeric_limits<int64_t>::max();
559 PushDown(depth + 1, pos,
560 (residual_max == std::numeric_limits<int64_t>::min()
561 ? std::numeric_limits<int64_t>::min()
562 :
CapSub(new_min, residual_max)),
563 (residual_min == std::numeric_limits<int64_t>::max()
564 ? std::numeric_limits<int64_t>::min()
565 :
CapSub(new_max, residual_min)));
571 void LeafChanged(
int term_index) {
572 IntVar*
const var = vars_[term_index];
573 PushUp(term_index,
CapSub(var->Min(), var->OldMin()),
574 CapSub(var->OldMax(), var->Max()));
575 EnqueueDelayedDemon(sum_demon_);
578 void PushUp(
int position, int64_t delta_min, int64_t delta_max) {
579 DCHECK_GE(delta_max, 0);
580 DCHECK_GE(delta_min, 0);
581 if (
CapAdd(delta_min, delta_max) == 0) {
586 bool delta_corrupted =
false;
587 for (
int depth = MaxDepth(); depth >= 0; --depth) {
588 if (Min(depth, position) != std::numeric_limits<int64_t>::min() &&
589 Max(depth, position) != std::numeric_limits<int64_t>::max() &&
590 delta_min != std::numeric_limits<int64_t>::max() &&
591 delta_max != std::numeric_limits<int64_t>::max() &&
593 ReduceRange(depth, position, delta_min, delta_max);
594 }
else if (depth == MaxDepth()) {
595 SetRange(depth, position, vars_[position]->Min(),
596 vars_[position]->Max());
597 delta_corrupted =
true;
601 SafeComputeNode(depth, position, &sum_min, &sum_max);
602 if (sum_min == std::numeric_limits<int64_t>::min() &&
603 sum_max == std::numeric_limits<int64_t>::max()) {
606 SetRange(depth, position, sum_min, sum_max);
607 delta_corrupted =
true;
609 position = Parent(position);
611 DCHECK_EQ(0, position);
612 target_var_->SetRange(RootMin(), RootMax());
615 std::string DebugString()
const override {
616 return DebugStringInternal(
"Sum");
619 void Accept(ModelVisitor*
const visitor)
const override {
624 bool CheckInternalState() {
625 for (
int i = 0;
i < vars_.size(); ++
i) {
626 CheckLeaf(i, vars_[i]->Min(), vars_[i]->Max());
629 for (
int i = MaxDepth() - 1;
i >= 0; --
i) {
630 for (
int j = 0; j < Width(i); ++j) {
633 SafeComputeNode(i, j, &sum_min, &sum_max);
634 CheckNode(i, j, sum_min, sum_max);
640 void CheckLeaf(
int position, int64_t var_min, int64_t var_max) {
641 CheckNode(MaxDepth(), position, var_min, var_max);
644 void CheckNode(
int depth,
int position, int64_t node_min, int64_t node_max) {
645 DCHECK_EQ(Min(depth, position), node_min);
646 DCHECK_EQ(Max(depth, position), node_max);
655class MinConstraint :
public TreeArrayConstraint {
657 MinConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
658 IntVar*
const min_var)
659 : TreeArrayConstraint(solver, vars, min_var), min_demon_(nullptr) {}
661 ~MinConstraint()
override {}
663 void Post()
override {
664 for (
int i = 0;
i < vars_.size(); ++
i) {
666 solver(),
this, &MinConstraint::LeafChanged,
"LeafChanged", i);
667 vars_[
i]->WhenRange(demon);
670 solver(),
this, &MinConstraint::MinVarChanged,
"MinVarChanged"));
671 target_var_->WhenRange(min_demon_);
674 void InitialPropagate()
override {
676 for (
int i = 0;
i < vars_.size(); ++
i) {
677 InitLeaf(i, vars_[i]->Min(), vars_[i]->Max());
681 for (
int i = MaxDepth() - 1;
i >= 0; --
i) {
682 for (
int j = 0; j < Width(i); ++j) {
683 int64_t min_min = std::numeric_limits<int64_t>::max();
684 int64_t min_max = std::numeric_limits<int64_t>::max();
685 const int block_start = ChildStart(j);
686 const int block_end = ChildEnd(i, j);
687 for (
int k = block_start; k <= block_end; ++k) {
688 min_min = std::min(min_min, Min(i + 1, k));
689 min_max = std::min(min_max, Max(i + 1, k));
691 InitNode(i, j, min_min, min_max);
695 target_var_->SetRange(RootMin(), RootMax());
701 void MinVarChanged() {
702 PushDown(0, 0, target_var_->Min(), target_var_->Max());
705 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
707 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
713 vars_[position]->SetRange(new_min, new_max);
717 const int64_t node_min = Min(depth, position);
718 const int64_t node_max = Max(depth, position);
722 const int block_start = ChildStart(position);
723 const int block_end = ChildEnd(depth, position);
725 if (new_max < node_max) {
727 for (
int i = block_start;
i <= block_end; ++
i) {
728 if (Min(depth + 1, i) <= new_max) {
740 if (node_min < new_min) {
741 for (
int i = block_start;
i <= block_end; ++
i) {
742 if (i == candidate && active == 1) {
743 PushDown(depth + 1, i, new_min, new_max);
745 PushDown(depth + 1, i, new_min, Max(depth + 1, i));
748 }
else if (active == 1) {
749 PushDown(depth + 1, candidate, Min(depth + 1, candidate), new_max);
754 void LeafChanged(
int term_index) {
755 IntVar*
const var = vars_[term_index];
756 SetRange(MaxDepth(), term_index, var->Min(), var->Max());
757 const int parent_depth = MaxDepth() - 1;
758 const int parent = Parent(term_index);
759 const int64_t old_min = var->OldMin();
760 const int64_t var_min = var->Min();
761 const int64_t var_max = var->Max();
762 if ((old_min == Min(parent_depth, parent) && old_min != var_min) ||
763 var_max < Max(parent_depth, parent)) {
769 void PushUp(
int position) {
770 int depth = MaxDepth();
772 const int parent = Parent(position);
773 const int parent_depth = depth - 1;
774 int64_t min_min = std::numeric_limits<int64_t>::max();
775 int64_t min_max = std::numeric_limits<int64_t>::max();
776 const int block_start = ChildStart(parent);
777 const int block_end = ChildEnd(parent_depth, parent);
778 for (
int k = block_start; k <= block_end; ++k) {
779 min_min = std::min(min_min, Min(depth, k));
780 min_max = std::min(min_max, Max(depth, k));
782 if (min_min > Min(parent_depth, parent) ||
783 min_max < Max(parent_depth, parent)) {
784 SetRange(parent_depth, parent, min_min, min_max);
788 depth = parent_depth;
792 target_var_->SetRange(RootMin(), RootMax());
797 std::string DebugString()
const override {
798 return DebugStringInternal(
"Min");
801 void Accept(ModelVisitor*
const visitor)
const override {
811 SmallMinConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
812 IntVar*
const target_var)
813 : Constraint(solver),
815 target_var_(target_var),
819 ~SmallMinConstraint()
override {}
821 void Post()
override {
822 for (
int i = 0;
i < vars_.size(); ++
i) {
823 if (!vars_[i]->Bound()) {
825 solver(),
this, &SmallMinConstraint::VarChanged,
"VarChanged",
827 vars_[
i]->WhenRange(demon);
831 solver(),
this, &SmallMinConstraint::MinVarChanged,
"MinVarChanged"));
832 target_var_->WhenRange(mdemon);
835 void InitialPropagate()
override {
836 int64_t min_min = std::numeric_limits<int64_t>::max();
837 int64_t min_max = std::numeric_limits<int64_t>::max();
838 for (IntVar*
const var : vars_) {
839 min_min = std::min(min_min, var->Min());
840 min_max = std::min(min_max, var->Max());
842 computed_min_.SetValue(solver(), min_min);
843 computed_max_.SetValue(solver(), min_max);
845 target_var_->SetRange(min_min, min_max);
851 std::string DebugString()
const override {
852 return absl::StrFormat(
"SmallMin(%s) == %s",
854 target_var_->DebugString());
857 void Accept(ModelVisitor*
const visitor)
const override {
867 void VarChanged(IntVar* var) {
868 const int64_t old_min = var->OldMin();
869 const int64_t var_min = var->Min();
870 const int64_t var_max = var->Max();
871 if ((old_min == computed_min_.Value() && old_min != var_min) ||
872 var_max < computed_max_.Value()) {
874 int64_t min_min = std::numeric_limits<int64_t>::max();
875 int64_t min_max = std::numeric_limits<int64_t>::max();
876 for (IntVar*
const var : vars_) {
877 min_min = std::min(min_min, var->Min());
878 min_max = std::min(min_max, var->Max());
880 if (min_min > computed_min_.Value() || min_max < computed_max_.Value()) {
881 computed_min_.SetValue(solver(), min_min);
882 computed_max_.SetValue(solver(), min_max);
883 target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
889 void MinVarChanged() {
890 const int64_t new_min = target_var_->Min();
891 const int64_t new_max = target_var_->Max();
893 if (new_min <= computed_min_.Value() && new_max >= computed_max_.Value()) {
897 IntVar* candidate =
nullptr;
900 if (new_max < computed_max_.Value()) {
902 for (IntVar*
const var : vars_) {
903 if (var->Min() <= new_max) {
914 if (computed_min_.Value() < new_min) {
916 candidate->SetRange(new_min, new_max);
918 for (IntVar*
const var : vars_) {
919 var->SetMin(new_min);
922 }
else if (active == 1) {
923 candidate->SetMax(new_max);
927 std::vector<IntVar*> vars_;
928 IntVar*
const target_var_;
929 Rev<int64_t> computed_min_;
930 Rev<int64_t> computed_max_;
936class MaxConstraint :
public TreeArrayConstraint {
938 MaxConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
939 IntVar*
const max_var)
940 : TreeArrayConstraint(solver, vars, max_var), max_demon_(nullptr) {}
942 ~MaxConstraint()
override {}
944 void Post()
override {
945 for (
int i = 0;
i < vars_.size(); ++
i) {
947 solver(),
this, &MaxConstraint::LeafChanged,
"LeafChanged", i);
948 vars_[
i]->WhenRange(demon);
951 solver(),
this, &MaxConstraint::MaxVarChanged,
"MaxVarChanged"));
952 target_var_->WhenRange(max_demon_);
955 void InitialPropagate()
override {
957 for (
int i = 0;
i < vars_.size(); ++
i) {
958 InitLeaf(i, vars_[i]->Min(), vars_[i]->Max());
962 for (
int i = MaxDepth() - 1;
i >= 0; --
i) {
963 for (
int j = 0; j < Width(i); ++j) {
964 int64_t max_min = std::numeric_limits<int64_t>::min();
965 int64_t max_max = std::numeric_limits<int64_t>::min();
966 const int block_start = ChildStart(j);
967 const int block_end = ChildEnd(i, j);
968 for (
int k = block_start; k <= block_end; ++k) {
969 max_min = std::max(max_min, Min(i + 1, k));
970 max_max = std::max(max_max, Max(i + 1, k));
972 InitNode(i, j, max_min, max_max);
976 target_var_->SetRange(RootMin(), RootMax());
982 void MaxVarChanged() {
983 PushDown(0, 0, target_var_->Min(), target_var_->Max());
986 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
988 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
994 vars_[position]->SetRange(new_min, new_max);
998 const int64_t node_min = Min(depth, position);
999 const int64_t node_max = Max(depth, position);
1003 const int block_start = ChildStart(position);
1004 const int block_end = ChildEnd(depth, position);
1006 if (node_min < new_min) {
1008 for (
int i = block_start;
i <= block_end; ++
i) {
1009 if (Max(depth + 1, i) >= new_min) {
1010 if (active++ >= 1) {
1021 if (node_max > new_max) {
1022 for (
int i = block_start;
i <= block_end; ++
i) {
1023 if (i == candidate && active == 1) {
1024 PushDown(depth + 1, i, new_min, new_max);
1026 PushDown(depth + 1, i, Min(depth + 1, i), new_max);
1029 }
else if (active == 1) {
1030 PushDown(depth + 1, candidate, new_min, Max(depth + 1, candidate));
1034 void LeafChanged(
int term_index) {
1035 IntVar*
const var = vars_[term_index];
1036 SetRange(MaxDepth(), term_index, var->Min(), var->Max());
1037 const int parent_depth = MaxDepth() - 1;
1038 const int parent = Parent(term_index);
1039 const int64_t old_max = var->OldMax();
1040 const int64_t var_min = var->Min();
1041 const int64_t var_max = var->Max();
1042 if ((old_max == Max(parent_depth, parent) && old_max != var_max) ||
1043 var_min > Min(parent_depth, parent)) {
1049 void PushUp(
int position) {
1050 int depth = MaxDepth();
1052 const int parent = Parent(position);
1053 const int parent_depth = depth - 1;
1054 int64_t max_min = std::numeric_limits<int64_t>::min();
1055 int64_t max_max = std::numeric_limits<int64_t>::min();
1056 const int block_start = ChildStart(parent);
1057 const int block_end = ChildEnd(parent_depth, parent);
1058 for (
int k = block_start; k <= block_end; ++k) {
1059 max_min = std::max(max_min, Min(depth, k));
1060 max_max = std::max(max_max, Max(depth, k));
1062 if (max_min > Min(parent_depth, parent) ||
1063 max_max < Max(parent_depth, parent)) {
1064 SetRange(parent_depth, parent, max_min, max_max);
1068 depth = parent_depth;
1072 target_var_->SetRange(RootMin(), RootMax());
1077 std::string DebugString()
const override {
1078 return DebugStringInternal(
"Max");
1081 void Accept(ModelVisitor*
const visitor)
const override {
1089class SmallMaxConstraint :
public Constraint {
1091 SmallMaxConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
1092 IntVar*
const target_var)
1093 : Constraint(solver),
1095 target_var_(target_var),
1099 ~SmallMaxConstraint()
override {}
1101 void Post()
override {
1102 for (
int i = 0;
i < vars_.size(); ++
i) {
1103 if (!vars_[i]->Bound()) {
1105 solver(),
this, &SmallMaxConstraint::VarChanged,
"VarChanged",
1107 vars_[
i]->WhenRange(demon);
1111 solver(),
this, &SmallMaxConstraint::MaxVarChanged,
"MinVarChanged"));
1112 target_var_->WhenRange(mdemon);
1115 void InitialPropagate()
override {
1116 int64_t max_min = std::numeric_limits<int64_t>::min();
1117 int64_t max_max = std::numeric_limits<int64_t>::min();
1118 for (IntVar*
const var : vars_) {
1119 max_min = std::max(max_min, var->Min());
1120 max_max = std::max(max_max, var->Max());
1122 computed_min_.SetValue(solver(), max_min);
1123 computed_max_.SetValue(solver(), max_max);
1125 target_var_->SetRange(max_min, max_max);
1131 std::string DebugString()
const override {
1132 return absl::StrFormat(
"SmallMax(%s) == %s",
1134 target_var_->DebugString());
1137 void Accept(ModelVisitor*
const visitor)
const override {
1147 void VarChanged(IntVar* var) {
1148 const int64_t old_max = var->OldMax();
1149 const int64_t var_min = var->Min();
1150 const int64_t var_max = var->Max();
1151 if ((old_max == computed_max_.Value() && old_max != var_max) ||
1152 var_min > computed_min_.Value()) {
1154 int64_t max_min = std::numeric_limits<int64_t>::min();
1155 int64_t max_max = std::numeric_limits<int64_t>::min();
1156 for (IntVar*
const var : vars_) {
1157 max_min = std::max(max_min, var->Min());
1158 max_max = std::max(max_max, var->Max());
1160 if (max_min > computed_min_.Value() || max_max < computed_max_.Value()) {
1161 computed_min_.SetValue(solver(), max_min);
1162 computed_max_.SetValue(solver(), max_max);
1163 target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
1169 void MaxVarChanged() {
1170 const int64_t new_min = target_var_->Min();
1171 const int64_t new_max = target_var_->Max();
1173 if (new_min <= computed_min_.Value() && new_max >= computed_max_.Value()) {
1177 IntVar* candidate =
nullptr;
1180 if (new_min > computed_min_.Value()) {
1182 for (IntVar*
const var : vars_) {
1183 if (var->Max() >= new_min) {
1184 if (active++ >= 1) {
1194 if (computed_max_.Value() > new_max) {
1196 candidate->SetRange(new_min, new_max);
1198 for (IntVar*
const var : vars_) {
1199 var->SetMax(new_max);
1202 }
else if (active == 1) {
1203 candidate->SetMin(new_min);
1207 std::vector<IntVar*> vars_;
1208 IntVar*
const target_var_;
1209 Rev<int64_t> computed_min_;
1210 Rev<int64_t> computed_max_;
1217 ArrayBoolAndEq(Solver*
const s,
const std::vector<IntVar*>& vars,
1218 IntVar*
const target)
1219 : CastConstraint(s, target),
1221 demons_(vars.size()),
1224 ~ArrayBoolAndEq()
override {}
1226 void Post()
override {
1227 for (
int i = 0;
i < vars_.size(); ++
i) {
1228 if (!vars_[i]->Bound()) {
1231 "PropagateVar", vars_[i]);
1232 vars_[
i]->WhenBound(demons_[i]);
1235 if (!target_var_->Bound()) {
1237 solver(),
this, &ArrayBoolAndEq::PropagateTarget,
"PropagateTarget");
1238 target_var_->WhenBound(target_demon);
1242 void InitialPropagate()
override {
1243 target_var_->SetRange(0, 1);
1244 if (target_var_->Min() == 1) {
1245 for (
int i = 0;
i < vars_.size(); ++
i) {
1246 vars_[
i]->SetMin(1);
1249 int possible_zero = -1;
1252 for (
int i = 0;
i < vars_.size(); ++
i) {
1253 if (!vars_[i]->Bound()) {
1256 }
else if (vars_[i]->Max() == 0) {
1258 target_var_->SetMax(0);
1261 DCHECK_EQ(1, vars_[i]->Min());
1265 if (unbounded == 0) {
1266 target_var_->SetMin(1);
1267 }
else if (target_var_->Max() == 0 && unbounded == 1) {
1268 CHECK_NE(-1, possible_zero);
1269 vars_[possible_zero]->SetMax(0);
1271 unbounded_.SetValue(solver(), unbounded);
1276 void PropagateVar(IntVar* var) {
1277 if (var->Min() == 1) {
1278 unbounded_.Decr(solver());
1279 if (unbounded_.Value() == 0 && !decided_.Switched()) {
1280 target_var_->SetMin(1);
1281 decided_.Switch(solver());
1282 }
else if (target_var_->Max() == 0 && unbounded_.Value() == 1 &&
1283 !decided_.Switched()) {
1288 target_var_->SetMax(0);
1292 void PropagateTarget() {
1293 if (target_var_->Min() == 1) {
1294 for (
int i = 0;
i < vars_.size(); ++
i) {
1295 vars_[
i]->SetMin(1);
1298 if (unbounded_.Value() == 1 && !decided_.Switched()) {
1304 std::string DebugString()
const override {
1306 target_var_->DebugString());
1309 void Accept(ModelVisitor*
const visitor)
const override {
1320 for (
int i = 0;
i < demons_.size(); ++
i) {
1321 if (demons_[i] !=
nullptr) {
1322 demons_[
i]->inhibit(solver());
1327 void ForceToZero() {
1328 for (
int i = 0;
i < vars_.size(); ++
i) {
1329 if (vars_[i]->Min() == 0) {
1330 vars_[
i]->SetValue(0);
1331 decided_.Switch(solver());
1338 const std::vector<IntVar*> vars_;
1339 std::vector<Demon*> demons_;
1340 NumericalRev<int> unbounded_;
1346 ArrayBoolOrEq(Solver*
const s,
const std::vector<IntVar*>& vars,
1347 IntVar*
const target)
1348 : CastConstraint(s, target),
1350 demons_(vars.size()),
1353 ~ArrayBoolOrEq()
override {}
1355 void Post()
override {
1356 for (
int i = 0;
i < vars_.size(); ++
i) {
1357 if (!vars_[i]->Bound()) {
1360 "PropagateVar", vars_[i]);
1361 vars_[
i]->WhenBound(demons_[i]);
1364 if (!target_var_->Bound()) {
1366 solver(),
this, &ArrayBoolOrEq::PropagateTarget,
"PropagateTarget");
1367 target_var_->WhenBound(target_demon);
1371 void InitialPropagate()
override {
1372 target_var_->SetRange(0, 1);
1373 if (target_var_->Max() == 0) {
1374 for (
int i = 0;
i < vars_.size(); ++
i) {
1375 vars_[
i]->SetMax(0);
1379 int possible_one = -1;
1381 for (
int i = 0;
i < vars_.size(); ++
i) {
1382 if (!vars_[i]->Bound()) {
1385 }
else if (vars_[i]->Min() == 1) {
1387 target_var_->SetMin(1);
1390 DCHECK_EQ(0, vars_[i]->Max());
1394 if (unbounded == 0) {
1395 target_var_->SetMax(0);
1396 }
else if (target_var_->Min() == 1 && unbounded == 1) {
1397 CHECK_NE(-1, possible_one);
1398 vars_[possible_one]->SetMin(1);
1400 unbounded_.SetValue(solver(), unbounded);
1405 void PropagateVar(IntVar* var) {
1406 if (var->Min() == 0) {
1407 unbounded_.Decr(solver());
1408 if (unbounded_.Value() == 0 && !decided_.Switched()) {
1409 target_var_->SetMax(0);
1410 decided_.Switch(solver());
1412 if (target_var_->Min() == 1 && unbounded_.Value() == 1 &&
1413 !decided_.Switched()) {
1418 target_var_->SetMin(1);
1422 void PropagateTarget() {
1423 if (target_var_->Max() == 0) {
1424 for (
int i = 0;
i < vars_.size(); ++
i) {
1425 vars_[
i]->SetMax(0);
1428 if (unbounded_.Value() == 1 && !decided_.Switched()) {
1434 std::string DebugString()
const override {
1436 target_var_->DebugString());
1439 void Accept(ModelVisitor*
const visitor)
const override {
1450 for (
int i = 0;
i < demons_.size(); ++
i) {
1451 if (demons_[i] !=
nullptr) {
1452 demons_[
i]->inhibit(solver());
1458 for (
int i = 0;
i < vars_.size(); ++
i) {
1459 if (vars_[i]->Max() == 1) {
1460 vars_[
i]->SetValue(1);
1461 decided_.Switch(solver());
1468 const std::vector<IntVar*> vars_;
1469 std::vector<Demon*> demons_;
1470 NumericalRev<int> unbounded_;
1476class BaseSumBooleanConstraint :
public Constraint {
1478 BaseSumBooleanConstraint(Solver*
const s,
const std::vector<IntVar*>& vars)
1479 : Constraint(s), vars_(vars) {}
1481 ~BaseSumBooleanConstraint()
override {}
1484 std::string DebugStringInternal(absl::string_view name)
const {
1488 const std::vector<IntVar*> vars_;
1489 RevSwitch inactive_;
1494class SumBooleanLessOrEqualToOne :
public BaseSumBooleanConstraint {
1496 SumBooleanLessOrEqualToOne(Solver*
const s,
const std::vector<IntVar*>& vars)
1497 : BaseSumBooleanConstraint(s, vars) {}
1499 ~SumBooleanLessOrEqualToOne()
override {}
1501 void Post()
override {
1502 for (
int i = 0;
i < vars_.size(); ++
i) {
1503 if (!vars_[i]->Bound()) {
1505 &SumBooleanLessOrEqualToOne::Update,
1506 "Update", vars_[i]);
1507 vars_[
i]->WhenBound(u);
1512 void InitialPropagate()
override {
1513 for (
int i = 0;
i < vars_.size(); ++
i) {
1514 if (vars_[i]->Min() == 1) {
1515 PushAllToZeroExcept(vars_[i]);
1521 void Update(IntVar* var) {
1522 if (!inactive_.Switched()) {
1523 DCHECK(var->Bound());
1524 if (var->Min() == 1) {
1525 PushAllToZeroExcept(var);
1530 void PushAllToZeroExcept(IntVar* var) {
1531 inactive_.Switch(solver());
1532 for (
int i = 0;
i < vars_.size(); ++
i) {
1533 IntVar*
const other = vars_[
i];
1534 if (other != var && other->Max() != 0) {
1540 std::string DebugString()
const override {
1541 return DebugStringInternal(
"SumBooleanLessOrEqualToOne");
1544 void Accept(ModelVisitor*
const visitor)
const override {
1557class SumBooleanGreaterOrEqualToOne :
public BaseSumBooleanConstraint {
1559 SumBooleanGreaterOrEqualToOne(Solver* s,
const std::vector<IntVar*>& vars);
1560 ~SumBooleanGreaterOrEqualToOne()
override {}
1562 void Post()
override;
1563 void InitialPropagate()
override;
1565 void Update(
int index);
1568 std::string DebugString()
const override;
1570 void Accept(ModelVisitor*
const visitor)
const override {
1582SumBooleanGreaterOrEqualToOne::SumBooleanGreaterOrEqualToOne(
1583 Solver*
const s,
const std::vector<IntVar*>& vars)
1584 : BaseSumBooleanConstraint(s, vars), bits_(vars.size()) {}
1586void SumBooleanGreaterOrEqualToOne::Post() {
1587 for (
int i = 0;
i < vars_.size(); ++
i) {
1589 solver(),
this, &SumBooleanGreaterOrEqualToOne::Update,
"Update", i);
1590 vars_[
i]->WhenRange(d);
1594void SumBooleanGreaterOrEqualToOne::InitialPropagate() {
1595 for (
int i = 0;
i < vars_.size(); ++
i) {
1596 IntVar*
const var = vars_[
i];
1597 if (var->Min() == 1LL) {
1598 inactive_.Switch(solver());
1601 if (var->Max() == 1LL) {
1602 bits_.SetToOne(solver(), i);
1605 if (bits_.IsCardinalityZero()) {
1607 }
else if (bits_.IsCardinalityOne()) {
1608 vars_[bits_.GetFirstBit(0)]->SetValue(int64_t{1});
1609 inactive_.Switch(solver());
1613void SumBooleanGreaterOrEqualToOne::Update(
int index) {
1614 if (!inactive_.Switched()) {
1615 if (vars_[index]->Min() == 1LL) {
1616 inactive_.Switch(solver());
1618 bits_.SetToZero(solver(), index);
1619 if (bits_.IsCardinalityZero()) {
1621 }
else if (bits_.IsCardinalityOne()) {
1622 vars_[bits_.GetFirstBit(0)]->SetValue(int64_t{1});
1623 inactive_.Switch(solver());
1629std::string SumBooleanGreaterOrEqualToOne::DebugString()
const {
1630 return DebugStringInternal(
"SumBooleanGreaterOrEqualToOne");
1635class SumBooleanEqualToOne :
public BaseSumBooleanConstraint {
1637 SumBooleanEqualToOne(Solver*
const s,
const std::vector<IntVar*>& vars)
1638 : BaseSumBooleanConstraint(s, vars), active_vars_(0) {}
1640 ~SumBooleanEqualToOne()
override {}
1642 void Post()
override {
1643 for (
int i = 0;
i < vars_.size(); ++
i) {
1645 solver(),
this, &SumBooleanEqualToOne::Update,
"Update", i);
1646 vars_[
i]->WhenBound(u);
1650 void InitialPropagate()
override {
1655 for (
int i = 0;
i < vars_.size(); ++
i) {
1656 const IntVar*
const var = vars_[
i];
1657 if (var->Min() == 1) {
1661 if (var->Max() == 1) {
1666 if (min1 > 1 || max1 == 0) {
1668 }
else if (min1 == 1) {
1669 DCHECK_NE(-1, index_min);
1670 PushAllToZeroExcept(index_min);
1671 }
else if (max1 == 1) {
1672 DCHECK_NE(-1, index_max);
1673 vars_[index_max]->SetValue(1);
1674 inactive_.Switch(solver());
1676 active_vars_.SetValue(solver(), max1);
1680 void Update(
int index) {
1681 if (!inactive_.Switched()) {
1682 DCHECK(vars_[index]->Bound());
1683 const int64_t value = vars_[index]->Min();
1685 active_vars_.Decr(solver());
1686 DCHECK_GE(active_vars_.Value(), 0);
1687 if (active_vars_.Value() == 0) {
1689 }
else if (active_vars_.Value() == 1) {
1691 for (
int i = 0;
i < vars_.size(); ++
i) {
1692 IntVar*
const var = vars_[
i];
1693 if (var->Max() == 1) {
1695 PushAllToZeroExcept(i);
1705 PushAllToZeroExcept(index);
1710 void PushAllToZeroExcept(
int index) {
1711 inactive_.Switch(solver());
1712 for (
int i = 0;
i < vars_.size(); ++
i) {
1713 if (i != index && vars_[i]->Max() != 0) {
1714 vars_[
i]->SetMax(0);
1719 std::string DebugString()
const override {
1720 return DebugStringInternal(
"SumBooleanEqualToOne");
1723 void Accept(ModelVisitor*
const visitor)
const override {
1724 visitor->BeginVisitConstraint(ModelVisitor::kSumEqual,
this);
1725 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1727 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, 1);
1728 visitor->EndVisitConstraint(ModelVisitor::kSumEqual,
this);
1732 NumericalRev<int> active_vars_;
1737class SumBooleanEqualToVar :
public BaseSumBooleanConstraint {
1739 SumBooleanEqualToVar(Solver*
const s,
const std::vector<IntVar*>& bool_vars,
1740 IntVar*
const sum_var)
1741 : BaseSumBooleanConstraint(s, bool_vars),
1742 num_possible_true_vars_(0),
1743 num_always_true_vars_(0),
1744 sum_var_(sum_var) {}
1746 ~SumBooleanEqualToVar()
override {}
1748 void Post()
override {
1749 for (
int i = 0;
i < vars_.size(); ++
i) {
1751 solver(),
this, &SumBooleanEqualToVar::Update,
"Update", i);
1752 vars_[
i]->WhenBound(u);
1754 if (!sum_var_->Bound()) {
1756 solver(),
this, &SumBooleanEqualToVar::UpdateVar,
"UpdateVar");
1757 sum_var_->WhenRange(u);
1761 void InitialPropagate()
override {
1762 int num_always_true_vars = 0;
1763 int possible_true = 0;
1764 for (
int i = 0;
i < vars_.size(); ++
i) {
1765 const IntVar*
const var = vars_[
i];
1766 if (var->Min() == 1) {
1767 num_always_true_vars++;
1769 if (var->Max() == 1) {
1773 sum_var_->SetRange(num_always_true_vars, possible_true);
1774 const int64_t var_min = sum_var_->Min();
1775 const int64_t var_max = sum_var_->Max();
1776 if (num_always_true_vars == var_max && possible_true > var_max) {
1777 PushAllUnboundToZero();
1778 }
else if (possible_true == var_min && num_always_true_vars < var_min) {
1779 PushAllUnboundToOne();
1781 num_possible_true_vars_.SetValue(solver(), possible_true);
1782 num_always_true_vars_.SetValue(solver(), num_always_true_vars);
1787 if (!inactive_.Switched()) {
1788 if (num_possible_true_vars_.Value() == sum_var_->Min()) {
1789 PushAllUnboundToOne();
1790 sum_var_->SetValue(num_possible_true_vars_.Value());
1791 }
else if (num_always_true_vars_.Value() == sum_var_->Max()) {
1792 PushAllUnboundToZero();
1793 sum_var_->SetValue(num_always_true_vars_.Value());
1798 void Update(
int index) {
1799 if (!inactive_.Switched()) {
1800 DCHECK(vars_[index]->Bound());
1801 const int64_t value = vars_[index]->Min();
1803 num_possible_true_vars_.Decr(solver());
1804 sum_var_->SetRange(num_always_true_vars_.Value(),
1805 num_possible_true_vars_.Value());
1806 if (num_possible_true_vars_.Value() == sum_var_->Min()) {
1807 PushAllUnboundToOne();
1810 DCHECK_EQ(1, value);
1811 num_always_true_vars_.Incr(solver());
1812 sum_var_->SetRange(num_always_true_vars_.Value(),
1813 num_possible_true_vars_.Value());
1814 if (num_always_true_vars_.Value() == sum_var_->Max()) {
1815 PushAllUnboundToZero();
1821 void PushAllUnboundToZero() {
1822 int64_t counter = 0;
1823 inactive_.Switch(solver());
1824 for (
int i = 0;
i < vars_.size(); ++
i) {
1825 if (vars_[i]->Min() == 0) {
1826 vars_[
i]->SetValue(0);
1831 if (counter < sum_var_->Min() || counter > sum_var_->Max()) {
1836 void PushAllUnboundToOne() {
1837 int64_t counter = 0;
1838 inactive_.Switch(solver());
1839 for (
int i = 0;
i < vars_.size(); ++
i) {
1840 if (vars_[i]->Max() == 1) {
1841 vars_[
i]->SetValue(1);
1845 if (counter < sum_var_->Min() || counter > sum_var_->Max()) {
1850 std::string DebugString()
const override {
1851 return absl::StrFormat(
"%s == %s", DebugStringInternal(
"SumBoolean"),
1852 sum_var_->DebugString());
1855 void Accept(ModelVisitor*
const visitor)
const override {
1856 visitor->BeginVisitConstraint(ModelVisitor::kSumEqual,
this);
1857 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1859 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1861 visitor->EndVisitConstraint(ModelVisitor::kSumEqual,
this);
1865 NumericalRev<int> num_possible_true_vars_;
1866 NumericalRev<int> num_always_true_vars_;
1867 IntVar*
const sum_var_;
1877 Container(IntVar* v, int64_t c) : var(v), coef(
c) {}
1878 bool operator<(
const Container& c)
const {
return (coef <
c.coef); }
1888int64_t SortBothChangeConstant(std::vector<IntVar*>*
const vars,
1889 std::vector<int64_t>*
const coefs,
1891 CHECK(vars !=
nullptr);
1892 CHECK(coefs !=
nullptr);
1893 if (vars->empty()) {
1897 std::vector<Container> to_sort;
1898 for (
int index = 0; index < vars->size(); ++index) {
1899 if ((*vars)[index]->Bound()) {
1900 cst =
CapAdd(cst,
CapProd((*coefs)[index], (*vars)[index]->Min()));
1901 }
else if ((*coefs)[index] != 0) {
1902 to_sort.push_back(Container((*vars)[index], (*coefs)[index]));
1905 if (keep_inside && cst != 0) {
1906 CHECK_LT(to_sort.size(), vars->size());
1907 Solver*
const solver = (*vars)[0]->solver();
1908 to_sort.push_back(Container(solver->MakeIntConst(1), cst));
1911 std::sort(to_sort.begin(), to_sort.end());
1912 for (
int index = 0; index < to_sort.size(); ++index) {
1913 (*vars)[index] = to_sort[index].var;
1914 (*coefs)[index] = to_sort[index].coef;
1916 vars->resize(to_sort.size());
1917 coefs->resize(to_sort.size());
1923class BooleanScalProdLessConstant :
public Constraint {
1925 BooleanScalProdLessConstant(Solver*
const s,
const std::vector<IntVar*>& vars,
1926 const std::vector<int64_t>& coefs,
1927 int64_t upper_bound)
1931 upper_bound_(upper_bound),
1932 first_unbound_backward_(vars.size() - 1),
1933 sum_of_bound_variables_(0LL),
1934 max_coefficient_(0) {
1935 CHECK(!vars.empty());
1936 for (
int i = 0;
i < vars_.size(); ++
i) {
1937 DCHECK_GE(coefs_[i], 0);
1940 CapSub(upper_bound, SortBothChangeConstant(&vars_, &coefs_,
false));
1941 max_coefficient_.SetValue(s, coefs_[vars_.size() - 1]);
1944 ~BooleanScalProdLessConstant()
override {}
1946 void Post()
override {
1947 for (
int var_index = 0; var_index < vars_.size(); ++var_index) {
1948 if (vars_[var_index]->Bound()) {
1952 &BooleanScalProdLessConstant::Update,
1953 "InitialPropagate", var_index);
1954 vars_[var_index]->WhenRange(d);
1958 void PushFromTop() {
1959 const int64_t slack =
CapSub(upper_bound_, sum_of_bound_variables_.Value());
1963 if (slack < max_coefficient_.Value()) {
1964 int64_t last_unbound = first_unbound_backward_.Value();
1965 for (; last_unbound >= 0; --last_unbound) {
1966 if (!vars_[last_unbound]->Bound()) {
1967 if (coefs_[last_unbound] <= slack) {
1968 max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
1971 vars_[last_unbound]->SetValue(0);
1975 first_unbound_backward_.SetValue(solver(), last_unbound);
1979 void InitialPropagate()
override {
1980 Solver*
const s = solver();
1981 int last_unbound = -1;
1983 for (
int index = 0; index < vars_.size(); ++index) {
1984 if (vars_[index]->Bound()) {
1985 const int64_t value = vars_[index]->Min();
1988 last_unbound = index;
1991 sum_of_bound_variables_.SetValue(s, sum);
1992 first_unbound_backward_.SetValue(s, last_unbound);
1996 void Update(
int var_index) {
1997 if (vars_[var_index]->Min() == 1) {
1998 sum_of_bound_variables_.SetValue(
1999 solver(),
CapAdd(sum_of_bound_variables_.Value(), coefs_[var_index]));
2005 return absl::StrFormat(
"BooleanScalProd([%s], [%s]) <= %d)",
2007 absl::StrJoin(coefs_,
", "), upper_bound_);
2010 void Accept(ModelVisitor*
const visitor)
const override {
2011 visitor->BeginVisitConstraint(ModelVisitor::kScalProdLessOrEqual,
this);
2012 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2014 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2016 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, upper_bound_);
2017 visitor->EndVisitConstraint(ModelVisitor::kScalProdLessOrEqual,
this);
2021 std::vector<IntVar*> vars_;
2022 std::vector<int64_t> coefs_;
2023 int64_t upper_bound_;
2024 Rev<int> first_unbound_backward_;
2025 Rev<int64_t> sum_of_bound_variables_;
2026 Rev<int64_t> max_coefficient_;
2031class PositiveBooleanScalProdEqVar :
public CastConstraint {
2033 PositiveBooleanScalProdEqVar(Solver*
const s,
2034 const std::vector<IntVar*>& vars,
2035 const std::vector<int64_t>& coefs,
2037 : CastConstraint(s, var),
2040 first_unbound_backward_(vars.size() - 1),
2041 sum_of_bound_variables_(0LL),
2042 sum_of_all_variables_(0LL),
2043 max_coefficient_(0) {
2044 SortBothChangeConstant(&vars_, &coefs_,
true);
2045 max_coefficient_.SetValue(s, coefs_[vars_.size() - 1]);
2048 ~PositiveBooleanScalProdEqVar()
override {}
2050 void Post()
override {
2051 for (
int var_index = 0; var_index < vars_.size(); ++var_index) {
2052 if (vars_[var_index]->Bound()) {
2056 solver(),
this, &PositiveBooleanScalProdEqVar::Update,
"Update",
2058 vars_[var_index]->WhenRange(d);
2060 if (!target_var_->Bound()) {
2062 solver(),
this, &PositiveBooleanScalProdEqVar::Propagate,
2064 target_var_->WhenRange(uv);
2069 target_var_->SetRange(sum_of_bound_variables_.Value(),
2070 sum_of_all_variables_.Value());
2071 const int64_t slack_up =
2072 CapSub(target_var_->Max(), sum_of_bound_variables_.Value());
2073 const int64_t slack_down =
2074 CapSub(sum_of_all_variables_.Value(), target_var_->Min());
2075 const int64_t max_coeff = max_coefficient_.Value();
2076 if (slack_down < max_coeff || slack_up < max_coeff) {
2077 int64_t last_unbound = first_unbound_backward_.Value();
2078 for (; last_unbound >= 0; --last_unbound) {
2079 if (!vars_[last_unbound]->Bound()) {
2080 if (coefs_[last_unbound] > slack_up) {
2081 vars_[last_unbound]->SetValue(0);
2082 }
else if (coefs_[last_unbound] > slack_down) {
2083 vars_[last_unbound]->SetValue(1);
2085 max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
2090 first_unbound_backward_.SetValue(solver(), last_unbound);
2094 void InitialPropagate()
override {
2095 Solver*
const s = solver();
2096 int last_unbound = -1;
2097 int64_t sum_bound = 0;
2098 int64_t sum_all = 0;
2099 for (
int index = 0; index < vars_.size(); ++index) {
2100 const int64_t value =
CapProd(vars_[index]->Max(), coefs_[index]);
2101 sum_all =
CapAdd(sum_all, value);
2102 if (vars_[index]->Bound()) {
2103 sum_bound =
CapAdd(sum_bound, value);
2105 last_unbound = index;
2108 sum_of_bound_variables_.SetValue(s, sum_bound);
2109 sum_of_all_variables_.SetValue(s, sum_all);
2110 first_unbound_backward_.SetValue(s, last_unbound);
2114 void Update(
int var_index) {
2115 if (vars_[var_index]->Min() == 1) {
2116 sum_of_bound_variables_.SetValue(
2117 solver(),
CapAdd(sum_of_bound_variables_.Value(), coefs_[var_index]));
2119 sum_of_all_variables_.SetValue(
2120 solver(),
CapSub(sum_of_all_variables_.Value(), coefs_[var_index]));
2125 std::string DebugString()
const override {
2126 return absl::StrFormat(
"PositiveBooleanScal([%s], [%s]) == %s",
2128 absl::StrJoin(coefs_,
", "),
2129 target_var_->DebugString());
2132 void Accept(ModelVisitor*
const visitor)
const override {
2133 visitor->BeginVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2134 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2136 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2138 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
2140 visitor->EndVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2144 std::vector<IntVar*> vars_;
2145 std::vector<int64_t> coefs_;
2146 Rev<int> first_unbound_backward_;
2147 Rev<int64_t> sum_of_bound_variables_;
2148 Rev<int64_t> sum_of_all_variables_;
2149 Rev<int64_t> max_coefficient_;
2154class PositiveBooleanScalProd :
public BaseIntExpr {
2158 PositiveBooleanScalProd(Solver*
const s,
const std::vector<IntVar*>& vars,
2159 const std::vector<int64_t>& coefs)
2160 : BaseIntExpr(s), vars_(vars), coefs_(coefs) {
2161 CHECK(!vars.empty());
2162 SortBothChangeConstant(&vars_, &coefs_,
true);
2163 for (
int i = 0;
i < vars_.size(); ++
i) {
2164 DCHECK_GE(coefs_[i], 0);
2168 ~PositiveBooleanScalProd()
override {}
2170 int64_t Min()
const override {
2172 for (
int i = 0;
i < vars_.size(); ++
i) {
2173 if (vars_[i]->Min()) {
2174 min =
CapAdd(min, coefs_[i]);
2180 void SetMin(int64_t m)
override {
2181 SetRange(m, std::numeric_limits<int64_t>::max());
2184 int64_t Max()
const override {
2186 for (
int i = 0;
i < vars_.size(); ++
i) {
2187 if (vars_[i]->Max()) {
2188 max =
CapAdd(max, coefs_[i]);
2194 void SetMax(int64_t m)
override {
2195 SetRange(std::numeric_limits<int64_t>::min(), m);
2198 void SetRange(int64_t l, int64_t u)
override {
2199 int64_t current_min = 0;
2200 int64_t current_max = 0;
2201 int64_t diameter = -1;
2202 for (
int i = 0;
i < vars_.size(); ++
i) {
2203 const int64_t coefficient = coefs_[
i];
2204 const int64_t var_min =
CapProd(vars_[i]->Min(), coefficient);
2205 const int64_t var_max =
CapProd(vars_[i]->Max(), coefficient);
2206 current_min =
CapAdd(current_min, var_min);
2207 current_max =
CapAdd(current_max, var_max);
2208 if (var_min != var_max) {
2209 diameter =
CapSub(var_max, var_min);
2212 if (u >= current_max && l <= current_min) {
2215 if (u < current_min || l > current_max) {
2219 u = std::min(current_max, u);
2220 l = std::max(l, current_min);
2222 if (
CapSub(u, l) > diameter) {
2226 for (
int i = 0;
i < vars_.size(); ++
i) {
2227 const int64_t coefficient = coefs_[
i];
2228 IntVar*
const var = vars_[
i];
2229 const int64_t new_min =
2231 const int64_t new_max =
2233 if (new_max < 0 || new_min > coefficient || new_min > new_max) {
2236 if (new_min > 0LL) {
2237 var->SetMin(int64_t{1});
2238 }
else if (new_max < coefficient) {
2239 var->SetMax(int64_t{0});
2244 std::string DebugString()
const override {
2245 return absl::StrFormat(
"PositiveBooleanScalProd([%s], [%s])",
2247 absl::StrJoin(coefs_,
", "));
2250 void WhenRange(Demon* d)
override {
2251 for (
int i = 0;
i < vars_.size(); ++
i) {
2252 vars_[
i]->WhenRange(d);
2255 IntVar* CastToVar()
override {
2256 Solver*
const s = solver();
2259 Range(&vmin, &vmax);
2260 IntVar*
const var = solver()->MakeIntVar(vmin, vmax);
2261 if (!vars_.empty()) {
2262 CastConstraint*
const ct =
2263 s->RevAlloc(
new PositiveBooleanScalProdEqVar(s, vars_, coefs_, var));
2264 s->AddCastConstraint(ct, var,
this);
2269 void Accept(ModelVisitor*
const visitor)
const override {
2270 visitor->BeginVisitIntegerExpression(ModelVisitor::kScalProd,
this);
2271 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2273 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2275 visitor->EndVisitIntegerExpression(ModelVisitor::kScalProd,
this);
2279 std::vector<IntVar*> vars_;
2280 std::vector<int64_t> coefs_;
2285class PositiveBooleanScalProdEqCst :
public Constraint {
2287 PositiveBooleanScalProdEqCst(Solver*
const s,
2288 const std::vector<IntVar*>& vars,
2289 const std::vector<int64_t>& coefs,
2294 first_unbound_backward_(vars.size() - 1),
2295 sum_of_bound_variables_(0LL),
2296 sum_of_all_variables_(0LL),
2297 constant_(constant),
2298 max_coefficient_(0) {
2299 CHECK(!vars.empty());
2301 CapSub(constant_, SortBothChangeConstant(&vars_, &coefs_,
false));
2302 max_coefficient_.SetValue(s, coefs_[vars_.size() - 1]);
2305 ~PositiveBooleanScalProdEqCst()
override {}
2307 void Post()
override {
2308 for (
int var_index = 0; var_index < vars_.size(); ++var_index) {
2309 if (!vars_[var_index]->Bound()) {
2311 solver(),
this, &PositiveBooleanScalProdEqCst::Update,
"Update",
2313 vars_[var_index]->WhenRange(d);
2319 if (sum_of_bound_variables_.Value() > constant_ ||
2320 sum_of_all_variables_.Value() < constant_) {
2323 const int64_t slack_up =
CapSub(constant_, sum_of_bound_variables_.Value());
2324 const int64_t slack_down =
CapSub(sum_of_all_variables_.Value(), constant_);
2325 const int64_t max_coeff = max_coefficient_.Value();
2326 if (slack_down < max_coeff || slack_up < max_coeff) {
2327 int64_t last_unbound = first_unbound_backward_.Value();
2328 for (; last_unbound >= 0; --last_unbound) {
2329 if (!vars_[last_unbound]->Bound()) {
2330 if (coefs_[last_unbound] > slack_up) {
2331 vars_[last_unbound]->SetValue(0);
2332 }
else if (coefs_[last_unbound] > slack_down) {
2333 vars_[last_unbound]->SetValue(1);
2335 max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
2340 first_unbound_backward_.SetValue(solver(), last_unbound);
2344 void InitialPropagate()
override {
2345 Solver*
const s = solver();
2346 int last_unbound = -1;
2347 int64_t sum_bound = 0LL;
2348 int64_t sum_all = 0LL;
2349 for (
int index = 0; index < vars_.size(); ++index) {
2350 const int64_t value =
CapProd(vars_[index]->Max(), coefs_[index]);
2351 sum_all =
CapAdd(sum_all, value);
2352 if (vars_[index]->Bound()) {
2353 sum_bound =
CapAdd(sum_bound, value);
2355 last_unbound = index;
2358 sum_of_bound_variables_.SetValue(s, sum_bound);
2359 sum_of_all_variables_.SetValue(s, sum_all);
2360 first_unbound_backward_.SetValue(s, last_unbound);
2364 void Update(
int var_index) {
2365 if (vars_[var_index]->Min() == 1) {
2366 sum_of_bound_variables_.SetValue(
2367 solver(),
CapAdd(sum_of_bound_variables_.Value(), coefs_[var_index]));
2369 sum_of_all_variables_.SetValue(
2370 solver(),
CapSub(sum_of_all_variables_.Value(), coefs_[var_index]));
2376 return absl::StrFormat(
"PositiveBooleanScalProd([%s], [%s]) == %d",
2378 absl::StrJoin(coefs_,
", "), constant_);
2381 void Accept(ModelVisitor*
const visitor)
const override {
2382 visitor->BeginVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2383 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2385 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2387 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, constant_);
2388 visitor->EndVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2392 std::vector<IntVar*> vars_;
2393 std::vector<int64_t> coefs_;
2394 Rev<int> first_unbound_backward_;
2395 Rev<int64_t> sum_of_bound_variables_;
2396 Rev<int64_t> sum_of_all_variables_;
2398 Rev<int64_t> max_coefficient_;
2403#define IS_TYPE(type, tag) type.compare(ModelVisitor::tag) == 0
2405class ExprLinearizer :
public ModelParser {
2407 explicit ExprLinearizer(
2408 absl::flat_hash_map<IntVar*, int64_t>*
const variables_to_coefficients)
2409 : variables_to_coefficients_(variables_to_coefficients), constant_(0) {}
2411 ~ExprLinearizer()
override {}
2414 void BeginVisitModel(
const std::string& solver_name)
override {
2415 LOG(FATAL) <<
"Should not be here";
2418 void EndVisitModel(
const std::string& solver_name)
override {
2419 LOG(FATAL) <<
"Should not be here";
2422 void BeginVisitConstraint(
const std::string& type_name,
2423 const Constraint*
const constraint)
override {
2424 LOG(FATAL) <<
"Should not be here";
2427 void EndVisitConstraint(
const std::string& type_name,
2428 const Constraint*
const constraint)
override {
2429 LOG(FATAL) <<
"Should not be here";
2432 void BeginVisitExtension(
const std::string& type)
override {}
2434 void EndVisitExtension(
const std::string& type)
override {}
2435 void BeginVisitIntegerExpression(
const std::string& type_name,
2436 const IntExpr*
const expr)
override {
2440 void EndVisitIntegerExpression(
const std::string& type_name,
2441 const IntExpr*
const expr)
override {
2442 if (
IS_TYPE(type_name, kSum)) {
2444 }
else if (
IS_TYPE(type_name, kScalProd)) {
2445 VisitScalProd(expr);
2446 }
else if (
IS_TYPE(type_name, kDifference)) {
2447 VisitDifference(expr);
2448 }
else if (
IS_TYPE(type_name, kOpposite)) {
2449 VisitOpposite(expr);
2450 }
else if (
IS_TYPE(type_name, kProduct)) {
2452 }
else if (
IS_TYPE(type_name, kTrace)) {
2455 VisitIntegerExpression(expr);
2460 void VisitIntegerVariable(
const IntVar*
const variable,
2461 const std::string& operation, int64_t value,
2462 IntVar*
const delegate)
override {
2463 if (operation == ModelVisitor::kSumOperation) {
2465 VisitSubExpression(delegate);
2466 }
else if (operation == ModelVisitor::kDifferenceOperation) {
2469 VisitSubExpression(delegate);
2471 }
else if (operation == ModelVisitor::kProductOperation) {
2472 PushMultiplier(value);
2473 VisitSubExpression(delegate);
2475 }
else if (operation == ModelVisitor::kTraceOperation) {
2476 VisitSubExpression(delegate);
2480 void VisitIntegerVariable(
const IntVar*
const variable,
2481 IntExpr*
const delegate)
override {
2482 if (delegate !=
nullptr) {
2483 VisitSubExpression(delegate);
2485 if (variable->Bound()) {
2486 AddConstant(variable->Min());
2488 RegisterExpression(variable, 1);
2494 void VisitIntegerArgument(
const std::string& arg_name,
2495 int64_t value)
override {
2496 Top()->SetIntegerArgument(arg_name, value);
2499 void VisitIntegerArrayArgument(
const std::string& arg_name,
2500 const std::vector<int64_t>& values)
override {
2501 Top()->SetIntegerArrayArgument(arg_name, values);
2504 void VisitIntegerMatrixArgument(
const std::string& arg_name,
2505 const IntTupleSet& values)
override {
2506 Top()->SetIntegerMatrixArgument(arg_name, values);
2510 void VisitIntegerExpressionArgument(
const std::string& arg_name,
2511 IntExpr*
const argument)
override {
2512 Top()->SetIntegerExpressionArgument(arg_name, argument);
2515 void VisitIntegerVariableArrayArgument(
2516 const std::string& arg_name,
2517 const std::vector<IntVar*>& arguments)
override {
2518 Top()->SetIntegerVariableArrayArgument(arg_name, arguments);
2522 void VisitIntervalArgument(
const std::string& arg_name,
2523 IntervalVar*
const argument)
override {}
2525 void VisitIntervalArrayArgument(
2526 const std::string& arg_name,
2527 const std::vector<IntervalVar*>& argument)
override {}
2529 void Visit(
const IntExpr*
const expr, int64_t multiplier) {
2530 if (expr->Min() == expr->Max()) {
2531 constant_ = CapAdd(constant_, CapProd(expr->Min(), multiplier));
2533 PushMultiplier(multiplier);
2539 int64_t Constant()
const {
return constant_; }
2541 std::string DebugString()
const override {
return "ExprLinearizer"; }
2544 void BeginVisit(
bool active) { PushArgumentHolder(); }
2546 void EndVisit() { PopArgumentHolder(); }
2548 void VisitSubExpression(
const IntExpr*
const cp_expr) {
2549 cp_expr->Accept(
this);
2552 void VisitSum(
const IntExpr*
const cp_expr) {
2553 if (Top()->HasIntegerVariableArrayArgument(ModelVisitor::kVarsArgument)) {
2554 const std::vector<IntVar*>& cp_vars =
2555 Top()->FindIntegerVariableArrayArgumentOrDie(
2556 ModelVisitor::kVarsArgument);
2557 for (
int i = 0; i < cp_vars.size(); ++i) {
2558 VisitSubExpression(cp_vars[i]);
2560 }
else if (Top()->HasIntegerExpressionArgument(
2561 ModelVisitor::kLeftArgument)) {
2562 const IntExpr*
const left = Top()->FindIntegerExpressionArgumentOrDie(
2563 ModelVisitor::kLeftArgument);
2564 const IntExpr*
const right = Top()->FindIntegerExpressionArgumentOrDie(
2565 ModelVisitor::kRightArgument);
2566 VisitSubExpression(left);
2567 VisitSubExpression(right);
2569 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2570 ModelVisitor::kExpressionArgument);
2571 const int64_t value =
2572 Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2573 VisitSubExpression(expr);
2578 void VisitScalProd(
const IntExpr*
const cp_expr) {
2579 const std::vector<IntVar*>& cp_vars =
2580 Top()->FindIntegerVariableArrayArgumentOrDie(
2581 ModelVisitor::kVarsArgument);
2582 const std::vector<int64_t>& cp_coefficients =
2583 Top()->FindIntegerArrayArgumentOrDie(
2584 ModelVisitor::kCoefficientsArgument);
2585 CHECK_EQ(cp_vars.size(), cp_coefficients.size());
2586 for (
int i = 0; i < cp_vars.size(); ++i) {
2587 const int64_t coefficient = cp_coefficients[i];
2588 PushMultiplier(coefficient);
2589 VisitSubExpression(cp_vars[i]);
2594 void VisitDifference(
const IntExpr*
const cp_expr) {
2595 if (Top()->HasIntegerExpressionArgument(ModelVisitor::kLeftArgument)) {
2596 const IntExpr*
const left = Top()->FindIntegerExpressionArgumentOrDie(
2597 ModelVisitor::kLeftArgument);
2598 const IntExpr*
const right = Top()->FindIntegerExpressionArgumentOrDie(
2599 ModelVisitor::kRightArgument);
2600 VisitSubExpression(left);
2602 VisitSubExpression(right);
2605 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2606 ModelVisitor::kExpressionArgument);
2607 const int64_t value =
2608 Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2611 VisitSubExpression(expr);
2616 void VisitOpposite(
const IntExpr*
const cp_expr) {
2617 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2618 ModelVisitor::kExpressionArgument);
2620 VisitSubExpression(expr);
2624 void VisitProduct(
const IntExpr*
const cp_expr) {
2625 if (Top()->HasIntegerExpressionArgument(
2626 ModelVisitor::kExpressionArgument)) {
2627 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2628 ModelVisitor::kExpressionArgument);
2629 const int64_t value =
2630 Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2631 PushMultiplier(value);
2632 VisitSubExpression(expr);
2635 RegisterExpression(cp_expr, 1);
2639 void VisitTrace(
const IntExpr*
const cp_expr) {
2640 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2641 ModelVisitor::kExpressionArgument);
2642 VisitSubExpression(expr);
2645 void VisitIntegerExpression(
const IntExpr*
const cp_expr) {
2646 RegisterExpression(cp_expr, 1);
2649 void RegisterExpression(
const IntExpr*
const expr, int64_t coef) {
2651 (*variables_to_coefficients_)[
const_cast<IntExpr*
>(expr)->Var()];
2652 value = CapAdd(value, CapProd(coef, multipliers_.back()));
2655 void AddConstant(int64_t constant) {
2656 constant_ = CapAdd(constant_, CapProd(constant, multipliers_.back()));
2659 void PushMultiplier(int64_t multiplier) {
2660 if (multipliers_.empty()) {
2661 multipliers_.push_back(multiplier);
2663 multipliers_.push_back(CapProd(multiplier, multipliers_.back()));
2667 void PopMultiplier() { multipliers_.pop_back(); }
2671 absl::flat_hash_map<IntVar*, int64_t>*
const variables_to_coefficients_;
2672 std::vector<int64_t> multipliers_;
2679void DeepLinearize(Solver*
const solver,
const std::vector<IntVar*>& pre_vars,
2680 absl::Span<const int64_t> pre_coefs,
2681 std::vector<IntVar*>* vars, std::vector<int64_t>* coefs,
2682 int64_t* constant) {
2683 CHECK(solver !=
nullptr);
2684 CHECK(vars !=
nullptr);
2685 CHECK(coefs !=
nullptr);
2686 CHECK(constant !=
nullptr);
2688 vars->reserve(pre_vars.size());
2689 coefs->reserve(pre_coefs.size());
2691 bool need_linearization =
false;
2692 for (
int i = 0;
i < pre_vars.size(); ++
i) {
2693 IntVar*
const variable = pre_vars[
i];
2694 const int64_t coefficient = pre_coefs[
i];
2695 if (variable->Bound()) {
2696 *constant =
CapAdd(*constant,
CapProd(coefficient, variable->Min()));
2697 }
else if (solver->CastExpression(variable) ==
nullptr) {
2698 vars->push_back(variable);
2699 coefs->push_back(coefficient);
2701 need_linearization =
true;
2707 if (need_linearization) {
2709 absl::flat_hash_map<IntVar*, int64_t> variables_to_coefficients;
2710 ExprLinearizer linearizer(&variables_to_coefficients);
2711 for (
int i = 0;
i < pre_vars.size(); ++
i) {
2712 linearizer.Visit(pre_vars[i], pre_coefs[i]);
2714 *constant = linearizer.Constant();
2715 for (
const auto& variable_to_coefficient : variables_to_coefficients) {
2716 if (variable_to_coefficient.second != 0) {
2717 vars->push_back(variable_to_coefficient.first);
2718 coefs->push_back(variable_to_coefficient.second);
2724Constraint* MakeScalProdEqualityFct(Solver*
const solver,
2725 const std::vector<IntVar*>& pre_vars,
2726 absl::Span<const int64_t> pre_coefs,
2728 int64_t constant = 0;
2729 std::vector<IntVar*> vars;
2730 std::vector<int64_t> coefs;
2731 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2732 cst =
CapSub(cst, constant);
2734 const int size = vars.size();
2736 return cst == 0 ? solver->MakeTrueConstraint()
2737 : solver->MakeFalseConstraint();
2741 for (
int i = 0;
i < size; ++
i) {
2744 return sum == cst ? solver->MakeTrueConstraint()
2745 : solver->MakeFalseConstraint();
2748 return solver->MakeSumEquality(vars, cst);
2752 return solver->RevAlloc(
2753 new PositiveBooleanScalProdEqCst(solver, vars, coefs, cst));
2756 std::vector<int64_t> opp_coefs(coefs.size());
2757 for (
int i = 0;
i < coefs.size(); ++
i) {
2758 opp_coefs[
i] = -coefs[
i];
2760 return solver->RevAlloc(
2761 new PositiveBooleanScalProdEqCst(solver, vars, opp_coefs, -cst));
2769 for (
int i = 0;
i < size; ++
i) {
2770 if (coefs[i] == 0 || vars[i]->Bound()) {
2772 }
else if (coefs[i] > 0) {
2778 if (positives > 0 && negatives > 0) {
2779 std::vector<IntVar*> pos_terms;
2780 std::vector<IntVar*> neg_terms;
2782 for (
int i = 0;
i < size; ++
i) {
2783 if (coefs[i] == 0 || vars[i]->Bound()) {
2785 }
else if (coefs[i] > 0) {
2786 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2788 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2791 if (negatives == 1) {
2793 pos_terms.push_back(solver->MakeIntConst(-rhs));
2795 return solver->MakeSumEquality(pos_terms, neg_terms[0]);
2796 }
else if (positives == 1) {
2798 neg_terms.push_back(solver->MakeIntConst(rhs));
2800 return solver->MakeSumEquality(neg_terms, pos_terms[0]);
2803 neg_terms.push_back(solver->MakeIntConst(rhs));
2805 return solver->MakeEquality(solver->MakeSum(pos_terms),
2806 solver->MakeSum(neg_terms));
2808 }
else if (positives == 1) {
2809 IntExpr* pos_term =
nullptr;
2811 for (
int i = 0;
i < size; ++
i) {
2812 if (coefs[i] == 0 || vars[i]->Bound()) {
2814 }
else if (coefs[i] > 0) {
2815 pos_term = solver->MakeProd(vars[i], coefs[i]);
2817 LOG(FATAL) <<
"Should not be here";
2820 return solver->MakeEquality(pos_term, rhs);
2821 }
else if (negatives == 1) {
2822 IntExpr* neg_term =
nullptr;
2824 for (
int i = 0;
i < size; ++
i) {
2825 if (coefs[i] == 0 || vars[i]->Bound()) {
2827 }
else if (coefs[i] > 0) {
2828 LOG(FATAL) <<
"Should not be here";
2830 neg_term = solver->MakeProd(vars[i], -coefs[i]);
2833 return solver->MakeEquality(neg_term, -rhs);
2834 }
else if (positives > 1) {
2835 std::vector<IntVar*> pos_terms;
2837 for (
int i = 0;
i < size; ++
i) {
2838 if (coefs[i] == 0 || vars[i]->Bound()) {
2840 }
else if (coefs[i] > 0) {
2841 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2843 LOG(FATAL) <<
"Should not be here";
2846 return solver->MakeSumEquality(pos_terms, rhs);
2847 }
else if (negatives > 1) {
2848 std::vector<IntVar*> neg_terms;
2850 for (
int i = 0;
i < size; ++
i) {
2851 if (coefs[i] == 0 || vars[i]->Bound()) {
2853 }
else if (coefs[i] > 0) {
2854 LOG(FATAL) <<
"Should not be here";
2856 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2859 return solver->MakeSumEquality(neg_terms, -rhs);
2861 std::vector<IntVar*> terms;
2862 for (
int i = 0;
i < size; ++
i) {
2863 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2865 return solver->MakeSumEquality(terms, solver->MakeIntConst(cst));
2868Constraint* MakeScalProdEqualityVarFct(Solver*
const solver,
2869 const std::vector<IntVar*>& pre_vars,
2870 absl::Span<const int64_t> pre_coefs,
2871 IntVar*
const target) {
2872 int64_t constant = 0;
2873 std::vector<IntVar*> vars;
2874 std::vector<int64_t> coefs;
2875 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2877 const int size = vars.size();
2878 if (size == 0 || AreAllNull<int64_t>(coefs)) {
2879 return solver->MakeEquality(target, constant);
2882 return solver->MakeSumEquality(vars,
2883 solver->MakeSum(target, -constant)->Var());
2887 return solver->RevAlloc(
new PositiveBooleanScalProdEqVar(
2888 solver, vars, coefs, solver->MakeSum(target, -constant)->Var()));
2890 std::vector<IntVar*> terms;
2891 for (
int i = 0;
i < size; ++
i) {
2892 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2894 return solver->MakeSumEquality(terms,
2895 solver->MakeSum(target, -constant)->Var());
2898Constraint* MakeScalProdGreaterOrEqualFct(Solver* solver,
2899 const std::vector<IntVar*>& pre_vars,
2900 absl::Span<const int64_t> pre_coefs,
2902 int64_t constant = 0;
2903 std::vector<IntVar*> vars;
2904 std::vector<int64_t> coefs;
2905 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2906 cst =
CapSub(cst, constant);
2908 const int size = vars.size();
2909 if (size == 0 || AreAllNull<int64_t>(coefs)) {
2910 return cst <= 0 ? solver->MakeTrueConstraint()
2911 : solver->MakeFalseConstraint();
2914 return solver->MakeSumGreaterOrEqual(vars, cst);
2918 std::vector<IntVar*> terms;
2919 for (
int i = 0;
i < size; ++
i) {
2921 terms.push_back(vars[i]);
2924 return solver->MakeSumGreaterOrEqual(terms, 1);
2926 std::vector<IntVar*> terms;
2927 for (
int i = 0;
i < size; ++
i) {
2928 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2930 return solver->MakeSumGreaterOrEqual(terms, cst);
2933Constraint* MakeScalProdLessOrEqualFct(Solver* solver,
2934 const std::vector<IntVar*>& pre_vars,
2935 absl::Span<const int64_t> pre_coefs,
2936 int64_t upper_bound) {
2937 int64_t constant = 0;
2938 std::vector<IntVar*> vars;
2939 std::vector<int64_t> coefs;
2940 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2941 upper_bound =
CapSub(upper_bound, constant);
2943 const int size = vars.size();
2944 if (size == 0 || AreAllNull<int64_t>(coefs)) {
2945 return upper_bound >= 0 ? solver->MakeTrueConstraint()
2946 : solver->MakeFalseConstraint();
2951 for (
int i = 0;
i < size; ++
i) {
2954 return cst <= upper_bound ? solver->MakeTrueConstraint()
2955 : solver->MakeFalseConstraint();
2958 return solver->MakeSumLessOrEqual(vars, upper_bound);
2961 return solver->RevAlloc(
2962 new BooleanScalProdLessConstant(solver, vars, coefs, upper_bound));
2968 for (
int i = 0;
i < size; ++
i) {
2969 if (coefs[i] == 0 || vars[i]->Bound()) {
2971 }
else if (coefs[i] > 0) {
2977 if (positives > 0 && negatives > 0) {
2978 std::vector<IntVar*> pos_terms;
2979 std::vector<IntVar*> neg_terms;
2980 int64_t rhs = upper_bound;
2981 for (
int i = 0;
i < size; ++
i) {
2982 if (coefs[i] == 0 || vars[i]->Bound()) {
2984 }
else if (coefs[i] > 0) {
2985 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2987 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2990 if (negatives == 1) {
2991 IntExpr*
const neg_term = solver->MakeSum(neg_terms[0], rhs);
2992 return solver->MakeLessOrEqual(solver->MakeSum(pos_terms), neg_term);
2993 }
else if (positives == 1) {
2994 IntExpr*
const pos_term = solver->MakeSum(pos_terms[0], -rhs);
2995 return solver->MakeGreaterOrEqual(solver->MakeSum(neg_terms), pos_term);
2998 neg_terms.push_back(solver->MakeIntConst(rhs));
3000 return solver->MakeLessOrEqual(solver->MakeSum(pos_terms),
3001 solver->MakeSum(neg_terms));
3003 }
else if (positives == 1) {
3004 IntExpr* pos_term =
nullptr;
3005 int64_t rhs = upper_bound;
3006 for (
int i = 0;
i < size; ++
i) {
3007 if (coefs[i] == 0 || vars[i]->Bound()) {
3009 }
else if (coefs[i] > 0) {
3010 pos_term = solver->MakeProd(vars[i], coefs[i]);
3012 LOG(FATAL) <<
"Should not be here";
3015 return solver->MakeLessOrEqual(pos_term, rhs);
3016 }
else if (negatives == 1) {
3017 IntExpr* neg_term =
nullptr;
3018 int64_t rhs = upper_bound;
3019 for (
int i = 0;
i < size; ++
i) {
3020 if (coefs[i] == 0 || vars[i]->Bound()) {
3022 }
else if (coefs[i] > 0) {
3023 LOG(FATAL) <<
"Should not be here";
3025 neg_term = solver->MakeProd(vars[i], -coefs[i]);
3028 return solver->MakeGreaterOrEqual(neg_term, -rhs);
3029 }
else if (positives > 1) {
3030 std::vector<IntVar*> pos_terms;
3031 int64_t rhs = upper_bound;
3032 for (
int i = 0;
i < size; ++
i) {
3033 if (coefs[i] == 0 || vars[i]->Bound()) {
3035 }
else if (coefs[i] > 0) {
3036 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3038 LOG(FATAL) <<
"Should not be here";
3041 return solver->MakeSumLessOrEqual(pos_terms, rhs);
3042 }
else if (negatives > 1) {
3043 std::vector<IntVar*> neg_terms;
3044 int64_t rhs = upper_bound;
3045 for (
int i = 0;
i < size; ++
i) {
3046 if (coefs[i] == 0 || vars[i]->Bound()) {
3048 }
else if (coefs[i] > 0) {
3049 LOG(FATAL) <<
"Should not be here";
3051 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
3054 return solver->MakeSumGreaterOrEqual(neg_terms, -rhs);
3056 std::vector<IntVar*> terms;
3057 for (
int i = 0;
i < size; ++
i) {
3058 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3060 return solver->MakeLessOrEqual(solver->MakeSum(terms), upper_bound);
3063IntExpr* MakeSumArrayAux(Solver*
const solver,
const std::vector<IntVar*>& vars,
3065 const int size = vars.size();
3067 int64_t new_min = 0;
3068 int64_t new_max = 0;
3069 for (
int i = 0;
i < size; ++
i) {
3070 if (new_min != std::numeric_limits<int64_t>::min()) {
3071 new_min =
CapAdd(vars[i]->Min(), new_min);
3073 if (new_max != std::numeric_limits<int64_t>::max()) {
3074 new_max =
CapAdd(vars[i]->Max(), new_max);
3077 IntExpr*
const cache =
3078 solver->Cache()->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_SUM);
3079 if (cache !=
nullptr) {
3080 return solver->MakeSum(cache, constant);
3082 const std::string name =
3083 absl::StrFormat(
"Sum([%s])",
JoinNamePtr(vars,
", "));
3084 IntVar*
const sum_var = solver->MakeIntVar(new_min, new_max, name);
3086 solver->AddConstraint(
3087 solver->RevAlloc(
new SumBooleanEqualToVar(solver, vars, sum_var)));
3088 }
else if (size <= solver->parameters().array_split_size()) {
3089 solver->AddConstraint(
3090 solver->RevAlloc(
new SmallSumConstraint(solver, vars, sum_var)));
3092 solver->AddConstraint(
3093 solver->RevAlloc(
new SumConstraint(solver, vars, sum_var)));
3095 solver->Cache()->InsertVarArrayExpression(sum_var, vars,
3096 ModelCache::VAR_ARRAY_SUM);
3097 return solver->MakeSum(sum_var, constant);
3101IntExpr* MakeSumAux(Solver*
const solver,
const std::vector<IntVar*>& vars,
3103 const int size = vars.size();
3105 return solver->MakeIntConst(constant);
3106 }
else if (size == 1) {
3107 return solver->MakeSum(vars[0], constant);
3108 }
else if (size == 2) {
3109 return solver->MakeSum(solver->MakeSum(vars[0], vars[1]), constant);
3111 return MakeSumArrayAux(solver, vars, constant);
3115IntExpr* MakeScalProdAux(Solver* solver,
const std::vector<IntVar*>& vars,
3116 const std::vector<int64_t>& coefs, int64_t constant) {
3118 return MakeSumAux(solver, vars, constant);
3121 const int size = vars.size();
3123 return solver->MakeIntConst(constant);
3124 }
else if (size == 1) {
3125 return solver->MakeSum(solver->MakeProd(vars[0], coefs[0]), constant);
3126 }
else if (size == 2) {
3127 if (coefs[0] > 0 && coefs[1] < 0) {
3128 return solver->MakeSum(
3129 solver->MakeDifference(solver->MakeProd(vars[0], coefs[0]),
3130 solver->MakeProd(vars[1], -coefs[1])),
3132 }
else if (coefs[0] < 0 && coefs[1] > 0) {
3133 return solver->MakeSum(
3134 solver->MakeDifference(solver->MakeProd(vars[1], coefs[1]),
3135 solver->MakeProd(vars[0], -coefs[0])),
3138 return solver->MakeSum(
3139 solver->MakeSum(solver->MakeProd(vars[0], coefs[0]),
3140 solver->MakeProd(vars[1], coefs[1])),
3146 if (vars.size() > 8) {
3147 return solver->MakeSum(
3149 ->RegisterIntExpr(solver->RevAlloc(
3150 new PositiveBooleanScalProd(solver, vars, coefs)))
3154 return solver->MakeSum(
3155 solver->RegisterIntExpr(solver->RevAlloc(
3156 new PositiveBooleanScalProd(solver, vars, coefs))),
3167 std::vector<int64_t> positive_coefs;
3168 std::vector<int64_t> negative_coefs;
3169 std::vector<IntVar*> positive_coef_vars;
3170 std::vector<IntVar*> negative_coef_vars;
3171 for (
int i = 0;
i < size; ++
i) {
3172 const int coef = coefs[
i];
3174 positive_coefs.push_back(coef);
3175 positive_coef_vars.push_back(vars[i]);
3176 }
else if (coef < 0) {
3177 negative_coefs.push_back(-coef);
3178 negative_coef_vars.push_back(vars[i]);
3181 CHECK_GT(negative_coef_vars.size(), 0);
3182 IntExpr*
const negatives =
3183 MakeScalProdAux(solver, negative_coef_vars, negative_coefs, 0);
3184 if (!positive_coef_vars.empty()) {
3185 IntExpr*
const positives = MakeScalProdAux(solver, positive_coef_vars,
3186 positive_coefs, constant);
3187 return solver->MakeDifference(positives, negatives);
3189 return solver->MakeDifference(constant, negatives);
3194 std::vector<IntVar*> terms;
3195 for (
int i = 0;
i < size; ++
i) {
3196 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3198 return MakeSumArrayAux(solver, terms, constant);
3201IntExpr* MakeScalProdFct(Solver* solver,
const std::vector<IntVar*>& pre_vars,
3202 absl::Span<const int64_t> pre_coefs) {
3203 int64_t constant = 0;
3204 std::vector<IntVar*> vars;
3205 std::vector<int64_t> coefs;
3206 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
3209 return solver->MakeIntConst(constant);
3212 int64_t gcd = std::abs(coefs[0]);
3213 for (
int i = 1;
i < coefs.size(); ++
i) {
3214 gcd = MathUtil::GCD64(gcd, std::abs(coefs[i]));
3219 if (constant != 0 && gcd != 1) {
3220 gcd = MathUtil::GCD64(gcd, std::abs(constant));
3223 for (
int i = 0;
i < coefs.size(); ++
i) {
3226 return solver->MakeProd(
3227 MakeScalProdAux(solver, vars, coefs, constant / gcd), gcd);
3229 return MakeScalProdAux(solver, vars, coefs, constant);
3232IntExpr* MakeSumFct(Solver* solver,
const std::vector<IntVar*>& pre_vars) {
3233 absl::flat_hash_map<IntVar*, int64_t> variables_to_coefficients;
3234 ExprLinearizer linearizer(&variables_to_coefficients);
3235 for (
int i = 0;
i < pre_vars.size(); ++
i) {
3236 linearizer.Visit(pre_vars[i], 1);
3238 const int64_t constant = linearizer.Constant();
3239 std::vector<IntVar*> vars;
3240 std::vector<int64_t> coefs;
3241 for (
const auto& variable_to_coefficient : variables_to_coefficients) {
3242 if (variable_to_coefficient.second != 0) {
3243 vars.push_back(variable_to_coefficient.first);
3244 coefs.push_back(variable_to_coefficient.second);
3247 return MakeScalProdAux(solver, vars, coefs, constant);
3254 const int size = vars.size();
3257 }
else if (size == 1) {
3259 }
else if (size == 2) {
3260 return MakeSum(vars[0], vars[1]);
3264 if (cache !=
nullptr) {
3267 int64_t new_min = 0;
3268 int64_t new_max = 0;
3269 for (
int i = 0; i < size; ++i) {
3270 if (new_min != std::numeric_limits<int64_t>::min()) {
3271 new_min =
CapAdd(vars[i]->Min(), new_min);
3273 if (new_max != std::numeric_limits<int64_t>::max()) {
3274 new_max =
CapAdd(vars[i]->Max(), new_max);
3280 const std::string name =
3281 absl::StrFormat(
"BooleanSum([%s])",
JoinNamePtr(vars,
", "));
3282 sum_expr =
MakeIntVar(new_min, new_max, name);
3284 RevAlloc(
new SumBooleanEqualToVar(
this, vars, sum_expr->
Var())));
3285 }
else if (new_min != std::numeric_limits<int64_t>::min() &&
3286 new_max != std::numeric_limits<int64_t>::max()) {
3287 sum_expr = MakeSumFct(
this, vars);
3289 const std::string name =
3290 absl::StrFormat(
"Sum([%s])",
JoinNamePtr(vars,
", "));
3291 sum_expr =
MakeIntVar(new_min, new_max, name);
3293 RevAlloc(
new SafeSumConstraint(
this, vars, sum_expr->
Var())));
3295 model_cache_->InsertVarArrayExpression(sum_expr, vars,
3303 const int size = vars.size();
3305 LOG(WARNING) <<
"operations_research::Solver::MakeMin() was called with an "
3306 "empty list of variables. Was this intentional?";
3307 return MakeIntConst(std::numeric_limits<int64_t>::max());
3308 }
else if (size == 1) {
3310 }
else if (size == 2) {
3311 return MakeMin(vars[0], vars[1]);
3315 if (cache !=
nullptr) {
3321 model_cache_->InsertVarArrayExpression(new_var, vars,
3325 int64_t new_min = std::numeric_limits<int64_t>::max();
3326 int64_t new_max = std::numeric_limits<int64_t>::max();
3327 for (
int i = 0; i < size; ++i) {
3328 new_min = std::min(new_min, vars[i]->Min());
3329 new_max = std::min(new_max, vars[i]->Max());
3332 if (size <= parameters_.array_split_size()) {
3337 model_cache_->InsertVarArrayExpression(new_var, vars,
3346 const int size = vars.size();
3348 LOG(WARNING) <<
"operations_research::Solver::MakeMax() was called with an "
3349 "empty list of variables. Was this intentional?";
3350 return MakeIntConst(std::numeric_limits<int64_t>::min());
3351 }
else if (size == 1) {
3353 }
else if (size == 2) {
3354 return MakeMax(vars[0], vars[1]);
3358 if (cache !=
nullptr) {
3364 model_cache_->InsertVarArrayExpression(new_var, vars,
3368 int64_t new_min = std::numeric_limits<int64_t>::min();
3369 int64_t new_max = std::numeric_limits<int64_t>::min();
3370 for (
int i = 0; i < size; ++i) {
3371 new_min = std::max(new_min, vars[i]->Min());
3372 new_max = std::max(new_max, vars[i]->Max());
3375 if (size <= parameters_.array_split_size()) {
3380 model_cache_->InsertVarArrayExpression(new_var, vars,
3390 const int size = vars.size();
3393 return RevAlloc(
new ArrayBoolAndEq(
this, vars, min_var));
3394 }
else if (size <= parameters_.array_split_size()) {
3395 return RevAlloc(
new SmallMinConstraint(
this, vars, min_var));
3397 return RevAlloc(
new MinConstraint(
this, vars, min_var));
3399 }
else if (size == 2) {
3401 }
else if (size == 1) {
3404 LOG(WARNING) <<
"operations_research::Solver::MakeMinEquality() was called "
3405 "with an empty list of variables. Was this intentional?";
3406 return MakeEquality(min_var, std::numeric_limits<int64_t>::max());
3412 const int size = vars.size();
3415 return RevAlloc(
new ArrayBoolOrEq(
this, vars, max_var));
3416 }
else if (size <= parameters_.array_split_size()) {
3417 return RevAlloc(
new SmallMaxConstraint(
this, vars, max_var));
3419 return RevAlloc(
new MaxConstraint(
this, vars, max_var));
3421 }
else if (size == 2) {
3423 }
else if (size == 1) {
3426 LOG(WARNING) <<
"operations_research::Solver::MakeMaxEquality() was called "
3427 "with an empty list of variables. Was this intentional?";
3428 return MakeEquality(max_var, std::numeric_limits<int64_t>::min());
3434 const int size = vars.size();
3436 return RevAlloc(
new SumBooleanLessOrEqualToOne(
this, vars));
3444 const int size = vars.size();
3446 return RevAlloc(
new SumBooleanGreaterOrEqualToOne(
this, vars));
3454 const int size = vars.size();
3460 return RevAlloc(
new SumBooleanEqualToOne(
this, vars));
3461 }
else if (cst < 0 || cst > size) {
3467 if (vars.size() == 1) {
3469 }
else if (vars.size() == 2) {
3472 if (DetectSumOverflow(vars)) {
3474 }
else if (size <= parameters_.array_split_size()) {
3484 const int size = vars.size();
3489 return RevAlloc(
new SumBooleanEqualToVar(
this, vars, var));
3490 }
else if (size == 0) {
3492 }
else if (size == 1) {
3494 }
else if (size == 2) {
3497 if (DetectSumOverflow(vars)) {
3498 return RevAlloc(
new SafeSumConstraint(
this, vars, var));
3499 }
else if (size <= parameters_.array_split_size()) {
3500 return RevAlloc(
new SmallSumConstraint(
this, vars, var));
3502 return RevAlloc(
new SumConstraint(
this, vars, var));
3508 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& coefficients,
3510 DCHECK_EQ(vars.size(), coefficients.size());
3511 return MakeScalProdEqualityFct(
this, vars, coefficients, cst);
3515 const std::vector<int>& coefficients,
3517 DCHECK_EQ(vars.size(), coefficients.size());
3518 return MakeScalProdEqualityFct(
this, vars,
ToInt64Vector(coefficients), cst);
3522 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& coefficients,
3524 DCHECK_EQ(vars.size(), coefficients.size());
3525 return MakeScalProdEqualityVarFct(
this, vars, coefficients, target);
3529 const std::vector<int>& coefficients,
3531 DCHECK_EQ(vars.size(), coefficients.size());
3532 return MakeScalProdEqualityVarFct(
this, vars,
ToInt64Vector(coefficients),
3537 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& coeffs,
3539 DCHECK_EQ(vars.size(), coeffs.size());
3540 return MakeScalProdGreaterOrEqualFct(
this, vars, coeffs, cst);
3544 const std::vector<int>& coeffs,
3546 DCHECK_EQ(vars.size(), coeffs.size());
3547 return MakeScalProdGreaterOrEqualFct(
this, vars,
ToInt64Vector(coeffs), cst);
3551 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& coefficients,
3553 DCHECK_EQ(vars.size(), coefficients.size());
3554 return MakeScalProdLessOrEqualFct(
this, vars, coefficients, cst);
3558 const std::vector<IntVar*>& vars,
const std::vector<int>& coefficients,
3560 DCHECK_EQ(vars.size(), coefficients.size());
3561 return MakeScalProdLessOrEqualFct(
this, vars,
ToInt64Vector(coefficients),
3566 const std::vector<int64_t>& coefs) {
3567 DCHECK_EQ(vars.size(), coefs.size());
3568 return MakeScalProdFct(
this, vars, coefs);
3572 const std::vector<int>& coefs) {
3573 DCHECK_EQ(vars.size(), coefs.size());
virtual IntVar * Var()=0
Creates a variable from the expression.
static const char kMinEqual[]
static const char kTargetArgument[]
static const char kSumGreaterOrEqual[]
static const char kValueArgument[]
static const char kMaxEqual[]
static const char kSumLessOrEqual[]
static const char kVarsArgument[]
static const char kSumEqual[]
Constraint * MakeScalProdLessOrEqual(const std::vector< IntVar * > &vars, const std::vector< int64_t > &coefficients, int64_t cst)
IntExpr * MakeScalProd(const std::vector< IntVar * > &vars, const std::vector< int64_t > &coefs)
scalar product
Constraint * MakeSumEquality(const std::vector< IntVar * > &vars, int64_t cst)
IntVar * MakeBoolVar(const std::string &name)
MakeBoolVar will create a variable with a {0, 1} domain.
IntExpr * MakeMax(const std::vector< IntVar * > &vars)
std::max(vars)
IntExpr * MakeDifference(IntExpr *left, IntExpr *right)
left - right
Constraint * MakeGreaterOrEqual(IntExpr *left, IntExpr *right)
left >= right
IntExpr * MakeSum(IntExpr *left, IntExpr *right)
left + right.
Constraint * MakeScalProdEquality(const std::vector< IntVar * > &vars, const std::vector< int64_t > &coefficients, int64_t cst)
IntExpr * MakeMin(const std::vector< IntVar * > &vars)
std::min(vars)
Constraint * MakeSumLessOrEqual(const std::vector< IntVar * > &vars, int64_t cst)
Variation on arrays.
Constraint * MakeSumGreaterOrEqual(const std::vector< IntVar * > &vars, int64_t cst)
Constraint * MakeMinEquality(const std::vector< IntVar * > &vars, IntVar *min_var)
Constraint * MakeScalProdGreaterOrEqual(const std::vector< IntVar * > &vars, const std::vector< int64_t > &coeffs, int64_t cst)
Constraint * MakeMaxEquality(const std::vector< IntVar * > &vars, IntVar *max_var)
Constraint * MakeEquality(IntExpr *left, IntExpr *right)
left == right
Constraint * MakeTrueConstraint()
This constraint always succeeds.
Constraint * MakeLessOrEqual(IntExpr *left, IntExpr *right)
left <= right
IntVar * MakeIntVar(int64_t min, int64_t max, const std::string &name)
MakeIntVar will create the best range based int var for the bounds given.
Constraint * MakeFalseConstraint()
This constraint always fails.
IntVar * MakeIntConst(int64_t val, const std::string &name)
IntConst will create a constant expression.
void AddConstraint(Constraint *c)
Adds the constraint 'c' to the model.
#define IS_TYPE(type, tag)
std::pair< double, double > Range
int64_t CapAdd(int64_t x, int64_t y)
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
bool AreAllNegative(const std::vector< T > &values)
int64_t CapSub(int64_t x, int64_t y)
bool AreAllBoundOrNull(const std::vector< IntVar * > &vars, const std::vector< T > &values)
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
bool AreAllBooleans(const std::vector< IntVar * > &vars)
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
int64_t CapProd(int64_t x, int64_t y)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
bool AreAllNull(const std::vector< T > &values)
bool AreAllPositive(const std::vector< T > &values)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
bool AreAllOnes(const std::vector< T > &values)
std::string JoinNamePtr(const std::vector< T > &v, absl::string_view separator)
std::string DebugString() const