From 6ebaffe02142b94d8fb13c25c57c0e86f454b097 Mon Sep 17 00:00:00 2001 From: "lperron@google.com" Date: Mon, 26 May 2014 17:59:03 +0000 Subject: [PATCH] experimental code, create interval variable from start and performed variables (fixed duration) --- src/constraint_solver/constraint_solver.h | 24 ++ src/constraint_solver/interval.cc | 282 +++++++++++++++++++++- 2 files changed, 304 insertions(+), 2 deletions(-) diff --git a/src/constraint_solver/constraint_solver.h b/src/constraint_solver/constraint_solver.h index 812a03b50a..4b84b4a3b0 100644 --- a/src/constraint_solver/constraint_solver.h +++ b/src/constraint_solver/constraint_solver.h @@ -1796,6 +1796,14 @@ class Solver { IntervalVar* MakeFixedDurationIntervalVar(IntVar* const start_variable, int64 duration, const std::string& name); + // Creates an interval var with a fixed duration, and performed var. + // The duration must be greater than 0. + IntervalVar* MakeFixedDurationIntervalVar(IntVar* const start_variable, + int64 duration, + IntVar* const performed_var, + const std::string& name); + + // This method fills the vector with 'count' interval var built with // the corresponding start variables. void MakeFixedDurationIntervalVarArray(const std::vector& start_variables, @@ -1815,6 +1823,22 @@ class Solver { const std::string& name, std::vector* const array); + // This method fills the vector with interval variables built with + // the corresponding start and performed variables. + void MakeFixedDurationIntervalVarArray(const std::vector& start_variables, + const std::vector& durations, + const std::vector& performed_variables, + const std::string& name, + std::vector* const array); + + // This method fills the vector with interval variables built with + // the corresponding start and performed variables. + void MakeFixedDurationIntervalVarArray(const std::vector& start_variables, + const std::vector& durations, + const std::vector& performed_variables, + const std::string& name, + std::vector* const array); + // Creates a fixed and performed interval. IntervalVar* MakeFixedInterval(int64 start, int64 duration, const std::string& name); diff --git a/src/constraint_solver/interval.cc b/src/constraint_solver/interval.cc index 9811a728fa..093b93aff4 100644 --- a/src/constraint_solver/interval.cc +++ b/src/constraint_solver/interval.cc @@ -1320,6 +1320,237 @@ std::string StartVarPerformedIntervalVar::DebugString() const { return out; } +// ----- StartVarIntervalVar ----- + +class StartVarIntervalVar : public BaseIntervalVar { + public: + StartVarIntervalVar(Solver* const s, IntVar* const start, int64 duration, + IntVar* const performed, const string& name); + virtual ~StartVarIntervalVar() {} + + virtual int64 StartMin() const; + virtual int64 StartMax() const; + virtual void SetStartMin(int64 m); + virtual void SetStartMax(int64 m); + virtual void SetStartRange(int64 mi, int64 ma); + virtual int64 OldStartMin() const { return start_->OldMin(); } + virtual int64 OldStartMax() const { return start_->OldMax(); } + virtual void WhenStartRange(Demon* const d) { + if (performed_->Max() == 1) { + start_->WhenRange(d); + } + } + virtual void WhenStartBound(Demon* const d) { + if (performed_->Max() == 1) { + start_->WhenBound(d); + } + } + + virtual int64 DurationMin() const; + virtual int64 DurationMax() const; + virtual void SetDurationMin(int64 m); + virtual void SetDurationMax(int64 m); + virtual void SetDurationRange(int64 mi, int64 ma); + virtual int64 OldDurationMin() const { return duration_; } + virtual int64 OldDurationMax() const { return duration_; } + virtual void WhenDurationRange(Demon* const d) {} + virtual void WhenDurationBound(Demon* const d) {} + + virtual int64 EndMin() const; + virtual int64 EndMax() const; + virtual void SetEndMin(int64 m); + virtual void SetEndMax(int64 m); + virtual void SetEndRange(int64 mi, int64 ma); + virtual int64 OldEndMin() const { return CapAdd(OldStartMin(), duration_); } + virtual int64 OldEndMax() const { return CapAdd(OldStartMax(), duration_); } + virtual void WhenEndRange(Demon* const d) { WhenStartRange(d); } + virtual void WhenEndBound(Demon* const d) { WhenStartBound(d); } + + virtual bool MustBePerformed() const; + virtual bool MayBePerformed() const; + virtual void SetPerformed(bool val); + virtual bool WasPerformedBound() const { + return performed_->OldMin() == performed_->OldMax(); + } + virtual void WhenPerformedBound(Demon* const d) { performed_->WhenBound(d); } + virtual string DebugString() const; + + virtual void Accept(ModelVisitor* const visitor) const { + visitor->VisitIntervalVariable(this, "", 0, NullInterval()); + } + + virtual IntExpr* StartExpr() { return start_; } + virtual IntExpr* DurationExpr() { return solver()->MakeIntConst(duration_); } + virtual IntExpr* EndExpr() { + return solver()->MakeSum(StartExpr(), duration_); + } + virtual IntExpr* PerformedExpr() { return performed_; } + virtual IntExpr* SafeStartExpr(int64 unperformed_value) { + return BuildSafeStartExpr(this, unperformed_value); + } + virtual IntExpr* SafeDurationExpr(int64 unperformed_value) { + return BuildSafeDurationExpr(this, unperformed_value); + } + virtual IntExpr* SafeEndExpr(int64 unperformed_value) { + return BuildSafeEndExpr(this, unperformed_value); + } + + virtual void Process() { LOG(FATAL) << "Should not be here"; } + + virtual void Push() { LOG(FATAL) << "Should not be here"; } + + private: + IntVar* const start_; + int64 duration_; + IntVar* const performed_; + Rev start_min_; + Rev start_max_; +}; + +StartVarIntervalVar::StartVarIntervalVar(Solver* const s, IntVar* const start, + int64 duration, + IntVar* const performed, + const string& name) + : BaseIntervalVar(s, name), + start_(start), + duration_(duration), + performed_(performed), + start_min_(start->Min()), + start_max_(start->Max()) {} + +int64 StartVarIntervalVar::StartMin() const { + CHECK_EQ(performed_->Max(), 1); + return std::max(start_->Min(), start_min_.Value()); +} + +int64 StartVarIntervalVar::StartMax() const { + CHECK_EQ(performed_->Max(), 1); + return std::min(start_->Max(), start_max_.Value()); +} + +void StartVarIntervalVar::SetStartMin(int64 m) { +if (performed_->Min() == 1) { + start_->SetMin(m); + } else { + start_min_.SetValue(solver(), std::max(m, start_min_.Value())); + if (start_min_.Value() > start_max_.Value()) { + performed_->SetValue(0); + } + } +} + +void StartVarIntervalVar::SetStartMax(int64 m) { + if (performed_->Min() == 1) { + start_->SetMax(m); + } else { + start_max_.SetValue(solver(), std::min(m, start_max_.Value())); + if (start_min_.Value() > start_max_.Value()) { + performed_->SetValue(0); + } + } +} + +void StartVarIntervalVar::SetStartRange(int64 mi, int64 ma) { + if (performed_->Min() == 1) { + start_->SetRange(mi, ma); + } else { + start_min_.SetValue(solver(), std::max(mi, start_min_.Value())); + start_max_.SetValue(solver(), std::min(ma, start_max_.Value())); + if (start_min_.Value() > start_max_.Value()) { + performed_->SetValue(0); + } + } +} + +int64 StartVarIntervalVar::DurationMin() const { + CHECK_EQ(performed_->Max(), 1); + return duration_; +} + +int64 StartVarIntervalVar::DurationMax() const { + CHECK_EQ(performed_->Max(), 1); + return duration_; +} + +void StartVarIntervalVar::SetDurationMin(int64 m) { + if (m > duration_) { + SetPerformed(false); + } +} + +void StartVarIntervalVar::SetDurationMax(int64 m) { + if (m < duration_) { + SetPerformed(false); + } +} + +void StartVarIntervalVar::SetDurationRange(int64 mi, int64 ma) { + if (mi > duration_ || ma < duration_ || mi > ma) { + SetPerformed(false); + } +} + +int64 StartVarIntervalVar::EndMin() const { + CHECK_EQ(performed_->Max(), 1); + return CapAdd(StartMin(), duration_); +} + +int64 StartVarIntervalVar::EndMax() const { + CHECK_EQ(performed_->Max(), 1); + return CapAdd(StartMax(), duration_); +} + +void StartVarIntervalVar::SetEndMin(int64 m) { + SetStartMin(CapSub(m, duration_)); +} + +void StartVarIntervalVar::SetEndMax(int64 m) { + SetStartMax(CapSub(m, duration_)); +} + +void StartVarIntervalVar::SetEndRange(int64 mi, int64 ma) { + SetStartRange(CapSub(mi, duration_), CapSub(ma, duration_)); +} + +bool StartVarIntervalVar::MustBePerformed() const { + return (performed_->Min() == 1); +} + +bool StartVarIntervalVar::MayBePerformed() const { + return (performed_->Max() == 1); +} + +void StartVarIntervalVar::SetPerformed(bool val) { + const bool was_bound = performed_->Bound(); + performed_->SetValue(val); + if (val && !was_bound) { + start_->SetRange(start_min_.Value(), start_max_.Value()); + } +} + +string StartVarIntervalVar::DebugString() const { + const std::string& var_name = name(); + if (performed_->Max() == 0) { + if (!var_name.empty()) { + return StringPrintf("%s(performed = false)", var_name.c_str()); + } else { + return "IntervalVar(performed = false)"; + } + } else { + string out; + if (!var_name.empty()) { + out = var_name + "(start = "; + } else { + out = "IntervalVar(start = "; + } + StringAppendF(&out, "%s, duration = %" GG_LL_FORMAT "d, performed = %s)", + start_->DebugString().c_str(), duration_, + performed_->DebugString().c_str()); + return out; + } +} + + // ----- FixedInterval ----- class FixedInterval : public IntervalVar { @@ -1997,6 +2228,25 @@ IntervalVar* Solver::MakeFixedDurationIntervalVar(IntVar* const start_variable, new StartVarPerformedIntervalVar(this, start_variable, duration, name))); } + // Creates an interval var with a fixed duration, and performed var. + // The duration must be greater than 0. +IntervalVar* Solver::MakeFixedDurationIntervalVar(IntVar* const start_variable, + int64 duration, + IntVar* const performed_variable, + const std::string& name) { + CHECK(start_variable != nullptr); + CHECK(performed_variable != nullptr); + CHECK_GE(duration, 0); + if (!performed_variable->Bound()) { + return RegisterIntervalVar(RevAlloc( + new StartVarIntervalVar(this, start_variable, duration, performed_variable, name))); + } else if (performed_variable->Min() == 1) { + return RegisterIntervalVar(RevAlloc( + new StartVarPerformedIntervalVar(this, start_variable, duration, name))); + } + return nullptr; +} + void Solver::MakeFixedDurationIntervalVarArray( const std::vector& start_variables, int64 duration, const std::string& name, std::vector* array) { @@ -2009,8 +2259,6 @@ void Solver::MakeFixedDurationIntervalVarArray( } } -// This method fills the vector with interval variables built with -// the corresponding start variables. void Solver::MakeFixedDurationIntervalVarArray( const std::vector& start_variables, const std::vector& durations, const std::string& name, std::vector* array) { @@ -2037,6 +2285,36 @@ void Solver::MakeFixedDurationIntervalVarArray( } } +void Solver::MakeFixedDurationIntervalVarArray( + const std::vector& start_variables, + const std::vector& durations, + const std::vector& performed_variables, const std::string& name, + std::vector* array) { + CHECK(array != nullptr); + array->clear(); + for (int i = 0; i < start_variables.size(); ++i) { + const std::string var_name = StringPrintf("%s%i", name.c_str(), i); + array->push_back( + MakeFixedDurationIntervalVar(start_variables[i], durations[i], + performed_variables[i], var_name)); + } +} + +void Solver::MakeFixedDurationIntervalVarArray( + const std::vector& start_variables, + const std::vector& durations, + const std::vector& performed_variables, const std::string& name, + std::vector* array) { + CHECK(array != nullptr); + array->clear(); + for (int i = 0; i < start_variables.size(); ++i) { + const std::string var_name = StringPrintf("%s%i", name.c_str(), i); + array->push_back( + MakeFixedDurationIntervalVar(start_variables[i], durations[i], + performed_variables[i], var_name)); + } +} + // Variable Duration Interval Var IntervalVar* Solver::MakeIntervalVar(int64 start_min, int64 start_max,