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)");
48 EqualityExprCst(Solver* s, IntExpr* e, int64_t v);
49 ~EqualityExprCst()
override {}
51 void InitialPropagate()
override;
52 IntVar* Var()
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)
73void EqualityExprCst::Post() {
74 if (!expr_->IsVar()) {
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();
98 return RevAlloc(
new EqualityExprCst(
this, e, v));
102Constraint* Solver::MakeEquality(IntExpr*
const e,
int v) {
103 CHECK_EQ(
this, e->solver());
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();
113 return RevAlloc(
new EqualityExprCst(
this, e, v));
123 GreaterEqExprCst(Solver* s, IntExpr* e, int64_t v);
124 ~GreaterEqExprCst()
override {}
125 void Post()
override;
126 void InitialPropagate()
override;
128 IntVar* Var()
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);
141 IntExpr*
const expr_;
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() {
161 if (demon_ !=
nullptr && expr_->
Min() >= value_) {
166std::string GreaterEqExprCst::DebugString()
const {
167 return absl::StrFormat(
"(%s >= %d)", expr_->
DebugString(), value_);
172 CHECK_EQ(
this, e->solver());
175 }
else if (e->Max() < v) {
176 return MakeFalseConstraint();
178 return RevAlloc(
new GreaterEqExprCst(
this, e, v));
183 CHECK_EQ(
this, e->solver());
186 }
else if (e->Max() < v) {
187 return MakeFalseConstraint();
189 return RevAlloc(
new GreaterEqExprCst(
this, e, v));
194 CHECK_EQ(
this, e->solver());
197 }
else if (e->Max() <= v) {
198 return MakeFalseConstraint();
200 return RevAlloc(
new GreaterEqExprCst(
this, e, v + 1));
205 CHECK_EQ(
this, e->solver());
208 }
else if (e->Max() <= v) {
209 return MakeFalseConstraint();
211 return RevAlloc(
new GreaterEqExprCst(
this, e, v + 1));
219class LessEqExprCst :
public Constraint {
221 LessEqExprCst(Solver* s, IntExpr* e, int64_t v);
222 ~LessEqExprCst()
override {}
223 void Post()
override;
224 void InitialPropagate()
override;
225 std::string DebugString()
const override;
226 IntVar* Var()
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);
238 IntExpr*
const expr_;
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() {
258 if (demon_ !=
nullptr && expr_->
Max() <= value_) {
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();
275 return RevAlloc(
new LessEqExprCst(
this, e, v));
280 CHECK_EQ(
this, e->solver());
283 }
else if (e->Min() > v) {
284 return MakeFalseConstraint();
286 return RevAlloc(
new LessEqExprCst(
this, e, v));
291 CHECK_EQ(
this, e->solver());
294 }
else if (e->Min() >= v) {
295 return MakeFalseConstraint();
297 return RevAlloc(
new LessEqExprCst(
this, e, v - 1));
302 CHECK_EQ(
this, e->solver());
305 }
else if (e->Min() >= v) {
306 return MakeFalseConstraint();
308 return RevAlloc(
new LessEqExprCst(
this, e, v - 1));
316class DiffCst :
public Constraint {
318 DiffCst(Solver* s, IntVar* var, int64_t value);
319 ~DiffCst()
override {}
320 void Post()
override {}
321 void InitialPropagate()
override;
322 void BoundPropagate();
323 std::string DebugString()
const override;
324 IntVar* Var()
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_) {
361 }
else if (var_min == value_) {
363 }
else if (var_max == value_) {
365 }
else if (!HasLargeDomain(var_)) {
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());
382 IntExpr* left =
nullptr;
383 IntExpr* right =
nullptr;
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));
396 CHECK_EQ(
this, e->solver());
397 IntExpr* left =
nullptr;
398 IntExpr* right =
nullptr;
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();
406 return RevAlloc(
new DiffCst(
this, e->Var(), v));
412class IsEqualCstCt :
public CastConstraint {
414 IsEqualCstCt(Solver*
const s, IntVar*
const v, int64_t c, IntVar*
const b)
415 : CastConstraint(s,
b), var_(v), cst_(
c), demon_(nullptr) {}
416 void Post()
override {
417 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
419 target_var_->WhenBound(demon_);
421 void InitialPropagate()
override {
422 bool inhibit = var_->
Bound();
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) {
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);
464 IntExpr* left =
nullptr;
465 IntExpr* right =
nullptr;
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();
475 return MakeIntConst(0);
479 return var->Var()->IsEqual(value);
481 IntVar*
const boolvar =
482 MakeBoolVar(absl::StrFormat(
"Is(%s == %d)", var->DebugString(), value));
483 AddConstraint(MakeIsEqualCstCt(var, value, boolvar));
489 IntVar*
const boolvar) {
490 CHECK_EQ(
this, var->solver());
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);
504 if (boolvar->Bound()) {
505 if (boolvar->Min() == 0) {
506 return MakeNonEquality(var, value);
508 return MakeEquality(var, value);
513 model_cache_->InsertExprConstantExpression(
515 IntExpr* left =
nullptr;
516 IntExpr* right =
nullptr;
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) {}
532 void Post()
override {
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) {
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);
582 IntExpr* left =
nullptr;
583 IntExpr* right =
nullptr;
584 if (IsADifference(var, &left, &right)) {
591 IntVar*
const boolvar) {
592 CHECK_EQ(
this, var->solver());
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());
606 if (boolvar->Bound()) {
607 if (boolvar->Min() == 0) {
608 return MakeEquality(var, value);
610 return MakeNonEquality(var, value);
613 model_cache_->InsertExprConstantExpression(
615 IntExpr* left =
nullptr;
616 IntExpr* right =
nullptr;
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) {}
632 void Post()
override {
633 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
635 target_var_->WhenBound(demon_);
637 void InitialPropagate()
override {
638 bool inhibit =
false;
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) {
650 if (inhibit && ((target_var_->Max() == 0 && expr_->
Max() < cst_) ||
651 (target_var_->Min() == 1 && expr_->
Min() >= cst_))) {
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);
674 IntExpr*
const expr_;
681 if (var->Min() >= value) {
682 return MakeIntConst(int64_t{1});
684 if (var->Max() < value) {
688 return var->Var()->IsGreaterOrEqual(value);
690 IntVar*
const boolvar =
691 MakeBoolVar(absl::StrFormat(
"Is(%s >= %d)", var->DebugString(), value));
692 AddConstraint(MakeIsGreaterOrEqualCstCt(var, value, boolvar));
698 return MakeIsGreaterOrEqualCstVar(var, value + 1);
703 if (boolvar->
Bound()) {
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));
719 return MakeIsGreaterOrEqualCstCt(v, c + 1, b);
727 IsLessEqualCstCt(
Solver*
const s,
IntExpr*
const v, int64_t c,
731 void Post()
override {
732 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
734 target_var_->WhenBound(demon_);
737 void InitialPropagate()
override {
738 bool inhibit =
false;
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) {
750 if (inhibit && ((target_var_->Max() == 0 && expr_->
Min() > cst_) ||
751 (target_var_->Min() == 1 && expr_->
Max() <= cst_))) {
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});
790 IntVar*
const boolvar =
791 MakeBoolVar(absl::StrFormat(
"Is(%s <= %d)", var->
DebugString(), value));
792 AddConstraint(MakeIsLessOrEqualCstCt(var, value, boolvar));
798 return MakeIsLessOrEqualCstVar(var, value - 1);
803 if (boolvar->
Bound()) {
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));
819 return MakeIsLessOrEqualCstCt(v, c - 1, b);
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) {}
830 void Post()
override {
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_) {
848 return absl::StrFormat(
"BetweenCt(%s, %d, %d)", expr_->
DebugString(), min_,
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) {}
875 void Post()
override {
876 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
880 void InitialPropagate()
override {
883 expr_->
Range(&emin, &emax);
886 }
else if (emax <= max_) {
890 if (!expr_->
IsVar() && (emax < min_ || emin > max_)) {
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));
958 DCHECK_EQ(
this, expr->solver());
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);
975 return RevAlloc(
new NotBetweenCt(
this, expr, l, u));
983 IsBetweenCt(Solver*
const s, IntExpr*
const e, int64_t l, int64_t u,
992 void Post()
override {
993 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
998 void InitialPropagate()
override {
999 bool inhibit =
false;
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_) {
1014 }
else if (emax < max_) {
1021 if (inhibit && expr_->
IsVar()) {
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);
1044 IntExpr*
const expr_;
1047 IntVar*
const boolvar_;
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) {
1106 DCHECK(v !=
nullptr);
1107 DCHECK(s !=
nullptr);
1110 void Post()
override {}
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_;
1134 NotMemberCt(Solver*
const s, IntVar*
const v,
1135 const std::vector<int64_t>& sorted_values)
1136 :
Constraint(s), var_(v), values_(sorted_values) {
1137 DCHECK(v !=
nullptr);
1138 DCHECK(s !=
nullptr);
1141 void Post()
override {}
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;
1213 copied_values.clear();
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) {
1235 const std::vector<int64_t>& values) {
1236 const int64_t coeff = ExtractExprProductCoeff(&expr);
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;
1282 copied_values.clear();
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) {
1309 const std::vector<int64_t>& sorted_values,
IntVar*
const b)
1312 values_as_set_(sorted_values.begin(), sorted_values.end()),
1313 values_(sorted_values),
1317 domain_(var_->MakeDomainIterator(
true)),
1318 neg_support_(std::numeric_limits<int64_t>::min()) {
1319 DCHECK(v !=
nullptr);
1320 DCHECK(s !=
nullptr);
1321 DCHECK(b !=
nullptr);
1322 while (values_as_set_.contains(neg_support_)) {
1327 void Post()
override {
1330 if (!var_->
Bound()) {
1333 if (!boolvar_->
Bound()) {
1335 solver(),
this, &IsMemberCt::TargetBound,
"TargetBound");
1340 void InitialPropagate()
override {
1342 if (boolvar_->
Bound()) {
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])) {
1373 support_ = candidate;
1374 if (var_->
Bound()) {
1381 if (var_->
Contains(neg_support_)) {
1386 if (!values_as_set_.contains(value)) {
1387 neg_support_ = value;
1404 void TargetBound() {
1405 DCHECK(boolvar_->
Bound());
1406 if (boolvar_->
Min() == 1LL) {
1416 absl::flat_hash_set<int64_t> values_as_set_;
1417 std::vector<int64_t> values_;
1422 int64_t neg_support_;
1427 const std::vector<T>& values,
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) {
1437 if (value % coef == 0) {
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;
1446 bool all_values =
false;
1447 if (expr->
IsVar()) {
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()) {
1468 }
else if (all_values) {
1470 }
else if (filtered_values.size() == 1) {
1472 }
else if (filtered_values.back() ==
1473 filtered_values.front() + filtered_values.size() - 1) {
1476 filtered_values.back(), boolvar);
1479 new IsMemberCt(solver, expr->
Var(), filtered_values, boolvar));
1485 const std::vector<int64_t>& values,
1487 return BuildIsMemberCt(
this, expr, values, boolvar);
1491 const std::vector<int>& values,
1493 return BuildIsMemberCt(
this, expr, values, boolvar);
1497 const std::vector<int64_t>& values) {
1498 IntVar*
const b = MakeBoolVar();
1499 AddConstraint(MakeIsMemberCt(expr, values, b));
1504 const std::vector<int>& values) {
1505 IntVar*
const b = MakeBoolVar();
1506 AddConstraint(MakeIsMemberCt(expr, values, b));
1511class SortedDisjointForbiddenIntervalsConstraint :
public Constraint {
1513 SortedDisjointForbiddenIntervalsConstraint(
1516 :
Constraint(solver), var_(var), intervals_(std::move(intervals)) {}
1518 ~SortedDisjointForbiddenIntervalsConstraint()
override {}
1520 void Post()
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) {
1545 if (vmax <= last_interval_it->
end) {
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}));
1585 std::vector<int> starts,
1586 std::vector<int> 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)
Constraint * MakeNotMemberCt(IntExpr *expr, const std::vector< int64_t > &values)
expr not in set.
IntVar * MakeIsMemberVar(IntExpr *expr, const std::vector< int64_t > &values)
Constraint * MakeNonEquality(IntExpr *left, IntExpr *right)
left != right
IntVar * MakeIsEqualCstVar(IntExpr *var, int64_t value)
status var of (var == value)
IntExpr * MakeDifference(IntExpr *left, IntExpr *right)
left - right
Constraint * MakeMemberCt(IntExpr *expr, const std::vector< int64_t > &values)
Constraint * MakeGreaterOrEqual(IntExpr *left, IntExpr *right)
left >= right
IntVar * MakeIsLessOrEqualCstVar(IntExpr *var, int64_t value)
status var of (var <= value)
IntExpr * MakeSum(IntExpr *left, IntExpr *right)
left + right.
Constraint * MakeIsMemberCt(IntExpr *expr, const std::vector< int64_t > &values, IntVar *boolvar)
boolvar == (expr in set)
IntVar * MakeIsDifferentVar(IntExpr *v1, IntExpr *v2)
status var of (v1 != v2)
Constraint * MakeIsGreaterCstCt(IntExpr *v, int64_t c, IntVar *b)
b == (v > c)
IntVar * MakeIsGreaterCstVar(IntExpr *var, int64_t value)
status var of (var > value)
Constraint * MakeIsLessCstCt(IntExpr *v, int64_t c, IntVar *b)
b == (v < c)
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)
IntVar * MakeIsBetweenVar(IntExpr *v, int64_t l, int64_t u)
IntVar * MakeIsGreaterOrEqualCstVar(IntExpr *var, int64_t value)
status var of (var >= value)
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)
std::string DebugString() const
!defined(SWIG)
Constraint * MakeBetweenCt(IntExpr *expr, int64_t l, int64_t u)
(l <= expr <= u)
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)
Constraint * MakeIsBetweenCt(IntExpr *expr, int64_t l, int64_t u, IntVar *b)
b == (l <= expr <= u)
Constraint * MakeIsLessOrEqualCstCt(IntExpr *var, int64_t value, IntVar *boolvar)
boolvar == (var <= value)
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)
Constraint * MakeIsDifferentCstCt(IntExpr *var, int64_t value, IntVar *boolvar)
boolvar == (var != value)
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