Generated on Tue Apr 18 10:22:12 2017 for Gecode by doxygen 1.6.3

weights.hpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Guido Tack <tack@gecode.org>
00005  *     Christian Schulte <schulte@gecode.org>
00006  *     Gabor Szokoli <szokoli@gecode.org>
00007  *
00008  *  Copyright:
00009  *     Guido Tack, 2004
00010  *     Christian Schulte, 2004
00011  *     Gabor Szokoli, 2004
00012  *
00013  *  Last modified:
00014  *     $Date: 2016-10-25 12:52:26 +0200 (Tue, 25 Oct 2016) $ by $Author: schulte $
00015  *     $Revision: 15233 $
00016  *
00017  *  This file is part of Gecode, the generic constraint
00018  *  development environment:
00019  *     http://www.gecode.org
00020  *
00021  *  Permission is hereby granted, free of charge, to any person obtaining
00022  *  a copy of this software and associated documentation files (the
00023  *  "Software"), to deal in the Software without restriction, including
00024  *  without limitation the rights to use, copy, modify, merge, publish,
00025  *  distribute, sublicense, and/or sell copies of the Software, and to
00026  *  permit persons to whom the Software is furnished to do so, subject to
00027  *  the following conditions:
00028  *
00029  *  The above copyright notice and this permission notice shall be
00030  *  included in all copies or substantial portions of the Software.
00031  *
00032  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00033  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00034  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00035  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00036  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00037  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00038  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00039  *
00040  */
00041 
00042 #include <gecode/set.hh>
00043 #include <gecode/int.hh>
00044 
00045 namespace Gecode { namespace Set { namespace Int {
00046 
00048   template<class I>
00049   class OverweightValues {
00050   private:
00052     int threshold;
00054     I iter;
00056     const SharedArray<int> elements;
00058     const SharedArray<int> weights;
00060     int index;
00062     void next(void);
00063   public:
00065 
00066 
00067     OverweightValues(void);
00069     OverweightValues(int t,
00070                      SharedArray<int>& elements0,
00071                      SharedArray<int>& weights0,
00072                      I& i);
00074     void init(int t,
00075               SharedArray<int>& elements0,
00076               SharedArray<int>& weights0,
00077               I& i);
00079 
00081 
00082 
00083     bool operator ()(void) const;
00085     void operator ++(void);
00087 
00088 
00089 
00090     int  val(void) const;
00092   };
00093 
00094   template<class I>
00095   forceinline void
00096   OverweightValues<I>::next(void) {
00097     while (iter()) {
00098       while (elements[index]<iter.val()) index++;
00099       assert(elements[index]==iter.val());
00100       if (weights[index] > threshold) {
00101         return;
00102       }
00103       ++iter;
00104     }
00105   }
00106 
00107   template<class I>
00108   forceinline
00109   OverweightValues<I>::OverweightValues(void) {}
00110 
00111   template<class I>
00112   forceinline
00113   OverweightValues<I>::OverweightValues(int t,
00114                                         SharedArray<int>& elements0,
00115                                         SharedArray<int>& weights0,
00116                                         I& i) : threshold(t),
00117                                                 iter(i),
00118                                                 elements(elements0),
00119                                                 weights(weights0),
00120                                                 index(0) {
00121     next();
00122   }
00123 
00124   template<class I>
00125   forceinline void
00126   OverweightValues<I>::init(int t,
00127                             SharedArray<int>& elements0,
00128                             SharedArray<int>& weights0,
00129                             I& i) {
00130     threshold = t; iter = i;
00131     elements = elements0; weights = weights0;
00132     index = 0;
00133     next();
00134   }
00135 
00136   template<class I>
00137   forceinline bool
00138   OverweightValues<I>::operator ()(void) const { return iter(); }
00139 
00140   template<class I>
00141   forceinline void
00142   OverweightValues<I>::operator ++(void) { ++iter; next(); }
00143 
00144   template<class I>
00145   forceinline int
00146   OverweightValues<I>::val(void) const { return elements[index]; }
00147 
00148   template<class View>
00149   forceinline
00150   Weights<View>::Weights(Home home,
00151                          const SharedArray<int>& elements0,
00152                          const SharedArray<int>& weights0,
00153                          View x0, Gecode::Int::IntView y0)
00154     : Propagator(home), elements(elements0), weights(weights0),
00155       x(x0), y(y0) {
00156     home.notice(*this,AP_DISPOSE);
00157     x.subscribe(home,*this, PC_SET_ANY);
00158     y.subscribe(home,*this, Gecode::Int::PC_INT_BND);
00159   }
00160 
00161   template<class View>
00162   forceinline
00163   Weights<View>::Weights(Space& home, bool share, Weights& p)
00164     : Propagator(home,share,p) {
00165     x.update(home,share,p.x);
00166     y.update(home,share,p.y);
00167     elements.update(home,share,p.elements);
00168     weights.update(home,share,p.weights);
00169   }
00170 
00171   template<class View>
00172   inline ExecStatus
00173   Weights<View>::post(Home home, const SharedArray<int>& elements,
00174                       const SharedArray<int>& weights,
00175                       View x, Gecode::Int::IntView y) {
00176     if (elements.size() != weights.size())
00177       throw ArgumentSizeMismatch("Weights");
00178     Region r(home);
00179     int* els_arr = r.alloc<int>(elements.size());
00180     for (int i=elements.size(); i--;)
00181       els_arr[i] = elements[i];
00182     IntSet els(els_arr, elements.size());
00183     IntSetRanges er(els);
00184     GECODE_ME_CHECK(x.intersectI(home, er));
00185     (void) new (home) Weights(home,elements,weights,x,y);
00186     return ES_OK;
00187   }
00188 
00189   template<class View>
00190   PropCost
00191   Weights<View>::cost(const Space&, const ModEventDelta&) const {
00192     return PropCost::linear(PropCost::LO, y.size()+1);
00193   }
00194 
00195   template<class View>
00196   void
00197   Weights<View>::reschedule(Space& home) {
00198     x.reschedule(home,*this, PC_SET_ANY);
00199     y.reschedule(home,*this, Gecode::Int::PC_INT_BND);
00200   }
00201 
00202   template<class View>
00203   forceinline size_t
00204   Weights<View>::dispose(Space& home) {
00205     home.ignore(*this,AP_DISPOSE);
00206     x.cancel(home,*this, PC_SET_ANY);
00207     y.cancel(home,*this, Gecode::Int::PC_INT_BND);
00208     elements.~SharedArray();
00209     weights.~SharedArray();
00210     (void) Propagator::dispose(home);
00211     return sizeof(*this);
00212   }
00213 
00214   template<class View>
00215   Actor*
00216   Weights<View>::copy(Space& home, bool share) {
00217     return new (home) Weights(home,share,*this);
00218   }
00219 
00221   template<class I>
00222   forceinline
00223   int weightI(SharedArray<int>& elements,
00224               SharedArray<int>& weights,
00225               I& iter) {
00226     int sum = 0;
00227     int i = 0;
00228     Iter::Ranges::ToValues<I> v(iter);
00229     for (; v(); ++v) {
00230       // Skip all elements below the current
00231       while (elements[i]<v.val()) i++;
00232       assert(elements[i] == v.val());
00233       sum += weights[i];
00234     }
00235     assert(!v());
00236     return sum;
00237   }
00238 
00239 
00241   class IntLess {
00242   public:
00243     bool operator ()(int x, int y);
00244   };
00245 
00246   forceinline bool
00247   IntLess::operator ()(int x, int y) {
00248     return x < y;
00249   }
00250 
00251   template<class View>
00252   ExecStatus
00253   Weights<View>::propagate(Space& home, const ModEventDelta&) {
00254     ModEvent me = ME_SET_NONE;
00255 
00256     if (!x.assigned()) {
00257       // Collect the weights of the elements in the unknown set in an array
00258       int size = elements.size();
00259       Region r(home);
00260       int* minWeights = r.alloc<int>(size);
00261       int* maxWeights = r.alloc<int>(size);
00262 
00263       UnknownRanges<View> ur(x);
00264       Iter::Ranges::ToValues<UnknownRanges<View> > urv(ur);
00265       for (int i=0; i<size; i++) {
00266         if (!urv() || elements[i]<urv.val()) {
00267           minWeights[i] = INT_MAX;
00268           maxWeights[i] = INT_MIN;
00269         } else {
00270           assert(elements[i] == urv.val());
00271           minWeights[i] = weights[i];
00272           maxWeights[i] = weights[i];
00273           ++urv;
00274         }
00275       }
00276 
00277       // Sort the weights of the unknown elements
00278       IntLess il;
00279       Support::quicksort<int>(minWeights, size, il);
00280       Support::quicksort<int>(maxWeights, size, il);
00281 
00282       // The maximum number of elements that can still be added to x
00283       int delta = static_cast<int>(std::min(x.unknownSize(), x.cardMax() - x.glbSize()));
00284 
00285       // The weight of the elements already in x
00286       GlbRanges<View> glb(x);
00287       int glbWeight = weightI<GlbRanges<View> >(elements, weights, glb);
00288 
00289       // Compute the weight of the current lower bound of x, plus at most
00290       // delta-1 further elements with smallest negative weights. This weight
00291       // determines which elements in the upper bound cannot possibly be
00292       // added to x (those whose weight would exceed the capacity even if
00293       // all other elements are minimal)
00294       int lowWeight = glbWeight;
00295       for (int i=0; i<delta-1; i++) {
00296         if (minWeights[i] >= 0)
00297           break;
00298         lowWeight+=minWeights[i];
00299       }
00300 
00301       // Compute the lowest possible weight of x. If there is another element
00302       // with negative weight left, then add its weight to lowWeight.
00303       // Otherwise lowWeight is already the lowest possible weight.
00304       int lowestWeight = lowWeight;
00305       if (delta>0 && minWeights[delta-1]<0)
00306         lowestWeight+=minWeights[delta-1];
00307 
00308       // If after including the minimal number of required elements,
00309       // no more element with negative weight is available, then
00310       // a tighter lower bound can be computed.
00311       if ( (x.cardMin() - x.glbSize() > 0 &&
00312             minWeights[x.cardMin() - x.glbSize() - 1] >= 0) ||
00313            minWeights[0] >= 0 ) {
00314         int lowestPosWeight = glbWeight;
00315         for (unsigned int i=0; i<x.cardMin() - x.glbSize(); i++) {
00316           lowestPosWeight += minWeights[i];
00317         }
00318         lowestWeight = std::max(lowestWeight, lowestPosWeight);
00319       }
00320 
00321       // Compute the highest possible weight of x as the weight of the lower
00322       // bound plus the weight of the delta heaviest elements still in the
00323       // upper bound.
00324       int highestWeight = glbWeight;
00325       for (int i=0; i<delta; i++) {
00326         if (maxWeights[size-i-1]<=0)
00327           break;
00328         highestWeight += maxWeights[size-i-1];
00329       }
00330 
00331       // Prune the weight using the computed bounds
00332       GECODE_ME_CHECK(y.gq(home, lowestWeight));
00333       GECODE_ME_CHECK(y.lq(home, highestWeight));
00334 
00335       // Exclude all elements that are too heavy from the set x.
00336       // Elements are too heavy if their weight alone already
00337       // exceeds the remaining capacity
00338       int remainingCapacity = y.max()-lowWeight;
00339 
00340       UnknownRanges<View> ur2(x);
00341       Iter::Ranges::ToValues<UnknownRanges<View> > urv2(ur2);
00342       OverweightValues<Iter::Ranges::ToValues<UnknownRanges<View> > >
00343         ov(remainingCapacity, elements, weights, urv2);
00344       Iter::Values::ToRanges<OverweightValues<
00345         Iter::Ranges::ToValues<UnknownRanges<View> > > > ovr(ov);
00346       me = x.excludeI(home, ovr);
00347       GECODE_ME_CHECK(me);
00348     }
00349     if (x.assigned()) {
00350       // If x is assigned, just compute its weight and assign y.
00351       GlbRanges<View> glb(x);
00352       int w =
00353         weightI<GlbRanges<View> >(elements, weights, glb);
00354       GECODE_ME_CHECK(y.eq(home, w));
00355       return home.ES_SUBSUMED(*this);
00356     }
00357 
00358     // return me_modified(me) ? ES_NOFIX : ES_FIX;
00359     return ES_NOFIX;
00360   }
00361 
00362 }}}
00363 
00364 // STATISTICS: set-prop