git-subtree-dir: software/gecode_on_record git-subtree-split: 37ed9bda495ea87e63217c19a374b5a93bb0078e
481 lines
13 KiB
C++
Executable File
481 lines
13 KiB
C++
Executable File
/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
|
/*
|
|
* Main authors:
|
|
* Christian Schulte <schulte@gecode.org>
|
|
*
|
|
* Copyright:
|
|
* Christian Schulte, 2006
|
|
*
|
|
* 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 { namespace Linear {
|
|
|
|
/**
|
|
* \brief %Set for support information
|
|
*
|
|
* Records supported positions of values such that with iteration
|
|
* the supported values can be reconstructed.
|
|
*
|
|
*/
|
|
class SupportSet {
|
|
private:
|
|
/// Bitset for storing support information
|
|
Support::BitSetBase bs;
|
|
public:
|
|
/// Default constructor
|
|
SupportSet(void);
|
|
/// Initialize support set with cardinality \a n
|
|
void init(Region& r, unsigned int n);
|
|
/// Record that there is support at position \a i
|
|
void support(unsigned int i);
|
|
/// Check whether position \arg i has support
|
|
bool supported(unsigned int i) const;
|
|
|
|
private:
|
|
/// Support-based iterator: iterates values to be removed
|
|
class ResultIter : public ViewValues<IntView> {
|
|
protected:
|
|
/// The support set used
|
|
const SupportSet& s;
|
|
/// The current position of the value
|
|
unsigned int p;
|
|
public:
|
|
/// Initialize iterator
|
|
ResultIter(const SupportSet& s0, const IntView& x);
|
|
/// Increment to next supported value
|
|
void operator ++(void);
|
|
};
|
|
|
|
public:
|
|
/// Perform tell according to recorded support information on \arg x
|
|
ModEvent tell(Space& home, IntView& x) const;
|
|
};
|
|
|
|
/**
|
|
* \brief Base-class for support-based iterator
|
|
*
|
|
*/
|
|
template<class Val>
|
|
class SupportIter {
|
|
protected:
|
|
/// Integer coefficient for view
|
|
int a;
|
|
/// Integer view
|
|
IntView x;
|
|
/// Set of support for values in x
|
|
SupportSet s;
|
|
/// Current value
|
|
int c;
|
|
/// Position of current value
|
|
unsigned int p;
|
|
/// Lower bound information for value
|
|
Val l;
|
|
/// Upper bound information for value
|
|
Val u;
|
|
public:
|
|
/// Initialize view
|
|
void init(Region& r, int a, const IntView& x, Val l, Val u);
|
|
/// Record value at current position as supported
|
|
void support(void);
|
|
/// Tell back new variable domain according to support found
|
|
ModEvent tell(Space& home);
|
|
};
|
|
|
|
|
|
/**
|
|
* \brief Support-based iterator for positive view
|
|
*
|
|
*/
|
|
template<class Val>
|
|
class PosSupportIter : public SupportIter<Val> {
|
|
private:
|
|
/// Iterate ranges of integer view in increasing order
|
|
IntVarImpFwd i;
|
|
// Using-declarations for dependant names
|
|
using SupportIter<Val>::a;
|
|
using SupportIter<Val>::x;
|
|
using SupportIter<Val>::s;
|
|
using SupportIter<Val>::c;
|
|
using SupportIter<Val>::p;
|
|
using SupportIter<Val>::l;
|
|
using SupportIter<Val>::u;
|
|
public:
|
|
/// Reset iterator to beginning and adjust \arg d accordingly
|
|
bool reset(Val& d);
|
|
/// Adjust \arg d and return true if next value still works
|
|
bool adjust(Val& d);
|
|
};
|
|
|
|
|
|
/**
|
|
* \brief Support-based iterator for negative view
|
|
*
|
|
*/
|
|
template<class Val>
|
|
class NegSupportIter : public SupportIter<Val> {
|
|
private:
|
|
/// Iterate ranges of integer view in decreasing order
|
|
IntVarImpBwd i;
|
|
// Using-declarations for dependant names
|
|
using SupportIter<Val>::a;
|
|
using SupportIter<Val>::x;
|
|
using SupportIter<Val>::s;
|
|
using SupportIter<Val>::c;
|
|
using SupportIter<Val>::p;
|
|
using SupportIter<Val>::l;
|
|
using SupportIter<Val>::u;
|
|
public:
|
|
/// Reset iterator to beginning and adjust \arg d accordingly
|
|
bool reset(Val& d);
|
|
/// Adjust \arg d and return true if next value still works
|
|
bool adjust(Val& d);
|
|
};
|
|
|
|
|
|
/*
|
|
* Support set
|
|
*
|
|
*/
|
|
forceinline
|
|
SupportSet::SupportSet(void) {}
|
|
forceinline void
|
|
SupportSet::init(Region& r, unsigned int n) {
|
|
bs.init(r,n);
|
|
}
|
|
forceinline void
|
|
SupportSet::support(unsigned int i) {
|
|
bs.set(i);
|
|
}
|
|
forceinline bool
|
|
SupportSet::supported(unsigned int i) const {
|
|
return bs.get(i);
|
|
}
|
|
|
|
forceinline
|
|
SupportSet::ResultIter::ResultIter(const SupportSet& s0, const IntView& x)
|
|
: ViewValues<IntView>(x), s(s0), p(0) {
|
|
while (ViewValues<IntView>::operator ()() && s.supported(p)) {
|
|
ViewValues<IntView>::operator ++(); ++p;
|
|
}
|
|
}
|
|
forceinline void
|
|
SupportSet::ResultIter::operator ++(void) {
|
|
do {
|
|
ViewValues<IntView>::operator ++(); ++p;
|
|
} while (ViewValues<IntView>::operator ()() && s.supported(p));
|
|
}
|
|
|
|
|
|
forceinline ModEvent
|
|
SupportSet::tell(Space& home, IntView& x) const {
|
|
switch (bs.status()) {
|
|
case Support::BSS_NONE:
|
|
return ME_INT_FAILED;
|
|
case Support::BSS_ALL:
|
|
return ME_INT_NONE;
|
|
case Support::BSS_SOME:
|
|
{
|
|
ResultIter i(*this,x);
|
|
return x.minus_v(home,i);
|
|
}
|
|
default:
|
|
GECODE_NEVER;
|
|
}
|
|
return ME_INT_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Base-class for support-based iterator
|
|
*
|
|
*/
|
|
template<class Val>
|
|
forceinline void
|
|
SupportIter<Val>::init(Region& r,
|
|
int a0, const IntView& x0, Val l0, Val u0) {
|
|
a=a0; x=x0; l=l0; u=u0;
|
|
s.init(r,x.size());
|
|
}
|
|
template<class Val>
|
|
forceinline void
|
|
SupportIter<Val>::support(void) {
|
|
s.support(p);
|
|
}
|
|
template<class Val>
|
|
forceinline ModEvent
|
|
SupportIter<Val>::tell(Space& home) {
|
|
return s.tell(home,x);
|
|
}
|
|
|
|
|
|
/*
|
|
* Support-based iterator for positive view
|
|
*
|
|
*/
|
|
template<class Val>
|
|
forceinline bool
|
|
PosSupportIter<Val>::reset(Val& d) {
|
|
// Way too small, no value can make it big enough
|
|
if (d + static_cast<Val>(a)*x.max() < u)
|
|
return false;
|
|
// Restart iterator and position of values
|
|
i.init(x.varimp()); p = 0;
|
|
// Skip all ranges which are too small
|
|
while (d + static_cast<Val>(a)*i.max() < u) {
|
|
p += i.width(); ++i;
|
|
}
|
|
// There is at least one range left (check of max)
|
|
assert(i());
|
|
// Initialize current range and adjust value
|
|
c = i.min();
|
|
// Skip all values which are too small
|
|
while (d + static_cast<Val>(a)*c < u) {
|
|
p++; c++;
|
|
}
|
|
// Adjust to new value
|
|
d += static_cast<Val>(a) * c;
|
|
return true;
|
|
}
|
|
template<class Val>
|
|
forceinline bool
|
|
PosSupportIter<Val>::adjust(Val& d) {
|
|
// Current value
|
|
Val v = static_cast<Val>(a) * c;
|
|
// Subtract current value from d
|
|
d -= v;
|
|
// Move to next position (number of value)
|
|
p++;
|
|
// Still in the same range
|
|
if (c < i.max()) {
|
|
// Decrement current values
|
|
c += 1; v += a;
|
|
} else {
|
|
// Go to next range
|
|
++i;
|
|
if (!i())
|
|
return false;
|
|
c = i.min(); v = static_cast<Val>(a) * c;
|
|
}
|
|
// Is d with the current value too large?
|
|
if (d + v > l)
|
|
return false;
|
|
// Update d
|
|
d += v;
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
* Support-based iterator for negative view
|
|
*
|
|
*/
|
|
template<class Val>
|
|
forceinline bool
|
|
NegSupportIter<Val>::reset(Val& d) {
|
|
// Way too small, no value can make it big enough
|
|
if (d + static_cast<Val>(a)*x.min() < u)
|
|
return false;
|
|
// Restart iterator and position of values
|
|
i.init(x.varimp()); p = x.size()-1;
|
|
// Skip all ranges which are too small
|
|
while (d + static_cast<Val>(a)*i.min() < u) {
|
|
p -= i.width(); ++i;
|
|
}
|
|
// There is at least one range left (check of max)
|
|
assert(i());
|
|
// Initialize current range
|
|
c = i.max();
|
|
// Skip all values which are too small
|
|
while (d + static_cast<Val>(a)*c < u) {
|
|
p--; c--;
|
|
}
|
|
// Adjust to new value
|
|
d += static_cast<Val>(a) * c;
|
|
return true;
|
|
}
|
|
template<class Val>
|
|
forceinline bool
|
|
NegSupportIter<Val>::adjust(Val& d) {
|
|
// Current value
|
|
Val v = static_cast<Val>(a) * c;
|
|
// Subtract current value from d
|
|
d -= v;
|
|
// Move to next position (number of value)
|
|
p--;
|
|
// Still in the same range
|
|
if (c > i.min()) {
|
|
// Decrement current values
|
|
c -= 1; v -= a;
|
|
} else {
|
|
// Go to next range
|
|
++i;
|
|
if (!i())
|
|
return false;
|
|
c = i.max(); v = static_cast<Val>(a) * c;
|
|
}
|
|
// Is d with the current value too large?
|
|
if (d + v > l)
|
|
return false;
|
|
// Update d
|
|
d += v;
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* The domain consisten equality propagator
|
|
*
|
|
*/
|
|
template<class Val, class View>
|
|
forceinline
|
|
DomEq<Val,View>::DomEq(Home home,
|
|
ViewArray<View >& x, ViewArray<View >& y,
|
|
Val c)
|
|
: Lin<Val,View,View,PC_INT_DOM>(home,x,y,c) {}
|
|
|
|
template<class Val, class View>
|
|
ExecStatus
|
|
DomEq<Val,View>::post(Home home,
|
|
ViewArray<View>& x, ViewArray<View>& y,
|
|
Val c) {
|
|
(void) new (home) DomEq<Val,View>(home,x,y,c);
|
|
return ES_OK;
|
|
}
|
|
|
|
template<class Val, class View>
|
|
forceinline
|
|
DomEq<Val,View>::DomEq(Space& home, DomEq<Val,View>& p)
|
|
: Lin<Val,View,View,PC_INT_DOM>(home,p) {}
|
|
|
|
template<class Val, class View>
|
|
Actor*
|
|
DomEq<Val,View>::copy(Space& home) {
|
|
return new (home) DomEq<Val,View>(home,*this);
|
|
}
|
|
|
|
template<class Val, class View>
|
|
PropCost
|
|
DomEq<Val,View>::cost(const Space&, const ModEventDelta& med) const {
|
|
if (View::me(med) != ME_INT_DOM)
|
|
return PropCost::linear(PropCost::LO, x.size()+y.size());
|
|
else
|
|
return PropCost::crazy(PropCost::HI, x.size()+y.size());
|
|
}
|
|
|
|
template<class Val, class View>
|
|
ExecStatus
|
|
DomEq<Val,View>::propagate(Space& home, const ModEventDelta& med) {
|
|
if (View::me(med) != ME_INT_DOM) {
|
|
ExecStatus es = prop_bnd<Val,View,View>(home,med,*this,x,y,c);
|
|
GECODE_ES_CHECK(es);
|
|
return home.ES_FIX_PARTIAL(*this,View::med(ME_INT_DOM));
|
|
}
|
|
|
|
// Value of equation for partial assignment
|
|
Val d = -c;
|
|
|
|
int n = x.size();
|
|
int m = y.size();
|
|
|
|
Region r;
|
|
// Create support-base iterators
|
|
PosSupportIter<Val>* xp = r.alloc<PosSupportIter<Val> >(n);
|
|
NegSupportIter<Val>* yp = r.alloc<NegSupportIter<Val> >(m);
|
|
|
|
// Initialize views for assignments
|
|
{
|
|
Val l = 0;
|
|
Val u = 0;
|
|
for (int j=m; j--; ) {
|
|
yp[j].init(r,-y[j].scale(),y[j].base(),l,u);
|
|
l += y[j].max(); u += y[j].min();
|
|
}
|
|
for (int i=n; i--; ) {
|
|
xp[i].init(r,x[i].scale(),x[i].base(),l,u);
|
|
l -= x[i].min(); u -= x[i].max();
|
|
}
|
|
}
|
|
|
|
// Collect support information by iterating assignments
|
|
{
|
|
// Force reset of all iterators in first round
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
next_i:
|
|
// Reset all iterators for positive views and update d
|
|
while (i<n) {
|
|
if (!xp[i].reset(d)) goto prev_i;
|
|
i++;
|
|
}
|
|
next_j:
|
|
// Reset all iterators for negative views and update d
|
|
while (j<m) {
|
|
if (!yp[j].reset(d)) goto prev_j;
|
|
j++;
|
|
}
|
|
// Check whether current assignment is solution
|
|
if (d == 0) {
|
|
// Record support
|
|
for (int is=0; is<n; is++) xp[is].support();
|
|
for (int js=0; js<m; js++) yp[js].support();
|
|
}
|
|
prev_j:
|
|
// Try iterating to next assignment: negative views
|
|
while (j>0) {
|
|
if (yp[j-1].adjust(d)) goto next_j;
|
|
j--;
|
|
}
|
|
prev_i:
|
|
// Try iterating to next assignment: positive views
|
|
while (i>0) {
|
|
if (xp[i-1].adjust(d)) goto next_i;
|
|
i--;
|
|
}
|
|
}
|
|
|
|
// Tell back new variable domains
|
|
bool assigned = true;
|
|
for (int i=0; i<n; i++) {
|
|
GECODE_ME_CHECK(xp[i].tell(home));
|
|
if (!x[i].assigned())
|
|
assigned = false;
|
|
}
|
|
for (int j=0; j<m; j++) {
|
|
GECODE_ME_CHECK(yp[j].tell(home));
|
|
if (!y[j].assigned())
|
|
assigned = false;
|
|
}
|
|
if (assigned)
|
|
return home.ES_SUBSUMED(*this);
|
|
return ES_FIX;
|
|
}
|
|
|
|
}}}
|
|
|
|
// STATISTICS: int-prop
|