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 3e72b0e857 Squashed 'software/gecode_on_record/' content from commit 37ed9bda4
git-subtree-dir: software/gecode_on_record
git-subtree-split: 37ed9bda495ea87e63217c19a374b5a93bb0078e
2021-06-16 14:03:52 +10:00

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