Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
range_cst.cc
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14//
15// Range constraints
16
17#include <stddef.h>
18
19#include <string>
20
21#include "absl/strings/str_format.h"
25
26namespace operations_research {
27
28//-----------------------------------------------------------------------------
29// RangeEquality
30
31namespace {
32class RangeEquality : public Constraint {
33 public:
34 RangeEquality(Solver* const s, IntExpr* const l, IntExpr* const r)
35 : Constraint(s), left_(l), right_(r) {}
36
37 ~RangeEquality() override {}
38
39 void Post() override {
40 Demon* const d = solver()->MakeConstraintInitialPropagateCallback(this);
41 left_->WhenRange(d);
42 right_->WhenRange(d);
43 }
44
45 void InitialPropagate() override {
46 left_->SetRange(right_->Min(), right_->Max());
47 right_->SetRange(left_->Min(), left_->Max());
48 }
49
50 std::string DebugString() const override {
51 return left_->DebugString() + " == " + right_->DebugString();
52 }
53
54 IntVar* Var() override { return solver()->MakeIsEqualVar(left_, right_); }
55
56 void Accept(ModelVisitor* const visitor) const override {
57 visitor->BeginVisitConstraint(ModelVisitor::kEquality, this);
58 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
59 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
60 right_);
61 visitor->EndVisitConstraint(ModelVisitor::kEquality, this);
62 }
63
64 private:
65 IntExpr* const left_;
66 IntExpr* const right_;
67};
68
69//-----------------------------------------------------------------------------
70// RangeLessOrEqual
71
72class RangeLessOrEqual : public Constraint {
73 public:
74 RangeLessOrEqual(Solver* s, IntExpr* l, IntExpr* r);
75 ~RangeLessOrEqual() override {}
76 void Post() override;
77 void InitialPropagate() override;
78 std::string DebugString() const override;
79 IntVar* Var() override {
80 return solver()->MakeIsLessOrEqualVar(left_, right_);
81 }
82 void Accept(ModelVisitor* const visitor) const override {
83 visitor->BeginVisitConstraint(ModelVisitor::kLessOrEqual, this);
84 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
85 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
86 right_);
87 visitor->EndVisitConstraint(ModelVisitor::kLessOrEqual, this);
88 }
89
90 private:
91 IntExpr* const left_;
92 IntExpr* const right_;
93 Demon* demon_;
94};
95
96RangeLessOrEqual::RangeLessOrEqual(Solver* const s, IntExpr* const l,
97 IntExpr* const r)
98 : Constraint(s), left_(l), right_(r), demon_(nullptr) {}
99
100void RangeLessOrEqual::Post() {
101 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
102 left_->WhenRange(demon_);
103 right_->WhenRange(demon_);
104}
105
106void RangeLessOrEqual::InitialPropagate() {
107 left_->SetMax(right_->Max());
108 right_->SetMin(left_->Min());
109 if (left_->Max() <= right_->Min()) {
110 demon_->inhibit(solver());
111 }
112}
113
114std::string RangeLessOrEqual::DebugString() const {
115 return left_->DebugString() + " <= " + right_->DebugString();
116}
117
118//-----------------------------------------------------------------------------
119// RangeLess
120
121class RangeLess : public Constraint {
122 public:
123 RangeLess(Solver* s, IntExpr* l, IntExpr* r);
124 ~RangeLess() override {}
125 void Post() override;
126 void InitialPropagate() override;
127 std::string DebugString() const override;
128 IntVar* Var() override { return solver()->MakeIsLessVar(left_, right_); }
129 void Accept(ModelVisitor* const visitor) const override {
130 visitor->BeginVisitConstraint(ModelVisitor::kLess, this);
131 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
132 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
133 right_);
134 visitor->EndVisitConstraint(ModelVisitor::kLess, this);
135 }
136
137 private:
138 IntExpr* const left_;
139 IntExpr* const right_;
140 Demon* demon_;
141};
142
143RangeLess::RangeLess(Solver* const s, IntExpr* const l, IntExpr* const r)
144 : Constraint(s), left_(l), right_(r), demon_(nullptr) {}
145
146void RangeLess::Post() {
147 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
148 left_->WhenRange(demon_);
149 right_->WhenRange(demon_);
150}
151
152void RangeLess::InitialPropagate() {
153 if (right_->Max() == kint64min) solver()->Fail();
154 left_->SetMax(right_->Max() - 1);
155 if (left_->Min() == kint64max) solver()->Fail();
156 right_->SetMin(left_->Min() + 1);
157 if (left_->Max() < right_->Min()) {
158 demon_->inhibit(solver());
159 }
160}
161
162std::string RangeLess::DebugString() const {
163 return left_->DebugString() + " < " + right_->DebugString();
164}
165
166//-----------------------------------------------------------------------------
167// DiffVar
168
169class DiffVar : public Constraint {
170 public:
171 DiffVar(Solver* s, IntVar* l, IntVar* r);
172 ~DiffVar() override {}
173 void Post() override;
174 void InitialPropagate() override;
175 std::string DebugString() const override;
176 IntVar* Var() override { return solver()->MakeIsDifferentVar(left_, right_); }
177 void LeftBound();
178 void RightBound();
179
180 void Accept(ModelVisitor* const visitor) const override {
181 visitor->BeginVisitConstraint(ModelVisitor::kNonEqual, this);
182 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
183 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
184 right_);
185 visitor->EndVisitConstraint(ModelVisitor::kNonEqual, this);
186 }
187
188 private:
189 IntVar* const left_;
190 IntVar* const right_;
191};
192
193DiffVar::DiffVar(Solver* const s, IntVar* const l, IntVar* const r)
194 : Constraint(s), left_(l), right_(r) {}
195
196void DiffVar::Post() {
197 Demon* const left_demon =
198 MakeConstraintDemon0(solver(), this, &DiffVar::LeftBound, "LeftBound");
199 Demon* const right_demon =
200 MakeConstraintDemon0(solver(), this, &DiffVar::RightBound, "RightBound");
201 left_->WhenBound(left_demon);
202 right_->WhenBound(right_demon);
203 // TODO(user) : improve me, separated demons, actually to test
204}
205
206void DiffVar::LeftBound() {
207 if (right_->Size() < 0xFFFFFF) {
208 right_->RemoveValue(left_->Min()); // we use min instead of value
209 } else {
210 solver()->AddConstraint(solver()->MakeNonEquality(right_, left_->Min()));
211 }
212}
213
214void DiffVar::RightBound() {
215 if (left_->Size() < 0xFFFFFF) {
216 left_->RemoveValue(right_->Min()); // see above
217 } else {
218 solver()->AddConstraint(solver()->MakeNonEquality(left_, right_->Min()));
219 }
220}
221
222void DiffVar::InitialPropagate() {
223 if (left_->Bound()) {
224 LeftBound();
225 }
226 if (right_->Bound()) {
227 RightBound();
228 }
229}
230
231std::string DiffVar::DebugString() const {
232 return left_->DebugString() + " != " + right_->DebugString();
233}
234
235// --------------------- Reified API -------------------
236// A reified API transforms a constraint into a status variables.
237// For example x == y is transformed into IsEqual(x, y, b) where
238// b is a boolean variable which is true if and only if x is equal to b.
239
240// IsEqualCt
241
242class IsEqualCt : public CastConstraint {
243 public:
244 IsEqualCt(Solver* const s, IntExpr* const l, IntExpr* const r,
245 IntVar* const b)
246 : CastConstraint(s, b), left_(l), right_(r), range_demon_(nullptr) {}
247
248 ~IsEqualCt() override {}
249
250 void Post() override {
251 range_demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
252 left_->WhenRange(range_demon_);
253 right_->WhenRange(range_demon_);
254 Demon* const target_demon = MakeConstraintDemon0(
255 solver(), this, &IsEqualCt::PropagateTarget, "PropagateTarget");
256 target_var_->WhenBound(target_demon);
257 }
258
259 void InitialPropagate() override {
260 if (target_var_->Bound()) {
261 PropagateTarget();
262 return;
263 }
264 if (left_->Min() > right_->Max() || left_->Max() < right_->Min()) {
265 target_var_->SetValue(0);
266 range_demon_->inhibit(solver());
267 } else if (left_->Bound()) {
268 if (right_->Bound()) {
269 target_var_->SetValue(left_->Min() == right_->Min());
270 } else if (right_->IsVar() && !right_->Var()->Contains(left_->Min())) {
271 range_demon_->inhibit(solver());
272 target_var_->SetValue(0);
273 }
274 } else if (right_->Bound() && left_->IsVar() &&
275 !left_->Var()->Contains(right_->Min())) {
276 range_demon_->inhibit(solver());
277 target_var_->SetValue(0);
278 }
279 }
280
281 void PropagateTarget() {
282 if (target_var_->Min() == 0) {
283 if (left_->Bound()) {
284 range_demon_->inhibit(solver());
285 if (right_->IsVar()) {
286 right_->Var()->RemoveValue(left_->Min());
287 } else {
288 solver()->AddConstraint(
289 solver()->MakeNonEquality(right_, left_->Min()));
290 }
291 } else if (right_->Bound()) {
292 range_demon_->inhibit(solver());
293 if (left_->IsVar()) {
294 left_->Var()->RemoveValue(right_->Min());
295 } else {
296 solver()->AddConstraint(
297 solver()->MakeNonEquality(left_, right_->Min()));
298 }
299 }
300 } else { // Var is true.
301 left_->SetRange(right_->Min(), right_->Max());
302 right_->SetRange(left_->Min(), left_->Max());
303 }
304 }
305
306 std::string DebugString() const override {
307 return absl::StrFormat("IsEqualCt(%s, %s, %s)", left_->DebugString(),
308 right_->DebugString(), target_var_->DebugString());
309 }
310
311 void Accept(ModelVisitor* const visitor) const override {
312 visitor->BeginVisitConstraint(ModelVisitor::kIsEqual, this);
313 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
314 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
315 right_);
316 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
317 target_var_);
318 visitor->EndVisitConstraint(ModelVisitor::kIsEqual, this);
319 }
320
321 private:
322 IntExpr* const left_;
323 IntExpr* const right_;
324 Demon* range_demon_;
325};
326
327// IsDifferentCt
328
329class IsDifferentCt : public CastConstraint {
330 public:
331 IsDifferentCt(Solver* const s, IntExpr* const l, IntExpr* const r,
332 IntVar* const b)
333 : CastConstraint(s, b), left_(l), right_(r), range_demon_(nullptr) {}
334
335 ~IsDifferentCt() override {}
336
337 void Post() override {
338 range_demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
339 left_->WhenRange(range_demon_);
340 right_->WhenRange(range_demon_);
341 Demon* const target_demon = MakeConstraintDemon0(
342 solver(), this, &IsDifferentCt::PropagateTarget, "PropagateTarget");
343 target_var_->WhenBound(target_demon);
344 }
345
346 void InitialPropagate() override {
347 if (target_var_->Bound()) {
348 PropagateTarget();
349 return;
350 }
351 if (left_->Min() > right_->Max() || left_->Max() < right_->Min()) {
352 target_var_->SetValue(1);
353 range_demon_->inhibit(solver());
354 } else if (left_->Bound()) {
355 if (right_->Bound()) {
356 target_var_->SetValue(left_->Min() != right_->Min());
357 } else if (right_->IsVar() && !right_->Var()->Contains(left_->Min())) {
358 range_demon_->inhibit(solver());
359 target_var_->SetValue(1);
360 }
361 } else if (right_->Bound() && left_->IsVar() &&
362 !left_->Var()->Contains(right_->Min())) {
363 range_demon_->inhibit(solver());
364 target_var_->SetValue(1);
365 }
366 }
367
368 void PropagateTarget() {
369 if (target_var_->Min() == 0) {
370 left_->SetRange(right_->Min(), right_->Max());
371 right_->SetRange(left_->Min(), left_->Max());
372 } else { // Var is true.
373 if (left_->Bound()) {
374 range_demon_->inhibit(solver());
375 solver()->AddConstraint(
376 solver()->MakeNonEquality(right_, left_->Min()));
377 } else if (right_->Bound()) {
378 range_demon_->inhibit(solver());
379 solver()->AddConstraint(
380 solver()->MakeNonEquality(left_, right_->Min()));
381 }
382 }
383 }
384
385 std::string DebugString() const override {
386 return absl::StrFormat("IsDifferentCt(%s, %s, %s)", left_->DebugString(),
387 right_->DebugString(), target_var_->DebugString());
388 }
389
390 void Accept(ModelVisitor* const visitor) const override {
391 visitor->BeginVisitConstraint(ModelVisitor::kIsDifferent, this);
392 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
393 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
394 right_);
395 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
396 target_var_);
397 visitor->EndVisitConstraint(ModelVisitor::kIsDifferent, this);
398 }
399
400 private:
401 IntExpr* const left_;
402 IntExpr* const right_;
403 Demon* range_demon_;
404};
405
406class IsLessOrEqualCt : public CastConstraint {
407 public:
408 IsLessOrEqualCt(Solver* const s, IntExpr* const l, IntExpr* const r,
409 IntVar* const b)
410 : CastConstraint(s, b), left_(l), right_(r), demon_(nullptr) {}
411
412 ~IsLessOrEqualCt() override {}
413
414 void Post() override {
415 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
416 left_->WhenRange(demon_);
417 right_->WhenRange(demon_);
418 target_var_->WhenBound(demon_);
419 }
420
421 void InitialPropagate() override {
422 if (target_var_->Bound()) {
423 if (target_var_->Min() == 0) {
424 right_->SetMax(left_->Max() - 1);
425 left_->SetMin(right_->Min() + 1);
426 } else { // Var is true.
427 right_->SetMin(left_->Min());
428 left_->SetMax(right_->Max());
429 }
430 } else if (right_->Min() >= left_->Max()) {
431 demon_->inhibit(solver());
432 target_var_->SetValue(1);
433 } else if (right_->Max() < left_->Min()) {
434 demon_->inhibit(solver());
435 target_var_->SetValue(0);
436 }
437 }
438
439 std::string DebugString() const override {
440 return absl::StrFormat("IsLessOrEqualCt(%s, %s, %s)", left_->DebugString(),
441 right_->DebugString(), target_var_->DebugString());
442 }
443
444 void Accept(ModelVisitor* const visitor) const override {
445 visitor->BeginVisitConstraint(ModelVisitor::kIsLessOrEqual, this);
446 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
447 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
448 right_);
449 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
450 target_var_);
451 visitor->EndVisitConstraint(ModelVisitor::kIsLessOrEqual, this);
452 }
453
454 private:
455 IntExpr* const left_;
456 IntExpr* const right_;
457 Demon* demon_;
458};
459
460class IsLessCt : public CastConstraint {
461 public:
462 IsLessCt(Solver* const s, IntExpr* const l, IntExpr* const r, IntVar* const b)
463 : CastConstraint(s, b), left_(l), right_(r), demon_(nullptr) {}
464
465 ~IsLessCt() override {}
466
467 void Post() override {
468 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
469 left_->WhenRange(demon_);
470 right_->WhenRange(demon_);
471 target_var_->WhenBound(demon_);
472 }
473
474 void InitialPropagate() override {
475 if (target_var_->Bound()) {
476 if (target_var_->Min() == 0) {
477 right_->SetMax(left_->Max());
478 left_->SetMin(right_->Min());
479 } else { // Var is true.
480 right_->SetMin(left_->Min() + 1);
481 left_->SetMax(right_->Max() - 1);
482 }
483 } else if (right_->Min() > left_->Max()) {
484 demon_->inhibit(solver());
485 target_var_->SetValue(1);
486 } else if (right_->Max() <= left_->Min()) {
487 demon_->inhibit(solver());
488 target_var_->SetValue(0);
489 }
490 }
491
492 std::string DebugString() const override {
493 return absl::StrFormat("IsLessCt(%s, %s, %s)", left_->DebugString(),
494 right_->DebugString(), target_var_->DebugString());
495 }
496
497 void Accept(ModelVisitor* const visitor) const override {
498 visitor->BeginVisitConstraint(ModelVisitor::kIsLess, this);
499 visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
500 visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
501 right_);
502 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
503 target_var_);
504 visitor->EndVisitConstraint(ModelVisitor::kIsLess, this);
505 }
506
507 private:
508 IntExpr* const left_;
509 IntExpr* const right_;
510 Demon* demon_;
511};
512} // namespace
513
514Constraint* Solver::MakeEquality(IntExpr* const l, IntExpr* const r) {
515 CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
516 CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
517 CHECK_EQ(this, l->solver());
518 CHECK_EQ(this, r->solver());
519 if (l->Bound()) {
520 return MakeEquality(r, l->Min());
521 } else if (r->Bound()) {
522 return MakeEquality(l, r->Min());
523 } else {
524 return RevAlloc(new RangeEquality(this, l, r));
525 }
526}
527
528Constraint* Solver::MakeLessOrEqual(IntExpr* const l, IntExpr* const r) {
529 CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
530 CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
531 CHECK_EQ(this, l->solver());
532 CHECK_EQ(this, r->solver());
533 if (l == r) {
534 return MakeTrueConstraint();
535 } else if (l->Bound()) {
536 return MakeGreaterOrEqual(r, l->Min());
537 } else if (r->Bound()) {
538 return MakeLessOrEqual(l, r->Min());
539 } else {
540 return RevAlloc(new RangeLessOrEqual(this, l, r));
541 }
542}
543
544Constraint* Solver::MakeGreaterOrEqual(IntExpr* const l, IntExpr* const r) {
545 return MakeLessOrEqual(r, l);
546}
547
548Constraint* Solver::MakeLess(IntExpr* const l, IntExpr* const r) {
549 CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
550 CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
551 CHECK_EQ(this, l->solver());
552 CHECK_EQ(this, r->solver());
553 if (l->Bound()) {
554 return MakeGreater(r, l->Min());
555 } else if (r->Bound()) {
556 return MakeLess(l, r->Min());
557 } else {
558 return RevAlloc(new RangeLess(this, l, r));
559 }
560}
561
562Constraint* Solver::MakeGreater(IntExpr* const l, IntExpr* const r) {
563 return MakeLess(r, l);
564}
565
566Constraint* Solver::MakeNonEquality(IntExpr* const l, IntExpr* const r) {
567 CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
568 CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
569 CHECK_EQ(this, l->solver());
570 CHECK_EQ(this, r->solver());
571 if (l->Bound()) {
572 return MakeNonEquality(r, l->Min());
573 } else if (r->Bound()) {
574 return MakeNonEquality(l, r->Min());
575 }
576 return RevAlloc(new DiffVar(this, l->Var(), r->Var()));
577}
578
579IntVar* Solver::MakeIsEqualVar(IntExpr* const v1, IntExpr* const v2) {
580 CHECK_EQ(this, v1->solver());
581 CHECK_EQ(this, v2->solver());
582 if (v1->Bound()) {
583 return MakeIsEqualCstVar(v2, v1->Min());
584 } else if (v2->Bound()) {
585 return MakeIsEqualCstVar(v1, v2->Min());
586 }
587 IntExpr* cache = model_cache_->FindExprExprExpression(
588 v1, v2, ModelCache::EXPR_EXPR_IS_EQUAL);
589 if (cache == nullptr) {
590 cache = model_cache_->FindExprExprExpression(
591 v2, v1, ModelCache::EXPR_EXPR_IS_EQUAL);
592 }
593 if (cache != nullptr) {
594 return cache->Var();
595 } else {
596 IntVar* boolvar = nullptr;
597 IntExpr* reverse_cache = model_cache_->FindExprExprExpression(
598 v1, v2, ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
599 if (reverse_cache == nullptr) {
600 reverse_cache = model_cache_->FindExprExprExpression(
601 v2, v1, ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
602 }
603 if (reverse_cache != nullptr) {
604 boolvar = MakeDifference(1, reverse_cache)->Var();
605 } else {
606 std::string name1 = v1->name();
607 if (name1.empty()) {
608 name1 = v1->DebugString();
609 }
610 std::string name2 = v2->name();
611 if (name2.empty()) {
612 name2 = v2->DebugString();
613 }
614 boolvar =
615 MakeBoolVar(absl::StrFormat("IsEqualVar(%s, %s)", name1, name2));
616 AddConstraint(MakeIsEqualCt(v1, v2, boolvar));
617 model_cache_->InsertExprExprExpression(boolvar, v1, v2,
618 ModelCache::EXPR_EXPR_IS_EQUAL);
619 }
620 return boolvar;
621 }
622}
623
624Constraint* Solver::MakeIsEqualCt(IntExpr* const v1, IntExpr* const v2,
625 IntVar* b) {
626 CHECK_EQ(this, v1->solver());
627 CHECK_EQ(this, v2->solver());
628 if (v1->Bound()) {
629 return MakeIsEqualCstCt(v2, v1->Min(), b);
630 } else if (v2->Bound()) {
631 return MakeIsEqualCstCt(v1, v2->Min(), b);
632 }
633 if (b->Bound()) {
634 if (b->Min() == 0) {
635 return MakeNonEquality(v1, v2);
636 } else {
637 return MakeEquality(v1, v2);
638 }
639 }
640 return RevAlloc(new IsEqualCt(this, v1, v2, b));
641}
642
643IntVar* Solver::MakeIsDifferentVar(IntExpr* const v1, IntExpr* const v2) {
644 CHECK_EQ(this, v1->solver());
645 CHECK_EQ(this, v2->solver());
646 if (v1->Bound()) {
647 return MakeIsDifferentCstVar(v2, v1->Min());
648 } else if (v2->Bound()) {
649 return MakeIsDifferentCstVar(v1, v2->Min());
650 }
651 IntExpr* cache = model_cache_->FindExprExprExpression(
652 v1, v2, ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
653 if (cache == nullptr) {
654 cache = model_cache_->FindExprExprExpression(
655 v2, v1, ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
656 }
657 if (cache != nullptr) {
658 return cache->Var();
659 } else {
660 IntVar* boolvar = nullptr;
661 IntExpr* reverse_cache = model_cache_->FindExprExprExpression(
662 v1, v2, ModelCache::EXPR_EXPR_IS_EQUAL);
663 if (reverse_cache == nullptr) {
664 reverse_cache = model_cache_->FindExprExprExpression(
665 v2, v1, ModelCache::EXPR_EXPR_IS_EQUAL);
666 }
667 if (reverse_cache != nullptr) {
668 boolvar = MakeDifference(1, reverse_cache)->Var();
669 } else {
670 std::string name1 = v1->name();
671 if (name1.empty()) {
672 name1 = v1->DebugString();
673 }
674 std::string name2 = v2->name();
675 if (name2.empty()) {
676 name2 = v2->DebugString();
677 }
678 boolvar =
679 MakeBoolVar(absl::StrFormat("IsDifferentVar(%s, %s)", name1, name2));
680 AddConstraint(MakeIsDifferentCt(v1, v2, boolvar));
681 }
682 model_cache_->InsertExprExprExpression(boolvar, v1, v2,
683 ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
684 return boolvar;
685 }
686}
687
688Constraint* Solver::MakeIsDifferentCt(IntExpr* const v1, IntExpr* const v2,
689 IntVar* b) {
690 CHECK_EQ(this, v1->solver());
691 CHECK_EQ(this, v2->solver());
692 if (v1->Bound()) {
693 return MakeIsDifferentCstCt(v2, v1->Min(), b);
694 } else if (v2->Bound()) {
695 return MakeIsDifferentCstCt(v1, v2->Min(), b);
696 }
697 return RevAlloc(new IsDifferentCt(this, v1, v2, b));
698}
699
700IntVar* Solver::MakeIsLessOrEqualVar(IntExpr* const left,
701 IntExpr* const right) {
702 CHECK_EQ(this, left->solver());
703 CHECK_EQ(this, right->solver());
704 if (left->Bound()) {
705 return MakeIsGreaterOrEqualCstVar(right, left->Min());
706 } else if (right->Bound()) {
707 return MakeIsLessOrEqualCstVar(left, right->Min());
708 }
709 IntExpr* const cache = model_cache_->FindExprExprExpression(
710 left, right, ModelCache::EXPR_EXPR_IS_LESS_OR_EQUAL);
711 if (cache != nullptr) {
712 return cache->Var();
713 } else {
714 std::string name1 = left->name();
715 if (name1.empty()) {
716 name1 = left->DebugString();
717 }
718 std::string name2 = right->name();
719 if (name2.empty()) {
720 name2 = right->DebugString();
721 }
722 IntVar* const boolvar =
723 MakeBoolVar(absl::StrFormat("IsLessOrEqual(%s, %s)", name1, name2));
724
725 AddConstraint(RevAlloc(new IsLessOrEqualCt(this, left, right, boolvar)));
726 model_cache_->InsertExprExprExpression(
727 boolvar, left, right, ModelCache::EXPR_EXPR_IS_LESS_OR_EQUAL);
728 return boolvar;
729 }
730}
731
732Constraint* Solver::MakeIsLessOrEqualCt(IntExpr* const left,
733 IntExpr* const right, IntVar* const b) {
734 CHECK_EQ(this, left->solver());
735 CHECK_EQ(this, right->solver());
736 if (left->Bound()) {
737 return MakeIsGreaterOrEqualCstCt(right, left->Min(), b);
738 } else if (right->Bound()) {
739 return MakeIsLessOrEqualCstCt(left, right->Min(), b);
740 }
741 return RevAlloc(new IsLessOrEqualCt(this, left, right, b));
742}
743
744IntVar* Solver::MakeIsLessVar(IntExpr* const left, IntExpr* const right) {
745 CHECK_EQ(this, left->solver());
746 CHECK_EQ(this, right->solver());
747 if (left->Bound()) {
748 return MakeIsGreaterCstVar(right, left->Min());
749 } else if (right->Bound()) {
750 return MakeIsLessCstVar(left, right->Min());
751 }
752 IntExpr* const cache = model_cache_->FindExprExprExpression(
753 left, right, ModelCache::EXPR_EXPR_IS_LESS);
754 if (cache != nullptr) {
755 return cache->Var();
756 } else {
757 std::string name1 = left->name();
758 if (name1.empty()) {
759 name1 = left->DebugString();
760 }
761 std::string name2 = right->name();
762 if (name2.empty()) {
763 name2 = right->DebugString();
764 }
765 IntVar* const boolvar =
766 MakeBoolVar(absl::StrFormat("IsLessOrEqual(%s, %s)", name1, name2));
767
768 AddConstraint(RevAlloc(new IsLessCt(this, left, right, boolvar)));
769 model_cache_->InsertExprExprExpression(boolvar, left, right,
770 ModelCache::EXPR_EXPR_IS_LESS);
771 return boolvar;
772 }
773}
774
775Constraint* Solver::MakeIsLessCt(IntExpr* const left, IntExpr* const right,
776 IntVar* const b) {
777 CHECK_EQ(this, left->solver());
778 CHECK_EQ(this, right->solver());
779 if (left->Bound()) {
780 return MakeIsGreaterCstCt(right, left->Min(), b);
781 } else if (right->Bound()) {
782 return MakeIsLessCstCt(left, right->Min(), b);
783 }
784 return RevAlloc(new IsLessCt(this, left, right, b));
785}
786
787IntVar* Solver::MakeIsGreaterOrEqualVar(IntExpr* const left,
788 IntExpr* const right) {
789 return MakeIsLessOrEqualVar(right, left);
790}
792Constraint* Solver::MakeIsGreaterOrEqualCt(IntExpr* const left,
793 IntExpr* const right,
794 IntVar* const b) {
795 return MakeIsLessOrEqualCt(right, left, b);
797
798IntVar* Solver::MakeIsGreaterVar(IntExpr* const left, IntExpr* const right) {
799 return MakeIsLessVar(right, left);
800}
801
802Constraint* Solver::MakeIsGreaterCt(IntExpr* const left, IntExpr* const right,
803 IntVar* const b) {
804 return MakeIsLessCt(right, left, b);
805}
807} // namespace operations_research
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.
int64_t b
Definition table.cc:45
In SWIG mode, we don't want anything besides these top-level includes.
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
static const int64_t kint64max
Definition types.h:32
static const int64_t kint64min
Definition types.h:31