1 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2 /*
3  *  Main authors:
4  *     Guido Tack <tack@gecode.org>
5  *     Christian Schulte <schulte@gecode.org>
6  *     Gabor Szokoli <szokoli@gecode.org>
7  *
8  *  Copyright:
9  *     Guido Tack, 2004
10  *     Christian Schulte, 2004
11  *     Gabor Szokoli, 2004
12  *
13  *  This file is part of Gecode, the generic constraint
14  *  development environment:
15  *     http://www.gecode.org
16  *
17  *  Permission is hereby granted, free of charge, to any person obtaining
18  *  a copy of this software and associated documentation files (the
19  *  "Software"), to deal in the Software without restriction, including
20  *  without limitation the rights to use, copy, modify, merge, publish,
21  *  distribute, sublicense, and/or sell copies of the Software, and to
22  *  permit persons to whom the Software is furnished to do so, subject to
23  *  the following conditions:
24  *
25  *  The above copyright notice and this permission notice shall be
26  *  included in all copies or substantial portions of the Software.
27  *
28  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35  *
36  */
37 
38 #include <gecode/set.hh>
39 #include <gecode/int.hh>
40 
41 namespace Gecode { namespace Set { namespace Int {
42 
43   /// Value Iterator for values above a certain weight
44   template<class I>
45   class OverweightValues {
46   private:
47     /// The threshold above which values should be iterated
48     int threshold;
49     /// The value iterator
50     I iter;
51     /// A superset of the elements found in the iterator
52     SharedArray<int> elements;
53     /// Weights for all the possible elements
54     SharedArray<int> weights;
55     /// The current index into the elements and weights
56     int index;
57     /// Move to the next element
58     void next(void);
59   public:
60     /// \name Constructors and initialization
61     //@{
62     /// Default constructor
63     OverweightValues(void);
64     /// Initialize with elements/weights pairs, threshold \a t and iterator \a i
65     OverweightValues(int t,
66                      SharedArray<int>& elements0,
67                      SharedArray<int>& weights0,
68                      I& i);
69     /// Initialize with elements/weights pairs, threshold \a t and iterator \a i
70     void init(int t,
71               SharedArray<int>& elements0,
72               SharedArray<int>& weights0,
73               I& i);
74     //@}
75 
76     /// \name Iteration control
77     //@{
78     /// Test whether iterator is still at a value or done
79     bool operator ()(void) const;
80     /// Move iterator to next value (if possible)
81     void operator ++(void);
82     //@}
83     /// \name Value access
84     //@{
85     /// Return current value
86     int  val(void) const;
87     //@}
88   };
89 
90   template<class I>
91   forceinline void
next(void)92   OverweightValues<I>::next(void) {
93     while (iter()) {
94       while (elements[index]<iter.val()) index++;
95       assert(elements[index]==iter.val());
96       if (weights[index] > threshold) {
97         return;
98       }
99       ++iter;
100     }
101   }
102 
103   template<class I>
104   forceinline
OverweightValues(void)105   OverweightValues<I>::OverweightValues(void) {}
106 
107   template<class I>
108   forceinline
OverweightValues(int t,SharedArray<int> & elements0,SharedArray<int> & weights0,I & i)109   OverweightValues<I>::OverweightValues(int t,
110                                         SharedArray<int>& elements0,
111                                         SharedArray<int>& weights0,
112                                         I& i) : threshold(t),
113                                                 iter(i),
114                                                 elements(elements0),
115                                                 weights(weights0),
116                                                 index(0) {
117     next();
118   }
119 
120   template<class I>
121   forceinline void
init(int t,SharedArray<int> & elements0,SharedArray<int> & weights0,I & i)122   OverweightValues<I>::init(int t,
123                             SharedArray<int>& elements0,
124                             SharedArray<int>& weights0,
125                             I& i) {
126     threshold = t; iter = i;
127     elements = elements0; weights = weights0;
128     index = 0;
129     next();
130   }
131 
132   template<class I>
133   forceinline bool
operator ()(void) const134   OverweightValues<I>::operator ()(void) const { return iter(); }
135 
136   template<class I>
137   forceinline void
operator ++(void)138   OverweightValues<I>::operator ++(void) { ++iter; next(); }
139 
140   template<class I>
141   forceinline int
val(void) const142   OverweightValues<I>::val(void) const { return elements[index]; }
143 
144   template<class View>
145   forceinline
Weights(Home home,const SharedArray<int> & elements0,const SharedArray<int> & weights0,View x0,Gecode::Int::IntView y0)146   Weights<View>::Weights(Home home,
147                          const SharedArray<int>& elements0,
148                          const SharedArray<int>& weights0,
149                          View x0, Gecode::Int::IntView y0)
150     : Propagator(home), elements(elements0), weights(weights0),
151       x(x0), y(y0) {
152     home.notice(*this,AP_DISPOSE);
153     x.subscribe(home,*this, PC_SET_ANY);
154     y.subscribe(home,*this, Gecode::Int::PC_INT_BND);
155   }
156 
157   template<class View>
158   forceinline
Weights(Space & home,Weights & p)159   Weights<View>::Weights(Space& home, Weights& p)
160     : Propagator(home,p), elements(p.elements), weights(p.weights) {
161     x.update(home,p.x);
162     y.update(home,p.y);
163   }
164 
165   template<class View>
166   inline ExecStatus
post(Home home,const SharedArray<int> & elements,const SharedArray<int> & weights,View x,Gecode::Int::IntView y)167   Weights<View>::post(Home home, const SharedArray<int>& elements,
168                       const SharedArray<int>& weights,
169                       View x, Gecode::Int::IntView y) {
170     if (elements.size() != weights.size())
171       throw ArgumentSizeMismatch("Weights");
172     Region r;
173     int* els_arr = r.alloc<int>(elements.size());
174     for (int i=elements.size(); i--;)
175       els_arr[i] = elements[i];
176     IntSet els(els_arr, elements.size());
177     IntSetRanges er(els);
178     GECODE_ME_CHECK(x.intersectI(home, er));
179     (void) new (home) Weights(home,elements,weights,x,y);
180     return ES_OK;
181   }
182 
183   template<class View>
184   PropCost
cost(const Space &,const ModEventDelta &) const185   Weights<View>::cost(const Space&, const ModEventDelta&) const {
186     return PropCost::linear(PropCost::LO, y.size()+1);
187   }
188 
189   template<class View>
190   void
reschedule(Space & home)191   Weights<View>::reschedule(Space& home) {
192     x.reschedule(home,*this, PC_SET_ANY);
193     y.reschedule(home,*this, Gecode::Int::PC_INT_BND);
194   }
195 
196   template<class View>
197   forceinline size_t
dispose(Space & home)198   Weights<View>::dispose(Space& home) {
199     home.ignore(*this,AP_DISPOSE);
200     x.cancel(home,*this, PC_SET_ANY);
201     y.cancel(home,*this, Gecode::Int::PC_INT_BND);
202     elements.~SharedArray();
203     weights.~SharedArray();
204     (void) Propagator::dispose(home);
205     return sizeof(*this);
206   }
207 
208   template<class View>
209   Actor*
copy(Space & home)210   Weights<View>::copy(Space& home) {
211     return new (home) Weights(home,*this);
212   }
213 
214   /// Compute the weight of the elements in the iterator \a I
215   template<class I>
216   forceinline
weightI(SharedArray<int> & elements,SharedArray<int> & weights,I & iter)217   int weightI(SharedArray<int>& elements,
218               SharedArray<int>& weights,
219               I& iter) {
220     int sum = 0;
221     int i = 0;
222     Iter::Ranges::ToValues<I> v(iter);
223     for (; v(); ++v) {
224       // Skip all elements below the current
225       while (elements[i]<v.val()) i++;
226       assert(elements[i] == v.val());
227       sum += weights[i];
228     }
229     assert(!v());
230     return sum;
231   }
232 
233 
234   /// Sort order for integers
235   class IntLess {
236   public:
237     bool operator ()(int x, int y);
238   };
239 
240   forceinline bool
operator ()(int x,int y)241   IntLess::operator ()(int x, int y) {
242     return x < y;
243   }
244 
245   template<class View>
246   ExecStatus
propagate(Space & home,const ModEventDelta &)247   Weights<View>::propagate(Space& home, const ModEventDelta&) {
248     ModEvent me = ME_SET_NONE;
249 
250     if (!x.assigned()) {
251       // Collect the weights of the elements in the unknown set in an array
252       int size = elements.size();
253       Region r;
254       int* minWeights = r.alloc<int>(size);
255       int* maxWeights = r.alloc<int>(size);
256 
257       UnknownRanges<View> ur(x);
258       Iter::Ranges::ToValues<UnknownRanges<View> > urv(ur);
259       for (int i=0; i<size; i++) {
260         if (!urv() || elements[i]<urv.val()) {
261           minWeights[i] = INT_MAX;
262           maxWeights[i] = INT_MIN;
263         } else {
264           assert(elements[i] == urv.val());
265           minWeights[i] = weights[i];
266           maxWeights[i] = weights[i];
267           ++urv;
268         }
269       }
270 
271       // Sort the weights of the unknown elements
272       IntLess il;
273       Support::quicksort<int>(minWeights, size, il);
274       Support::quicksort<int>(maxWeights, size, il);
275 
276       // The maximum number of elements that can still be added to x
277       int delta = static_cast<int>(std::min(x.unknownSize(), x.cardMax() - x.glbSize()));
278 
279       // The weight of the elements already in x
280       GlbRanges<View> glb(x);
281       int glbWeight = weightI<GlbRanges<View> >(elements, weights, glb);
282 
283       // Compute the weight of the current lower bound of x, plus at most
284       // delta-1 further elements with smallest negative weights. This weight
285       // determines which elements in the upper bound cannot possibly be
286       // added to x (those whose weight would exceed the capacity even if
287       // all other elements are minimal)
288       int lowWeight = glbWeight;
289       for (int i=0; i<delta-1; i++) {
290         if (minWeights[i] >= 0)
291           break;
292         lowWeight+=minWeights[i];
293       }
294 
295       // Compute the lowest possible weight of x. If there is another element
296       // with negative weight left, then add its weight to lowWeight.
297       // Otherwise lowWeight is already the lowest possible weight.
298       int lowestWeight = lowWeight;
299       if (delta>0 && minWeights[delta-1]<0)
300         lowestWeight+=minWeights[delta-1];
301 
302       // If after including the minimal number of required elements,
303       // no more element with negative weight is available, then
304       // a tighter lower bound can be computed.
305       if ( (x.cardMin() - x.glbSize() > 0 &&
306             minWeights[x.cardMin() - x.glbSize() - 1] >= 0) ||
307            minWeights[0] >= 0 ) {
308         int lowestPosWeight = glbWeight;
309         for (unsigned int i=0; i<x.cardMin() - x.glbSize(); i++) {
310           lowestPosWeight += minWeights[i];
311         }
312         lowestWeight = std::max(lowestWeight, lowestPosWeight);
313       }
314 
315       // Compute the highest possible weight of x as the weight of the lower
316       // bound plus the weight of the delta heaviest elements still in the
317       // upper bound.
318       int highestWeight = glbWeight;
319       for (int i=0; i<delta; i++) {
320         if (maxWeights[size-i-1]<=0)
321           break;
322         highestWeight += maxWeights[size-i-1];
323       }
324 
325       // Prune the weight using the computed bounds
326       GECODE_ME_CHECK(y.gq(home, lowestWeight));
327       GECODE_ME_CHECK(y.lq(home, highestWeight));
328 
329       // Exclude all elements that are too heavy from the set x.
330       // Elements are too heavy if their weight alone already
331       // exceeds the remaining capacity
332       int remainingCapacity = y.max()-lowWeight;
333 
334       UnknownRanges<View> ur2(x);
335       Iter::Ranges::ToValues<UnknownRanges<View> > urv2(ur2);
336       OverweightValues<Iter::Ranges::ToValues<UnknownRanges<View> > >
337         ov(remainingCapacity, elements, weights, urv2);
338       Iter::Values::ToRanges<OverweightValues<
339         Iter::Ranges::ToValues<UnknownRanges<View> > > > ovr(ov);
340       me = x.excludeI(home, ovr);
341       GECODE_ME_CHECK(me);
342     }
343     if (x.assigned()) {
344       // If x is assigned, just compute its weight and assign y.
345       GlbRanges<View> glb(x);
346       int w =
347         weightI<GlbRanges<View> >(elements, weights, glb);
348       GECODE_ME_CHECK(y.eq(home, w));
349       return home.ES_SUBSUMED(*this);
350     }
351 
352     // return me_modified(me) ? ES_NOFIX : ES_FIX;
353     return ES_NOFIX;
354   }
355 
356 }}}
357 
358 // STATISTICS: set-prop
359