Google OR-Tools: ortools/constraint_solver/range_cst.cc Source File
20#include "absl/strings/str_format.h"
31class RangeEquality : public Constraint {
33 RangeEquality(Solver* const s, IntExpr* const l, IntExpr* const r)
34 : Constraint(s), left_(l), right_(r) {}
36 ~RangeEquality() override {}
39 Demon* const d = solver()->MakeConstraintInitialPropagateCallback(this);
44 void InitialPropagate() override {
45 left_->SetRange(right_->Min(), right_->Max());
46 right_->SetRange(left_->Min(), left_->Max());
49 std::string DebugString() const override {
50 return left_->DebugString() + " == " + right_->DebugString();
53 IntVar* Var() override { return solver()->MakeIsEqualVar(left_, right_); }
55 void Accept(ModelVisitor* const visitor) const override {
71class RangeLessOrEqual : public Constraint {
73 RangeLessOrEqual(Solver* s, IntExpr* l, IntExpr* r);
74 ~RangeLessOrEqual() override {}
76 void InitialPropagate() override;
77 std::string DebugString() const override;
79 return solver()->MakeIsLessOrEqualVar(left_, right_);
81 void Accept(ModelVisitor* const visitor) const override {
95RangeLessOrEqual::RangeLessOrEqual(Solver* const s, IntExpr* const l,
97 : Constraint(s), left_(l), right_(r), demon_(nullptr) {}
99void RangeLessOrEqual::Post() {
100 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
102 right_->WhenRange(demon_);
105void RangeLessOrEqual::InitialPropagate() {
106 left_->SetMax(right_->Max());
107 right_->SetMin(left_->Min());
108 if (left_->Max() <= right_->Min()) {
109 demon_->inhibit(solver());
113std::string RangeLessOrEqual::DebugString() const {
114 return left_->DebugString() + " <= " + right_->DebugString();
122 RangeLess(Solver* s, IntExpr* l, IntExpr* r);
125 void InitialPropagate() override;
126 std::string DebugString() const override;
127 IntVar* Var() override { return solver()->MakeIsLessVar(left_, right_); }
128 void Accept(ModelVisitor* const visitor) const override {
129 visitor->BeginVisitConstraint(ModelVisitor::kLess, this);
130 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
131 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
133 visitor->EndVisitConstraint(ModelVisitor::kLess, this);
142RangeLess::RangeLess(Solver* const s, IntExpr* const l, IntExpr* const r)
143 : Constraint(s), left_(l), right_(r), demon_(nullptr) {}
146 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
148 right_->WhenRange(demon_);
151void RangeLess::InitialPropagate() {
152 if (right_->Max() == kint64min) solver()->Fail();
153 left_->SetMax(right_->Max() - 1);
154 if (left_->Min() == kint64max) solver()->Fail();
155 right_->SetMin(left_->Min() + 1);
156 if (left_->Max() < right_->Min()) {
157 demon_->inhibit(solver());
161std::string RangeLess::DebugString() const {
162 return left_->DebugString() + " < " + right_->DebugString();
170 DiffVar(Solver* s, IntVar* l, IntVar* r);
173 void InitialPropagate() override;
174 std::string DebugString() const override;
175 IntVar* Var() override { return solver()->MakeIsDifferentVar(left_, right_); }
179 void Accept(ModelVisitor* const visitor) const override {
180 visitor->BeginVisitConstraint(ModelVisitor::kNonEqual, this);
181 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
182 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
184 visitor->EndVisitConstraint(ModelVisitor::kNonEqual, this);
192DiffVar::DiffVar(Solver* const s, IntVar* const l, IntVar* const r)
193 : Constraint(s), left_(l), right_(r) {}
198 Demon* const right_demon =
200 left_->WhenBound(left_demon);
201 right_->WhenBound(right_demon);
205void DiffVar::LeftBound() {
206 if (right_->Size() < 0xFFFFFF) {
207 right_->RemoveValue(left_->Min());
209 solver()->AddConstraint(solver()->MakeNonEquality(right_, left_->Min()));
213void DiffVar::RightBound() {
214 if (left_->Size() < 0xFFFFFF) {
215 left_->RemoveValue(right_->Min());
217 solver()->AddConstraint(solver()->MakeNonEquality(left_, right_->Min()));
221void DiffVar::InitialPropagate() {
230std::string DiffVar::DebugString() const {
231 return left_->DebugString() + " != " + right_->DebugString();
241class IsEqualCt : public CastConstraint {
243 IsEqualCt(Solver* const s, IntExpr* const l, IntExpr* const r,
245 : CastConstraint(s, b), left_(l), right_(r), range_demon_(nullptr) {}
250 range_demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
251 left_->WhenRange(range_demon_);
252 right_->WhenRange(range_demon_);
254 solver(), this, &IsEqualCt::PropagateTarget, "PropagateTarget");
255 target_var_->WhenBound(target_demon);
258 void InitialPropagate() override {
259 if (target_var_->Bound()) {
263 if (left_->Min() > right_->Max() || left_->Max() < right_->Min()) {
265 range_demon_->inhibit(solver());
266 } else if (left_->Bound()) {
268 target_var_->SetValue(left_->Min() == right_->Min());
269 } else if (right_->IsVar() && !right_->Var()->Contains(left_->Min())) {
270 range_demon_->inhibit(solver());
273 } else if (right_->Bound() && left_->IsVar() &&
274 !left_->Var()->Contains(right_->Min())) {
275 range_demon_->inhibit(solver());
281 if (target_var_->Min() == 0) {
283 range_demon_->inhibit(solver());
285 right_->Var()->RemoveValue(left_->Min());
288 solver()->MakeNonEquality(right_, left_->Min()));
290 } else if (right_->Bound()) {
291 range_demon_->inhibit(solver());
293 left_->Var()->RemoveValue(right_->Min());
296 solver()->MakeNonEquality(left_, right_->Min()));
300 left_->SetRange(right_->Min(), right_->Max());
301 right_->SetRange(left_->Min(), left_->Max());
305 std::string DebugString() const override {
306 return absl::StrFormat("IsEqualCt(%s, %s, %s)", left_->DebugString(),
307 right_->DebugString(), target_var_->DebugString());
310 void Accept(ModelVisitor* const visitor) const override {
311 visitor->BeginVisitConstraint(ModelVisitor::kIsEqual, this);
312 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
313 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
315 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
317 visitor->EndVisitConstraint(ModelVisitor::kIsEqual, this);
328class IsDifferentCt : public CastConstraint {
330 IsDifferentCt(Solver* const s, IntExpr* const l, IntExpr* const r,
332 : CastConstraint(s, b), left_(l), right_(r), range_demon_(nullptr) {}
334 ~IsDifferentCt() override {}
337 range_demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
338 left_->WhenRange(range_demon_);
339 right_->WhenRange(range_demon_);
341 solver(), this, &IsDifferentCt::PropagateTarget, "PropagateTarget");
342 target_var_->WhenBound(target_demon);
345 void InitialPropagate() override {
346 if (target_var_->Bound()) {
350 if (left_->Min() > right_->Max() || left_->Max() < right_->Min()) {
352 range_demon_->inhibit(solver());
353 } else if (left_->Bound()) {
355 target_var_->SetValue(left_->Min() != right_->Min());
356 } else if (right_->IsVar() && !right_->Var()->Contains(left_->Min())) {
357 range_demon_->inhibit(solver());
360 } else if (right_->Bound() && left_->IsVar() &&
361 !left_->Var()->Contains(right_->Min())) {
362 range_demon_->inhibit(solver());
368 if (target_var_->Min() == 0) {
369 left_->SetRange(right_->Min(), right_->Max());
370 right_->SetRange(left_->Min(), left_->Max());
373 range_demon_->inhibit(solver());
375 solver()->MakeNonEquality(right_, left_->Min()));
376 } else if (right_->Bound()) {
377 range_demon_->inhibit(solver());
379 solver()->MakeNonEquality(left_, right_->Min()));
384 std::string DebugString() const override {
385 return absl::StrFormat("IsDifferentCt(%s, %s, %s)", left_->DebugString(),
386 right_->DebugString(), target_var_->DebugString());
389 void Accept(ModelVisitor* const visitor) const override {
390 visitor->BeginVisitConstraint(ModelVisitor::kIsDifferent, this);
391 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
392 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
394 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
396 visitor->EndVisitConstraint(ModelVisitor::kIsDifferent, this);
405class IsLessOrEqualCt : public CastConstraint {
407 IsLessOrEqualCt(Solver* const s, IntExpr* const l, IntExpr* const r,
409 : CastConstraint(s, b), left_(l), right_(r), demon_(nullptr) {}
411 ~IsLessOrEqualCt() override {}
414 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
416 right_->WhenRange(demon_);
417 target_var_->WhenBound(demon_);
420 void InitialPropagate() override {
421 if (target_var_->Bound()) {
422 if (target_var_->Min() == 0) {
423 right_->SetMax(left_->Max() - 1);
424 left_->SetMin(right_->Min() + 1);
426 right_->SetMin(left_->Min());
427 left_->SetMax(right_->Max());
429 } else if (right_->Min() >= left_->Max()) {
430 demon_->inhibit(solver());
432 } else if (right_->Max() < left_->Min()) {
433 demon_->inhibit(solver());
438 std::string DebugString() const override {
439 return absl::StrFormat("IsLessOrEqualCt(%s, %s, %s)", left_->DebugString(),
440 right_->DebugString(), target_var_->DebugString());
443 void Accept(ModelVisitor* const visitor) const override {
444 visitor->BeginVisitConstraint(ModelVisitor::kIsLessOrEqual, this);
445 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
446 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
448 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
450 visitor->EndVisitConstraint(ModelVisitor::kIsLessOrEqual, this);
459class IsLessCt : public CastConstraint {
461 IsLessCt(Solver* const s, IntExpr* const l, IntExpr* const r, IntVar* const b)
462 : CastConstraint(s, b), left_(l), right_(r), demon_(nullptr) {}
467 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
469 right_->WhenRange(demon_);
470 target_var_->WhenBound(demon_);
473 void InitialPropagate() override {
474 if (target_var_->Bound()) {
475 if (target_var_->Min() == 0) {
476 right_->SetMax(left_->Max());
477 left_->SetMin(right_->Min());
479 right_->SetMin(left_->Min() + 1);
480 left_->SetMax(right_->Max() - 1);
482 } else if (right_->Min() > left_->Max()) {
483 demon_->inhibit(solver());
485 } else if (right_->Max() <= left_->Min()) {
486 demon_->inhibit(solver());
491 std::string DebugString() const override {
492 return absl::StrFormat("IsLessCt(%s, %s, %s)", left_->DebugString(),
493 right_->DebugString(), target_var_->DebugString());
496 void Accept(ModelVisitor* const visitor) const override {
497 visitor->BeginVisitConstraint(ModelVisitor::kIsLess, this);
498 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
499 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
501 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
503 visitor->EndVisitConstraint(ModelVisitor::kIsLess, this);
513Constraint* Solver::MakeEquality(IntExpr* const l, IntExpr* const r) {
514 CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
515 CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
516 CHECK_EQ(this, l->solver());
517 CHECK_EQ(this, r->solver());
521 return MakeEquality(l, r->Min());
523 return RevAlloc(new RangeEquality(this, l, r));
527Constraint* Solver::MakeLessOrEqual(IntExpr* const l, IntExpr* const r) {
528 CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
529 CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
530 CHECK_EQ(this, l->solver());
531 CHECK_EQ(this, r->solver());
535 return MakeGreaterOrEqual(r, l->Min());
537 return MakeLessOrEqual(l, r->Min());
539 return RevAlloc(new RangeLessOrEqual(this, l, r));
543Constraint* Solver::MakeGreaterOrEqual(IntExpr* const l, IntExpr* const r) {
548 CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
549 CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
550 CHECK_EQ(this, l->solver());
552 if (l->Bound()) {
554 } else if (r->Bound()) {
555 return MakeLess(l, r->Min());
557 return RevAlloc(new RangeLess(this, l, r));
561Constraint* Solver::MakeGreater(IntExpr* const l, IntExpr* const r) {
566 CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
567 CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
568 CHECK_EQ(this, l->solver());
570 if (l->Bound()) {
572 } else if (r->Bound()) {
573 return MakeNonEquality(l, r->Min());
575 return RevAlloc(new DiffVar(this, l->Var(), r->Var()));
578IntVar* Solver::MakeIsEqualVar(IntExpr* const v1, IntExpr* const v2) {
584 return MakeIsEqualCstVar(v1, v2->Min());
586 IntExpr* cache = model_cache_->FindExprExprExpression(
587 v1, v2, ModelCache::EXPR_EXPR_IS_EQUAL);
589 cache = model_cache_->FindExprExprExpression(
590 v2, v1, ModelCache::EXPR_EXPR_IS_EQUAL);
595 IntVar* boolvar = nullptr;
596 IntExpr* reverse_cache = model_cache_->FindExprExprExpression(
597 v1, v2, ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
598 if (reverse_cache == nullptr) {
599 reverse_cache = model_cache_->FindExprExprExpression(
600 v2, v1, ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
602 if (reverse_cache != nullptr) {
603 boolvar = MakeDifference(1, reverse_cache)->Var();
605 std::string name1 = v1->name();
607 name1 = v1->DebugString();
609 std::string name2 = v2->name();
611 name2 = v2->DebugString();
614 MakeBoolVar(absl::StrFormat("IsEqualVar(%s, %s)", name1, name2));
615 AddConstraint(MakeIsEqualCt(v1, v2, boolvar));
616 model_cache_->InsertExprExprExpression(boolvar, v1, v2,
617 ModelCache::EXPR_EXPR_IS_EQUAL);
623Constraint* Solver::MakeIsEqualCt(IntExpr* const v1, IntExpr* const v2,
626 CHECK_EQ(this, v2->solver());
627 if (v1->Bound()) {
630 return MakeIsEqualCstCt(v1, v2->Min(), b);
634 return MakeNonEquality(v1, v2);
636 return MakeEquality(v1, v2);
639 return RevAlloc(new IsEqualCt(this, v1, v2, b));
642IntVar* Solver::MakeIsDifferentVar(IntExpr* const v1, IntExpr* const v2) {
648 return MakeIsDifferentCstVar(v1, v2->Min());
650 IntExpr* cache = model_cache_->FindExprExprExpression(
651 v1, v2, ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
653 cache = model_cache_->FindExprExprExpression(
654 v2, v1, ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
659 IntVar* boolvar = nullptr;
660 IntExpr* reverse_cache = model_cache_->FindExprExprExpression(
661 v1, v2, ModelCache::EXPR_EXPR_IS_EQUAL);
662 if (reverse_cache == nullptr) {
663 reverse_cache = model_cache_->FindExprExprExpression(
664 v2, v1, ModelCache::EXPR_EXPR_IS_EQUAL);
666 if (reverse_cache != nullptr) {
667 boolvar = MakeDifference(1, reverse_cache)->Var();
669 std::string name1 = v1->name();
671 name1 = v1->DebugString();
673 std::string name2 = v2->name();
675 name2 = v2->DebugString();
678 MakeBoolVar(absl::StrFormat("IsDifferentVar(%s, %s)", name1, name2));
679 AddConstraint(MakeIsDifferentCt(v1, v2, boolvar));
681 model_cache_->InsertExprExprExpression(boolvar, v1, v2,
682 ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
687Constraint* Solver::MakeIsDifferentCt(IntExpr* const v1, IntExpr* const v2,
690 CHECK_EQ(this, v2->solver());
691 if (v1->Bound()) {
694 return MakeIsDifferentCstCt(v1, v2->Min(), b);
696 return RevAlloc(new IsDifferentCt(this, v1, v2, b));
699IntVar* Solver::MakeIsLessOrEqualVar(IntExpr* const left,
702 CHECK_EQ(this, right->solver());
703 if (left->Bound()) {
705 } else if (right->Bound()) {
706 return MakeIsLessOrEqualCstVar(left, right->Min());
708 IntExpr* const cache = model_cache_->FindExprExprExpression(
709 left, right, ModelCache::EXPR_EXPR_IS_LESS_OR_EQUAL);
713 std::string name1 = left->name();
715 name1 = left->DebugString();
717 std::string name2 = right->name();
719 name2 = right->DebugString();
722 MakeBoolVar(absl::StrFormat("IsLessOrEqual(%s, %s)", name1, name2));
724 AddConstraint(RevAlloc(new IsLessOrEqualCt(this, left, right, boolvar)));
725 model_cache_->InsertExprExprExpression(
726 boolvar, left, right, ModelCache::EXPR_EXPR_IS_LESS_OR_EQUAL);
731Constraint* Solver::MakeIsLessOrEqualCt(IntExpr* const left,
734 CHECK_EQ(this, right->solver());
735 if (left->Bound()) {
737 } else if (right->Bound()) {
738 return MakeIsLessOrEqualCstCt(left, right->Min(), b);
740 return RevAlloc(new IsLessOrEqualCt(this, left, right, b));
743IntVar* Solver::MakeIsLessVar(IntExpr* const left, IntExpr* const right) {
748 } else if (right->Bound()) {
749 return MakeIsLessCstVar(left, right->Min());
751 IntExpr* const cache = model_cache_->FindExprExprExpression(
752 left, right, ModelCache::EXPR_EXPR_IS_LESS);
756 std::string name1 = left->name();
758 name1 = left->DebugString();
760 std::string name2 = right->name();
762 name2 = right->DebugString();
765 MakeBoolVar(absl::StrFormat("IsLessOrEqual(%s, %s)", name1, name2));
767 AddConstraint(RevAlloc(new IsLessCt(this, left, right, boolvar)));
768 model_cache_->InsertExprExprExpression(boolvar, left, right,
769 ModelCache::EXPR_EXPR_IS_LESS);
774Constraint* Solver::MakeIsLessCt(IntExpr* const left, IntExpr* const right,
777 CHECK_EQ(this, right->solver());
778 if (left->Bound()) {
780 } else if (right->Bound()) {
781 return MakeIsLessCstCt(left, right->Min(), b);
783 return RevAlloc(new IsLessCt(this, left, right, b));
786IntVar* Solver::MakeIsGreaterOrEqualVar(IntExpr* const left,
std::string DebugString() const override
virtual bool Bound() const
Returns true if the min and the max of the expression are equal.
virtual int64_t Min() const =0
virtual IntVar * Var()=0
Creates a variable from the expression.
static const char kLessOrEqual[]
static const char kRightArgument[]
static const char kEquality[]
static const char kLeftArgument[]
Constraint * MakeIsLessOrEqualCt(IntExpr *left, IntExpr *right, IntVar *b)
b == (left <= right)
Definition range_cst.cc:735
Constraint * MakeIsEqualCstCt(IntExpr *var, int64_t value, IntVar *boolvar)
boolvar == (var == value)
Constraint * MakeIsGreaterCt(IntExpr *left, IntExpr *right, IntVar *b)
b == (left > right)
Definition range_cst.cc:805
Constraint * MakeIsGreaterOrEqualCt(IntExpr *left, IntExpr *right, IntVar *b)
b == (left >= right)
Definition range_cst.cc:795
IntVar * MakeIsEqualCstVar(IntExpr *var, int64_t value)
status var of (var == value)
IntVar * MakeIsGreaterVar(IntExpr *left, IntExpr *right)
status var of (left > right)
Definition range_cst.cc:801
Constraint * MakeIsGreaterCstCt(IntExpr *v, int64_t c, IntVar *b)
b == (v > c)
IntVar * MakeIsGreaterCstVar(IntExpr *var, int64_t value)
status var of (var > value)
IntVar * MakeIsDifferentCstVar(IntExpr *var, int64_t value)
status var of (var != value)
IntVar * MakeIsGreaterOrEqualCstVar(IntExpr *var, int64_t value)
status var of (var >= value)
Constraint * MakeIsLessCt(IntExpr *left, IntExpr *right, IntVar *b)
b == (left < right)
Definition range_cst.cc:778
Constraint * MakeTrueConstraint()
This constraint always succeeds.
Constraint * MakeIsGreaterOrEqualCstCt(IntExpr *var, int64_t value, IntVar *boolvar)
boolvar == (var >= value)
Constraint * MakeIsDifferentCstCt(IntExpr *var, int64_t value, IntVar *boolvar)
boolvar == (var != value)
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
std::string DebugString() const
static const int64_t kint64max
static const int64_t kint64min