Files
ortools-clone/constraint_solver/interval.cc
lperron@google.com 1524c8f391 initial checking
2010-09-15 12:42:33 +00:00

796 lines
20 KiB
C++

// Copyright 2010 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/stringprintf.h"
#include "constraint_solver/constraint_solveri.h"
#if defined(_MSC_VER)
#pragma warning(disable : 4351 4355 4804 4805)
#endif
namespace operations_research {
// ----- Interval Var -----
class IntervalVarStartExpr : public BaseIntExpr {
public:
explicit IntervalVarStartExpr(IntervalVar* const i)
: BaseIntExpr(i->solver()), interval_(i) {}
virtual ~IntervalVarStartExpr() {}
virtual int64 Min() const {
return interval_->StartMin();
}
virtual void SetMin(int64 m) {
interval_->SetStartMin(m);
}
virtual int64 Max() const {
return interval_->StartMax();
}
virtual void SetMax(int64 m) {
interval_->SetStartMax(m);
}
virtual void SetRange(int64 l, int64 u) {
interval_->SetStartRange(l, u);
}
virtual void SetValue(int64 v) {
interval_->SetStartRange(v, v);
}
virtual bool Bound() const {
return interval_->StartMin() == interval_->StartMax();
}
virtual void WhenRange(Demon* d) {
interval_->WhenStartRange(d);
}
virtual string DebugString() const {
return StringPrintf("start(%s)", interval_->DebugString().c_str());
}
private:
IntervalVar* interval_;
DISALLOW_COPY_AND_ASSIGN(IntervalVarStartExpr);
};
class IntervalVarEndExpr : public BaseIntExpr {
public:
explicit IntervalVarEndExpr(IntervalVar* const i)
: BaseIntExpr(i->solver()), interval_(i) {}
virtual ~IntervalVarEndExpr() {}
virtual int64 Min() const {
return interval_->EndMin();
}
virtual void SetMin(int64 m) {
interval_->SetEndMin(m);
}
virtual int64 Max() const {
return interval_->EndMax();
}
virtual void SetMax(int64 m) {
interval_->SetEndMax(m);
}
virtual void SetRange(int64 l, int64 u) {
interval_->SetEndRange(l, u);
}
virtual void SetValue(int64 v) {
interval_->SetEndRange(v, v);
}
virtual bool Bound() const {
return interval_->EndMin() == interval_->EndMax();
}
virtual void WhenRange(Demon* d) {
interval_->WhenEndRange(d);
}
virtual string DebugString() const {
return StringPrintf("end(%s)", interval_->DebugString().c_str());
}
private:
IntervalVar* interval_;
DISALLOW_COPY_AND_ASSIGN(IntervalVarEndExpr);
};
class IntervalVarDurationExpr : public BaseIntExpr {
public:
explicit IntervalVarDurationExpr(IntervalVar* const i)
: BaseIntExpr(i->solver()), interval_(i) {}
virtual ~IntervalVarDurationExpr() {}
virtual int64 Min() const {
return interval_->DurationMin();
}
virtual void SetMin(int64 m) {
interval_->SetDurationMin(m);
}
virtual int64 Max() const {
return interval_->DurationMax();
}
virtual void SetMax(int64 m) {
interval_->SetDurationMax(m);
}
virtual void SetRange(int64 l, int64 u) {
interval_->SetDurationRange(l, u);
}
virtual void SetValue(int64 v) {
interval_->SetDurationRange(v, v);
}
virtual bool Bound() const {
return interval_->DurationMin() == interval_->DurationMax();
}
virtual void WhenRange(Demon* d) {
interval_->WhenDurationRange(d);
}
virtual string DebugString() const {
return StringPrintf("duration(%s)", interval_->DebugString().c_str());
}
private:
IntervalVar* interval_;
DISALLOW_COPY_AND_ASSIGN(IntervalVarDurationExpr);
};
class IntervalVarPerformedExpr : public BaseIntExpr {
public:
explicit IntervalVarPerformedExpr(IntervalVar* const i)
: BaseIntExpr(i->solver()), interval_(i) {}
virtual ~IntervalVarPerformedExpr() {}
virtual int64 Min() const {
return interval_->PerformedMin();
}
virtual void SetMin(int64 m) {
if (m == 1) {
interval_->SetPerformed(true);
} else if (m > 1) {
solver()->Fail();
}
}
virtual int64 Max() const {
return interval_->PerformedMax();
}
virtual void SetMax(int64 m) {
if (m == 0) {
interval_->SetPerformed(false);
} else if (m < 0) {
solver()->Fail();
}
}
virtual void SetRange(int64 l, int64 u) {
SetMin(l);
SetMax(u);
}
virtual void SetValue(int64 v) {
SetRange(v, v);
}
virtual bool Bound() const {
return interval_->PerformedMin() == interval_->PerformedMax();
}
virtual void WhenRange(Demon* d) {
interval_->WhenPerformedBound(d);
}
virtual string DebugString() const {
return StringPrintf("performed(%s)", interval_->DebugString().c_str());
}
private:
IntervalVar* interval_;
DISALLOW_COPY_AND_ASSIGN(IntervalVarPerformedExpr);
};
IntExpr* IntervalVar::StartExpr() {
if (start_expr_ == NULL) {
solver()->SaveValue(reinterpret_cast<void**>(&start_expr_));
start_expr_ = solver()->RevAlloc(new IntervalVarStartExpr(this));
}
return start_expr_;
}
IntExpr* IntervalVar::DurationExpr() {
if (duration_expr_ == NULL) {
solver()->SaveValue(reinterpret_cast<void**>(&duration_expr_));
duration_expr_ = solver()->RevAlloc(new IntervalVarDurationExpr(this));
}
return duration_expr_;
}
IntExpr* IntervalVar::EndExpr() {
if (end_expr_ == NULL) {
solver()->SaveValue(reinterpret_cast<void**>(&end_expr_));
end_expr_ = solver()->RevAlloc(new IntervalVarEndExpr(this));
}
return end_expr_;
}
IntExpr* IntervalVar::PerformedExpr() {
if (performed_expr_ == NULL) {
solver()->SaveValue(reinterpret_cast<void**>(&performed_expr_));
performed_expr_ = solver()->RevAlloc(new IntervalVarPerformedExpr(this));
}
return performed_expr_;
}
// ----- FixedDurationIntervalVar -----
class FixedDurationIntervalVar : public IntervalVar {
public:
class FixedDurationIntervalVarHandler : public Demon {
public:
explicit FixedDurationIntervalVarHandler(
FixedDurationIntervalVar* const var) : Demon(), var_(var) {}
virtual ~FixedDurationIntervalVarHandler() {}
virtual void Run(Solver* const s) {
var_->Process();
}
virtual Solver::DemonPriority priority() const {
return Solver::VAR_PRIORITY;
}
virtual string DebugString() const {
return StringPrintf("Handler(%s)", var_->DebugString().c_str());
}
private:
FixedDurationIntervalVar* const var_;
};
class FixedDurationIntervalVarCleaner : public Action {
public:
explicit FixedDurationIntervalVarCleaner(
FixedDurationIntervalVar* const var) : Action(), var_(var) {}
virtual ~FixedDurationIntervalVarCleaner() {}
virtual void Run(Solver* const s) {
var_->ClearInProcess();
}
private:
FixedDurationIntervalVar* const var_;
};
FixedDurationIntervalVar(Solver* const s,
int64 start_min,
int64 start_max,
int64 duration,
bool optional,
const string& name);
// Unperformed interval.
FixedDurationIntervalVar(Solver* const s, const string& name);
virtual ~FixedDurationIntervalVar() {}
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 void WhenStartRange(Demon* const d) {
start_range_demons_.PushIfNotTop(solver(), d);
}
virtual void WhenStartBound(Demon* const d) {
start_bound_demons_.PushIfNotTop(solver(), 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 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 void WhenEndRange(Demon* const d) {
start_range_demons_.PushIfNotTop(solver(), d);
}
virtual void WhenEndBound(Demon* const d) {
start_bound_demons_.PushIfNotTop(solver(), d);
}
virtual bool PerformedMin() const;
virtual bool PerformedMax() const;
virtual void SetPerformed(bool val);
virtual void WhenPerformedBound(Demon* const d) {
performed_bound_demons_.PushIfNotTop(solver(), d);
}
void Process();
void ClearInProcess();
virtual string DebugString() const;
private:
void CheckOldStartBounds() {
if (old_start_min_ > start_min_) {
old_start_min_ = start_min_;
}
if (old_start_max_ < start_max_) {
old_start_max_ = start_max_;
}
}
void CheckOldPerformed() {
if (performed_ == 2) {
old_performed_ = 2;
}
}
void CheckNotUnperformed() const {
CHECK_NE(0, performed_);
}
void Push();
int64 start_min_;
int64 start_max_;
int64 new_start_min_;
int64 new_start_max_;
int64 old_start_min_;
int64 old_start_max_;
int64 duration_;
int performed_;
int new_performed_;
int old_performed_;
SimpleRevFIFO<Demon*> start_bound_demons_;
SimpleRevFIFO<Demon*> start_range_demons_;
SimpleRevFIFO<Demon*> performed_bound_demons_;
FixedDurationIntervalVarHandler handler_;
FixedDurationIntervalVarCleaner cleaner_;
bool in_process_;
};
FixedDurationIntervalVar::FixedDurationIntervalVar(Solver* const s,
int64 start_min,
int64 start_max,
int64 duration,
bool optional,
const string& name)
: IntervalVar(s, name),
start_min_(start_min),
start_max_(start_max),
new_start_min_(start_min),
new_start_max_(start_max),
old_start_min_(start_min),
old_start_max_(start_max),
duration_(duration),
performed_(optional ? 2 : 1),
new_performed_(performed_),
old_performed_(performed_),
handler_(this),
cleaner_(this),
in_process_(false) {
}
FixedDurationIntervalVar::FixedDurationIntervalVar(Solver* const s,
const string& name)
: IntervalVar(s, name),
start_min_(0),
start_max_(0),
new_start_min_(0),
new_start_max_(0),
old_start_min_(0),
old_start_max_(0),
duration_(0),
performed_(0),
new_performed_(0),
old_performed_(0),
handler_(this),
cleaner_(this),
in_process_(false) {
}
void FixedDurationIntervalVar::Process() {
CHECK(!in_process_);
in_process_ = true;
new_start_min_ = start_min_;
new_start_max_ = start_max_;
new_performed_ = performed_;
set_queue_action_on_fail(&cleaner_);
if (performed_ != 0) {
if (start_min_ == start_max_) {
for (SimpleRevFIFO<Demon*>::Iterator it(&start_bound_demons_);
it.ok();
++it) {
Enqueue(*it);
}
}
if (start_min_ != old_start_min_ || start_max_ != old_start_max_) {
for (SimpleRevFIFO<Demon*>::Iterator it(&start_range_demons_);
it.ok();
++it) {
Enqueue(*it);
}
}
}
if (old_performed_ != performed_) {
for (SimpleRevFIFO<Demon*>::Iterator it(&performed_bound_demons_);
it.ok();
++it) {
Enqueue(*it);
}
}
ProcessDemonsOnQueue();
clear_queue_action_on_fail();
ClearInProcess();
old_start_min_ = start_min_;
old_start_max_ = start_max_;
old_performed_ = performed_;
if (start_min_ < new_start_min_) {
SetStartMin(new_start_min_);
}
if (start_max_ > new_start_max_) {
SetStartMax(new_start_max_);
}
if (new_performed_ != performed_) {
CHECK_NE(2, new_performed_);
SetPerformed(new_performed_);
}
}
void FixedDurationIntervalVar::ClearInProcess() {
in_process_ = false;
}
int64 FixedDurationIntervalVar::StartMin() const {
CheckNotUnperformed();
return start_min_;
}
int64 FixedDurationIntervalVar::StartMax() const {
CheckNotUnperformed();
return start_max_;
}
void FixedDurationIntervalVar::SetStartMin(int64 m) {
if (performed_ != 0) {
if (m > start_max_) {
SetPerformed(false);
return;
}
if (m > start_min_) {
if (in_process_) {
if (m > new_start_max_) {
solver()->Fail();
}
if (m > new_start_min_) {
new_start_min_ = m;
}
} else {
CheckOldStartBounds();
solver()->SaveAndSetValue(&start_min_, m);
Push();
}
}
}
}
void FixedDurationIntervalVar::SetStartMax(int64 m) {
if (performed_ != 0) {
if (m < start_min_) {
SetPerformed(false);
return;
}
if (m < start_max_) {
if (in_process_) {
if (m < new_start_min_) {
solver()->Fail();
}
if (m < new_start_max_) {
new_start_max_ = m;
}
} else {
CheckOldStartBounds();
solver()->SaveAndSetValue(&start_max_, m);
Push();
}
}
}
}
void FixedDurationIntervalVar::SetStartRange(int64 mi, int64 ma) {
SetStartMin(mi);
SetStartMax(ma);
}
int64 FixedDurationIntervalVar::DurationMin() const {
CheckNotUnperformed();
return duration_;
}
int64 FixedDurationIntervalVar::DurationMax() const {
CheckNotUnperformed();
return duration_;
}
void FixedDurationIntervalVar::SetDurationMin(int64 m) {
if (m > duration_) {
SetPerformed(false);
}
}
void FixedDurationIntervalVar::SetDurationMax(int64 m) {
if (m < duration_) {
SetPerformed(false);
}
}
int64 FixedDurationIntervalVar::EndMin() const {
CheckNotUnperformed();
return start_min_ + duration_;
}
int64 FixedDurationIntervalVar::EndMax() const {
CheckNotUnperformed();
return start_max_ + duration_;
}
void FixedDurationIntervalVar::SetEndMin(int64 m) {
if (m > start_min_ + duration_) {
SetStartMin(m - duration_);
}
}
void FixedDurationIntervalVar::SetEndMax(int64 m) {
if (m < start_max_ + duration_) {
SetStartMax(m - duration_);
}
}
void FixedDurationIntervalVar::SetEndRange(int64 mi, int64 ma) {
if (mi < start_min_ + duration_) {
mi = start_min_ + duration_;
}
if (ma > start_max_ + duration_) {
ma = start_max_ + duration_;
}
SetStartRange(mi - duration_, ma - duration_);
}
void FixedDurationIntervalVar::SetDurationRange(int64 mi, int64 ma) {
if (mi > duration_ || ma < duration_ || mi > ma) {
SetPerformed(false);
}
}
bool FixedDurationIntervalVar::PerformedMin() const {
return (performed_ == 1);
}
bool FixedDurationIntervalVar::PerformedMax() const {
return (performed_ != 0);
}
void FixedDurationIntervalVar::SetPerformed(bool val) {
CHECK_GE(val, 0);
CHECK_LE(val, 1);
if (performed_ == 2) {
if (in_process_) {
if (new_performed_ == 2) {
new_performed_ = val;
} else if (new_performed_ != val) {
solver()->Fail();
}
} else {
CheckOldPerformed();
solver()->SaveAndSetValue(&performed_, static_cast<int>(val));
Push();
}
} else if (performed_ != val) {
solver()->Fail();
}
}
void FixedDurationIntervalVar::Push() {
const bool in_process = in_process_;
Enqueue(&handler_);
CHECK_EQ(in_process, in_process_);
}
string FixedDurationIntervalVar::DebugString() const {
string out;
const string& var_name = name();
if (!var_name.empty()) {
out = var_name + "(start = ";
} else {
out = "IntervalVar(start = ";
}
StringAppendF(&out, "%" GG_LL_FORMAT "d", start_min_);
if (start_max_ != start_min_) {
StringAppendF(&out, " .. %" GG_LL_FORMAT "d", start_max_);
}
StringAppendF(&out, ", duration = %" GG_LL_FORMAT "d, status = ", duration_);
switch (performed_) {
case 0:
out += "unperformed)";
break;
case 1:
out += "performed)";
break;
case 2:
out += "optional)";
break;
}
return out;
}
// ----- FixedInterval -----
class FixedInterval : public IntervalVar {
public:
FixedInterval(Solver* const s, int64 start, int64 duration,
const string& name);
virtual ~FixedInterval() {}
virtual int64 StartMin() const { return start_; }
virtual int64 StartMax() const { return start_; }
virtual void SetStartMin(int64 m);
virtual void SetStartMax(int64 m);
virtual void SetStartRange(int64 mi, int64 ma);
virtual void WhenStartRange(Demon* const d) {}
virtual void WhenStartBound(Demon* const d) {}
virtual int64 DurationMin() const { return duration_; }
virtual int64 DurationMax() const { return duration_; }
virtual void SetDurationMin(int64 m);
virtual void SetDurationMax(int64 m);
virtual void SetDurationRange(int64 mi, int64 ma);
virtual void WhenDurationRange(Demon* const d) { }
virtual void WhenDurationBound(Demon* const d) { }
virtual int64 EndMin() const { return start_ + duration_; }
virtual int64 EndMax() const { return start_ + duration_; }
virtual void SetEndMin(int64 m);
virtual void SetEndMax(int64 m);
virtual void SetEndRange(int64 mi, int64 ma);
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 void SetPerformed(bool val);
virtual void WhenPerformedBound(Demon* const d) {}
virtual string DebugString() const;
private:
const int64 start_;
const int64 duration_;
};
FixedInterval::FixedInterval(Solver* const s,
int64 start,
int64 duration,
const string& name)
: IntervalVar(s, name),
start_(start),
duration_(duration) {
}
void FixedInterval::SetStartMin(int64 m) {
if (m > start_) {
solver()->Fail();
}
}
void FixedInterval::SetStartMax(int64 m) {
if (m < start_) {
solver()->Fail();
}
}
void FixedInterval::SetStartRange(int64 mi, int64 ma) {
if (mi > start_ || ma < start_) {
solver()->Fail();
}
}
void FixedInterval::SetDurationMin(int64 m) {
if (m > duration_) {
solver()->Fail();
}
}
void FixedInterval::SetDurationMax(int64 m) {
if (m < duration_) {
solver()->Fail();
}
}
void FixedInterval::SetEndMin(int64 m) {
if (m > start_ + duration_) {
solver()->Fail();
}
}
void FixedInterval::SetEndMax(int64 m) {
if (m < start_ + duration_) {
solver()->Fail();
}
}
void FixedInterval::SetEndRange(int64 mi, int64 ma) {
if (mi > start_ + duration_ || ma < start_ + duration_) {
solver()->Fail();
}
}
void FixedInterval::SetDurationRange(int64 mi, int64 ma) {
if (mi > duration_ || ma < duration_) {
solver()->Fail();
}
}
void FixedInterval::SetPerformed(bool val) {
if (!val) {
solver()->Fail();
}
}
string FixedInterval::DebugString() const {
string out;
const string& var_name = name();
if (!var_name.empty()) {
out = var_name + "(start = ";
} else {
out = "IntervalVar(start = ";
}
StringAppendF(&out, "%" GG_LL_FORMAT "d, duration = %" GG_LL_FORMAT
"d, status = performed)",
start_, duration_);
return out;
}
IntervalVar* Solver::MakeFixedInterval(int64 start,
int64 duration,
const string& name) {
return RevAlloc(new FixedInterval(this, start, duration, name));
}
IntervalVar* Solver::MakeFixedDurationIntervalVar(int64 start_min,
int64 start_max,
int64 duration,
bool optional,
const string& name) {
if (start_min == start_max && !optional) {
return MakeFixedInterval(start_min, duration, name);
}
return RevAlloc(new FixedDurationIntervalVar(this, start_min, start_max,
duration, optional, name));
}
} // namespace operations_research