29#include "absl/strings/str_format.h"
39class TreeArrayConstraint :
public Constraint {
41 enum PerformedStatus { UNPERFORMED, PERFORMED, UNDECIDED };
43 TreeArrayConstraint(Solver*
const solver,
44 const std::vector<IntervalVar*>& vars,
45 IntervalVar*
const target_var)
49 block_size_(solver->
parameters().array_split_size()) {
50 std::vector<int> lengths;
51 lengths.push_back(
vars_.size());
52 while (lengths.back() > 1) {
53 const int current = lengths.back();
54 lengths.push_back((current + block_size_ - 1) / block_size_);
56 tree_.resize(lengths.size());
57 for (
int i = 0; i < lengths.size(); ++i) {
58 tree_[i].resize(lengths[lengths.size() - i - 1]);
62 root_node_ = &tree_[0][0];
65 std::string DebugStringInternal(
const std::string&
name)
const {
70 void AcceptInternal(
const std::string&
name,
71 ModelVisitor*
const visitor)
const {
72 visitor->BeginVisitConstraint(
name,
this);
76 visitor->EndVisitConstraint(
name,
this);
80 void ReduceDomain(
int depth,
int position, int64_t new_start_min,
81 int64_t new_start_max, int64_t new_end_min,
82 int64_t new_end_max, PerformedStatus
performed) {
83 NodeInfo*
const info = &tree_[depth][position];
84 if (new_start_min > info->start_min.Value()) {
85 info->start_min.SetValue(solver(), new_start_min);
87 if (new_start_max < info->
start_max.Value()) {
88 info->start_max.SetValue(solver(), new_start_max);
90 if (new_end_min > info->end_min.Value()) {
91 info->end_min.SetValue(solver(), new_end_min);
93 if (new_end_max < info->
end_max.Value()) {
94 info->end_max.SetValue(solver(), new_end_max);
98 info->performed.Value() == UNDECIDED);
99 info->performed.SetValue(solver(),
performed);
111 tree_[depth][position].start_min.SetValue(solver(),
start_min);
112 tree_[depth][position].start_max.SetValue(solver(),
start_max);
113 tree_[depth][position].end_min.SetValue(solver(),
end_min);
114 tree_[depth][position].end_max.SetValue(solver(),
end_max);
115 tree_[depth][position].performed.SetValue(solver(),
119 int64_t StartMin(
int depth,
int position)
const {
120 return tree_[depth][position].start_min.Value();
123 int64_t StartMax(
int depth,
int position)
const {
124 return tree_[depth][position].start_max.Value();
127 int64_t EndMax(
int depth,
int position)
const {
128 return tree_[depth][position].end_max.Value();
131 int64_t EndMin(
int depth,
int position)
const {
132 return tree_[depth][position].end_min.Value();
135 PerformedStatus Performed(
int depth,
int position)
const {
136 const int p = tree_[depth][position].performed.Value();
139 return static_cast<PerformedStatus
>(p);
142 int64_t RootStartMin()
const {
return root_node_->start_min.Value(); }
144 int64_t RootStartMax()
const {
return root_node_->start_max.Value(); }
146 int64_t RootEndMin()
const {
return root_node_->end_min.Value(); }
148 int64_t RootEndMax()
const {
return root_node_->end_max.Value(); }
150 PerformedStatus RootPerformed()
const {
return Performed(0, 0); }
154 int64_t VarStartMin(
int position)
const {
155 return vars_[position]->MayBePerformed() ?
vars_[position]->StartMin() : 0;
158 int64_t VarStartMax(
int position)
const {
159 return vars_[position]->MayBePerformed() ?
vars_[position]->StartMax() : 0;
162 int64_t VarEndMin(
int position)
const {
163 return vars_[position]->MayBePerformed() ?
vars_[position]->EndMin() : 0;
166 int64_t VarEndMax(
int position)
const {
167 return vars_[position]->MayBePerformed() ?
vars_[position]->EndMax() : 0;
170 int64_t TargetVarStartMin()
const {
174 int64_t TargetVarStartMax()
const {
178 int64_t TargetVarEndMin()
const {
182 int64_t TargetVarEndMax()
const {
188 PerformedStatus VarPerformed(
int position)
const {
189 IntervalVar*
const var =
vars_[position];
190 if (
var->MustBePerformed()) {
192 }
else if (
var->MayBePerformed()) {
200 PerformedStatus TargetVarPerformed()
const {
211 int Parent(
int position)
const {
return position / block_size_; }
214 int ChildStart(
int position)
const {
return position * block_size_; }
219 int ChildEnd(
int depth,
int position)
const {
221 return std::min((position + 1) * block_size_ - 1, Width(depth + 1) - 1);
224 bool IsLeaf(
int depth)
const {
return depth == MaxDepth(); }
226 int MaxDepth()
const {
return tree_.size() - 1; }
228 int Width(
int depth)
const {
return tree_[depth].size(); }
231 const std::vector<IntervalVar*>
vars_;
250 std::vector<std::vector<NodeInfo> > tree_;
251 const int block_size_;
252 NodeInfo* root_node_;
256class CoverConstraint :
public TreeArrayConstraint {
258 CoverConstraint(Solver*
const solver,
const std::vector<IntervalVar*>& vars,
259 IntervalVar*
const cover_var)
260 : TreeArrayConstraint(solver, vars, cover_var), cover_demon_(
nullptr) {}
262 ~CoverConstraint()
override {}
264 void Post()
override {
265 for (
int i = 0; i <
vars_.size(); ++i) {
267 solver(),
this, &CoverConstraint::LeafChanged,
"LeafChanged", i);
268 vars_[i]->WhenStartRange(demon);
269 vars_[i]->WhenEndRange(demon);
270 vars_[i]->WhenPerformedBound(demon);
273 solver(),
this, &CoverConstraint::CoverVarChanged,
"CoverVarChanged"));
279 void InitialPropagate()
override {
281 for (
int i = 0; i <
vars_.size(); ++i) {
282 InitLeaf(i, VarStartMin(i), VarStartMax(i), VarEndMin(i), VarEndMax(i),
287 for (
int i = MaxDepth() - 1; i >= 0; --i) {
288 for (
int j = 0; j < Width(i); ++j) {
293 bool one_undecided =
false;
294 const PerformedStatus up_performed = ComputePropagationUp(
295 i, j, &bucket_start_min, &bucket_start_max, &bucket_end_min,
296 &bucket_end_max, &one_undecided);
297 InitNode(i, j, bucket_start_min, bucket_start_max, bucket_end_min,
298 bucket_end_max, up_performed);
305 void PropagateRoot() {
307 switch (RootPerformed()) {
313 ABSL_FALLTHROUGH_INTENDED;
315 target_var_->SetStartRange(RootStartMin(), RootStartMax());
316 target_var_->SetEndRange(RootEndMin(), RootEndMax());
326 void CoverVarChanged() {
327 PushDown(0, 0, TargetVarStartMin(), TargetVarStartMax(), TargetVarEndMin(),
328 TargetVarEndMax(), TargetVarPerformed());
331 void PushDown(
int depth,
int position, int64_t new_start_min,
332 int64_t new_start_max, int64_t new_end_min, int64_t new_end_max,
336 if (new_start_min <= StartMin(depth, position) &&
337 new_start_max >= StartMax(depth, position) &&
338 new_end_min <= EndMin(depth, position) &&
339 new_end_max >= EndMax(depth, position) &&
347 vars_[position]->SetPerformed(
false);
350 vars_[position]->SetPerformed(
true);
351 ABSL_FALLTHROUGH_INTENDED;
353 vars_[position]->SetStartRange(new_start_min, new_start_max);
354 vars_[position]->SetEndRange(new_end_min, new_end_max);
359 const int block_start = ChildStart(position);
360 const int block_end = ChildEnd(depth, position);
364 for (
int i = block_start; i <= block_end; ++i) {
365 PushDown(depth + 1, i, new_start_min, new_start_max, new_end_min,
366 new_end_max, UNPERFORMED);
372 int may_be_performed_count = 0;
373 int must_be_performed_count = 0;
374 for (
int i = block_start; i <= block_end; ++i) {
375 switch (Performed(depth + 1, i)) {
379 must_be_performed_count++;
380 ABSL_FALLTHROUGH_INTENDED;
382 may_be_performed_count++;
386 if (may_be_performed_count == 0) {
388 }
else if (may_be_performed_count == 1) {
389 PushDown(depth + 1, candidate, new_start_min, new_start_max,
390 new_end_min, new_end_max, PERFORMED);
392 for (
int i = block_start; i <= block_end; ++i) {
397 PushDown(depth + 1, i, new_start_min, new_end_max, new_start_min,
398 new_end_max, UNDECIDED);
404 for (
int i = block_start; i <= block_end; ++i) {
409 PushDown(depth + 1, i, new_start_min, new_end_max, new_start_min,
410 new_end_max, UNDECIDED);
416 void LeafChanged(
int term_index) {
417 ReduceDomain(MaxDepth(), term_index, VarStartMin(term_index),
418 VarStartMax(term_index), VarEndMin(term_index),
419 VarEndMax(term_index), VarPerformed(term_index));
421 const int parent = Parent(term_index);
422 const int parent_depth = MaxDepth() - 1;
423 const int64_t parent_start_min = StartMin(parent_depth, parent);
424 const int64_t parent_start_max = StartMax(parent_depth, parent);
425 const int64_t parent_end_min = EndMin(parent_depth, parent);
426 const int64_t parent_end_max = EndMax(parent_depth, parent);
427 IntervalVar*
const var =
vars_[term_index];
428 const bool performed_bound =
var->IsPerformedBound();
429 const bool was_performed_bound =
var->WasPerformedBound();
430 if (performed_bound == was_performed_bound &&
var->MayBePerformed() &&
431 var->OldStartMin() != parent_start_min &&
432 var->OldStartMax() != parent_start_max &&
433 var->OldEndMin() != parent_end_min &&
434 var->OldEndMax() != parent_end_max) {
442 void PushUp(
int position) {
443 int depth = MaxDepth();
445 const int parent = Parent(position);
446 const int parent_depth = depth - 1;
451 bool one_undecided =
false;
452 const PerformedStatus status_up = ComputePropagationUp(
453 parent_depth, parent, &bucket_start_min, &bucket_start_max,
454 &bucket_end_min, &bucket_end_max, &one_undecided);
455 if (bucket_start_min > StartMin(parent_depth, parent) ||
456 bucket_start_max < StartMax(parent_depth, parent) ||
457 bucket_end_min > EndMin(parent_depth, parent) ||
458 bucket_end_max < EndMax(parent_depth, parent) ||
459 status_up != Performed(parent_depth, parent)) {
460 ReduceDomain(parent_depth, parent, bucket_start_min, bucket_start_max,
461 bucket_end_min, bucket_end_max, status_up);
463 if (one_undecided && TargetVarPerformed() == PERFORMED) {
471 depth = parent_depth;
478 std::string DebugString()
const override {
482 void Accept(ModelVisitor*
const visitor)
const override {
487 PerformedStatus ComputePropagationUp(
int parent_depth,
int parent_position,
488 int64_t*
const bucket_start_min,
489 int64_t*
const bucket_start_max,
490 int64_t*
const bucket_end_min,
491 int64_t*
const bucket_end_max,
492 bool* one_undecided) {
498 int may_be_performed_count = 0;
499 int must_be_performed_count = 0;
500 const int block_start = ChildStart(parent_position);
501 const int block_end = ChildEnd(parent_depth, parent_position);
502 for (
int k = block_start; k <= block_end; ++k) {
503 const PerformedStatus
performed = Performed(parent_depth + 1, k);
506 std::min(*bucket_start_min, StartMin(parent_depth + 1, k));
508 std::max(*bucket_end_max, EndMax(parent_depth + 1, k));
509 may_be_performed_count++;
512 std::min(*bucket_start_max, StartMax(parent_depth + 1, k));
514 std::max(*bucket_end_min, EndMin(parent_depth + 1, k));
515 must_be_performed_count++;
519 const PerformedStatus up_performed =
520 must_be_performed_count > 0
522 : (may_be_performed_count > 0 ? UNDECIDED : UNPERFORMED);
524 (may_be_performed_count == 1) && (must_be_performed_count == 0);
531class IntervalEquality :
public Constraint {
533 IntervalEquality(Solver*
const solver, IntervalVar*
const var1,
534 IntervalVar*
const var2)
535 : Constraint(solver), var1_(var1), var2_(var2) {}
537 ~IntervalEquality()
override {}
539 void Post()
override {
540 Demon*
const demon = solver()->MakeConstraintInitialPropagateCallback(
this);
541 var1_->WhenAnything(demon);
542 var2_->WhenAnything(demon);
545 void InitialPropagate()
override {
547 if (!var1_->MayBePerformed()) {
548 var2_->SetPerformed(
false);
550 if (var1_->MustBePerformed()) {
551 var2_->SetPerformed(
true);
553 var2_->SetStartRange(var1_->StartMin(), var1_->StartMax());
554 var2_->SetDurationRange(var1_->DurationMin(), var1_->DurationMax());
555 var2_->SetEndRange(var1_->EndMin(), var1_->EndMax());
557 if (!var2_->MayBePerformed()) {
558 var1_->SetPerformed(
false);
560 if (var2_->MustBePerformed()) {
561 var1_->SetPerformed(
true);
563 var1_->SetStartRange(var2_->StartMin(), var2_->StartMax());
564 var1_->SetDurationRange(var2_->DurationMin(), var2_->DurationMax());
565 var1_->SetEndRange(var2_->EndMin(), var2_->EndMax());
569 std::string DebugString()
const override {
570 return absl::StrFormat(
"Equality(%s, %s)", var1_->DebugString(),
571 var2_->DebugString());
574 void Accept(ModelVisitor*
const visitor)
const override {
582 IntervalVar*
const var1_;
583 IntervalVar*
const var2_;
589 CHECK(!vars.empty());
590 if (vars.size() == 1) {
593 return RevAlloc(
new CoverConstraint(
this, vars, target_var));
599 return RevAlloc(
new IntervalEquality(
this, var1, var2));
#define CHECK_GE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_LT(val1, val2)
#define CHECK_LE(val1, val2)
#define DCHECK_EQ(val1, val2)
A constraint is the main modeling object.
Interval variables are often used in scheduling.
static const char kTargetArgument[]
static const char kIntervalsArgument[]
static const char kLeftArgument[]
static const char kRightArgument[]
static const char kCover[]
static const char kEquality[]
Constraint * MakeEquality(IntExpr *const left, IntExpr *const right)
left == right
Constraint * MakeCover(const std::vector< IntervalVar * > &vars, IntervalVar *const target_var)
This constraint states that the target_var is the convex hull of the intervals.
T * RevAlloc(T *object)
Registers the given object as being reversible.
Collection of objects used to extend the Constraint Solver library.
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
IntervalVar *const target_var_
const std::vector< IntervalVar * > vars_