Monotonic Functional Element
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user