25#include "absl/strings/str_format.h"
26#include "absl/strings/str_join.h"
27#include "absl/strings/string_view.h"
28#include "absl/types/span.h"
41class TreeArrayConstraint :
public CastConstraint {
43 TreeArrayConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
44 IntVar*
const sum_var)
45 : CastConstraint(solver, sum_var),
47 block_size_(solver->
parameters().array_split_size()) {
48 std::vector<int> lengths;
49 lengths.push_back(
vars_.size());
50 while (lengths.back() > 1) {
51 const int current = lengths.back();
52 lengths.push_back((current + block_size_ - 1) / block_size_);
54 tree_.resize(lengths.size());
55 for (
int i = 0;
i < lengths.size(); ++
i) {
56 tree_[
i].resize(lengths[lengths.size() - i - 1]);
58 DCHECK_GE(tree_.size(), 1);
59 DCHECK_EQ(1, tree_[0].
size());
60 root_node_ = &tree_[0][0];
63 std::string DebugStringInternal(absl::string_view
name)
const {
64 return absl::StrFormat(
"%s(%s) == %s",
name,
66 target_var_->DebugString());
69 void AcceptInternal(
const std::string&
name,
70 ModelVisitor*
const visitor)
const {
71 visitor->BeginVisitConstraint(
name,
this);
76 visitor->EndVisitConstraint(
name,
this);
80 void ReduceRange(
int depth,
int position, int64_t delta_min,
82 NodeInfo*
const info = &tree_[depth][position];
84 info->node_min.SetValue(solver(),
85 CapAdd(info->node_min.Value(), delta_min));
88 info->node_max.SetValue(solver(),
89 CapSub(info->node_max.Value(), delta_max));
94 void SetRange(
int depth,
int position, int64_t new_min, int64_t new_max) {
95 NodeInfo*
const info = &tree_[depth][position];
96 if (new_min > info->node_min.Value()) {
97 info->node_min.SetValue(solver(), new_min);
99 if (new_max < info->
node_max.Value()) {
100 info->node_max.SetValue(solver(), new_max);
104 void InitLeaf(
int position, int64_t var_min, int64_t var_max) {
105 InitNode(MaxDepth(), position, var_min, var_max);
108 void InitNode(
int depth,
int position, int64_t
node_min, int64_t
node_max) {
109 tree_[depth][position].node_min.SetValue(solver(),
node_min);
110 tree_[depth][position].node_max.SetValue(solver(),
node_max);
113 int64_t Min(
int depth,
int position)
const {
114 return tree_[depth][position].node_min.Value();
117 int64_t Max(
int depth,
int position)
const {
118 return tree_[depth][position].node_max.Value();
121 int64_t RootMin()
const {
return root_node_->node_min.Value(); }
123 int64_t RootMax()
const {
return root_node_->node_max.Value(); }
125 int Parent(
int position)
const {
return position / block_size_; }
127 int ChildStart(
int position)
const {
return position * block_size_; }
129 int ChildEnd(
int depth,
int position)
const {
130 DCHECK_LT(depth + 1, tree_.size());
131 return std::min((position + 1) * block_size_ - 1, Width(depth + 1) - 1);
134 bool IsLeaf(
int depth)
const {
return depth == MaxDepth(); }
136 int MaxDepth()
const {
return tree_.size() - 1; }
138 int Width(
int depth)
const {
return tree_[depth].size(); }
150 std::vector<std::vector<NodeInfo> > tree_;
151 const int block_size_;
152 NodeInfo* root_node_;
167class SumConstraint :
public TreeArrayConstraint {
169 SumConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
170 IntVar*
const sum_var)
171 : TreeArrayConstraint(solver, vars, sum_var), sum_demon_(
nullptr) {}
173 ~SumConstraint()
override {}
175 void Post()
override {
176 for (
int i = 0;
i <
vars_.size(); ++
i) {
178 solver(),
this, &SumConstraint::LeafChanged,
"LeafChanged", i);
179 vars_[
i]->WhenRange(demon);
182 solver(),
this, &SumConstraint::SumChanged,
"SumChanged"));
183 target_var_->WhenRange(sum_demon_);
186 void InitialPropagate()
override {
188 for (
int i = 0;
i <
vars_.size(); ++
i) {
189 InitLeaf(i,
vars_[i]->Min(),
vars_[i]->Max());
192 for (
int i = MaxDepth() - 1;
i >= 0; --
i) {
193 for (
int j = 0; j < Width(i); ++j) {
196 const int block_start = ChildStart(j);
197 const int block_end = ChildEnd(i, j);
198 for (
int k = block_start; k <= block_end; ++k) {
199 sum_min =
CapAdd(sum_min, Min(i + 1, k));
200 sum_max =
CapAdd(sum_max, Max(i + 1, k));
202 InitNode(i, j, sum_min, sum_max);
206 target_var_->SetRange(RootMin(), RootMax());
213 if (target_var_->Max() == RootMin() &&
214 target_var_->Max() != std::numeric_limits<int64_t>::max()) {
216 for (
int i = 0;
i <
vars_.size(); ++
i) {
219 }
else if (target_var_->Min() == RootMax() &&
220 target_var_->Min() != std::numeric_limits<int64_t>::min()) {
222 for (
int i = 0;
i <
vars_.size(); ++
i) {
226 PushDown(0, 0, target_var_->Min(), target_var_->Max());
230 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
232 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
238 vars_[position]->SetRange(new_min, new_max);
246 const int64_t sum_min = Min(depth, position);
247 const int64_t sum_max = Max(depth, position);
250 new_max = std::min(sum_max, new_max);
251 new_min = std::max(sum_min, new_min);
254 if (new_max < sum_min || new_min > sum_max) {
259 const int block_start = ChildStart(position);
260 const int block_end = ChildEnd(depth, position);
261 for (
int i = block_start;
i <= block_end; ++
i) {
262 const int64_t target_var_min = Min(depth + 1, i);
263 const int64_t target_var_max = Max(depth + 1, i);
264 const int64_t residual_min =
CapSub(sum_min, target_var_min);
265 const int64_t residual_max =
CapSub(sum_max, target_var_max);
266 PushDown(depth + 1, i,
CapSub(new_min, residual_max),
267 CapSub(new_max, residual_min));
273 void LeafChanged(
int term_index) {
274 IntVar*
const var =
vars_[term_index];
277 EnqueueDelayedDemon(sum_demon_);
280 void PushUp(
int position, int64_t delta_min, int64_t delta_max) {
281 DCHECK_GE(delta_max, 0);
282 DCHECK_GE(delta_min, 0);
283 DCHECK_GT(
CapAdd(delta_min, delta_max), 0);
284 for (
int depth = MaxDepth(); depth >= 0; --depth) {
285 ReduceRange(depth, position, delta_min, delta_max);
286 position = Parent(position);
288 DCHECK_EQ(0, position);
289 target_var_->SetRange(RootMin(), RootMax());
292 std::string DebugString()
const override {
293 return DebugStringInternal(
"Sum");
296 void Accept(ModelVisitor*
const visitor)
const override {
305class SmallSumConstraint :
public Constraint {
307 SmallSumConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
308 IntVar*
const target_var)
309 : Constraint(solver),
311 target_var_(target_var),
314 sum_demon_(nullptr) {}
316 ~SmallSumConstraint()
override {}
318 void Post()
override {
319 for (
int i = 0;
i <
vars_.size(); ++
i) {
320 if (!vars_[i]->Bound()) {
322 solver(),
this, &SmallSumConstraint::VarChanged,
"VarChanged",
324 vars_[
i]->WhenRange(demon);
328 solver(),
this, &SmallSumConstraint::SumChanged,
"SumChanged"));
329 target_var_->WhenRange(sum_demon_);
332 void InitialPropagate()
override {
336 for (IntVar*
const var : vars_) {
342 computed_min_.SetValue(solver(), sum_min);
343 computed_max_.SetValue(solver(), sum_max);
344 target_var_->SetRange(sum_min, sum_max);
351 int64_t new_min = target_var_->Min();
352 int64_t new_max = target_var_->Max();
353 const int64_t sum_min = computed_min_.Value();
354 const int64_t sum_max = computed_max_.Value();
355 if (new_max == sum_min && new_max != std::numeric_limits<int64_t>::max()) {
357 for (
int i = 0;
i <
vars_.size(); ++
i) {
358 vars_[
i]->SetValue(vars_[i]->Min());
360 }
else if (new_min == sum_max &&
361 new_min != std::numeric_limits<int64_t>::min()) {
363 for (
int i = 0;
i <
vars_.size(); ++
i) {
364 vars_[
i]->SetValue(vars_[i]->Max());
367 if (new_min > sum_min || new_max < sum_max) {
369 new_max = std::min(sum_max, new_max);
370 new_min = std::max(sum_min, new_min);
373 if (new_max < sum_min || new_min > sum_max) {
378 for (IntVar*
const var : vars_) {
379 const int64_t var_min =
var->Min();
380 const int64_t var_max =
var->Max();
381 const int64_t residual_min =
CapSub(sum_min, var_min);
382 const int64_t residual_max =
CapSub(sum_max, var_max);
383 var->SetRange(
CapSub(new_min, residual_max),
384 CapSub(new_max, residual_min));
390 void VarChanged(IntVar*
var) {
391 const int64_t delta_min =
CapSub(
var->Min(),
var->OldMin());
392 const int64_t delta_max =
CapSub(
var->OldMax(),
var->Max());
393 computed_min_.Add(solver(), delta_min);
394 computed_max_.Add(solver(), -delta_max);
395 if (computed_max_.Value() < target_var_->Max() ||
396 computed_min_.Value() > target_var_->Min()) {
397 target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
399 EnqueueDelayedDemon(sum_demon_);
403 std::string DebugString()
const override {
404 return absl::StrFormat(
"SmallSum(%s) == %s",
406 target_var_->DebugString());
409 void Accept(ModelVisitor*
const visitor)
const override {
419 const std::vector<IntVar*>
vars_;
421 NumericalRev<int64_t> computed_min_;
422 NumericalRev<int64_t> computed_max_;
427bool DetectSumOverflow(
const std::vector<IntVar*>& vars) {
430 for (
int i = 0;
i < vars.size(); ++
i) {
431 sum_min =
CapAdd(sum_min, vars[i]->Min());
432 sum_max =
CapAdd(sum_max, vars[i]->Max());
433 if (sum_min == std::numeric_limits<int64_t>::min() ||
434 sum_max == std::numeric_limits<int64_t>::max()) {
442class SafeSumConstraint :
public TreeArrayConstraint {
444 SafeSumConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
445 IntVar*
const sum_var)
446 : TreeArrayConstraint(solver, vars, sum_var), sum_demon_(nullptr) {}
448 ~SafeSumConstraint()
override {}
450 void Post()
override {
451 for (
int i = 0;
i <
vars_.size(); ++
i) {
453 solver(),
this, &SafeSumConstraint::LeafChanged,
"LeafChanged", i);
454 vars_[
i]->WhenRange(demon);
457 solver(),
this, &SafeSumConstraint::SumChanged,
"SumChanged"));
458 target_var_->WhenRange(sum_demon_);
461 void SafeComputeNode(
int depth,
int position, int64_t*
const sum_min,
462 int64_t*
const sum_max) {
463 DCHECK_LT(depth, MaxDepth());
464 const int block_start = ChildStart(position);
465 const int block_end = ChildEnd(depth, position);
466 for (
int k = block_start; k <= block_end; ++k) {
467 if (*sum_min != std::numeric_limits<int64_t>::min()) {
468 *sum_min =
CapAdd(*sum_min, Min(depth + 1, k));
470 if (*sum_max != std::numeric_limits<int64_t>::max()) {
471 *sum_max =
CapAdd(*sum_max, Max(depth + 1, k));
473 if (*sum_min == std::numeric_limits<int64_t>::min() &&
474 *sum_max == std::numeric_limits<int64_t>::max()) {
480 void InitialPropagate()
override {
482 for (
int i = 0;
i <
vars_.size(); ++
i) {
483 InitLeaf(i,
vars_[i]->Min(),
vars_[i]->Max());
486 for (
int i = MaxDepth() - 1;
i >= 0; --
i) {
487 for (
int j = 0; j < Width(i); ++j) {
490 SafeComputeNode(i, j, &sum_min, &sum_max);
491 InitNode(i, j, sum_min, sum_max);
495 target_var_->SetRange(RootMin(), RootMax());
502 DCHECK(CheckInternalState());
503 if (target_var_->Max() == RootMin()) {
505 for (
int i = 0;
i <
vars_.size(); ++
i) {
508 }
else if (target_var_->Min() == RootMax()) {
510 for (
int i = 0;
i <
vars_.size(); ++
i) {
514 PushDown(0, 0, target_var_->Min(), target_var_->Max());
518 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
520 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
526 vars_[position]->SetRange(new_min, new_max);
534 const int64_t sum_min = Min(depth, position);
535 const int64_t sum_max = Max(depth, position);
538 new_max = std::min(sum_max, new_max);
539 new_min = std::max(sum_min, new_min);
542 if (new_max < sum_min || new_min > sum_max) {
547 const int block_start = ChildStart(position);
548 const int block_end = ChildEnd(depth, position);
549 for (
int pos = block_start; pos <= block_end; ++pos) {
550 const int64_t target_var_min = Min(depth + 1, pos);
551 const int64_t residual_min =
552 sum_min != std::numeric_limits<int64_t>::min()
553 ?
CapSub(sum_min, target_var_min)
554 :
std::numeric_limits<int64_t>::
min();
555 const int64_t target_var_max = Max(depth + 1, pos);
556 const int64_t residual_max =
557 sum_max != std::numeric_limits<int64_t>::max()
558 ?
CapSub(sum_max, target_var_max)
559 :
std::numeric_limits<int64_t>::
max();
560 PushDown(depth + 1, pos,
561 (residual_max == std::numeric_limits<int64_t>::min()
562 ? std::numeric_limits<int64_t>::min()
563 :
CapSub(new_min, residual_max)),
564 (residual_min == std::numeric_limits<int64_t>::max()
565 ? std::numeric_limits<int64_t>::min()
566 :
CapSub(new_max, residual_min)));
572 void LeafChanged(
int term_index) {
573 IntVar*
const var =
vars_[term_index];
576 EnqueueDelayedDemon(sum_demon_);
579 void PushUp(
int position, int64_t delta_min, int64_t delta_max) {
580 DCHECK_GE(delta_max, 0);
581 DCHECK_GE(delta_min, 0);
582 if (
CapAdd(delta_min, delta_max) == 0) {
587 bool delta_corrupted =
false;
588 for (
int depth = MaxDepth(); depth >= 0; --depth) {
589 if (Min(depth, position) != std::numeric_limits<int64_t>::min() &&
590 Max(depth, position) != std::numeric_limits<int64_t>::max() &&
591 delta_min != std::numeric_limits<int64_t>::max() &&
592 delta_max != std::numeric_limits<int64_t>::max() &&
594 ReduceRange(depth, position, delta_min, delta_max);
595 }
else if (depth == MaxDepth()) {
596 SetRange(depth, position,
vars_[position]->Min(),
597 vars_[position]->Max());
598 delta_corrupted =
true;
602 SafeComputeNode(depth, position, &sum_min, &sum_max);
603 if (sum_min == std::numeric_limits<int64_t>::min() &&
604 sum_max == std::numeric_limits<int64_t>::max()) {
607 SetRange(depth, position, sum_min, sum_max);
608 delta_corrupted =
true;
610 position = Parent(position);
612 DCHECK_EQ(0, position);
613 target_var_->SetRange(RootMin(), RootMax());
616 std::string DebugString()
const override {
617 return DebugStringInternal(
"Sum");
620 void Accept(ModelVisitor*
const visitor)
const override {
625 bool CheckInternalState() {
626 for (
int i = 0;
i <
vars_.size(); ++
i) {
627 CheckLeaf(i,
vars_[i]->Min(),
vars_[i]->Max());
630 for (
int i = MaxDepth() - 1;
i >= 0; --
i) {
631 for (
int j = 0; j < Width(i); ++j) {
634 SafeComputeNode(i, j, &sum_min, &sum_max);
635 CheckNode(i, j, sum_min, sum_max);
641 void CheckLeaf(
int position, int64_t var_min, int64_t var_max) {
642 CheckNode(MaxDepth(), position, var_min, var_max);
645 void CheckNode(
int depth,
int position, int64_t
node_min, int64_t
node_max) {
646 DCHECK_EQ(Min(depth, position),
node_min);
647 DCHECK_EQ(Max(depth, position),
node_max);
656class MinConstraint :
public TreeArrayConstraint {
658 MinConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
659 IntVar*
const min_var)
660 : TreeArrayConstraint(solver, vars, min_var), min_demon_(nullptr) {}
662 ~MinConstraint()
override {}
664 void Post()
override {
665 for (
int i = 0;
i <
vars_.size(); ++
i) {
667 solver(),
this, &MinConstraint::LeafChanged,
"LeafChanged", i);
668 vars_[
i]->WhenRange(demon);
671 solver(),
this, &MinConstraint::MinVarChanged,
"MinVarChanged"));
672 target_var_->WhenRange(min_demon_);
675 void InitialPropagate()
override {
677 for (
int i = 0;
i <
vars_.size(); ++
i) {
678 InitLeaf(i,
vars_[i]->Min(),
vars_[i]->Max());
682 for (
int i = MaxDepth() - 1;
i >= 0; --
i) {
683 for (
int j = 0; j < Width(i); ++j) {
684 int64_t min_min = std::numeric_limits<int64_t>::max();
685 int64_t min_max = std::numeric_limits<int64_t>::max();
686 const int block_start = ChildStart(j);
687 const int block_end = ChildEnd(i, j);
688 for (
int k = block_start; k <= block_end; ++k) {
689 min_min = std::min(min_min, Min(i + 1, k));
690 min_max = std::min(min_max, Max(i + 1, k));
692 InitNode(i, j, min_min, min_max);
696 target_var_->SetRange(RootMin(), RootMax());
702 void MinVarChanged() {
703 PushDown(0, 0, target_var_->Min(), target_var_->Max());
706 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
708 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
714 vars_[position]->SetRange(new_min, new_max);
718 const int64_t
node_min = Min(depth, position);
719 const int64_t
node_max = Max(depth, position);
723 const int block_start = ChildStart(position);
724 const int block_end = ChildEnd(depth, position);
728 for (
int i = block_start;
i <= block_end; ++
i) {
729 if (Min(depth + 1, i) <= new_max) {
742 for (
int i = block_start;
i <= block_end; ++
i) {
743 if (i == candidate && active == 1) {
744 PushDown(depth + 1, i, new_min, new_max);
746 PushDown(depth + 1, i, new_min, Max(depth + 1, i));
749 }
else if (active == 1) {
750 PushDown(depth + 1, candidate, Min(depth + 1, candidate), new_max);
755 void LeafChanged(
int term_index) {
756 IntVar*
const var =
vars_[term_index];
757 SetRange(MaxDepth(), term_index,
var->Min(),
var->Max());
758 const int parent_depth = MaxDepth() - 1;
759 const int parent = Parent(term_index);
760 const int64_t old_min =
var->OldMin();
761 const int64_t var_min =
var->Min();
762 const int64_t var_max =
var->Max();
763 if ((old_min == Min(parent_depth, parent) && old_min != var_min) ||
764 var_max < Max(parent_depth, parent)) {
770 void PushUp(
int position) {
771 int depth = MaxDepth();
773 const int parent = Parent(position);
774 const int parent_depth = depth - 1;
775 int64_t min_min = std::numeric_limits<int64_t>::max();
776 int64_t min_max = std::numeric_limits<int64_t>::max();
777 const int block_start = ChildStart(parent);
778 const int block_end = ChildEnd(parent_depth, parent);
779 for (
int k = block_start; k <= block_end; ++k) {
780 min_min = std::min(min_min, Min(depth, k));
781 min_max = std::min(min_max, Max(depth, k));
783 if (min_min > Min(parent_depth, parent) ||
784 min_max < Max(parent_depth, parent)) {
785 SetRange(parent_depth, parent, min_min, min_max);
789 depth = parent_depth;
793 target_var_->SetRange(RootMin(), RootMax());
798 std::string DebugString()
const override {
799 return DebugStringInternal(
"Min");
802 void Accept(ModelVisitor*
const visitor)
const override {
810class SmallMinConstraint :
public Constraint {
812 SmallMinConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
813 IntVar*
const target_var)
814 : Constraint(solver),
816 target_var_(target_var),
820 ~SmallMinConstraint()
override {}
822 void Post()
override {
823 for (
int i = 0;
i <
vars_.size(); ++
i) {
824 if (!vars_[i]->Bound()) {
826 solver(),
this, &SmallMinConstraint::VarChanged,
"VarChanged",
828 vars_[
i]->WhenRange(demon);
832 solver(),
this, &SmallMinConstraint::MinVarChanged,
"MinVarChanged"));
833 target_var_->WhenRange(mdemon);
836 void InitialPropagate()
override {
837 int64_t min_min = std::numeric_limits<int64_t>::max();
838 int64_t min_max = std::numeric_limits<int64_t>::max();
839 for (IntVar*
const var : vars_) {
840 min_min = std::min(min_min,
var->Min());
841 min_max = std::min(min_max,
var->Max());
843 computed_min_.SetValue(solver(), min_min);
844 computed_max_.SetValue(solver(), min_max);
846 target_var_->SetRange(min_min, min_max);
852 std::string DebugString()
const override {
853 return absl::StrFormat(
"SmallMin(%s) == %s",
855 target_var_->DebugString());
858 void Accept(ModelVisitor*
const visitor)
const override {
868 void VarChanged(IntVar*
var) {
869 const int64_t old_min =
var->OldMin();
870 const int64_t var_min =
var->Min();
871 const int64_t var_max =
var->Max();
872 if ((old_min == computed_min_.Value() && old_min != var_min) ||
873 var_max < computed_max_.Value()) {
875 int64_t min_min = std::numeric_limits<int64_t>::max();
876 int64_t min_max = std::numeric_limits<int64_t>::max();
877 for (IntVar*
const var : vars_) {
878 min_min = std::min(min_min,
var->Min());
879 min_max = std::min(min_max,
var->Max());
881 if (min_min > computed_min_.Value() || min_max < computed_max_.Value()) {
882 computed_min_.SetValue(solver(), min_min);
883 computed_max_.SetValue(solver(), min_max);
884 target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
890 void MinVarChanged() {
891 const int64_t new_min = target_var_->Min();
892 const int64_t new_max = target_var_->Max();
894 if (new_min <= computed_min_.Value() && new_max >= computed_max_.Value()) {
898 IntVar* candidate =
nullptr;
901 if (new_max < computed_max_.Value()) {
903 for (IntVar*
const var : vars_) {
904 if (
var->Min() <= new_max) {
915 if (computed_min_.Value() < new_min) {
917 candidate->SetRange(new_min, new_max);
919 for (IntVar*
const var : vars_) {
920 var->SetMin(new_min);
923 }
else if (active == 1) {
924 candidate->SetMax(new_max);
928 std::vector<IntVar*>
vars_;
929 IntVar*
const target_var_;
930 Rev<int64_t> computed_min_;
931 Rev<int64_t> computed_max_;
937class MaxConstraint :
public TreeArrayConstraint {
939 MaxConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
940 IntVar*
const max_var)
941 : TreeArrayConstraint(solver, vars, max_var), max_demon_(nullptr) {}
943 ~MaxConstraint()
override {}
945 void Post()
override {
946 for (
int i = 0;
i <
vars_.size(); ++
i) {
948 solver(),
this, &MaxConstraint::LeafChanged,
"LeafChanged", i);
949 vars_[
i]->WhenRange(demon);
952 solver(),
this, &MaxConstraint::MaxVarChanged,
"MaxVarChanged"));
953 target_var_->WhenRange(max_demon_);
956 void InitialPropagate()
override {
958 for (
int i = 0;
i <
vars_.size(); ++
i) {
959 InitLeaf(i,
vars_[i]->Min(),
vars_[i]->Max());
963 for (
int i = MaxDepth() - 1;
i >= 0; --
i) {
964 for (
int j = 0; j < Width(i); ++j) {
965 int64_t max_min = std::numeric_limits<int64_t>::min();
966 int64_t max_max = std::numeric_limits<int64_t>::min();
967 const int block_start = ChildStart(j);
968 const int block_end = ChildEnd(i, j);
969 for (
int k = block_start; k <= block_end; ++k) {
970 max_min = std::max(max_min, Min(i + 1, k));
971 max_max = std::max(max_max, Max(i + 1, k));
973 InitNode(i, j, max_min, max_max);
977 target_var_->SetRange(RootMin(), RootMax());
983 void MaxVarChanged() {
984 PushDown(0, 0, target_var_->Min(), target_var_->Max());
987 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
989 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
995 vars_[position]->SetRange(new_min, new_max);
999 const int64_t
node_min = Min(depth, position);
1000 const int64_t
node_max = Max(depth, position);
1004 const int block_start = ChildStart(position);
1005 const int block_end = ChildEnd(depth, position);
1009 for (
int i = block_start;
i <= block_end; ++
i) {
1010 if (Max(depth + 1, i) >= new_min) {
1011 if (active++ >= 1) {
1023 for (
int i = block_start;
i <= block_end; ++
i) {
1024 if (i == candidate && active == 1) {
1025 PushDown(depth + 1, i, new_min, new_max);
1027 PushDown(depth + 1, i, Min(depth + 1, i), new_max);
1030 }
else if (active == 1) {
1031 PushDown(depth + 1, candidate, new_min, Max(depth + 1, candidate));
1035 void LeafChanged(
int term_index) {
1036 IntVar*
const var =
vars_[term_index];
1037 SetRange(MaxDepth(), term_index,
var->Min(),
var->Max());
1038 const int parent_depth = MaxDepth() - 1;
1039 const int parent = Parent(term_index);
1040 const int64_t old_max =
var->OldMax();
1041 const int64_t var_min =
var->Min();
1042 const int64_t var_max =
var->Max();
1043 if ((old_max == Max(parent_depth, parent) && old_max != var_max) ||
1044 var_min > Min(parent_depth, parent)) {
1050 void PushUp(
int position) {
1051 int depth = MaxDepth();
1053 const int parent = Parent(position);
1054 const int parent_depth = depth - 1;
1055 int64_t max_min = std::numeric_limits<int64_t>::min();
1056 int64_t max_max = std::numeric_limits<int64_t>::min();
1057 const int block_start = ChildStart(parent);
1058 const int block_end = ChildEnd(parent_depth, parent);
1059 for (
int k = block_start; k <= block_end; ++k) {
1060 max_min = std::max(max_min, Min(depth, k));
1061 max_max = std::max(max_max, Max(depth, k));
1063 if (max_min > Min(parent_depth, parent) ||
1064 max_max < Max(parent_depth, parent)) {
1065 SetRange(parent_depth, parent, max_min, max_max);
1069 depth = parent_depth;
1073 target_var_->SetRange(RootMin(), RootMax());
1078 std::string DebugString()
const override {
1079 return DebugStringInternal(
"Max");
1082 void Accept(ModelVisitor*
const visitor)
const override {
1090class SmallMaxConstraint :
public Constraint {
1092 SmallMaxConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
1093 IntVar*
const target_var)
1094 : Constraint(solver),
1096 target_var_(target_var),
1100 ~SmallMaxConstraint()
override {}
1102 void Post()
override {
1103 for (
int i = 0;
i <
vars_.size(); ++
i) {
1104 if (!vars_[i]->Bound()) {
1106 solver(),
this, &SmallMaxConstraint::VarChanged,
"VarChanged",
1108 vars_[
i]->WhenRange(demon);
1112 solver(),
this, &SmallMaxConstraint::MaxVarChanged,
"MinVarChanged"));
1113 target_var_->WhenRange(mdemon);
1116 void InitialPropagate()
override {
1117 int64_t max_min = std::numeric_limits<int64_t>::min();
1118 int64_t max_max = std::numeric_limits<int64_t>::min();
1119 for (IntVar*
const var : vars_) {
1120 max_min = std::max(max_min,
var->Min());
1121 max_max = std::max(max_max,
var->Max());
1123 computed_min_.SetValue(solver(), max_min);
1124 computed_max_.SetValue(solver(), max_max);
1126 target_var_->SetRange(max_min, max_max);
1132 std::string DebugString()
const override {
1133 return absl::StrFormat(
"SmallMax(%s) == %s",
1135 target_var_->DebugString());
1138 void Accept(ModelVisitor*
const visitor)
const override {
1148 void VarChanged(IntVar*
var) {
1149 const int64_t old_max =
var->OldMax();
1150 const int64_t var_min =
var->Min();
1151 const int64_t var_max =
var->Max();
1152 if ((old_max == computed_max_.Value() && old_max != var_max) ||
1153 var_min > computed_min_.Value()) {
1155 int64_t max_min = std::numeric_limits<int64_t>::min();
1156 int64_t max_max = std::numeric_limits<int64_t>::min();
1157 for (IntVar*
const var : vars_) {
1158 max_min = std::max(max_min,
var->Min());
1159 max_max = std::max(max_max,
var->Max());
1161 if (max_min > computed_min_.Value() || max_max < computed_max_.Value()) {
1162 computed_min_.SetValue(solver(), max_min);
1163 computed_max_.SetValue(solver(), max_max);
1164 target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
1170 void MaxVarChanged() {
1171 const int64_t new_min = target_var_->Min();
1172 const int64_t new_max = target_var_->Max();
1174 if (new_min <= computed_min_.Value() && new_max >= computed_max_.Value()) {
1178 IntVar* candidate =
nullptr;
1181 if (new_min > computed_min_.Value()) {
1183 for (IntVar*
const var : vars_) {
1184 if (
var->Max() >= new_min) {
1185 if (active++ >= 1) {
1195 if (computed_max_.Value() > new_max) {
1197 candidate->SetRange(new_min, new_max);
1199 for (IntVar*
const var : vars_) {
1200 var->SetMax(new_max);
1203 }
else if (active == 1) {
1204 candidate->SetMin(new_min);
1208 std::vector<IntVar*>
vars_;
1209 IntVar*
const target_var_;
1210 Rev<int64_t> computed_min_;
1211 Rev<int64_t> computed_max_;
1216class ArrayBoolAndEq :
public CastConstraint {
1218 ArrayBoolAndEq(Solver*
const s,
const std::vector<IntVar*>& vars,
1219 IntVar*
const target)
1220 : CastConstraint(s, target),
1222 demons_(vars.
size()),
1225 ~ArrayBoolAndEq()
override {}
1227 void Post()
override {
1228 for (
int i = 0;
i <
vars_.size(); ++
i) {
1229 if (!vars_[i]->Bound()) {
1232 "PropagateVar", vars_[i]);
1233 vars_[
i]->WhenBound(demons_[i]);
1236 if (!target_var_->Bound()) {
1238 solver(),
this, &ArrayBoolAndEq::PropagateTarget,
"PropagateTarget");
1239 target_var_->WhenBound(target_demon);
1243 void InitialPropagate()
override {
1244 target_var_->SetRange(0, 1);
1245 if (target_var_->Min() == 1) {
1246 for (
int i = 0;
i <
vars_.size(); ++
i) {
1250 int possible_zero = -1;
1253 for (
int i = 0;
i <
vars_.size(); ++
i) {
1254 if (!vars_[i]->Bound()) {
1257 }
else if (vars_[i]->Max() == 0) {
1259 target_var_->SetMax(0);
1262 DCHECK_EQ(1, vars_[i]->Min());
1266 if (unbounded == 0) {
1267 target_var_->SetMin(1);
1268 }
else if (target_var_->Max() == 0 && unbounded == 1) {
1269 CHECK_NE(-1, possible_zero);
1270 vars_[possible_zero]->SetMax(0);
1272 unbounded_.SetValue(solver(), unbounded);
1277 void PropagateVar(IntVar*
var) {
1278 if (
var->Min() == 1) {
1279 unbounded_.Decr(solver());
1280 if (unbounded_.Value() == 0 && !decided_.Switched()) {
1281 target_var_->SetMin(1);
1282 decided_.Switch(solver());
1283 }
else if (target_var_->Max() == 0 && unbounded_.Value() == 1 &&
1284 !decided_.Switched()) {
1289 target_var_->SetMax(0);
1293 void PropagateTarget() {
1294 if (target_var_->Min() == 1) {
1295 for (
int i = 0;
i <
vars_.size(); ++
i) {
1299 if (unbounded_.Value() == 1 && !decided_.Switched()) {
1305 std::string DebugString()
const override {
1307 target_var_->DebugString());
1310 void Accept(ModelVisitor*
const visitor)
const override {
1321 for (
int i = 0;
i < demons_.size(); ++
i) {
1322 if (demons_[i] !=
nullptr) {
1323 demons_[
i]->inhibit(solver());
1328 void ForceToZero() {
1329 for (
int i = 0;
i <
vars_.size(); ++
i) {
1330 if (vars_[i]->Min() == 0) {
1332 decided_.Switch(solver());
1339 const std::vector<IntVar*>
vars_;
1340 std::vector<Demon*> demons_;
1341 NumericalRev<int> unbounded_;
1345class ArrayBoolOrEq :
public CastConstraint {
1347 ArrayBoolOrEq(Solver*
const s,
const std::vector<IntVar*>& vars,
1348 IntVar*
const target)
1349 : CastConstraint(s, target),
1351 demons_(vars.
size()),
1354 ~ArrayBoolOrEq()
override {}
1356 void Post()
override {
1357 for (
int i = 0;
i <
vars_.size(); ++
i) {
1358 if (!vars_[i]->Bound()) {
1361 "PropagateVar", vars_[i]);
1362 vars_[
i]->WhenBound(demons_[i]);
1365 if (!target_var_->Bound()) {
1367 solver(),
this, &ArrayBoolOrEq::PropagateTarget,
"PropagateTarget");
1368 target_var_->WhenBound(target_demon);
1372 void InitialPropagate()
override {
1373 target_var_->SetRange(0, 1);
1374 if (target_var_->Max() == 0) {
1375 for (
int i = 0;
i <
vars_.size(); ++
i) {
1380 int possible_one = -1;
1382 for (
int i = 0;
i <
vars_.size(); ++
i) {
1383 if (!vars_[i]->Bound()) {
1386 }
else if (vars_[i]->Min() == 1) {
1388 target_var_->SetMin(1);
1391 DCHECK_EQ(0, vars_[i]->Max());
1395 if (unbounded == 0) {
1396 target_var_->SetMax(0);
1397 }
else if (target_var_->Min() == 1 && unbounded == 1) {
1398 CHECK_NE(-1, possible_one);
1399 vars_[possible_one]->SetMin(1);
1401 unbounded_.SetValue(solver(), unbounded);
1406 void PropagateVar(IntVar*
var) {
1407 if (
var->Min() == 0) {
1408 unbounded_.Decr(solver());
1409 if (unbounded_.Value() == 0 && !decided_.Switched()) {
1410 target_var_->SetMax(0);
1411 decided_.Switch(solver());
1413 if (target_var_->Min() == 1 && unbounded_.Value() == 1 &&
1414 !decided_.Switched()) {
1419 target_var_->SetMin(1);
1423 void PropagateTarget() {
1424 if (target_var_->Max() == 0) {
1425 for (
int i = 0;
i <
vars_.size(); ++
i) {
1429 if (unbounded_.Value() == 1 && !decided_.Switched()) {
1435 std::string DebugString()
const override {
1437 target_var_->DebugString());
1440 void Accept(ModelVisitor*
const visitor)
const override {
1451 for (
int i = 0;
i < demons_.size(); ++
i) {
1452 if (demons_[i] !=
nullptr) {
1453 demons_[
i]->inhibit(solver());
1459 for (
int i = 0;
i <
vars_.size(); ++
i) {
1460 if (vars_[i]->Max() == 1) {
1462 decided_.Switch(solver());
1469 const std::vector<IntVar*>
vars_;
1470 std::vector<Demon*> demons_;
1471 NumericalRev<int> unbounded_;
1477class BaseSumBooleanConstraint :
public Constraint {
1479 BaseSumBooleanConstraint(Solver*
const s,
const std::vector<IntVar*>& vars)
1480 : Constraint(s),
vars_(vars) {}
1482 ~BaseSumBooleanConstraint()
override {}
1485 std::string DebugStringInternal(absl::string_view
name)
const {
1489 const std::vector<IntVar*>
vars_;
1495class SumBooleanLessOrEqualToOne :
public BaseSumBooleanConstraint {
1497 SumBooleanLessOrEqualToOne(Solver*
const s,
const std::vector<IntVar*>& vars)
1498 : BaseSumBooleanConstraint(s, vars) {}
1500 ~SumBooleanLessOrEqualToOne()
override {}
1502 void Post()
override {
1503 for (
int i = 0;
i <
vars_.size(); ++
i) {
1504 if (!
vars_[i]->Bound()) {
1506 &SumBooleanLessOrEqualToOne::Update,
1507 "Update",
vars_[i]);
1513 void InitialPropagate()
override {
1514 for (
int i = 0;
i <
vars_.size(); ++
i) {
1515 if (
vars_[i]->Min() == 1) {
1516 PushAllToZeroExcept(
vars_[i]);
1522 void Update(IntVar*
var) {
1524 DCHECK(
var->Bound());
1525 if (
var->Min() == 1) {
1526 PushAllToZeroExcept(
var);
1531 void PushAllToZeroExcept(IntVar*
var) {
1533 for (
int i = 0;
i <
vars_.size(); ++
i) {
1534 IntVar*
const other =
vars_[
i];
1535 if (other !=
var && other->Max() != 0) {
1541 std::string DebugString()
const override {
1542 return DebugStringInternal(
"SumBooleanLessOrEqualToOne");
1545 void Accept(ModelVisitor*
const visitor)
const override {
1558class SumBooleanGreaterOrEqualToOne :
public BaseSumBooleanConstraint {
1560 SumBooleanGreaterOrEqualToOne(Solver* s,
const std::vector<IntVar*>& vars);
1561 ~SumBooleanGreaterOrEqualToOne()
override {}
1563 void Post()
override;
1564 void InitialPropagate()
override;
1566 void Update(
int index);
1569 std::string DebugString()
const override;
1571 void Accept(ModelVisitor*
const visitor)
const override {
1583SumBooleanGreaterOrEqualToOne::SumBooleanGreaterOrEqualToOne(
1584 Solver*
const s,
const std::vector<IntVar*>& vars)
1585 : BaseSumBooleanConstraint(s, vars), bits_(vars.
size()) {}
1587void SumBooleanGreaterOrEqualToOne::Post() {
1588 for (
int i = 0;
i <
vars_.size(); ++
i) {
1590 solver(),
this, &SumBooleanGreaterOrEqualToOne::Update,
"Update", i);
1595void SumBooleanGreaterOrEqualToOne::InitialPropagate() {
1596 for (
int i = 0;
i <
vars_.size(); ++
i) {
1598 if (
var->Min() == 1LL) {
1602 if (
var->Max() == 1LL) {
1603 bits_.SetToOne(solver(), i);
1606 if (bits_.IsCardinalityZero()) {
1608 }
else if (bits_.IsCardinalityOne()) {
1609 vars_[bits_.GetFirstBit(0)]->SetValue(int64_t{1});
1614void SumBooleanGreaterOrEqualToOne::Update(
int index) {
1619 bits_.SetToZero(solver(),
index);
1620 if (bits_.IsCardinalityZero()) {
1622 }
else if (bits_.IsCardinalityOne()) {
1623 vars_[bits_.GetFirstBit(0)]->SetValue(int64_t{1});
1630std::string SumBooleanGreaterOrEqualToOne::DebugString()
const {
1631 return DebugStringInternal(
"SumBooleanGreaterOrEqualToOne");
1636class SumBooleanEqualToOne :
public BaseSumBooleanConstraint {
1638 SumBooleanEqualToOne(Solver*
const s,
const std::vector<IntVar*>& vars)
1639 : BaseSumBooleanConstraint(s, vars), active_vars_(0) {}
1641 ~SumBooleanEqualToOne()
override {}
1643 void Post()
override {
1644 for (
int i = 0;
i <
vars_.size(); ++
i) {
1646 solver(),
this, &SumBooleanEqualToOne::Update,
"Update", i);
1651 void InitialPropagate()
override {
1656 for (
int i = 0;
i <
vars_.size(); ++
i) {
1658 if (
var->Min() == 1) {
1662 if (
var->Max() == 1) {
1667 if (min1 > 1 || max1 == 0) {
1669 }
else if (min1 == 1) {
1670 DCHECK_NE(-1, index_min);
1671 PushAllToZeroExcept(index_min);
1672 }
else if (max1 == 1) {
1673 DCHECK_NE(-1, index_max);
1674 vars_[index_max]->SetValue(1);
1677 active_vars_.SetValue(solver(), max1);
1681 void Update(
int index) {
1686 active_vars_.Decr(solver());
1687 DCHECK_GE(active_vars_.Value(), 0);
1688 if (active_vars_.Value() == 0) {
1690 }
else if (active_vars_.Value() == 1) {
1692 for (
int i = 0;
i <
vars_.size(); ++
i) {
1694 if (
var->Max() == 1) {
1696 PushAllToZeroExcept(i);
1706 PushAllToZeroExcept(
index);
1711 void PushAllToZeroExcept(
int index) {
1713 for (
int i = 0;
i <
vars_.size(); ++
i) {
1720 std::string DebugString()
const override {
1721 return DebugStringInternal(
"SumBooleanEqualToOne");
1724 void Accept(ModelVisitor*
const visitor)
const override {
1725 visitor->BeginVisitConstraint(ModelVisitor::kSumEqual,
this);
1726 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1728 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, 1);
1729 visitor->EndVisitConstraint(ModelVisitor::kSumEqual,
this);
1733 NumericalRev<int> active_vars_;
1738class SumBooleanEqualToVar :
public BaseSumBooleanConstraint {
1740 SumBooleanEqualToVar(Solver*
const s,
const std::vector<IntVar*>& bool_vars,
1741 IntVar*
const sum_var)
1742 : BaseSumBooleanConstraint(s, bool_vars),
1743 num_possible_true_vars_(0),
1744 num_always_true_vars_(0),
1745 sum_var_(sum_var) {}
1747 ~SumBooleanEqualToVar()
override {}
1749 void Post()
override {
1750 for (
int i = 0;
i <
vars_.size(); ++
i) {
1752 solver(),
this, &SumBooleanEqualToVar::Update,
"Update", i);
1755 if (!sum_var_->Bound()) {
1757 solver(),
this, &SumBooleanEqualToVar::UpdateVar,
"UpdateVar");
1758 sum_var_->WhenRange(u);
1762 void InitialPropagate()
override {
1763 int num_always_true_vars = 0;
1764 int possible_true = 0;
1765 for (
int i = 0;
i <
vars_.size(); ++
i) {
1767 if (
var->Min() == 1) {
1768 num_always_true_vars++;
1770 if (
var->Max() == 1) {
1774 sum_var_->SetRange(num_always_true_vars, possible_true);
1775 const int64_t var_min = sum_var_->Min();
1776 const int64_t var_max = sum_var_->Max();
1777 if (num_always_true_vars == var_max && possible_true > var_max) {
1778 PushAllUnboundToZero();
1779 }
else if (possible_true == var_min && num_always_true_vars < var_min) {
1780 PushAllUnboundToOne();
1782 num_possible_true_vars_.SetValue(solver(), possible_true);
1783 num_always_true_vars_.SetValue(solver(), num_always_true_vars);
1789 if (num_possible_true_vars_.Value() == sum_var_->Min()) {
1790 PushAllUnboundToOne();
1791 sum_var_->SetValue(num_possible_true_vars_.Value());
1792 }
else if (num_always_true_vars_.Value() == sum_var_->Max()) {
1793 PushAllUnboundToZero();
1794 sum_var_->SetValue(num_always_true_vars_.Value());
1799 void Update(
int index) {
1804 num_possible_true_vars_.Decr(solver());
1805 sum_var_->SetRange(num_always_true_vars_.Value(),
1806 num_possible_true_vars_.Value());
1807 if (num_possible_true_vars_.Value() == sum_var_->Min()) {
1808 PushAllUnboundToOne();
1811 DCHECK_EQ(1,
value);
1812 num_always_true_vars_.Incr(solver());
1813 sum_var_->SetRange(num_always_true_vars_.Value(),
1814 num_possible_true_vars_.Value());
1815 if (num_always_true_vars_.Value() == sum_var_->Max()) {
1816 PushAllUnboundToZero();
1822 void PushAllUnboundToZero() {
1823 int64_t counter = 0;
1825 for (
int i = 0;
i <
vars_.size(); ++
i) {
1826 if (
vars_[i]->Min() == 0) {
1832 if (counter < sum_var_->Min() || counter > sum_var_->Max()) {
1837 void PushAllUnboundToOne() {
1838 int64_t counter = 0;
1840 for (
int i = 0;
i <
vars_.size(); ++
i) {
1841 if (
vars_[i]->Max() == 1) {
1846 if (counter < sum_var_->Min() || counter > sum_var_->Max()) {
1851 std::string DebugString()
const override {
1852 return absl::StrFormat(
"%s == %s", DebugStringInternal(
"SumBoolean"),
1853 sum_var_->DebugString());
1856 void Accept(ModelVisitor*
const visitor)
const override {
1857 visitor->BeginVisitConstraint(ModelVisitor::kSumEqual,
this);
1858 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1860 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1862 visitor->EndVisitConstraint(ModelVisitor::kSumEqual,
this);
1866 NumericalRev<int> num_possible_true_vars_;
1867 NumericalRev<int> num_always_true_vars_;
1868 IntVar*
const sum_var_;
1878 Container(IntVar* v, int64_t c) :
var(v),
coef(c) {}
1879 bool operator<(
const Container& c)
const {
return (
coef <
c.coef); }
1889int64_t SortBothChangeConstant(std::vector<IntVar*>*
const vars,
1890 std::vector<int64_t>*
const coefs,
1892 CHECK(vars !=
nullptr);
1893 CHECK(coefs !=
nullptr);
1894 if (vars->empty()) {
1898 std::vector<Container> to_sort;
1900 if ((*vars)[
index]->Bound()) {
1902 }
else if ((*coefs)[
index] != 0) {
1903 to_sort.push_back(Container((*vars)[
index], (*coefs)[
index]));
1906 if (keep_inside && cst != 0) {
1907 CHECK_LT(to_sort.size(), vars->size());
1908 Solver*
const solver = (*vars)[0]->solver();
1909 to_sort.push_back(Container(solver->MakeIntConst(1), cst));
1912 std::sort(to_sort.begin(), to_sort.end());
1917 vars->resize(to_sort.size());
1918 coefs->resize(to_sort.size());
1924class BooleanScalProdLessConstant :
public Constraint {
1926 BooleanScalProdLessConstant(Solver*
const s,
const std::vector<IntVar*>& vars,
1927 const std::vector<int64_t>& coefs,
1933 first_unbound_backward_(vars.
size() - 1),
1934 sum_of_bound_variables_(0LL),
1935 max_coefficient_(0) {
1936 CHECK(!vars.empty());
1937 for (
int i = 0;
i <
vars_.size(); ++
i) {
1938 DCHECK_GE(coefs_[i], 0);
1942 max_coefficient_.SetValue(s, coefs_[
vars_.size() - 1]);
1945 ~BooleanScalProdLessConstant()
override {}
1947 void Post()
override {
1953 &BooleanScalProdLessConstant::Update,
1959 void PushFromTop() {
1960 const int64_t slack =
CapSub(upper_bound_, sum_of_bound_variables_.Value());
1964 if (slack < max_coefficient_.Value()) {
1965 int64_t last_unbound = first_unbound_backward_.Value();
1966 for (; last_unbound >= 0; --last_unbound) {
1967 if (!
vars_[last_unbound]->Bound()) {
1968 if (coefs_[last_unbound] <= slack) {
1969 max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
1972 vars_[last_unbound]->SetValue(0);
1976 first_unbound_backward_.SetValue(solver(), last_unbound);
1980 void InitialPropagate()
override {
1981 Solver*
const s = solver();
1982 int last_unbound = -1;
1989 last_unbound =
index;
1992 sum_of_bound_variables_.SetValue(s, sum);
1993 first_unbound_backward_.SetValue(s, last_unbound);
1999 sum_of_bound_variables_.SetValue(
2000 solver(),
CapAdd(sum_of_bound_variables_.Value(), coefs_[
var_index]));
2005 std::string DebugString()
const override {
2006 return absl::StrFormat(
"BooleanScalProd([%s], [%s]) <= %d)",
2008 absl::StrJoin(coefs_,
", "), upper_bound_);
2011 void Accept(ModelVisitor*
const visitor)
const override {
2012 visitor->BeginVisitConstraint(ModelVisitor::kScalProdLessOrEqual,
this);
2013 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2015 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2017 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, upper_bound_);
2018 visitor->EndVisitConstraint(ModelVisitor::kScalProdLessOrEqual,
this);
2022 std::vector<IntVar*>
vars_;
2023 std::vector<int64_t> coefs_;
2024 int64_t upper_bound_;
2025 Rev<int> first_unbound_backward_;
2026 Rev<int64_t> sum_of_bound_variables_;
2027 Rev<int64_t> max_coefficient_;
2032class PositiveBooleanScalProdEqVar :
public CastConstraint {
2034 PositiveBooleanScalProdEqVar(Solver*
const s,
2035 const std::vector<IntVar*>& vars,
2036 const std::vector<int64_t>& coefs,
2038 : CastConstraint(s,
var),
2041 first_unbound_backward_(vars.
size() - 1),
2042 sum_of_bound_variables_(0LL),
2043 sum_of_all_variables_(0LL),
2044 max_coefficient_(0) {
2045 SortBothChangeConstant(&
vars_, &coefs_,
true);
2046 max_coefficient_.SetValue(s, coefs_[
vars_.size() - 1]);
2049 ~PositiveBooleanScalProdEqVar()
override {}
2051 void Post()
override {
2057 solver(),
this, &PositiveBooleanScalProdEqVar::Update,
"Update",
2061 if (!target_var_->Bound()) {
2063 solver(),
this, &PositiveBooleanScalProdEqVar::Propagate,
2065 target_var_->WhenRange(uv);
2070 target_var_->SetRange(sum_of_bound_variables_.Value(),
2071 sum_of_all_variables_.Value());
2072 const int64_t slack_up =
2073 CapSub(target_var_->Max(), sum_of_bound_variables_.Value());
2074 const int64_t slack_down =
2075 CapSub(sum_of_all_variables_.Value(), target_var_->Min());
2076 const int64_t max_coeff = max_coefficient_.Value();
2077 if (slack_down < max_coeff || slack_up < max_coeff) {
2078 int64_t last_unbound = first_unbound_backward_.Value();
2079 for (; last_unbound >= 0; --last_unbound) {
2080 if (!
vars_[last_unbound]->Bound()) {
2081 if (coefs_[last_unbound] > slack_up) {
2082 vars_[last_unbound]->SetValue(0);
2083 }
else if (coefs_[last_unbound] > slack_down) {
2084 vars_[last_unbound]->SetValue(1);
2086 max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
2091 first_unbound_backward_.SetValue(solver(), last_unbound);
2095 void InitialPropagate()
override {
2096 Solver*
const s = solver();
2097 int last_unbound = -1;
2098 int64_t sum_bound = 0;
2099 int64_t sum_all = 0;
2106 last_unbound =
index;
2109 sum_of_bound_variables_.SetValue(s, sum_bound);
2110 sum_of_all_variables_.SetValue(s, sum_all);
2111 first_unbound_backward_.SetValue(s, last_unbound);
2117 sum_of_bound_variables_.SetValue(
2118 solver(),
CapAdd(sum_of_bound_variables_.Value(), coefs_[
var_index]));
2120 sum_of_all_variables_.SetValue(
2126 std::string DebugString()
const override {
2127 return absl::StrFormat(
"PositiveBooleanScal([%s], [%s]) == %s",
2129 absl::StrJoin(coefs_,
", "),
2130 target_var_->DebugString());
2133 void Accept(ModelVisitor*
const visitor)
const override {
2134 visitor->BeginVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2135 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2137 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2139 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
2141 visitor->EndVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2145 std::vector<IntVar*>
vars_;
2146 std::vector<int64_t> coefs_;
2147 Rev<int> first_unbound_backward_;
2148 Rev<int64_t> sum_of_bound_variables_;
2149 Rev<int64_t> sum_of_all_variables_;
2150 Rev<int64_t> max_coefficient_;
2155class PositiveBooleanScalProd :
public BaseIntExpr {
2159 PositiveBooleanScalProd(Solver*
const s,
const std::vector<IntVar*>& vars,
2160 const std::vector<int64_t>& coefs)
2161 : BaseIntExpr(s),
vars_(vars), coefs_(coefs) {
2162 CHECK(!vars.empty());
2163 SortBothChangeConstant(&
vars_, &coefs_,
true);
2164 for (
int i = 0;
i <
vars_.size(); ++
i) {
2165 DCHECK_GE(coefs_[i], 0);
2169 ~PositiveBooleanScalProd()
override {}
2171 int64_t Min()
const override {
2173 for (
int i = 0;
i <
vars_.size(); ++
i) {
2174 if (
vars_[i]->Min()) {
2181 void SetMin(int64_t m)
override {
2182 SetRange(m, std::numeric_limits<int64_t>::max());
2185 int64_t Max()
const override {
2187 for (
int i = 0;
i <
vars_.size(); ++
i) {
2188 if (
vars_[i]->Max()) {
2195 void SetMax(int64_t m)
override {
2196 SetRange(std::numeric_limits<int64_t>::min(), m);
2199 void SetRange(int64_t l, int64_t u)
override {
2200 int64_t current_min = 0;
2201 int64_t current_max = 0;
2202 int64_t diameter = -1;
2203 for (
int i = 0;
i <
vars_.size(); ++
i) {
2207 current_min =
CapAdd(current_min, var_min);
2208 current_max =
CapAdd(current_max, var_max);
2209 if (var_min != var_max) {
2210 diameter =
CapSub(var_max, var_min);
2213 if (u >= current_max && l <= current_min) {
2216 if (u < current_min || l > current_max) {
2220 u = std::min(current_max, u);
2221 l = std::max(l, current_min);
2223 if (
CapSub(u, l) > diameter) {
2227 for (
int i = 0;
i <
vars_.size(); ++
i) {
2230 const int64_t new_min =
2232 const int64_t new_max =
2234 if (new_max < 0 || new_min >
coefficient || new_min > new_max) {
2237 if (new_min > 0LL) {
2238 var->SetMin(int64_t{1});
2240 var->SetMax(int64_t{0});
2245 std::string DebugString()
const override {
2246 return absl::StrFormat(
"PositiveBooleanScalProd([%s], [%s])",
2248 absl::StrJoin(coefs_,
", "));
2251 void WhenRange(Demon* d)
override {
2252 for (
int i = 0;
i <
vars_.size(); ++
i) {
2256 IntVar* CastToVar()
override {
2257 Solver*
const s = solver();
2260 Range(&vmin, &vmax);
2261 IntVar*
const var = solver()->MakeIntVar(vmin, vmax);
2262 if (!
vars_.empty()) {
2263 CastConstraint*
const ct =
2264 s->RevAlloc(
new PositiveBooleanScalProdEqVar(s,
vars_, coefs_,
var));
2265 s->AddCastConstraint(
ct,
var,
this);
2270 void Accept(ModelVisitor*
const visitor)
const override {
2271 visitor->BeginVisitIntegerExpression(ModelVisitor::kScalProd,
this);
2272 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2274 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2276 visitor->EndVisitIntegerExpression(ModelVisitor::kScalProd,
this);
2280 std::vector<IntVar*>
vars_;
2281 std::vector<int64_t> coefs_;
2286class PositiveBooleanScalProdEqCst :
public Constraint {
2288 PositiveBooleanScalProdEqCst(Solver*
const s,
2289 const std::vector<IntVar*>& vars,
2290 const std::vector<int64_t>& coefs,
2295 first_unbound_backward_(vars.
size() - 1),
2296 sum_of_bound_variables_(0LL),
2297 sum_of_all_variables_(0LL),
2298 constant_(constant),
2299 max_coefficient_(0) {
2300 CHECK(!vars.empty());
2302 CapSub(constant_, SortBothChangeConstant(&
vars_, &coefs_,
false));
2303 max_coefficient_.SetValue(s, coefs_[
vars_.size() - 1]);
2306 ~PositiveBooleanScalProdEqCst()
override {}
2308 void Post()
override {
2312 solver(),
this, &PositiveBooleanScalProdEqCst::Update,
"Update",
2320 if (sum_of_bound_variables_.Value() > constant_ ||
2321 sum_of_all_variables_.Value() < constant_) {
2324 const int64_t slack_up =
CapSub(constant_, sum_of_bound_variables_.Value());
2325 const int64_t slack_down =
CapSub(sum_of_all_variables_.Value(), constant_);
2326 const int64_t max_coeff = max_coefficient_.Value();
2327 if (slack_down < max_coeff || slack_up < max_coeff) {
2328 int64_t last_unbound = first_unbound_backward_.Value();
2329 for (; last_unbound >= 0; --last_unbound) {
2330 if (!
vars_[last_unbound]->Bound()) {
2331 if (coefs_[last_unbound] > slack_up) {
2332 vars_[last_unbound]->SetValue(0);
2333 }
else if (coefs_[last_unbound] > slack_down) {
2334 vars_[last_unbound]->SetValue(1);
2336 max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
2341 first_unbound_backward_.SetValue(solver(), last_unbound);
2345 void InitialPropagate()
override {
2346 Solver*
const s = solver();
2347 int last_unbound = -1;
2348 int64_t sum_bound = 0LL;
2349 int64_t sum_all = 0LL;
2356 last_unbound =
index;
2359 sum_of_bound_variables_.SetValue(s, sum_bound);
2360 sum_of_all_variables_.SetValue(s, sum_all);
2361 first_unbound_backward_.SetValue(s, last_unbound);
2367 sum_of_bound_variables_.SetValue(
2368 solver(),
CapAdd(sum_of_bound_variables_.Value(), coefs_[
var_index]));
2370 sum_of_all_variables_.SetValue(
2376 std::string DebugString()
const override {
2377 return absl::StrFormat(
"PositiveBooleanScalProd([%s], [%s]) == %d",
2379 absl::StrJoin(coefs_,
", "), constant_);
2382 void Accept(ModelVisitor*
const visitor)
const override {
2383 visitor->BeginVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2384 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2386 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2388 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, constant_);
2389 visitor->EndVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2393 std::vector<IntVar*>
vars_;
2394 std::vector<int64_t> coefs_;
2395 Rev<int> first_unbound_backward_;
2396 Rev<int64_t> sum_of_bound_variables_;
2397 Rev<int64_t> sum_of_all_variables_;
2399 Rev<int64_t> max_coefficient_;
2404#define IS_TYPE(type, tag) type.compare(ModelVisitor::tag) == 0
2406class ExprLinearizer :
public ModelParser {
2408 explicit ExprLinearizer(
2409 absl::flat_hash_map<IntVar*, int64_t>*
const variables_to_coefficients)
2410 : variables_to_coefficients_(variables_to_coefficients), constant_(0) {}
2412 ~ExprLinearizer()
override {}
2415 void BeginVisitModel(
const std::string& solver_name)
override {
2416 LOG(FATAL) <<
"Should not be here";
2419 void EndVisitModel(
const std::string& solver_name)
override {
2420 LOG(FATAL) <<
"Should not be here";
2423 void BeginVisitConstraint(
const std::string& type_name,
2424 const Constraint*
const constraint)
override {
2425 LOG(FATAL) <<
"Should not be here";
2428 void EndVisitConstraint(
const std::string& type_name,
2429 const Constraint*
const constraint)
override {
2430 LOG(FATAL) <<
"Should not be here";
2433 void BeginVisitExtension(
const std::string& type)
override {}
2435 void EndVisitExtension(
const std::string& type)
override {}
2436 void BeginVisitIntegerExpression(
const std::string& type_name,
2437 const IntExpr*
const expr)
override {
2441 void EndVisitIntegerExpression(
const std::string& type_name,
2442 const IntExpr*
const expr)
override {
2443 if (
IS_TYPE(type_name, kSum)) {
2445 }
else if (
IS_TYPE(type_name, kScalProd)) {
2446 VisitScalProd(expr);
2447 }
else if (
IS_TYPE(type_name, kDifference)) {
2448 VisitDifference(expr);
2449 }
else if (
IS_TYPE(type_name, kOpposite)) {
2450 VisitOpposite(expr);
2451 }
else if (
IS_TYPE(type_name, kProduct)) {
2453 }
else if (
IS_TYPE(type_name, kTrace)) {
2456 VisitIntegerExpression(expr);
2461 void VisitIntegerVariable(
const IntVar*
const variable,
2462 const std::string& operation, int64_t
value,
2463 IntVar*
const delegate)
override {
2464 if (operation == ModelVisitor::kSumOperation) {
2466 VisitSubExpression(delegate);
2467 }
else if (operation == ModelVisitor::kDifferenceOperation) {
2470 VisitSubExpression(delegate);
2472 }
else if (operation == ModelVisitor::kProductOperation) {
2473 PushMultiplier(
value);
2474 VisitSubExpression(delegate);
2476 }
else if (operation == ModelVisitor::kTraceOperation) {
2477 VisitSubExpression(delegate);
2481 void VisitIntegerVariable(
const IntVar*
const variable,
2482 IntExpr*
const delegate)
override {
2483 if (delegate !=
nullptr) {
2484 VisitSubExpression(delegate);
2486 if (variable->Bound()) {
2487 AddConstant(variable->Min());
2489 RegisterExpression(variable, 1);
2495 void VisitIntegerArgument(
const std::string& arg_name,
2496 int64_t
value)
override {
2497 Top()->SetIntegerArgument(arg_name,
value);
2500 void VisitIntegerArrayArgument(
const std::string& arg_name,
2501 const std::vector<int64_t>& values)
override {
2502 Top()->SetIntegerArrayArgument(arg_name, values);
2505 void VisitIntegerMatrixArgument(
const std::string& arg_name,
2506 const IntTupleSet& values)
override {
2507 Top()->SetIntegerMatrixArgument(arg_name, values);
2511 void VisitIntegerExpressionArgument(
const std::string& arg_name,
2512 IntExpr*
const argument)
override {
2513 Top()->SetIntegerExpressionArgument(arg_name, argument);
2516 void VisitIntegerVariableArrayArgument(
2517 const std::string& arg_name,
2518 const std::vector<IntVar*>& arguments)
override {
2519 Top()->SetIntegerVariableArrayArgument(arg_name, arguments);
2523 void VisitIntervalArgument(
const std::string& arg_name,
2524 IntervalVar*
const argument)
override {}
2526 void VisitIntervalArrayArgument(
2527 const std::string& arg_name,
2528 const std::vector<IntervalVar*>& argument)
override {}
2530 void Visit(
const IntExpr*
const expr, int64_t multiplier) {
2531 if (expr->Min() == expr->Max()) {
2532 constant_ = CapAdd(constant_, CapProd(expr->Min(), multiplier));
2534 PushMultiplier(multiplier);
2540 int64_t Constant()
const {
return constant_; }
2542 std::string DebugString()
const override {
return "ExprLinearizer"; }
2545 void BeginVisit(
bool active) { PushArgumentHolder(); }
2547 void EndVisit() { PopArgumentHolder(); }
2549 void VisitSubExpression(
const IntExpr*
const cp_expr) {
2550 cp_expr->Accept(
this);
2553 void VisitSum(
const IntExpr*
const cp_expr) {
2554 if (Top()->HasIntegerVariableArrayArgument(ModelVisitor::kVarsArgument)) {
2555 const std::vector<IntVar*>& cp_vars =
2556 Top()->FindIntegerVariableArrayArgumentOrDie(
2557 ModelVisitor::kVarsArgument);
2558 for (
int i = 0; i < cp_vars.size(); ++i) {
2559 VisitSubExpression(cp_vars[i]);
2561 }
else if (Top()->HasIntegerExpressionArgument(
2562 ModelVisitor::kLeftArgument)) {
2563 const IntExpr*
const left = Top()->FindIntegerExpressionArgumentOrDie(
2564 ModelVisitor::kLeftArgument);
2565 const IntExpr*
const right = Top()->FindIntegerExpressionArgumentOrDie(
2566 ModelVisitor::kRightArgument);
2567 VisitSubExpression(left);
2568 VisitSubExpression(right);
2570 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2571 ModelVisitor::kExpressionArgument);
2572 const int64_t
value =
2573 Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2574 VisitSubExpression(expr);
2579 void VisitScalProd(
const IntExpr*
const cp_expr) {
2580 const std::vector<IntVar*>& cp_vars =
2581 Top()->FindIntegerVariableArrayArgumentOrDie(
2582 ModelVisitor::kVarsArgument);
2583 const std::vector<int64_t>& cp_coefficients =
2584 Top()->FindIntegerArrayArgumentOrDie(
2585 ModelVisitor::kCoefficientsArgument);
2586 CHECK_EQ(cp_vars.size(), cp_coefficients.size());
2587 for (
int i = 0; i < cp_vars.size(); ++i) {
2590 VisitSubExpression(cp_vars[i]);
2595 void VisitDifference(
const IntExpr*
const cp_expr) {
2596 if (Top()->HasIntegerExpressionArgument(ModelVisitor::kLeftArgument)) {
2597 const IntExpr*
const left = Top()->FindIntegerExpressionArgumentOrDie(
2598 ModelVisitor::kLeftArgument);
2599 const IntExpr*
const right = Top()->FindIntegerExpressionArgumentOrDie(
2600 ModelVisitor::kRightArgument);
2601 VisitSubExpression(left);
2603 VisitSubExpression(right);
2606 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2607 ModelVisitor::kExpressionArgument);
2608 const int64_t
value =
2609 Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2612 VisitSubExpression(expr);
2617 void VisitOpposite(
const IntExpr*
const cp_expr) {
2618 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2619 ModelVisitor::kExpressionArgument);
2621 VisitSubExpression(expr);
2625 void VisitProduct(
const IntExpr*
const cp_expr) {
2626 if (Top()->HasIntegerExpressionArgument(
2627 ModelVisitor::kExpressionArgument)) {
2628 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2629 ModelVisitor::kExpressionArgument);
2630 const int64_t
value =
2631 Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2632 PushMultiplier(
value);
2633 VisitSubExpression(expr);
2636 RegisterExpression(cp_expr, 1);
2640 void VisitTrace(
const IntExpr*
const cp_expr) {
2641 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2642 ModelVisitor::kExpressionArgument);
2643 VisitSubExpression(expr);
2646 void VisitIntegerExpression(
const IntExpr*
const cp_expr) {
2647 RegisterExpression(cp_expr, 1);
2650 void RegisterExpression(
const IntExpr*
const expr, int64_t
coef) {
2652 (*variables_to_coefficients_)[
const_cast<IntExpr*
>(expr)->Var()];
2656 void AddConstant(int64_t constant) {
2657 constant_ = CapAdd(constant_, CapProd(constant, multipliers_.back()));
2660 void PushMultiplier(int64_t multiplier) {
2661 if (multipliers_.empty()) {
2662 multipliers_.push_back(multiplier);
2664 multipliers_.push_back(CapProd(multiplier, multipliers_.back()));
2668 void PopMultiplier() { multipliers_.pop_back(); }
2672 absl::flat_hash_map<IntVar*, int64_t>*
const variables_to_coefficients_;
2673 std::vector<int64_t> multipliers_;
2680void DeepLinearize(Solver*
const solver,
const std::vector<IntVar*>& pre_vars,
2681 absl::Span<const int64_t> pre_coefs,
2682 std::vector<IntVar*>* vars, std::vector<int64_t>* coefs,
2683 int64_t* constant) {
2684 CHECK(solver !=
nullptr);
2685 CHECK(vars !=
nullptr);
2686 CHECK(coefs !=
nullptr);
2687 CHECK(constant !=
nullptr);
2689 vars->reserve(pre_vars.size());
2690 coefs->reserve(pre_coefs.size());
2692 bool need_linearization =
false;
2693 for (
int i = 0;
i < pre_vars.size(); ++
i) {
2694 IntVar*
const variable = pre_vars[
i];
2696 if (variable->Bound()) {
2698 }
else if (solver->CastExpression(variable) ==
nullptr) {
2699 vars->push_back(variable);
2702 need_linearization =
true;
2708 if (need_linearization) {
2710 absl::flat_hash_map<IntVar*, int64_t> variables_to_coefficients;
2711 ExprLinearizer linearizer(&variables_to_coefficients);
2712 for (
int i = 0;
i < pre_vars.size(); ++
i) {
2713 linearizer.Visit(pre_vars[i], pre_coefs[i]);
2715 *constant = linearizer.Constant();
2716 for (
const auto& variable_to_coefficient : variables_to_coefficients) {
2717 if (variable_to_coefficient.second != 0) {
2718 vars->push_back(variable_to_coefficient.first);
2719 coefs->push_back(variable_to_coefficient.second);
2725Constraint* MakeScalProdEqualityFct(Solver*
const solver,
2726 const std::vector<IntVar*>& pre_vars,
2727 absl::Span<const int64_t> pre_coefs,
2729 int64_t constant = 0;
2730 std::vector<IntVar*> vars;
2731 std::vector<int64_t> coefs;
2732 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2733 cst =
CapSub(cst, constant);
2735 const int size = vars.size();
2737 return cst == 0 ? solver->MakeTrueConstraint()
2738 : solver->MakeFalseConstraint();
2742 for (
int i = 0;
i <
size; ++
i) {
2745 return sum == cst ? solver->MakeTrueConstraint()
2746 : solver->MakeFalseConstraint();
2749 return solver->MakeSumEquality(vars, cst);
2753 return solver->RevAlloc(
2754 new PositiveBooleanScalProdEqCst(solver, vars, coefs, cst));
2757 std::vector<int64_t> opp_coefs(coefs.size());
2758 for (
int i = 0;
i < coefs.size(); ++
i) {
2759 opp_coefs[
i] = -coefs[
i];
2761 return solver->RevAlloc(
2762 new PositiveBooleanScalProdEqCst(solver, vars, opp_coefs, -cst));
2770 for (
int i = 0;
i <
size; ++
i) {
2771 if (coefs[i] == 0 || vars[i]->Bound()) {
2773 }
else if (coefs[i] > 0) {
2779 if (positives > 0 && negatives > 0) {
2780 std::vector<IntVar*> pos_terms;
2781 std::vector<IntVar*> neg_terms;
2783 for (
int i = 0;
i <
size; ++
i) {
2784 if (coefs[i] == 0 || vars[i]->Bound()) {
2786 }
else if (coefs[i] > 0) {
2787 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2789 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2792 if (negatives == 1) {
2794 pos_terms.push_back(solver->MakeIntConst(-rhs));
2796 return solver->MakeSumEquality(pos_terms, neg_terms[0]);
2797 }
else if (positives == 1) {
2799 neg_terms.push_back(solver->MakeIntConst(rhs));
2801 return solver->MakeSumEquality(neg_terms, pos_terms[0]);
2804 neg_terms.push_back(solver->MakeIntConst(rhs));
2806 return solver->MakeEquality(solver->MakeSum(pos_terms),
2807 solver->MakeSum(neg_terms));
2809 }
else if (positives == 1) {
2810 IntExpr* pos_term =
nullptr;
2812 for (
int i = 0;
i <
size; ++
i) {
2813 if (coefs[i] == 0 || vars[i]->Bound()) {
2815 }
else if (coefs[i] > 0) {
2816 pos_term = solver->MakeProd(vars[i], coefs[i]);
2818 LOG(FATAL) <<
"Should not be here";
2821 return solver->MakeEquality(pos_term, rhs);
2822 }
else if (negatives == 1) {
2823 IntExpr* neg_term =
nullptr;
2825 for (
int i = 0;
i <
size; ++
i) {
2826 if (coefs[i] == 0 || vars[i]->Bound()) {
2828 }
else if (coefs[i] > 0) {
2829 LOG(FATAL) <<
"Should not be here";
2831 neg_term = solver->MakeProd(vars[i], -coefs[i]);
2834 return solver->MakeEquality(neg_term, -rhs);
2835 }
else if (positives > 1) {
2836 std::vector<IntVar*> pos_terms;
2838 for (
int i = 0;
i <
size; ++
i) {
2839 if (coefs[i] == 0 || vars[i]->Bound()) {
2841 }
else if (coefs[i] > 0) {
2842 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2844 LOG(FATAL) <<
"Should not be here";
2847 return solver->MakeSumEquality(pos_terms, rhs);
2848 }
else if (negatives > 1) {
2849 std::vector<IntVar*> neg_terms;
2851 for (
int i = 0;
i <
size; ++
i) {
2852 if (coefs[i] == 0 || vars[i]->Bound()) {
2854 }
else if (coefs[i] > 0) {
2855 LOG(FATAL) <<
"Should not be here";
2857 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2860 return solver->MakeSumEquality(neg_terms, -rhs);
2862 std::vector<IntVar*> terms;
2863 for (
int i = 0;
i <
size; ++
i) {
2864 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2866 return solver->MakeSumEquality(terms, solver->MakeIntConst(cst));
2869Constraint* MakeScalProdEqualityVarFct(Solver*
const solver,
2870 const std::vector<IntVar*>& pre_vars,
2871 absl::Span<const int64_t> pre_coefs,
2872 IntVar*
const target) {
2873 int64_t constant = 0;
2874 std::vector<IntVar*> vars;
2875 std::vector<int64_t> coefs;
2876 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2878 const int size = vars.size();
2879 if (
size == 0 || AreAllNull<int64_t>(coefs)) {
2880 return solver->MakeEquality(target, constant);
2883 return solver->MakeSumEquality(vars,
2884 solver->MakeSum(target, -constant)->Var());
2888 return solver->RevAlloc(
new PositiveBooleanScalProdEqVar(
2889 solver, vars, coefs, solver->MakeSum(target, -constant)->Var()));
2891 std::vector<IntVar*> terms;
2892 for (
int i = 0;
i <
size; ++
i) {
2893 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2895 return solver->MakeSumEquality(terms,
2896 solver->MakeSum(target, -constant)->Var());
2899Constraint* MakeScalProdGreaterOrEqualFct(Solver* solver,
2900 const std::vector<IntVar*>& pre_vars,
2901 absl::Span<const int64_t> pre_coefs,
2903 int64_t constant = 0;
2904 std::vector<IntVar*> vars;
2905 std::vector<int64_t> coefs;
2906 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2907 cst =
CapSub(cst, constant);
2909 const int size = vars.size();
2910 if (
size == 0 || AreAllNull<int64_t>(coefs)) {
2911 return cst <= 0 ? solver->MakeTrueConstraint()
2912 : solver->MakeFalseConstraint();
2915 return solver->MakeSumGreaterOrEqual(vars, cst);
2919 std::vector<IntVar*> terms;
2920 for (
int i = 0;
i <
size; ++
i) {
2922 terms.push_back(vars[i]);
2925 return solver->MakeSumGreaterOrEqual(terms, 1);
2927 std::vector<IntVar*> terms;
2928 for (
int i = 0;
i <
size; ++
i) {
2929 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2931 return solver->MakeSumGreaterOrEqual(terms, cst);
2934Constraint* MakeScalProdLessOrEqualFct(Solver* solver,
2935 const std::vector<IntVar*>& pre_vars,
2936 absl::Span<const int64_t> pre_coefs,
2938 int64_t constant = 0;
2939 std::vector<IntVar*> vars;
2940 std::vector<int64_t> coefs;
2941 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2944 const int size = vars.size();
2945 if (
size == 0 || AreAllNull<int64_t>(coefs)) {
2946 return upper_bound >= 0 ? solver->MakeTrueConstraint()
2947 : solver->MakeFalseConstraint();
2952 for (
int i = 0;
i <
size; ++
i) {
2955 return cst <=
upper_bound ? solver->MakeTrueConstraint()
2956 : solver->MakeFalseConstraint();
2959 return solver->MakeSumLessOrEqual(vars,
upper_bound);
2962 return solver->RevAlloc(
2963 new BooleanScalProdLessConstant(solver, vars, coefs,
upper_bound));
2969 for (
int i = 0;
i <
size; ++
i) {
2970 if (coefs[i] == 0 || vars[i]->Bound()) {
2972 }
else if (coefs[i] > 0) {
2978 if (positives > 0 && negatives > 0) {
2979 std::vector<IntVar*> pos_terms;
2980 std::vector<IntVar*> neg_terms;
2982 for (
int i = 0;
i <
size; ++
i) {
2983 if (coefs[i] == 0 || vars[i]->Bound()) {
2985 }
else if (coefs[i] > 0) {
2986 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2988 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2991 if (negatives == 1) {
2992 IntExpr*
const neg_term = solver->MakeSum(neg_terms[0], rhs);
2993 return solver->MakeLessOrEqual(solver->MakeSum(pos_terms), neg_term);
2994 }
else if (positives == 1) {
2995 IntExpr*
const pos_term = solver->MakeSum(pos_terms[0], -rhs);
2996 return solver->MakeGreaterOrEqual(solver->MakeSum(neg_terms), pos_term);
2999 neg_terms.push_back(solver->MakeIntConst(rhs));
3001 return solver->MakeLessOrEqual(solver->MakeSum(pos_terms),
3002 solver->MakeSum(neg_terms));
3004 }
else if (positives == 1) {
3005 IntExpr* pos_term =
nullptr;
3007 for (
int i = 0;
i <
size; ++
i) {
3008 if (coefs[i] == 0 || vars[i]->Bound()) {
3010 }
else if (coefs[i] > 0) {
3011 pos_term = solver->MakeProd(vars[i], coefs[i]);
3013 LOG(FATAL) <<
"Should not be here";
3016 return solver->MakeLessOrEqual(pos_term, rhs);
3017 }
else if (negatives == 1) {
3018 IntExpr* neg_term =
nullptr;
3020 for (
int i = 0;
i <
size; ++
i) {
3021 if (coefs[i] == 0 || vars[i]->Bound()) {
3023 }
else if (coefs[i] > 0) {
3024 LOG(FATAL) <<
"Should not be here";
3026 neg_term = solver->MakeProd(vars[i], -coefs[i]);
3029 return solver->MakeGreaterOrEqual(neg_term, -rhs);
3030 }
else if (positives > 1) {
3031 std::vector<IntVar*> pos_terms;
3033 for (
int i = 0;
i <
size; ++
i) {
3034 if (coefs[i] == 0 || vars[i]->Bound()) {
3036 }
else if (coefs[i] > 0) {
3037 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3039 LOG(FATAL) <<
"Should not be here";
3042 return solver->MakeSumLessOrEqual(pos_terms, rhs);
3043 }
else if (negatives > 1) {
3044 std::vector<IntVar*> neg_terms;
3046 for (
int i = 0;
i <
size; ++
i) {
3047 if (coefs[i] == 0 || vars[i]->Bound()) {
3049 }
else if (coefs[i] > 0) {
3050 LOG(FATAL) <<
"Should not be here";
3052 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
3055 return solver->MakeSumGreaterOrEqual(neg_terms, -rhs);
3057 std::vector<IntVar*> terms;
3058 for (
int i = 0;
i <
size; ++
i) {
3059 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3061 return solver->MakeLessOrEqual(solver->MakeSum(terms),
upper_bound);
3064IntExpr* MakeSumArrayAux(Solver*
const solver,
const std::vector<IntVar*>& vars,
3066 const int size = vars.size();
3068 int64_t new_min = 0;
3069 int64_t new_max = 0;
3070 for (
int i = 0;
i <
size; ++
i) {
3071 if (new_min != std::numeric_limits<int64_t>::min()) {
3072 new_min =
CapAdd(vars[i]->Min(), new_min);
3074 if (new_max != std::numeric_limits<int64_t>::max()) {
3075 new_max =
CapAdd(vars[i]->Max(), new_max);
3078 IntExpr*
const cache =
3079 solver->Cache()->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_SUM);
3080 if (cache !=
nullptr) {
3081 return solver->MakeSum(cache, constant);
3083 const std::string
name =
3084 absl::StrFormat(
"Sum([%s])",
JoinNamePtr(vars,
", "));
3085 IntVar*
const sum_var = solver->MakeIntVar(new_min, new_max,
name);
3087 solver->AddConstraint(
3088 solver->RevAlloc(
new SumBooleanEqualToVar(solver, vars, sum_var)));
3090 solver->AddConstraint(
3091 solver->RevAlloc(
new SmallSumConstraint(solver, vars, sum_var)));
3093 solver->AddConstraint(
3094 solver->RevAlloc(
new SumConstraint(solver, vars, sum_var)));
3096 solver->Cache()->InsertVarArrayExpression(sum_var, vars,
3097 ModelCache::VAR_ARRAY_SUM);
3098 return solver->MakeSum(sum_var, constant);
3102IntExpr* MakeSumAux(Solver*
const solver,
const std::vector<IntVar*>& vars,
3104 const int size = vars.size();
3106 return solver->MakeIntConst(constant);
3107 }
else if (
size == 1) {
3108 return solver->MakeSum(vars[0], constant);
3109 }
else if (
size == 2) {
3110 return solver->MakeSum(solver->MakeSum(vars[0], vars[1]), constant);
3112 return MakeSumArrayAux(solver, vars, constant);
3116IntExpr* MakeScalProdAux(Solver* solver,
const std::vector<IntVar*>& vars,
3117 const std::vector<int64_t>& coefs, int64_t constant) {
3119 return MakeSumAux(solver, vars, constant);
3122 const int size = vars.size();
3124 return solver->MakeIntConst(constant);
3125 }
else if (
size == 1) {
3126 return solver->MakeSum(solver->MakeProd(vars[0], coefs[0]), constant);
3127 }
else if (
size == 2) {
3128 if (coefs[0] > 0 && coefs[1] < 0) {
3129 return solver->MakeSum(
3130 solver->MakeDifference(solver->MakeProd(vars[0], coefs[0]),
3131 solver->MakeProd(vars[1], -coefs[1])),
3133 }
else if (coefs[0] < 0 && coefs[1] > 0) {
3134 return solver->MakeSum(
3135 solver->MakeDifference(solver->MakeProd(vars[1], coefs[1]),
3136 solver->MakeProd(vars[0], -coefs[0])),
3139 return solver->MakeSum(
3140 solver->MakeSum(solver->MakeProd(vars[0], coefs[0]),
3141 solver->MakeProd(vars[1], coefs[1])),
3147 if (vars.size() > 8) {
3148 return solver->MakeSum(
3150 ->RegisterIntExpr(solver->RevAlloc(
3151 new PositiveBooleanScalProd(solver, vars, coefs)))
3155 return solver->MakeSum(
3156 solver->RegisterIntExpr(solver->RevAlloc(
3157 new PositiveBooleanScalProd(solver, vars, coefs))),
3168 std::vector<int64_t> positive_coefs;
3169 std::vector<int64_t> negative_coefs;
3170 std::vector<IntVar*> positive_coef_vars;
3171 std::vector<IntVar*> negative_coef_vars;
3172 for (
int i = 0;
i <
size; ++
i) {
3173 const int coef = coefs[
i];
3175 positive_coefs.push_back(
coef);
3176 positive_coef_vars.push_back(vars[i]);
3177 }
else if (
coef < 0) {
3178 negative_coefs.push_back(-
coef);
3179 negative_coef_vars.push_back(vars[i]);
3182 CHECK_GT(negative_coef_vars.size(), 0);
3183 IntExpr*
const negatives =
3184 MakeScalProdAux(solver, negative_coef_vars, negative_coefs, 0);
3185 if (!positive_coef_vars.empty()) {
3186 IntExpr*
const positives = MakeScalProdAux(solver, positive_coef_vars,
3187 positive_coefs, constant);
3188 return solver->MakeDifference(positives, negatives);
3190 return solver->MakeDifference(constant, negatives);
3195 std::vector<IntVar*> terms;
3196 for (
int i = 0;
i <
size; ++
i) {
3197 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3199 return MakeSumArrayAux(solver, terms, constant);
3202IntExpr* MakeScalProdFct(Solver* solver,
const std::vector<IntVar*>& pre_vars,
3203 absl::Span<const int64_t> pre_coefs) {
3204 int64_t constant = 0;
3205 std::vector<IntVar*> vars;
3206 std::vector<int64_t> coefs;
3207 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
3210 return solver->MakeIntConst(constant);
3213 int64_t gcd = std::abs(coefs[0]);
3214 for (
int i = 1;
i < coefs.size(); ++
i) {
3215 gcd = MathUtil::GCD64(gcd, std::abs(coefs[i]));
3220 if (constant != 0 && gcd != 1) {
3221 gcd = MathUtil::GCD64(gcd, std::abs(constant));
3224 for (
int i = 0;
i < coefs.size(); ++
i) {
3227 return solver->MakeProd(
3228 MakeScalProdAux(solver, vars, coefs, constant / gcd), gcd);
3230 return MakeScalProdAux(solver, vars, coefs, constant);
3233IntExpr* MakeSumFct(Solver* solver,
const std::vector<IntVar*>& pre_vars) {
3234 absl::flat_hash_map<IntVar*, int64_t> variables_to_coefficients;
3235 ExprLinearizer linearizer(&variables_to_coefficients);
3236 for (
int i = 0;
i < pre_vars.size(); ++
i) {
3237 linearizer.Visit(pre_vars[i], 1);
3239 const int64_t constant = linearizer.Constant();
3240 std::vector<IntVar*> vars;
3241 std::vector<int64_t> coefs;
3242 for (
const auto& variable_to_coefficient : variables_to_coefficients) {
3243 if (variable_to_coefficient.second != 0) {
3244 vars.push_back(variable_to_coefficient.first);
3245 coefs.push_back(variable_to_coefficient.second);
3248 return MakeScalProdAux(solver, vars, coefs, constant);
3254IntExpr* Solver::MakeSum(
const std::vector<IntVar*>& vars) {
3255 const int size = vars.size();
3257 return MakeIntConst(int64_t{0});
3258 }
else if (
size == 1) {
3260 }
else if (
size == 2) {
3261 return MakeSum(vars[0], vars[1]);
3264 model_cache_->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_SUM);
3265 if (cache !=
nullptr) {
3268 int64_t new_min = 0;
3269 int64_t new_max = 0;
3270 for (
int i = 0; i <
size; ++i) {
3271 if (new_min != std::numeric_limits<int64_t>::min()) {
3272 new_min =
CapAdd(vars[i]->Min(), new_min);
3274 if (new_max != std::numeric_limits<int64_t>::max()) {
3275 new_max =
CapAdd(vars[i]->Max(), new_max);
3281 const std::string
name =
3282 absl::StrFormat(
"BooleanSum([%s])",
JoinNamePtr(vars,
", "));
3283 sum_expr = MakeIntVar(new_min, new_max,
name);
3285 RevAlloc(
new SumBooleanEqualToVar(
this, vars, sum_expr->
Var())));
3286 }
else if (new_min != std::numeric_limits<int64_t>::min() &&
3287 new_max != std::numeric_limits<int64_t>::max()) {
3288 sum_expr = MakeSumFct(
this, vars);
3290 const std::string
name =
3291 absl::StrFormat(
"Sum([%s])",
JoinNamePtr(vars,
", "));
3292 sum_expr = MakeIntVar(new_min, new_max,
name);
3294 RevAlloc(
new SafeSumConstraint(
this, vars, sum_expr->
Var())));
3296 model_cache_->InsertVarArrayExpression(sum_expr, vars,
3297 ModelCache::VAR_ARRAY_SUM);
3303IntExpr* Solver::MakeMin(
const std::vector<IntVar*>& vars) {
3304 const int size = vars.size();
3306 LOG(WARNING) <<
"operations_research::Solver::MakeMin() was called with an "
3307 "empty list of variables. Was this intentional?";
3308 return MakeIntConst(std::numeric_limits<int64_t>::max());
3309 }
else if (
size == 1) {
3311 }
else if (
size == 2) {
3312 return MakeMin(vars[0], vars[1]);
3315 model_cache_->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_MIN);
3316 if (cache !=
nullptr) {
3320 IntVar*
const new_var = MakeBoolVar();
3321 AddConstraint(RevAlloc(
new ArrayBoolAndEq(
this, vars, new_var)));
3322 model_cache_->InsertVarArrayExpression(new_var, vars,
3323 ModelCache::VAR_ARRAY_MIN);
3326 int64_t new_min = std::numeric_limits<int64_t>::max();
3327 int64_t new_max = std::numeric_limits<int64_t>::max();
3328 for (
int i = 0; i <
size; ++i) {
3329 new_min = std::min(new_min, vars[i]->Min());
3330 new_max = std::min(new_max, vars[i]->Max());
3332 IntVar*
const new_var = MakeIntVar(new_min, new_max);
3333 if (
size <= parameters_.array_split_size()) {
3334 AddConstraint(RevAlloc(
new SmallMinConstraint(
this, vars, new_var)));
3336 AddConstraint(RevAlloc(
new MinConstraint(
this, vars, new_var)));
3338 model_cache_->InsertVarArrayExpression(new_var, vars,
3339 ModelCache::VAR_ARRAY_MIN);
3346IntExpr* Solver::MakeMax(
const std::vector<IntVar*>& vars) {
3347 const int size = vars.size();
3349 LOG(WARNING) <<
"operations_research::Solver::MakeMax() was called with an "
3350 "empty list of variables. Was this intentional?";
3351 return MakeIntConst(std::numeric_limits<int64_t>::min());
3352 }
else if (
size == 1) {
3354 }
else if (
size == 2) {
3355 return MakeMax(vars[0], vars[1]);
3358 model_cache_->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_MAX);
3359 if (cache !=
nullptr) {
3363 IntVar*
const new_var = MakeBoolVar();
3364 AddConstraint(RevAlloc(
new ArrayBoolOrEq(
this, vars, new_var)));
3365 model_cache_->InsertVarArrayExpression(new_var, vars,
3366 ModelCache::VAR_ARRAY_MIN);
3369 int64_t new_min = std::numeric_limits<int64_t>::min();
3370 int64_t new_max = std::numeric_limits<int64_t>::min();
3371 for (
int i = 0; i <
size; ++i) {
3372 new_min = std::max(new_min, vars[i]->Min());
3373 new_max = std::max(new_max, vars[i]->Max());
3375 IntVar*
const new_var = MakeIntVar(new_min, new_max);
3376 if (
size <= parameters_.array_split_size()) {
3377 AddConstraint(RevAlloc(
new SmallMaxConstraint(
this, vars, new_var)));
3379 AddConstraint(RevAlloc(
new MaxConstraint(
this, vars, new_var)));
3381 model_cache_->InsertVarArrayExpression(new_var, vars,
3382 ModelCache::VAR_ARRAY_MAX);
3389Constraint* Solver::MakeMinEquality(
const std::vector<IntVar*>& vars,
3391 const int size = vars.size();
3394 return RevAlloc(
new ArrayBoolAndEq(
this, vars, min_var));
3395 }
else if (
size <= parameters_.array_split_size()) {
3396 return RevAlloc(
new SmallMinConstraint(
this, vars, min_var));
3398 return RevAlloc(
new MinConstraint(
this, vars, min_var));
3400 }
else if (
size == 2) {
3401 return MakeEquality(MakeMin(vars[0], vars[1]), min_var);
3402 }
else if (
size == 1) {
3403 return MakeEquality(vars[0], min_var);
3405 LOG(WARNING) <<
"operations_research::Solver::MakeMinEquality() was called "
3406 "with an empty list of variables. Was this intentional?";
3407 return MakeEquality(min_var, std::numeric_limits<int64_t>::max());
3411Constraint* Solver::MakeMaxEquality(
const std::vector<IntVar*>& vars,
3413 const int size = vars.size();
3416 return RevAlloc(
new ArrayBoolOrEq(
this, vars, max_var));
3417 }
else if (
size <= parameters_.array_split_size()) {
3418 return RevAlloc(
new SmallMaxConstraint(
this, vars, max_var));
3420 return RevAlloc(
new MaxConstraint(
this, vars, max_var));
3422 }
else if (
size == 2) {
3423 return MakeEquality(MakeMax(vars[0], vars[1]), max_var);
3424 }
else if (
size == 1) {
3425 return MakeEquality(vars[0], max_var);
3427 LOG(WARNING) <<
"operations_research::Solver::MakeMaxEquality() was called "
3428 "with an empty list of variables. Was this intentional?";
3429 return MakeEquality(max_var, std::numeric_limits<int64_t>::min());
3433Constraint* Solver::MakeSumLessOrEqual(
const std::vector<IntVar*>& vars,
3435 const int size = vars.size();
3437 return RevAlloc(
new SumBooleanLessOrEqualToOne(
this, vars));
3439 return MakeLessOrEqual(MakeSum(vars), cst);
3443Constraint* Solver::MakeSumGreaterOrEqual(
const std::vector<IntVar*>& vars,
3445 const int size = vars.size();
3447 return RevAlloc(
new SumBooleanGreaterOrEqualToOne(
this, vars));
3449 return MakeGreaterOrEqual(MakeSum(vars), cst);
3453Constraint* Solver::MakeSumEquality(
const std::vector<IntVar*>& vars,
3455 const int size = vars.size();
3457 return cst == 0 ? MakeTrueConstraint() : MakeFalseConstraint();
3461 return RevAlloc(
new SumBooleanEqualToOne(
this, vars));
3462 }
else if (cst < 0 || cst >
size) {
3463 return MakeFalseConstraint();
3465 return RevAlloc(
new SumBooleanEqualToVar(
this, vars, MakeIntConst(cst)));
3468 if (vars.size() == 1) {
3469 return MakeEquality(vars[0], cst);
3470 }
else if (vars.size() == 2) {
3471 return MakeEquality(vars[0], MakeDifference(cst, vars[1]));
3473 if (DetectSumOverflow(vars)) {
3474 return RevAlloc(
new SafeSumConstraint(
this, vars, MakeIntConst(cst)));
3475 }
else if (
size <= parameters_.array_split_size()) {
3476 return RevAlloc(
new SmallSumConstraint(
this, vars, MakeIntConst(cst)));
3478 return RevAlloc(
new SumConstraint(
this, vars, MakeIntConst(cst)));
3483Constraint* Solver::MakeSumEquality(
const std::vector<IntVar*>& vars,
3485 const int size = vars.size();
3487 return MakeEquality(
var,
Zero());
3490 return RevAlloc(
new SumBooleanEqualToVar(
this, vars,
var));
3491 }
else if (
size == 0) {
3492 return MakeEquality(
var,
Zero());
3493 }
else if (
size == 1) {
3494 return MakeEquality(vars[0],
var);
3495 }
else if (
size == 2) {
3496 return MakeEquality(MakeSum(vars[0], vars[1]),
var);
3498 if (DetectSumOverflow(vars)) {
3499 return RevAlloc(
new SafeSumConstraint(
this, vars,
var));
3500 }
else if (
size <= parameters_.array_split_size()) {
3501 return RevAlloc(
new SmallSumConstraint(
this, vars,
var));
3503 return RevAlloc(
new SumConstraint(
this, vars,
var));
3509 const std::vector<IntVar*>& vars,
const std::vector<int64_t>&
coefficients,
3512 return MakeScalProdEqualityFct(
this, vars,
coefficients, cst);
3515Constraint* Solver::MakeScalProdEquality(
const std::vector<IntVar*>& vars,
3523 const std::vector<IntVar*>& vars,
const std::vector<int64_t>&
coefficients,
3526 return MakeScalProdEqualityVarFct(
this, vars,
coefficients, target);
3529Constraint* Solver::MakeScalProdEquality(
const std::vector<IntVar*>& vars,
3538 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& coeffs,
3540 DCHECK_EQ(vars.size(), coeffs.size());
3541 return MakeScalProdGreaterOrEqualFct(
this, vars, coeffs, cst);
3544Constraint* Solver::MakeScalProdGreaterOrEqual(
const std::vector<IntVar*>& vars,
3545 const std::vector<int>& coeffs,
3547 DCHECK_EQ(vars.size(), coeffs.size());
3548 return MakeScalProdGreaterOrEqualFct(
this, vars,
ToInt64Vector(coeffs), cst);
3552 const std::vector<IntVar*>& vars,
const std::vector<int64_t>&
coefficients,
3555 return MakeScalProdLessOrEqualFct(
this, vars,
coefficients, cst);
3559 const std::vector<IntVar*>& vars,
const std::vector<int>&
coefficients,
3566IntExpr* Solver::MakeScalProd(
const std::vector<IntVar*>& vars,
3567 const std::vector<int64_t>& coefs) {
3568 DCHECK_EQ(vars.size(), coefs.size());
3569 return MakeScalProdFct(
this, vars, coefs);
3572IntExpr* Solver::MakeScalProd(
const std::vector<IntVar*>& vars,
3573 const std::vector<int>& coefs) {
3574 DCHECK_EQ(vars.size(), coefs.size());
const std::vector< IntVar * > vars_
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[]
const std::string name
A name for logging purposes.
const std::vector< IntVar * > vars_
#define IS_TYPE(type, tag)
--— Linearizer --—
absl::Span< const double > coefficients
std::pair< double, double > Range
A range of values, first is the minimum, second is the maximum.
In SWIG mode, we don't want anything besides these top-level includes.
int64_t CapAdd(int64_t x, int64_t y)
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->DebugString().
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)
--— Vector manipulations --—
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)
Join v[i]->name().