30#include "absl/base/attributes.h"
31#include "absl/log/check.h"
32#include "absl/strings/str_format.h"
33#include "absl/strings/string_view.h"
40class TreeArrayConstraint :
public Constraint {
42 enum PerformedStatus { UNPERFORMED, PERFORMED, UNDECIDED };
44 TreeArrayConstraint(Solver*
const solver,
45 const std::vector<IntervalVar*>& vars,
46 IntervalVar*
const target_var)
49 target_var_(target_var),
50 block_size_(solver->
parameters().array_split_size()) {
51 std::vector<int> lengths;
52 lengths.push_back(
vars_.size());
53 while (lengths.back() > 1) {
54 const int current = lengths.back();
55 lengths.push_back((current + block_size_ - 1) / block_size_);
57 tree_.resize(lengths.size());
58 for (
int i = 0;
i < lengths.size(); ++
i) {
59 tree_[
i].resize(lengths[lengths.size() - i - 1]);
61 DCHECK_GE(tree_.size(), 1);
62 DCHECK_EQ(1, tree_[0].
size());
63 root_node_ = &tree_[0][0];
66 std::string DebugStringInternal(absl::string_view
name)
const {
68 target_var_->DebugString());
71 void AcceptInternal(
const std::string&
name,
72 ModelVisitor*
const visitor)
const {
73 visitor->BeginVisitConstraint(
name,
this);
77 visitor->EndVisitConstraint(
name,
this);
81 void ReduceDomain(
int depth,
int position, int64_t new_start_min,
82 int64_t new_start_max, int64_t new_end_min,
83 int64_t new_end_max, PerformedStatus
performed) {
84 NodeInfo*
const info = &tree_[depth][position];
85 if (new_start_min > info->start_min.Value()) {
86 info->start_min.SetValue(solver(), new_start_min);
88 if (new_start_max < info->
start_max.Value()) {
89 info->start_max.SetValue(solver(), new_start_max);
91 if (new_end_min > info->end_min.Value()) {
92 info->end_min.SetValue(solver(), new_end_min);
94 if (new_end_max < info->
end_max.Value()) {
95 info->end_max.SetValue(solver(), new_end_max);
98 CHECK(
performed == info->performed.Value() ||
99 info->performed.Value() == UNDECIDED);
100 info->performed.SetValue(solver(),
performed);
112 tree_[depth][position].start_min.SetValue(solver(),
start_min);
113 tree_[depth][position].start_max.SetValue(solver(),
start_max);
114 tree_[depth][position].end_min.SetValue(solver(),
end_min);
115 tree_[depth][position].end_max.SetValue(solver(),
end_max);
116 tree_[depth][position].performed.SetValue(solver(),
120 int64_t StartMin(
int depth,
int position)
const {
121 return tree_[depth][position].start_min.Value();
124 int64_t StartMax(
int depth,
int position)
const {
125 return tree_[depth][position].start_max.Value();
128 int64_t EndMax(
int depth,
int position)
const {
129 return tree_[depth][position].end_max.Value();
132 int64_t EndMin(
int depth,
int position)
const {
133 return tree_[depth][position].end_min.Value();
136 PerformedStatus Performed(
int depth,
int position)
const {
137 const int p = tree_[depth][position].performed.Value();
138 CHECK_GE(p, UNPERFORMED);
139 CHECK_LE(p, UNDECIDED);
140 return static_cast<PerformedStatus
>(p);
143 int64_t RootStartMin()
const {
return root_node_->start_min.Value(); }
145 int64_t RootStartMax()
const {
return root_node_->start_max.Value(); }
147 int64_t RootEndMin()
const {
return root_node_->end_min.Value(); }
149 int64_t RootEndMax()
const {
return root_node_->end_max.Value(); }
151 PerformedStatus RootPerformed()
const {
return Performed(0, 0); }
155 int64_t VarStartMin(
int position)
const {
156 return vars_[position]->MayBePerformed() ?
vars_[position]->StartMin() : 0;
159 int64_t VarStartMax(
int position)
const {
160 return vars_[position]->MayBePerformed() ?
vars_[position]->StartMax() : 0;
163 int64_t VarEndMin(
int position)
const {
164 return vars_[position]->MayBePerformed() ?
vars_[position]->EndMin() : 0;
167 int64_t VarEndMax(
int position)
const {
168 return vars_[position]->MayBePerformed() ?
vars_[position]->EndMax() : 0;
171 int64_t TargetVarStartMin()
const {
172 return target_var_->MayBePerformed() ? target_var_->StartMin() : 0;
175 int64_t TargetVarStartMax()
const {
176 return target_var_->MayBePerformed() ? target_var_->StartMax() : 0;
179 int64_t TargetVarEndMin()
const {
180 return target_var_->MayBePerformed() ? target_var_->EndMin() : 0;
183 int64_t TargetVarEndMax()
const {
184 return target_var_->MayBePerformed() ? target_var_->EndMax() : 0;
189 PerformedStatus VarPerformed(
int position)
const {
190 IntervalVar*
const var =
vars_[position];
191 if (
var->MustBePerformed()) {
193 }
else if (
var->MayBePerformed()) {
201 PerformedStatus TargetVarPerformed()
const {
202 if (target_var_->MustBePerformed()) {
204 }
else if (target_var_->MayBePerformed()) {
212 int Parent(
int position)
const {
return position / block_size_; }
215 int ChildStart(
int position)
const {
return position * block_size_; }
220 int ChildEnd(
int depth,
int position)
const {
221 DCHECK_LT(depth + 1, tree_.size());
222 return std::min((position + 1) * block_size_ - 1, Width(depth + 1) - 1);
225 bool IsLeaf(
int depth)
const {
return depth == MaxDepth(); }
227 int MaxDepth()
const {
return tree_.size() - 1; }
229 int Width(
int depth)
const {
return tree_[depth].size(); }
232 const std::vector<IntervalVar*>
vars_;
233 IntervalVar*
const target_var_;
251 std::vector<std::vector<NodeInfo> > tree_;
252 const int block_size_;
253 NodeInfo* root_node_;
257class CoverConstraint :
public TreeArrayConstraint {
259 CoverConstraint(Solver*
const solver,
const std::vector<IntervalVar*>& vars,
260 IntervalVar*
const cover_var)
261 : TreeArrayConstraint(solver, vars, cover_var), cover_demon_(
nullptr) {}
263 ~CoverConstraint()
override {}
265 void Post()
override {
266 for (
int i = 0;
i <
vars_.size(); ++
i) {
268 solver(),
this, &CoverConstraint::LeafChanged,
"LeafChanged", i);
269 vars_[
i]->WhenStartRange(demon);
270 vars_[
i]->WhenEndRange(demon);
271 vars_[
i]->WhenPerformedBound(demon);
274 solver(),
this, &CoverConstraint::CoverVarChanged,
"CoverVarChanged"));
275 target_var_->WhenStartRange(cover_demon_);
276 target_var_->WhenEndRange(cover_demon_);
277 target_var_->WhenPerformedBound(cover_demon_);
280 void InitialPropagate()
override {
282 for (
int i = 0;
i <
vars_.size(); ++
i) {
283 InitLeaf(i, VarStartMin(i), VarStartMax(i), VarEndMin(i), VarEndMax(i),
288 for (
int i = MaxDepth() - 1;
i >= 0; --
i) {
289 for (
int j = 0; j < Width(i); ++j) {
290 int64_t bucket_start_min = std::numeric_limits<int64_t>::max();
291 int64_t bucket_start_max = std::numeric_limits<int64_t>::max();
292 int64_t bucket_end_min = std::numeric_limits<int64_t>::min();
293 int64_t bucket_end_max = std::numeric_limits<int64_t>::min();
294 bool one_undecided =
false;
295 const PerformedStatus up_performed = ComputePropagationUp(
296 i, j, &bucket_start_min, &bucket_start_max, &bucket_end_min,
297 &bucket_end_max, &one_undecided);
298 InitNode(i, j, bucket_start_min, bucket_start_max, bucket_end_min,
299 bucket_end_max, up_performed);
306 void PropagateRoot() {
308 switch (RootPerformed()) {
310 target_var_->SetPerformed(
false);
313 target_var_->SetPerformed(
true);
314 ABSL_FALLTHROUGH_INTENDED;
316 target_var_->SetStartRange(RootStartMin(), RootStartMax());
317 target_var_->SetEndRange(RootEndMin(), RootEndMax());
327 void CoverVarChanged() {
328 PushDown(0, 0, TargetVarStartMin(), TargetVarStartMax(), TargetVarEndMin(),
329 TargetVarEndMax(), TargetVarPerformed());
332 void PushDown(
int depth,
int position, int64_t new_start_min,
333 int64_t new_start_max, int64_t new_end_min, int64_t new_end_max,
337 if (new_start_min <= StartMin(depth, position) &&
338 new_start_max >= StartMax(depth, position) &&
339 new_end_min <= EndMin(depth, position) &&
340 new_end_max >= EndMax(depth, position) &&
348 vars_[position]->SetPerformed(
false);
351 vars_[position]->SetPerformed(
true);
352 ABSL_FALLTHROUGH_INTENDED;
354 vars_[position]->SetStartRange(new_start_min, new_start_max);
355 vars_[position]->SetEndRange(new_end_min, new_end_max);
360 const int block_start = ChildStart(position);
361 const int block_end = ChildEnd(depth, position);
365 for (
int i = block_start;
i <= block_end; ++
i) {
366 PushDown(depth + 1, i, new_start_min, new_start_max, new_end_min,
367 new_end_max, UNPERFORMED);
373 int may_be_performed_count = 0;
374 int must_be_performed_count = 0;
375 for (
int i = block_start;
i <= block_end; ++
i) {
376 switch (Performed(depth + 1, i)) {
380 must_be_performed_count++;
381 ABSL_FALLTHROUGH_INTENDED;
383 may_be_performed_count++;
387 if (may_be_performed_count == 0) {
389 }
else if (may_be_performed_count == 1) {
390 PushDown(depth + 1, candidate, new_start_min, new_start_max,
391 new_end_min, new_end_max, PERFORMED);
393 for (
int i = block_start;
i <= block_end; ++
i) {
398 PushDown(depth + 1, i, new_start_min, new_end_max, new_start_min,
399 new_end_max, UNDECIDED);
405 for (
int i = block_start;
i <= block_end; ++
i) {
410 PushDown(depth + 1, i, new_start_min, new_end_max, new_start_min,
411 new_end_max, UNDECIDED);
417 void LeafChanged(
int term_index) {
418 ReduceDomain(MaxDepth(), term_index, VarStartMin(term_index),
419 VarStartMax(term_index), VarEndMin(term_index),
420 VarEndMax(term_index), VarPerformed(term_index));
422 const int parent = Parent(term_index);
423 const int parent_depth = MaxDepth() - 1;
424 const int64_t parent_start_min = StartMin(parent_depth, parent);
425 const int64_t parent_start_max = StartMax(parent_depth, parent);
426 const int64_t parent_end_min = EndMin(parent_depth, parent);
427 const int64_t parent_end_max = EndMax(parent_depth, parent);
428 IntervalVar*
const var =
vars_[term_index];
429 const bool performed_bound =
var->IsPerformedBound();
430 const bool was_performed_bound =
var->WasPerformedBound();
431 if (performed_bound == was_performed_bound &&
var->MayBePerformed() &&
432 var->OldStartMin() != parent_start_min &&
433 var->OldStartMax() != parent_start_max &&
434 var->OldEndMin() != parent_end_min &&
435 var->OldEndMax() != parent_end_max) {
443 void PushUp(
int position) {
444 int depth = MaxDepth();
446 const int parent = Parent(position);
447 const int parent_depth = depth - 1;
448 int64_t bucket_start_min = std::numeric_limits<int64_t>::max();
449 int64_t bucket_start_max = std::numeric_limits<int64_t>::max();
450 int64_t bucket_end_min = std::numeric_limits<int64_t>::min();
451 int64_t bucket_end_max = std::numeric_limits<int64_t>::min();
452 bool one_undecided =
false;
453 const PerformedStatus status_up = ComputePropagationUp(
454 parent_depth, parent, &bucket_start_min, &bucket_start_max,
455 &bucket_end_min, &bucket_end_max, &one_undecided);
456 if (bucket_start_min > StartMin(parent_depth, parent) ||
457 bucket_start_max < StartMax(parent_depth, parent) ||
458 bucket_end_min > EndMin(parent_depth, parent) ||
459 bucket_end_max < EndMax(parent_depth, parent) ||
460 status_up != Performed(parent_depth, parent)) {
461 ReduceDomain(parent_depth, parent, bucket_start_min, bucket_start_max,
462 bucket_end_min, bucket_end_max, status_up);
464 if (one_undecided && TargetVarPerformed() == PERFORMED) {
472 depth = parent_depth;
479 std::string DebugString()
const override {
483 void Accept(ModelVisitor*
const visitor)
const override {
488 PerformedStatus ComputePropagationUp(
int parent_depth,
int parent_position,
489 int64_t*
const bucket_start_min,
490 int64_t*
const bucket_start_max,
491 int64_t*
const bucket_end_min,
492 int64_t*
const bucket_end_max,
493 bool* one_undecided) {
494 *bucket_start_min = std::numeric_limits<int64_t>::max();
495 *bucket_start_max = std::numeric_limits<int64_t>::max();
496 *bucket_end_min = std::numeric_limits<int64_t>::min();
497 *bucket_end_max = std::numeric_limits<int64_t>::min();
499 int may_be_performed_count = 0;
500 int must_be_performed_count = 0;
501 const int block_start = ChildStart(parent_position);
502 const int block_end = ChildEnd(parent_depth, parent_position);
503 for (
int k = block_start; k <= block_end; ++k) {
504 const PerformedStatus
performed = Performed(parent_depth + 1, k);
507 std::min(*bucket_start_min, StartMin(parent_depth + 1, k));
509 std::max(*bucket_end_max, EndMax(parent_depth + 1, k));
510 may_be_performed_count++;
513 std::min(*bucket_start_max, StartMax(parent_depth + 1, k));
515 std::max(*bucket_end_min, EndMin(parent_depth + 1, k));
516 must_be_performed_count++;
520 const PerformedStatus up_performed =
521 must_be_performed_count > 0
523 : (may_be_performed_count > 0 ? UNDECIDED : UNPERFORMED);
525 (may_be_performed_count == 1) && (must_be_performed_count == 0);
532class IntervalEquality :
public Constraint {
534 IntervalEquality(Solver*
const solver, IntervalVar*
const var1,
535 IntervalVar*
const var2)
536 : Constraint(solver), var1_(var1), var2_(var2) {}
538 ~IntervalEquality()
override {}
540 void Post()
override {
541 Demon*
const demon = solver()->MakeConstraintInitialPropagateCallback(
this);
542 var1_->WhenAnything(demon);
543 var2_->WhenAnything(demon);
546 void InitialPropagate()
override {
548 if (!var1_->MayBePerformed()) {
549 var2_->SetPerformed(
false);
551 if (var1_->MustBePerformed()) {
552 var2_->SetPerformed(
true);
554 var2_->SetStartRange(var1_->StartMin(), var1_->StartMax());
555 var2_->SetDurationRange(var1_->DurationMin(), var1_->DurationMax());
556 var2_->SetEndRange(var1_->EndMin(), var1_->EndMax());
558 if (!var2_->MayBePerformed()) {
559 var1_->SetPerformed(
false);
561 if (var2_->MustBePerformed()) {
562 var1_->SetPerformed(
true);
564 var1_->SetStartRange(var2_->StartMin(), var2_->StartMax());
565 var1_->SetDurationRange(var2_->DurationMin(), var2_->DurationMax());
566 var1_->SetEndRange(var2_->EndMin(), var2_->EndMax());
570 std::string DebugString()
const override {
571 return absl::StrFormat(
"Equality(%s, %s)", var1_->DebugString(),
572 var2_->DebugString());
575 void Accept(ModelVisitor*
const visitor)
const override {
583 IntervalVar*
const var1_;
584 IntervalVar*
const var2_;
590 CHECK(!vars.empty());
591 if (vars.size() == 1) {
594 return RevAlloc(
new CoverConstraint(
this, vars, target_var));
600 return RevAlloc(
new IntervalEquality(
this, var1, var2));
const std::vector< IntVar * > vars_
static const char kTargetArgument[]
static const char kRightArgument[]
static const char kEquality[]
static const char kLeftArgument[]
static const char kCover[]
static const char kIntervalsArgument[]
Constraint * MakeEquality(IntExpr *left, IntExpr *right)
left == right
Constraint * MakeCover(const std::vector< IntervalVar * > &vars, IntervalVar *target_var)
const std::string name
A name for logging purposes.
In SWIG mode, we don't want anything besides these top-level includes.
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->DebugString().
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)