Google OR-Tools: ortools/constraint_solver/timetabling.cc Source File

1

2

3

4

5

6

7

8

9

10

11

12

13

14#include <cstdint>

15#include <string>

16

17#include "absl/log/check.h"

18#include "absl/strings/str_format.h"

21

23

24

25

26namespace {

27const char* kUnaryNames[] = {

28 "ENDS_AFTER", "ENDS_AT", "ENDS_BEFORE", "STARTS_AFTER",

29 "STARTS_AT", "STARTS_BEFORE", "CROSS_DATE", "AVOID_DATE",

30};

31

32const char* kBinaryNames[] = {

33 "ENDS_AFTER_END", "ENDS_AFTER_START", "ENDS_AT_END",

34 "ENDS_AT_START", "STARTS_AFTER_END", "STARTS_AFTER_START",

35 "STARTS_AT_END", "STARTS_AT_START", "STAYS_IN_SYNC"};

36

37class IntervalUnaryRelation : public Constraint {

38 public:

39 IntervalUnaryRelation(Solver* const s, IntervalVar* const t, int64_t d,

41 : Constraint(s), t_(t), d_(d), rel_(rel) {}

42 ~IntervalUnaryRelation() override {}

43

44 void Post() override;

45

46 void InitialPropagate() override;

47

48 std::string DebugString() const override {

49 return absl::StrFormat("(%s %s %d)", t_->DebugString(), kUnaryNames[rel_],

50 d_);

51 }

52

53 void Accept(ModelVisitor* const visitor) const override {

59 }

60

61 private:

62 IntervalVar* const t_;

63 const int64_t d_;

65};

66

67void IntervalUnaryRelation::Post() {

69 Demon* d = solver()->MakeConstraintInitialPropagateCallback(this);

71 }

72}

73

74void IntervalUnaryRelation::InitialPropagate() {

76 switch (rel_) {

77 case Solver::ENDS_AFTER:

79 break;

80 case Solver::ENDS_AT:

82 break;

83 case Solver::ENDS_BEFORE:

85 break;

86 case Solver::STARTS_AFTER:

88 break;

89 case Solver::STARTS_AT:

91 break;

92

93 case Solver::STARTS_BEFORE:

95 break;

96 case Solver::CROSS_DATE:

99 break;

100 case Solver::AVOID_DATE:

101 if (t_->EndMin() > d_) {

103 } else if (t_->StartMax() < d_) {

105 }

106 break;

107 }

108 }

109}

110}

111

114 int64_t d) {

115 return RevAlloc(new IntervalUnaryRelation(this, t, d, r));

116}

117

118

119

120namespace {

121class IntervalBinaryRelation : public Constraint {

122 public:

126 : Constraint(s), t1_(t1), t2_(t2), rel_(rel), delay_(delay) {}

127 ~IntervalBinaryRelation() override {}

128

129 void Post() override;

130

131 void InitialPropagate() override;

132

133 std::string DebugString() const override {

134 return absl::StrFormat("(%s %s %s)", t1_->DebugString(), kBinaryNames[rel_],

136 }

137

138 void Accept(ModelVisitor* const visitor) const override {

139 visitor->BeginVisitConstraint(ModelVisitor::kIntervalBinaryRelation, this);

140 visitor->VisitIntervalArgument(ModelVisitor::kLeftArgument, t1_);

141 visitor->VisitIntegerArgument(ModelVisitor::kRelationArgument, rel_);

142 visitor->VisitIntervalArgument(ModelVisitor::kRightArgument, t2_);

143 visitor->EndVisitConstraint(ModelVisitor::kIntervalBinaryRelation, this);

144 }

145

146 private:

147 IntervalVar* const t1_;

148 IntervalVar* const t2_;

149 const Solver::BinaryIntervalRelation rel_;

150 const int64_t delay_;

151};

152

153void IntervalBinaryRelation::Post() {

155 Demon* d = solver()->MakeConstraintInitialPropagateCallback(this);

158 }

159}

160

161

162void IntervalBinaryRelation::InitialPropagate() {

164 switch (rel_) {

165 case Solver::ENDS_AFTER_END:

167 break;

168 case Solver::ENDS_AFTER_START:

170 break;

171 case Solver::ENDS_AT_END:

173 break;

174 case Solver::ENDS_AT_START:

176 break;

177 case Solver::STARTS_AFTER_END:

179 break;

180 case Solver::STARTS_AFTER_START:

182 break;

183 case Solver::STARTS_AT_END:

185 break;

186 case Solver::STARTS_AT_START:

188 break;

189 case Solver::STAYS_IN_SYNC:

192 break;

193 }

194 }

195

197 switch (rel_) {

198 case Solver::ENDS_AFTER_END:

200 break;

201 case Solver::ENDS_AFTER_START:

203 break;

204 case Solver::ENDS_AT_END:

206 break;

207 case Solver::ENDS_AT_START:

209 break;

210 case Solver::STARTS_AFTER_END:

212 break;

213 case Solver::STARTS_AFTER_START:

215 break;

216 case Solver::STARTS_AT_END:

218 break;

219 case Solver::STARTS_AT_START:

221 break;

222 case Solver::STAYS_IN_SYNC:

225 break;

226 }

227 }

228}

229}

230

234 return RevAlloc(new IntervalBinaryRelation(this, t1, t2, r, 0));

235}

236

240 return RevAlloc(new IntervalBinaryRelation(this, t1, t2, r, delay));

241}

242

243

244

245namespace {

246class TemporalDisjunction : public Constraint {

247 public:

248 enum State { ONE_BEFORE_TWO, TWO_BEFORE_ONE, UNDECIDED };

249

250 TemporalDisjunction(Solver* const s, IntervalVar* const t1,

251 IntervalVar* const t2, IntVar* const alt)

252 : Constraint(s), t1_(t1), t2_(t2), alt_(alt), state_(UNDECIDED) {}

253 ~TemporalDisjunction() override {}

254

255 void Post() override;

256 void InitialPropagate() override;

257 std::string DebugString() const override;

258

259 void RangeDemon1();

260 void RangeDemon2();

261 void RangeAlt();

262 void Decide(State s);

263 void TryToDecide();

264

265 void Accept(ModelVisitor* const visitor) const override {

266 visitor->BeginVisitConstraint(ModelVisitor::kIntervalDisjunction, this);

267 visitor->VisitIntervalArgument(ModelVisitor::kLeftArgument, t1_);

268 visitor->VisitIntervalArgument(ModelVisitor::kRightArgument, t2_);

269 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,

270 alt_);

271 visitor->EndVisitConstraint(ModelVisitor::kIntervalDisjunction, this);

272 }

273

274 private:

275 IntervalVar* const t1_;

276 IntervalVar* const t2_;

277 IntVar* const alt_;

278 State state_;

279};

280

281void TemporalDisjunction::Post() {

282 Solver* const s = solver();

284 "RangeDemon1");

287 "RangeDemon2");

289 if (alt_ != nullptr) {

291 "RangeAlt");

293 }

294}

295

296void TemporalDisjunction::InitialPropagate() {

297 if (alt_ != nullptr) {

299 }

300 if (alt_ != nullptr && alt_->Bound()) {

301 RangeAlt();

302 } else {

303 RangeDemon1();

304 RangeDemon2();

305 }

306}

307

308std::string TemporalDisjunction::DebugString() const {

309 std::string out;

310 (out = absl::StrFormat("TemporalDisjunction(%s, %s", t1_->DebugString(),

312 if (alt_ != nullptr) {

313 absl::StrAppendFormat(&out, " => %s", alt_->DebugString());

314 }

315 out += ") ";

316 return out;

317}

318

319void TemporalDisjunction::TryToDecide() {

320 DCHECK_EQ(UNDECIDED, state_);

324 Decide(TWO_BEFORE_ONE);

326 Decide(ONE_BEFORE_TWO);

327 }

328 }

329}

330

331void TemporalDisjunction::RangeDemon1() {

332 switch (state_) {

333 case ONE_BEFORE_TWO: {

336 }

337 break;

338 }

339 case TWO_BEFORE_ONE: {

342 }

343 break;

344 }

345 case UNDECIDED: {

346 TryToDecide();

347 }

348 }

349}

350

351void TemporalDisjunction::RangeDemon2() {

353 switch (state_) {

354 case ONE_BEFORE_TWO: {

357 }

358 break;

359 }

360 case TWO_BEFORE_ONE: {

363 }

364 break;

365 }

366 case UNDECIDED: {

367 TryToDecide();

368 }

369 }

370 }

371}

372

373void TemporalDisjunction::RangeAlt() {

374 DCHECK(alt_ != nullptr);

375 if (alt_->Value() == 0) {

376 Decide(ONE_BEFORE_TWO);

377 } else {

378 Decide(TWO_BEFORE_ONE);

379 }

380}

381

382void TemporalDisjunction::Decide(State s) {

383

384 DCHECK_NE(s, UNDECIDED);

385 if (state_ != UNDECIDED && state_ != s) {

386 solver()->Fail();

387 }

388 solver()->SaveValue(reinterpret_cast<int*>(&state_));

389 state_ = s;

390 if (alt_ != nullptr) {

391 if (s == ONE_BEFORE_TWO) {

393 } else {

395 }

396 }

397 RangeDemon1();

398 RangeDemon2();

399}

400}

401

405 return RevAlloc(new TemporalDisjunction(this, t1, t2, alt));

406}

407

410 return RevAlloc(new TemporalDisjunction(this, t1, t2, nullptr));

411}

412

413}

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 SetRange(int64_t l, int64_t u)

This method sets both the min and the max of the expression.

virtual void WhenRange(Demon *d)=0

Attach a demon that will watch the min or the max of the expression.

virtual int64_t Value() const =0

virtual void SetEndRange(int64_t mi, int64_t ma)=0

virtual int64_t EndMax() const =0

virtual int64_t EndMin() const =0

These methods query, set, and watch the end position of the interval var.

virtual void SetEndMax(int64_t m)=0

virtual void SetStartRange(int64_t mi, int64_t ma)=0

virtual void SetStartMax(int64_t m)=0

void WhenAnything(Demon *d)

Attaches a demon awakened when anything about this interval changes.

virtual int64_t StartMax() const =0

virtual bool MayBePerformed() const =0

virtual void SetEndMin(int64_t m)=0

virtual void SetStartMin(int64_t m)=0

virtual int64_t StartMin() const =0

virtual bool MustBePerformed() const =0

static const char kRelationArgument[]

static const char kIntervalUnaryRelation[]

static const char kValueArgument[]

static const char kIntervalArgument[]

std::string DebugString() const override

Constraint * MakeTemporalDisjunction(IntervalVar *t1, IntervalVar *t2, IntVar *alt)

Definition timetabling.cc:402

Constraint * MakeIntervalVarRelationWithDelay(IntervalVar *t1, BinaryIntervalRelation r, IntervalVar *t2, int64_t delay)

Definition timetabling.cc:237

Constraint * MakeIntervalVarRelation(IntervalVar *t, UnaryIntervalRelation r, int64_t d)

Definition timetabling.cc:112

Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)