/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack * Christian Schulte * Gabor Szokoli * * Copyright: * Guido Tack, 2004 * Christian Schulte, 2004 * Gabor Szokoli, 2004 * * Last modified: * $Date: 2008-01-31 18:29:16 +0100 (Thu, 31 Jan 2008) $ by $Author: tack $ * $Revision: 6017 $ * * 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 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 const SharedArray elements; /// Weights for all the possible elements const SharedArray 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& elements0, SharedArray& weights0, I& i); /// Initialize with elements/weights pairs, threshold \a t and iterator \a i void init(int t, SharedArray& elements0, SharedArray& 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 forceinline void OverweightValues::next(void) { while (iter()) { while (elements[index] threshold) { return; } ++iter; } } template forceinline OverweightValues::OverweightValues(void) {} template forceinline OverweightValues::OverweightValues(int t, SharedArray& elements0, SharedArray& weights0, I& i) : threshold(t), iter(i), elements(elements0), weights(weights0), index(0) { next(); } template forceinline void OverweightValues::init(int t, SharedArray& elements0, SharedArray& weights0, I& i) { threshold = t; iter = i; elements = elements0; weights = weights0; index = 0; next(); } template forceinline bool OverweightValues::operator()(void) const { return iter(); } template forceinline void OverweightValues::operator++(void) { ++iter; next(); } template forceinline int OverweightValues::val(void) const { return elements[index]; } template forceinline Weights::Weights(Space* home, const IntArgs& elements0, const IntArgs& weights0, View x0, Gecode::Int::IntView y0) : Propagator(home), elements(elements0.size()), weights(weights0.size()), x(x0), y(y0) { x.subscribe(home,this, PC_SET_ANY); y.subscribe(home,this, Gecode::Int::PC_INT_BND); for (int i=elements0.size(); i--;) { elements[i] = elements0[i]; weights[i] = weights0[i]; } } template forceinline Weights::Weights(Space* home, bool share, Weights& p) : Propagator(home,share,p) { x.update(home,share,p.x); y.update(home,share,p.y); elements.update(home,share,p.elements); weights.update(home,share,p.weights); } template inline ExecStatus Weights::post(Space* home, const IntArgs& elements, const IntArgs& weights, View x, Gecode::Int::IntView y) { if (elements.size() != weights.size()) throw ArgumentSizeMismatch("Weights"); GECODE_AUTOARRAY(int, els_arr, 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 PropCost Weights::cost(ModEventDelta) const { return PC_LINEAR_LO; } template size_t Weights::dispose(Space* home) { assert(!home->failed()); x.cancel(home,this, PC_SET_ANY); y.cancel(home,this, Gecode::Int::PC_INT_BND); (void) Propagator::dispose(home); return sizeof(*this); } template Actor* Weights::copy(Space* home, bool share) { return new (home) Weights(home,share,*this); } enum CostType { POS_COST, NEG_COST, ALL_COST }; template forceinline int weightI(SharedArray& elements, SharedArray& weights, I& iter) { int sum = 0; int i = 0; for (Iter::Ranges::ToValues v(iter); v(); ++v) { // Skip all elements below the current while (elements[i] 0) sum += weights[i]; break; case NEG_COST: if (weights[i] < 0) sum += weights[i]; break; default: GECODE_NEVER; } } return sum; } /// Sort order for integers class IntLt { public: bool operator()(int x, int y); }; forceinline bool IntLt::operator()(int x, int y) { return x < y; } template ExecStatus Weights::propagate(Space* home, ModEventDelta) { if (x.assigned()) { GlbRanges glb(x); int w = weightI,ALL_COST>(elements, weights, glb); GECODE_ME_CHECK(y.eq(home, w)); return ES_SUBSUMED(this,home); } int lowCost; int lowestCost; int highestCost; int size = elements.size(); { UnknownRanges ur(x); Iter::Ranges::ToValues > urv(ur); GECODE_AUTOARRAY(int, currentWeights, size); for (int i=0; i(currentWeights, size, ilt); GlbRanges glb(x); lowCost = weightI,ALL_COST>(elements, weights, glb); highestCost = weightI,ALL_COST>(elements, weights, glb); int delta = std::min(x.unknownSize(), x.cardMax() - x.glbSize()); for (int i=0; i= 0) break; lowCost+=currentWeights[i]; } lowestCost = lowCost; if (delta>0 && currentWeights[delta-1]<0) lowestCost+=currentWeights[delta-1]; for (int i=0; i ur2(x); Iter::Ranges::ToValues > urv(ur2); OverweightValues > > ov(y.max()-lowCost, elements, weights, urv); Iter::Values::ToRanges > > > ovr(ov); me = x.excludeI(home, ovr); GECODE_ME_CHECK(me); } if (x.assigned()) { GlbRanges glb(x); int w = weightI,ALL_COST>(elements, weights, glb); GECODE_ME_CHECK(y.eq(home, w)); return ES_SUBSUMED(this,home); } return me_modified(me) ? ES_NOFIX : ES_FIX; } template Support::Symbol Weights::ati(void) { return Reflection::mangle("Gecode::Set::Int::Weights"); } template Reflection::ActorSpec Weights::spec(const Space* home, Reflection::VarMap& m) const { Reflection::ActorSpec s(ati()); return s << Reflection::Arg::newIntArray(elements) << Reflection::Arg::newIntArray(weights) << x.spec(home, m) << y.spec(home, m); } template void Weights::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(4); Reflection::IntArrayArg* elementsArg = spec[0]->toIntArray(); Reflection::IntArrayArg* weightsArg = spec[1]->toIntArray(); IntArgs elements(elementsArg->size()); IntArgs weights(weightsArg->size()); for (int i=elementsArg->size(); i--;) elements[i] = (*elementsArg)[i]; for (int i=weightsArg->size(); i--;) weights[i] = (*weightsArg)[i]; View x0(home, vars, spec[2]); Gecode::Int::IntView x1(home, vars, spec[3]); (void) new (home) Weights(home,elements,weights,x0,x1); } }}} // STATISTICS: set-prop