diff --git a/constraint_solver/assignment.cc b/constraint_solver/assignment.cc index d6014c540b..8b87ffe990 100644 --- a/constraint_solver/assignment.cc +++ b/constraint_solver/assignment.cc @@ -113,8 +113,8 @@ void IntervalVarElement::Copy(const IntervalVarElement& element) { } void IntervalVarElement::Store() { - performed_min_ = var_->PerformedMin(); - performed_max_ = var_->PerformedMax(); + performed_min_ = static_cast(var_->MustBePerformed()); + performed_max_ = static_cast(var_->MayBePerformed()); if (performed_max_ != 0LL) { start_min_ = var_->StartMin(); start_max_ = var_->StartMax(); diff --git a/constraint_solver/constraint_solver.h b/constraint_solver/constraint_solver.h index 1abdbd25c5..0b41fdc522 100644 --- a/constraint_solver/constraint_solver.h +++ b/constraint_solver/constraint_solver.h @@ -2387,8 +2387,11 @@ class IntervalVar : public PropagationBaseObject { // These methods query, set and watches the performed status of the // interval var. - virtual bool PerformedMin() const = 0; - virtual bool PerformedMax() const = 0; + virtual bool MustBePerformed() const = 0; + virtual bool MayBePerformed() const = 0; + bool IsPerformedBound() { + return MustBePerformed() == MayBePerformed(); + } virtual void SetPerformed(bool val) = 0; virtual void WhenPerformedBound(Demon* const d) = 0; diff --git a/constraint_solver/interval.cc b/constraint_solver/interval.cc index a01eaff46e..efc0e65156 100644 --- a/constraint_solver/interval.cc +++ b/constraint_solver/interval.cc @@ -65,8 +65,8 @@ class MirrorIntervalVar : public IntervalVar { // These methods query, set and watches the performed status of the // interval var. - virtual bool PerformedMin() const { return t_->PerformedMin(); } - virtual bool PerformedMax() const { return t_->PerformedMax(); } + virtual bool MustBePerformed() const { return t_->MustBePerformed(); } + virtual bool MayBePerformed() const { return t_->MayBePerformed(); } virtual void SetPerformed(bool val) { t_->SetPerformed(val); } virtual void WhenPerformedBound(Demon* const d) { t_->WhenPerformedBound(d); } @@ -224,7 +224,8 @@ class IntervalVarPerformedExpr : public BaseIntExpr { virtual ~IntervalVarPerformedExpr() {} virtual int64 Min() const { - return interval_->PerformedMin(); + // Returns 0ll or 1ll + return static_cast(interval_->MustBePerformed()); } virtual void SetMin(int64 m) { @@ -236,7 +237,8 @@ class IntervalVarPerformedExpr : public BaseIntExpr { } virtual int64 Max() const { - return interval_->PerformedMax(); + // Returns 0ll or 1ll + return static_cast(interval_->MayBePerformed()); } virtual void SetMax(int64 m) { @@ -257,7 +259,7 @@ class IntervalVarPerformedExpr : public BaseIntExpr { } virtual bool Bound() const { - return interval_->PerformedMin() == interval_->PerformedMax(); + return interval_->IsPerformedBound(); } virtual void WhenRange(Demon* d) { @@ -381,8 +383,8 @@ class FixedDurationIntervalVar : public IntervalVar { start_bound_demons_.PushIfNotTop(solver(), d); } - virtual bool PerformedMin() const; - virtual bool PerformedMax() const; + virtual bool MustBePerformed() const; + virtual bool MayBePerformed() const; virtual void SetPerformed(bool val); virtual void WhenPerformedBound(Demon* const d) { performed_bound_demons_.PushIfNotTop(solver(), d); @@ -640,11 +642,11 @@ void FixedDurationIntervalVar::SetDurationRange(int64 mi, int64 ma) { } } -bool FixedDurationIntervalVar::PerformedMin() const { +bool FixedDurationIntervalVar::MustBePerformed() const { return (performed_ == 1); } -bool FixedDurationIntervalVar::PerformedMax() const { +bool FixedDurationIntervalVar::MayBePerformed() const { return (performed_ != 0); } @@ -733,8 +735,8 @@ class FixedInterval : public IntervalVar { virtual void WhenEndRange(Demon* const d) {} virtual void WhenEndBound(Demon* const d) {} - virtual bool PerformedMin() const { return true; } - virtual bool PerformedMax() const { return true; } + virtual bool MustBePerformed() const { return true; } + virtual bool MayBePerformed() const { return true; } virtual void SetPerformed(bool val); virtual void WhenPerformedBound(Demon* const d) {} virtual string DebugString() const; diff --git a/constraint_solver/sched_search.cc b/constraint_solver/sched_search.cc index 8f4dd4d700..082ccb264a 100644 --- a/constraint_solver/sched_search.cc +++ b/constraint_solver/sched_search.cc @@ -69,7 +69,7 @@ class SetTimesForward : public DecisionBuilder { int refuted = 0; for (int i = 0; i < size_; ++i) { IntervalVar* const v = vars_[i]; - if (v->PerformedMax() != 0LL && v->StartMax() > v->StartMin()) { + if (v->MayBePerformed() && v->StartMax() > v->StartMin()) { if (v->StartMin() >= markers_[i] && (v->StartMin() < best_est || (v->StartMin() == best_est && v->EndMax() < best_lct))) { @@ -176,7 +176,7 @@ class RankFirstSequences : public DecisionBuilder { for (int i = 0; i < seq->size(); ++i) { if (seq->PossibleFirst(i)) { IntervalVar* t = seq->Interval(i); - if (t->PerformedMax() != 0LL && t->StartMin() < smin) { + if (t->MayBePerformed() && t->StartMin() < smin) { index = i; smin = t->StartMin(); } diff --git a/constraint_solver/timetabling.cc b/constraint_solver/timetabling.cc index d5a593b1b2..995781e815 100644 --- a/constraint_solver/timetabling.cc +++ b/constraint_solver/timetabling.cc @@ -70,7 +70,7 @@ class IntervalUnaryRelation : public Constraint { }; void IntervalUnaryRelation::Post() { - if (t_->PerformedMax() != 0) { + if (t_->MayBePerformed()) { Demon* d = solver()->MakeConstraintInitialPropagateCallback(this); t_->WhenStartRange(d); t_->WhenDurationRange(d); @@ -80,7 +80,7 @@ void IntervalUnaryRelation::Post() { } void IntervalUnaryRelation::InitialPropagate() { - if (t_->PerformedMax() == 1) { + if (t_->MayBePerformed()) { switch (rel_) { case Solver::ENDS_AFTER: t_->SetEndMin(d_); @@ -149,7 +149,13 @@ class IntervalBinaryRelation : public Constraint { }; void IntervalBinaryRelation::Post() { - if (t1_->PerformedMin() + t2_->PerformedMin() >= 1) { + if (t1_->MustBePerformed() || t2_->MustBePerformed()) { + // TODO(user): This was, before lhm's modifications: + // if (t1_->PerformedMin() + t2_->PerformedMin() >= 1) { + // the new expression corresponds exactly to that. However, I suspect it + // is actually intended to be: + // if (t1_->MayBePerformed() && t2_->MayBePerformed()) + // Please let me know -- lhm. Demon* d = solver()->MakeConstraintInitialPropagateCallback(this); t1_->WhenStartRange(d); t1_->WhenDurationRange(d); @@ -166,66 +172,66 @@ void IntervalBinaryRelation::Post() { void IntervalBinaryRelation::InitialPropagate() { switch (rel_) { case Solver::ENDS_AFTER_END: - if (t2_->PerformedMin() == 1 && t1_->PerformedMax() != 0) { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { t1_->SetEndMin(t2_->EndMin()); } - if (t1_->PerformedMin() == 1 && t2_->PerformedMax() != 0) { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { t2_->SetEndMax(t1_->EndMax()); } break; case Solver::ENDS_AFTER_START: - if (t2_->PerformedMin() == 1 && t1_->PerformedMax() != 0) { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { t1_->SetEndMin(t2_->StartMin()); } - if (t1_->PerformedMin() == 1 && t2_->PerformedMax() != 0) { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { t2_->SetStartMax(t1_->EndMax()); } break; case Solver::ENDS_AT_END: - if (t2_->PerformedMin() == 1 && t1_->PerformedMax() != 0) { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { t1_->SetEndRange(t2_->EndMin(), t2_->EndMax()); } - if (t1_->PerformedMin() == 1 && t2_->PerformedMax() != 0) { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { t2_->SetEndRange(t1_->EndMin(), t1_->EndMax()); } break; case Solver::ENDS_AT_START: - if (t2_->PerformedMin() == 1 && t1_->PerformedMax() != 0) { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { t1_->SetEndRange(t2_->StartMin(), t2_->StartMax()); } - if (t1_->PerformedMin() == 1 && t2_->PerformedMax() != 0) { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { t2_->SetStartRange(t1_->EndMin(), t1_->EndMax()); } break; case Solver::STARTS_AFTER_END: - if (t2_->PerformedMin() == 1 && t1_->PerformedMax() != 0) { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { t1_->SetStartMin(t2_->EndMin()); } - if (t1_->PerformedMin() == 1 && t2_->PerformedMax() != 0) { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { t2_->SetEndMax(t1_->StartMax()); } break; case Solver::STARTS_AFTER_START: - if (t2_->PerformedMin() == 1 && t1_->PerformedMax() != 0) { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { t1_->SetStartMin(t2_->StartMin()); } - if (t1_->PerformedMin() == 1 && t2_->PerformedMax() != 0) { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { t2_->SetEndMax(t1_->StartMax()); } break; case Solver::STARTS_AT_END: - if (t2_->PerformedMin() == 1 && t1_->PerformedMax() != 0) { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { t1_->SetStartRange(t2_->EndMin(), t2_->EndMax()); } - if (t1_->PerformedMin() == 1 && t2_->PerformedMax() != 0) { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { t2_->SetEndRange(t1_->StartMin(), t1_->StartMax()); } break; case Solver::STARTS_AT_START: - if (t2_->PerformedMin() == 1 && t1_->PerformedMax() != 0) { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { t1_->SetStartRange(t2_->StartMin(), t2_->StartMax()); } - if (t1_->PerformedMin() == 1 && t2_->PerformedMax() != 0) { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { t2_->SetStartRange(t1_->StartMin(), t1_->StartMax()); } break; @@ -313,8 +319,8 @@ string TemporalDisjunction::DebugString() const { void TemporalDisjunction::TryToDecide() { DCHECK_EQ(UNDECIDED, state_); - if (t1_->PerformedMax() + t2_->PerformedMax() == 2 && - t1_->PerformedMin() + t2_->PerformedMin() > 0) { + if (t1_->MayBePerformed() && t2_->MayBePerformed() && + (t1_->MustBePerformed() || t2_->MustBePerformed())) { if (t1_->EndMin() > t2_->StartMax()) { Decide(TWO_BEFORE_ONE); } else if (t2_->EndMin() > t1_->StartMax()) { @@ -326,13 +332,13 @@ void TemporalDisjunction::TryToDecide() { void TemporalDisjunction::RangeDemon1() { switch (state_) { case ONE_BEFORE_TWO: { - if (t1_->PerformedMin() == 1 && t2_->PerformedMax() != 0) { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { t2_->SetStartMin(t1_->EndMin()); } break; } case TWO_BEFORE_ONE: { - if (t1_->PerformedMin() == 1 && t2_->PerformedMax() != 0) { + if (t1_->MustBePerformed() && t2_->MayBePerformed()) { t2_->SetEndMax(t1_->StartMax()); } break; @@ -344,16 +350,16 @@ void TemporalDisjunction::RangeDemon1() { } void TemporalDisjunction::RangeDemon2() { - if (t1_->PerformedMax() == 1 || t2_->PerformedMax() == 1) { + if (t1_->MayBePerformed() || t2_->MayBePerformed()) { switch (state_) { case ONE_BEFORE_TWO: { - if (t2_->PerformedMin() == 1 && t1_->PerformedMax() != 0) { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { t1_->SetEndMax(t2_->StartMax()); } break; } case TWO_BEFORE_ONE: { - if (t2_->PerformedMin() == 1 && t1_->PerformedMax() != 0) { + if (t2_->MustBePerformed() && t1_->MayBePerformed()) { t1_->SetStartMin(t2_->EndMin()); } break; @@ -407,7 +413,7 @@ Constraint* Solver::MakeTemporalDisjunction(IntervalVar* const t1, // ----- Sequence ----- Constraint* MakeSequenceConstraintOnPerformed( - Solver* const s, const IntervalVar* const * intervals, int size); + Solver* const s, IntervalVar* const * intervals, int size); Sequence::Sequence(Solver* const s, const IntervalVar* const * intervals, @@ -445,9 +451,9 @@ void Sequence::Post() { int all_performed = 0; int all_decided = 0; for (int i = 0; i < size_; ++i) { - if (intervals_[i]->PerformedMax() == 0) { + if (!intervals_[i]->MayBePerformed()) { all_decided++; - } else if (intervals_[i]->PerformedMin() == 1) { + } else if (intervals_[i]->MustBePerformed()) { all_decided++; all_performed++; } @@ -460,7 +466,7 @@ void Sequence::Post() { } else if (all_decided == size_ && all_performed > 1) { vector performed; for (int i = 0; i < size_; ++i) { - if (intervals_[i]->PerformedMin() == 1) { + if (intervals_[i]->MustBePerformed()) { performed.push_back(intervals_[i]); } } @@ -497,17 +503,17 @@ void Sequence::Apply(int i, int j) { TryToDecide(i, j); } if (s == ONE_BEFORE_TWO) { - if (t1->PerformedMin() == 1 && t2->PerformedMax() != 0) { + if (t1->MustBePerformed() && t2->MayBePerformed()) { t2->SetStartMin(t1->EndMin()); } - if (t2->PerformedMin() == 1 && t1->PerformedMax() != 0) { + if (t2->MustBePerformed() && t1->MayBePerformed()) { t1->SetEndMax(t2->StartMax()); } } else if (s == TWO_BEFORE_ONE) { - if (t1->PerformedMin() == 1 && t2->PerformedMax() != 0) { + if (t1->MustBePerformed() && t2->MayBePerformed()) { t2->SetEndMax(t1->StartMax()); } - if (t2->PerformedMin() == 1 && t1->PerformedMax() != 0) { + if (t2->MustBePerformed() && t1->MayBePerformed()) { t1->SetStartMin(t2->EndMin()); } } @@ -518,8 +524,8 @@ void Sequence::TryToDecide(int i, int j) { DCHECK_EQ(UNDECIDED, states_[i][j]); IntervalVar* t1 = intervals_[i]; IntervalVar* t2 = intervals_[j]; - if (t1->PerformedMax() + t2->PerformedMax() == 2 && - t1->PerformedMin() + t2->PerformedMin() > 0) { + if (t1->MayBePerformed() && t2->MayBePerformed() && + (t1->MustBePerformed() || t2->MustBePerformed())) { if (t1->EndMin() > t2->StartMax()) { Decide(TWO_BEFORE_ONE, i, j); } else if (t2->EndMin() > t1->StartMax()) { @@ -558,8 +564,8 @@ void Sequence::DurationRange(int64* dmin, int64* dmax) const { int64 dur_max = 0; for (int i = 0; i < size_; ++i) { IntervalVar* t = intervals_[i]; - if (t->PerformedMax() == 1) { - if (t->PerformedMin() == 1) { + if (t->MayBePerformed()) { + if (t->MustBePerformed()) { dur_min += t->DurationMin(); } dur_max += t->DurationMax(); @@ -574,7 +580,7 @@ void Sequence::HorizonRange(int64* hmin, int64* hmax) const { int64 hor_max = kint64min; for (int i = 0; i < size_; ++i) { IntervalVar* t = intervals_[i]; - if (t->PerformedMax() == 1) { + if (t->MayBePerformed()) { const int64 tmin = t->StartMin(); const int64 tmax = t->EndMax(); if (tmin < hor_min) { @@ -594,7 +600,7 @@ void Sequence::ActiveHorizonRange(int64* hmin, int64* hmax) const { int64 hor_max = kint64min; for (int i = 0; i < size_; ++i) { IntervalVar* t = intervals_[i]; - if (t->PerformedMax() == 1 && ranks_[i] >= current_rank_) { + if (t->MayBePerformed() && ranks_[i] >= current_rank_) { const int64 tmin = t->StartMin(); const int64 tmax = t->EndMax(); if (tmin < hor_min) { @@ -612,7 +618,7 @@ void Sequence::ActiveHorizonRange(int64* hmin, int64* hmax) const { int Sequence::Ranked() const { int count = 0; for (int i = 0; i < size_; ++i) { - if (ranks_[i] < current_rank_ && intervals_[i]->PerformedMax() != 0) { + if (ranks_[i] < current_rank_ && intervals_[i]->MayBePerformed()) { count++; } } @@ -622,8 +628,7 @@ int Sequence::Ranked() const { int Sequence::NotRanked() const { int count = 0; for (int i = 0; i < size_; ++i) { - if (ranks_[i] >= current_rank_ && - intervals_[i]->PerformedMax() != 0) { + if (ranks_[i] >= current_rank_ && intervals_[i]->MayBePerformed()) { count++; } } @@ -633,7 +638,7 @@ int Sequence::NotRanked() const { int Sequence::Active() const { int count = 0; for (int i = 0; i < size_; ++i) { - if (intervals_[i]->PerformedMax() != 0) { + if (intervals_[i]->MayBePerformed()) { count++; } } @@ -643,7 +648,7 @@ int Sequence::Active() const { int Sequence::Fixed() const { int count = 0; for (int i = 0; i < size_; ++i) { - if (intervals_[i]->PerformedMin() == 1 && + if (intervals_[i]->MustBePerformed() && intervals_[i]->StartMin() == intervals_[i]->StartMax()) { count++; } @@ -657,7 +662,7 @@ void Sequence::ComputePossibleRanks() { int before = 0; int after = 0; for (int j = 0; j < i; ++j) { - if (intervals_[j]->PerformedMin() == 1) { + if (intervals_[j]->MustBePerformed()) { State s = states_[j][i]; if (s == ONE_BEFORE_TWO) { before++; @@ -667,7 +672,7 @@ void Sequence::ComputePossibleRanks() { } } for (int j = i + 1; j < size_; ++j) { - if (intervals_[j]->PerformedMin() == 1) { + if (intervals_[j]->MustBePerformed()) { State s = states_[i][j]; if (s == ONE_BEFORE_TWO) { after++; @@ -694,7 +699,7 @@ void Sequence::RankFirst(int index) { for (int i = 0; i < size_; ++i) { if (i != index && ranks_[i] >= current_rank_ && - intervals_[i]->PerformedMax() != 0LL) { + intervals_[i]->MayBePerformed()) { s->SaveAndSetValue(&ranks_[i], current_rank_ + 1); if (i < index) { Decide(TWO_BEFORE_ONE, i, index); @@ -712,7 +717,7 @@ void Sequence::RankNotFirst(int index) { int count = 0; int support = -1; for (int i = 0; i < size_; ++i) { - if (ranks_[i] == current_rank_ && intervals_[i]->PerformedMax() == 1) { + if (ranks_[i] == current_rank_ && intervals_[i]->MayBePerformed()) { count++; support = i; } @@ -720,7 +725,7 @@ void Sequence::RankNotFirst(int index) { if (count == 0) { solver()->Fail(); } - if (count == 1 && intervals_[support]->PerformedMin() == 1) { + if (count == 1 && intervals_[support]->MustBePerformed()) { RankFirst(support); } } @@ -1105,133 +1110,102 @@ string LambdaThetaTree::DebugString() const { return out; } -} // namespace - -class SequenceConstraintOnPerformed : public Constraint { +// One half of the SequenceConstraintOnPerformed. Must be coupled with a +// mirrored version to do the whole propagation. +class SequenceConstraintOnPerformedOneSided { public: - SequenceConstraintOnPerformed(Solver* const s, - const IntervalVar* const * intervals, - int size); - virtual ~SequenceConstraintOnPerformed(); - - virtual void Post() { - Demon* d = MakeDelayedConstraintDemon0( - solver(), - this, - &SequenceConstraintOnPerformed::InitialPropagate, - "InitialPropagate"); - for (int32 i = 0; i < size_; ++i) { - intervals_[i]->WhenStartRange(d); - intervals_[i]->WhenDurationRange(d); - intervals_[i]->WhenEndRange(d); - } + SequenceConstraintOnPerformedOneSided(Solver* const solver, + IntervalVar* const * intervals, + int size, + bool mirror); + ~SequenceConstraintOnPerformedOneSided() { + STLDeleteElements(&wrappers_); } - virtual void InitialPropagate(); - + int size() const { return size_; } + IntervalVar* const * intervals() { return intervals_.get(); } void UpdateEst(); void OverloadChecking(); bool DetectablePrecedences(); bool NotFirstNotLast(); bool EdgeFinder(); + private: + Solver* const solver_; scoped_array intervals_; const int size_; - ThetaTree theta_tree_; vector wrappers_; + + // --- All the following member variables are essentially used as local ones: + // no invariant is maintained about them, except for the fact that the vectors + // always contains all the considered intervals, so any function that wants to + // use them must first sort them in the right order. + + ThetaTree theta_tree_; vector ect_; vector est_; vector lct_; vector lst_; vector new_est_; - vector mwrappers_; - vector mect_; - vector mest_; - vector mlct_; - vector mlst_; vector new_lct_; LambdaThetaTree lt_tree_; }; -SequenceConstraintOnPerformed::SequenceConstraintOnPerformed( - Solver* const s, const IntervalVar* const * intervals, int size) - : Constraint(s), intervals_(new IntervalVar*[size]), - size_(size), theta_tree_(size), lt_tree_(size) { - memcpy(intervals_.get(), intervals, size_ * sizeof(*intervals)); +SequenceConstraintOnPerformedOneSided::SequenceConstraintOnPerformedOneSided( + Solver* const solver, + IntervalVar* const * intervals, + int size, + bool mirror) + : solver_(solver), + intervals_(new IntervalVar*[size]), + size_(size), theta_tree_(size), lt_tree_(size) { + // Populate of the array of intervals + if (mirror) { + for (int i = 0; i < size; ++i) { + intervals_[i] = solver->MakeMirrorInterval(intervals[i]); + } + } else { + memcpy(intervals_.get(), intervals, size_ * sizeof(*intervals)); + } for (int i = 0; i < size; ++i) { - IntervalWrapper* w = new IntervalWrapper(i, intervals_[i]); + IntervalWrapper* const w = new IntervalWrapper(i, intervals_[i]); wrappers_.push_back(w); ect_.push_back(w); est_.push_back(w); lct_.push_back(w); lst_.push_back(w); new_est_.push_back(kint64min); - IntervalVar* m = s->MakeMirrorInterval(intervals_[i]); - w = new IntervalWrapper(i, m); - mwrappers_.push_back(w); - mect_.push_back(w); - mest_.push_back(w); - mlct_.push_back(w); - mlst_.push_back(w); new_lct_.push_back(kint64max); } } -SequenceConstraintOnPerformed::~SequenceConstraintOnPerformed() { - STLDeleteElements(&wrappers_); - STLDeleteElements(&mwrappers_); -} - -void SequenceConstraintOnPerformed::UpdateEst() { +void SequenceConstraintOnPerformedOneSided::UpdateEst() { std::sort(est_.begin(), est_.end(), CompareESTLT); for (int i = 0; i < size_; ++i) { est_[i]->set_est_pos(i); } - std::sort(mest_.begin(), mest_.end(), CompareESTLT); - for (int i = 0; i < size_; ++i) { - mest_[i]->set_est_pos(i); - } } -void SequenceConstraintOnPerformed::InitialPropagate() { - do { - do { - do { - OverloadChecking(); - } while (DetectablePrecedences()); - } while (NotFirstNotLast()); - } while (EdgeFinder()); -} - -void SequenceConstraintOnPerformed::OverloadChecking() { +void SequenceConstraintOnPerformedOneSided::OverloadChecking() { // Init UpdateEst(); - - // One direction std::sort(lct_.begin(), lct_.end(), CompareLCTLT); theta_tree_.Clear(); - for (int i = 0; i < size_; ++i) { - IntervalWrapper* iw = lct_[i]; - theta_tree_.Insert(iw->interval(), iw->est_pos()); - if (theta_tree_.ECT() > iw->interval()->EndMax()) { - solver()->Fail(); - } - } - // Other direction - std::sort(mlct_.begin(), mlct_.end(), CompareLCTLT); - theta_tree_.Clear(); for (int i = 0; i < size_; ++i) { - IntervalWrapper* iw = mlct_[i]; + IntervalWrapper* const iw = lct_[i]; theta_tree_.Insert(iw->interval(), iw->est_pos()); if (theta_tree_.ECT() > iw->interval()->EndMax()) { - solver()->Fail(); + solver_->Fail(); } } } -bool SequenceConstraintOnPerformed::DetectablePrecedences() { +bool SequenceConstraintOnPerformedOneSided::DetectablePrecedences() { // Init UpdateEst(); + for (int i = 0; i < size_; ++i) { + new_est_[i] = kint64min; + } // Propagate in one direction std::sort(ect_.begin(), ect_.end(), CompareECTLT); @@ -1239,7 +1213,7 @@ bool SequenceConstraintOnPerformed::DetectablePrecedences() { theta_tree_.Clear(); int j = 0; for (int i = 0; i < size_; ++i) { - IntervalWrapper* twi = ect_[i]; + IntervalWrapper* const twi = ect_[i]; if (j < size_) { IntervalWrapper* twj = lst_[j]; while (twi->interval()->EndMin() > twj->interval()->StartMax()) { @@ -1266,39 +1240,6 @@ bool SequenceConstraintOnPerformed::DetectablePrecedences() { } } - // Propagate in other direction - std::sort(mect_.begin(), mect_.end(), CompareECTLT); - std::sort(mlst_.begin(), mlst_.end(), CompareLSTLT); - theta_tree_.Clear(); - j = 0; - for (int i = 0; i < size_; ++i) { - IntervalWrapper* twi = mect_[i]; - if (j < size_) { - IntervalWrapper* twj = mlst_[j]; - while (twi->interval()->EndMin() > twj->interval()->StartMax()) { - theta_tree_.Insert(twj->interval(), twj->est_pos()); - j++; - if (j == size_) - break; - twj = mlst_[j]; - } - } - const int64 lcti = twi->interval()->StartMin(); - bool inserted = theta_tree_.Inserted(twi->est_pos()); - if (inserted) { - theta_tree_.Remove(twi->est_pos()); - } - const int64 olcti = theta_tree_.ECT(); - if (inserted) { - theta_tree_.Insert(twi->interval(), twi->est_pos()); - } - if (olcti > lcti) { - new_lct_[twi->index()] = -olcti; - } else { - new_lct_[twi->index()] = kint64max; - } - } - // Apply modifications bool modified = false; for (int i = 0; i < size_; ++i) { @@ -1306,23 +1247,18 @@ bool SequenceConstraintOnPerformed::DetectablePrecedences() { modified = true; intervals_[i]->SetStartMin(new_est_[i]); } - if (new_lct_[i] != kint64max) { - modified = true; - intervals_[i]->SetEndMax(new_lct_[i]); - } } return modified; } -bool SequenceConstraintOnPerformed::NotFirstNotLast() { +bool SequenceConstraintOnPerformedOneSided::NotFirstNotLast() { // Init UpdateEst(); for (int i = 0; i < size_; ++i) { new_lct_[i] = intervals_[i]->EndMax(); - new_est_[i] = intervals_[i]->StartMin(); } - // Push in one direction. + // Push in one direction: update the latest completion time std::sort(lst_.begin(), lst_.end(), CompareLSTLT); std::sort(lct_.begin(), lct_.end(), CompareLCTLT); theta_tree_.Clear(); @@ -1351,54 +1287,22 @@ bool SequenceConstraintOnPerformed::NotFirstNotLast() { } } - // Push in other direction. - std::sort(mlst_.begin(), mlst_.end(), CompareLSTLT); - std::sort(mlct_.begin(), mlct_.end(), CompareLCTLT); - theta_tree_.Clear(); - j = 0; - for (int i = 0; i < size_; ++i) { - IntervalWrapper* twi = mlct_[i]; - while (j < size_ && - twi->interval()->EndMax() > mlst_[j]->interval()->StartMax()) { - if (j > 0 && theta_tree_.ECT() > mlst_[j]->interval()->StartMax()) { - new_est_[mlst_[j]->index()] = -mlst_[j - 1]->interval()->StartMax(); - } - theta_tree_.Insert(mlst_[j]->interval(), mlst_[j]->est_pos()); - j++; - } - bool inserted = theta_tree_.Inserted(twi->est_pos()); - if (inserted) { - theta_tree_.Remove(twi->est_pos()); - } - const int64 mect_theta_less_i = theta_tree_.ECT(); - if (inserted) { - theta_tree_.Insert(twi->interval(), twi->est_pos()); - } - if (mect_theta_less_i > twi->interval()->EndMax() && j > 0) { - new_est_[twi->index()] = - max(new_est_[twi->index()], -mlst_[j - 1]->interval()->EndMax()); - } - } - // Apply modifications bool modified = false; for (int i = 0; i < size_; ++i) { - if (intervals_[i]->EndMax() > new_lct_[i] || - intervals_[i]->StartMin() < new_est_[i]) { + if (intervals_[i]->EndMax() > new_lct_[i]) { modified = true; - intervals_[i]->SetStartMin(new_est_[i]); intervals_[i]->SetEndMax(new_lct_[i]); } } return modified; } -bool SequenceConstraintOnPerformed::EdgeFinder() { +bool SequenceConstraintOnPerformedOneSided::EdgeFinder() { // Init UpdateEst(); for (int i = 0; i < size_; ++i) { new_est_[i] = intervals_[i]->StartMin(); - new_lct_[i] = intervals_[i]->EndMax(); } // Push in one direction. @@ -1417,7 +1321,7 @@ bool SequenceConstraintOnPerformed::EdgeFinder() { } twj = lct_[j]; if (lt_tree_.ECT() > twj->interval()->EndMax()) { - solver()->Fail(); // Resource is overloaded + solver_->Fail(); // Resource is overloaded } while (lt_tree_.ECT_opt() > twj->interval()->EndMax()) { const int i = lt_tree_.Responsible_opt(); @@ -1430,51 +1334,70 @@ bool SequenceConstraintOnPerformed::EdgeFinder() { } } while (j >= 0); - // Push in other direction. - std::sort(mlct_.begin(), mlct_.end(), CompareLCTLT); - lt_tree_.Clear(); - for (int i = 0; i < size_; ++i) { - lt_tree_.Insert(mest_[i]->interval(), i); - DCHECK_EQ(i, mest_[i]->est_pos()); - } - j = size_ - 1; - twj = mlct_[j]; - do { - lt_tree_.Grey(twj->est_pos()); - if (--j < 0) { - break; - } - twj = mlct_[j]; - if (lt_tree_.ECT() > twj->interval()->EndMax()) { - solver()->Fail(); // Resource is overloaded - } - while (lt_tree_.ECT_opt() > twj->interval()->EndMax()) { - const int i = lt_tree_.Responsible_opt(); - DCHECK_GE(i, 0); - const int act_i = mest_[i]->index(); - if (-lt_tree_.ECT() < new_lct_[act_i]) { - new_lct_[act_i] = -lt_tree_.ECT(); - } - lt_tree_.Remove(i); - } - } while (j >= 0); - // Apply modifications. bool modified = false; for (int i = 0; i < size_; ++i) { - if (intervals_[i]->EndMax() > new_lct_[i] || - intervals_[i]->StartMin() < new_est_[i]) { + if (intervals_[i]->StartMin() < new_est_[i]) { modified = true; intervals_[i]->SetStartMin(new_est_[i]); - intervals_[i]->SetEndMax(new_lct_[i]); } } return modified; } +class SequenceConstraintOnPerformed : public Constraint { + public: + SequenceConstraintOnPerformed(Solver* const s, + IntervalVar* const * intervals, + int size); + virtual ~SequenceConstraintOnPerformed() { } + + virtual void Post() { + Demon* d = MakeDelayedConstraintDemon0( + solver(), + this, + &SequenceConstraintOnPerformed::InitialPropagate, + "InitialPropagate"); + for (int32 i = 0; i < straight_.size(); ++i) { + IntervalVar* interval_var = straight_.intervals()[i]; + interval_var->WhenStartRange(d); + interval_var->WhenDurationRange(d); + interval_var->WhenEndRange(d); + } + } + + virtual void InitialPropagate() { + do { + do { + do { + straight_.OverloadChecking(); + mirror_.OverloadChecking(); + } while (straight_.DetectablePrecedences() || + mirror_.DetectablePrecedences()); + } while (straight_.NotFirstNotLast() || + mirror_.NotFirstNotLast()); + } while (straight_.EdgeFinder() || + mirror_.EdgeFinder()); + } + + private: + SequenceConstraintOnPerformedOneSided straight_; + SequenceConstraintOnPerformedOneSided mirror_; +}; + +SequenceConstraintOnPerformed::SequenceConstraintOnPerformed(Solver* const s, + IntervalVar* const * intervals, + int size) +: Constraint(s), + straight_(s, intervals, size, false), + mirror_(s, intervals, size, true) { +} + +} // namespace + Constraint* MakeSequenceConstraintOnPerformed(Solver* const s, - const IntervalVar* const * intervals, - int size) { + IntervalVar* const * intervals, + int size) { return s->RevAlloc(new SequenceConstraintOnPerformed(s, intervals, size)); }