OR-Tools  9.6
range_cst.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 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"
22 #include "ortools/base/logging.h"
25 
26 namespace operations_research {
27 
28 //-----------------------------------------------------------------------------
29 // RangeEquality
30 
31 namespace {
32 class 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 
72 class RangeLessOrEqual : public Constraint {
73  public:
74  RangeLessOrEqual(Solver* const s, IntExpr* const l, IntExpr* const 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 
96 RangeLessOrEqual::RangeLessOrEqual(Solver* const s, IntExpr* const l,
97  IntExpr* const r)
98  : Constraint(s), left_(l), right_(r), demon_(nullptr) {}
99 
100 void RangeLessOrEqual::Post() {
101  demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
102  left_->WhenRange(demon_);
103  right_->WhenRange(demon_);
104 }
105 
106 void 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 
114 std::string RangeLessOrEqual::DebugString() const {
115  return left_->DebugString() + " <= " + right_->DebugString();
116 }
117 
118 //-----------------------------------------------------------------------------
119 // RangeLess
120 
121 class RangeLess : public Constraint {
122  public:
123  RangeLess(Solver* const s, IntExpr* const l, IntExpr* const 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 
143 RangeLess::RangeLess(Solver* const s, IntExpr* const l, IntExpr* const r)
144  : Constraint(s), left_(l), right_(r), demon_(nullptr) {}
145 
146 void RangeLess::Post() {
147  demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
148  left_->WhenRange(demon_);
149  right_->WhenRange(demon_);
150 }
151 
152 void 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 
162 std::string RangeLess::DebugString() const {
163  return left_->DebugString() + " < " + right_->DebugString();
164 }
165 
166 //-----------------------------------------------------------------------------
167 // DiffVar
168 
169 class DiffVar : public Constraint {
170  public:
171  DiffVar(Solver* const s, IntVar* const l, IntVar* const 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 
193 DiffVar::DiffVar(Solver* const s, IntVar* const l, IntVar* const r)
194  : Constraint(s), left_(l), right_(r) {}
195 
196 void 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 
206 void 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 
214 void 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 
222 void DiffVar::InitialPropagate() {
223  if (left_->Bound()) {
224  LeftBound();
225  }
226  if (right_->Bound()) {
227  RightBound();
228  }
229 }
230 
231 std::string DiffVar::DebugString() const {
232  return left_->DebugString() + " != " + right_->DebugString();
233 }
234 
235 // --------------------- Reified API -------------------
236 // A reified API transforms an 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 
242 class 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 
329 class 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 
406 class 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 
460 class 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 
514 Constraint* 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 
528 Constraint* 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 
544 Constraint* Solver::MakeGreaterOrEqual(IntExpr* const l, IntExpr* const r) {
545  return MakeLessOrEqual(r, l);
546 }
547 
548 Constraint* 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 
562 Constraint* Solver::MakeGreater(IntExpr* const l, IntExpr* const r) {
563  return MakeLess(r, l);
564 }
565 
566 Constraint* 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 
579 IntVar* 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 
624 Constraint* 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 
643 IntVar* 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 
688 Constraint* 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 
700 IntVar* 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 
732 Constraint* 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 
744 IntVar* 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 
775 Constraint* 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 
787 IntVar* Solver::MakeIsGreaterOrEqualVar(IntExpr* const left,
788  IntExpr* const right) {
789  return MakeIsLessOrEqualVar(right, left);
790 }
791 
792 Constraint* Solver::MakeIsGreaterOrEqualCt(IntExpr* const left,
793  IntExpr* const right,
794  IntVar* const b) {
795  return MakeIsLessOrEqualCt(right, left, b);
796 }
797 
798 IntVar* Solver::MakeIsGreaterVar(IntExpr* const left, IntExpr* const right) {
799  return MakeIsLessVar(right, left);
800 }
801 
802 Constraint* Solver::MakeIsGreaterCt(IntExpr* const left, IntExpr* const right,
803  IntVar* const b) {
804  return MakeIsLessCt(right, left, b);
805 }
806 
807 } // namespace operations_research
A constraint is the main modeling object.
The class IntExpr is the base of all integer expressions in constraint programming.
virtual IntVar * Var()=0
Creates a variable from the expression.
virtual bool Bound() const
Returns true if the min and the max of the expression are equal.
virtual int64_t Min() const =0
The class IntVar is a subset of IntExpr.
IntVar * Var() override
Creates a variable from the expression.
virtual std::string name() const
Object naming.
int64_t b
static const int64_t kint64max
static const int64_t kint64min
Collection of objects used to extend the Constraint Solver library.
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
IntervalVar *const target_var_