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

615 lines
19 KiB
C++
Executable File

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Guido Tack <tack@gecode.org>
* Christian Schulte <schulte@gecode.org>
*
* Contributing authors:
* Gabor Szokoli <szokoli@gecode.org>
*
* Copyright:
* Guido Tack, 2004
* Christian Schulte, 2004
* Gabor Szokoli, 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.
*
*/
#ifndef GECODE_SET_RELOP_COMM_ICC
#define GECODE_SET_RELOP_COMM_ICC
namespace Gecode {
template<class View0, class View1>
forceinline bool
viewarrayshared(const ViewArray<View0>& va, const View1& y) {
return shared(va,y);
}
template<>
forceinline bool
viewarrayshared<Set::SingletonView,Set::SetView>
(const ViewArray<Set::SingletonView>&, const Set::SetView&) {
return false;
}
template<>
forceinline bool
viewarrayshared<Set::ComplementView<Set::SingletonView>,Set::SetView>
(const ViewArray<Set::ComplementView<Set::SingletonView> >&,
const Set::SetView&) {
return false;
}
template<>
forceinline bool
viewarrayshared<Set::ComplementView<Set::SingletonView>,
Set::ComplementView<Set::SetView> >
(const ViewArray<Set::ComplementView<Set::SingletonView> >&,
const Set::ComplementView<Set::SetView>&) {
return false;
}
namespace Set { namespace RelOp {
/*
* Detect sharing between 3 variables
*
*/
template<class View0, class View1, class View2>
forceinline bool
shared(View0 v0, View1 v1, View2 v2) {
return shared(v0,v1) || shared(v0,v2) || shared(v1,v2);
}
template<class View0, class View1, class View2>
ExecStatus interCard(Space& home,
bool& retmodified, View0& x0, View1& x1, View2& x2) {
bool modified = false;
do {
retmodified |= modified;
modified = false;
{
LubRanges<View0> x0ub(x0);
LubRanges<View1> x1ub(x1);
Iter::Ranges::Union<LubRanges<View0>, LubRanges<View1> >
u1(x0ub,x1ub);
unsigned int s1 = Iter::Ranges::size(u1);
if (x0.cardMin() + x1.cardMin() > s1) {
GECODE_ME_CHECK_MODIFIED(modified,
x2.cardMin(home, x0.cardMin()+x1.cardMin()-s1));
}
// unsigned int res = std::max(x0.cardMin()+
// (x1.cardMin()<s1 ?
// 0 : x1.cardMin()-s1),
// std::max(x0.cardMin(),
// x1.cardMin()));
// GECODE_ME_CHECK_MODIFIED(modified, x2.cardMin(home,res));
}
{
GlbRanges<View0> x0lb(x0);
GlbRanges<View1> x1lb(x1);
Iter::Ranges::Union<GlbRanges<View0>, GlbRanges<View1> >
u1(x0lb,x1lb);
unsigned int s1 = Iter::Ranges::size(u1);
GECODE_ME_CHECK_MODIFIED(modified,
x2.cardMax(home,
x0.cardMax()+x1.cardMax()-s1));
}
if (x2.cardMax() < x1.cardMin())
GECODE_ME_CHECK_MODIFIED(modified,
x0.cardMax(home,
Set::Limits::card+x2.cardMax()-x1.cardMin()));
if (x2.cardMax() < x0.cardMin())
GECODE_ME_CHECK_MODIFIED(modified,
x1.cardMax(home,
Set::Limits::card+x2.cardMax()-x0.cardMin()));
GECODE_ME_CHECK_MODIFIED(modified,
x0.cardMin(home,x2.cardMin()));
GECODE_ME_CHECK_MODIFIED(modified,
x1.cardMin(home,x2.cardMin()));
} while(modified);
return ES_FIX;
}
template<class View0, class View1, class View2>
ExecStatus unionCard(Space& home,
bool& retmodified, View0& x0, View1& x1, View2& x2) {
bool modified = false;
do {
retmodified |= modified;
modified = false;
{
LubRanges<View0> x0ub(x0);
LubRanges<View1> x1ub(x1);
Iter::Ranges::Inter<LubRanges<View0>, LubRanges<View1> > i1(x0ub,x1ub);
unsigned int s1 = Iter::Ranges::size(i1);
unsigned int res = std::max(x0.cardMin()+
(x1.cardMin()<s1 ?
0 : x1.cardMin()-s1),
std::max(x0.cardMin(),
x1.cardMin()));
GECODE_ME_CHECK_MODIFIED(modified, x2.cardMin(home,res));
}
{
LubRanges<View0> x0ub(x0);
LubRanges<View1> x1ub(x1);
Iter::Ranges::Union<LubRanges<View0>, LubRanges<View1> > u1(x0ub,x1ub);
unsigned int s1 = Iter::Ranges::size(u1);
GECODE_ME_CHECK_MODIFIED(modified,
x2.cardMax(home,
std::min(x0.cardMax()+x1.cardMax(),s1)));
}
if (x2.cardMin() > x1.cardMax())
GECODE_ME_CHECK_MODIFIED(modified,
x0.cardMin(home,x2.cardMin() - x1.cardMax()));
if (x2.cardMin() > x0.cardMax())
GECODE_ME_CHECK_MODIFIED(modified,
x1.cardMin(home,x2.cardMin() - x0.cardMax()));
GECODE_ME_CHECK_MODIFIED(modified,
x0.cardMax(home,x2.cardMax()));
GECODE_ME_CHECK_MODIFIED(modified,
x1.cardMax(home,x2.cardMax()));
} while(modified);
return ES_FIX;
}
template<class View0, class View1>
ExecStatus
unionNCard(Space& home, bool& modified, ViewArray<View0>& x,
View1& y, GLBndSet& unionOfDets) {
int xsize = x.size();
// Max(Xi.cardMin) <= y.card <= Sum(Xi.cardMax)
// Xi.card <=y.cardMax
unsigned int cardMaxSum=unionOfDets.size();
bool maxValid = true;
for (int i=xsize; i--; ) {
cardMaxSum+=x[i].cardMax();
if (cardMaxSum < x[i].cardMax()) { maxValid = false; } //overflow
GECODE_ME_CHECK_MODIFIED(modified, y.cardMin(home,x[i].cardMin()) );
GECODE_ME_CHECK_MODIFIED(modified, x[i].cardMax(home,y.cardMax()) );
}
if (maxValid) {
GECODE_ME_CHECK_MODIFIED(modified, y.cardMax(home,cardMaxSum));
}
//y.cardMin - Sum(Xj.cardMax) <= Xi.card
if (x.size() == 0)
return ES_NOFIX;
Region r;
//TODO: overflow management is a waste now.
{
unsigned int* rightSum = r.alloc<unsigned int>(xsize);
rightSum[xsize-1]=0;
for (int i=x.size()-1;i--;) {
rightSum[i] = rightSum[i+1] + x[i+1].cardMax();
if (rightSum[i] < rightSum[i+1]) {
//overflow, fill the rest of the array.
for (int j=i; j>0;j--) {
rightSum[j]=Limits::card;
}
break;
}
}
//Size of union of determied vars missing from x sneaked in here:
unsigned int leftAcc=unionOfDets.size();
for (int i=0; i<xsize;i++) {
unsigned int jsum = leftAcc+rightSum[i];
//If jsum did not overflow and is less than y.cardMin:
if (jsum >= leftAcc && jsum < y.cardMin()) {
GECODE_ME_CHECK_MODIFIED(modified, x[i].cardMin(home,y.cardMin()-jsum));
}
leftAcc += x[i].cardMax();
if (leftAcc < x[i].cardMax()) {leftAcc = Limits::card;}
}
}
//y.cardMin - |U(Xj.ub)| <= Xi.card
{
GLBndSet* rightUnion =
static_cast<GLBndSet*>(r.ralloc(sizeof(GLBndSet)*xsize));
new (&rightUnion[xsize-1]) GLBndSet(home);
for (int i=xsize-1;i--;) {
BndSetRanges prev(rightUnion[i+1]);
LubRanges<View0> prevX(x[i+1]);
Iter::Ranges::Union< BndSetRanges,LubRanges<View0> >
iter(prev,prevX);
new (&rightUnion[i]) GLBndSet(home);
rightUnion[i].includeI(home, iter);
}
//union of determied vars missing from x sneaked in here:
GLBndSet leftAcc;
leftAcc.update(home,unionOfDets);
for (int i=0; i<xsize; i++) {
BndSetRanges left(leftAcc);
BndSetRanges right(rightUnion[i]);
Iter::Ranges::Union<BndSetRanges,
BndSetRanges> iter(left, right);
unsigned int unionSize = Iter::Ranges::size(iter);
if (y.cardMin() > unionSize) {
GECODE_ME_CHECK_MODIFIED(modified,
x[i].cardMin(home, y.cardMin() - unionSize) );
}
LubRanges<View0> xiub(x[i]);
leftAcc.includeI(home, xiub);
}
for (int i=xsize; i--;)
rightUnion[i].dispose(home);
leftAcc.dispose(home);
}
//no need for this: |y.lb - U(Xj.cardMax)| <= S.card
return ES_NOFIX;
}
/*
* Xi UB is subset of YUB
* Subscribes to Y UB
*/
template<class View0, class View1>
ExecStatus
unionNXiUB(Space& home,
bool& modified, ViewArray<View0>& x, View1& y,
GLBndSet &) {
int xsize = x.size();
for (int i=xsize; i--; ) {
LubRanges<View1> yub(y);
GECODE_ME_CHECK_MODIFIED(modified, x[i].intersectI(home, yub));
}
return ES_FIX;
}
// cardinality rules for PartitionN constraint
template<class View0, class View1>
ExecStatus
partitionNCard(Space& home,
bool& modified, ViewArray<View0>& x, View1& y,
GLBndSet& unionOfDets) {
unsigned int cardMinSum=unionOfDets.size();
unsigned int cardMaxSum=unionOfDets.size();
int xsize = x.size();
for (int i=xsize; i--; ) {
cardMinSum+=x[i].cardMin();
if (cardMinSum < x[i].cardMin()) {
//sum of mins overflows: fail the space.
GECODE_ME_CHECK(ME_SET_FAILED);
}
}
GECODE_ME_CHECK_MODIFIED(modified, y.cardMin(home,cardMinSum));
for (int i=xsize; i--; ) {
cardMaxSum+=x[i].cardMax();
if (cardMaxSum < x[i].cardMax()) {
//sum of maxes overflows: no useful information to tell.
goto overflow;
}
}
GECODE_ME_CHECK_MODIFIED(modified, y.cardMax(home,cardMaxSum));
if (x.size() == 0)
return ES_NOFIX;
overflow:
//Cardinality of each x[i] limited by cardinality of y minus all x[j]s:
{
Region r;
unsigned int* rightMinSum = r.alloc<unsigned int>(xsize);
unsigned int* rightMaxSum = r.alloc<unsigned int>(xsize);
rightMinSum[xsize-1]=0;
rightMaxSum[xsize-1]=0;
for (int i=x.size()-1;i--;) {
rightMaxSum[i] = rightMaxSum[i+1] + x[i+1].cardMax();
if (rightMaxSum[i] < rightMaxSum[i+1]) {
//overflow, fill the rest of the array.
for (int j=i; j>0;j--) {
rightMaxSum[j]=Limits::card;
}
break;
}
}
for (int i=x.size()-1;i--;) {
rightMinSum[i] = rightMinSum[i+1] + x[i+1].cardMin();
if (rightMinSum[i] < rightMinSum[i+1]) {
//overflow, fail the space
GECODE_ME_CHECK(ME_SET_FAILED);
}
}
unsigned int leftMinAcc=unionOfDets.size();
unsigned int leftMaxAcc=unionOfDets.size();
for (int i=0; i<xsize;i++) {
unsigned int maxSum = leftMaxAcc+rightMaxSum[i];
unsigned int minSum = leftMinAcc+rightMinSum[i];
//If maxSum did not overflow and is less than y.cardMin:
if (maxSum >= leftMaxAcc && maxSum < y.cardMin()) {
GECODE_ME_CHECK_MODIFIED(modified, x[i].cardMin(home,y.cardMin()-maxSum));
}
//Overflow, fail.
if (minSum < leftMinAcc || y.cardMax() < minSum) {
GECODE_ME_CHECK(ME_SET_FAILED);
}
else {
GECODE_ME_CHECK_MODIFIED(modified, x[i].cardMax(home,y.cardMax()-minSum));
}
leftMaxAcc += x[i].cardMax();
if (leftMaxAcc < x[i].cardMax())
leftMaxAcc = Limits::card;
leftMinAcc += x[i].cardMin();
if (leftMinAcc < x[i].cardMin())
GECODE_ME_CHECK(ME_SET_FAILED);
}
}
return ES_NOFIX;
}
// Xi LB includes YLB minus union Xj UB
// Xi UB is subset of YUB minus union of Xj LBs
template<class View0, class View1>
ExecStatus
partitionNXi(Space& home,
bool& modified, ViewArray<View0>& x, View1& y) {
int xsize = x.size();
Region r;
GLBndSet* afterUB =
static_cast<GLBndSet*>(r.ralloc(sizeof(GLBndSet)*xsize));
GLBndSet* afterLB =
static_cast<GLBndSet*>(r.ralloc(sizeof(GLBndSet)*xsize));
{
GLBndSet sofarAfterUB;
GLBndSet sofarAfterLB;
for (int i=xsize; i--;) {
new (&afterUB[i]) GLBndSet(home);
new (&afterLB[i]) GLBndSet(home);
afterUB[i].update(home,sofarAfterUB);
afterLB[i].update(home,sofarAfterLB);
LubRanges<View0> xiub(x[i]);
GlbRanges<View0> xilb(x[i]);
sofarAfterUB.includeI(home,xiub);
sofarAfterLB.includeI(home,xilb);
}
sofarAfterUB.dispose(home);
sofarAfterLB.dispose(home);
}
{
GLBndSet sofarBeforeUB;
GLBndSet sofarBeforeLB;
for (int i=0; i<xsize; i++) {
LubRanges<View1> yub(y);
BndSetRanges slb(sofarBeforeLB);
BndSetRanges afterlb(afterLB[i]);
Iter::Ranges::Union<BndSetRanges,
BndSetRanges> xjlb(slb, afterlb);
Iter::Ranges::Diff<LubRanges<View1>,
Iter::Ranges::Union<BndSetRanges,
BndSetRanges> > diff1(yub, xjlb);
GECODE_ME_CHECK_MODIFIED(modified, x[i].intersectI(home,diff1));
GlbRanges<View1> ylb(y);
BndSetRanges sub(sofarBeforeUB);
BndSetRanges afterub(afterUB[i]);
Iter::Ranges::Union<BndSetRanges,
BndSetRanges> xjub(sub, afterub);
Iter::Ranges::Diff<GlbRanges<View1>,
Iter::Ranges::Union<BndSetRanges,
BndSetRanges> > diff2(ylb, xjub);
GECODE_ME_CHECK_MODIFIED(modified, x[i].includeI(home,diff2));
LubRanges<View0> xiub(x[i]);
GlbRanges<View0> xilb(x[i]);
sofarBeforeUB.includeI(home,xiub);
sofarBeforeLB.includeI(home,xilb);
}
sofarBeforeLB.dispose(home);
sofarBeforeUB.dispose(home);
}
for (int i=xsize;i--;) {
afterUB[i].dispose(home);
afterLB[i].dispose(home);
}
return ES_NOFIX;
}
// Xi UB is subset of YUB minus union of Xj LBs
template<class View0, class View1>
ExecStatus
partitionNXiUB(Space& home,
bool& modified, ViewArray<View0>& x, View1& y,
GLBndSet& unionOfDets) {
int xsize = x.size();
Region r;
GLBndSet* afterLB =
static_cast<GLBndSet*>(r.ralloc(sizeof(GLBndSet)*xsize));
{
GLBndSet sofarAfterLB;
for (int i=xsize; i--;) {
new (&afterLB[i]) GLBndSet(home);
afterLB[i].update(home,sofarAfterLB);
GlbRanges<View0> xilb(x[i]);
sofarAfterLB.includeI(home,xilb);
}
sofarAfterLB.dispose(home);
}
{
GLBndSet sofarBeforeLB;
sofarBeforeLB.update(home,unionOfDets);
for (int i=0; i<xsize; i++) {
LubRanges<View1> yub(y);
BndSetRanges slb(sofarBeforeLB);
BndSetRanges afterlb(afterLB[i]);
Iter::Ranges::Union<BndSetRanges,
BndSetRanges> xjlb(slb, afterlb);
Iter::Ranges::Diff<LubRanges<View1>,
Iter::Ranges::Union<BndSetRanges,
BndSetRanges> > diff1(yub, xjlb);
GECODE_ME_CHECK_MODIFIED(modified, x[i].intersectI(home,diff1));
GlbRanges<View0> xilb(x[i]);
sofarBeforeLB.includeI(home,xilb);
}
sofarBeforeLB.dispose(home);
}
for (int i=xsize; i--;)
afterLB[i].dispose(home);
return ES_NOFIX;
}
// Xi LB includes YLB minus union Xj UB
template<class View0, class View1>
ExecStatus
partitionNXiLB(Space& home,
bool& modified, ViewArray<View0>& x, View1& y,
GLBndSet& unionOfDets) {
int xsize = x.size();
Region r;
GLBndSet* afterUB =
static_cast<GLBndSet*>(r.ralloc(sizeof(GLBndSet)*xsize));
{
GLBndSet sofarAfterUB;
for (int i=xsize; i--;) {
new (&afterUB[i]) GLBndSet(home);
afterUB[i].update(home,sofarAfterUB);
LubRanges<View0> xiub(x[i]);
sofarAfterUB.includeI(home,xiub);
}
sofarAfterUB.dispose(home);
}
{
//The union of previously determined x[j]-s is added to the mix here:
GLBndSet sofarBeforeUB;
sofarBeforeUB.update(home,unionOfDets);
for (int i=0; i<xsize; i++) {
GlbRanges<View1> ylb(y);
BndSetRanges sub(sofarBeforeUB);
BndSetRanges afterub(afterUB[i]);
Iter::Ranges::Union<BndSetRanges,
BndSetRanges> xjub(sub, afterub);
Iter::Ranges::Diff<GlbRanges<View1>,
Iter::Ranges::Union<BndSetRanges,
BndSetRanges> > diff2(ylb, xjub);
GECODE_ME_CHECK_MODIFIED(modified, x[i].includeI(home,diff2));
LubRanges<View0> xiub(x[i]);
sofarBeforeUB.includeI(home,xiub);
}
sofarBeforeUB.dispose(home);
}
for (int i=xsize;i--;)
afterUB[i].dispose(home);
return ES_NOFIX;
}
// Y LB contains union of X LBs
template<class View0, class View1>
ExecStatus
partitionNYLB(Space& home,
bool& modified, ViewArray<View0>& x, View1& y,
GLBndSet& unionOfDets) {
assert(unionOfDets.isConsistent());
int xsize = x.size();
Region reg;
GlbRanges<View0>* xLBs = reg.alloc<GlbRanges<View0> >(xsize);
int nonEmptyCounter=0;
for (int i = xsize; i--; ) {
GlbRanges<View0> r(x[i]);
if (r()) {
xLBs[nonEmptyCounter] = r;
nonEmptyCounter++;
}
}
if (nonEmptyCounter !=0) {
Iter::Ranges::NaryUnion xLBUnion(reg,xLBs,nonEmptyCounter);
BndSetRanges dets(unionOfDets);
xLBUnion |= dets;
GECODE_ME_CHECK_MODIFIED(modified, y.includeI(home,xLBUnion));
}
return ES_FIX;
}
// Y UB is subset of union of X UBs
template<class View0, class View1>
ExecStatus
partitionNYUB(Space& home,
bool& modified, ViewArray<View0>& x, View1& y,
GLBndSet& unionOfDets) {
int xsize = x.size();
Region reg;
LubRanges<View0>* xUBs = reg.alloc<LubRanges<View0> >(xsize);
int nonEmptyCounter=0;
for (int i = xsize; i--; ) {
LubRanges<View0> r(x[i]);
if (r()) {
xUBs[nonEmptyCounter] = r;
nonEmptyCounter++;
}
}
if (nonEmptyCounter != 0) {
Iter::Ranges::NaryUnion xUBUnion(reg,xUBs,nonEmptyCounter);
BndSetRanges dets(unionOfDets);
xUBUnion |= dets;
GECODE_ME_CHECK_MODIFIED(modified, y.intersectI(home,xUBUnion));
}
return ES_FIX;
}
}}}
#endif
// STATISTICS: set-prop