1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.
Jip J. Dekker 2572df0663 Squashed 'software/gecode_base/' content from commit bbefcea214
git-subtree-dir: software/gecode_base
git-subtree-split: bbefcea214fec798a0f5acc442581984555acd21
2021-07-11 17:26:05 +10:00

296 lines
9.2 KiB
C++

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Guido Tack <tack@gecode.org>
* Christian Schulte <schulte@gecode.org>
*
* Copyright:
* Guido Tack, 2004,2006,2007
* Christian Schulte, 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 Set { namespace Element {
template<class SView, class RView>
forceinline
ElementUnionConst<SView,RView>::
ElementUnionConst(Home home, SView y0,
const IntSetArgs& iv0,
RView y1)
: Propagator(home), x0(y0), n_iv(iv0.size()), x1(y1) {
home.notice(*this,AP_DISPOSE);
x0.subscribe(home,*this, PC_SET_ANY);
x1.subscribe(home,*this, PC_SET_ANY);
iv=static_cast<Space&>(home).alloc<IntSet>(n_iv);
for (unsigned int i=iv0.size(); i--;)
iv[i]=iv0[i];
}
template<class SView, class RView>
forceinline
ElementUnionConst<SView,RView>::
ElementUnionConst(Space& home, ElementUnionConst<SView,RView>& p)
: Propagator(home,p), n_iv(p.n_iv) {
x0.update(home,p.x0);
x1.update(home,p.x1);
iv=home.alloc<IntSet>(n_iv);
for (unsigned int i=n_iv; i--;)
iv[i]=p.iv[i];
}
template<class SView, class RView>
PropCost
ElementUnionConst<SView,RView>::cost(const Space&, const ModEventDelta&) const {
return PropCost::linear(PropCost::HI, n_iv+2);
}
template<class SView, class RView>
void
ElementUnionConst<SView,RView>::reschedule(Space& home) {
x0.reschedule(home,*this, PC_SET_ANY);
x1.reschedule(home,*this, PC_SET_ANY);
}
template<class SView, class RView>
forceinline size_t
ElementUnionConst<SView,RView>::dispose(Space& home) {
home.ignore(*this,AP_DISPOSE);
if (!home.failed()) {
x0.cancel(home,*this, PC_SET_ANY);
x1.cancel(home,*this, PC_SET_ANY);
}
for (unsigned int i=n_iv; i--;)
iv[i].~IntSet();
(void) Propagator::dispose(home);
return sizeof(*this);
}
template<class SView, class RView>
ExecStatus
ElementUnionConst<SView,RView>::
post(Home home, SView x0, const IntSetArgs& xs,
RView x1) {
int n = xs.size();
// s2 \subseteq {1,...,n}
Iter::Ranges::Singleton s(0, n-1);
GECODE_ME_CHECK(x1.intersectI(home,s));
(void) new (home)
ElementUnionConst<SView,RView>(home,x0,xs,x1);
return ES_OK;
}
template<class SView, class RView>
Actor*
ElementUnionConst<SView,RView>::copy(Space& home) {
return new (home) ElementUnionConst<SView,RView>(home,*this);
}
template<class SView, class RView>
ExecStatus
ElementUnionConst<SView,RView>::propagate(Space& home, const ModEventDelta&) {
Region r;
bool* stillSelected = r.alloc<bool>(n_iv);
bool loopVar;
do {
loopVar = false;
for (int i=n_iv; i--;)
stillSelected[i] = false;
// Cache the upper bound iterator, as we have to
// modify the upper bound while iterating
LubRanges<RView> x1ub(x1);
Iter::Ranges::Cache x1ubc(r,x1ub);
Iter::Ranges::ToValues<Iter::Ranges::Cache>
vx1ub(x1ubc);
GlbRanges<RView> x1lb(x1);
Iter::Ranges::Cache x1lbc(r,x1lb);
Iter::Ranges::ToValues<Iter::Ranges::Cache>
vx1(x1lbc);
// In the first iteration, compute in before[i] the union
// of all the upper bounds of the x_i. At the same time,
// exclude inconsistent x_i from x1.
GLBndSet sofarBefore(home);
LUBndSet selectedInter(home, IntSet (Limits::min,
Limits::max));
GLBndSet* before =
static_cast<GLBndSet*>(r.ralloc(sizeof(GLBndSet)*n_iv));
unsigned int maxCard = 0;
unsigned int minCard = Limits::card;
while (vx1ub()) {
int i = vx1ub.val();
IntSetRanges candCardR(iv[i]);
unsigned int candidateCard = Iter::Ranges::size(candCardR);
IntSetRanges candlb(iv[i]);
LubRanges<SView> x0ub(x0);
Iter::Ranges::Diff<IntSetRanges,
LubRanges<SView> > diff(candlb, x0ub);
bool selectSingleInconsistent = false;
if (x1.cardMax() <= 1) {
GlbRanges<SView> x0lb(x0);
IntSetRanges candub(iv[i]);
Iter::Ranges::Diff<GlbRanges<SView>,
IntSetRanges > diff2(x0lb, candub);
selectSingleInconsistent = diff2() || candidateCard < x0.cardMin();
}
// exclude inconsistent x_i
// an x_i is inconsistent if
// * at most one x_i can be selected and there are
// elements in x_0 that can't be in x_i
// (selectSingleInconsistent)
// * its min cardinality is greater than maxCard of x0
// * inter is not empty (there are elements in x_i
// that can't be in x_0)
if (selectSingleInconsistent ||
candidateCard > x0.cardMax() ||
diff()) {
ModEvent me = (x1.exclude(home,i));
loopVar |= me_modified(me);
GECODE_ME_CHECK(me);
} else {
stillSelected[i] = true;
// if x_i is consistent, check whether we know
// that its index is in x1
if (vx1() && vx1.val()==i) {
// x0 >= candidate, candidate <= x0
// GlbRanges<SView> candlb(candidate);
IntSetRanges candlb(iv[i]);
ModEvent me = x0.includeI(home,candlb);
loopVar |= me_modified(me);
GECODE_ME_CHECK(me);
++vx1;
}
new (&before[i]) GLBndSet(home);
before[i].update(home,sofarBefore);
IntSetRanges cub(iv[i]);
sofarBefore.includeI(home,cub);
IntSetRanges clb(iv[i]);
selectedInter.intersectI(home,clb);
maxCard = std::max(maxCard, candidateCard);
minCard = std::min(minCard, candidateCard);
}
++vx1ub;
}
if (x1.cardMax()==0) {
// Selector is empty, hence the result must be empty
{
GECODE_ME_CHECK(x0.cardMax(home,0));
}
for (int i=n_iv; i--;)
if (stillSelected[i])
before[i].dispose(home);
selectedInter.dispose(home);
sofarBefore.dispose(home);
return home.ES_SUBSUMED(*this);
}
if (x1.cardMin() > 0) {
// Selector is not empty, hence the intersection of the
// possibly selected lower bounds is contained in x0
BndSetRanges si(selectedInter);
ModEvent me = x0.includeI(home, si);
loopVar |= me_modified(me);
GECODE_ME_CHECK(me);
me = x0.cardMin(home, minCard);
loopVar |= me_modified(me);
GECODE_ME_CHECK(me);
}
selectedInter.dispose(home);
if (x1.cardMax() <= 1) {
ModEvent me = x0.cardMax(home, maxCard);
loopVar |= me_modified(me);
GECODE_ME_CHECK(me);
}
{
// x0 <= sofarBefore
BndSetRanges sfB(sofarBefore);
ModEvent me = x0.intersectI(home,sfB);
loopVar |= me_modified(me);
GECODE_ME_CHECK(me);
}
sofarBefore.dispose(home);
GLBndSet sofarAfter(home);
// In the second iteration, this time backwards, compute
// sofarAfter as the union of all lub(x_j) with j>i
for (int i=n_iv; i--;) {
if (!stillSelected[i])
continue;
BndSetRanges b(before[i]);
BndSetRanges s(sofarAfter);
GlbRanges<SView> x0lb(x0);
Iter::Ranges::Union<BndSetRanges, BndSetRanges> inter(b,s);
Iter::Ranges::Diff<GlbRanges<SView>,
Iter::Ranges::Union<BndSetRanges,BndSetRanges> > diff(x0lb, inter);
if (diff()) {
ModEvent me = (x1.include(home,i));
loopVar |= me_modified(me);
GECODE_ME_CHECK(me);
// candidate != extra
IntSetRanges ivi(iv[i]);
if (!Iter::Ranges::subset(diff, ivi))
GECODE_ME_CHECK(ME_SET_FAILED);
}
IntSetRanges iviub(iv[i]);
sofarAfter.includeI(home,iviub);
before[i].dispose(home);
}
sofarAfter.dispose(home);
} while (loopVar);
if (x1.assigned()) {
assert(x0.assigned());
return home.ES_SUBSUMED(*this);
}
return ES_FIX;
}
}}}
// STATISTICS: set-prop