24#include "absl/strings/str_format.h"
25#include "absl/strings/str_join.h"
38class TreeArrayConstraint :
public CastConstraint {
40 TreeArrayConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
41 IntVar*
const sum_var)
42 : CastConstraint(solver, sum_var),
44 block_size_(solver->
parameters().array_split_size()) {
45 std::vector<int> lengths;
46 lengths.push_back(
vars_.size());
47 while (lengths.back() > 1) {
48 const int current = lengths.back();
49 lengths.push_back((current + block_size_ - 1) / block_size_);
51 tree_.resize(lengths.size());
52 for (
int i = 0; i < lengths.size(); ++i) {
53 tree_[i].resize(lengths[lengths.size() - i - 1]);
57 root_node_ = &tree_[0][0];
60 std::string DebugStringInternal(
const std::string&
name)
const {
61 return absl::StrFormat(
"%s(%s) == %s",
name,
66 void AcceptInternal(
const std::string&
name,
67 ModelVisitor*
const visitor)
const {
68 visitor->BeginVisitConstraint(
name,
this);
73 visitor->EndVisitConstraint(
name,
this);
77 void ReduceRange(
int depth,
int position, int64_t delta_min,
79 NodeInfo*
const info = &tree_[depth][position];
81 info->node_min.SetValue(solver(),
82 CapAdd(info->node_min.Value(), delta_min));
85 info->node_max.SetValue(solver(),
86 CapSub(info->node_max.Value(), delta_max));
91 void SetRange(
int depth,
int position, int64_t new_min, int64_t new_max) {
92 NodeInfo*
const info = &tree_[depth][position];
93 if (new_min > info->node_min.Value()) {
94 info->node_min.SetValue(solver(), new_min);
96 if (new_max < info->
node_max.Value()) {
97 info->node_max.SetValue(solver(), new_max);
101 void InitLeaf(
int position, int64_t var_min, int64_t var_max) {
102 InitNode(MaxDepth(), position, var_min, var_max);
105 void InitNode(
int depth,
int position, int64_t
node_min, int64_t
node_max) {
106 tree_[depth][position].node_min.SetValue(solver(),
node_min);
107 tree_[depth][position].node_max.SetValue(solver(),
node_max);
110 int64_t Min(
int depth,
int position)
const {
111 return tree_[depth][position].node_min.Value();
114 int64_t Max(
int depth,
int position)
const {
115 return tree_[depth][position].node_max.Value();
118 int64_t RootMin()
const {
return root_node_->node_min.Value(); }
120 int64_t RootMax()
const {
return root_node_->node_max.Value(); }
122 int Parent(
int position)
const {
return position / block_size_; }
124 int ChildStart(
int position)
const {
return position * block_size_; }
126 int ChildEnd(
int depth,
int position)
const {
128 return std::min((position + 1) * block_size_ - 1, Width(depth + 1) - 1);
131 bool IsLeaf(
int depth)
const {
return depth == MaxDepth(); }
133 int MaxDepth()
const {
return tree_.size() - 1; }
135 int Width(
int depth)
const {
return tree_[depth].size(); }
147 std::vector<std::vector<NodeInfo> > tree_;
148 const int block_size_;
149 NodeInfo* root_node_;
164class SumConstraint :
public TreeArrayConstraint {
166 SumConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
167 IntVar*
const sum_var)
168 : TreeArrayConstraint(solver, vars, sum_var), sum_demon_(
nullptr) {}
170 ~SumConstraint()
override {}
172 void Post()
override {
173 for (
int i = 0; i <
vars_.size(); ++i) {
175 solver(),
this, &SumConstraint::LeafChanged,
"LeafChanged", i);
176 vars_[i]->WhenRange(demon);
179 solver(),
this, &SumConstraint::SumChanged,
"SumChanged"));
183 void InitialPropagate()
override {
185 for (
int i = 0; i <
vars_.size(); ++i) {
186 InitLeaf(i,
vars_[i]->Min(),
vars_[i]->Max());
189 for (
int i = MaxDepth() - 1; i >= 0; --i) {
190 for (
int j = 0; j < Width(i); ++j) {
193 const int block_start = ChildStart(j);
194 const int block_end = ChildEnd(i, j);
195 for (
int k = block_start; k <= block_end; ++k) {
196 sum_min =
CapAdd(sum_min, Min(i + 1, k));
197 sum_max =
CapAdd(sum_max, Max(i + 1, k));
199 InitNode(i, j, sum_min, sum_max);
213 for (
int i = 0; i <
vars_.size(); ++i) {
219 for (
int i = 0; i <
vars_.size(); ++i) {
227 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
229 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
235 vars_[position]->SetRange(new_min, new_max);
243 const int64_t sum_min = Min(depth, position);
244 const int64_t sum_max = Max(depth, position);
247 new_max =
std::min(sum_max, new_max);
248 new_min =
std::max(sum_min, new_min);
251 if (new_max < sum_min || new_min > sum_max) {
256 const int block_start = ChildStart(position);
257 const int block_end = ChildEnd(depth, position);
258 for (
int i = block_start; i <= block_end; ++i) {
259 const int64_t target_var_min = Min(depth + 1, i);
260 const int64_t target_var_max = Max(depth + 1, i);
261 const int64_t residual_min =
CapSub(sum_min, target_var_min);
262 const int64_t residual_max =
CapSub(sum_max, target_var_max);
263 PushDown(depth + 1, i,
CapSub(new_min, residual_max),
264 CapSub(new_max, residual_min));
270 void LeafChanged(
int term_index) {
271 IntVar*
const var =
vars_[term_index];
274 EnqueueDelayedDemon(sum_demon_);
277 void PushUp(
int position, int64_t delta_min, int64_t delta_max) {
281 for (
int depth = MaxDepth(); depth >= 0; --depth) {
282 ReduceRange(depth, position, delta_min, delta_max);
283 position = Parent(position);
289 std::string DebugString()
const override {
290 return DebugStringInternal(
"Sum");
293 void Accept(ModelVisitor*
const visitor)
const override {
302class SmallSumConstraint :
public Constraint {
304 SmallSumConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
305 IntVar*
const target_var)
306 : Constraint(solver),
311 sum_demon_(nullptr) {}
313 ~SmallSumConstraint()
override {}
315 void Post()
override {
316 for (
int i = 0; i <
vars_.size(); ++i) {
317 if (!
vars_[i]->Bound()) {
319 solver(),
this, &SmallSumConstraint::VarChanged,
"VarChanged",
321 vars_[i]->WhenRange(demon);
325 solver(),
this, &SmallSumConstraint::SumChanged,
"SumChanged"));
329 void InitialPropagate()
override {
339 computed_min_.SetValue(solver(), sum_min);
340 computed_max_.SetValue(solver(), sum_max);
350 const int64_t sum_min = computed_min_.Value();
351 const int64_t sum_max = computed_max_.Value();
354 for (
int i = 0; i <
vars_.size(); ++i) {
357 }
else if (new_min == sum_max &&
360 for (
int i = 0; i <
vars_.size(); ++i) {
364 if (new_min > sum_min || new_max < sum_max) {
366 new_max =
std::min(sum_max, new_max);
367 new_min =
std::max(sum_min, new_min);
370 if (new_max < sum_min || new_min > sum_max) {
376 const int64_t var_min =
var->Min();
377 const int64_t var_max =
var->Max();
378 const int64_t residual_min =
CapSub(sum_min, var_min);
379 const int64_t residual_max =
CapSub(sum_max, var_max);
380 var->SetRange(
CapSub(new_min, residual_max),
381 CapSub(new_max, residual_min));
387 void VarChanged(IntVar*
var) {
388 const int64_t delta_min =
CapSub(
var->Min(),
var->OldMin());
389 const int64_t delta_max =
CapSub(
var->OldMax(),
var->Max());
390 computed_min_.Add(solver(), delta_min);
391 computed_max_.Add(solver(), -delta_max);
394 target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
396 EnqueueDelayedDemon(sum_demon_);
400 std::string DebugString()
const override {
401 return absl::StrFormat(
"SmallSum(%s) == %s",
406 void Accept(ModelVisitor*
const visitor)
const override {
416 const std::vector<IntVar*>
vars_;
418 NumericalRev<int64_t> computed_min_;
419 NumericalRev<int64_t> computed_max_;
424bool DetectSumOverflow(
const std::vector<IntVar*>& vars) {
427 for (
int i = 0; i < vars.size(); ++i) {
428 sum_min =
CapAdd(sum_min, vars[i]->Min());
429 sum_max =
CapAdd(sum_max, vars[i]->Max());
439class SafeSumConstraint :
public TreeArrayConstraint {
441 SafeSumConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
442 IntVar*
const sum_var)
443 : TreeArrayConstraint(solver, vars, sum_var), sum_demon_(nullptr) {}
445 ~SafeSumConstraint()
override {}
447 void Post()
override {
448 for (
int i = 0; i <
vars_.size(); ++i) {
450 solver(),
this, &SafeSumConstraint::LeafChanged,
"LeafChanged", i);
451 vars_[i]->WhenRange(demon);
454 solver(),
this, &SafeSumConstraint::SumChanged,
"SumChanged"));
458 void SafeComputeNode(
int depth,
int position, int64_t*
const sum_min,
459 int64_t*
const sum_max) {
461 const int block_start = ChildStart(position);
462 const int block_end = ChildEnd(depth, position);
463 for (
int k = block_start; k <= block_end; ++k) {
465 *sum_min =
CapAdd(*sum_min, Min(depth + 1, k));
468 *sum_max =
CapAdd(*sum_max, Max(depth + 1, k));
477 void InitialPropagate()
override {
479 for (
int i = 0; i <
vars_.size(); ++i) {
480 InitLeaf(i,
vars_[i]->Min(),
vars_[i]->Max());
483 for (
int i = MaxDepth() - 1; i >= 0; --i) {
484 for (
int j = 0; j < Width(i); ++j) {
487 SafeComputeNode(i, j, &sum_min, &sum_max);
488 InitNode(i, j, sum_min, sum_max);
499 DCHECK(CheckInternalState());
502 for (
int i = 0; i <
vars_.size(); ++i) {
507 for (
int i = 0; i <
vars_.size(); ++i) {
515 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
517 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
523 vars_[position]->SetRange(new_min, new_max);
531 const int64_t sum_min = Min(depth, position);
532 const int64_t sum_max = Max(depth, position);
535 new_max =
std::min(sum_max, new_max);
536 new_min =
std::max(sum_min, new_min);
539 if (new_max < sum_min || new_min > sum_max) {
544 const int block_start = ChildStart(position);
545 const int block_end = ChildEnd(depth, position);
546 for (
int pos = block_start; pos <= block_end; ++pos) {
547 const int64_t target_var_min = Min(depth + 1, pos);
548 const int64_t residual_min =
550 ?
CapSub(sum_min, target_var_min)
551 :
std::numeric_limits<int64_t>::
min();
552 const int64_t target_var_max = Max(depth + 1, pos);
553 const int64_t residual_max =
555 ?
CapSub(sum_max, target_var_max)
556 :
std::numeric_limits<int64_t>::
max();
557 PushDown(depth + 1, pos,
560 :
CapSub(new_min, residual_max)),
563 :
CapSub(new_max, residual_min)));
569 void LeafChanged(
int term_index) {
570 IntVar*
const var =
vars_[term_index];
573 EnqueueDelayedDemon(sum_demon_);
576 void PushUp(
int position, int64_t delta_min, int64_t delta_max) {
579 if (
CapAdd(delta_min, delta_max) == 0) {
584 bool delta_corrupted =
false;
585 for (
int depth = MaxDepth(); depth >= 0; --depth) {
591 ReduceRange(depth, position, delta_min, delta_max);
592 }
else if (depth == MaxDepth()) {
593 SetRange(depth, position,
vars_[position]->Min(),
594 vars_[position]->Max());
595 delta_corrupted =
true;
599 SafeComputeNode(depth, position, &sum_min, &sum_max);
604 SetRange(depth, position, sum_min, sum_max);
605 delta_corrupted =
true;
607 position = Parent(position);
613 std::string DebugString()
const override {
614 return DebugStringInternal(
"Sum");
617 void Accept(ModelVisitor*
const visitor)
const override {
622 bool CheckInternalState() {
623 for (
int i = 0; i <
vars_.size(); ++i) {
624 CheckLeaf(i,
vars_[i]->Min(),
vars_[i]->Max());
627 for (
int i = MaxDepth() - 1; i >= 0; --i) {
628 for (
int j = 0; j < Width(i); ++j) {
631 SafeComputeNode(i, j, &sum_min, &sum_max);
632 CheckNode(i, j, sum_min, sum_max);
638 void CheckLeaf(
int position, int64_t var_min, int64_t var_max) {
639 CheckNode(MaxDepth(), position, var_min, var_max);
642 void CheckNode(
int depth,
int position, int64_t
node_min, int64_t
node_max) {
653class MinConstraint :
public TreeArrayConstraint {
655 MinConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
656 IntVar*
const min_var)
657 : TreeArrayConstraint(solver, vars, min_var), min_demon_(nullptr) {}
659 ~MinConstraint()
override {}
661 void Post()
override {
662 for (
int i = 0; i <
vars_.size(); ++i) {
664 solver(),
this, &MinConstraint::LeafChanged,
"LeafChanged", i);
665 vars_[i]->WhenRange(demon);
668 solver(),
this, &MinConstraint::MinVarChanged,
"MinVarChanged"));
672 void InitialPropagate()
override {
674 for (
int i = 0; i <
vars_.size(); ++i) {
675 InitLeaf(i,
vars_[i]->Min(),
vars_[i]->Max());
679 for (
int i = MaxDepth() - 1; i >= 0; --i) {
680 for (
int j = 0; j < Width(i); ++j) {
683 const int block_start = ChildStart(j);
684 const int block_end = ChildEnd(i, j);
685 for (
int k = block_start; k <= block_end; ++k) {
686 min_min =
std::min(min_min, Min(i + 1, k));
687 min_max =
std::min(min_max, Max(i + 1, k));
689 InitNode(i, j, min_min, min_max);
699 void MinVarChanged() {
703 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
705 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
711 vars_[position]->SetRange(new_min, new_max);
715 const int64_t
node_min = Min(depth, position);
716 const int64_t
node_max = Max(depth, position);
720 const int block_start = ChildStart(position);
721 const int block_end = ChildEnd(depth, position);
725 for (
int i = block_start; i <= block_end; ++i) {
726 if (Min(depth + 1, i) <= new_max) {
739 for (
int i = block_start; i <= block_end; ++i) {
740 if (i == candidate && active == 1) {
741 PushDown(depth + 1, i, new_min, new_max);
743 PushDown(depth + 1, i, new_min, Max(depth + 1, i));
746 }
else if (active == 1) {
747 PushDown(depth + 1, candidate, Min(depth + 1, candidate), new_max);
752 void LeafChanged(
int term_index) {
753 IntVar*
const var =
vars_[term_index];
754 SetRange(MaxDepth(), term_index,
var->Min(),
var->Max());
755 const int parent_depth = MaxDepth() - 1;
756 const int parent = Parent(term_index);
757 const int64_t old_min =
var->OldMin();
758 const int64_t var_min =
var->Min();
759 const int64_t var_max =
var->Max();
760 if ((old_min == Min(parent_depth, parent) && old_min != var_min) ||
761 var_max < Max(parent_depth, parent)) {
767 void PushUp(
int position) {
768 int depth = MaxDepth();
770 const int parent = Parent(position);
771 const int parent_depth = depth - 1;
774 const int block_start = ChildStart(parent);
775 const int block_end = ChildEnd(parent_depth, parent);
776 for (
int k = block_start; k <= block_end; ++k) {
777 min_min =
std::min(min_min, Min(depth, k));
778 min_max =
std::min(min_max, Max(depth, k));
780 if (min_min > Min(parent_depth, parent) ||
781 min_max < Max(parent_depth, parent)) {
782 SetRange(parent_depth, parent, min_min, min_max);
786 depth = parent_depth;
795 std::string DebugString()
const override {
796 return DebugStringInternal(
"Min");
799 void Accept(ModelVisitor*
const visitor)
const override {
807class SmallMinConstraint :
public Constraint {
809 SmallMinConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
810 IntVar*
const target_var)
811 : Constraint(solver),
817 ~SmallMinConstraint()
override {}
819 void Post()
override {
820 for (
int i = 0; i <
vars_.size(); ++i) {
821 if (!
vars_[i]->Bound()) {
823 solver(),
this, &SmallMinConstraint::VarChanged,
"VarChanged",
825 vars_[i]->WhenRange(demon);
829 solver(),
this, &SmallMinConstraint::MinVarChanged,
"MinVarChanged"));
833 void InitialPropagate()
override {
840 computed_min_.SetValue(solver(), min_min);
841 computed_max_.SetValue(solver(), min_max);
849 std::string DebugString()
const override {
850 return absl::StrFormat(
"SmallMin(%s) == %s",
855 void Accept(ModelVisitor*
const visitor)
const override {
865 void VarChanged(IntVar*
var) {
866 const int64_t old_min =
var->OldMin();
867 const int64_t var_min =
var->Min();
868 const int64_t var_max =
var->Max();
869 if ((old_min == computed_min_.Value() && old_min != var_min) ||
870 var_max < computed_max_.Value()) {
878 if (min_min > computed_min_.Value() || min_max < computed_max_.Value()) {
879 computed_min_.SetValue(solver(), min_min);
880 computed_max_.SetValue(solver(), min_max);
881 target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
887 void MinVarChanged() {
891 if (new_min <= computed_min_.Value() && new_max >= computed_max_.Value()) {
895 IntVar* candidate =
nullptr;
898 if (new_max < computed_max_.Value()) {
901 if (
var->Min() <= new_max) {
912 if (computed_min_.Value() < new_min) {
914 candidate->SetRange(new_min, new_max);
917 var->SetMin(new_min);
920 }
else if (active == 1) {
921 candidate->SetMax(new_max);
925 std::vector<IntVar*>
vars_;
927 Rev<int64_t> computed_min_;
928 Rev<int64_t> computed_max_;
934class MaxConstraint :
public TreeArrayConstraint {
936 MaxConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
937 IntVar*
const max_var)
938 : TreeArrayConstraint(solver, vars, max_var), max_demon_(nullptr) {}
940 ~MaxConstraint()
override {}
942 void Post()
override {
943 for (
int i = 0; i <
vars_.size(); ++i) {
945 solver(),
this, &MaxConstraint::LeafChanged,
"LeafChanged", i);
946 vars_[i]->WhenRange(demon);
949 solver(),
this, &MaxConstraint::MaxVarChanged,
"MaxVarChanged"));
953 void InitialPropagate()
override {
955 for (
int i = 0; i <
vars_.size(); ++i) {
956 InitLeaf(i,
vars_[i]->Min(),
vars_[i]->Max());
960 for (
int i = MaxDepth() - 1; i >= 0; --i) {
961 for (
int j = 0; j < Width(i); ++j) {
964 const int block_start = ChildStart(j);
965 const int block_end = ChildEnd(i, j);
966 for (
int k = block_start; k <= block_end; ++k) {
967 max_min =
std::max(max_min, Min(i + 1, k));
968 max_max =
std::max(max_max, Max(i + 1, k));
970 InitNode(i, j, max_min, max_max);
980 void MaxVarChanged() {
984 void PushDown(
int depth,
int position, int64_t new_min, int64_t new_max) {
986 if (new_min <= Min(depth, position) && new_max >= Max(depth, position)) {
992 vars_[position]->SetRange(new_min, new_max);
996 const int64_t
node_min = Min(depth, position);
997 const int64_t
node_max = Max(depth, position);
1001 const int block_start = ChildStart(position);
1002 const int block_end = ChildEnd(depth, position);
1006 for (
int i = block_start; i <= block_end; ++i) {
1007 if (Max(depth + 1, i) >= new_min) {
1008 if (active++ >= 1) {
1020 for (
int i = block_start; i <= block_end; ++i) {
1021 if (i == candidate && active == 1) {
1022 PushDown(depth + 1, i, new_min, new_max);
1024 PushDown(depth + 1, i, Min(depth + 1, i), new_max);
1027 }
else if (active == 1) {
1028 PushDown(depth + 1, candidate, new_min, Max(depth + 1, candidate));
1032 void LeafChanged(
int term_index) {
1033 IntVar*
const var =
vars_[term_index];
1034 SetRange(MaxDepth(), term_index,
var->Min(),
var->Max());
1035 const int parent_depth = MaxDepth() - 1;
1036 const int parent = Parent(term_index);
1037 const int64_t old_max =
var->OldMax();
1038 const int64_t var_min =
var->Min();
1039 const int64_t var_max =
var->Max();
1040 if ((old_max == Max(parent_depth, parent) && old_max != var_max) ||
1041 var_min > Min(parent_depth, parent)) {
1047 void PushUp(
int position) {
1048 int depth = MaxDepth();
1050 const int parent = Parent(position);
1051 const int parent_depth = depth - 1;
1054 const int block_start = ChildStart(parent);
1055 const int block_end = ChildEnd(parent_depth, parent);
1056 for (
int k = block_start; k <= block_end; ++k) {
1057 max_min =
std::max(max_min, Min(depth, k));
1058 max_max =
std::max(max_max, Max(depth, k));
1060 if (max_min > Min(parent_depth, parent) ||
1061 max_max < Max(parent_depth, parent)) {
1062 SetRange(parent_depth, parent, max_min, max_max);
1066 depth = parent_depth;
1075 std::string DebugString()
const override {
1076 return DebugStringInternal(
"Max");
1079 void Accept(ModelVisitor*
const visitor)
const override {
1087class SmallMaxConstraint :
public Constraint {
1089 SmallMaxConstraint(Solver*
const solver,
const std::vector<IntVar*>& vars,
1090 IntVar*
const target_var)
1091 : Constraint(solver),
1097 ~SmallMaxConstraint()
override {}
1099 void Post()
override {
1100 for (
int i = 0; i <
vars_.size(); ++i) {
1101 if (!
vars_[i]->Bound()) {
1103 solver(),
this, &SmallMaxConstraint::VarChanged,
"VarChanged",
1105 vars_[i]->WhenRange(demon);
1109 solver(),
this, &SmallMaxConstraint::MaxVarChanged,
"MinVarChanged"));
1113 void InitialPropagate()
override {
1120 computed_min_.SetValue(solver(), max_min);
1121 computed_max_.SetValue(solver(), max_max);
1129 std::string DebugString()
const override {
1130 return absl::StrFormat(
"SmallMax(%s) == %s",
1135 void Accept(ModelVisitor*
const visitor)
const override {
1145 void VarChanged(IntVar*
var) {
1146 const int64_t old_max =
var->OldMax();
1147 const int64_t var_min =
var->Min();
1148 const int64_t var_max =
var->Max();
1149 if ((old_max == computed_max_.Value() && old_max != var_max) ||
1150 var_min > computed_min_.Value()) {
1158 if (max_min > computed_min_.Value() || max_max < computed_max_.Value()) {
1159 computed_min_.SetValue(solver(), max_min);
1160 computed_max_.SetValue(solver(), max_max);
1161 target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
1167 void MaxVarChanged() {
1171 if (new_min <= computed_min_.Value() && new_max >= computed_max_.Value()) {
1175 IntVar* candidate =
nullptr;
1178 if (new_min > computed_min_.Value()) {
1181 if (
var->Max() >= new_min) {
1182 if (active++ >= 1) {
1192 if (computed_max_.Value() > new_max) {
1194 candidate->SetRange(new_min, new_max);
1197 var->SetMax(new_max);
1200 }
else if (active == 1) {
1201 candidate->SetMin(new_min);
1205 std::vector<IntVar*>
vars_;
1207 Rev<int64_t> computed_min_;
1208 Rev<int64_t> computed_max_;
1213class ArrayBoolAndEq :
public CastConstraint {
1215 ArrayBoolAndEq(Solver*
const s,
const std::vector<IntVar*>& vars,
1216 IntVar*
const target)
1217 : CastConstraint(s, target),
1219 demons_(vars.size()),
1222 ~ArrayBoolAndEq()
override {}
1224 void Post()
override {
1225 for (
int i = 0; i <
vars_.size(); ++i) {
1226 if (!
vars_[i]->Bound()) {
1229 "PropagateVar",
vars_[i]);
1230 vars_[i]->WhenBound(demons_[i]);
1235 solver(),
this, &ArrayBoolAndEq::PropagateTarget,
"PropagateTarget");
1240 void InitialPropagate()
override {
1243 for (
int i = 0; i <
vars_.size(); ++i) {
1244 vars_[i]->SetMin(1);
1247 int possible_zero = -1;
1250 for (
int i = 0; i <
vars_.size(); ++i) {
1251 if (!
vars_[i]->Bound()) {
1254 }
else if (
vars_[i]->Max() == 0) {
1263 if (unbounded == 0) {
1265 }
else if (
target_var_->Max() == 0 && unbounded == 1) {
1267 vars_[possible_zero]->SetMax(0);
1269 unbounded_.SetValue(solver(), unbounded);
1274 void PropagateVar(IntVar*
var) {
1275 if (
var->Min() == 1) {
1276 unbounded_.Decr(solver());
1277 if (unbounded_.Value() == 0 && !decided_.Switched()) {
1279 decided_.Switch(solver());
1280 }
else if (
target_var_->Max() == 0 && unbounded_.Value() == 1 &&
1281 !decided_.Switched()) {
1290 void PropagateTarget() {
1292 for (
int i = 0; i <
vars_.size(); ++i) {
1293 vars_[i]->SetMin(1);
1296 if (unbounded_.Value() == 1 && !decided_.Switched()) {
1302 std::string DebugString()
const override {
1307 void Accept(ModelVisitor*
const visitor)
const override {
1318 for (
int i = 0; i < demons_.size(); ++i) {
1319 if (demons_[i] !=
nullptr) {
1320 demons_[i]->inhibit(solver());
1325 void ForceToZero() {
1326 for (
int i = 0; i <
vars_.size(); ++i) {
1327 if (
vars_[i]->Min() == 0) {
1328 vars_[i]->SetValue(0);
1329 decided_.Switch(solver());
1336 const std::vector<IntVar*>
vars_;
1337 std::vector<Demon*> demons_;
1338 NumericalRev<int> unbounded_;
1342class ArrayBoolOrEq :
public CastConstraint {
1344 ArrayBoolOrEq(Solver*
const s,
const std::vector<IntVar*>& vars,
1345 IntVar*
const target)
1346 : CastConstraint(s, target),
1348 demons_(vars.size()),
1351 ~ArrayBoolOrEq()
override {}
1353 void Post()
override {
1354 for (
int i = 0; i <
vars_.size(); ++i) {
1355 if (!
vars_[i]->Bound()) {
1358 "PropagateVar",
vars_[i]);
1359 vars_[i]->WhenBound(demons_[i]);
1364 solver(),
this, &ArrayBoolOrEq::PropagateTarget,
"PropagateTarget");
1369 void InitialPropagate()
override {
1372 for (
int i = 0; i <
vars_.size(); ++i) {
1373 vars_[i]->SetMax(0);
1377 int possible_one = -1;
1379 for (
int i = 0; i <
vars_.size(); ++i) {
1380 if (!
vars_[i]->Bound()) {
1383 }
else if (
vars_[i]->Min() == 1) {
1392 if (unbounded == 0) {
1394 }
else if (
target_var_->Min() == 1 && unbounded == 1) {
1396 vars_[possible_one]->SetMin(1);
1398 unbounded_.SetValue(solver(), unbounded);
1403 void PropagateVar(IntVar*
var) {
1404 if (
var->Min() == 0) {
1405 unbounded_.Decr(solver());
1406 if (unbounded_.Value() == 0 && !decided_.Switched()) {
1408 decided_.Switch(solver());
1410 if (
target_var_->Min() == 1 && unbounded_.Value() == 1 &&
1411 !decided_.Switched()) {
1420 void PropagateTarget() {
1422 for (
int i = 0; i <
vars_.size(); ++i) {
1423 vars_[i]->SetMax(0);
1426 if (unbounded_.Value() == 1 && !decided_.Switched()) {
1432 std::string DebugString()
const override {
1437 void Accept(ModelVisitor*
const visitor)
const override {
1448 for (
int i = 0; i < demons_.size(); ++i) {
1449 if (demons_[i] !=
nullptr) {
1450 demons_[i]->inhibit(solver());
1456 for (
int i = 0; i <
vars_.size(); ++i) {
1457 if (
vars_[i]->Max() == 1) {
1458 vars_[i]->SetValue(1);
1459 decided_.Switch(solver());
1466 const std::vector<IntVar*>
vars_;
1467 std::vector<Demon*> demons_;
1468 NumericalRev<int> unbounded_;
1474class BaseSumBooleanConstraint :
public Constraint {
1476 BaseSumBooleanConstraint(Solver*
const s,
const std::vector<IntVar*>& vars)
1477 : Constraint(s),
vars_(vars) {}
1479 ~BaseSumBooleanConstraint()
override {}
1482 std::string DebugStringInternal(
const std::string&
name)
const {
1486 const std::vector<IntVar*>
vars_;
1492class SumBooleanLessOrEqualToOne :
public BaseSumBooleanConstraint {
1494 SumBooleanLessOrEqualToOne(Solver*
const s,
const std::vector<IntVar*>& vars)
1495 : BaseSumBooleanConstraint(s, vars) {}
1497 ~SumBooleanLessOrEqualToOne()
override {}
1499 void Post()
override {
1500 for (
int i = 0; i <
vars_.size(); ++i) {
1501 if (!
vars_[i]->Bound()) {
1503 &SumBooleanLessOrEqualToOne::Update,
1504 "Update",
vars_[i]);
1505 vars_[i]->WhenBound(u);
1510 void InitialPropagate()
override {
1511 for (
int i = 0; i <
vars_.size(); ++i) {
1512 if (
vars_[i]->Min() == 1) {
1513 PushAllToZeroExcept(
vars_[i]);
1519 void Update(IntVar*
var) {
1522 if (
var->Min() == 1) {
1523 PushAllToZeroExcept(
var);
1528 void PushAllToZeroExcept(IntVar*
var) {
1530 for (
int i = 0; i <
vars_.size(); ++i) {
1531 IntVar*
const other =
vars_[i];
1532 if (other !=
var && other->Max() != 0) {
1538 std::string DebugString()
const override {
1539 return DebugStringInternal(
"SumBooleanLessOrEqualToOne");
1542 void Accept(ModelVisitor*
const visitor)
const override {
1555class SumBooleanGreaterOrEqualToOne :
public BaseSumBooleanConstraint {
1557 SumBooleanGreaterOrEqualToOne(Solver*
const s,
1558 const std::vector<IntVar*>& vars);
1559 ~SumBooleanGreaterOrEqualToOne()
override {}
1561 void Post()
override;
1562 void InitialPropagate()
override;
1564 void Update(
int index);
1567 std::string DebugString()
const override;
1569 void Accept(ModelVisitor*
const visitor)
const override {
1581SumBooleanGreaterOrEqualToOne::SumBooleanGreaterOrEqualToOne(
1582 Solver*
const s,
const std::vector<IntVar*>& vars)
1583 : BaseSumBooleanConstraint(s, vars), bits_(vars.size()) {}
1585void SumBooleanGreaterOrEqualToOne::Post() {
1586 for (
int i = 0; i <
vars_.size(); ++i) {
1588 solver(),
this, &SumBooleanGreaterOrEqualToOne::Update,
"Update", i);
1589 vars_[i]->WhenRange(d);
1593void SumBooleanGreaterOrEqualToOne::InitialPropagate() {
1594 for (
int i = 0; i <
vars_.size(); ++i) {
1596 if (
var->Min() == 1LL) {
1600 if (
var->Max() == 1LL) {
1601 bits_.SetToOne(solver(), i);
1604 if (bits_.IsCardinalityZero()) {
1606 }
else if (bits_.IsCardinalityOne()) {
1607 vars_[bits_.GetFirstBit(0)]->SetValue(int64_t{1});
1612void SumBooleanGreaterOrEqualToOne::Update(
int index) {
1617 bits_.SetToZero(solver(),
index);
1618 if (bits_.IsCardinalityZero()) {
1620 }
else if (bits_.IsCardinalityOne()) {
1621 vars_[bits_.GetFirstBit(0)]->SetValue(int64_t{1});
1628std::string SumBooleanGreaterOrEqualToOne::DebugString()
const {
1629 return DebugStringInternal(
"SumBooleanGreaterOrEqualToOne");
1634class SumBooleanEqualToOne :
public BaseSumBooleanConstraint {
1636 SumBooleanEqualToOne(Solver*
const s,
const std::vector<IntVar*>& vars)
1637 : BaseSumBooleanConstraint(s, vars), active_vars_(0) {}
1639 ~SumBooleanEqualToOne()
override {}
1641 void Post()
override {
1642 for (
int i = 0; i <
vars_.size(); ++i) {
1644 solver(),
this, &SumBooleanEqualToOne::Update,
"Update", i);
1645 vars_[i]->WhenBound(u);
1649 void InitialPropagate()
override {
1654 for (
int i = 0; i <
vars_.size(); ++i) {
1655 const IntVar*
const var =
vars_[i];
1656 if (
var->Min() == 1) {
1660 if (
var->Max() == 1) {
1665 if (min1 > 1 || max1 == 0) {
1667 }
else if (min1 == 1) {
1669 PushAllToZeroExcept(index_min);
1670 }
else if (max1 == 1) {
1672 vars_[index_max]->SetValue(1);
1675 active_vars_.SetValue(solver(), max1);
1679 void Update(
int index) {
1684 active_vars_.Decr(solver());
1686 if (active_vars_.Value() == 0) {
1688 }
else if (active_vars_.Value() == 1) {
1690 for (
int i = 0; i <
vars_.size(); ++i) {
1692 if (
var->Max() == 1) {
1694 PushAllToZeroExcept(i);
1704 PushAllToZeroExcept(
index);
1709 void PushAllToZeroExcept(
int index) {
1711 for (
int i = 0; i <
vars_.size(); ++i) {
1713 vars_[i]->SetMax(0);
1718 std::string DebugString()
const override {
1719 return DebugStringInternal(
"SumBooleanEqualToOne");
1722 void Accept(ModelVisitor*
const visitor)
const override {
1723 visitor->BeginVisitConstraint(ModelVisitor::kSumEqual,
this);
1724 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1726 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, 1);
1727 visitor->EndVisitConstraint(ModelVisitor::kSumEqual,
this);
1731 NumericalRev<int> active_vars_;
1736class SumBooleanEqualToVar :
public BaseSumBooleanConstraint {
1738 SumBooleanEqualToVar(Solver*
const s,
const std::vector<IntVar*>& bool_vars,
1739 IntVar*
const sum_var)
1740 : BaseSumBooleanConstraint(s, bool_vars),
1741 num_possible_true_vars_(0),
1742 num_always_true_vars_(0),
1743 sum_var_(sum_var) {}
1745 ~SumBooleanEqualToVar()
override {}
1747 void Post()
override {
1748 for (
int i = 0; i <
vars_.size(); ++i) {
1750 solver(),
this, &SumBooleanEqualToVar::Update,
"Update", i);
1751 vars_[i]->WhenBound(u);
1753 if (!sum_var_->Bound()) {
1755 solver(),
this, &SumBooleanEqualToVar::UpdateVar,
"UpdateVar");
1756 sum_var_->WhenRange(u);
1760 void InitialPropagate()
override {
1761 int num_always_true_vars = 0;
1762 int possible_true = 0;
1763 for (
int i = 0; i <
vars_.size(); ++i) {
1764 const IntVar*
const var =
vars_[i];
1765 if (
var->Min() == 1) {
1766 num_always_true_vars++;
1768 if (
var->Max() == 1) {
1772 sum_var_->SetRange(num_always_true_vars, possible_true);
1773 const int64_t var_min = sum_var_->Min();
1774 const int64_t var_max = sum_var_->Max();
1775 if (num_always_true_vars == var_max && possible_true > var_max) {
1776 PushAllUnboundToZero();
1777 }
else if (possible_true == var_min && num_always_true_vars < var_min) {
1778 PushAllUnboundToOne();
1780 num_possible_true_vars_.SetValue(solver(), possible_true);
1781 num_always_true_vars_.SetValue(solver(), num_always_true_vars);
1787 if (num_possible_true_vars_.Value() == sum_var_->Min()) {
1788 PushAllUnboundToOne();
1789 sum_var_->SetValue(num_possible_true_vars_.Value());
1790 }
else if (num_always_true_vars_.Value() == sum_var_->Max()) {
1791 PushAllUnboundToZero();
1792 sum_var_->SetValue(num_always_true_vars_.Value());
1797 void Update(
int index) {
1802 num_possible_true_vars_.Decr(solver());
1803 sum_var_->SetRange(num_always_true_vars_.Value(),
1804 num_possible_true_vars_.Value());
1805 if (num_possible_true_vars_.Value() == sum_var_->Min()) {
1806 PushAllUnboundToOne();
1810 num_always_true_vars_.Incr(solver());
1811 sum_var_->SetRange(num_always_true_vars_.Value(),
1812 num_possible_true_vars_.Value());
1813 if (num_always_true_vars_.Value() == sum_var_->Max()) {
1814 PushAllUnboundToZero();
1820 void PushAllUnboundToZero() {
1821 int64_t counter = 0;
1823 for (
int i = 0; i <
vars_.size(); ++i) {
1824 if (
vars_[i]->Min() == 0) {
1825 vars_[i]->SetValue(0);
1830 if (counter < sum_var_->Min() || counter > sum_var_->Max()) {
1835 void PushAllUnboundToOne() {
1836 int64_t counter = 0;
1838 for (
int i = 0; i <
vars_.size(); ++i) {
1839 if (
vars_[i]->Max() == 1) {
1840 vars_[i]->SetValue(1);
1844 if (counter < sum_var_->Min() || counter > sum_var_->Max()) {
1849 std::string DebugString()
const override {
1850 return absl::StrFormat(
"%s == %s", DebugStringInternal(
"SumBoolean"),
1851 sum_var_->DebugString());
1854 void Accept(ModelVisitor*
const visitor)
const override {
1855 visitor->BeginVisitConstraint(ModelVisitor::kSumEqual,
this);
1856 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1858 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1860 visitor->EndVisitConstraint(ModelVisitor::kSumEqual,
this);
1864 NumericalRev<int> num_possible_true_vars_;
1865 NumericalRev<int> num_always_true_vars_;
1866 IntVar*
const sum_var_;
1876 Container(IntVar* v, int64_t c) :
var(v),
coef(c) {}
1877 bool operator<(
const Container& c)
const {
return (
coef < c.coef); }
1887int64_t SortBothChangeConstant(std::vector<IntVar*>*
const vars,
1888 std::vector<int64_t>*
const coefs,
1890 CHECK(vars !=
nullptr);
1891 CHECK(coefs !=
nullptr);
1892 if (vars->empty()) {
1896 std::vector<Container> to_sort;
1898 if ((*vars)[
index]->Bound()) {
1900 }
else if ((*coefs)[
index] != 0) {
1901 to_sort.push_back(Container((*vars)[
index], (*coefs)[
index]));
1904 if (keep_inside && cst != 0) {
1905 CHECK_LT(to_sort.size(), vars->size());
1906 Solver*
const solver = (*vars)[0]->solver();
1907 to_sort.push_back(Container(solver->MakeIntConst(1), cst));
1910 std::sort(to_sort.begin(), to_sort.end());
1915 vars->resize(to_sort.size());
1916 coefs->resize(to_sort.size());
1922class BooleanScalProdLessConstant :
public Constraint {
1924 BooleanScalProdLessConstant(Solver*
const s,
const std::vector<IntVar*>& vars,
1925 const std::vector<int64_t>& coefs,
1931 first_unbound_backward_(vars.size() - 1),
1932 sum_of_bound_variables_(0LL),
1933 max_coefficient_(0) {
1934 CHECK(!vars.empty());
1935 for (
int i = 0; i <
vars_.size(); ++i) {
1940 max_coefficient_.SetValue(s, coefs_[
vars_.size() - 1]);
1943 ~BooleanScalProdLessConstant()
override {}
1945 void Post()
override {
1946 for (
int var_index = 0; var_index <
vars_.size(); ++var_index) {
1947 if (
vars_[var_index]->Bound()) {
1951 &BooleanScalProdLessConstant::Update,
1952 "InitialPropagate", var_index);
1953 vars_[var_index]->WhenRange(d);
1957 void PushFromTop() {
1958 const int64_t slack =
CapSub(upper_bound_, sum_of_bound_variables_.Value());
1962 if (slack < max_coefficient_.Value()) {
1963 int64_t last_unbound = first_unbound_backward_.Value();
1964 for (; last_unbound >= 0; --last_unbound) {
1965 if (!
vars_[last_unbound]->Bound()) {
1966 if (coefs_[last_unbound] <= slack) {
1967 max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
1970 vars_[last_unbound]->SetValue(0);
1974 first_unbound_backward_.SetValue(solver(), last_unbound);
1978 void InitialPropagate()
override {
1979 Solver*
const s = solver();
1980 int last_unbound = -1;
1987 last_unbound =
index;
1990 sum_of_bound_variables_.SetValue(s, sum);
1991 first_unbound_backward_.SetValue(s, last_unbound);
1995 void Update(
int var_index) {
1996 if (
vars_[var_index]->Min() == 1) {
1997 sum_of_bound_variables_.SetValue(
1998 solver(),
CapAdd(sum_of_bound_variables_.Value(), coefs_[var_index]));
2003 std::string DebugString()
const override {
2004 return absl::StrFormat(
"BooleanScalProd([%s], [%s]) <= %d)",
2006 absl::StrJoin(coefs_,
", "), upper_bound_);
2009 void Accept(ModelVisitor*
const visitor)
const override {
2010 visitor->BeginVisitConstraint(ModelVisitor::kScalProdLessOrEqual,
this);
2011 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2013 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2015 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, upper_bound_);
2016 visitor->EndVisitConstraint(ModelVisitor::kScalProdLessOrEqual,
this);
2020 std::vector<IntVar*>
vars_;
2021 std::vector<int64_t> coefs_;
2022 int64_t upper_bound_;
2023 Rev<int> first_unbound_backward_;
2024 Rev<int64_t> sum_of_bound_variables_;
2025 Rev<int64_t> max_coefficient_;
2030class PositiveBooleanScalProdEqVar :
public CastConstraint {
2032 PositiveBooleanScalProdEqVar(Solver*
const s,
2033 const std::vector<IntVar*>& vars,
2034 const std::vector<int64_t>& coefs,
2036 : CastConstraint(s,
var),
2039 first_unbound_backward_(vars.size() - 1),
2040 sum_of_bound_variables_(0LL),
2041 sum_of_all_variables_(0LL),
2042 max_coefficient_(0) {
2043 SortBothChangeConstant(&
vars_, &coefs_,
true);
2044 max_coefficient_.SetValue(s, coefs_[
vars_.size() - 1]);
2047 ~PositiveBooleanScalProdEqVar()
override {}
2049 void Post()
override {
2050 for (
int var_index = 0; var_index <
vars_.size(); ++var_index) {
2051 if (
vars_[var_index]->Bound()) {
2055 solver(),
this, &PositiveBooleanScalProdEqVar::Update,
"Update",
2057 vars_[var_index]->WhenRange(d);
2061 solver(),
this, &PositiveBooleanScalProdEqVar::Propagate,
2068 target_var_->SetRange(sum_of_bound_variables_.Value(),
2069 sum_of_all_variables_.Value());
2070 const int64_t slack_up =
2072 const int64_t slack_down =
2074 const int64_t max_coeff = max_coefficient_.Value();
2075 if (slack_down < max_coeff || slack_up < max_coeff) {
2076 int64_t last_unbound = first_unbound_backward_.Value();
2077 for (; last_unbound >= 0; --last_unbound) {
2078 if (!
vars_[last_unbound]->Bound()) {
2079 if (coefs_[last_unbound] > slack_up) {
2080 vars_[last_unbound]->SetValue(0);
2081 }
else if (coefs_[last_unbound] > slack_down) {
2082 vars_[last_unbound]->SetValue(1);
2084 max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
2089 first_unbound_backward_.SetValue(solver(), last_unbound);
2093 void InitialPropagate()
override {
2094 Solver*
const s = solver();
2095 int last_unbound = -1;
2096 int64_t sum_bound = 0;
2097 int64_t sum_all = 0;
2104 last_unbound =
index;
2107 sum_of_bound_variables_.SetValue(s, sum_bound);
2108 sum_of_all_variables_.SetValue(s, sum_all);
2109 first_unbound_backward_.SetValue(s, last_unbound);
2113 void Update(
int var_index) {
2114 if (
vars_[var_index]->Min() == 1) {
2115 sum_of_bound_variables_.SetValue(
2116 solver(),
CapAdd(sum_of_bound_variables_.Value(), coefs_[var_index]));
2118 sum_of_all_variables_.SetValue(
2119 solver(),
CapSub(sum_of_all_variables_.Value(), coefs_[var_index]));
2124 std::string DebugString()
const override {
2125 return absl::StrFormat(
"PositiveBooleanScal([%s], [%s]) == %s",
2127 absl::StrJoin(coefs_,
", "),
2131 void Accept(ModelVisitor*
const visitor)
const override {
2132 visitor->BeginVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2133 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2135 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2137 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
2139 visitor->EndVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2143 std::vector<IntVar*>
vars_;
2144 std::vector<int64_t> coefs_;
2145 Rev<int> first_unbound_backward_;
2146 Rev<int64_t> sum_of_bound_variables_;
2147 Rev<int64_t> sum_of_all_variables_;
2148 Rev<int64_t> max_coefficient_;
2153class PositiveBooleanScalProd :
public BaseIntExpr {
2157 PositiveBooleanScalProd(Solver*
const s,
const std::vector<IntVar*>& vars,
2158 const std::vector<int64_t>& coefs)
2159 : BaseIntExpr(s),
vars_(vars), coefs_(coefs) {
2160 CHECK(!vars.empty());
2161 SortBothChangeConstant(&
vars_, &coefs_,
true);
2162 for (
int i = 0; i <
vars_.size(); ++i) {
2167 ~PositiveBooleanScalProd()
override {}
2169 int64_t Min()
const override {
2171 for (
int i = 0; i <
vars_.size(); ++i) {
2172 if (
vars_[i]->Min()) {
2179 void SetMin(int64_t m)
override {
2183 int64_t Max()
const override {
2185 for (
int i = 0; i <
vars_.size(); ++i) {
2186 if (
vars_[i]->Max()) {
2193 void SetMax(int64_t m)
override {
2197 void SetRange(int64_t l, int64_t u)
override {
2198 int64_t current_min = 0;
2199 int64_t current_max = 0;
2200 int64_t diameter = -1;
2201 for (
int i = 0; i <
vars_.size(); ++i) {
2205 current_min =
CapAdd(current_min, var_min);
2206 current_max =
CapAdd(current_max, var_max);
2207 if (var_min != var_max) {
2208 diameter =
CapSub(var_max, var_min);
2211 if (u >= current_max && l <= current_min) {
2214 if (u < current_min || l > current_max) {
2221 if (
CapSub(u, l) > diameter) {
2225 for (
int i = 0; i <
vars_.size(); ++i) {
2228 const int64_t new_min =
2230 const int64_t new_max =
2232 if (new_max < 0 || new_min >
coefficient || new_min > new_max) {
2235 if (new_min > 0LL) {
2236 var->SetMin(int64_t{1});
2238 var->SetMax(int64_t{0});
2243 std::string DebugString()
const override {
2244 return absl::StrFormat(
"PositiveBooleanScalProd([%s], [%s])",
2246 absl::StrJoin(coefs_,
", "));
2249 void WhenRange(Demon* d)
override {
2250 for (
int i = 0; i <
vars_.size(); ++i) {
2251 vars_[i]->WhenRange(d);
2254 IntVar* CastToVar()
override {
2255 Solver*
const s = solver();
2258 Range(&vmin, &vmax);
2259 IntVar*
const var = solver()->MakeIntVar(vmin, vmax);
2260 if (!
vars_.empty()) {
2261 CastConstraint*
const ct =
2262 s->RevAlloc(
new PositiveBooleanScalProdEqVar(s,
vars_, coefs_,
var));
2263 s->AddCastConstraint(
ct,
var,
this);
2268 void Accept(ModelVisitor*
const visitor)
const override {
2269 visitor->BeginVisitIntegerExpression(ModelVisitor::kScalProd,
this);
2270 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2272 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2274 visitor->EndVisitIntegerExpression(ModelVisitor::kScalProd,
this);
2278 std::vector<IntVar*>
vars_;
2279 std::vector<int64_t> coefs_;
2284class PositiveBooleanScalProdEqCst :
public Constraint {
2286 PositiveBooleanScalProdEqCst(Solver*
const s,
2287 const std::vector<IntVar*>& vars,
2288 const std::vector<int64_t>& coefs,
2293 first_unbound_backward_(vars.size() - 1),
2294 sum_of_bound_variables_(0LL),
2295 sum_of_all_variables_(0LL),
2296 constant_(constant),
2297 max_coefficient_(0) {
2298 CHECK(!vars.empty());
2300 CapSub(constant_, SortBothChangeConstant(&
vars_, &coefs_,
false));
2301 max_coefficient_.SetValue(s, coefs_[
vars_.size() - 1]);
2304 ~PositiveBooleanScalProdEqCst()
override {}
2306 void Post()
override {
2307 for (
int var_index = 0; var_index <
vars_.size(); ++var_index) {
2308 if (!
vars_[var_index]->Bound()) {
2310 solver(),
this, &PositiveBooleanScalProdEqCst::Update,
"Update",
2312 vars_[var_index]->WhenRange(d);
2318 if (sum_of_bound_variables_.Value() > constant_ ||
2319 sum_of_all_variables_.Value() < constant_) {
2322 const int64_t slack_up =
CapSub(constant_, sum_of_bound_variables_.Value());
2323 const int64_t slack_down =
CapSub(sum_of_all_variables_.Value(), constant_);
2324 const int64_t max_coeff = max_coefficient_.Value();
2325 if (slack_down < max_coeff || slack_up < max_coeff) {
2326 int64_t last_unbound = first_unbound_backward_.Value();
2327 for (; last_unbound >= 0; --last_unbound) {
2328 if (!
vars_[last_unbound]->Bound()) {
2329 if (coefs_[last_unbound] > slack_up) {
2330 vars_[last_unbound]->SetValue(0);
2331 }
else if (coefs_[last_unbound] > slack_down) {
2332 vars_[last_unbound]->SetValue(1);
2334 max_coefficient_.SetValue(solver(), coefs_[last_unbound]);
2339 first_unbound_backward_.SetValue(solver(), last_unbound);
2343 void InitialPropagate()
override {
2344 Solver*
const s = solver();
2345 int last_unbound = -1;
2346 int64_t sum_bound = 0LL;
2347 int64_t sum_all = 0LL;
2354 last_unbound =
index;
2357 sum_of_bound_variables_.SetValue(s, sum_bound);
2358 sum_of_all_variables_.SetValue(s, sum_all);
2359 first_unbound_backward_.SetValue(s, last_unbound);
2363 void Update(
int var_index) {
2364 if (
vars_[var_index]->Min() == 1) {
2365 sum_of_bound_variables_.SetValue(
2366 solver(),
CapAdd(sum_of_bound_variables_.Value(), coefs_[var_index]));
2368 sum_of_all_variables_.SetValue(
2369 solver(),
CapSub(sum_of_all_variables_.Value(), coefs_[var_index]));
2374 std::string DebugString()
const override {
2375 return absl::StrFormat(
"PositiveBooleanScalProd([%s], [%s]) == %d",
2377 absl::StrJoin(coefs_,
", "), constant_);
2380 void Accept(ModelVisitor*
const visitor)
const override {
2381 visitor->BeginVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2382 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2384 visitor->VisitIntegerArrayArgument(ModelVisitor::kCoefficientsArgument,
2386 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, constant_);
2387 visitor->EndVisitConstraint(ModelVisitor::kScalProdEqual,
this);
2391 std::vector<IntVar*>
vars_;
2392 std::vector<int64_t> coefs_;
2393 Rev<int> first_unbound_backward_;
2394 Rev<int64_t> sum_of_bound_variables_;
2395 Rev<int64_t> sum_of_all_variables_;
2397 Rev<int64_t> max_coefficient_;
2402#define IS_TYPE(type, tag) type.compare(ModelVisitor::tag) == 0
2404class ExprLinearizer :
public ModelParser {
2406 explicit ExprLinearizer(
2407 absl::flat_hash_map<IntVar*, int64_t>*
const variables_to_coefficients)
2408 : variables_to_coefficients_(variables_to_coefficients), constant_(0) {}
2410 ~ExprLinearizer()
override {}
2413 void BeginVisitModel(
const std::string& solver_name)
override {
2414 LOG(
FATAL) <<
"Should not be here";
2417 void EndVisitModel(
const std::string& solver_name)
override {
2418 LOG(
FATAL) <<
"Should not be here";
2421 void BeginVisitConstraint(
const std::string& type_name,
2422 const Constraint*
const constraint)
override {
2423 LOG(
FATAL) <<
"Should not be here";
2426 void EndVisitConstraint(
const std::string& type_name,
2427 const Constraint*
const constraint)
override {
2428 LOG(
FATAL) <<
"Should not be here";
2431 void BeginVisitExtension(
const std::string& type)
override {}
2433 void EndVisitExtension(
const std::string& type)
override {}
2434 void BeginVisitIntegerExpression(
const std::string& type_name,
2435 const IntExpr*
const expr)
override {
2439 void EndVisitIntegerExpression(
const std::string& type_name,
2440 const IntExpr*
const expr)
override {
2441 if (
IS_TYPE(type_name, kSum)) {
2443 }
else if (
IS_TYPE(type_name, kScalProd)) {
2444 VisitScalProd(expr);
2445 }
else if (
IS_TYPE(type_name, kDifference)) {
2446 VisitDifference(expr);
2447 }
else if (
IS_TYPE(type_name, kOpposite)) {
2448 VisitOpposite(expr);
2449 }
else if (
IS_TYPE(type_name, kProduct)) {
2451 }
else if (
IS_TYPE(type_name, kTrace)) {
2454 VisitIntegerExpression(expr);
2459 void VisitIntegerVariable(
const IntVar*
const variable,
2460 const std::string& operation, int64_t
value,
2461 IntVar*
const delegate)
override {
2462 if (operation == ModelVisitor::kSumOperation) {
2464 VisitSubExpression(delegate);
2465 }
else if (operation == ModelVisitor::kDifferenceOperation) {
2468 VisitSubExpression(delegate);
2470 }
else if (operation == ModelVisitor::kProductOperation) {
2471 PushMultiplier(
value);
2472 VisitSubExpression(delegate);
2474 }
else if (operation == ModelVisitor::kTraceOperation) {
2475 VisitSubExpression(delegate);
2479 void VisitIntegerVariable(
const IntVar*
const variable,
2480 IntExpr*
const delegate)
override {
2481 if (delegate !=
nullptr) {
2482 VisitSubExpression(delegate);
2484 if (variable->Bound()) {
2485 AddConstant(variable->Min());
2487 RegisterExpression(variable, 1);
2493 void VisitIntegerArgument(
const std::string& arg_name,
2494 int64_t
value)
override {
2495 Top()->SetIntegerArgument(arg_name,
value);
2498 void VisitIntegerArrayArgument(
const std::string& arg_name,
2499 const std::vector<int64_t>& values)
override {
2500 Top()->SetIntegerArrayArgument(arg_name, values);
2503 void VisitIntegerMatrixArgument(
const std::string& arg_name,
2504 const IntTupleSet& values)
override {
2505 Top()->SetIntegerMatrixArgument(arg_name, values);
2509 void VisitIntegerExpressionArgument(
const std::string& arg_name,
2510 IntExpr*
const argument)
override {
2511 Top()->SetIntegerExpressionArgument(arg_name, argument);
2514 void VisitIntegerVariableArrayArgument(
2515 const std::string& arg_name,
2516 const std::vector<IntVar*>& arguments)
override {
2517 Top()->SetIntegerVariableArrayArgument(arg_name, arguments);
2521 void VisitIntervalArgument(
const std::string& arg_name,
2522 IntervalVar*
const argument)
override {}
2524 void VisitIntervalArrayArgument(
2525 const std::string& arg_name,
2526 const std::vector<IntervalVar*>& argument)
override {}
2528 void Visit(
const IntExpr*
const expr, int64_t multiplier) {
2529 if (expr->Min() == expr->Max()) {
2530 constant_ =
CapAdd(constant_,
CapProd(expr->Min(), multiplier));
2532 PushMultiplier(multiplier);
2538 int64_t Constant()
const {
return constant_; }
2540 std::string DebugString()
const override {
return "ExprLinearizer"; }
2543 void BeginVisit(
bool active) { PushArgumentHolder(); }
2545 void EndVisit() { PopArgumentHolder(); }
2547 void VisitSubExpression(
const IntExpr*
const cp_expr) {
2548 cp_expr->Accept(
this);
2551 void VisitSum(
const IntExpr*
const cp_expr) {
2552 if (Top()->HasIntegerVariableArrayArgument(ModelVisitor::kVarsArgument)) {
2553 const std::vector<IntVar*>& cp_vars =
2554 Top()->FindIntegerVariableArrayArgumentOrDie(
2555 ModelVisitor::kVarsArgument);
2556 for (
int i = 0; i < cp_vars.size(); ++i) {
2557 VisitSubExpression(cp_vars[i]);
2559 }
else if (Top()->HasIntegerExpressionArgument(
2560 ModelVisitor::kLeftArgument)) {
2561 const IntExpr*
const left = Top()->FindIntegerExpressionArgumentOrDie(
2562 ModelVisitor::kLeftArgument);
2563 const IntExpr*
const right = Top()->FindIntegerExpressionArgumentOrDie(
2564 ModelVisitor::kRightArgument);
2565 VisitSubExpression(left);
2566 VisitSubExpression(right);
2568 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2569 ModelVisitor::kExpressionArgument);
2570 const int64_t
value =
2571 Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2572 VisitSubExpression(expr);
2577 void VisitScalProd(
const IntExpr*
const cp_expr) {
2578 const std::vector<IntVar*>& cp_vars =
2579 Top()->FindIntegerVariableArrayArgumentOrDie(
2580 ModelVisitor::kVarsArgument);
2581 const std::vector<int64_t>& cp_coefficients =
2582 Top()->FindIntegerArrayArgumentOrDie(
2583 ModelVisitor::kCoefficientsArgument);
2584 CHECK_EQ(cp_vars.size(), cp_coefficients.size());
2585 for (
int i = 0; i < cp_vars.size(); ++i) {
2588 VisitSubExpression(cp_vars[i]);
2593 void VisitDifference(
const IntExpr*
const cp_expr) {
2594 if (Top()->HasIntegerExpressionArgument(ModelVisitor::kLeftArgument)) {
2595 const IntExpr*
const left = Top()->FindIntegerExpressionArgumentOrDie(
2596 ModelVisitor::kLeftArgument);
2597 const IntExpr*
const right = Top()->FindIntegerExpressionArgumentOrDie(
2598 ModelVisitor::kRightArgument);
2599 VisitSubExpression(left);
2601 VisitSubExpression(right);
2604 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2605 ModelVisitor::kExpressionArgument);
2606 const int64_t
value =
2607 Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2610 VisitSubExpression(expr);
2615 void VisitOpposite(
const IntExpr*
const cp_expr) {
2616 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2617 ModelVisitor::kExpressionArgument);
2619 VisitSubExpression(expr);
2623 void VisitProduct(
const IntExpr*
const cp_expr) {
2624 if (Top()->HasIntegerExpressionArgument(
2625 ModelVisitor::kExpressionArgument)) {
2626 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2627 ModelVisitor::kExpressionArgument);
2628 const int64_t
value =
2629 Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument);
2630 PushMultiplier(
value);
2631 VisitSubExpression(expr);
2634 RegisterExpression(cp_expr, 1);
2638 void VisitTrace(
const IntExpr*
const cp_expr) {
2639 const IntExpr*
const expr = Top()->FindIntegerExpressionArgumentOrDie(
2640 ModelVisitor::kExpressionArgument);
2641 VisitSubExpression(expr);
2644 void VisitIntegerExpression(
const IntExpr*
const cp_expr) {
2645 RegisterExpression(cp_expr, 1);
2648 void RegisterExpression(
const IntExpr*
const expr, int64_t
coef) {
2650 (*variables_to_coefficients_)[
const_cast<IntExpr*
>(expr)->Var()];
2654 void AddConstant(int64_t constant) {
2655 constant_ =
CapAdd(constant_,
CapProd(constant, multipliers_.back()));
2658 void PushMultiplier(int64_t multiplier) {
2659 if (multipliers_.empty()) {
2660 multipliers_.push_back(multiplier);
2662 multipliers_.push_back(
CapProd(multiplier, multipliers_.back()));
2666 void PopMultiplier() { multipliers_.pop_back(); }
2670 absl::flat_hash_map<IntVar*, int64_t>*
const variables_to_coefficients_;
2671 std::vector<int64_t> multipliers_;
2678void DeepLinearize(Solver*
const solver,
const std::vector<IntVar*>& pre_vars,
2679 const std::vector<int64_t>& pre_coefs,
2680 std::vector<IntVar*>* vars, std::vector<int64_t>* coefs,
2681 int64_t* constant) {
2682 CHECK(solver !=
nullptr);
2683 CHECK(vars !=
nullptr);
2684 CHECK(coefs !=
nullptr);
2685 CHECK(constant !=
nullptr);
2687 vars->reserve(pre_vars.size());
2688 coefs->reserve(pre_coefs.size());
2690 bool need_linearization =
false;
2691 for (
int i = 0; i < pre_vars.size(); ++i) {
2692 IntVar*
const variable = pre_vars[i];
2694 if (variable->Bound()) {
2696 }
else if (solver->CastExpression(variable) ==
nullptr) {
2697 vars->push_back(variable);
2700 need_linearization =
true;
2706 if (need_linearization) {
2708 absl::flat_hash_map<IntVar*, int64_t> variables_to_coefficients;
2709 ExprLinearizer linearizer(&variables_to_coefficients);
2710 for (
int i = 0; i < pre_vars.size(); ++i) {
2711 linearizer.Visit(pre_vars[i], pre_coefs[i]);
2713 *constant = linearizer.Constant();
2714 for (
const auto& variable_to_coefficient : variables_to_coefficients) {
2715 if (variable_to_coefficient.second != 0) {
2716 vars->push_back(variable_to_coefficient.first);
2717 coefs->push_back(variable_to_coefficient.second);
2723Constraint* MakeScalProdEqualityFct(Solver*
const solver,
2724 const std::vector<IntVar*>& pre_vars,
2725 const std::vector<int64_t>& pre_coefs,
2727 int64_t constant = 0;
2728 std::vector<IntVar*> vars;
2729 std::vector<int64_t> coefs;
2730 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2731 cst =
CapSub(cst, constant);
2733 const int size = vars.size();
2735 return cst == 0 ? solver->MakeTrueConstraint()
2736 : solver->MakeFalseConstraint();
2740 for (
int i = 0; i < size; ++i) {
2743 return sum == cst ? solver->MakeTrueConstraint()
2744 : solver->MakeFalseConstraint();
2747 return solver->MakeSumEquality(vars, cst);
2751 return solver->RevAlloc(
2752 new PositiveBooleanScalProdEqCst(solver, vars, coefs, cst));
2755 std::vector<int64_t> opp_coefs(coefs.size());
2756 for (
int i = 0; i < coefs.size(); ++i) {
2757 opp_coefs[i] = -coefs[i];
2759 return solver->RevAlloc(
2760 new PositiveBooleanScalProdEqCst(solver, vars, opp_coefs, -cst));
2768 for (
int i = 0; i < size; ++i) {
2769 if (coefs[i] == 0 || vars[i]->Bound()) {
2771 }
else if (coefs[i] > 0) {
2777 if (positives > 0 && negatives > 0) {
2778 std::vector<IntVar*> pos_terms;
2779 std::vector<IntVar*> neg_terms;
2781 for (
int i = 0; i < size; ++i) {
2782 if (coefs[i] == 0 || vars[i]->Bound()) {
2784 }
else if (coefs[i] > 0) {
2785 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2787 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2790 if (negatives == 1) {
2792 pos_terms.push_back(solver->MakeIntConst(-rhs));
2794 return solver->MakeSumEquality(pos_terms, neg_terms[0]);
2795 }
else if (positives == 1) {
2797 neg_terms.push_back(solver->MakeIntConst(rhs));
2799 return solver->MakeSumEquality(neg_terms, pos_terms[0]);
2802 neg_terms.push_back(solver->MakeIntConst(rhs));
2804 return solver->MakeEquality(solver->MakeSum(pos_terms),
2805 solver->MakeSum(neg_terms));
2807 }
else if (positives == 1) {
2808 IntExpr* pos_term =
nullptr;
2810 for (
int i = 0; i < size; ++i) {
2811 if (coefs[i] == 0 || vars[i]->Bound()) {
2813 }
else if (coefs[i] > 0) {
2814 pos_term = solver->MakeProd(vars[i], coefs[i]);
2816 LOG(
FATAL) <<
"Should not be here";
2819 return solver->MakeEquality(pos_term, rhs);
2820 }
else if (negatives == 1) {
2821 IntExpr* neg_term =
nullptr;
2823 for (
int i = 0; i < size; ++i) {
2824 if (coefs[i] == 0 || vars[i]->Bound()) {
2826 }
else if (coefs[i] > 0) {
2827 LOG(
FATAL) <<
"Should not be here";
2829 neg_term = solver->MakeProd(vars[i], -coefs[i]);
2832 return solver->MakeEquality(neg_term, -rhs);
2833 }
else if (positives > 1) {
2834 std::vector<IntVar*> pos_terms;
2836 for (
int i = 0; i < size; ++i) {
2837 if (coefs[i] == 0 || vars[i]->Bound()) {
2839 }
else if (coefs[i] > 0) {
2840 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2842 LOG(
FATAL) <<
"Should not be here";
2845 return solver->MakeSumEquality(pos_terms, rhs);
2846 }
else if (negatives > 1) {
2847 std::vector<IntVar*> neg_terms;
2849 for (
int i = 0; i < size; ++i) {
2850 if (coefs[i] == 0 || vars[i]->Bound()) {
2852 }
else if (coefs[i] > 0) {
2853 LOG(
FATAL) <<
"Should not be here";
2855 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2858 return solver->MakeSumEquality(neg_terms, -rhs);
2860 std::vector<IntVar*> terms;
2861 for (
int i = 0; i < size; ++i) {
2862 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2864 return solver->MakeSumEquality(terms, solver->MakeIntConst(cst));
2867Constraint* MakeScalProdEqualityVarFct(Solver*
const solver,
2868 const std::vector<IntVar*>& pre_vars,
2869 const std::vector<int64_t>& pre_coefs,
2870 IntVar*
const target) {
2871 int64_t constant = 0;
2872 std::vector<IntVar*> vars;
2873 std::vector<int64_t> coefs;
2874 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2876 const int size = vars.size();
2877 if (size == 0 || AreAllNull<int64_t>(coefs)) {
2878 return solver->MakeEquality(target, constant);
2881 return solver->MakeSumEquality(vars,
2882 solver->MakeSum(target, -constant)->Var());
2886 return solver->RevAlloc(
new PositiveBooleanScalProdEqVar(
2887 solver, vars, coefs, solver->MakeSum(target, -constant)->Var()));
2889 std::vector<IntVar*> terms;
2890 for (
int i = 0; i < size; ++i) {
2891 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2893 return solver->MakeSumEquality(terms,
2894 solver->MakeSum(target, -constant)->Var());
2897Constraint* MakeScalProdGreaterOrEqualFct(Solver* solver,
2898 const std::vector<IntVar*>& pre_vars,
2899 const std::vector<int64_t>& pre_coefs,
2901 int64_t constant = 0;
2902 std::vector<IntVar*> vars;
2903 std::vector<int64_t> coefs;
2904 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2905 cst =
CapSub(cst, constant);
2907 const int size = vars.size();
2908 if (size == 0 || AreAllNull<int64_t>(coefs)) {
2909 return cst <= 0 ? solver->MakeTrueConstraint()
2910 : solver->MakeFalseConstraint();
2913 return solver->MakeSumGreaterOrEqual(vars, cst);
2917 std::vector<IntVar*> terms;
2918 for (
int i = 0; i < size; ++i) {
2920 terms.push_back(vars[i]);
2923 return solver->MakeSumGreaterOrEqual(terms, 1);
2925 std::vector<IntVar*> terms;
2926 for (
int i = 0; i < size; ++i) {
2927 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2929 return solver->MakeSumGreaterOrEqual(terms, cst);
2932Constraint* MakeScalProdLessOrEqualFct(Solver* solver,
2933 const std::vector<IntVar*>& pre_vars,
2934 const std::vector<int64_t>& pre_coefs,
2936 int64_t constant = 0;
2937 std::vector<IntVar*> vars;
2938 std::vector<int64_t> coefs;
2939 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
2942 const int size = vars.size();
2943 if (size == 0 || AreAllNull<int64_t>(coefs)) {
2944 return upper_bound >= 0 ? solver->MakeTrueConstraint()
2945 : solver->MakeFalseConstraint();
2950 for (
int i = 0; i < size; ++i) {
2953 return cst <=
upper_bound ? solver->MakeTrueConstraint()
2954 : solver->MakeFalseConstraint();
2957 return solver->MakeSumLessOrEqual(vars,
upper_bound);
2960 return solver->RevAlloc(
2961 new BooleanScalProdLessConstant(solver, vars, coefs,
upper_bound));
2967 for (
int i = 0; i < size; ++i) {
2968 if (coefs[i] == 0 || vars[i]->Bound()) {
2970 }
else if (coefs[i] > 0) {
2976 if (positives > 0 && negatives > 0) {
2977 std::vector<IntVar*> pos_terms;
2978 std::vector<IntVar*> neg_terms;
2980 for (
int i = 0; i < size; ++i) {
2981 if (coefs[i] == 0 || vars[i]->Bound()) {
2983 }
else if (coefs[i] > 0) {
2984 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
2986 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
2989 if (negatives == 1) {
2990 IntExpr*
const neg_term = solver->MakeSum(neg_terms[0], rhs);
2991 return solver->MakeLessOrEqual(solver->MakeSum(pos_terms), neg_term);
2992 }
else if (positives == 1) {
2993 IntExpr*
const pos_term = solver->MakeSum(pos_terms[0], -rhs);
2994 return solver->MakeGreaterOrEqual(solver->MakeSum(neg_terms), pos_term);
2997 neg_terms.push_back(solver->MakeIntConst(rhs));
2999 return solver->MakeLessOrEqual(solver->MakeSum(pos_terms),
3000 solver->MakeSum(neg_terms));
3002 }
else if (positives == 1) {
3003 IntExpr* pos_term =
nullptr;
3005 for (
int i = 0; i < size; ++i) {
3006 if (coefs[i] == 0 || vars[i]->Bound()) {
3008 }
else if (coefs[i] > 0) {
3009 pos_term = solver->MakeProd(vars[i], coefs[i]);
3011 LOG(
FATAL) <<
"Should not be here";
3014 return solver->MakeLessOrEqual(pos_term, rhs);
3015 }
else if (negatives == 1) {
3016 IntExpr* neg_term =
nullptr;
3018 for (
int i = 0; i < size; ++i) {
3019 if (coefs[i] == 0 || vars[i]->Bound()) {
3021 }
else if (coefs[i] > 0) {
3022 LOG(
FATAL) <<
"Should not be here";
3024 neg_term = solver->MakeProd(vars[i], -coefs[i]);
3027 return solver->MakeGreaterOrEqual(neg_term, -rhs);
3028 }
else if (positives > 1) {
3029 std::vector<IntVar*> pos_terms;
3031 for (
int i = 0; i < size; ++i) {
3032 if (coefs[i] == 0 || vars[i]->Bound()) {
3034 }
else if (coefs[i] > 0) {
3035 pos_terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3037 LOG(
FATAL) <<
"Should not be here";
3040 return solver->MakeSumLessOrEqual(pos_terms, rhs);
3041 }
else if (negatives > 1) {
3042 std::vector<IntVar*> neg_terms;
3044 for (
int i = 0; i < size; ++i) {
3045 if (coefs[i] == 0 || vars[i]->Bound()) {
3047 }
else if (coefs[i] > 0) {
3048 LOG(
FATAL) <<
"Should not be here";
3050 neg_terms.push_back(solver->MakeProd(vars[i], -coefs[i])->Var());
3053 return solver->MakeSumGreaterOrEqual(neg_terms, -rhs);
3055 std::vector<IntVar*> terms;
3056 for (
int i = 0; i < size; ++i) {
3057 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3059 return solver->MakeLessOrEqual(solver->MakeSum(terms),
upper_bound);
3062IntExpr* MakeSumArrayAux(Solver*
const solver,
const std::vector<IntVar*>& vars,
3064 const int size = vars.size();
3066 int64_t new_min = 0;
3067 int64_t new_max = 0;
3068 for (
int i = 0; i < size; ++i) {
3070 new_min =
CapAdd(vars[i]->Min(), new_min);
3073 new_max =
CapAdd(vars[i]->Max(), new_max);
3076 IntExpr*
const cache =
3077 solver->Cache()->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_SUM);
3078 if (cache !=
nullptr) {
3079 return solver->MakeSum(cache, constant);
3081 const std::string
name =
3082 absl::StrFormat(
"Sum([%s])",
JoinNamePtr(vars,
", "));
3083 IntVar*
const sum_var = solver->MakeIntVar(new_min, new_max,
name);
3085 solver->AddConstraint(
3086 solver->RevAlloc(
new SumBooleanEqualToVar(solver, vars, sum_var)));
3087 }
else if (size <= solver->
parameters().array_split_size()) {
3088 solver->AddConstraint(
3089 solver->RevAlloc(
new SmallSumConstraint(solver, vars, sum_var)));
3091 solver->AddConstraint(
3092 solver->RevAlloc(
new SumConstraint(solver, vars, sum_var)));
3094 solver->Cache()->InsertVarArrayExpression(sum_var, vars,
3095 ModelCache::VAR_ARRAY_SUM);
3096 return solver->MakeSum(sum_var, constant);
3100IntExpr* MakeSumAux(Solver*
const solver,
const std::vector<IntVar*>& vars,
3102 const int size = vars.size();
3104 return solver->MakeIntConst(constant);
3105 }
else if (size == 1) {
3106 return solver->MakeSum(vars[0], constant);
3107 }
else if (size == 2) {
3108 return solver->MakeSum(solver->MakeSum(vars[0], vars[1]), constant);
3110 return MakeSumArrayAux(solver, vars, constant);
3114IntExpr* MakeScalProdAux(Solver* solver,
const std::vector<IntVar*>& vars,
3115 const std::vector<int64_t>& coefs, int64_t constant) {
3117 return MakeSumAux(solver, vars, constant);
3120 const int size = vars.size();
3122 return solver->MakeIntConst(constant);
3123 }
else if (size == 1) {
3124 return solver->MakeSum(solver->MakeProd(vars[0], coefs[0]), constant);
3125 }
else if (size == 2) {
3126 if (coefs[0] > 0 && coefs[1] < 0) {
3127 return solver->MakeSum(
3128 solver->MakeDifference(solver->MakeProd(vars[0], coefs[0]),
3129 solver->MakeProd(vars[1], -coefs[1])),
3131 }
else if (coefs[0] < 0 && coefs[1] > 0) {
3132 return solver->MakeSum(
3133 solver->MakeDifference(solver->MakeProd(vars[1], coefs[1]),
3134 solver->MakeProd(vars[0], -coefs[0])),
3137 return solver->MakeSum(
3138 solver->MakeSum(solver->MakeProd(vars[0], coefs[0]),
3139 solver->MakeProd(vars[1], coefs[1])),
3145 if (vars.size() > 8) {
3146 return solver->MakeSum(
3148 ->RegisterIntExpr(solver->RevAlloc(
3149 new PositiveBooleanScalProd(solver, vars, coefs)))
3153 return solver->MakeSum(
3154 solver->RegisterIntExpr(solver->RevAlloc(
3155 new PositiveBooleanScalProd(solver, vars, coefs))),
3166 std::vector<int64_t> positive_coefs;
3167 std::vector<int64_t> negative_coefs;
3168 std::vector<IntVar*> positive_coef_vars;
3169 std::vector<IntVar*> negative_coef_vars;
3170 for (
int i = 0; i < size; ++i) {
3171 const int coef = coefs[i];
3173 positive_coefs.push_back(
coef);
3174 positive_coef_vars.push_back(vars[i]);
3175 }
else if (
coef < 0) {
3176 negative_coefs.push_back(-
coef);
3177 negative_coef_vars.push_back(vars[i]);
3180 CHECK_GT(negative_coef_vars.size(), 0);
3181 IntExpr*
const negatives =
3182 MakeScalProdAux(solver, negative_coef_vars, negative_coefs, 0);
3183 if (!positive_coef_vars.empty()) {
3184 IntExpr*
const positives = MakeScalProdAux(solver, positive_coef_vars,
3185 positive_coefs, constant);
3186 return solver->MakeDifference(positives, negatives);
3188 return solver->MakeDifference(constant, negatives);
3193 std::vector<IntVar*> terms;
3194 for (
int i = 0; i < size; ++i) {
3195 terms.push_back(solver->MakeProd(vars[i], coefs[i])->Var());
3197 return MakeSumArrayAux(solver, terms, constant);
3200IntExpr* MakeScalProdFct(Solver* solver,
const std::vector<IntVar*>& pre_vars,
3201 const std::vector<int64_t>& pre_coefs) {
3202 int64_t constant = 0;
3203 std::vector<IntVar*> vars;
3204 std::vector<int64_t> coefs;
3205 DeepLinearize(solver, pre_vars, pre_coefs, &vars, &coefs, &constant);
3208 return solver->MakeIntConst(constant);
3211 int64_t gcd = std::abs(coefs[0]);
3212 for (
int i = 1; i < coefs.size(); ++i) {
3213 gcd = MathUtil::GCD64(gcd, std::abs(coefs[i]));
3218 if (constant != 0 && gcd != 1) {
3219 gcd = MathUtil::GCD64(gcd, std::abs(constant));
3222 for (
int i = 0; i < coefs.size(); ++i) {
3225 return solver->MakeProd(
3226 MakeScalProdAux(solver, vars, coefs, constant / gcd), gcd);
3228 return MakeScalProdAux(solver, vars, coefs, constant);
3231IntExpr* MakeSumFct(Solver* solver,
const std::vector<IntVar*>& pre_vars) {
3232 absl::flat_hash_map<IntVar*, int64_t> variables_to_coefficients;
3233 ExprLinearizer linearizer(&variables_to_coefficients);
3234 for (
int i = 0; i < pre_vars.size(); ++i) {
3235 linearizer.Visit(pre_vars[i], 1);
3237 const int64_t constant = linearizer.Constant();
3238 std::vector<IntVar*> vars;
3239 std::vector<int64_t> coefs;
3240 for (
const auto& variable_to_coefficient : variables_to_coefficients) {
3241 if (variable_to_coefficient.second != 0) {
3242 vars.push_back(variable_to_coefficient.first);
3243 coefs.push_back(variable_to_coefficient.second);
3246 return MakeScalProdAux(solver, vars, coefs, constant);
3252IntExpr* Solver::MakeSum(
const std::vector<IntVar*>& vars) {
3253 const int size = vars.size();
3255 return MakeIntConst(int64_t{0});
3256 }
else if (size == 1) {
3258 }
else if (size == 2) {
3259 return MakeSum(vars[0], vars[1]);
3262 model_cache_->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_SUM);
3263 if (cache !=
nullptr) {
3266 int64_t new_min = 0;
3267 int64_t new_max = 0;
3268 for (
int i = 0; i < size; ++i) {
3270 new_min =
CapAdd(vars[i]->Min(), new_min);
3273 new_max =
CapAdd(vars[i]->Max(), new_max);
3279 const std::string
name =
3280 absl::StrFormat(
"BooleanSum([%s])",
JoinNamePtr(vars,
", "));
3281 sum_expr = MakeIntVar(new_min, new_max,
name);
3283 RevAlloc(
new SumBooleanEqualToVar(
this, vars, sum_expr->
Var())));
3286 sum_expr = MakeSumFct(
this, vars);
3288 const std::string
name =
3289 absl::StrFormat(
"Sum([%s])",
JoinNamePtr(vars,
", "));
3290 sum_expr = MakeIntVar(new_min, new_max,
name);
3292 RevAlloc(
new SafeSumConstraint(
this, vars, sum_expr->
Var())));
3294 model_cache_->InsertVarArrayExpression(sum_expr, vars,
3295 ModelCache::VAR_ARRAY_SUM);
3301IntExpr* Solver::MakeMin(
const std::vector<IntVar*>& vars) {
3302 const int size = vars.size();
3304 LOG(
WARNING) <<
"operations_research::Solver::MakeMin() was called with an "
3305 "empty list of variables. Was this intentional?";
3307 }
else if (size == 1) {
3309 }
else if (size == 2) {
3310 return MakeMin(vars[0], vars[1]);
3313 model_cache_->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_MIN);
3314 if (cache !=
nullptr) {
3318 IntVar*
const new_var = MakeBoolVar();
3319 AddConstraint(RevAlloc(
new ArrayBoolAndEq(
this, vars, new_var)));
3320 model_cache_->InsertVarArrayExpression(new_var, vars,
3321 ModelCache::VAR_ARRAY_MIN);
3326 for (
int i = 0; i < size; ++i) {
3327 new_min =
std::min(new_min, vars[i]->Min());
3328 new_max =
std::min(new_max, vars[i]->Max());
3330 IntVar*
const new_var = MakeIntVar(new_min, new_max);
3331 if (size <= parameters_.array_split_size()) {
3332 AddConstraint(RevAlloc(
new SmallMinConstraint(
this, vars, new_var)));
3334 AddConstraint(RevAlloc(
new MinConstraint(
this, vars, new_var)));
3336 model_cache_->InsertVarArrayExpression(new_var, vars,
3337 ModelCache::VAR_ARRAY_MIN);
3344IntExpr* Solver::MakeMax(
const std::vector<IntVar*>& vars) {
3345 const int size = vars.size();
3347 LOG(
WARNING) <<
"operations_research::Solver::MakeMax() was called with an "
3348 "empty list of variables. Was this intentional?";
3350 }
else if (size == 1) {
3352 }
else if (size == 2) {
3353 return MakeMax(vars[0], vars[1]);
3356 model_cache_->FindVarArrayExpression(vars, ModelCache::VAR_ARRAY_MAX);
3357 if (cache !=
nullptr) {
3361 IntVar*
const new_var = MakeBoolVar();
3362 AddConstraint(RevAlloc(
new ArrayBoolOrEq(
this, vars, new_var)));
3363 model_cache_->InsertVarArrayExpression(new_var, vars,
3364 ModelCache::VAR_ARRAY_MIN);
3369 for (
int i = 0; i < size; ++i) {
3370 new_min =
std::max(new_min, vars[i]->Min());
3371 new_max =
std::max(new_max, vars[i]->Max());
3373 IntVar*
const new_var = MakeIntVar(new_min, new_max);
3374 if (size <= parameters_.array_split_size()) {
3375 AddConstraint(RevAlloc(
new SmallMaxConstraint(
this, vars, new_var)));
3377 AddConstraint(RevAlloc(
new MaxConstraint(
this, vars, new_var)));
3379 model_cache_->InsertVarArrayExpression(new_var, vars,
3380 ModelCache::VAR_ARRAY_MAX);
3387Constraint* Solver::MakeMinEquality(
const std::vector<IntVar*>& vars,
3389 const int size = vars.size();
3392 return RevAlloc(
new ArrayBoolAndEq(
this, vars, min_var));
3393 }
else if (size <= parameters_.array_split_size()) {
3394 return RevAlloc(
new SmallMinConstraint(
this, vars, min_var));
3396 return RevAlloc(
new MinConstraint(
this, vars, min_var));
3398 }
else if (size == 2) {
3399 return MakeEquality(MakeMin(vars[0], vars[1]), min_var);
3400 }
else if (size == 1) {
3401 return MakeEquality(vars[0], min_var);
3403 LOG(
WARNING) <<
"operations_research::Solver::MakeMinEquality() was called "
3404 "with an empty list of variables. Was this intentional?";
3409Constraint* Solver::MakeMaxEquality(
const std::vector<IntVar*>& vars,
3411 const int size = vars.size();
3414 return RevAlloc(
new ArrayBoolOrEq(
this, vars, max_var));
3415 }
else if (size <= parameters_.array_split_size()) {
3416 return RevAlloc(
new SmallMaxConstraint(
this, vars, max_var));
3418 return RevAlloc(
new MaxConstraint(
this, vars, max_var));
3420 }
else if (size == 2) {
3421 return MakeEquality(MakeMax(vars[0], vars[1]), max_var);
3422 }
else if (size == 1) {
3423 return MakeEquality(vars[0], max_var);
3425 LOG(
WARNING) <<
"operations_research::Solver::MakeMaxEquality() was called "
3426 "with an empty list of variables. Was this intentional?";
3431Constraint* Solver::MakeSumLessOrEqual(
const std::vector<IntVar*>& vars,
3433 const int size = vars.size();
3435 return RevAlloc(
new SumBooleanLessOrEqualToOne(
this, vars));
3437 return MakeLessOrEqual(MakeSum(vars), cst);
3441Constraint* Solver::MakeSumGreaterOrEqual(
const std::vector<IntVar*>& vars,
3443 const int size = vars.size();
3445 return RevAlloc(
new SumBooleanGreaterOrEqualToOne(
this, vars));
3447 return MakeGreaterOrEqual(MakeSum(vars), cst);
3451Constraint* Solver::MakeSumEquality(
const std::vector<IntVar*>& vars,
3453 const int size = vars.size();
3455 return cst == 0 ? MakeTrueConstraint() : MakeFalseConstraint();
3459 return RevAlloc(
new SumBooleanEqualToOne(
this, vars));
3460 }
else if (cst < 0 || cst > size) {
3461 return MakeFalseConstraint();
3463 return RevAlloc(
new SumBooleanEqualToVar(
this, vars, MakeIntConst(cst)));
3466 if (vars.size() == 1) {
3467 return MakeEquality(vars[0], cst);
3468 }
else if (vars.size() == 2) {
3469 return MakeEquality(vars[0], MakeDifference(cst, vars[1]));
3471 if (DetectSumOverflow(vars)) {
3472 return RevAlloc(
new SafeSumConstraint(
this, vars, MakeIntConst(cst)));
3473 }
else if (size <= parameters_.array_split_size()) {
3474 return RevAlloc(
new SmallSumConstraint(
this, vars, MakeIntConst(cst)));
3476 return RevAlloc(
new SumConstraint(
this, vars, MakeIntConst(cst)));
3481Constraint* Solver::MakeSumEquality(
const std::vector<IntVar*>& vars,
3483 const int size = vars.size();
3485 return MakeEquality(
var,
Zero());
3488 return RevAlloc(
new SumBooleanEqualToVar(
this, vars,
var));
3489 }
else if (size == 0) {
3490 return MakeEquality(
var,
Zero());
3491 }
else if (size == 1) {
3492 return MakeEquality(vars[0],
var);
3493 }
else if (size == 2) {
3494 return MakeEquality(MakeSum(vars[0], vars[1]),
var);
3496 if (DetectSumOverflow(vars)) {
3497 return RevAlloc(
new SafeSumConstraint(
this, vars,
var));
3498 }
else if (size <= parameters_.array_split_size()) {
3499 return RevAlloc(
new SmallSumConstraint(
this, vars,
var));
3501 return RevAlloc(
new SumConstraint(
this, vars,
var));
3507 const std::vector<IntVar*>& vars,
const std::vector<int64_t>&
coefficients,
3510 return MakeScalProdEqualityFct(
this, vars,
coefficients, cst);
3513Constraint* Solver::MakeScalProdEquality(
const std::vector<IntVar*>& vars,
3521 const std::vector<IntVar*>& vars,
const std::vector<int64_t>&
coefficients,
3524 return MakeScalProdEqualityVarFct(
this, vars,
coefficients, target);
3527Constraint* Solver::MakeScalProdEquality(
const std::vector<IntVar*>& vars,
3536 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& coeffs,
3539 return MakeScalProdGreaterOrEqualFct(
this, vars, coeffs, cst);
3542Constraint* Solver::MakeScalProdGreaterOrEqual(
const std::vector<IntVar*>& vars,
3543 const std::vector<int>& coeffs,
3546 return MakeScalProdGreaterOrEqualFct(
this, vars,
ToInt64Vector(coeffs), cst);
3550 const std::vector<IntVar*>& vars,
const std::vector<int64_t>&
coefficients,
3553 return MakeScalProdLessOrEqualFct(
this, vars,
coefficients, cst);
3557 const std::vector<IntVar*>& vars,
const std::vector<int>&
coefficients,
3564IntExpr* Solver::MakeScalProd(
const std::vector<IntVar*>& vars,
3565 const std::vector<int64_t>& coefs) {
3567 return MakeScalProdFct(
this, vars, coefs);
3570IntExpr* Solver::MakeScalProd(
const std::vector<IntVar*>& vars,
3571 const std::vector<int>& coefs) {
#define DCHECK_NE(val1, val2)
#define CHECK_LT(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GT(val1, val2)
#define DCHECK_GE(val1, val2)
#define CHECK_NE(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
A constraint is the main modeling object.
The class IntExpr is the base of all integer expressions in constraint programming.
virtual IntVar * Var()=0
Creates a variable from the expression.
The class IntVar is a subset of IntExpr.
static const char kSumEqual[]
static const char kTargetArgument[]
static const char kValueArgument[]
static const char kMaxEqual[]
static const char kSumLessOrEqual[]
static const char kVarsArgument[]
static const char kMinEqual[]
static const char kSumGreaterOrEqual[]
const std::vector< IntVar * > vars_
#define IS_TYPE(type, tag)
absl::Span< const double > coefficients
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
bool AreAllNegative(const std::vector< T > &values)
int64_t CapSub(int64_t x, int64_t y)
bool AreAllBoundOrNull(const std::vector< IntVar * > &vars, const std::vector< T > &values)
Returns true if all the variables are assigned to a single value, or if their corresponding value is ...
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
bool AreAllBooleans(const std::vector< IntVar * > &vars)
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
int64_t CapProd(int64_t x, int64_t y)
bool AreAllNull(const std::vector< T > &values)
bool AreAllPositive(const std::vector< T > &values)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
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, const std::string &separator)
IntervalVar *const target_var_