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

359 lines
11 KiB
C++

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Guido Tack <tack@gecode.org>
* Christian Schulte <schulte@gecode.org>
* 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.
*
*/
#include <gecode/set.hh>
#include <gecode/int.hh>
namespace Gecode { namespace Set { namespace Int {
/// Value Iterator for values above a certain weight
template<class I>
class OverweightValues {
private:
/// The threshold above which values should be iterated
int threshold;
/// The value iterator
I iter;
/// A superset of the elements found in the iterator
SharedArray<int> elements;
/// Weights for all the possible elements
SharedArray<int> weights;
/// The current index into the elements and weights
int index;
/// Move to the next element
void next(void);
public:
/// \name Constructors and initialization
//@{
/// Default constructor
OverweightValues(void);
/// Initialize with elements/weights pairs, threshold \a t and iterator \a i
OverweightValues(int t,
SharedArray<int>& elements0,
SharedArray<int>& weights0,
I& i);
/// Initialize with elements/weights pairs, threshold \a t and iterator \a i
void init(int t,
SharedArray<int>& elements0,
SharedArray<int>& weights0,
I& i);
//@}
/// \name Iteration control
//@{
/// Test whether iterator is still at a value or done
bool operator ()(void) const;
/// Move iterator to next value (if possible)
void operator ++(void);
//@}
/// \name Value access
//@{
/// Return current value
int val(void) const;
//@}
};
template<class I>
forceinline void
OverweightValues<I>::next(void) {
while (iter()) {
while (elements[index]<iter.val()) index++;
assert(elements[index]==iter.val());
if (weights[index] > threshold) {
return;
}
++iter;
}
}
template<class I>
forceinline
OverweightValues<I>::OverweightValues(void) {}
template<class I>
forceinline
OverweightValues<I>::OverweightValues(int t,
SharedArray<int>& elements0,
SharedArray<int>& weights0,
I& i) : threshold(t),
iter(i),
elements(elements0),
weights(weights0),
index(0) {
next();
}
template<class I>
forceinline void
OverweightValues<I>::init(int t,
SharedArray<int>& elements0,
SharedArray<int>& weights0,
I& i) {
threshold = t; iter = i;
elements = elements0; weights = weights0;
index = 0;
next();
}
template<class I>
forceinline bool
OverweightValues<I>::operator ()(void) const { return iter(); }
template<class I>
forceinline void
OverweightValues<I>::operator ++(void) { ++iter; next(); }
template<class I>
forceinline int
OverweightValues<I>::val(void) const { return elements[index]; }
template<class View>
forceinline
Weights<View>::Weights(Home home,
const SharedArray<int>& elements0,
const SharedArray<int>& weights0,
View x0, Gecode::Int::IntView y0)
: Propagator(home), elements(elements0), weights(weights0),
x(x0), y(y0) {
home.notice(*this,AP_DISPOSE);
x.subscribe(home,*this, PC_SET_ANY);
y.subscribe(home,*this, Gecode::Int::PC_INT_BND);
}
template<class View>
forceinline
Weights<View>::Weights(Space& home, Weights& p)
: Propagator(home,p), elements(p.elements), weights(p.weights) {
x.update(home,p.x);
y.update(home,p.y);
}
template<class View>
inline ExecStatus
Weights<View>::post(Home home, const SharedArray<int>& elements,
const SharedArray<int>& weights,
View x, Gecode::Int::IntView y) {
if (elements.size() != weights.size())
throw ArgumentSizeMismatch("Weights");
Region r;
int* els_arr = r.alloc<int>(elements.size());
for (int i=elements.size(); i--;)
els_arr[i] = elements[i];
IntSet els(els_arr, elements.size());
IntSetRanges er(els);
GECODE_ME_CHECK(x.intersectI(home, er));
(void) new (home) Weights(home,elements,weights,x,y);
return ES_OK;
}
template<class View>
PropCost
Weights<View>::cost(const Space&, const ModEventDelta&) const {
return PropCost::linear(PropCost::LO, y.size()+1);
}
template<class View>
void
Weights<View>::reschedule(Space& home) {
x.reschedule(home,*this, PC_SET_ANY);
y.reschedule(home,*this, Gecode::Int::PC_INT_BND);
}
template<class View>
forceinline size_t
Weights<View>::dispose(Space& home) {
home.ignore(*this,AP_DISPOSE);
x.cancel(home,*this, PC_SET_ANY);
y.cancel(home,*this, Gecode::Int::PC_INT_BND);
elements.~SharedArray();
weights.~SharedArray();
(void) Propagator::dispose(home);
return sizeof(*this);
}
template<class View>
Actor*
Weights<View>::copy(Space& home) {
return new (home) Weights(home,*this);
}
/// Compute the weight of the elements in the iterator \a I
template<class I>
forceinline
int weightI(SharedArray<int>& elements,
SharedArray<int>& weights,
I& iter) {
int sum = 0;
int i = 0;
Iter::Ranges::ToValues<I> v(iter);
for (; v(); ++v) {
// Skip all elements below the current
while (elements[i]<v.val()) i++;
assert(elements[i] == v.val());
sum += weights[i];
}
assert(!v());
return sum;
}
/// Sort order for integers
class IntLess {
public:
bool operator ()(int x, int y);
};
forceinline bool
IntLess::operator ()(int x, int y) {
return x < y;
}
template<class View>
ExecStatus
Weights<View>::propagate(Space& home, const ModEventDelta&) {
ModEvent me = ME_SET_NONE;
if (!x.assigned()) {
// Collect the weights of the elements in the unknown set in an array
int size = elements.size();
Region r;
int* minWeights = r.alloc<int>(size);
int* maxWeights = r.alloc<int>(size);
UnknownRanges<View> ur(x);
Iter::Ranges::ToValues<UnknownRanges<View> > urv(ur);
for (int i=0; i<size; i++) {
if (!urv() || elements[i]<urv.val()) {
minWeights[i] = INT_MAX;
maxWeights[i] = INT_MIN;
} else {
assert(elements[i] == urv.val());
minWeights[i] = weights[i];
maxWeights[i] = weights[i];
++urv;
}
}
// Sort the weights of the unknown elements
IntLess il;
Support::quicksort<int>(minWeights, size, il);
Support::quicksort<int>(maxWeights, size, il);
// The maximum number of elements that can still be added to x
int delta = static_cast<int>(std::min(x.unknownSize(), x.cardMax() - x.glbSize()));
// The weight of the elements already in x
GlbRanges<View> glb(x);
int glbWeight = weightI<GlbRanges<View> >(elements, weights, glb);
// Compute the weight of the current lower bound of x, plus at most
// delta-1 further elements with smallest negative weights. This weight
// determines which elements in the upper bound cannot possibly be
// added to x (those whose weight would exceed the capacity even if
// all other elements are minimal)
int lowWeight = glbWeight;
for (int i=0; i<delta-1; i++) {
if (minWeights[i] >= 0)
break;
lowWeight+=minWeights[i];
}
// Compute the lowest possible weight of x. If there is another element
// with negative weight left, then add its weight to lowWeight.
// Otherwise lowWeight is already the lowest possible weight.
int lowestWeight = lowWeight;
if (delta>0 && minWeights[delta-1]<0)
lowestWeight+=minWeights[delta-1];
// If after including the minimal number of required elements,
// no more element with negative weight is available, then
// a tighter lower bound can be computed.
if ( (x.cardMin() - x.glbSize() > 0 &&
minWeights[x.cardMin() - x.glbSize() - 1] >= 0) ||
minWeights[0] >= 0 ) {
int lowestPosWeight = glbWeight;
for (unsigned int i=0; i<x.cardMin() - x.glbSize(); i++) {
lowestPosWeight += minWeights[i];
}
lowestWeight = std::max(lowestWeight, lowestPosWeight);
}
// Compute the highest possible weight of x as the weight of the lower
// bound plus the weight of the delta heaviest elements still in the
// upper bound.
int highestWeight = glbWeight;
for (int i=0; i<delta; i++) {
if (maxWeights[size-i-1]<=0)
break;
highestWeight += maxWeights[size-i-1];
}
// Prune the weight using the computed bounds
GECODE_ME_CHECK(y.gq(home, lowestWeight));
GECODE_ME_CHECK(y.lq(home, highestWeight));
// Exclude all elements that are too heavy from the set x.
// Elements are too heavy if their weight alone already
// exceeds the remaining capacity
int remainingCapacity = y.max()-lowWeight;
UnknownRanges<View> ur2(x);
Iter::Ranges::ToValues<UnknownRanges<View> > urv2(ur2);
OverweightValues<Iter::Ranges::ToValues<UnknownRanges<View> > >
ov(remainingCapacity, elements, weights, urv2);
Iter::Values::ToRanges<OverweightValues<
Iter::Ranges::ToValues<UnknownRanges<View> > > > ovr(ov);
me = x.excludeI(home, ovr);
GECODE_ME_CHECK(me);
}
if (x.assigned()) {
// If x is assigned, just compute its weight and assign y.
GlbRanges<View> glb(x);
int w =
weightI<GlbRanges<View> >(elements, weights, glb);
GECODE_ME_CHECK(y.eq(home, w));
return home.ES_SUBSUMED(*this);
}
// return me_modified(me) ? ES_NOFIX : ES_FIX;
return ES_NOFIX;
}
}}}
// STATISTICS: set-prop