git-subtree-dir: software/gecode_on_replay git-subtree-split: 8051d92b9c89e49cccfbd1c201371580d7703ab4
1005 lines
26 KiB
C++
1005 lines
26 KiB
C++
/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
|
/*
|
|
* Main authors:
|
|
* Christian Schulte <schulte@gecode.org>
|
|
*
|
|
* Contributing authors:
|
|
* Guido Tack <tack@gecode.org>
|
|
*
|
|
* Copyright:
|
|
* Christian Schulte, 2003
|
|
* Guido Tack, 2004
|
|
*
|
|
* This file is part of Gecode, the generic constraint
|
|
* development environment:
|
|
* http://www.gecode.org
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
namespace Gecode { namespace Int {
|
|
|
|
/*
|
|
* Range lists
|
|
*
|
|
*/
|
|
|
|
#define GECODE_INT_RL2PD(r) reinterpret_cast<ptrdiff_t>(r)
|
|
#define GECODE_INT_PD2RL(p) reinterpret_cast<RangeList*>(p)
|
|
|
|
forceinline
|
|
IntVarImp::RangeList::RangeList(void) {}
|
|
|
|
forceinline
|
|
IntVarImp::RangeList::RangeList(int min, int max)
|
|
: _min(min), _max(max) {}
|
|
|
|
forceinline
|
|
IntVarImp::RangeList::RangeList(int min, int max, RangeList* p, RangeList* n)
|
|
: _min(min), _max(max) {
|
|
_next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(p)^GECODE_INT_RL2PD(n));
|
|
}
|
|
|
|
forceinline IntVarImp::RangeList*
|
|
IntVarImp::RangeList::next(const RangeList* p) const {
|
|
return GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^GECODE_INT_RL2PD(p));
|
|
}
|
|
forceinline IntVarImp::RangeList*
|
|
IntVarImp::RangeList::prev(const RangeList* n) const {
|
|
return GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^GECODE_INT_RL2PD(n));
|
|
}
|
|
forceinline void
|
|
IntVarImp::RangeList::prevnext(RangeList* p, RangeList* n) {
|
|
_next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(p)^GECODE_INT_RL2PD(n));
|
|
}
|
|
forceinline void
|
|
IntVarImp::RangeList::next(RangeList* o, RangeList* n) {
|
|
_next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^
|
|
(GECODE_INT_RL2PD(o)^GECODE_INT_RL2PD(n)));
|
|
}
|
|
forceinline void
|
|
IntVarImp::RangeList::prev(RangeList* o, RangeList* n) {
|
|
_next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^
|
|
(GECODE_INT_RL2PD(o)^GECODE_INT_RL2PD(n)));
|
|
}
|
|
forceinline void
|
|
IntVarImp::RangeList::fix(RangeList* n) {
|
|
_next = n;
|
|
}
|
|
|
|
forceinline void
|
|
IntVarImp::RangeList::min(int n) {
|
|
_min = n;
|
|
}
|
|
forceinline void
|
|
IntVarImp::RangeList::max(int n) {
|
|
_max = n;
|
|
}
|
|
|
|
forceinline int
|
|
IntVarImp::RangeList::min(void) const {
|
|
return _min;
|
|
}
|
|
forceinline int
|
|
IntVarImp::RangeList::max(void) const {
|
|
return _max;
|
|
}
|
|
forceinline unsigned int
|
|
IntVarImp::RangeList::width(void) const {
|
|
return static_cast<unsigned int>(_max - _min) + 1;
|
|
}
|
|
|
|
|
|
forceinline void
|
|
IntVarImp::RangeList::operator delete(void*) {}
|
|
|
|
forceinline void
|
|
IntVarImp::RangeList::operator delete(void*, Space&) {
|
|
GECODE_NEVER;
|
|
}
|
|
forceinline void
|
|
IntVarImp::RangeList::operator delete(void*, void*) {
|
|
GECODE_NEVER;
|
|
}
|
|
|
|
forceinline void*
|
|
IntVarImp::RangeList::operator new(size_t, Space& home) {
|
|
return home.fl_alloc<sizeof(RangeList)>();
|
|
}
|
|
|
|
forceinline void*
|
|
IntVarImp::RangeList::operator new(size_t, void* p) {
|
|
return p;
|
|
}
|
|
|
|
forceinline void
|
|
IntVarImp::RangeList::dispose(Space& home, RangeList* p, RangeList* l) {
|
|
RangeList* c = this;
|
|
while (c != l) {
|
|
RangeList* n = c->next(p);
|
|
c->fix(n);
|
|
p=c; c=n;
|
|
}
|
|
home.fl_dispose<sizeof(RangeList)>(this,l);
|
|
}
|
|
|
|
forceinline void
|
|
IntVarImp::RangeList::dispose(Space& home, RangeList* l) {
|
|
home.fl_dispose<sizeof(RangeList)>(this,l);
|
|
}
|
|
|
|
forceinline void
|
|
IntVarImp::RangeList::dispose(Space& home) {
|
|
home.fl_dispose<sizeof(RangeList)>(this,this);
|
|
}
|
|
|
|
#undef GECODE_INT_RL2PD
|
|
#undef GECODE_INT_PD2RL
|
|
|
|
/*
|
|
* Mainitaining range lists for variable domain
|
|
*
|
|
*/
|
|
|
|
forceinline IntVarImp::RangeList*
|
|
IntVarImp::fst(void) const {
|
|
return dom.next(nullptr);
|
|
}
|
|
|
|
forceinline void
|
|
IntVarImp::fst(IntVarImp::RangeList* f) {
|
|
dom.prevnext(nullptr,f);
|
|
}
|
|
|
|
forceinline IntVarImp::RangeList*
|
|
IntVarImp::lst(void) const {
|
|
return _lst;
|
|
}
|
|
|
|
forceinline void
|
|
IntVarImp::lst(IntVarImp::RangeList* l) {
|
|
_lst = l;
|
|
}
|
|
|
|
/*
|
|
* Creation of new variable implementations
|
|
*
|
|
*/
|
|
|
|
forceinline
|
|
IntVarImp::IntVarImp(Space& home, int min, int max)
|
|
: IntVarImpBase(home), dom(min,max,nullptr,nullptr), holes(0) {}
|
|
|
|
forceinline
|
|
IntVarImp::IntVarImp(Space& home, const IntSet& d)
|
|
: IntVarImpBase(home), dom(d.min(),d.max()) {
|
|
if (d.ranges() > 1) {
|
|
int n = d.ranges();
|
|
assert(n >= 2);
|
|
RangeList* r = home.alloc<RangeList>(n);
|
|
fst(r); lst(r+n-1);
|
|
unsigned int h = static_cast<unsigned int>(d.max()-d.min())+1;
|
|
h -= d.width(0);
|
|
r[0].min(d.min(0)); r[0].max(d.max(0));
|
|
r[0].prevnext(nullptr,&r[1]);
|
|
for (int i = 1; i < n-1; i++) {
|
|
h -= d.width(i);
|
|
r[i].min(d.min(i)); r[i].max(d.max(i));
|
|
r[i].prevnext(&r[i-1],&r[i+1]);
|
|
}
|
|
h -= d.width(n-1);
|
|
r[n-1].min(d.min(n-1)); r[n-1].max(d.max(n-1));
|
|
r[n-1].prevnext(&r[n-2],nullptr);
|
|
holes = h;
|
|
} else {
|
|
fst(nullptr); holes = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Operations on integer variable implementations
|
|
*
|
|
*/
|
|
|
|
forceinline int
|
|
IntVarImp::min(void) const {
|
|
return dom.min();
|
|
}
|
|
forceinline int
|
|
IntVarImp::max(void) const {
|
|
return dom.max();
|
|
}
|
|
forceinline int
|
|
IntVarImp::val(void) const {
|
|
assert(dom.min() == dom.max());
|
|
return dom.min();
|
|
}
|
|
|
|
forceinline bool
|
|
IntVarImp::range(void) const {
|
|
return fst() == nullptr;
|
|
}
|
|
forceinline bool
|
|
IntVarImp::assigned(void) const {
|
|
return dom.min() == dom.max();
|
|
}
|
|
|
|
|
|
forceinline unsigned int
|
|
IntVarImp::width(void) const {
|
|
return dom.width();
|
|
}
|
|
|
|
forceinline unsigned int
|
|
IntVarImp::size(void) const {
|
|
return dom.width() - holes;
|
|
}
|
|
|
|
forceinline unsigned int
|
|
IntVarImp::regret_min(void) const {
|
|
if (fst() == nullptr) {
|
|
return (dom.min() == dom.max()) ? 0U : 1U;
|
|
} else if (dom.min() == fst()->max()) {
|
|
return static_cast<unsigned int>(fst()->next(nullptr)->min()-dom.min());
|
|
} else {
|
|
return 1U;
|
|
}
|
|
}
|
|
forceinline unsigned int
|
|
IntVarImp::regret_max(void) const {
|
|
if (fst() == nullptr) {
|
|
return (dom.min() == dom.max()) ? 0U : 1U;
|
|
} else if (dom.max() == lst()->min()) {
|
|
return static_cast<unsigned int>(dom.max()-lst()->prev(nullptr)->max());
|
|
} else {
|
|
return 1U;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Tests
|
|
*
|
|
*/
|
|
|
|
forceinline bool
|
|
IntVarImp::in(int n) const {
|
|
if ((n < dom.min()) || (n > dom.max()))
|
|
return false;
|
|
return (fst() == nullptr) || in_full(n);
|
|
}
|
|
forceinline bool
|
|
IntVarImp::in(long long int n) const {
|
|
if ((n < dom.min()) || (n > dom.max()))
|
|
return false;
|
|
return (fst() == nullptr) || in_full(static_cast<int>(n));
|
|
}
|
|
|
|
|
|
/*
|
|
* Accessing rangelists for iteration
|
|
*
|
|
*/
|
|
|
|
forceinline const IntVarImp::RangeList*
|
|
IntVarImp::ranges_fwd(void) const {
|
|
return (fst() == nullptr) ? &dom : fst();
|
|
}
|
|
|
|
forceinline const IntVarImp::RangeList*
|
|
IntVarImp::ranges_bwd(void) const {
|
|
return (fst() == nullptr) ? &dom : lst();
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Support for delta information
|
|
*
|
|
*/
|
|
forceinline int
|
|
IntVarImp::min(const Delta& d) {
|
|
return static_cast<const IntDelta&>(d).min();
|
|
}
|
|
forceinline int
|
|
IntVarImp::max(const Delta& d) {
|
|
return static_cast<const IntDelta&>(d).max();
|
|
}
|
|
forceinline unsigned int
|
|
IntVarImp::width(const Delta& d) {
|
|
return static_cast<const IntDelta&>(d).width();
|
|
}
|
|
forceinline bool
|
|
IntVarImp::any(const Delta& d) {
|
|
return static_cast<const IntDelta&>(d).any();
|
|
}
|
|
|
|
|
|
/*
|
|
* Tell operations (to be inlined: performing bounds checks first)
|
|
*
|
|
*/
|
|
|
|
forceinline ModEvent
|
|
IntVarImp::gq(Space& home, int n) {
|
|
if (n <= dom.min()) return ME_INT_NONE;
|
|
if (n > dom.max()) return fail(home);
|
|
ModEvent me = gq_full(home,n);
|
|
GECODE_ASSUME((me == ME_INT_FAILED) |
|
|
(me == ME_INT_VAL) |
|
|
(me == ME_INT_BND));
|
|
return me;
|
|
}
|
|
forceinline ModEvent
|
|
IntVarImp::gq(Space& home, long long int n) {
|
|
if (n <= dom.min()) return ME_INT_NONE;
|
|
if (n > dom.max()) return fail(home);
|
|
ModEvent me = gq_full(home,static_cast<int>(n));
|
|
GECODE_ASSUME((me == ME_INT_FAILED) |
|
|
(me == ME_INT_VAL) |
|
|
(me == ME_INT_BND));
|
|
return me;
|
|
}
|
|
|
|
forceinline ModEvent
|
|
IntVarImp::lq(Space& home, int n) {
|
|
if (n >= dom.max()) return ME_INT_NONE;
|
|
if (n < dom.min()) return fail(home);
|
|
ModEvent me = lq_full(home,n);
|
|
GECODE_ASSUME((me == ME_INT_FAILED) |
|
|
(me == ME_INT_VAL) |
|
|
(me == ME_INT_BND));
|
|
return me;
|
|
}
|
|
forceinline ModEvent
|
|
IntVarImp::lq(Space& home, long long int n) {
|
|
if (n >= dom.max()) return ME_INT_NONE;
|
|
if (n < dom.min()) return fail(home);
|
|
ModEvent me = lq_full(home,static_cast<int>(n));
|
|
GECODE_ASSUME((me == ME_INT_FAILED) |
|
|
(me == ME_INT_VAL) |
|
|
(me == ME_INT_BND));
|
|
return me;
|
|
}
|
|
|
|
forceinline ModEvent
|
|
IntVarImp::eq(Space& home, int n) {
|
|
if ((n < dom.min()) || (n > dom.max()))
|
|
return fail(home);
|
|
if ((n == dom.min()) && (n == dom.max()))
|
|
return ME_INT_NONE;
|
|
ModEvent me = eq_full(home,n);
|
|
GECODE_ASSUME((me == ME_INT_FAILED) | (me == ME_INT_VAL));
|
|
return me;
|
|
}
|
|
forceinline ModEvent
|
|
IntVarImp::eq(Space& home, long long int m) {
|
|
if ((m < dom.min()) || (m > dom.max()))
|
|
return fail(home);
|
|
int n = static_cast<int>(m);
|
|
if ((n == dom.min()) && (n == dom.max()))
|
|
return ME_INT_NONE;
|
|
ModEvent me = eq_full(home,n);
|
|
GECODE_ASSUME((me == ME_INT_FAILED) | (me == ME_INT_VAL));
|
|
return me;
|
|
}
|
|
|
|
forceinline ModEvent
|
|
IntVarImp::nq(Space& home, int n) {
|
|
if ((n < dom.min()) || (n > dom.max()))
|
|
return ME_INT_NONE;
|
|
return nq_full(home,n);
|
|
}
|
|
forceinline ModEvent
|
|
IntVarImp::nq(Space& home, long long int d) {
|
|
if ((d < dom.min()) || (d > dom.max()))
|
|
return ME_INT_NONE;
|
|
return nq_full(home,static_cast<int>(d));
|
|
}
|
|
|
|
|
|
/*
|
|
* Forward range iterator for rangelists
|
|
*
|
|
*/
|
|
|
|
forceinline
|
|
IntVarImpFwd::IntVarImpFwd(void) {}
|
|
forceinline
|
|
IntVarImpFwd::IntVarImpFwd(const IntVarImp* x)
|
|
: p(nullptr), c(x->ranges_fwd()) {}
|
|
forceinline void
|
|
IntVarImpFwd::init(const IntVarImp* x) {
|
|
p=nullptr; c=x->ranges_fwd();
|
|
}
|
|
|
|
forceinline bool
|
|
IntVarImpFwd::operator ()(void) const {
|
|
return c != nullptr;
|
|
}
|
|
forceinline void
|
|
IntVarImpFwd::operator ++(void) {
|
|
const IntVarImp::RangeList* n=c->next(p); p=c; c=n;
|
|
}
|
|
|
|
forceinline int
|
|
IntVarImpFwd::min(void) const {
|
|
return c->min();
|
|
}
|
|
forceinline int
|
|
IntVarImpFwd::max(void) const {
|
|
return c->max();
|
|
}
|
|
forceinline unsigned int
|
|
IntVarImpFwd::width(void) const {
|
|
return c->width();
|
|
}
|
|
|
|
|
|
/*
|
|
* Backward range iterator for rangelists
|
|
*
|
|
*/
|
|
|
|
forceinline
|
|
IntVarImpBwd::IntVarImpBwd(void) {}
|
|
forceinline
|
|
IntVarImpBwd::IntVarImpBwd(const IntVarImp* x)
|
|
: n(nullptr), c(x->ranges_bwd()) {}
|
|
forceinline void
|
|
IntVarImpBwd::init(const IntVarImp* x) {
|
|
n=nullptr; c=x->ranges_bwd();
|
|
}
|
|
|
|
forceinline bool
|
|
IntVarImpBwd::operator ()(void) const {
|
|
return c != nullptr;
|
|
}
|
|
forceinline void
|
|
IntVarImpBwd::operator ++(void) {
|
|
const IntVarImp::RangeList* p=c->prev(n); n=c; c=p;
|
|
}
|
|
|
|
forceinline int
|
|
IntVarImpBwd::min(void) const {
|
|
return c->min();
|
|
}
|
|
forceinline int
|
|
IntVarImpBwd::max(void) const {
|
|
return c->max();
|
|
}
|
|
forceinline unsigned int
|
|
IntVarImpBwd::width(void) const {
|
|
return c->width();
|
|
}
|
|
|
|
|
|
/*
|
|
* Iterator-based domain operations
|
|
*
|
|
*/
|
|
template<class I>
|
|
forceinline ModEvent
|
|
IntVarImp::narrow_r(Space& home, I& ri, bool depends) {
|
|
// Is new domain empty?
|
|
if (!ri())
|
|
return fail(home);
|
|
|
|
int min0 = ri.min();
|
|
int max0 = ri.max();
|
|
++ri;
|
|
|
|
ModEvent me;
|
|
|
|
// Is new domain range?
|
|
if (!ri()) {
|
|
// Remove possible rangelist (if it was not a range, the domain
|
|
// must have been narrowed!)
|
|
if (fst()) {
|
|
fst()->dispose(home,nullptr,lst());
|
|
fst(nullptr); holes = 0;
|
|
}
|
|
const int min1 = dom.min(); dom.min(min0);
|
|
const int max1 = dom.max(); dom.max(max0);
|
|
if ((min0 == min1) && (max0 == max1))
|
|
return ME_INT_NONE;
|
|
me = (min0 == max0) ? ME_INT_VAL : ME_INT_BND;
|
|
goto notify;
|
|
}
|
|
|
|
if (depends || range()) {
|
|
// Construct new rangelist
|
|
RangeList* f = new (home) RangeList(min0,max0,nullptr,nullptr);
|
|
RangeList* l = f;
|
|
unsigned int s = static_cast<unsigned int>(max0-min0+1);
|
|
do {
|
|
RangeList* n = new (home) RangeList(ri.min(),ri.max(),l,nullptr);
|
|
l->next(nullptr,n);
|
|
l = n;
|
|
s += ri.width();
|
|
++ri;
|
|
} while (ri());
|
|
if (fst() != nullptr)
|
|
fst()->dispose(home,nullptr,lst());
|
|
fst(f); lst(l);
|
|
|
|
// Check for modification
|
|
if (size() == s)
|
|
return ME_INT_NONE;
|
|
|
|
const int min1 = dom.min(); min0 = f->min(); dom.min(min0);
|
|
const int max1 = dom.max(); max0 = l->max(); dom.max(max0);
|
|
holes = width() - s;
|
|
|
|
me = ((min0 == min1) && (max0 == max1)) ? ME_INT_DOM : ME_INT_BND;
|
|
goto notify;
|
|
} else {
|
|
// Set up two sentinel elements
|
|
RangeList f, l;
|
|
// Put all ranges between sentinels
|
|
f.prevnext(nullptr,fst()); l.prevnext(lst(),nullptr);
|
|
fst()->prev(nullptr,&f); lst()->next(nullptr,&l);
|
|
|
|
// Number of values removed (potential holes)
|
|
unsigned int h = 0;
|
|
// The previous range
|
|
RangeList* p = &f;
|
|
// The current range
|
|
RangeList* r = f.next(nullptr);
|
|
|
|
while (true) {
|
|
assert((r != &f) && (r != &l));
|
|
if (r->max() < min0) {
|
|
// Entire range removed
|
|
h += r->width();
|
|
RangeList* n=r->next(p);
|
|
p->next(r,n); n->prev(r,p);
|
|
r->dispose(home);
|
|
r=n;
|
|
if (r == &l)
|
|
goto done;
|
|
} else if ((r->min() == min0) && (r->max() == max0)) {
|
|
// Range unchanged
|
|
RangeList* n=r->next(p); p=r; r=n;
|
|
if (r == &l)
|
|
goto done;
|
|
if (!ri())
|
|
goto done;
|
|
min0=ri.min(); max0=ri.max(); ++ri;
|
|
} else {
|
|
// Range might have been split into many small ranges
|
|
assert((r->min() <= min0) && (max0 <= r->max()));
|
|
h += r->width();
|
|
int end = r->max();
|
|
// Copy first range
|
|
r->min(min0); r->max(max0);
|
|
assert(h > r->width());
|
|
h -= r->width();
|
|
{
|
|
RangeList* n=r->next(p); p=r; r=n;
|
|
}
|
|
while (true) {
|
|
if (!ri())
|
|
goto done;
|
|
min0=ri.min(); max0=ri.max(); ++ri;
|
|
if (max0 > end)
|
|
break;
|
|
assert(h > static_cast<unsigned int>(max0-min0+1));
|
|
h -= max0-min0+1;
|
|
RangeList* n = new (home) RangeList(min0,max0,p,r);
|
|
p->next(r,n); r->prev(p,n);
|
|
p=n;
|
|
}
|
|
if (r == &l)
|
|
goto done;
|
|
}
|
|
}
|
|
done:
|
|
|
|
// Remove remaining ranges
|
|
while (r != &l) {
|
|
h += r->width();
|
|
RangeList* n=r->next(p);
|
|
p->next(r,n); n->prev(r,p);
|
|
r->dispose(home);
|
|
r=n;
|
|
}
|
|
|
|
assert((r == &l) && !ri());
|
|
|
|
// New first and last ranges
|
|
RangeList* fn = f.next(nullptr);
|
|
RangeList* ln = l.prev(nullptr);
|
|
|
|
// All ranges pruned?
|
|
assert(fn != &l);
|
|
|
|
// Only a single range left?
|
|
assert(fn != ln);
|
|
|
|
// The number of removed values
|
|
holes += h;
|
|
// Unlink sentinel ranges
|
|
fn->prev(&f,nullptr); ln->next(&l,nullptr);
|
|
// How many values where removed at the bounds
|
|
unsigned int b = (static_cast<unsigned int>(fn->min()-dom.min()) +
|
|
static_cast<unsigned int>(dom.max()-ln->max()));
|
|
// Set new first and last ranges
|
|
fst(fn); lst(ln);
|
|
|
|
if (b > 0) {
|
|
assert((dom.min() != fn->min()) || (dom.max() != ln->max()));
|
|
dom.min(fn->min()); dom.max(ln->max());
|
|
holes -= b;
|
|
me = ME_INT_BND; goto notify;
|
|
}
|
|
|
|
if (h > 0) {
|
|
assert((dom.min() == fn->min()) && (dom.max() == ln->max()));
|
|
me = ME_INT_DOM; goto notify;
|
|
}
|
|
return ME_INT_NONE;
|
|
}
|
|
notify:
|
|
IntDelta d;
|
|
return notify(home,me,d);
|
|
}
|
|
|
|
template<class I>
|
|
forceinline ModEvent
|
|
IntVarImp::inter_r(Space& home, I& i, bool) {
|
|
IntVarImpFwd j(this);
|
|
Iter::Ranges::Inter<I,IntVarImpFwd> ij(i,j);
|
|
return narrow_r(home,ij,true);
|
|
}
|
|
|
|
template<class I>
|
|
forceinline ModEvent
|
|
IntVarImp::minus_r(Space& home, I& i, bool depends) {
|
|
if (depends) {
|
|
IntVarImpFwd j(this);
|
|
Iter::Ranges::Diff<IntVarImpFwd,I> ij(j,i);
|
|
return narrow_r(home,ij,true);
|
|
}
|
|
|
|
// Skip all ranges that are too small
|
|
while (i() && (i.max() < dom.min()))
|
|
++i;
|
|
|
|
// Is there no range left or all are too large?
|
|
if (!i() || (i.min() > dom.max()))
|
|
return ME_INT_NONE;
|
|
|
|
int i_min = i.min();
|
|
int i_max = i.max();
|
|
++i;
|
|
|
|
if ((i_min <= dom.min()) && (i_max >= dom.max()))
|
|
return fail(home);
|
|
|
|
if ((i_min > dom.min()) && (i_max >= dom.max()))
|
|
return lq(home,i_min-1);
|
|
|
|
if ((i_min <= dom.min()) && (i_max < dom.max()) &&
|
|
(!i() || (i.min() > dom.max())))
|
|
return gq(home,i_max+1);
|
|
|
|
// Set up two sentinel elements
|
|
RangeList f, l;
|
|
// Put all ranges between sentinels
|
|
if (range()) {
|
|
// Create a new rangelist just for simplicity
|
|
RangeList* n = new (home) RangeList(min(),max(),&f,&l);
|
|
f.prevnext(nullptr,n); l.prevnext(n,nullptr);
|
|
} else {
|
|
// Link the two sentinel elements
|
|
f.prevnext(nullptr,fst()); l.prevnext(lst(),nullptr);
|
|
fst()->prev(nullptr,&f); lst()->next(nullptr,&l);
|
|
}
|
|
|
|
// Number of values removed (potential holes)
|
|
unsigned int h = 0;
|
|
// The previous range
|
|
RangeList* p = &f;
|
|
// The current range
|
|
RangeList* r = f.next(nullptr);
|
|
|
|
while (true) {
|
|
assert((r != &f) && (r != &l));
|
|
if (i_min > r->max()) {
|
|
RangeList* n=r->next(p); p=r; r=n;
|
|
if (r == &l)
|
|
break;
|
|
} else if (i_max < r->min()) {
|
|
if (!i())
|
|
break;
|
|
i_min = i.min();
|
|
i_max = i.max();
|
|
++i;
|
|
} else if ((i_min <= r->min()) && (r->max() <= i_max)) {
|
|
// r is included in i: remove entire range r
|
|
h += r->width();
|
|
RangeList* n=r->next(p);
|
|
p->next(r,n); n->prev(r,p);
|
|
r->dispose(home);
|
|
r=n;
|
|
if (r == &l)
|
|
break;
|
|
} else if ((i_min > r->min()) && (i_max < r->max())) {
|
|
// i is included in r: create new range before the current one
|
|
h += static_cast<unsigned int>(i_max - i_min) + 1;
|
|
RangeList* n = new (home) RangeList(r->min(),i_min-1,p,r);
|
|
r->min(i_max+1);
|
|
p->next(r,n); r->prev(p,n);
|
|
p=n;
|
|
if (!i())
|
|
break;
|
|
i_min = i.min();
|
|
i_max = i.max();
|
|
++i;
|
|
} else if (i_max < r->max()) {
|
|
assert(i_min <= r->min());
|
|
// i ends before r: adjust minimum of r
|
|
h += i_max-r->min()+1;
|
|
r->min(i_max+1);
|
|
if (!i())
|
|
break;
|
|
i_min = i.min();
|
|
i_max = i.max();
|
|
++i;
|
|
} else {
|
|
assert((i_max >= r->max()) && (r->min() < i_min));
|
|
// r ends before i: adjust maximum of r
|
|
h += r->max()-i_min+1;
|
|
r->max(i_min-1);
|
|
RangeList* n=r->next(p); p=r; r=n;
|
|
if (r == &l)
|
|
break;
|
|
}
|
|
}
|
|
|
|
// New first and last ranges
|
|
RangeList* fn = f.next(nullptr);
|
|
RangeList* ln = l.prev(nullptr);
|
|
|
|
// All ranges pruned?
|
|
if (fn == &l) {
|
|
fst(nullptr); lst(nullptr); holes=0;
|
|
return fail(home);
|
|
}
|
|
|
|
ModEvent me;
|
|
unsigned int b;
|
|
|
|
// Only a single range left?
|
|
if (fn == ln) {
|
|
assert(h > 0);
|
|
dom.min(fn->min()); dom.max(fn->max());
|
|
fn->dispose(home);
|
|
fst(nullptr); lst(nullptr);
|
|
holes = 0;
|
|
me = assigned() ? ME_INT_VAL : ME_INT_BND;
|
|
goto notify;
|
|
}
|
|
|
|
// The number of removed values
|
|
holes += h;
|
|
// Unlink sentinel ranges
|
|
fn->prev(&f,nullptr); ln->next(&l,nullptr);
|
|
// How many values where removed at the bounds
|
|
b = (static_cast<unsigned int>(fn->min()-dom.min()) +
|
|
static_cast<unsigned int>(dom.max()-ln->max()));
|
|
// Set new first and last ranges
|
|
fst(fn); lst(ln);
|
|
|
|
if (b > 0) {
|
|
assert((dom.min() != fn->min()) || (dom.max() != ln->max()));
|
|
dom.min(fn->min()); dom.max(ln->max());
|
|
holes -= b;
|
|
me = ME_INT_BND; goto notify;
|
|
}
|
|
|
|
if (h > 0) {
|
|
assert((dom.min() == fn->min()) && (dom.max() == ln->max()));
|
|
me = ME_INT_DOM; goto notify;
|
|
}
|
|
|
|
return ME_INT_NONE;
|
|
notify:
|
|
IntDelta d;
|
|
return notify(home,me,d);
|
|
}
|
|
|
|
template<class I>
|
|
forceinline ModEvent
|
|
IntVarImp::narrow_v(Space& home, I& i, bool depends) {
|
|
Iter::Values::ToRanges<I> r(i);
|
|
return narrow_r(home,r,depends);
|
|
}
|
|
|
|
template<class I>
|
|
forceinline ModEvent
|
|
IntVarImp::inter_v(Space& home, I& i, bool depends) {
|
|
Iter::Values::ToRanges<I> r(i);
|
|
return inter_r(home,r,depends);
|
|
}
|
|
|
|
template<class I>
|
|
forceinline ModEvent
|
|
IntVarImp::minus_v(Space& home, I& i, bool depends) {
|
|
if (depends) {
|
|
Iter::Values::ToRanges<I> r(i);
|
|
return minus_r(home, r, true);
|
|
}
|
|
|
|
// Skip all values that are too small
|
|
while (i() && (i.val() < dom.min()))
|
|
++i;
|
|
|
|
// Is there no value left or all are too large?
|
|
if (!i() || (i.val() > dom.max()))
|
|
return ME_INT_NONE;
|
|
|
|
int v = i.val();
|
|
// Skip values that are the same
|
|
do {
|
|
++i;
|
|
} while (i() && (i.val() == v));
|
|
|
|
// Is there only a single value to be pruned?
|
|
if (!i() || (i.val() > dom.max()))
|
|
return nq_full(home,v);
|
|
|
|
// Set up two sentinel elements
|
|
RangeList f, l;
|
|
// Put all ranges between sentinels
|
|
if (range()) {
|
|
// Create a new rangelist just for simplicity
|
|
RangeList* n = new (home) RangeList(min(),max(),&f,&l);
|
|
f.prevnext(nullptr,n); l.prevnext(n,nullptr);
|
|
} else {
|
|
// Link the two sentinel elements
|
|
f.prevnext(nullptr,fst()); l.prevnext(lst(),nullptr);
|
|
fst()->prev(nullptr,&f); lst()->next(nullptr,&l);
|
|
}
|
|
|
|
// Number of values removed (potential holes)
|
|
unsigned int h = 0;
|
|
// The previous range
|
|
RangeList* p = &f;
|
|
// The current range
|
|
RangeList* r = f.next(nullptr);
|
|
|
|
while (true) {
|
|
assert((r != &f) && (r != &l));
|
|
if (v > r->max()) {
|
|
// Move to next range
|
|
RangeList* n=r->next(p); p=r; r=n;
|
|
if (r == &l)
|
|
break;
|
|
} else {
|
|
if ((v == r->min()) && (v == r->max())) {
|
|
// Remove range
|
|
h++;
|
|
RangeList* n=r->next(p);
|
|
p->next(r,n); n->prev(r,p);
|
|
r->dispose(home);
|
|
r=n;
|
|
if (r == &l)
|
|
break;
|
|
} else if (v == r->min()) {
|
|
h++; r->min(v+1);
|
|
} else if (v == r->max()) {
|
|
h++; r->max(v-1);
|
|
RangeList* n=r->next(p); p=r; r=n;
|
|
if (r == &l)
|
|
break;
|
|
} else if (v > r->min()) {
|
|
// Create new range before the current one
|
|
assert(v < r->max());
|
|
h++;
|
|
RangeList* n = new (home) RangeList(r->min(),v-1,p,r);
|
|
r->min(v+1);
|
|
p->next(r,n); r->prev(p,n);
|
|
p=n;
|
|
}
|
|
if (!i())
|
|
break;
|
|
// Move to next value
|
|
v = i.val(); ++i;
|
|
}
|
|
}
|
|
assert((r == &l) || !i());
|
|
|
|
// New first and last ranges
|
|
RangeList* fn = f.next(nullptr);
|
|
RangeList* ln = l.prev(nullptr);
|
|
|
|
// All ranges pruned?
|
|
if (fn == &l) {
|
|
fst(nullptr); lst(nullptr); holes=0;
|
|
return fail(home);
|
|
}
|
|
|
|
IntDelta d;
|
|
|
|
// Only a single range left?
|
|
if (fn == ln) {
|
|
assert(h > 0);
|
|
dom.min(fn->min()); dom.max(fn->max());
|
|
fn->dispose(home);
|
|
fst(nullptr); lst(nullptr);
|
|
holes = 0;
|
|
if (assigned())
|
|
return notify(home,ME_INT_VAL,d);
|
|
else
|
|
return notify(home,ME_INT_BND,d);
|
|
}
|
|
|
|
// The number of removed values
|
|
holes += h;
|
|
// Unlink sentinel ranges
|
|
fn->prev(&f,nullptr); ln->next(&l,nullptr);
|
|
// How many values where removed at the bounds
|
|
unsigned int b = (static_cast<unsigned int>(fn->min()-dom.min()) +
|
|
static_cast<unsigned int>(dom.max()-ln->max()));
|
|
// Set new first and last ranges
|
|
fst(fn); lst(ln);
|
|
|
|
if (b > 0) {
|
|
assert((dom.min() != fn->min()) || (dom.max() != ln->max()));
|
|
dom.min(fn->min()); dom.max(ln->max());
|
|
holes -= b;
|
|
return notify(home,ME_INT_BND,d);
|
|
}
|
|
|
|
if (h > 0) {
|
|
assert((dom.min() == fn->min()) && (dom.max() == ln->max()));
|
|
return notify(home,ME_INT_DOM,d);
|
|
}
|
|
|
|
return ME_INT_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Copying a variable
|
|
*
|
|
*/
|
|
|
|
forceinline IntVarImp*
|
|
IntVarImp::copy(Space& home) {
|
|
return copied() ? static_cast<IntVarImp*>(forward())
|
|
: perform_copy(home);
|
|
}
|
|
|
|
|
|
forceinline ModEventDelta
|
|
IntVarImp::med(ModEvent me) {
|
|
return IntVarImpBase::med(me);
|
|
}
|
|
|
|
}}
|
|
|
|
// STATISTICS: int-var
|