Monotonic Functional Element

This commit is contained in:
lperron@google.com
2011-04-15 14:34:37 +00:00
parent af007d8c54
commit 0e39768372
2 changed files with 173 additions and 5 deletions

View File

@@ -702,14 +702,21 @@ class Solver {
// vals[expr]
IntExpr* MakeElement(const vector<int64>& vals, IntVar* const index);
// Function-based, constraint takes ownership of callback
// The callback must be able to cope with any possible value in the
// domain of 'index' (potentially negative ones too).
// TODO(user): Add typedef for callbacks below.
// Function-based element. The constraint takes ownership of
// callback The callback must be able to cope with any possible
// value in the domain of 'index' (potentially negative ones too).
IntExpr* MakeElement(IndexEvaluator1* values, IntVar* const index);
// Function based element. The constraint takes ownership of
// callback. The callback must be monotonic. It must be able to
// cope with any possible value in the domain of 'index'
// (potentially negative ones too).
IntExpr* MakeMonotonicElement(IndexEvaluator1* values,
bool increasing,
IntVar* const index);
// 2D version of function-based element expression, values(expr1, expr2).
IntExpr* MakeElement(IndexEvaluator2* values,
IntVar* const index1, IntVar* const index2);
IntVar* const index1,
IntVar* const index2);
// vars[expr]
IntExpr* MakeElement(const IntVar* const * vars, int size,

View File

@@ -531,12 +531,173 @@ IntExprFunctionElement::~IntExprFunctionElement() {
}
}
// ----- Increasing Element -----
class MonotonicIntExprFunctionElement : public BaseIntExpr {
public:
MonotonicIntExprFunctionElement(Solver* const s,
ResultCallback1<int64, int64>* values,
bool increasing,
bool to_delete,
IntVar* const index)
: BaseIntExpr(s),
values_(values),
increasing_(increasing),
delete_(to_delete),
index_(index) {
DCHECK(values);
DCHECK(index);
DCHECK(s);
values->CheckIsRepeatable();
}
virtual ~MonotonicIntExprFunctionElement() {
if (delete_) {
delete values_;
}
}
virtual int64 Min() const {
return increasing_?
values_->Run(index_->Min()):
values_->Run(index_->Max());
}
virtual void SetMin(int64 m) {
const int64 expression_min = index_->Min();
const int64 expression_max = index_->Max();
if (increasing_) {
if (m > values_->Run(expression_max)) {
solver()->Fail();
}
int64 nmin = expression_min;
while (nmin <= expression_max && values_->Run(nmin) < m) {
nmin++;
}
DCHECK_LE(nmin, expression_max);
index_->SetMin(nmin);
} else {
if (m > values_->Run(expression_min)) {
solver()->Fail();
}
int64 nmax = expression_max;
while (nmax >= expression_min && values_->Run(nmax) < m) {
nmax--;
}
DCHECK_GE(nmax, expression_min);
index_->SetMax(nmax);
}
}
virtual int64 Max() const {
return increasing_?
values_->Run(index_->Max()):
values_->Run(index_->Min());
}
virtual void SetMax(int64 m) {
const int64 expression_min = index_->Min();
const int64 expression_max = index_->Max();
if (increasing_) {
if (m < values_->Run(expression_min)) {
solver()->Fail();
}
int64 nmax = expression_max;
while (nmax >= expression_min && values_->Run(nmax) > m) {
nmax--;
}
DCHECK_GE(nmax, expression_min);
index_->SetMax(nmax);
} else {
if (m < values_->Run(expression_max)) {
solver()->Fail();
}
int64 nmin = expression_min;
while (nmin <= expression_max && values_->Run(nmin) > m) {
nmin++;
}
DCHECK_LE(nmin, expression_max);
index_->SetMin(nmin);
}
}
virtual void SetRange(int64 mi, int64 ma) {
const int64 expression_min = index_->Min();
const int64 expression_max = index_->Max();
if (increasing_) {
if (mi > ma ||
ma < values_->Run(expression_min) ||
mi > values_->Run(expression_max)) {
solver()->Fail();
}
int64 nmax = expression_max;
while (nmax >= expression_min && values_->Run(nmax) > ma) {
nmax--;
}
DCHECK_GE(nmax, expression_min);
int64 nmin = expression_min;
while (nmin <= nmax && values_->Run(nmin) < mi) {
nmin++;
}
DCHECK_LE(nmin, nmax);
index_->SetRange(nmin, nmax);
} else {
if (mi > ma ||
ma < values_->Run(expression_max) ||
mi > values_->Run(expression_min)) {
solver()->Fail();
}
int64 nmin = expression_min;
while (nmin <= expression_max && values_->Run(nmin) > ma) {
nmin++;
}
DCHECK_LE(nmin, expression_max);
int64 nmax = expression_max;
while (nmax >= expression_min && values_->Run(nmax) < mi) {
nmax--;
}
DCHECK_GE(nmax, nmin);
index_->SetRange(nmin, nmax);
}
}
virtual string name() const {
return StringPrintf("MonotonicIntExprFunctionElement(values, %d, %s)",
increasing_, index_->name().c_str());
}
virtual string DebugString() const {
return StringPrintf("MonotonicIntExprFunctionElement(values, %d, %s)",
increasing_, index_->DebugString().c_str());
}
virtual void WhenRange(Demon* d) {
index_->WhenRange(d);
}
private:
ResultCallback1<int64, int64>* values_;
const bool increasing_;
const bool delete_;
IntVar* const index_;
};
IntExpr* Solver::MakeElement(ResultCallback1<int64, int64>* values,
IntVar* const index) {
CHECK_EQ(this, index->solver());
return RevAlloc(new IntExprFunctionElement(this, values, index, true));
}
IntExpr* Solver::MakeMonotonicElement(ResultCallback1<int64, int64>* values,
bool increasing,
IntVar* const index) {
CHECK_EQ(this, index->solver());
return RevAlloc(new MonotonicIntExprFunctionElement(this,
values,
increasing,
true,
index));
}
// ----- IntIntExprFunctionElement -----
class IntIntExprFunctionElement : public BaseIntExpr {