00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <string.h>
00015 #include <algorithm>
00016 #include <string>
00017 #include <vector>
00018
00019 #include "base/callback.h"
00020 #include "base/integral_types.h"
00021 #include "base/logging.h"
00022 #include "base/scoped_ptr.h"
00023 #include "base/stringprintf.h"
00024 #include "constraint_solver/constraint_solver.h"
00025 #include "constraint_solver/constraint_solveri.h"
00026 #include "util/const_int_array.h"
00027 #include "util/string_array.h"
00028
00029 namespace operations_research {
00030
00031
00032 void LinkVarExpr(Solver* const s, IntExpr* const expr, IntVar* const var);
00033
00034 namespace {
00035
00036
00037 class BaseIntExprElement : public BaseIntExpr {
00038 public:
00039 BaseIntExprElement(Solver* const s, IntVar* const expr);
00040 virtual ~BaseIntExprElement() {}
00041 virtual int64 Min() const;
00042 virtual int64 Max() const;
00043 virtual void Range(int64* mi, int64* ma);
00044 virtual void SetMin(int64 m);
00045 virtual void SetMax(int64 m);
00046 virtual void SetRange(int64 mi, int64 ma);
00047 virtual bool Bound() const { return (expr_->Bound()); }
00048
00049 virtual void WhenRange(Demon* d) {
00050 expr_->WhenRange(d);
00051 }
00052
00053 protected:
00054 virtual int64 ElementValue(int index) const = 0;
00055 virtual int64 ExprMin() const = 0;
00056 virtual int64 ExprMax() const = 0;
00057
00058 IntVar* const expr_;
00059
00060 private:
00061 void UpdateSupports() const;
00062
00063 mutable int64 min_;
00064 mutable int min_support_;
00065 mutable int64 max_;
00066 mutable int max_support_;
00067 mutable bool initial_update_;
00068 IntVarIterator* const expr_iterator_;
00069 };
00070
00071 BaseIntExprElement::BaseIntExprElement(Solver* const s, IntVar* const e)
00072 : BaseIntExpr(s),
00073 expr_(e),
00074 min_(0),
00075 min_support_(-1),
00076 max_(0),
00077 max_support_(-1),
00078 initial_update_(true),
00079 expr_iterator_(expr_->MakeDomainIterator(true)) {
00080 CHECK_NOTNULL(s);
00081 CHECK_NOTNULL(e);
00082 }
00083
00084 int64 BaseIntExprElement::Min() const {
00085 UpdateSupports();
00086 return min_;
00087 }
00088
00089 int64 BaseIntExprElement::Max() const {
00090 UpdateSupports();
00091 return max_;
00092 }
00093
00094 void BaseIntExprElement::Range(int64* mi, int64* ma) {
00095 UpdateSupports();
00096 *mi = min_;
00097 *ma = max_;
00098 }
00099
00100 #define UPDATE_BASE_ELEMENT_INDEX_BOUNDS(test) \
00101 const int64 emin = ExprMin(); \
00102 const int64 emax = ExprMax(); \
00103 int64 nmin = emin; \
00104 int64 value = ElementValue(nmin); \
00105 while (nmin < emax && test) { \
00106 nmin++; \
00107 value = ElementValue(nmin); \
00108 } \
00109 if (nmin == emax && test) { \
00110 solver()->Fail(); \
00111 } \
00112 int64 nmax = emax; \
00113 value = ElementValue(nmax); \
00114 while (nmax >= nmin && test) { \
00115 nmax--; \
00116 value = ElementValue(nmax); \
00117 } \
00118 expr_->SetRange(nmin, nmax);
00119
00120 void BaseIntExprElement::SetMin(int64 m) {
00121 UPDATE_BASE_ELEMENT_INDEX_BOUNDS(value < m);
00122 }
00123
00124 void BaseIntExprElement::SetMax(int64 m) {
00125 UPDATE_BASE_ELEMENT_INDEX_BOUNDS(value > m);
00126 }
00127
00128 void BaseIntExprElement::SetRange(int64 mi, int64 ma) {
00129 if (mi > ma) {
00130 solver()->Fail();
00131 }
00132 UPDATE_BASE_ELEMENT_INDEX_BOUNDS((value < mi || value > ma));
00133 }
00134
00135 #undef UPDATE_BASE_ELEMENT_INDEX_BOUNDS
00136
00137 void BaseIntExprElement::UpdateSupports() const {
00138 if (initial_update_
00139 || !expr_->Contains(min_support_)
00140 || !expr_->Contains(max_support_)) {
00141 const int64 emin = ExprMin();
00142 const int64 emax = ExprMax();
00143 int64 min_value = ElementValue(emax);
00144 int64 max_value = min_value;
00145 int min_support = emax;
00146 int max_support = emax;
00147 const int64 expr_size = expr_->Size();
00148 if (expr_size > 1) {
00149 if (expr_size == emax - emin + 1) {
00150
00151 for (int64 index = emin; index < emax; ++index) {
00152 const int64 value = ElementValue(index);
00153 if (value > max_value) {
00154 max_value = value;
00155 max_support = index;
00156 } else if (value < min_value) {
00157 min_value = value;
00158 min_support = index;
00159 }
00160 }
00161 } else {
00162 for (expr_iterator_->Init();
00163 expr_iterator_->Ok();
00164 expr_iterator_->Next()) {
00165 const int64 index = expr_iterator_->Value();
00166 if (index >= emin && index <= emax) {
00167 const int64 value = ElementValue(index);
00168 if (value > max_value) {
00169 max_value = value;
00170 max_support = index;
00171 } else if (value < min_value) {
00172 min_value = value;
00173 min_support = index;
00174 }
00175 }
00176 }
00177 }
00178 }
00179 Solver* s = solver();
00180 s->SaveAndSetValue(&min_, min_value);
00181 s->SaveAndSetValue(&min_support_, min_support);
00182 s->SaveAndSetValue(&max_, max_value);
00183 s->SaveAndSetValue(&max_support_, max_support);
00184 s->SaveAndSetValue(&initial_update_, false);
00185 }
00186 }
00187
00188
00189
00190
00191
00192
00193 class IntElementConstraint : public CastConstraint {
00194 public:
00195 IntElementConstraint(Solver* const s,
00196 std::vector<int64>* const values,
00197 IntVar* const index,
00198 IntVar* const elem)
00199 : CastConstraint(s, elem),
00200 values_(values),
00201 index_(index),
00202 index_iterator_(index_->MakeDomainIterator(true)) {
00203 CHECK_NOTNULL(values);
00204 CHECK_NOTNULL(index);
00205 }
00206
00207 virtual void Post() {
00208 Demon* const d =
00209 solver()->MakeDelayedConstraintInitialPropagateCallback(this);
00210 index_->WhenDomain(d);
00211 target_var_->WhenRange(d);
00212 }
00213
00214 virtual void InitialPropagate() {
00215 index_->SetRange(0, values_.size() - 1);
00216 const int64 target_var_min = target_var_->Min();
00217 const int64 target_var_max = target_var_->Max();
00218 int64 new_min = target_var_max;
00219 int64 new_max = target_var_min;
00220 to_remove_.clear();
00221 for (index_iterator_->Init();
00222 index_iterator_->Ok();
00223 index_iterator_->Next()) {
00224 const int64 index = index_iterator_->Value();
00225 const int64 value = values_[index];
00226 if (value < target_var_min || value > target_var_max) {
00227 to_remove_.push_back(index);
00228 } else {
00229 if (value < new_min) {
00230 new_min = value;
00231 }
00232 if (value > new_max) {
00233 new_max = value;
00234 }
00235 }
00236 }
00237 target_var_->SetRange(new_min, new_max);
00238 if (!to_remove_.empty()) {
00239 index_->RemoveValues(to_remove_);
00240 }
00241 }
00242
00243 virtual string DebugString() const {
00244 return StringPrintf("IntElementConstraint(%s, %s, %s)",
00245 values_.DebugString().c_str(),
00246 index_->DebugString().c_str(),
00247 target_var_->DebugString().c_str());
00248 }
00249
00250 virtual void Accept(ModelVisitor* const visitor) const {
00251 visitor->BeginVisitConstraint(ModelVisitor::kElementEqual, this);
00252 visitor->VisitConstIntArrayArgument(ModelVisitor::kValuesArgument,
00253 values_);
00254 visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
00255 index_);
00256 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
00257 target_var_);
00258 visitor->EndVisitConstraint(ModelVisitor::kElementEqual, this);
00259 }
00260
00261 private:
00262 ConstIntArray values_;
00263 IntVar* const index_;
00264 IntVarIterator* const index_iterator_;
00265 std::vector<int64> to_remove_;
00266 };
00267
00268
00269
00270 IntVar* BuildDomainIntVar(Solver* const solver, std::vector<int64>* values);
00271
00272 class IntExprElement : public BaseIntExprElement {
00273 public:
00274 IntExprElement(Solver* const s,
00275 std::vector<int64>* const vals,
00276 IntVar* const expr);
00277
00278 virtual ~IntExprElement();
00279
00280 virtual string name() const {
00281 return StringPrintf("IntElement(%s, %s)",
00282 values_.DebugString().c_str(),
00283 expr_->name().c_str());
00284 }
00285
00286 virtual string DebugString() const {
00287 return StringPrintf("IntElement(%s, %s)",
00288 values_.DebugString().c_str(),
00289 expr_->DebugString().c_str());
00290 }
00291
00292 virtual IntVar* CastToVar() {
00293 Solver* const s = solver();
00294 std::vector<int64>* copied_data = values_.Copy();
00295 IntVar* const var = s->MakeIntVar(*copied_data);
00296
00297 s->AddCastConstraint(
00298 s->RevAlloc(new IntElementConstraint(s,
00299 copied_data,
00300 expr_,
00301 var)),
00302 var,
00303 this);
00304 return var;
00305 }
00306
00307 virtual void Accept(ModelVisitor* const visitor) const {
00308 visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
00309 visitor->VisitConstIntArrayArgument(ModelVisitor::kValuesArgument,
00310 values_);
00311 visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
00312 expr_);
00313 visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
00314 }
00315
00316 protected:
00317 virtual int64 ElementValue(int index) const {
00318 DCHECK_LT(index, values_.size());
00319 return values_[index];
00320 }
00321 virtual int64 ExprMin() const {
00322 return std::max(0LL, expr_->Min());
00323 }
00324 virtual int64 ExprMax() const {
00325 return std::min(values_.size() - 1LL, expr_->Max());
00326 }
00327
00328 private:
00329 ConstIntArray values_;
00330 };
00331
00332 IntExprElement::IntExprElement(Solver* const solver,
00333 std::vector<int64>* const values,
00334 IntVar* const index)
00335 : BaseIntExprElement(solver, index), values_(values) {
00336 CHECK_NOTNULL(values);
00337 }
00338
00339
00340 IntExprElement::~IntExprElement() {}
00341
00342
00343
00344 class IncreasingIntExprElement : public BaseIntExpr {
00345 public:
00346 IncreasingIntExprElement(Solver* const s,
00347 std::vector<int64>* const values,
00348 IntVar* const index);
00349 virtual ~IncreasingIntExprElement() {}
00350
00351 virtual int64 Min() const;
00352 virtual void SetMin(int64 m);
00353 virtual int64 Max() const;
00354 virtual void SetMax(int64 m);
00355 virtual void SetRange(int64 mi, int64 ma);
00356 virtual bool Bound() const { return (index_->Bound()); }
00357
00358 virtual string name() const {
00359 return StringPrintf("IntElement(%s, %s)",
00360 values_.DebugString().c_str(),
00361 index_->name().c_str());
00362 }
00363 virtual string DebugString() const {
00364 return StringPrintf("IntElement(%s, %s)",
00365 values_.DebugString().c_str(),
00366 index_->DebugString().c_str());
00367 }
00368
00369 virtual void Accept(ModelVisitor* const visitor) const {
00370 visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
00371 visitor->VisitConstIntArrayArgument(ModelVisitor::kValuesArgument,
00372 values_);
00373 visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
00374 index_);
00375 visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
00376 }
00377
00378 virtual void WhenRange(Demon* d) {
00379 index_->WhenRange(d);
00380 }
00381
00382 virtual IntVar* CastToVar() {
00383 Solver* const s = solver();
00384 std::vector<int64>* copied_data = values_.Copy();
00385 IntVar* const var = s->MakeIntVar(*copied_data);
00386 delete copied_data;
00387 LinkVarExpr(s, this, var);
00388 return var;
00389 }
00390
00391 private:
00392 ConstIntArray values_;
00393 IntVar* const index_;
00394 };
00395
00396 IncreasingIntExprElement::IncreasingIntExprElement(Solver* const s,
00397 std::vector<int64>* const values,
00398 IntVar* const index)
00399 : BaseIntExpr(s), values_(values), index_(index) {
00400 DCHECK(values);
00401 DCHECK(index);
00402 DCHECK(s);
00403 }
00404
00405 int64 IncreasingIntExprElement::Min() const {
00406 const int64 expression_min = std::max(0LL, index_->Min());
00407 return (expression_min < values_.size() ?
00408 values_[expression_min] :
00409 kint64max);
00410 }
00411
00412 void IncreasingIntExprElement::SetMin(int64 m) {
00413 const int64 expression_min = std::max(0LL, index_->Min());
00414 const int64 expression_max = std::min(values_.size() - 1LL, index_->Max());
00415 if (expression_min > expression_max || m > values_[expression_max]) {
00416 solver()->Fail();
00417 }
00418 int64 nmin = expression_min;
00419 while (nmin <= expression_max && values_[nmin] < m) {
00420 nmin++;
00421 }
00422 DCHECK_LE(nmin, expression_max);
00423 index_->SetMin(nmin);
00424 }
00425
00426 int64 IncreasingIntExprElement::Max() const {
00427 const int64 expression_max = std::min(values_.size() - 1LL, index_->Max());
00428 return (expression_max >= 0 ? values_[expression_max] : kint64max);
00429 }
00430
00431 void IncreasingIntExprElement::SetMax(int64 m) {
00432 const int64 expression_min = std::max(0LL, index_->Min());
00433 const int64 expression_max = std::min(values_.size() - 1LL, index_->Max());
00434 if (expression_min > expression_max || m < values_[expression_min]) {
00435 solver()->Fail();
00436 }
00437 int64 nmax = expression_max;
00438 while (nmax >= expression_min && values_[nmax] > m) {
00439 nmax--;
00440 }
00441 DCHECK_GE(nmax, expression_min);
00442 index_->SetRange(expression_min, nmax);
00443 }
00444
00445 void IncreasingIntExprElement::SetRange(int64 mi, int64 ma) {
00446 if (mi > ma) {
00447 solver()->Fail();
00448 }
00449 const int64 expression_min = std::max(0LL, index_->Min());
00450 const int64 expression_max = std::min(values_.size() - 1LL, index_->Max());
00451 if (expression_min > expression_max ||
00452 mi > values_[expression_max] ||
00453 ma < values_[expression_min]) {
00454 solver()->Fail();
00455 }
00456 int64 nmin = expression_min;
00457 while (nmin <= expression_max && (values_[nmin] < mi || values_[nmin] > ma)) {
00458 nmin++;
00459 }
00460 DCHECK_LE(nmin, expression_max);
00461 int64 nmax = expression_max;
00462 while (nmax >= nmin && (values_[nmax] < mi || values_[nmax] > ma)) {
00463 nmax--;
00464 }
00465 DCHECK_GE(nmax, expression_min);
00466 index_->SetRange(nmin, nmax);
00467 }
00468
00469
00470 IntExpr* BuildElement(Solver* const solver,
00471 ConstIntArray* values,
00472 IntVar* const index) {
00473
00474
00475 if (values->HasProperty(ConstIntArray::IS_CONSTANT)) {
00476 solver->AddConstraint(solver->MakeBetweenCt(index, 0, values->size() - 1));
00477 return solver->MakeIntConst(values->get(0));
00478 }
00479
00480
00481 if (values->HasProperty(ConstIntArray::IS_BOOLEAN)) {
00482 std::vector<int64> ones;
00483 int first_zero = -1;
00484 for (int i = 0; i < values->size(); ++i) {
00485 if (values->get(i) == 1LL) {
00486 ones.push_back(i);
00487 } else {
00488 first_zero = i;
00489 }
00490 }
00491 if (ones.size() == 1) {
00492 DCHECK_EQ(1LL, values->get(ones.back()));
00493 solver->AddConstraint(
00494 solver->MakeBetweenCt(index, 0, values->size() - 1));
00495 return solver->MakeIsEqualCstVar(index, ones.back());
00496 } else if (ones.size() == values->size() - 1) {
00497 solver->AddConstraint(
00498 solver->MakeBetweenCt(index, 0, values->size() - 1));
00499 return solver->MakeIsDifferentCstVar(index, first_zero);
00500 } else if (ones.size() == ones.back() - ones.front() + 1) {
00501 solver->AddConstraint(
00502 solver->MakeBetweenCt(index, 0, values->size() - 1));
00503 IntVar* const b = solver->MakeBoolVar("ContiguousBooleanElementVar");
00504 solver->AddConstraint(
00505 solver->MakeIsBetweenCt(index, ones.front(), ones.back(), b));
00506 return b;
00507 } else {
00508 IntVar* const b = solver->MakeBoolVar("NonContiguousBooleanElementVar");
00509 solver->AddConstraint(
00510 solver->MakeBetweenCt(index, 0, values->size() - 1));
00511 solver->AddConstraint(solver->MakeIsMemberCt(index, ones, b));
00512 return b;
00513 }
00514 }
00515
00516 if (values->HasProperty(ConstIntArray::IS_INCREASING)) {
00517 return solver->RegisterIntExpr(solver->RevAlloc(
00518 new IncreasingIntExprElement(solver, values->Release(), index)));
00519 }
00520 return solver->RegisterIntExpr(solver->RevAlloc(
00521 new IntExprElement(solver, values->Release(), index)));
00522 }
00523 }
00524
00525 IntExpr* Solver::MakeElement(const int* const vals,
00526 int size,
00527 IntVar* const index) {
00528 DCHECK(index);
00529 DCHECK_EQ(this, index->solver());
00530 DCHECK_GT(size, 0);
00531 DCHECK(vals);
00532 ConstIntArray values(vals, size);
00533 return BuildElement(this, &values, index);
00534 }
00535
00536 IntExpr* Solver::MakeElement(const std::vector<int64>& vals, IntVar* const index) {
00537 return MakeElement(vals.data(), vals.size(), index);
00538 }
00539
00540 IntExpr* Solver::MakeElement(const int64* const vals,
00541 int size,
00542 IntVar* const index) {
00543 DCHECK(index);
00544 DCHECK_EQ(this, index->solver());
00545 DCHECK_GT(size, 0);
00546 DCHECK(vals);
00547 ConstIntArray values(vals, size);
00548 return BuildElement(this, &values, index);
00549 }
00550
00551 IntExpr* Solver::MakeElement(const std::vector<int>& vals, IntVar* const index) {
00552 return MakeElement(vals.data(), vals.size(), index);
00553 }
00554
00555
00556
00557 namespace {
00558 class IntExprFunctionElement : public BaseIntExprElement {
00559 public:
00560 IntExprFunctionElement(Solver* const s,
00561 ResultCallback1<int64, int64>* values,
00562 IntVar* const expr,
00563 bool del);
00564 virtual ~IntExprFunctionElement();
00565
00566 virtual string name() const {
00567 return StringPrintf("IntFunctionElement(%s)", expr_->name().c_str());
00568 }
00569
00570 virtual string DebugString() const {
00571 return StringPrintf("IntFunctionElement(%s)", expr_->DebugString().c_str());
00572 }
00573
00574 virtual void Accept(ModelVisitor* const visitor) const {
00575
00576 visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
00577 visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
00578 expr_);
00579 if (expr_->Min() == 0) {
00580 visitor->VisitInt64ToInt64AsArray(values_,
00581 ModelVisitor::kValuesArgument,
00582 expr_->Max());
00583 } else {
00584 visitor->VisitInt64ToInt64Extension(values_, expr_->Min(), expr_->Max());
00585 }
00586 visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
00587 }
00588
00589 protected:
00590 virtual int64 ElementValue(int index) const { return values_->Run(index); }
00591 virtual int64 ExprMin() const { return expr_->Min(); }
00592 virtual int64 ExprMax() const { return expr_->Max(); }
00593
00594 private:
00595 ResultCallback1<int64, int64>* values_;
00596 const bool delete_;
00597 };
00598
00599 IntExprFunctionElement::IntExprFunctionElement(
00600 Solver* const s,
00601 ResultCallback1<int64, int64>* values,
00602 IntVar* const e,
00603 bool del)
00604 : BaseIntExprElement(s, e),
00605 values_(values),
00606 delete_(del) {
00607 CHECK(values) << "null pointer";
00608 values->CheckIsRepeatable();
00609 }
00610
00611 IntExprFunctionElement::~IntExprFunctionElement() {
00612 if (delete_) {
00613 delete values_;
00614 }
00615 }
00616
00617
00618
00619 class IncreasingIntExprFunctionElement : public BaseIntExpr {
00620 public:
00621 IncreasingIntExprFunctionElement(Solver* const s,
00622 ResultCallback1<int64, int64>* values,
00623 IntVar* const index)
00624 : BaseIntExpr(s),
00625 values_(values),
00626 index_(index) {
00627 DCHECK(values);
00628 DCHECK(index);
00629 DCHECK(s);
00630 values->CheckIsRepeatable();
00631 }
00632
00633 virtual ~IncreasingIntExprFunctionElement() {
00634 delete values_;
00635 }
00636
00637 virtual int64 Min() const {
00638 return values_->Run(index_->Min());
00639 }
00640
00641 virtual void SetMin(int64 m) {
00642 const int64 expression_min = index_->Min();
00643 const int64 expression_max = index_->Max();
00644 if (m > values_->Run(expression_max)) {
00645 solver()->Fail();
00646 }
00647 int64 nmin = expression_min;
00648 while (nmin <= expression_max && values_->Run(nmin) < m) {
00649 nmin++;
00650 }
00651 DCHECK_LE(nmin, expression_max);
00652 index_->SetMin(nmin);
00653 }
00654
00655 virtual int64 Max() const {
00656 return values_->Run(index_->Max());
00657 }
00658
00659 virtual void SetMax(int64 m) {
00660 const int64 expression_min = index_->Min();
00661 const int64 expression_max = index_->Max();
00662 if (m < values_->Run(expression_min)) {
00663 solver()->Fail();
00664 }
00665 int64 nmax = expression_max;
00666 while (nmax >= expression_min && values_->Run(nmax) > m) {
00667 nmax--;
00668 }
00669 DCHECK_GE(nmax, expression_min);
00670 index_->SetMax(nmax);
00671 }
00672
00673 virtual void SetRange(int64 mi, int64 ma) {
00674 const int64 expression_min = index_->Min();
00675 const int64 expression_max = index_->Max();
00676 if (mi > ma ||
00677 ma < values_->Run(expression_min) ||
00678 mi > values_->Run(expression_max)) {
00679 solver()->Fail();
00680 }
00681 int64 nmax = expression_max;
00682 while (nmax >= expression_min && values_->Run(nmax) > ma) {
00683 nmax--;
00684 }
00685 DCHECK_GE(nmax, expression_min);
00686 int64 nmin = expression_min;
00687 while (nmin <= nmax && values_->Run(nmin) < mi) {
00688 nmin++;
00689 }
00690 DCHECK_LE(nmin, nmax);
00691 index_->SetRange(nmin, nmax);
00692 }
00693
00694 virtual string name() const {
00695 return StringPrintf("IncreasingIntExprFunctionElement(values, %s)",
00696 index_->name().c_str());
00697 }
00698
00699 virtual string DebugString() const {
00700 return StringPrintf("IncreasingIntExprFunctionElement(values, %s)",
00701 index_->DebugString().c_str());
00702 }
00703
00704 virtual void WhenRange(Demon* d) {
00705 index_->WhenRange(d);
00706 }
00707
00708 virtual void Accept(ModelVisitor* const visitor) const {
00709
00710 visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
00711 visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
00712 index_);
00713 if (index_->Min() == 0) {
00714 visitor->VisitInt64ToInt64AsArray(values_,
00715 ModelVisitor::kValuesArgument,
00716 index_->Max());
00717 } else {
00718 visitor->VisitInt64ToInt64Extension(values_,
00719 index_->Min(),
00720 index_->Max());
00721 }
00722 visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
00723 }
00724
00725 private:
00726 ResultCallback1<int64, int64>* values_;
00727 IntVar* const index_;
00728 };
00729 }
00730
00731 IntExpr* Solver::MakeElement(ResultCallback1<int64, int64>* values,
00732 IntVar* const index) {
00733 CHECK_EQ(this, index->solver());
00734 return RegisterIntExpr(RevAlloc(
00735 new IntExprFunctionElement(this, values, index, true)));
00736 }
00737
00738 namespace {
00739 class OppositeCallback : public BaseObject {
00740 public:
00741 OppositeCallback(ResultCallback1<int64, int64>* const values)
00742 : values_(values) {
00743 CHECK_NOTNULL(values_);
00744 values_->CheckIsRepeatable();
00745 }
00746
00747 virtual ~OppositeCallback() {}
00748
00749 int64 Run(int64 index) {
00750 return -values_->Run(index);
00751 }
00752 public:
00753 scoped_ptr<ResultCallback1<int64, int64> > values_;
00754 };
00755 }
00756
00757 IntExpr* Solver::MakeMonotonicElement(ResultCallback1<int64, int64>* values,
00758 bool increasing,
00759 IntVar* const index) {
00760 CHECK_EQ(this, index->solver());
00761 if (increasing) {
00762 return RegisterIntExpr(RevAlloc(
00763 new IncreasingIntExprFunctionElement(this, values, index)));
00764 } else {
00765 OppositeCallback* const opposite_callback =
00766 RevAlloc(new OppositeCallback(values));
00767 ResultCallback1<int64, int64>* opposite_values =
00768 NewPermanentCallback(opposite_callback, &OppositeCallback::Run);
00769 return RegisterIntExpr(MakeOpposite(RevAlloc(
00770 new IncreasingIntExprFunctionElement(this, opposite_values, index))));
00771 }
00772 }
00773
00774
00775
00776 namespace {
00777 class IntIntExprFunctionElement : public BaseIntExpr {
00778 public:
00779 IntIntExprFunctionElement(Solver* const s,
00780 ResultCallback2<int64, int64, int64>* values,
00781 IntVar* const expr1,
00782 IntVar* const expr2);
00783 virtual ~IntIntExprFunctionElement();
00784 virtual string DebugString() const {
00785 return StringPrintf("IntIntFunctionElement(%s,%s)",
00786 expr1_->DebugString().c_str(),
00787 expr2_->DebugString().c_str());
00788 }
00789 virtual int64 Min() const;
00790 virtual int64 Max() const;
00791 virtual void Range(int64* mi, int64* ma);
00792 virtual void SetMin(int64 m);
00793 virtual void SetMax(int64 m);
00794 virtual void SetRange(int64 mi, int64 ma);
00795 virtual bool Bound() const { return expr1_->Bound() && expr2_->Bound(); }
00796
00797 virtual void WhenRange(Demon* d) {
00798 expr1_->WhenRange(d);
00799 expr2_->WhenRange(d);
00800 }
00801
00802 virtual void Accept(ModelVisitor* const visitor) const {
00803 visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
00804
00805 visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
00806 expr1_);
00807 visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndex2Argument,
00808 expr2_);
00809 visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
00810 }
00811
00812 private:
00813 int64 ElementValue(int index1, int index2) const {
00814 return values_->Run(index1, index2);
00815 }
00816 void UpdateSupports() const;
00817
00818 IntVar* const expr1_;
00819 IntVar* const expr2_;
00820 mutable int64 min_;
00821 mutable int min_support1_;
00822 mutable int min_support2_;
00823 mutable int64 max_;
00824 mutable int max_support1_;
00825 mutable int max_support2_;
00826 mutable bool initial_update_;
00827 scoped_ptr<ResultCallback2<int64, int64, int64> > values_;
00828 IntVarIterator* const expr1_iterator_;
00829 IntVarIterator* const expr2_iterator_;
00830 };
00831
00832 IntIntExprFunctionElement::IntIntExprFunctionElement(
00833 Solver* const s,
00834 ResultCallback2<int64, int64, int64>* values,
00835 IntVar* const expr1,
00836 IntVar* const expr2)
00837 : BaseIntExpr(s),
00838 expr1_(expr1),
00839 expr2_(expr2),
00840 min_(0),
00841 min_support1_(-1),
00842 min_support2_(-1),
00843 max_(0),
00844 max_support1_(-1),
00845 max_support2_(-1),
00846 initial_update_(true),
00847 values_(values),
00848 expr1_iterator_(expr1_->MakeDomainIterator(true)),
00849 expr2_iterator_(expr2_->MakeDomainIterator(true)) {
00850 CHECK(values) << "null pointer";
00851 values->CheckIsRepeatable();
00852 }
00853
00854 IntIntExprFunctionElement::~IntIntExprFunctionElement() {}
00855
00856 int64 IntIntExprFunctionElement::Min() const {
00857 UpdateSupports();
00858 return min_;
00859 }
00860
00861 int64 IntIntExprFunctionElement::Max() const {
00862 UpdateSupports();
00863 return max_;
00864 }
00865
00866 void IntIntExprFunctionElement::Range(int64* lower_bound, int64* upper_bound) {
00867 UpdateSupports();
00868 *lower_bound = min_;
00869 *upper_bound = max_;
00870 }
00871
00872 #define UPDATE_ELEMENT_INDEX_BOUNDS(test) \
00873 const int64 emin1 = expr1_->Min(); \
00874 const int64 emax1 = expr1_->Max(); \
00875 const int64 emin2 = expr2_->Min(); \
00876 const int64 emax2 = expr2_->Max(); \
00877 int64 nmin1 = emin1; \
00878 bool found = false; \
00879 while (nmin1 <= emax1 && !found) { \
00880 for (int i = emin2; i <= emax2; ++i) { \
00881 int64 value = ElementValue(nmin1, i); \
00882 if (test) { \
00883 found = true; \
00884 break; \
00885 } \
00886 } \
00887 if (!found) { \
00888 nmin1++; \
00889 } \
00890 } \
00891 if (nmin1 > emax1) { \
00892 solver()->Fail(); \
00893 } \
00894 int64 nmin2 = emin2; \
00895 found = false; \
00896 while (nmin2 <= emax2 && !found) { \
00897 for (int i = emin1; i <= emax1; ++i) { \
00898 int64 value = ElementValue(i, nmin2); \
00899 if (test) { \
00900 found = true; \
00901 break; \
00902 } \
00903 } \
00904 if (!found) { \
00905 nmin2++; \
00906 } \
00907 } \
00908 if (nmin2 > emax2) { \
00909 solver()->Fail(); \
00910 } \
00911 int64 nmax1 = emax1; \
00912 found = false; \
00913 while (nmax1 >= nmin1 && !found) { \
00914 for (int i = emin2; i <= emax2; ++i) { \
00915 int64 value = ElementValue(nmax1, i); \
00916 if (test) { \
00917 found = true; \
00918 break; \
00919 } \
00920 } \
00921 if (!found) { \
00922 nmax1--; \
00923 } \
00924 } \
00925 int64 nmax2 = emax2; \
00926 found = false; \
00927 while (nmax2 >= nmin2 && !found) { \
00928 for (int i = emin1; i <= emax1; ++i) { \
00929 int64 value = ElementValue(i, nmax2); \
00930 if (test) { \
00931 found = true; \
00932 break; \
00933 } \
00934 } \
00935 if (!found) { \
00936 nmax2--; \
00937 } \
00938 } \
00939 expr1_->SetRange(nmin1, nmax1); \
00940 expr2_->SetRange(nmin2, nmax2);
00941
00942 void IntIntExprFunctionElement::SetMin(int64 lower_bound) {
00943 UPDATE_ELEMENT_INDEX_BOUNDS(value >= lower_bound);
00944 }
00945
00946 void IntIntExprFunctionElement::SetMax(int64 upper_bound) {
00947 UPDATE_ELEMENT_INDEX_BOUNDS(value <= upper_bound);
00948 }
00949
00950 void IntIntExprFunctionElement::SetRange(int64 lower_bound, int64 upper_bound) {
00951 if (lower_bound > upper_bound) {
00952 solver()->Fail();
00953 }
00954 UPDATE_ELEMENT_INDEX_BOUNDS(value >= lower_bound && value <= upper_bound);
00955 }
00956
00957 #undef UPDATE_ELEMENT_INDEX_BOUNDS
00958
00959 void IntIntExprFunctionElement::UpdateSupports() const {
00960 if (initial_update_
00961 || !expr1_->Contains(min_support1_)
00962 || !expr1_->Contains(max_support1_)
00963 || !expr2_->Contains(min_support2_)
00964 || !expr2_->Contains(max_support2_)) {
00965 const int64 emax1 = expr1_->Max();
00966 const int64 emax2 = expr2_->Max();
00967 int64 min_value = ElementValue(emax1, emax2);
00968 int64 max_value = min_value;
00969 int min_support1 = emax1;
00970 int max_support1 = emax1;
00971 int min_support2 = emax2;
00972 int max_support2 = emax2;
00973 for (expr1_iterator_->Init();
00974 expr1_iterator_->Ok();
00975 expr1_iterator_->Next()) {
00976 const int64 index1 = expr1_iterator_->Value();
00977 for (expr2_iterator_->Init();
00978 expr2_iterator_->Ok();
00979 expr2_iterator_->Next()) {
00980 const int64 index2 = expr2_iterator_->Value();
00981 const int64 value = ElementValue(index1, index2);
00982 if (value > max_value) {
00983 max_value = value;
00984 max_support1 = index1;
00985 max_support2 = index2;
00986 } else if (value < min_value) {
00987 min_value = value;
00988 min_support1 = index1;
00989 min_support2 = index2;
00990 }
00991 }
00992 }
00993 Solver* s = solver();
00994 s->SaveAndSetValue(&min_, min_value);
00995 s->SaveAndSetValue(&min_support1_, min_support1);
00996 s->SaveAndSetValue(&min_support2_, min_support2);
00997 s->SaveAndSetValue(&max_, max_value);
00998 s->SaveAndSetValue(&max_support1_, max_support1);
00999 s->SaveAndSetValue(&max_support2_, max_support2);
01000 s->SaveAndSetValue(&initial_update_, false);
01001 }
01002 }
01003 }
01004
01005 IntExpr* Solver::MakeElement(ResultCallback2<int64, int64, int64>* values,
01006 IntVar* const index1, IntVar* const index2) {
01007 CHECK_EQ(this, index1->solver());
01008 CHECK_EQ(this, index2->solver());
01009 return RegisterIntExpr(RevAlloc(
01010 new IntIntExprFunctionElement(this, values, index1, index2)));
01011 }
01012
01013
01014
01015
01016
01017
01018
01019
01020 namespace {
01021 class IntExprArrayElementCt : public CastConstraint {
01022 public:
01023 IntExprArrayElementCt(Solver* const s,
01024 const IntVar* const * vars,
01025 int size,
01026 IntVar* const index,
01027 IntVar* const target_var);
01028 virtual ~IntExprArrayElementCt() {}
01029
01030 virtual void Post();
01031 virtual void InitialPropagate();
01032
01033 void Propagate();
01034 void Update(int index);
01035 void UpdateExpr();
01036
01037 virtual string DebugString() const;
01038
01039 virtual void Accept(ModelVisitor* const visitor) const {
01040 visitor->BeginVisitConstraint(ModelVisitor::kElementEqual, this);
01041 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
01042 vars_.get(),
01043 size_);
01044 visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
01045 index_);
01046 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
01047 target_var_);
01048 visitor->EndVisitConstraint(ModelVisitor::kElementEqual, this);
01049 }
01050
01051 private:
01052 scoped_array<IntVar*> vars_;
01053 int size_;
01054 IntVar* const index_;
01055 int min_support_;
01056 int max_support_;
01057 };
01058
01059 IntExprArrayElementCt::IntExprArrayElementCt(Solver* const s,
01060 const IntVar* const * vars,
01061 int size,
01062 IntVar* const index,
01063 IntVar* const target_var)
01064 : CastConstraint(s, target_var),
01065 vars_(new IntVar*[size]),
01066 size_(size),
01067 index_(index),
01068 min_support_(-1),
01069 max_support_(-1) {
01070 memcpy(vars_.get(), vars, size_ * sizeof(*vars));
01071 }
01072
01073 void IntExprArrayElementCt::Post() {
01074 Demon* const delayed_propagate_demon =
01075 MakeDelayedConstraintDemon0(solver(),
01076 this,
01077 &IntExprArrayElementCt::Propagate,
01078 "Propagate");
01079 for (int i = 0; i < size_; ++i) {
01080 vars_[i]->WhenRange(delayed_propagate_demon);
01081 Demon* const update_demon =
01082 MakeConstraintDemon1(solver(),
01083 this,
01084 &IntExprArrayElementCt::Update,
01085 "Update",
01086 i);
01087 vars_[i]->WhenRange(update_demon);
01088 }
01089 index_->WhenRange(delayed_propagate_demon);
01090 Demon* const update_expr_demon =
01091 MakeConstraintDemon0(solver(),
01092 this,
01093 &IntExprArrayElementCt::UpdateExpr,
01094 "UpdateExpr");
01095 index_->WhenRange(update_expr_demon);
01096 Demon* const update_var_demon =
01097 MakeConstraintDemon0(solver(),
01098 this,
01099 &IntExprArrayElementCt::Propagate,
01100 "UpdateVar");
01101
01102 target_var_->WhenRange(update_var_demon);
01103 }
01104
01105 void IntExprArrayElementCt::InitialPropagate() {
01106 Propagate();
01107 }
01108
01109 void IntExprArrayElementCt::Propagate() {
01110 const int64 emin = std::max(0LL, index_->Min());
01111 const int64 emax = std::min(size_ - 1LL, index_->Max());
01112 const int64 vmin = target_var_->Min();
01113 const int64 vmax = target_var_->Max();
01114 if (emin == emax) {
01115 index_->SetValue(emin);
01116 vars_[emin]->SetRange(vmin, vmax);
01117 } else {
01118 int64 nmin = emin;
01119 while (nmin <= emax && (vars_[nmin]->Min() > vmax ||
01120 vars_[nmin]->Max() < vmin)) {
01121 nmin++;
01122 }
01123 int64 nmax = emax;
01124 while (nmax >= nmin && (vars_[nmax]->Max() < vmin ||
01125 vars_[nmax]->Min() > vmax)) {
01126 nmax--;
01127 }
01128 index_->SetRange(nmin, nmax);
01129 if (nmin == nmax) {
01130 vars_[nmin]->SetRange(vmin, vmax);
01131 }
01132 }
01133 if (min_support_ == -1 || max_support_ == -1) {
01134 int min_support = -1;
01135 int max_support = -1;
01136 int64 gmin = kint64max;
01137 int64 gmax = kint64min;
01138 for (int i = index_->Min(); i <= index_->Max(); ++i) {
01139 const int64 vmin = vars_[i]->Min();
01140 if (vmin < gmin) {
01141 gmin = vmin;
01142 }
01143 const int64 vmax = vars_[i]->Max();
01144 if (vmax > gmax) {
01145 gmax = vmax;
01146 }
01147 }
01148 solver()->SaveAndSetValue(&min_support_, min_support);
01149 solver()->SaveAndSetValue(&max_support_, max_support);
01150 target_var_->SetRange(gmin, gmax);
01151 }
01152 }
01153
01154 void IntExprArrayElementCt::Update(int index) {
01155 if (index == min_support_ || index == max_support_) {
01156 solver()->SaveAndSetValue(&min_support_, -1);
01157 solver()->SaveAndSetValue(&max_support_, -1);
01158 }
01159 }
01160
01161 void IntExprArrayElementCt::UpdateExpr() {
01162 if (!index_->Contains(min_support_) || !index_->Contains(max_support_)) {
01163 solver()->SaveAndSetValue(&min_support_, -1);
01164 solver()->SaveAndSetValue(&max_support_, -1);
01165 }
01166 }
01167
01168 string IntExprArrayElementCt::DebugString() const {
01169 return StringPrintf("IntExprArrayElement([%s], %s) == %s",
01170 DebugStringArray(vars_.get(), size_, ", ").c_str(),
01171 index_->DebugString().c_str(),
01172 target_var_->DebugString().c_str());
01173 }
01174
01175
01176
01177 class IntExprArrayElement : public BaseIntExpr {
01178 public:
01179 IntExprArrayElement(Solver* const s,
01180 const IntVar* const * vars,
01181 int size,
01182 IntVar* const expr);
01183 virtual ~IntExprArrayElement() {}
01184
01185 virtual int64 Min() const;
01186 virtual void SetMin(int64 m);
01187 virtual int64 Max() const;
01188 virtual void SetMax(int64 m);
01189 virtual void SetRange(int64 mi, int64 ma);
01190 virtual bool Bound() const;
01191 virtual string name() const {
01192 return StringPrintf("IntArrayElement(%s, %s)",
01193 NameArray(vars_.get(), size_, ", ").c_str(),
01194 var_->name().c_str());
01195 }
01196 virtual string DebugString() const {
01197 return StringPrintf("IntArrayElement(%s, %s)",
01198 DebugStringArray(vars_.get(), size_, ", ").c_str(),
01199 var_->DebugString().c_str());
01200 }
01201 virtual void WhenRange(Demon* d) {
01202 var_->WhenRange(d);
01203 for (int i = 0; i < size_; ++i) {
01204 vars_[i]->WhenRange(d);
01205 }
01206 }
01207 virtual IntVar* CastToVar() {
01208 Solver* const s = solver();
01209 int64 vmin = 0LL;
01210 int64 vmax = 0LL;
01211 Range(&vmin, &vmax);
01212 IntVar* var = solver()->MakeIntVar(vmin, vmax);
01213 s->AddCastConstraint(s->RevAlloc(new IntExprArrayElementCt(s,
01214 vars_.get(),
01215 size_,
01216 var_,
01217 var)),
01218 var,
01219 this);
01220 return var;
01221 }
01222
01223 virtual void Accept(ModelVisitor* const visitor) const {
01224 visitor->BeginVisitIntegerExpression(ModelVisitor::kElement, this);
01225 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
01226 vars_.get(),
01227 size_);
01228 visitor->VisitIntegerExpressionArgument(ModelVisitor::kIndexArgument,
01229 var_);
01230 visitor->EndVisitIntegerExpression(ModelVisitor::kElement, this);
01231 }
01232
01233 private:
01234 scoped_array<IntVar*> vars_;
01235 int size_;
01236 IntVar* const var_;
01237 };
01238
01239 IntExprArrayElement::IntExprArrayElement(Solver* const s,
01240 const IntVar* const * vars,
01241 int size,
01242 IntVar* const v)
01243 : BaseIntExpr(s), vars_(new IntVar*[size]),
01244 size_(size), var_(v) {
01245 CHECK(vars);
01246 memcpy(vars_.get(), vars, size_ * sizeof(*vars));
01247 }
01248
01249 int64 IntExprArrayElement::Min() const {
01250 const int64 emin = std::max(0LL, var_->Min());
01251 const int64 emax = std::min(size_ - 1LL, var_->Max());
01252 int64 res = kint64max;
01253 for (int i = emin; i <= emax; ++i) {
01254 const int64 vmin = vars_[i]->Min();
01255 if (vmin < res && var_->Contains(i)) {
01256 res = vmin;
01257 }
01258 }
01259 return res;
01260 }
01261
01262 void IntExprArrayElement::SetMin(int64 m) {
01263 const int64 emin = std::max(0LL, var_->Min());
01264 const int64 emax = std::min(size_ - 1LL, var_->Max());
01265 if (emin == emax) {
01266 var_->SetValue(emin);
01267 vars_[emin]->SetMin(m);
01268 } else {
01269 int64 nmin = emin;
01270 while (nmin <= emax && vars_[nmin]->Max() < m) {
01271 nmin++;
01272 }
01273 if (nmin > emax) {
01274 solver()->Fail();
01275 }
01276 int64 nmax = emax;
01277 while (nmax >= nmin && vars_[nmax]->Max() < m) {
01278 nmax--;
01279 }
01280 var_->SetRange(nmin, nmax);
01281 if (var_->Bound()) {
01282 vars_[var_->Min()]->SetMin(m);
01283 }
01284 }
01285 }
01286
01287 int64 IntExprArrayElement::Max() const {
01288 const int64 emin = std::max(0LL, var_->Min());
01289 const int64 emax = std::min(size_ - 1LL, var_->Max());
01290 int64 res = kint64min;
01291 for (int i = emin; i <= emax; ++i) {
01292 const int64 vmax = vars_[i]->Max();
01293 if (vmax > res && var_->Contains(i)) {
01294 res = vmax;
01295 }
01296 }
01297 return res;
01298 }
01299
01300 void IntExprArrayElement::SetMax(int64 m) {
01301 const int64 emin = std::max(0LL, var_->Min());
01302 const int64 emax = std::min(size_ - 1LL, var_->Max());
01303 if (emin == emax) {
01304 var_->SetValue(emin);
01305 vars_[emin]->SetMax(m);
01306 } else {
01307 int64 nmin = emin;
01308 while (nmin <= emax && vars_[nmin]->Min() > m) {
01309 nmin++;
01310 }
01311 if (nmin > emax) {
01312 solver()->Fail();
01313 }
01314 int64 nmax = emax;
01315 while (nmax >= nmin && vars_[nmax]->Min() > m) {
01316 nmax--;
01317 }
01318 var_->SetRange(nmin, nmax);
01319 if (var_->Bound()) {
01320 vars_[var_->Min()]->SetMax(m);
01321 }
01322 }
01323 }
01324
01325 void IntExprArrayElement::SetRange(int64 mi, int64 ma) {
01326 if (mi > ma) {
01327 solver()->Fail();
01328 }
01329 const int64 emin = std::max(0LL, var_->Min());
01330 const int64 emax = std::min(size_ - 1LL, var_->Max());
01331 if (emin == emax) {
01332 var_->SetValue(emin);
01333 vars_[emin]->SetRange(mi, ma);
01334 } else {
01335 int64 nmin = emin;
01336 while (nmin <= emax && (vars_[nmin]->Min() > ma ||
01337 vars_[nmin]->Max() < mi)) {
01338 nmin++;
01339 }
01340 if (nmin > emax) {
01341 solver()->Fail();
01342 }
01343 int64 nmax = emax;
01344 while (nmax >= nmin && (vars_[nmax]->Max() < mi ||
01345 vars_[nmax]->Min() > ma)) {
01346 nmax--;
01347 }
01348 if (nmax < emin) {
01349 solver()->Fail();
01350 }
01351 var_->SetRange(nmin, nmax);
01352 if (var_->Bound()) {
01353 vars_[var_->Min()]->SetRange(mi, ma);
01354 }
01355 }
01356 }
01357
01358 bool IntExprArrayElement::Bound() const {
01359 const int64 emin = std::max(0LL, var_->Min());
01360 const int64 emax = std::min(size_ - 1LL, var_->Max());
01361 const int64 v = vars_[emin]->Min();
01362 for (int i = emin; i <= emax; ++i) {
01363 if (var_->Contains(i) && (!vars_[i]->Bound() || vars_[i]->Value() != v)) {
01364 return false;
01365 }
01366 }
01367 return true;
01368 }
01369 }
01370
01371 IntExpr* Solver::MakeElement(const IntVar* const * vars,
01372 int size,
01373 IntVar* const index) {
01374 CHECK_EQ(this, index->solver());
01375 return RegisterIntExpr(RevAlloc(
01376 new IntExprArrayElement(this, vars, size, index)));
01377 }
01378
01379 IntExpr* Solver::MakeElement(const std::vector<IntVar*>& vars, IntVar* const index) {
01380 CHECK_EQ(this, index->solver());
01381 return RegisterIntExpr(RevAlloc(
01382 new IntExprArrayElement(this, vars.data(), vars.size(), index)));
01383 }
01384
01385 }