Google OR-Tools: ortools/constraint_solver/expr_cst.cc Source File
25#include "absl/strings/str_format.h"
26#include "absl/strings/str_join.h"
37 "Initial size of the array of the hash "
38 "table of caches for objects of type Var(x == 3)");
46class EqualityExprCst : public Constraint {
48 EqualityExprCst(Solver* s, IntExpr* e, int64_t v);
49 ~EqualityExprCst() override {}
51 void InitialPropagate() override;
53 return solver()->MakeIsEqualCstVar(expr_->Var(), value_);
55 std::string DebugString() const override;
57 void Accept(ModelVisitor* const visitor) const override {
70EqualityExprCst::EqualityExprCst(Solver* const s, IntExpr* const e, int64_t v)
71 : Constraint(s), expr_(e), value_(v) {}
73void EqualityExprCst::Post() {
75 Demon* d = solver()->MakeConstraintInitialPropagateCallback(this);
80void EqualityExprCst::InitialPropagate() { expr_->SetValue(value_); }
82std::string EqualityExprCst::DebugString() const {
83 return absl::StrFormat("(%s == %d)", expr_->DebugString(), value_);
87Constraint* Solver::MakeEquality(IntExpr* const e, int64_t v) {
88 CHECK_EQ(this, e->solver());
91 if (IsADifference(e, &left, &right)) {
93 } else if (e->IsVar() && !e->Var()->Contains(v)) {
94 return MakeFalseConstraint();
95 } else if (e->Min() == e->Max() && e->Min() == v) {
96 return MakeTrueConstraint();
102Constraint* Solver::MakeEquality(IntExpr* const e, int v) {
103 CHECK_EQ(this, e->solver());
105 IntExpr* right = nullptr;
106 if (IsADifference(e, &left, &right)) {
108 } else if (e->IsVar() && !e->Var()->Contains(v)) {
109 return MakeFalseConstraint();
110 } else if (e->Min() == e->Max() && e->Min() == v) {
111 return MakeTrueConstraint();
121class GreaterEqExprCst : public Constraint {
123 GreaterEqExprCst(Solver* s, IntExpr* e, int64_t v);
124 ~GreaterEqExprCst() override {}
126 void InitialPropagate() override;
127 std::string DebugString() const override;
129 return solver()->MakeIsGreaterOrEqualCstVar(expr_->Var(), value_);
132 void Accept(ModelVisitor* const visitor) const override {
133 visitor->BeginVisitConstraint(ModelVisitor::kGreaterOrEqual, this);
134 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
136 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, value_);
137 visitor->EndVisitConstraint(ModelVisitor::kGreaterOrEqual, this);
146GreaterEqExprCst::GreaterEqExprCst(Solver* const s, IntExpr* const e, int64_t v)
147 : Constraint(s), expr_(e), value_(v), demon_(nullptr) {}
149void GreaterEqExprCst::Post() {
150 if (!expr_->IsVar() && expr_->Min() < value_) {
151 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
159void GreaterEqExprCst::InitialPropagate() {
160 expr_->SetMin(value_);
161 if (demon_ != nullptr && expr_->Min() >= value_) {
162 demon_->inhibit(solver());
166std::string GreaterEqExprCst::DebugString() const {
167 return absl::StrFormat("(%s >= %d)", expr_->DebugString(), value_);
172 CHECK_EQ(this, e->solver());
173 if (e->Min() >= v) {
175 } else if (e->Max() < v) {
176 return MakeFalseConstraint();
183 CHECK_EQ(this, e->solver());
184 if (e->Min() >= v) {
186 } else if (e->Max() < v) {
187 return MakeFalseConstraint();
194 CHECK_EQ(this, e->solver());
195 if (e->Min() > v) {
197 } else if (e->Max() <= v) {
198 return MakeFalseConstraint();
205 CHECK_EQ(this, e->solver());
206 if (e->Min() > v) {
208 } else if (e->Max() <= v) {
209 return MakeFalseConstraint();
219class LessEqExprCst : public Constraint {
221 LessEqExprCst(Solver* s, IntExpr* e, int64_t v);
222 ~LessEqExprCst() override {}
224 void InitialPropagate() override;
225 std::string DebugString() const override;
227 return solver()->MakeIsLessOrEqualCstVar(expr_->Var(), value_);
229 void Accept(ModelVisitor* const visitor) const override {
230 visitor->BeginVisitConstraint(ModelVisitor::kLessOrEqual, this);
231 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
233 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, value_);
234 visitor->EndVisitConstraint(ModelVisitor::kLessOrEqual, this);
243LessEqExprCst::LessEqExprCst(Solver* const s, IntExpr* const e, int64_t v)
244 : Constraint(s), expr_(e), value_(v), demon_(nullptr) {}
246void LessEqExprCst::Post() {
247 if (!expr_->IsVar() && expr_->Max() > value_) {
248 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
256void LessEqExprCst::InitialPropagate() {
257 expr_->SetMax(value_);
258 if (demon_ != nullptr && expr_->Max() <= value_) {
259 demon_->inhibit(solver());
263std::string LessEqExprCst::DebugString() const {
264 return absl::StrFormat("(%s <= %d)", expr_->DebugString(), value_);
269 CHECK_EQ(this, e->solver());
272 } else if (e->Min() > v) {
273 return MakeFalseConstraint();
283 } else if (e->Min() > v) {
284 return MakeFalseConstraint();
294 } else if (e->Min() >= v) {
295 return MakeFalseConstraint();
305 } else if (e->Min() >= v) {
306 return MakeFalseConstraint();
316class DiffCst : public Constraint {
318 DiffCst(Solver* s, IntVar* var, int64_t value);
321 void InitialPropagate() override;
323 std::string DebugString() const override;
325 return solver()->MakeIsDifferentCstVar(var_, value_);
327 void Accept(ModelVisitor* const visitor) const override {
328 visitor->BeginVisitConstraint(ModelVisitor::kNonEqual, this);
329 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
331 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, value_);
332 visitor->EndVisitConstraint(ModelVisitor::kNonEqual, this);
336 bool HasLargeDomain(IntVar* var);
343DiffCst::DiffCst(Solver* const s, IntVar* const var, int64_t value)
344 : Constraint(s), var_(var), value_(value), demon_(nullptr) {}
346void DiffCst::InitialPropagate() {
347 if (HasLargeDomain(var_)) {
356void DiffCst::BoundPropagate() {
357 const int64_t var_min = var_->Min();
358 const int64_t var_max = var_->Max();
359 if (var_min > value_ || var_max < value_) {
360 demon_->inhibit(solver());
361 } else if (var_min == value_) {
363 } else if (var_max == value_) {
365 } else if (!HasLargeDomain(var_)) {
366 demon_->inhibit(solver());
371std::string DiffCst::DebugString() const {
372 return absl::StrFormat("(%s != %d)", var_->DebugString(), value_);
375bool DiffCst::HasLargeDomain(IntVar* var) {
376 return CapSub(var->Max(), var->Min()) > 0xFFFFFF;
381 CHECK_EQ(this, e->solver());
384 if (IsADifference(e, &left, &right)) {
386 } else if (e->IsVar() && !e->Var()->Contains(v)) {
387 return MakeTrueConstraint();
388 } else if (e->Bound() && e->Min() == v) {
389 return MakeFalseConstraint();
391 return RevAlloc(new DiffCst(this, e->Var(), v));
399 if (IsADifference(e, &left, &right)) {
401 } else if (e->IsVar() && !e->Var()->Contains(v)) {
402 return MakeTrueConstraint();
403 } else if (e->Bound() && e->Min() == v) {
404 return MakeFalseConstraint();
414 IsEqualCstCt(Solver* const s, IntVar* const v, int64_t c, IntVar* const b)
415 : CastConstraint(s, b), var_(v), cst_(c), demon_(nullptr) {}
417 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
419 target_var_->WhenBound(demon_);
421 void InitialPropagate() override {
422 bool inhibit = var_->Bound();
423 int64_t u = var_->Contains(cst_);
424 int64_t l = inhibit ? u : 0;
425 target_var_->SetRange(l, u);
426 if (target_var_->Bound()) {
427 if (target_var_->Min() == 0) {
428 if (var_->Size() <= 0xFFFFFF) {
438 demon_->inhibit(solver());
441 std::string DebugString() const override {
442 return absl::StrFormat("IsEqualCstCt(%s, %d, %s)", var_->DebugString(),
443 cst_, target_var_->DebugString());
446 void Accept(ModelVisitor* const visitor) const override {
447 visitor->BeginVisitConstraint(ModelVisitor::kIsEqual, this);
448 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
450 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, cst_);
451 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
453 visitor->EndVisitConstraint(ModelVisitor::kIsEqual, this);
466 if (IsADifference(var, &left, &right)) {
469 if (CapSub(var->Max(), var->Min()) == 1) {
470 if (value == var->Min()) {
471 return MakeDifference(value + 1, var)->Var();
472 } else if (value == var->Max()) {
473 return MakeSum(var, -value + 1)->Var();
479 return var->Var()->IsEqual(value);
482 MakeBoolVar(absl::StrFormat("Is(%s == %d)", var->DebugString(), value));
491 CHECK_EQ(this, boolvar->solver());
492 if (value == var->Min()) {
493 if (CapSub(var->Max(), var->Min()) == 1) {
498 if (value == var->Max()) {
499 if (CapSub(var->Max(), var->Min()) == 1) {
500 return MakeEquality(MakeSum(var, -value + 1), boolvar);
502 return MakeIsGreaterOrEqualCstCt(var, value, boolvar);
505 if (boolvar->Min() == 0) {
506 return MakeNonEquality(var, value);
508 return MakeEquality(var, value);
513 model_cache_->InsertExprConstantExpression(
517 if (IsADifference(var, &left, &right)) {
518 return MakeIsEqualCt(left, MakeSum(right, value), boolvar);
520 return RevAlloc(new IsEqualCstCt(this, var->Var(), value, boolvar));
527class IsDiffCstCt : public CastConstraint {
529 IsDiffCstCt(Solver* const s, IntVar* const v, int64_t c, IntVar* const b)
530 : CastConstraint(s, b), var_(v), cst_(c), demon_(nullptr) {}
533 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
535 target_var_->WhenBound(demon_);
538 void InitialPropagate() override {
539 bool inhibit = var_->Bound();
540 int64_t l = 1 - var_->Contains(cst_);
541 int64_t u = inhibit ? l : 1;
542 target_var_->SetRange(l, u);
543 if (target_var_->Bound()) {
544 if (target_var_->Min() == 1) {
545 if (var_->Size() <= 0xFFFFFF) {
555 demon_->inhibit(solver());
559 std::string DebugString() const override {
560 return absl::StrFormat("IsDiffCstCt(%s, %d, %s)", var_->DebugString(), cst_,
561 target_var_->DebugString());
564 void Accept(ModelVisitor* const visitor) const override {
565 visitor->BeginVisitConstraint(ModelVisitor::kIsDifferent, this);
566 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
568 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, cst_);
569 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
571 visitor->EndVisitConstraint(ModelVisitor::kIsDifferent, this);
584 if (IsADifference(var, &left, &right)) {
593 CHECK_EQ(this, boolvar->solver());
594 if (value == var->Min()) {
597 if (value == var->Max()) {
598 return MakeIsLessOrEqualCstCt(var, value - 1, boolvar);
600 if (var->IsVar() && !var->Var()->Contains(value)) {
601 return MakeEquality(boolvar, int64_t{1});
603 if (var->Bound() && var->Min() == value) {
604 return MakeEquality(boolvar, Zero());
607 if (boolvar->Min() == 0) {
608 return MakeEquality(var, value);
610 return MakeNonEquality(var, value);
613 model_cache_->InsertExprConstantExpression(
617 if (IsADifference(var, &left, &right)) {
618 return MakeIsDifferentCt(left, MakeSum(right, value), boolvar);
620 return RevAlloc(new IsDiffCstCt(this, var->Var(), value, boolvar));
627class IsGreaterEqualCstCt : public CastConstraint {
629 IsGreaterEqualCstCt(Solver* const s, IntExpr* const v, int64_t c,
631 : CastConstraint(s, b), expr_(v), cst_(c), demon_(nullptr) {}
633 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
635 target_var_->WhenBound(demon_);
637 void InitialPropagate() override {
639 int64_t u = expr_->Max() >= cst_;
640 int64_t l = expr_->Min() >= cst_;
641 target_var_->SetRange(l, u);
642 if (target_var_->Bound()) {
644 if (target_var_->Min() == 0) {
645 expr_->SetMax(cst_ - 1);
650 if (inhibit && ((target_var_->Max() == 0 && expr_->Max() < cst_) ||
651 (target_var_->Min() == 1 && expr_->Min() >= cst_))) {
654 demon_->inhibit(solver());
657 std::string DebugString() const override {
658 return absl::StrFormat("IsGreaterEqualCstCt(%s, %d, %s)",
660 target_var_->DebugString());
663 void Accept(ModelVisitor* const visitor) const override {
664 visitor->BeginVisitConstraint(ModelVisitor::kIsGreaterOrEqual, this);
665 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
667 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, cst_);
668 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
670 visitor->EndVisitConstraint(ModelVisitor::kIsGreaterOrEqual, this);
681 if (var->Min() >= value) {
682 return MakeIntConst(int64_t{1});
684 if (var->Max() < value) {
688 return var->Var()->IsGreaterOrEqual(value);
691 MakeBoolVar(absl::StrFormat("Is(%s >= %d)", var->DebugString(), value));
692 AddConstraint(MakeIsGreaterOrEqualCstCt(var, value, boolvar));
704 if (boolvar->Min() == 0) {
707 return MakeGreaterOrEqual(var, value);
710 CHECK_EQ(this, var->solver());
711 CHECK_EQ(this, boolvar->solver());
712 model_cache_->InsertExprConstantExpression(
714 return RevAlloc(new IsGreaterEqualCstCt(this, var, value, boolvar));
727 IsLessEqualCstCt(Solver* const s, IntExpr* const v, int64_t c,
729 : CastConstraint(s, b), expr_(v), cst_(c), demon_(nullptr) {}
732 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
734 target_var_->WhenBound(demon_);
737 void InitialPropagate() override {
739 int64_t u = expr_->Min() <= cst_;
740 int64_t l = expr_->Max() <= cst_;
741 target_var_->SetRange(l, u);
742 if (target_var_->Bound()) {
744 if (target_var_->Min() == 0) {
745 expr_->SetMin(cst_ + 1);
750 if (inhibit && ((target_var_->Max() == 0 && expr_->Min() > cst_) ||
751 (target_var_->Min() == 1 && expr_->Max() <= cst_))) {
754 demon_->inhibit(solver());
758 std::string DebugString() const override {
759 return absl::StrFormat("IsLessEqualCstCt(%s, %d, %s)", expr_->DebugString(),
760 cst_, target_var_->DebugString());
781 if (var->Max() <= value) {
782 return MakeIntConst(int64_t{1});
787 if (var->IsVar()) {
791 MakeBoolVar(absl::StrFormat("Is(%s <= %d)", var->DebugString(), value));
792 AddConstraint(MakeIsLessOrEqualCstCt(var, value, boolvar));
804 if (boolvar->Min() == 0) {
807 return MakeLessOrEqual(var, value);
810 CHECK_EQ(this, var->solver());
811 CHECK_EQ(this, boolvar->solver());
812 model_cache_->InsertExprConstantExpression(
814 return RevAlloc(new IsLessEqualCstCt(this, var, value, boolvar));
827 BetweenCt(Solver* const s, IntExpr* const v, int64_t l, int64_t u)
828 : Constraint(s), expr_(v), min_(l), max_(u), demon_(nullptr) {}
831 if (!expr_->IsVar()) {
832 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
837 void InitialPropagate() override {
841 expr_->Range(&emin, &emax);
842 if (demon_ != nullptr && emin >= min_ && emax <= max_) {
843 demon_->inhibit(solver());
847 std::string DebugString() const override {
848 return absl::StrFormat("BetweenCt(%s, %d, %d)", expr_->DebugString(), min_,
870class NotBetweenCt : public Constraint {
872 NotBetweenCt(Solver* const s, IntExpr* const v, int64_t l, int64_t u)
873 : Constraint(s), expr_(v), min_(l), max_(u), demon_(nullptr) {}
876 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
880 void InitialPropagate() override {
883 expr_->Range(&emin, &emax);
885 expr_->SetMin(max_ + 1);
886 } else if (emax <= max_) {
887 expr_->SetMax(min_ - 1);
890 if (!expr_->IsVar() && (emax < min_ || emin > max_)) {
891 demon_->inhibit(solver());
895 std::string DebugString() const override {
896 return absl::StrFormat("NotBetweenCt(%s, %d, %d)", expr_->DebugString(),
916int64_t ExtractExprProductCoeff(IntExpr** expr) {
919 while ((*expr)->solver()->IsProduct(*expr, expr, &coeff)) prod *= coeff;
925 DCHECK_EQ(this, expr->solver());
933 expr->Range(&emin, &emax);
935 if (emax < l || emin > u) return MakeFalseConstraint();
936 if (emin >= l && emax <= u) return MakeTrueConstraint();
938 if (emax <= u) return MakeGreaterOrEqual(expr, l);
939 if (emin >= l) return MakeLessOrEqual(expr, u);
941 int64_t coeff = ExtractExprProductCoeff(&expr);
953 return RevAlloc(new BetweenCt(this, expr, l, u));
966 expr->Range(&emin, &emax);
968 if (emax < l || emin > u) return MakeTrueConstraint();
969 if (emin >= l && emax <= u) return MakeFalseConstraint();
971 if (emin >= l) return MakeGreater(expr, u);
972 if (emax <= u) return MakeLess(expr, l);
981class IsBetweenCt : public Constraint {
983 IsBetweenCt(Solver* const s, IntExpr* const e, int64_t l, int64_t u,
993 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
998 void InitialPropagate() override {
1002 expr_->Range(&emin, &emax);
1003 int64_t u = 1 - (emin > max_ || emax < min_);
1004 int64_t l = emax <= max_ && emin >= min_;
1006 if (boolvar_->Bound()) {
1008 if (boolvar_->Min() == 0) {
1009 if (expr_->IsVar()) {
1012 } else if (emin > min_) {
1013 expr_->SetMin(max_ + 1);
1014 } else if (emax < max_) {
1015 expr_->SetMax(min_ - 1);
1018 expr_->SetRange(min_, max_);
1021 if (inhibit && expr_->IsVar()) {
1022 demon_->inhibit(solver());
1027 std::string DebugString() const override {
1028 return absl::StrFormat("IsBetweenCt(%s, %d, %d, %s)", expr_->DebugString(),
1032 void Accept(ModelVisitor* const visitor) const override {
1033 visitor->BeginVisitConstraint(ModelVisitor::kIsBetween, this);
1034 visitor->VisitIntegerArgument(ModelVisitor::kMinArgument, min_);
1035 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
1037 visitor->VisitIntegerArgument(ModelVisitor::kMaxArgument, max_);
1038 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1040 visitor->EndVisitConstraint(ModelVisitor::kIsBetween, this);
1054 CHECK_EQ(this, expr->solver());
1055 CHECK_EQ(this, b->solver());
1063 expr->Range(&emin, &emax);
1065 if (emax < l || emin > u) return MakeEquality(b, Zero());
1066 if (emin >= l && emax <= u) return MakeEquality(b, 1);
1068 if (emax <= u) return MakeIsGreaterOrEqualCstCt(expr, l, b);
1069 if (emin >= l) return MakeIsLessOrEqualCstCt(expr, u, b);
1071 int64_t coeff = ExtractExprProductCoeff(&expr);
1084 return RevAlloc(new IsBetweenCt(this, expr, l, u, b));
1089 CHECK_EQ(this, v->solver());
1090 IntVar* const b = MakeBoolVar();
1091 AddConstraint(MakeIsBetweenCt(v, l, u, b));
1104 const std::vector<int64_t>& sorted_values)
1105 : Constraint(s), var_(v), values_(sorted_values) {
1112 void InitialPropagate() override { var_->SetValues(values_); }
1114 std::string DebugString() const override {
1115 return absl::StrFormat("Member(%s, %s)", var_->DebugString(),
1116 absl::StrJoin(values_, ", "));
1119 void Accept(ModelVisitor* const visitor) const override {
1129 const std::vector<int64_t> values_;
1132class NotMemberCt : public Constraint {
1134 NotMemberCt(Solver* const s, IntVar* const v,
1135 const std::vector<int64_t>& sorted_values)
1136 : Constraint(s), var_(v), values_(sorted_values) {
1143 void InitialPropagate() override { var_->RemoveValues(values_); }
1145 std::string DebugString() const override {
1146 return absl::StrFormat("NotMember(%s, %s)", var_->DebugString(),
1147 absl::StrJoin(values_, ", "));
1150 void Accept(ModelVisitor* const visitor) const override {
1151 visitor->BeginVisitConstraint(ModelVisitor::kMember, this);
1152 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
1154 visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument, values_);
1155 visitor->EndVisitConstraint(ModelVisitor::kMember, this);
1160 const std::vector<int64_t> values_;
1165 const std::vector<int64_t>& values) {
1166 const int64_t coeff = ExtractExprProductCoeff(&expr);
1168 return std::find(values.begin(), values.end(), 0) == values.end()
1172 std::vector<int64_t> copied_values = values;
1177 for (const int64_t v : copied_values) {
1178 if (v % coeff == 0) copied_values[num_kept++] = v / coeff;
1180 copied_values.resize(num_kept);
1186 expr->Range(&emin, &emax);
1187 for (const int64_t v : copied_values) {
1188 if (v >= emin && v <= emax) copied_values[num_kept++] = v;
1190 copied_values.resize(num_kept);
1192 if (copied_values.empty()) return MakeFalseConstraint();
1196 if (copied_values.size() == 1) return MakeEquality(expr, copied_values[0]);
1198 if (copied_values.size() ==
1199 copied_values.back() - copied_values.front() + 1) {
1201 return MakeBetweenCt(expr, copied_values.front(), copied_values.back());
1206 if (emax - emin < 2 * copied_values.size()) {
1208 std::vector<bool> is_among_input_values(emax - emin + 1, false);
1209 for (const int64_t v : copied_values)
1210 is_among_input_values[v - emin] = true;
1214 for (int64_t v_off = 0; v_off < is_among_input_values.size(); ++v_off) {
1215 if (!is_among_input_values[v_off]) copied_values.push_back(v_off + emin);
1219 DCHECK_GE(copied_values.size(), 1);
1220 if (copied_values.size() == 1) {
1221 return MakeNonEquality(expr, copied_values[0]);
1223 return RevAlloc(new NotMemberCt(this, expr->Var(), copied_values));
1226 return RevAlloc(new MemberCt(this, expr->Var(), copied_values));
1230 const std::vector<int>& values) {
1231 return MakeMemberCt(expr, ToInt64Vector(values));
1238 return std::find(values.begin(), values.end(), 0) == values.end()
1242 std::vector<int64_t> copied_values = values;
1247 for (const int64_t v : copied_values) {
1248 if (v % coeff == 0) copied_values[num_kept++] = v / coeff;
1250 copied_values.resize(num_kept);
1256 expr->Range(&emin, &emax);
1257 for (const int64_t v : copied_values) {
1258 if (v >= emin && v <= emax) copied_values[num_kept++] = v;
1260 copied_values.resize(num_kept);
1262 if (copied_values.empty()) return MakeTrueConstraint();
1266 if (copied_values.size() == 1) return MakeNonEquality(expr, copied_values[0]);
1268 if (copied_values.size() ==
1269 copied_values.back() - copied_values.front() + 1) {
1270 return MakeNotBetweenCt(expr, copied_values.front(), copied_values.back());
1275 if (emax - emin < 2 * copied_values.size()) {
1277 std::vector<bool> is_among_input_values(emax - emin + 1, false);
1278 for (const int64_t v : copied_values)
1279 is_among_input_values[v - emin] = true;
1283 for (int64_t v_off = 0; v_off < is_among_input_values.size(); ++v_off) {
1284 if (!is_among_input_values[v_off]) copied_values.push_back(v_off + emin);
1288 DCHECK_GE(copied_values.size(), 1);
1289 if (copied_values.size() == 1) {
1290 return MakeEquality(expr, copied_values[0]);
1292 return RevAlloc(new MemberCt(this, expr->Var(), copied_values));
1295 return RevAlloc(new NotMemberCt(this, expr->Var(), copied_values));
1299 const std::vector<int>& values) {
1300 return MakeNotMemberCt(expr, ToInt64Vector(values));
1306class IsMemberCt : public Constraint {
1308 IsMemberCt(Solver* const s, IntVar* const v,
1309 const std::vector<int64_t>& sorted_values, IntVar* const b)
1312 values_as_set_(sorted_values.begin(), sorted_values.end()),
1317 domain_(var_->MakeDomainIterator(true)),
1318 neg_support_(std::numeric_limits<int64_t>::min()) {
1322 while (values_as_set_.contains(neg_support_)) {
1330 if (!var_->Bound()) {
1333 if (!boolvar_->Bound()) {
1335 solver(), this, &IsMemberCt::TargetBound, "TargetBound");
1340 void InitialPropagate() override {
1342 if (boolvar_->Bound()) {
1349 std::string DebugString() const override {
1350 return absl::StrFormat("IsMemberCt(%s, %s, %s)", var_->DebugString(),
1351 absl::StrJoin(values_, ", "),
1367 if (boolvar_->Bound()) {
1370 for (int offset = 0; offset < values_.size(); ++offset) {
1371 const int candidate = (support_ + offset) % values_.size();
1372 if (var_->Contains(values_[candidate])) {
1374 if (var_->Bound()) {
1375 demon_->inhibit(solver());
1381 if (var_->Contains(neg_support_)) {
1386 if (!values_as_set_.contains(value)) {
1393 demon_->inhibit(solver());
1399 demon_->inhibit(solver());
1405 DCHECK(boolvar_->Bound());
1406 if (boolvar_->Min() == 1LL) {
1407 demon_->inhibit(solver());
1410 demon_->inhibit(solver());
1416 absl::flat_hash_set<int64_t> values_as_set_;
1417 std::vector<int64_t> values_;
1418 IntVar* const boolvar_;
1427 const std::vector<T>& values,
1428 IntVar* const boolvar) {
1433 if (solver->IsProduct(expr, &sub, &coef) && coef != 0 && coef != 1) {
1434 std::vector<int64_t> new_values;
1435 new_values.reserve(values.size());
1436 for (const int64_t value : values) {
1438 new_values.push_back(value / coef);
1441 return BuildIsMemberCt(solver, sub, new_values, boolvar);
1444 std::set<T> set_of_values(values.begin(), values.end());
1445 std::vector<int64_t> filtered_values;
1447 if (expr->IsVar()) {
1448 IntVar* const var = expr->Var();
1449 for (const T value : set_of_values) {
1451 filtered_values.push_back(value);
1454 all_values = (filtered_values.size() == var->Size());
1458 expr->Range(&emin, &emax);
1459 for (const T value : set_of_values) {
1460 if (value >= emin && value <= emax) {
1461 filtered_values.push_back(value);
1464 all_values = (filtered_values.size() == emax - emin + 1);
1466 if (filtered_values.empty()) {
1470 } else if (filtered_values.size() == 1) {
1471 return solver->MakeIsEqualCstCt(expr, filtered_values.back(), boolvar);
1472 } else if (filtered_values.back() ==
1473 filtered_values.front() + filtered_values.size() - 1) {
1475 return solver->MakeIsBetweenCt(expr, filtered_values.front(),
1476 filtered_values.back(), boolvar);
1479 new IsMemberCt(solver, expr->Var(), filtered_values, boolvar));
1485 const std::vector<int64_t>& values,
1486 IntVar* const boolvar) {
1487 return BuildIsMemberCt(this, expr, values, boolvar);
1493 return BuildIsMemberCt(this, expr, values, boolvar);
1499 AddConstraint(MakeIsMemberCt(expr, values, b));
1506 AddConstraint(MakeIsMemberCt(expr, values, b));
1511class SortedDisjointForbiddenIntervalsConstraint : public Constraint {
1513 SortedDisjointForbiddenIntervalsConstraint(
1516 : Constraint(solver), var_(var), intervals_(std::move(intervals)) {}
1518 ~SortedDisjointForbiddenIntervalsConstraint() override {}
1525 void InitialPropagate() override {
1526 const int64_t vmin = var_->Min();
1527 const int64_t vmax = var_->Max();
1529 if (first_interval_it == intervals_.end()) {
1534 if (last_interval_it == intervals_.end()) {
1540 if (vmin >= first_interval_it->start) {
1543 var_->SetMin(CapAdd(first_interval_it->end, 1));
1545 if (vmax <= last_interval_it->end) {
1547 var_->SetMax(CapSub(last_interval_it->start, 1));
1551 std::string DebugString() const override {
1552 return absl::StrFormat("ForbiddenIntervalCt(%s, %s)", var_->DebugString(),
1556 void Accept(ModelVisitor* const visitor) const override {
1560 std::vector<int64_t> starts;
1561 std::vector<int64_t> ends;
1562 for (auto& interval : intervals_) {
1563 starts.push_back(interval.start);
1564 ends.push_back(interval.end);
1578 std::vector<int64_t> starts,
1579 std::vector<int64_t> ends) {
1580 return RevAlloc(new SortedDisjointForbiddenIntervalsConstraint(
1581 this, expr->Var(), {starts, ends}));
1587 return RevAlloc(new SortedDisjointForbiddenIntervalsConstraint(
1588 this, expr->Var(), {starts, ends}));
1593 return RevAlloc(new SortedDisjointForbiddenIntervalsConstraint(
1594 this, expr->Var(), std::move(intervals)));
virtual void SetValue(int64_t v)
This method sets the value of the expression.
virtual bool Bound() const
Returns true if the min and the max of the expression are equal.
virtual void SetMax(int64_t m)=0
virtual bool IsVar() const
Returns true if the expression is indeed a variable.
virtual void SetRange(int64_t l, int64_t u)
This method sets both the min and the max of the expression.
virtual int64_t Min() const =0
virtual void SetMin(int64_t m)=0
virtual void WhenRange(Demon *d)=0
Attach a demon that will watch the min or the max of the expression.
virtual void Range(int64_t *l, int64_t *u)
virtual IntVar * Var()=0
Creates a variable from the expression.
virtual int64_t Max() const =0
virtual void WhenBound(Demon *d)=0
virtual void WhenDomain(Demon *d)=0
virtual void SetValues(const std::vector< int64_t > &values)
This method intersects the current domain with the values in the array.
virtual IntVar * IsDifferent(int64_t constant)=0
IntVar * Var() override
Creates a variable from the expression.
virtual IntVar * IsLessOrEqual(int64_t constant)=0
virtual bool Contains(int64_t v) const =0
virtual void RemoveValue(int64_t v)=0
This method removes the value 'v' from the domain of the variable.
virtual uint64_t Size() const =0
This method returns the number of values in the domain of the variable.
virtual void RemoveInterval(int64_t l, int64_t u)=0
virtual void RemoveValues(const std::vector< int64_t > &values)
This method remove the values from the domain of the variable.
@ EXPR_CONSTANT_IS_NOT_EQUAL
@ EXPR_CONSTANT_IS_GREATER_OR_EQUAL
@ EXPR_CONSTANT_IS_LESS_OR_EQUAL
static const char kIsMember[]
static const char kEndsArgument[]
static const char kNotBetween[]
virtual void VisitIntegerArgument(const std::string &arg_name, int64_t value)
Visit integer arguments.
static const char kMinArgument[]
static const char kExpressionArgument[]
static const char kTargetArgument[]
static const char kStartsArgument[]
static const char kMember[]
static const char kMaxArgument[]
virtual void VisitIntegerExpressionArgument(const std::string &arg_name, IntExpr *argument)
Visit integer expression argument.
static const char kNotMember[]
static const char kValueArgument[]
virtual void VisitIntegerArrayArgument(const std::string &arg_name, const std::vector< int64_t > &values)
static const char kValuesArgument[]
virtual void BeginVisitConstraint(const std::string &type_name, const Constraint *constraint)
static const char kEquality[]
static const char kBetween[]
static const char kIsLessOrEqual[]
virtual void EndVisitConstraint(const std::string &type_name, const Constraint *constraint)
std::string DebugString() const override
Constraint * MakeIsEqualCstCt(IntExpr *var, int64_t value, IntVar *boolvar)
boolvar == (var == value)
Definition expr_cst.cc:492
Constraint * MakeNotMemberCt(IntExpr *expr, const std::vector< int64_t > &values)
expr not in set.
Definition expr_cst.cc:1238
IntVar * MakeIsMemberVar(IntExpr *expr, const std::vector< int64_t > &values)
Definition expr_cst.cc:1500
Constraint * MakeNonEquality(IntExpr *left, IntExpr *right)
left != right
IntVar * MakeIsEqualCstVar(IntExpr *var, int64_t value)
status var of (var == value)
Definition expr_cst.cc:467
IntExpr * MakeDifference(IntExpr *left, IntExpr *right)
left - right
Constraint * MakeMemberCt(IntExpr *expr, const std::vector< int64_t > &values)
Definition expr_cst.cc:1168
Constraint * MakeGreaterOrEqual(IntExpr *left, IntExpr *right)
left >= right
IntVar * MakeIsLessOrEqualCstVar(IntExpr *var, int64_t value)
status var of (var <= value)
Definition expr_cst.cc:784
IntExpr * MakeSum(IntExpr *left, IntExpr *right)
left + right.
Constraint * MakeIsMemberCt(IntExpr *expr, const std::vector< int64_t > &values, IntVar *boolvar)
boolvar == (expr in set)
Definition expr_cst.cc:1488
IntVar * MakeIsDifferentVar(IntExpr *v1, IntExpr *v2)
status var of (v1 != v2)
Constraint * MakeIsGreaterCstCt(IntExpr *v, int64_t c, IntVar *b)
b == (v > c)
Definition expr_cst.cc:721
IntVar * MakeIsGreaterCstVar(IntExpr *var, int64_t value)
status var of (var > value)
Definition expr_cst.cc:701
Constraint * MakeIsLessCstCt(IntExpr *v, int64_t c, IntVar *b)
b == (v < c)
Definition expr_cst.cc:821
Constraint * MakeLess(IntExpr *left, IntExpr *right)
left < right
Constraint * MakeGreater(IntExpr *left, IntExpr *right)
left > right
IntVar * MakeIsEqualVar(IntExpr *v1, IntExpr *v2)
status var of (v1 == v2)
IntVar * MakeIsDifferentCstVar(IntExpr *var, int64_t value)
status var of (var != value)
Definition expr_cst.cc:585
IntVar * MakeIsBetweenVar(IntExpr *v, int64_t l, int64_t u)
Definition expr_cst.cc:1092
IntVar * MakeIsGreaterOrEqualCstVar(IntExpr *var, int64_t value)
status var of (var >= value)
Definition expr_cst.cc:684
void Accept(ModelVisitor *visitor) const
Accepts the given model visitor.
Constraint * MakeEquality(IntExpr *left, IntExpr *right)
left == right
Constraint * MakeTrueConstraint()
This constraint always succeeds.
Constraint * MakeLessOrEqual(IntExpr *left, IntExpr *right)
left <= right
Constraint * MakeIsGreaterOrEqualCstCt(IntExpr *var, int64_t value, IntVar *boolvar)
boolvar == (var >= value)
Definition expr_cst.cc:705
std::string DebugString() const
!defined(SWIG)
Constraint * MakeBetweenCt(IntExpr *expr, int64_t l, int64_t u)
(l <= expr <= u)
Definition expr_cst.cc:928
Demon * MakeConstraintInitialPropagateCallback(Constraint *ct)
Constraint * MakeFalseConstraint()
This constraint always fails.
bool IsProduct(IntExpr *expr, IntExpr **inner_expr, int64_t *coefficient)
IntVar * MakeIsLessCstVar(IntExpr *var, int64_t value)
status var of (var < value)
Definition expr_cst.cc:801
Constraint * MakeIsBetweenCt(IntExpr *expr, int64_t l, int64_t u, IntVar *b)
b == (l <= expr <= u)
Definition expr_cst.cc:1056
Constraint * MakeIsLessOrEqualCstCt(IntExpr *var, int64_t value, IntVar *boolvar)
boolvar == (var <= value)
Definition expr_cst.cc:805
IntVar * MakeIntConst(int64_t val, const std::string &name)
IntConst will create a constant expression.
Solver(const std::string &name)
Solver API.
Constraint * MakeNotBetweenCt(IntExpr *expr, int64_t l, int64_t u)
Definition expr_cst.cc:961
Constraint * MakeIsDifferentCstCt(IntExpr *var, int64_t value, IntVar *boolvar)
boolvar == (var != value)
Definition expr_cst.cc:594
Iterator LastIntervalLessOrEqual(int64_t value) const
std::string DebugString() const
Iterator FirstIntervalGreaterOrEqual(int64_t value) const
ConstIterator end() const
ABSL_FLAG(int, cache_initial_size, 1024, "Initial size of the array of the hash " "table of caches for objects of type Var(x == 3)")
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
ClosedInterval::Iterator end(ClosedInterval interval)
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
int64_t PosIntDivDown(int64_t e, int64_t v)
int64_t PosIntDivUp(int64_t e, int64_t v)
std::string DebugString() const