OR-Tools  8.0
timetabling.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 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 #include <string>
15 
16 #include "absl/strings/str_format.h"
18 #include "ortools/base/logging.h"
19 #include "ortools/base/macros.h"
22 
23 namespace operations_research {
24 
25 // ----- interval <unary relation> date -----
26 
27 namespace {
28 const char* kUnaryNames[] = {
29  "ENDS_AFTER", "ENDS_AT", "ENDS_BEFORE", "STARTS_AFTER",
30  "STARTS_AT", "STARTS_BEFORE", "CROSS_DATE", "AVOID_DATE",
31 };
32 
33 const char* kBinaryNames[] = {
34  "ENDS_AFTER_END", "ENDS_AFTER_START", "ENDS_AT_END",
35  "ENDS_AT_START", "STARTS_AFTER_END", "STARTS_AFTER_START",
36  "STARTS_AT_END", "STARTS_AT_START", "STAYS_IN_SYNC"};
37 
38 class IntervalUnaryRelation : public Constraint {
39  public:
40  IntervalUnaryRelation(Solver* const s, IntervalVar* const t, int64 d,
41  Solver::UnaryIntervalRelation rel)
42  : Constraint(s), t_(t), d_(d), rel_(rel) {}
43  ~IntervalUnaryRelation() override {}
44 
45  void Post() override;
46 
47  void InitialPropagate() override;
48 
49  std::string DebugString() const override {
50  return absl::StrFormat("(%s %s %d)", t_->DebugString(), kUnaryNames[rel_],
51  d_);
52  }
53 
54  void Accept(ModelVisitor* const visitor) const override {
55  visitor->BeginVisitConstraint(ModelVisitor::kIntervalUnaryRelation, this);
56  visitor->VisitIntervalArgument(ModelVisitor::kIntervalArgument, t_);
57  visitor->VisitIntegerArgument(ModelVisitor::kRelationArgument, rel_);
58  visitor->VisitIntegerArgument(ModelVisitor::kValueArgument, d_);
59  visitor->EndVisitConstraint(ModelVisitor::kIntervalUnaryRelation, this);
60  }
61 
62  private:
63  IntervalVar* const t_;
64  const int64 d_;
65  const Solver::UnaryIntervalRelation rel_;
66 };
67 
68 void IntervalUnaryRelation::Post() {
69  if (t_->MayBePerformed()) {
70  Demon* d = solver()->MakeConstraintInitialPropagateCallback(this);
71  t_->WhenAnything(d);
72  }
73 }
74 
75 void IntervalUnaryRelation::InitialPropagate() {
76  if (t_->MayBePerformed()) {
77  switch (rel_) {
78  case Solver::ENDS_AFTER:
79  t_->SetEndMin(d_);
80  break;
81  case Solver::ENDS_AT:
82  t_->SetEndRange(d_, d_);
83  break;
84  case Solver::ENDS_BEFORE:
85  t_->SetEndMax(d_);
86  break;
87  case Solver::STARTS_AFTER:
88  t_->SetStartMin(d_);
89  break;
90  case Solver::STARTS_AT:
91  t_->SetStartRange(d_, d_);
92  break;
93 
94  case Solver::STARTS_BEFORE:
95  t_->SetStartMax(d_);
96  break;
97  case Solver::CROSS_DATE:
98  t_->SetStartMax(d_);
99  t_->SetEndMin(d_);
100  break;
101  case Solver::AVOID_DATE:
102  if (t_->EndMin() > d_) {
103  t_->SetStartMin(d_);
104  } else if (t_->StartMax() < d_) {
105  t_->SetEndMax(d_);
106  }
107  break;
108  }
109  }
110 }
111 } // namespace
112 
113 Constraint* Solver::MakeIntervalVarRelation(IntervalVar* const t,
114  Solver::UnaryIntervalRelation r,
115  int64 d) {
116  return RevAlloc(new IntervalUnaryRelation(this, t, d, r));
117 }
118 
119 // ----- interval <binary relation> interval -----
120 
121 namespace {
122 class IntervalBinaryRelation : public Constraint {
123  public:
124  IntervalBinaryRelation(Solver* const s, IntervalVar* const t1,
125  IntervalVar* const t2,
126  Solver::BinaryIntervalRelation rel, int64 delay)
127  : Constraint(s), t1_(t1), t2_(t2), rel_(rel), delay_(delay) {}
128  ~IntervalBinaryRelation() override {}
129 
130  void Post() override;
131 
132  void InitialPropagate() override;
133 
134  std::string DebugString() const override {
135  return absl::StrFormat("(%s %s %s)", t1_->DebugString(), kBinaryNames[rel_],
136  t2_->DebugString());
137  }
138 
139  void Accept(ModelVisitor* const visitor) const override {
140  visitor->BeginVisitConstraint(ModelVisitor::kIntervalBinaryRelation, this);
141  visitor->VisitIntervalArgument(ModelVisitor::kLeftArgument, t1_);
142  visitor->VisitIntegerArgument(ModelVisitor::kRelationArgument, rel_);
143  visitor->VisitIntervalArgument(ModelVisitor::kRightArgument, t2_);
144  visitor->EndVisitConstraint(ModelVisitor::kIntervalBinaryRelation, this);
145  }
146 
147  private:
148  IntervalVar* const t1_;
149  IntervalVar* const t2_;
150  const Solver::BinaryIntervalRelation rel_;
151  const int64 delay_;
152 };
153 
154 void IntervalBinaryRelation::Post() {
155  if (t1_->MayBePerformed() && t2_->MayBePerformed()) {
156  Demon* d = solver()->MakeConstraintInitialPropagateCallback(this);
157  t1_->WhenAnything(d);
158  t2_->WhenAnything(d);
159  }
160 }
161 
162 // TODO(user) : make code more compact, use function pointers?
163 void IntervalBinaryRelation::InitialPropagate() {
164  if (t2_->MustBePerformed() && t1_->MayBePerformed()) {
165  switch (rel_) {
166  case Solver::ENDS_AFTER_END:
167  t1_->SetEndMin(t2_->EndMin() + delay_);
168  break;
169  case Solver::ENDS_AFTER_START:
170  t1_->SetEndMin(t2_->StartMin() + delay_);
171  break;
172  case Solver::ENDS_AT_END:
173  t1_->SetEndRange(t2_->EndMin() + delay_, t2_->EndMax() + delay_);
174  break;
175  case Solver::ENDS_AT_START:
176  t1_->SetEndRange(t2_->StartMin() + delay_, t2_->StartMax() + delay_);
177  break;
178  case Solver::STARTS_AFTER_END:
179  t1_->SetStartMin(t2_->EndMin() + delay_);
180  break;
181  case Solver::STARTS_AFTER_START:
182  t1_->SetStartMin(t2_->StartMin() + delay_);
183  break;
184  case Solver::STARTS_AT_END:
185  t1_->SetStartRange(t2_->EndMin() + delay_, t2_->EndMax() + delay_);
186  break;
187  case Solver::STARTS_AT_START:
188  t1_->SetStartRange(t2_->StartMin() + delay_, t2_->StartMax() + delay_);
189  break;
190  case Solver::STAYS_IN_SYNC:
191  t1_->SetStartRange(t2_->StartMin() + delay_, t2_->StartMax() + delay_);
192  t1_->SetEndRange(t2_->EndMin() + delay_, t2_->EndMax() + delay_);
193  break;
194  }
195  }
196 
197  if (t1_->MustBePerformed() && t2_->MayBePerformed()) {
198  switch (rel_) {
199  case Solver::ENDS_AFTER_END:
200  t2_->SetEndMax(t1_->EndMax() - delay_);
201  break;
202  case Solver::ENDS_AFTER_START:
203  t2_->SetStartMax(t1_->EndMax() - delay_);
204  break;
205  case Solver::ENDS_AT_END:
206  t2_->SetEndRange(t1_->EndMin() - delay_, t1_->EndMax() - delay_);
207  break;
208  case Solver::ENDS_AT_START:
209  t2_->SetStartRange(t1_->EndMin() - delay_, t1_->EndMax() - delay_);
210  break;
211  case Solver::STARTS_AFTER_END:
212  t2_->SetEndMax(t1_->StartMax() - delay_);
213  break;
214  case Solver::STARTS_AFTER_START:
215  t2_->SetStartMax(t1_->StartMax() - delay_);
216  break;
217  case Solver::STARTS_AT_END:
218  t2_->SetEndRange(t1_->StartMin() - delay_, t1_->StartMax() - delay_);
219  break;
220  case Solver::STARTS_AT_START:
221  t2_->SetStartRange(t1_->StartMin() - delay_, t1_->StartMax() - delay_);
222  break;
223  case Solver::STAYS_IN_SYNC:
224  t2_->SetStartRange(t1_->StartMin() - delay_, t1_->StartMax() - delay_);
225  t2_->SetEndRange(t1_->EndMin() - delay_, t1_->EndMax() - delay_);
226  break;
227  }
228  }
229 }
230 } // namespace
231 
232 Constraint* Solver::MakeIntervalVarRelation(IntervalVar* const t1,
233  Solver::BinaryIntervalRelation r,
234  IntervalVar* const t2) {
235  return RevAlloc(new IntervalBinaryRelation(this, t1, t2, r, 0));
236 }
237 
238 Constraint* Solver::MakeIntervalVarRelationWithDelay(
239  IntervalVar* const t1, Solver::BinaryIntervalRelation r,
240  IntervalVar* const t2, int64 delay) {
241  return RevAlloc(new IntervalBinaryRelation(this, t1, t2, r, delay));
242 }
243 
244 // ----- activity a before activity b or activity b before activity a -----
245 
246 namespace {
247 class TemporalDisjunction : public Constraint {
248  public:
249  enum State { ONE_BEFORE_TWO, TWO_BEFORE_ONE, UNDECIDED };
250 
251  TemporalDisjunction(Solver* const s, IntervalVar* const t1,
252  IntervalVar* const t2, IntVar* const alt)
253  : Constraint(s), t1_(t1), t2_(t2), alt_(alt), state_(UNDECIDED) {}
254  ~TemporalDisjunction() override {}
255 
256  void Post() override;
257  void InitialPropagate() override;
258  std::string DebugString() const override;
259 
260  void RangeDemon1();
261  void RangeDemon2();
262  void RangeAlt();
263  void Decide(State s);
264  void TryToDecide();
265 
266  void Accept(ModelVisitor* const visitor) const override {
267  visitor->BeginVisitConstraint(ModelVisitor::kIntervalDisjunction, this);
268  visitor->VisitIntervalArgument(ModelVisitor::kLeftArgument, t1_);
269  visitor->VisitIntervalArgument(ModelVisitor::kRightArgument, t2_);
270  visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
271  alt_);
272  visitor->EndVisitConstraint(ModelVisitor::kIntervalDisjunction, this);
273  }
274 
275  private:
276  IntervalVar* const t1_;
277  IntervalVar* const t2_;
278  IntVar* const alt_;
279  State state_;
280 };
281 
282 void TemporalDisjunction::Post() {
283  Solver* const s = solver();
284  Demon* d = MakeConstraintDemon0(s, this, &TemporalDisjunction::RangeDemon1,
285  "RangeDemon1");
286  t1_->WhenAnything(d);
287  d = MakeConstraintDemon0(s, this, &TemporalDisjunction::RangeDemon2,
288  "RangeDemon2");
289  t2_->WhenAnything(d);
290  if (alt_ != nullptr) {
291  d = MakeConstraintDemon0(s, this, &TemporalDisjunction::RangeAlt,
292  "RangeAlt");
293  alt_->WhenRange(d);
294  }
295 }
296 
297 void TemporalDisjunction::InitialPropagate() {
298  if (alt_ != nullptr) {
299  alt_->SetRange(0, 1);
300  }
301  if (alt_ != nullptr && alt_->Bound()) {
302  RangeAlt();
303  } else {
304  RangeDemon1();
305  RangeDemon2();
306  }
307 }
308 
309 std::string TemporalDisjunction::DebugString() const {
310  std::string out;
311  (out = absl::StrFormat("TemporalDisjunction(%s, %s", t1_->DebugString(),
312  t2_->DebugString()));
313  if (alt_ != nullptr) {
314  absl::StrAppendFormat(&out, " => %s", alt_->DebugString());
315  }
316  out += ") ";
317  return out;
318 }
319 
320 void TemporalDisjunction::TryToDecide() {
321  DCHECK_EQ(UNDECIDED, state_);
322  if (t1_->MayBePerformed() && t2_->MayBePerformed() &&
323  (t1_->MustBePerformed() || t2_->MustBePerformed())) {
324  if (t1_->EndMin() > t2_->StartMax()) {
325  Decide(TWO_BEFORE_ONE);
326  } else if (t2_->EndMin() > t1_->StartMax()) {
327  Decide(ONE_BEFORE_TWO);
328  }
329  }
330 }
331 
332 void TemporalDisjunction::RangeDemon1() {
333  switch (state_) {
334  case ONE_BEFORE_TWO: {
335  if (t1_->MustBePerformed() && t2_->MayBePerformed()) {
336  t2_->SetStartMin(t1_->EndMin());
337  }
338  break;
339  }
340  case TWO_BEFORE_ONE: {
341  if (t1_->MustBePerformed() && t2_->MayBePerformed()) {
342  t2_->SetEndMax(t1_->StartMax());
343  }
344  break;
345  }
346  case UNDECIDED: {
347  TryToDecide();
348  }
349  }
350 }
351 
352 void TemporalDisjunction::RangeDemon2() {
353  if (t1_->MayBePerformed() || t2_->MayBePerformed()) {
354  switch (state_) {
355  case ONE_BEFORE_TWO: {
356  if (t2_->MustBePerformed() && t1_->MayBePerformed()) {
357  t1_->SetEndMax(t2_->StartMax());
358  }
359  break;
360  }
361  case TWO_BEFORE_ONE: {
362  if (t2_->MustBePerformed() && t1_->MayBePerformed()) {
363  t1_->SetStartMin(t2_->EndMin());
364  }
365  break;
366  }
367  case UNDECIDED: {
368  TryToDecide();
369  }
370  }
371  }
372 }
373 
374 void TemporalDisjunction::RangeAlt() {
375  DCHECK(alt_ != nullptr);
376  if (alt_->Value() == 0) {
377  Decide(ONE_BEFORE_TWO);
378  } else {
379  Decide(TWO_BEFORE_ONE);
380  }
381 }
382 
383 void TemporalDisjunction::Decide(State s) {
384  // Should Decide on a fixed state?
385  DCHECK_NE(s, UNDECIDED);
386  if (state_ != UNDECIDED && state_ != s) {
387  solver()->Fail();
388  }
389  solver()->SaveValue(reinterpret_cast<int*>(&state_));
390  state_ = s;
391  if (alt_ != nullptr) {
392  if (s == ONE_BEFORE_TWO) {
393  alt_->SetValue(0);
394  } else {
395  alt_->SetValue(1);
396  }
397  }
398  RangeDemon1();
399  RangeDemon2();
400 }
401 } // namespace
402 
403 Constraint* Solver::MakeTemporalDisjunction(IntervalVar* const t1,
404  IntervalVar* const t2,
405  IntVar* const alt) {
406  return RevAlloc(new TemporalDisjunction(this, t1, t2, alt));
407 }
408 
409 Constraint* Solver::MakeTemporalDisjunction(IntervalVar* const t1,
410  IntervalVar* const t2) {
411  return RevAlloc(new TemporalDisjunction(this, t1, t2, nullptr));
412 }
413 
414 } // namespace operations_research
integral_types.h
logging.h
macros.h
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
int64
int64_t int64
Definition: integral_types.h:34
constraint_solveri.h
constraint_solver.h
operations_research::MakeConstraintDemon0
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
Definition: constraint_solveri.h:533