26#include "absl/strings/str_format.h"
27#include "absl/strings/str_join.h"
38 "Initial size of the array of the hash "
39 "table of caches for objects of type Var(x == 3)");
47class EqualityExprCst :
public Constraint {
49 EqualityExprCst(Solver* s, IntExpr* e, int64_t v);
50 ~EqualityExprCst()
override {}
52 void InitialPropagate()
override;
53 IntVar* Var()
override {
54 return solver()->MakeIsEqualCstVar(
expr_->Var(), value_);
56 std::string DebugString()
const override;
58 void Accept(ModelVisitor*
const visitor)
const override {
71EqualityExprCst::EqualityExprCst(Solver*
const s, IntExpr*
const e, int64_t v)
72 : Constraint(s),
expr_(e), value_(v) {}
74void EqualityExprCst::Post() {
75 if (!
expr_->IsVar()) {
76 Demon* d = solver()->MakeConstraintInitialPropagateCallback(
this);
81void EqualityExprCst::InitialPropagate() {
expr_->SetValue(value_); }
83std::string EqualityExprCst::DebugString()
const {
84 return absl::StrFormat(
"(%s == %d)",
expr_->DebugString(), value_);
88Constraint* Solver::MakeEquality(IntExpr*
const e, int64_t v) {
89 CHECK_EQ(
this, e->solver());
92 if (IsADifference(e, &left, &right)) {
93 return MakeEquality(left, MakeSum(right, v));
94 }
else if (e->IsVar() && !e->Var()->Contains(v)) {
95 return MakeFalseConstraint();
96 }
else if (e->Min() == e->Max() && e->Min() == v) {
97 return MakeTrueConstraint();
99 return RevAlloc(
new EqualityExprCst(
this, e, v));
103Constraint* Solver::MakeEquality(IntExpr*
const e,
int v) {
104 CHECK_EQ(
this, e->solver());
107 if (IsADifference(e, &left, &right)) {
108 return MakeEquality(left, MakeSum(right, v));
109 }
else if (e->IsVar() && !e->Var()->Contains(v)) {
110 return MakeFalseConstraint();
111 }
else if (e->Min() == e->Max() && e->Min() == v) {
112 return MakeTrueConstraint();
114 return RevAlloc(
new EqualityExprCst(
this, e, v));
122class GreaterEqExprCst :
public Constraint {
124 GreaterEqExprCst(Solver* s, IntExpr* e, int64_t v);
125 ~GreaterEqExprCst()
override {}
126 void Post()
override;
127 void InitialPropagate()
override;
128 std::string DebugString()
const override;
129 IntVar* Var()
override {
130 return solver()->MakeIsGreaterOrEqualCstVar(
expr_->Var(), value_);
133 void Accept(ModelVisitor*
const visitor)
const override {
134 visitor->BeginVisitConstraint(ModelVisitor::kGreaterOrEqual,
this);
135 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
137 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, value_);
138 visitor->EndVisitConstraint(ModelVisitor::kGreaterOrEqual,
this);
142 IntExpr*
const expr_;
147GreaterEqExprCst::GreaterEqExprCst(Solver*
const s, IntExpr*
const e, int64_t v)
148 : Constraint(s),
expr_(e), value_(v), demon_(nullptr) {}
150void GreaterEqExprCst::Post() {
151 if (!
expr_->IsVar() &&
expr_->Min() < value_) {
152 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
153 expr_->WhenRange(demon_);
160void GreaterEqExprCst::InitialPropagate() {
161 expr_->SetMin(value_);
162 if (demon_ !=
nullptr &&
expr_->Min() >= value_) {
167std::string GreaterEqExprCst::DebugString()
const {
168 return absl::StrFormat(
"(%s >= %d)",
expr_->DebugString(), value_);
173 CHECK_EQ(
this, e->solver());
175 return MakeTrueConstraint();
176 }
else if (e->Max() < v) {
177 return MakeFalseConstraint();
179 return RevAlloc(
new GreaterEqExprCst(
this, e, v));
184 CHECK_EQ(
this, e->solver());
186 return MakeTrueConstraint();
187 }
else if (e->Max() < v) {
188 return MakeFalseConstraint();
190 return RevAlloc(
new GreaterEqExprCst(
this, e, v));
195 CHECK_EQ(
this, e->solver());
197 return MakeTrueConstraint();
198 }
else if (e->Max() <= v) {
199 return MakeFalseConstraint();
201 return RevAlloc(
new GreaterEqExprCst(
this, e, v + 1));
206 CHECK_EQ(
this, e->solver());
208 return MakeTrueConstraint();
209 }
else if (e->Max() <= v) {
210 return MakeFalseConstraint();
212 return RevAlloc(
new GreaterEqExprCst(
this, e, v + 1));
220class LessEqExprCst :
public Constraint {
222 LessEqExprCst(Solver* s, IntExpr* e, int64_t v);
223 ~LessEqExprCst()
override {}
224 void Post()
override;
225 void InitialPropagate()
override;
226 std::string DebugString()
const override;
227 IntVar* Var()
override {
228 return solver()->MakeIsLessOrEqualCstVar(
expr_->Var(), value_);
230 void Accept(ModelVisitor*
const visitor)
const override {
231 visitor->BeginVisitConstraint(ModelVisitor::kLessOrEqual,
this);
232 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
234 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, value_);
235 visitor->EndVisitConstraint(ModelVisitor::kLessOrEqual,
this);
239 IntExpr*
const expr_;
244LessEqExprCst::LessEqExprCst(Solver*
const s, IntExpr*
const e, int64_t v)
245 : Constraint(s),
expr_(e), value_(v), demon_(nullptr) {}
247void LessEqExprCst::Post() {
248 if (!
expr_->IsVar() &&
expr_->Max() > value_) {
249 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
250 expr_->WhenRange(demon_);
257void LessEqExprCst::InitialPropagate() {
258 expr_->SetMax(value_);
259 if (demon_ !=
nullptr &&
expr_->Max() <= value_) {
264std::string LessEqExprCst::DebugString()
const {
265 return absl::StrFormat(
"(%s <= %d)",
expr_->DebugString(), value_);
270 CHECK_EQ(
this, e->solver());
272 return MakeTrueConstraint();
273 }
else if (e->Min() > v) {
274 return MakeFalseConstraint();
276 return RevAlloc(
new LessEqExprCst(
this, e, v));
281 CHECK_EQ(
this, e->solver());
283 return MakeTrueConstraint();
284 }
else if (e->Min() > v) {
285 return MakeFalseConstraint();
287 return RevAlloc(
new LessEqExprCst(
this, e, v));
292 CHECK_EQ(
this, e->solver());
294 return MakeTrueConstraint();
295 }
else if (e->Min() >= v) {
296 return MakeFalseConstraint();
298 return RevAlloc(
new LessEqExprCst(
this, e, v - 1));
303 CHECK_EQ(
this, e->solver());
305 return MakeTrueConstraint();
306 }
else if (e->Min() >= v) {
307 return MakeFalseConstraint();
309 return RevAlloc(
new LessEqExprCst(
this, e, v - 1));
317class DiffCst :
public Constraint {
319 DiffCst(Solver* s, IntVar*
var, int64_t
value);
320 ~DiffCst()
override {}
321 void Post()
override {}
322 void InitialPropagate()
override;
323 void BoundPropagate();
324 std::string DebugString()
const override;
325 IntVar* Var()
override {
326 return solver()->MakeIsDifferentCstVar(var_, value_);
328 void Accept(ModelVisitor*
const visitor)
const override {
329 visitor->BeginVisitConstraint(ModelVisitor::kNonEqual,
this);
330 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
332 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, value_);
333 visitor->EndVisitConstraint(ModelVisitor::kNonEqual,
this);
337 bool HasLargeDomain(IntVar*
var);
344DiffCst::DiffCst(Solver*
const s, IntVar*
const var, int64_t
value)
345 : Constraint(s), var_(
var), value_(
value), demon_(nullptr) {}
347void DiffCst::InitialPropagate() {
348 if (HasLargeDomain(var_)) {
357void DiffCst::BoundPropagate() {
358 const int64_t var_min = var_->
Min();
359 const int64_t var_max = var_->
Max();
360 if (var_min > value_ || var_max < value_) {
362 }
else if (var_min == value_) {
364 }
else if (var_max == value_) {
366 }
else if (!HasLargeDomain(var_)) {
372std::string DiffCst::DebugString()
const {
373 return absl::StrFormat(
"(%s != %d)", var_->
DebugString(), value_);
376bool DiffCst::HasLargeDomain(IntVar*
var) {
382 CHECK_EQ(
this, e->solver());
383 IntExpr* left =
nullptr;
384 IntExpr* right =
nullptr;
385 if (IsADifference(e, &left, &right)) {
386 return MakeNonEquality(left, MakeSum(right, v));
387 }
else if (e->IsVar() && !e->Var()->Contains(v)) {
388 return MakeTrueConstraint();
389 }
else if (e->Bound() && e->Min() == v) {
390 return MakeFalseConstraint();
392 return RevAlloc(
new DiffCst(
this, e->Var(), v));
397 CHECK_EQ(
this, e->solver());
398 IntExpr* left =
nullptr;
399 IntExpr* right =
nullptr;
400 if (IsADifference(e, &left, &right)) {
401 return MakeNonEquality(left, MakeSum(right, v));
402 }
else if (e->IsVar() && !e->Var()->Contains(v)) {
403 return MakeTrueConstraint();
404 }
else if (e->Bound() && e->Min() == v) {
405 return MakeFalseConstraint();
407 return RevAlloc(
new DiffCst(
this, e->Var(), v));
413class IsEqualCstCt :
public CastConstraint {
415 IsEqualCstCt(Solver*
const s, IntVar*
const v, int64_t c, IntVar*
const b)
416 : CastConstraint(s,
b), var_(v), cst_(
c), demon_(nullptr) {}
417 void Post()
override {
418 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
420 target_var_->WhenBound(demon_);
422 void InitialPropagate()
override {
423 bool inhibit = var_->
Bound();
425 int64_t l = inhibit ? u : 0;
426 target_var_->SetRange(l, u);
427 if (target_var_->Bound()) {
428 if (target_var_->Min() == 0) {
429 if (var_->
Size() <= 0xFFFFFF) {
442 std::string DebugString()
const override {
443 return absl::StrFormat(
"IsEqualCstCt(%s, %d, %s)", var_->
DebugString(),
444 cst_, target_var_->DebugString());
447 void Accept(ModelVisitor*
const visitor)
const override {
448 visitor->BeginVisitConstraint(ModelVisitor::kIsEqual,
this);
449 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
451 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, cst_);
452 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
454 visitor->EndVisitConstraint(ModelVisitor::kIsEqual,
this);
465 IntExpr* left =
nullptr;
466 IntExpr* right =
nullptr;
467 if (IsADifference(
var, &left, &right)) {
468 return MakeIsEqualVar(left, MakeSum(right,
value));
472 return MakeDifference(
value + 1,
var)->Var();
474 return MakeSum(
var, -
value + 1)->Var();
476 return MakeIntConst(0);
482 IntVar*
const boolvar =
483 MakeBoolVar(absl::StrFormat(
"Is(%s == %d)",
var->DebugString(),
value));
484 AddConstraint(MakeIsEqualCstCt(
var,
value, boolvar));
490 IntVar*
const boolvar) {
491 CHECK_EQ(
this,
var->solver());
492 CHECK_EQ(
this, boolvar->solver());
495 return MakeEquality(MakeDifference(
value + 1,
var), boolvar);
497 return MakeIsLessOrEqualCstCt(
var,
value, boolvar);
501 return MakeEquality(MakeSum(
var, -
value + 1), boolvar);
503 return MakeIsGreaterOrEqualCstCt(
var,
value, boolvar);
505 if (boolvar->Bound()) {
506 if (boolvar->Min() == 0) {
514 model_cache_->InsertExprConstantExpression(
516 IntExpr* left =
nullptr;
517 IntExpr* right =
nullptr;
518 if (IsADifference(
var, &left, &right)) {
519 return MakeIsEqualCt(left, MakeSum(right,
value), boolvar);
521 return RevAlloc(
new IsEqualCstCt(
this,
var->Var(),
value, boolvar));
528class IsDiffCstCt :
public CastConstraint {
530 IsDiffCstCt(Solver*
const s, IntVar*
const v, int64_t c, IntVar*
const b)
531 : CastConstraint(s,
b), var_(v), cst_(
c), demon_(nullptr) {}
533 void Post()
override {
534 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
536 target_var_->WhenBound(demon_);
539 void InitialPropagate()
override {
540 bool inhibit = var_->
Bound();
541 int64_t l = 1 - var_->
Contains(cst_);
542 int64_t u = inhibit ? l : 1;
543 target_var_->SetRange(l, u);
544 if (target_var_->Bound()) {
545 if (target_var_->Min() == 1) {
546 if (var_->
Size() <= 0xFFFFFF) {
560 std::string DebugString()
const override {
561 return absl::StrFormat(
"IsDiffCstCt(%s, %d, %s)", var_->
DebugString(), cst_,
562 target_var_->DebugString());
565 void Accept(ModelVisitor*
const visitor)
const override {
566 visitor->BeginVisitConstraint(ModelVisitor::kIsDifferent,
this);
567 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
569 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, cst_);
570 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
572 visitor->EndVisitConstraint(ModelVisitor::kIsDifferent,
this);
583 IntExpr* left =
nullptr;
584 IntExpr* right =
nullptr;
585 if (IsADifference(
var, &left, &right)) {
586 return MakeIsDifferentVar(left, MakeSum(right,
value));
592 IntVar*
const boolvar) {
593 CHECK_EQ(
this,
var->solver());
594 CHECK_EQ(
this, boolvar->solver());
596 return MakeIsGreaterOrEqualCstCt(
var,
value + 1, boolvar);
599 return MakeIsLessOrEqualCstCt(
var,
value - 1, boolvar);
601 if (
var->IsVar() && !
var->Var()->Contains(
value)) {
602 return MakeEquality(boolvar, int64_t{1});
605 return MakeEquality(boolvar,
Zero());
607 if (boolvar->Bound()) {
608 if (boolvar->Min() == 0) {
614 model_cache_->InsertExprConstantExpression(
616 IntExpr* left =
nullptr;
617 IntExpr* right =
nullptr;
618 if (IsADifference(
var, &left, &right)) {
619 return MakeIsDifferentCt(left, MakeSum(right,
value), boolvar);
621 return RevAlloc(
new IsDiffCstCt(
this,
var->Var(),
value, boolvar));
628class IsGreaterEqualCstCt :
public CastConstraint {
630 IsGreaterEqualCstCt(Solver*
const s, IntExpr*
const v, int64_t c,
632 : CastConstraint(s,
b),
expr_(v), cst_(
c), demon_(nullptr) {}
633 void Post()
override {
634 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
635 expr_->WhenRange(demon_);
636 target_var_->WhenBound(demon_);
638 void InitialPropagate()
override {
639 bool inhibit =
false;
640 int64_t u =
expr_->Max() >= cst_;
641 int64_t l =
expr_->Min() >= cst_;
642 target_var_->SetRange(l, u);
643 if (target_var_->Bound()) {
645 if (target_var_->Min() == 0) {
646 expr_->SetMax(cst_ - 1);
651 if (inhibit && ((target_var_->Max() == 0 &&
expr_->Max() < cst_) ||
652 (target_var_->Min() == 1 &&
expr_->Min() >= cst_))) {
658 std::string DebugString()
const override {
659 return absl::StrFormat(
"IsGreaterEqualCstCt(%s, %d, %s)",
660 expr_->DebugString(), cst_,
661 target_var_->DebugString());
664 void Accept(ModelVisitor*
const visitor)
const override {
665 visitor->BeginVisitConstraint(ModelVisitor::kIsGreaterOrEqual,
this);
666 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
668 visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, cst_);
669 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
671 visitor->EndVisitConstraint(ModelVisitor::kIsGreaterOrEqual,
this);
675 IntExpr*
const expr_;
683 return MakeIntConst(int64_t{1});
686 return MakeIntConst(int64_t{0});
689 return var->Var()->IsGreaterOrEqual(
value);
691 IntVar*
const boolvar =
692 MakeBoolVar(absl::StrFormat(
"Is(%s >= %d)",
var->DebugString(),
value));
693 AddConstraint(MakeIsGreaterOrEqualCstCt(
var,
value, boolvar));
699 return MakeIsGreaterOrEqualCstVar(
var,
value + 1);
704 if (boolvar->
Bound()) {
705 if (boolvar->
Min() == 0) {
708 return MakeGreaterOrEqual(
var,
value);
711 CHECK_EQ(
this,
var->solver());
712 CHECK_EQ(
this, boolvar->
solver());
713 model_cache_->InsertExprConstantExpression(
715 return RevAlloc(
new IsGreaterEqualCstCt(
this,
var,
value, boolvar));
720 return MakeIsGreaterOrEqualCstCt(v, c + 1,
b);
728 IsLessEqualCstCt(
Solver*
const s,
IntExpr*
const v, int64_t c,
732 void Post()
override {
733 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
734 expr_->WhenRange(demon_);
735 target_var_->WhenBound(demon_);
738 void InitialPropagate()
override {
739 bool inhibit =
false;
740 int64_t u =
expr_->Min() <= cst_;
741 int64_t l =
expr_->Max() <= cst_;
742 target_var_->SetRange(l, u);
743 if (target_var_->Bound()) {
745 if (target_var_->Min() == 0) {
746 expr_->SetMin(cst_ + 1);
751 if (inhibit && ((target_var_->Max() == 0 &&
expr_->Min() > cst_) ||
752 (target_var_->Min() == 1 &&
expr_->Max() <= cst_))) {
759 std::string DebugString()
const override {
760 return absl::StrFormat(
"IsLessEqualCstCt(%s, %d, %s)",
expr_->DebugString(),
761 cst_, target_var_->DebugString());
764 void Accept(
ModelVisitor*
const visitor)
const override {
783 return MakeIntConst(int64_t{1});
786 return MakeIntConst(int64_t{0});
789 return var->Var()->IsLessOrEqual(
value);
791 IntVar*
const boolvar =
792 MakeBoolVar(absl::StrFormat(
"Is(%s <= %d)",
var->DebugString(),
value));
793 AddConstraint(MakeIsLessOrEqualCstCt(
var,
value, boolvar));
799 return MakeIsLessOrEqualCstVar(
var,
value - 1);
804 if (boolvar->
Bound()) {
805 if (boolvar->
Min() == 0) {
811 CHECK_EQ(
this,
var->solver());
812 CHECK_EQ(
this, boolvar->
solver());
813 model_cache_->InsertExprConstantExpression(
815 return RevAlloc(
new IsLessEqualCstCt(
this,
var,
value, boolvar));
820 return MakeIsLessOrEqualCstCt(v, c - 1,
b);
828 BetweenCt(
Solver*
const s,
IntExpr*
const v, int64_t l, int64_t u)
831 void Post()
override {
832 if (!
expr_->IsVar()) {
833 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
834 expr_->WhenRange(demon_);
838 void InitialPropagate()
override {
839 expr_->SetRange(min_, max_);
842 expr_->Range(&emin, &emax);
843 if (demon_ !=
nullptr && emin >= min_ && emax <= max_) {
848 std::string DebugString()
const override {
849 return absl::StrFormat(
"BetweenCt(%s, %d, %d)",
expr_->DebugString(), min_,
853 void Accept(
ModelVisitor*
const visitor)
const override {
873 NotBetweenCt(
Solver*
const s,
IntExpr*
const v, int64_t l, int64_t u)
876 void Post()
override {
877 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
878 expr_->WhenRange(demon_);
881 void InitialPropagate()
override {
884 expr_->Range(&emin, &emax);
886 expr_->SetMin(max_ + 1);
887 }
else if (emax <= max_) {
888 expr_->SetMax(min_ - 1);
891 if (!
expr_->IsVar() && (emax < min_ || emin > max_)) {
896 std::string DebugString()
const override {
897 return absl::StrFormat(
"NotBetweenCt(%s, %d, %d)",
expr_->DebugString(),
901 void Accept(
ModelVisitor*
const visitor)
const override {
917int64_t ExtractExprProductCoeff(
IntExpr** expr) {
920 while ((*expr)->solver()->IsProduct(*expr, expr, &coeff)) prod *= coeff;
926 DCHECK_EQ(
this, expr->
solver());
929 if (l > u)
return MakeFalseConstraint();
930 return MakeEquality(expr, l);
934 expr->
Range(&emin, &emax);
936 if (emax < l || emin > u)
return MakeFalseConstraint();
937 if (emin >= l && emax <= u)
return MakeTrueConstraint();
939 if (emax <= u)
return MakeGreaterOrEqual(expr, l);
940 if (emin >= l)
return MakeLessOrEqual(expr, u);
942 int64_t coeff = ExtractExprProductCoeff(&expr);
954 return RevAlloc(
new BetweenCt(
this, expr, l, u));
959 DCHECK_EQ(
this, expr->solver());
962 return MakeTrueConstraint();
967 expr->Range(&emin, &emax);
969 if (emax < l || emin > u)
return MakeTrueConstraint();
970 if (emin >= l && emax <= u)
return MakeFalseConstraint();
972 if (emin >= l)
return MakeGreater(expr, u);
973 if (emax <= u)
return MakeLess(expr, l);
976 return RevAlloc(
new NotBetweenCt(
this, expr, l, u));
982class IsBetweenCt :
public Constraint {
984 IsBetweenCt(Solver*
const s, IntExpr*
const e, int64_t l, int64_t u,
993 void Post()
override {
994 demon_ = solver()->MakeConstraintInitialPropagateCallback(
this);
995 expr_->WhenRange(demon_);
999 void InitialPropagate()
override {
1000 bool inhibit =
false;
1003 expr_->Range(&emin, &emax);
1004 int64_t u = 1 - (emin > max_ || emax < min_);
1005 int64_t l = emax <= max_ && emin >= min_;
1007 if (boolvar_->
Bound()) {
1009 if (boolvar_->
Min() == 0) {
1010 if (
expr_->IsVar()) {
1011 expr_->Var()->RemoveInterval(min_, max_);
1013 }
else if (emin > min_) {
1014 expr_->SetMin(max_ + 1);
1015 }
else if (emax < max_) {
1016 expr_->SetMax(min_ - 1);
1019 expr_->SetRange(min_, max_);
1022 if (inhibit &&
expr_->IsVar()) {
1028 std::string DebugString()
const override {
1029 return absl::StrFormat(
"IsBetweenCt(%s, %d, %d, %s)",
expr_->DebugString(),
1033 void Accept(ModelVisitor*
const visitor)
const override {
1034 visitor->BeginVisitConstraint(ModelVisitor::kIsBetween,
this);
1035 visitor->VisitIntegerArgument(ModelVisitor::kMinArgument, min_);
1036 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
1038 visitor->VisitIntegerArgument(ModelVisitor::kMaxArgument, max_);
1039 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
1041 visitor->EndVisitConstraint(ModelVisitor::kIsBetween,
this);
1045 IntExpr*
const expr_;
1048 IntVar*
const boolvar_;
1055 CHECK_EQ(
this, expr->solver());
1056 CHECK_EQ(
this,
b->solver());
1059 if (l > u)
return MakeEquality(
b,
Zero());
1060 return MakeIsEqualCstCt(expr, l,
b);
1064 expr->Range(&emin, &emax);
1066 if (emax < l || emin > u)
return MakeEquality(
b,
Zero());
1067 if (emin >= l && emax <= u)
return MakeEquality(
b, 1);
1069 if (emax <= u)
return MakeIsGreaterOrEqualCstCt(expr, l,
b);
1070 if (emin >= l)
return MakeIsLessOrEqualCstCt(expr, u,
b);
1072 int64_t coeff = ExtractExprProductCoeff(&expr);
1085 return RevAlloc(
new IsBetweenCt(
this, expr, l, u,
b));
1090 CHECK_EQ(
this, v->solver());
1091 IntVar*
const b = MakeBoolVar();
1092 AddConstraint(MakeIsBetweenCt(v, l, u,
b));
1105 const std::vector<int64_t>& sorted_values)
1106 :
Constraint(s), var_(v), values_(sorted_values) {
1107 DCHECK(v !=
nullptr);
1108 DCHECK(s !=
nullptr);
1111 void Post()
override {}
1113 void InitialPropagate()
override { var_->
SetValues(values_); }
1115 std::string DebugString()
const override {
1116 return absl::StrFormat(
"Member(%s, %s)", var_->
DebugString(),
1117 absl::StrJoin(values_,
", "));
1120 void Accept(
ModelVisitor*
const visitor)
const override {
1130 const std::vector<int64_t> values_;
1133class NotMemberCt :
public Constraint {
1135 NotMemberCt(Solver*
const s, IntVar*
const v,
1136 const std::vector<int64_t>& sorted_values)
1137 : Constraint(s), var_(v), values_(sorted_values) {
1138 DCHECK(v !=
nullptr);
1139 DCHECK(s !=
nullptr);
1142 void Post()
override {}
1144 void InitialPropagate()
override { var_->
RemoveValues(values_); }
1146 std::string DebugString()
const override {
1147 return absl::StrFormat(
"NotMember(%s, %s)", var_->
DebugString(),
1148 absl::StrJoin(values_,
", "));
1151 void Accept(ModelVisitor*
const visitor)
const override {
1152 visitor->BeginVisitConstraint(ModelVisitor::kMember,
this);
1153 visitor->VisitIntegerExpressionArgument(ModelVisitor::kExpressionArgument,
1155 visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument, values_);
1156 visitor->EndVisitConstraint(ModelVisitor::kMember,
this);
1161 const std::vector<int64_t> values_;
1166 const std::vector<int64_t>& values) {
1167 const int64_t coeff = ExtractExprProductCoeff(&expr);
1169 return std::find(values.begin(), values.end(), 0) == values.end()
1170 ? MakeFalseConstraint()
1171 : MakeTrueConstraint();
1173 std::vector<int64_t> copied_values = values;
1178 for (
const int64_t v : copied_values) {
1179 if (v % coeff == 0) copied_values[num_kept++] = v / coeff;
1181 copied_values.resize(num_kept);
1187 expr->Range(&emin, &emax);
1188 for (
const int64_t v : copied_values) {
1189 if (v >= emin && v <= emax) copied_values[num_kept++] = v;
1191 copied_values.resize(num_kept);
1193 if (copied_values.empty())
return MakeFalseConstraint();
1197 if (copied_values.size() == 1)
return MakeEquality(expr, copied_values[0]);
1199 if (copied_values.size() ==
1200 copied_values.back() - copied_values.front() + 1) {
1202 return MakeBetweenCt(expr, copied_values.front(), copied_values.back());
1207 if (emax - emin < 2 * copied_values.size()) {
1209 std::vector<bool> is_among_input_values(emax - emin + 1,
false);
1210 for (
const int64_t v : copied_values)
1211 is_among_input_values[v - emin] =
true;
1214 copied_values.clear();
1215 for (int64_t v_off = 0; v_off < is_among_input_values.size(); ++v_off) {
1216 if (!is_among_input_values[v_off]) copied_values.push_back(v_off + emin);
1220 DCHECK_GE(copied_values.size(), 1);
1221 if (copied_values.size() == 1) {
1222 return MakeNonEquality(expr, copied_values[0]);
1224 return RevAlloc(
new NotMemberCt(
this, expr->Var(), copied_values));
1227 return RevAlloc(
new MemberCt(
this, expr->Var(), copied_values));
1231 const std::vector<int>& values) {
1236 const std::vector<int64_t>& values) {
1237 const int64_t coeff = ExtractExprProductCoeff(&expr);
1239 return std::find(values.begin(), values.end(), 0) == values.end()
1240 ? MakeTrueConstraint()
1241 : MakeFalseConstraint();
1243 std::vector<int64_t> copied_values = values;
1248 for (
const int64_t v : copied_values) {
1249 if (v % coeff == 0) copied_values[num_kept++] = v / coeff;
1251 copied_values.resize(num_kept);
1257 expr->
Range(&emin, &emax);
1258 for (
const int64_t v : copied_values) {
1259 if (v >= emin && v <= emax) copied_values[num_kept++] = v;
1261 copied_values.resize(num_kept);
1263 if (copied_values.empty())
return MakeTrueConstraint();
1267 if (copied_values.size() == 1)
return MakeNonEquality(expr, copied_values[0]);
1269 if (copied_values.size() ==
1270 copied_values.back() - copied_values.front() + 1) {
1271 return MakeNotBetweenCt(expr, copied_values.front(), copied_values.back());
1276 if (emax - emin < 2 * copied_values.size()) {
1278 std::vector<bool> is_among_input_values(emax - emin + 1,
false);
1279 for (
const int64_t v : copied_values)
1280 is_among_input_values[v - emin] =
true;
1283 copied_values.clear();
1284 for (int64_t v_off = 0; v_off < is_among_input_values.size(); ++v_off) {
1285 if (!is_among_input_values[v_off]) copied_values.push_back(v_off + emin);
1289 DCHECK_GE(copied_values.size(), 1);
1290 if (copied_values.size() == 1) {
1291 return MakeEquality(expr, copied_values[0]);
1293 return RevAlloc(
new MemberCt(
this, expr->
Var(), copied_values));
1296 return RevAlloc(
new NotMemberCt(
this, expr->
Var(), copied_values));
1300 const std::vector<int>& values) {
1310 const std::vector<int64_t>& sorted_values,
IntVar*
const b)
1313 values_as_set_(sorted_values.begin(), sorted_values.end()),
1314 values_(sorted_values),
1318 domain_(var_->MakeDomainIterator(
true)),
1319 neg_support_(std::numeric_limits<int64_t>::min()) {
1320 DCHECK(v !=
nullptr);
1321 DCHECK(s !=
nullptr);
1322 DCHECK(
b !=
nullptr);
1323 while (values_as_set_.contains(neg_support_)) {
1328 void Post()
override {
1331 if (!var_->
Bound()) {
1334 if (!boolvar_->
Bound()) {
1336 solver(),
this, &IsMemberCt::TargetBound,
"TargetBound");
1341 void InitialPropagate()
override {
1343 if (boolvar_->
Bound()) {
1350 std::string DebugString()
const override {
1351 return absl::StrFormat(
"IsMemberCt(%s, %s, %s)", var_->
DebugString(),
1352 absl::StrJoin(values_,
", "),
1356 void Accept(
ModelVisitor*
const visitor)
const override {
1368 if (boolvar_->
Bound()) {
1371 for (
int offset = 0; offset < values_.size(); ++offset) {
1372 const int candidate = (support_ + offset) % values_.size();
1373 if (var_->
Contains(values_[candidate])) {
1374 support_ = candidate;
1375 if (var_->
Bound()) {
1382 if (var_->
Contains(neg_support_)) {
1387 if (!values_as_set_.contains(
value)) {
1388 neg_support_ =
value;
1405 void TargetBound() {
1406 DCHECK(boolvar_->
Bound());
1407 if (boolvar_->
Min() == 1LL) {
1417 absl::flat_hash_set<int64_t> values_as_set_;
1418 std::vector<int64_t> values_;
1423 int64_t neg_support_;
1428 const std::vector<T>& values,
1435 std::vector<int64_t> new_values;
1436 new_values.reserve(values.size());
1437 for (
const int64_t
value : values) {
1442 return BuildIsMemberCt(solver, sub, new_values, boolvar);
1445 std::set<T> set_of_values(values.begin(), values.end());
1446 std::vector<int64_t> filtered_values;
1447 bool all_values =
false;
1448 if (expr->
IsVar()) {
1450 for (
const T
value : set_of_values) {
1452 filtered_values.push_back(
value);
1455 all_values = (filtered_values.size() ==
var->Size());
1459 expr->
Range(&emin, &emax);
1460 for (
const T
value : set_of_values) {
1462 filtered_values.push_back(
value);
1465 all_values = (filtered_values.size() == emax - emin + 1);
1467 if (filtered_values.empty()) {
1469 }
else if (all_values) {
1471 }
else if (filtered_values.size() == 1) {
1473 }
else if (filtered_values.back() ==
1474 filtered_values.front() + filtered_values.size() - 1) {
1477 filtered_values.back(), boolvar);
1480 new IsMemberCt(solver, expr->
Var(), filtered_values, boolvar));
1486 const std::vector<int64_t>& values,
1488 return BuildIsMemberCt(
this, expr, values, boolvar);
1492 const std::vector<int>& values,
1494 return BuildIsMemberCt(
this, expr, values, boolvar);
1498 const std::vector<int64_t>& values) {
1499 IntVar*
const b = MakeBoolVar();
1500 AddConstraint(MakeIsMemberCt(expr, values,
b));
1505 const std::vector<int>& values) {
1506 IntVar*
const b = MakeBoolVar();
1507 AddConstraint(MakeIsMemberCt(expr, values,
b));
1512class SortedDisjointForbiddenIntervalsConstraint :
public Constraint {
1514 SortedDisjointForbiddenIntervalsConstraint(
1517 :
Constraint(solver), var_(
var), intervals_(std::move(intervals)) {}
1519 ~SortedDisjointForbiddenIntervalsConstraint()
override {}
1521 void Post()
override {
1526 void InitialPropagate()
override {
1527 const int64_t vmin = var_->
Min();
1528 const int64_t vmax = var_->
Max();
1530 if (first_interval_it == intervals_.
end()) {
1535 if (last_interval_it == intervals_.
end()) {
1541 if (vmin >= first_interval_it->start) {
1546 if (vmax <= last_interval_it->
end) {
1552 std::string DebugString()
const override {
1553 return absl::StrFormat(
"ForbiddenIntervalCt(%s, %s)", var_->
DebugString(),
1557 void Accept(
ModelVisitor*
const visitor)
const override {
1561 std::vector<int64_t> starts;
1562 std::vector<int64_t> ends;
1563 for (
auto&
interval : intervals_) {
1579 std::vector<int64_t> starts,
1580 std::vector<int64_t> ends) {
1581 return RevAlloc(
new SortedDisjointForbiddenIntervalsConstraint(
1582 this, expr->Var(), {starts, ends}));
1586 std::vector<int> starts,
1587 std::vector<int> ends) {
1588 return RevAlloc(
new SortedDisjointForbiddenIntervalsConstraint(
1589 this, expr->
Var(), {starts, ends}));
1594 return RevAlloc(
new SortedDisjointForbiddenIntervalsConstraint(
1595 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 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 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
virtual void VisitIntegerArgument(const std::string &arg_name, int64_t value)
Visit integer arguments.
static const char kExpressionArgument[]
virtual void VisitIntegerExpressionArgument(const std::string &arg_name, IntExpr *argument)
Visit integer expression argument.
static const char kValueArgument[]
virtual void VisitIntegerArrayArgument(const std::string &arg_name, const std::vector< int64_t > &values)
virtual void BeginVisitConstraint(const std::string &type_name, const Constraint *constraint)
static const char kEquality[]
virtual void EndVisitConstraint(const std::string &type_name, const Constraint *constraint)
std::string DebugString() const override
For the time being, Solver is neither MT_SAFE nor MT_HOT.
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)
Constraint * MakeMemberCt(IntExpr *expr, const std::vector< int64_t > &values)
--— Member and related constraints --—
Constraint * MakeGreaterOrEqual(IntExpr *left, IntExpr *right)
left >= right
IntVar * MakeIsLessOrEqualCstVar(IntExpr *var, int64_t value)
status var of (var <= value)
Constraint * MakeIsMemberCt(IntExpr *expr, const std::vector< int64_t > &values, IntVar *boolvar)
boolvar == (expr in set)
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 * 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)
Constraint * MakeEquality(IntExpr *left, IntExpr *right)
left == right
Constraint * MakeLessOrEqual(IntExpr *left, IntExpr *right)
left <= right
Constraint * MakeIsGreaterOrEqualCstCt(IntExpr *var, int64_t value, IntVar *boolvar)
boolvar == (var >= value)
Constraint * MakeBetweenCt(IntExpr *expr, int64_t l, int64_t u)
--— Between and related constraints --—
Demon * MakeConstraintInitialPropagateCallback(Constraint *ct)
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)
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)")
Expression constraints.
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
In SWIG mode, we don't want anything besides these top-level includes.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
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)
--— Vector manipulations --—
int64_t PosIntDivDown(int64_t e, int64_t v)
int64_t PosIntDivUp(int64_t e, int64_t v)
std::optional< int64_t > end