Generated on Thu Mar 22 10:39:33 2012 for Gecode by doxygen 1.6.3

propagate.cpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Christian Schulte <schulte@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Christian Schulte, 2010
00008  *
00009  *  Last modified:
00010  *     $Date: 2011-06-07 22:37:43 +0200 (Tue, 07 Jun 2011) $ by $Author: schulte $
00011  *     $Revision: 12049 $
00012  *
00013  *  This file is part of Gecode, the generic constraint
00014  *  development environment:
00015  *     http://www.gecode.org
00016  *
00017  *  Permission is hereby granted, free of charge, to any person obtaining
00018  *  a copy of this software and associated documentation files (the
00019  *  "Software"), to deal in the Software without restriction, including
00020  *  without limitation the rights to use, copy, modify, merge, publish,
00021  *  distribute, sublicense, and/or sell copies of the Software, and to
00022  *  permit persons to whom the Software is furnished to do so, subject to
00023  *  the following conditions:
00024  *
00025  *  The above copyright notice and this permission notice shall be
00026  *  included in all copies or substantial portions of the Software.
00027  *
00028  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00029  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00030  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00031  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00032  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00033  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00034  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00035  *
00036  */
00037 
00038 #include <gecode/int/bin-packing.hh>
00039 
00040 namespace Gecode { namespace Int { namespace BinPacking {
00041 
00042   /*
00043    * Packing propagator
00044    *
00045    */
00046 
00047   PropCost 
00048   Pack::cost(const Space&, const ModEventDelta&) const {
00049     return PropCost::quadratic(PropCost::HI,bs.size());
00050   }
00051 
00052   Actor* 
00053   Pack::copy(Space& home, bool share) {
00054     return new (home) Pack(home,share,*this);
00055   }
00056 
00058   class TellCache {
00059   protected:
00061     int* _nq;
00063     int _n_nq;
00065     int _eq;
00066   public:
00068     TellCache(Region& region, int m);
00070     void nq(int j);
00072     void eq(int j);
00074     ExecStatus tell(Space& home, IntView x);
00075   };
00076 
00077   forceinline
00078   TellCache::TellCache(Region& region, int m) 
00079     : _nq(region.alloc<int>(m)), _n_nq(0), _eq(-1) {}
00080   forceinline void 
00081   TellCache::nq(int j) {
00082     _nq[_n_nq++] = j;
00083   }
00084   forceinline void
00085   TellCache::eq(int j) {
00086     // For eq: -1 mean not yet assigned, -2 means failure, positive means value
00087     if (_eq == -1)
00088       _eq = j;
00089     else
00090       _eq = -2;
00091   }
00092   ExecStatus
00093   TellCache::tell(Space& home, IntView x) {
00094     if (_eq == -2) {
00095       return ES_FAILED;
00096     } else if (_eq >= 0) {
00097       GECODE_ME_CHECK(x.eq(home,_eq));
00098     }
00099     Iter::Values::Array nqi(_nq, _n_nq);
00100     GECODE_ME_CHECK(x.minus_v(home, nqi));
00101     _n_nq=0; _eq=-1;
00102     return ES_OK;
00103   }
00104 
00105 
00106   /*
00107    * Propagation proper
00108    *
00109    */
00110   ExecStatus 
00111   Pack::propagate(Space& home, const ModEventDelta& med) {
00112     // Number of items
00113     int n = bs.size();
00114     // Number of bins
00115     int m = l.size();
00116 
00117     {
00118       Region region(home);
00119 
00120       // Possible sizes for bins
00121       int* s = region.alloc<int>(m);
00122 
00123       for (int j=m; j--; )
00124         s[j] = 0;
00125 
00126       // Compute sizes for bins
00127       if (OffsetView::me(med) == ME_INT_VAL) {
00128         // Also eliminate assigned items
00129         int k=0;
00130         for (int i=0; i<n; i++)
00131           if (bs[i].assigned()) {
00132             int j = bs[i].bin().val();
00133             l[j].offset(l[j].offset() - bs[i].size());
00134             t -= bs[i].size();
00135           } else {
00136             for (ViewValues<IntView> j(bs[i].bin()); j(); ++j)
00137               s[j.val()] += bs[i].size();
00138             bs[k++] = bs[i];
00139           }
00140         n=k; bs.size(n);
00141       } else {
00142         for (int i=n; i--; ) {
00143           assert(!bs[i].assigned());
00144           for (ViewValues<IntView> j(bs[i].bin()); j(); ++j)
00145             s[j.val()] += bs[i].size();
00146         }
00147       }
00148 
00149       // Propagate bin loads and compute lower and upper bound
00150       int min = t, max = t;
00151       for (int j=m; j--; ) {
00152         GECODE_ME_CHECK(l[j].gq(home,0));
00153         GECODE_ME_CHECK(l[j].lq(home,s[j]));
00154         min -= l[j].max(); max -= l[j].min();
00155       }
00156 
00157       // Propagate that load must be equal to total size
00158       for (bool mod = true; mod; ) {
00159         mod = false; ModEvent me;
00160         for (int j=m; j--; ) {
00161           int lj_min = l[j].min();
00162           me = l[j].gq(home, min + l[j].max());
00163           if (me_failed(me))
00164             return ES_FAILED;
00165           if (me_modified(me)) {
00166             max += lj_min - l[j].min(); mod = true;
00167           }
00168           int lj_max = l[j].max();
00169           me = l[j].lq(home, max + l[j].min());
00170           if (me_failed(me))
00171             return ES_FAILED;
00172           if (me_modified(me)) {
00173             min += lj_max - l[j].max(); mod = true;
00174           }
00175         }
00176       }
00177 
00178       if (n == 0) {
00179         assert(l.assigned());
00180         return home.ES_SUBSUMED(*this);
00181       }
00182 
00183     
00184       {
00185         TellCache tc(region,m);
00186 
00187         int k=0;
00188         for (int i=0; i<n; i++) {
00189           for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) {
00190             if (bs[i].size() > l[j.val()].max())
00191               tc.nq(j.val());
00192             if (s[j.val()] - bs[i].size() < l[j.val()].min()) 
00193               tc.eq(j.val());
00194           }
00195           GECODE_ES_CHECK(tc.tell(home,bs[i].bin()));
00196           // Eliminate assigned bin
00197           if (bs[i].assigned()) {
00198             int j = bs[i].bin().val();
00199             l[j].offset(l[j].offset() - bs[i].size());
00200             t -= bs[i].size();
00201           } else {
00202             bs[k++] = bs[i];
00203           }
00204         }
00205         n=k; bs.size(n);
00206       }
00207 
00208     }
00209 
00210     // Only if the propagator is at fixpoint here, continue with the more
00211     // expensive stage for propagation.
00212     if (IntView::me(modeventdelta()) != ME_INT_NONE)
00213       return ES_NOFIX;
00214 
00215     // Now the invariant holds that no more assigned bins exist!
00216     {
00217       Region region(home);
00218 
00219       // Size of items
00220       SizeSetMinusOne* s = region.alloc<SizeSetMinusOne>(m);
00221 
00222       for (int j=m; j--; )
00223         s[j] = SizeSetMinusOne(region,n);
00224 
00225       // Set up size information
00226       for (int i=0; i<n; i++) {
00227         assert(!bs[i].assigned());
00228         for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) 
00229           s[j.val()].add(bs[i].size());
00230       }
00231 
00232       for (int j=m; j--; ) {
00233         // Can items still be packed into bin?
00234         if (nosum(static_cast<SizeSet&>(s[j]), l[j].min(), l[j].max()))
00235           return ES_FAILED;
00236         int ap, bp;
00237         // Must there be packed more items into bin?
00238         if (nosum(static_cast<SizeSet&>(s[j]), l[j].min(), l[j].min(), 
00239                   ap, bp))
00240           GECODE_ME_CHECK(l[j].gq(home,bp));
00241         // Must there be packed less items into bin?
00242         if (nosum(static_cast<SizeSet&>(s[j]), l[j].max(), l[j].max(), 
00243                   ap, bp))
00244           GECODE_ME_CHECK(l[j].lq(home,ap));
00245       }
00246 
00247       TellCache tc(region,m);
00248 
00249       int k=0;
00250       for (int i=0; i<n; i++) {
00251         assert(!bs[i].assigned());
00252         for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) {
00253           // Items must be removed in decreasing size!
00254           s[j.val()].minus(bs[i].size());
00255           // Can item i still be packed into bin j?
00256           if (nosum(s[j.val()], 
00257                     l[j.val()].min() - bs[i].size(),
00258                     l[j.val()].max() - bs[i].size()))
00259             tc.nq(j.val());
00260           // Must item i be packed into bin j?
00261           if (nosum(s[j.val()], l[j.val()].min(), l[j.val()].max()))
00262             tc.eq(j.val());
00263         }
00264         GECODE_ES_CHECK(tc.tell(home,bs[i].bin()));
00265         if (bs[i].assigned()) {
00266           int j = bs[i].bin().val();
00267           l[j].offset(l[j].offset() - bs[i].size());
00268           t -= bs[i].size();
00269         } else {
00270           bs[k++] = bs[i];
00271         }
00272       }
00273       n=k; bs.size(n);
00274     }
00275 
00276     // Perform lower bound checking
00277     if (n > 0) {
00278       Region region(home);
00279 
00280       // Find capacity estimate (we start from bs[0] as it might be
00281       // not packable, actually (will be detected later anyway)!
00282       int c = bs[0].size();
00283       for (int j=m; j--; )
00284         c = std::max(c,l[j].max());
00285 
00286       // Count how many items have a certain size (bucket sort)
00287       int* n_s = region.alloc<int>(c+1);
00288 
00289       for (int i=c+1; i--; )
00290         n_s[i] = 0;
00291 
00292       // Count unpacked items
00293       for (int i=n; i--; )
00294         n_s[bs[i].size()]++;
00295 
00296       // Number of items and remaining bin load
00297       int nm = n;
00298 
00299       // Only count positive remaining bin loads
00300       for (int j=m; j--; ) 
00301         if (l[j].max() < 0) {
00302           return ES_FAILED;
00303         } else if (c > l[j].max()) {
00304           n_s[c - l[j].max()]++; nm++;
00305         }
00306 
00307       // Sizes of items and remaining bin loads
00308       int* s = region.alloc<int>(nm);
00309 
00310       // Setup sorted sizes
00311       {
00312         int k=0;
00313         for (int i=c+1; i--; )
00314           for (int n=n_s[i]; n--; )
00315             s[k++]=i;
00316         assert(k == nm);
00317       }
00318 
00319       // Items in N1 are from 0 ... n1 - 1
00320       int n1 = 0;
00321       // Items in N2 are from n1 ... n12 - 1, we count elements in N1 and N2
00322       int n12 = 0;
00323       // Items in N3 are from n12 ... n3 - 1 
00324       int n3 = 0;
00325       // Free space in N2
00326       int f2 = 0;
00327       // Total size of items in N3
00328       int s3 = 0;
00329 
00330       // Initialize n12 and f2
00331       for (; (n12 < nm) && (s[n12] > c/2); n12++)
00332         f2 += c - s[n12];
00333 
00334       // Initialize n3 and s3
00335       for (n3 = n12; n3 < nm; n3++)
00336         s3 += s[n3];
00337         
00338       // Compute lower bounds
00339       for (int k=0; k<=c/2; k++) {
00340         // Make N1 larger by adding elements and N2 smaller
00341         for (; (n1 < nm) && (s[n1] > c-k); n1++)
00342           f2 -= c - s[n1];
00343         assert(n1 <= n12);
00344         // Make N3 smaller by removing elements
00345         for (; (s[n3-1] < k) && (n3 > n12); n3--)
00346           s3 -= s[n3-1];
00347         // Overspill
00348         int o = (s3 > f2) ? ((s3 - f2 + c - 1) / c) : 0;
00349         if (n12 + o > m)
00350           return ES_FAILED;
00351       }
00352     }
00353 
00354     return ES_NOFIX;
00355   }
00356 
00357   ExecStatus
00358   Pack::post(Home home, ViewArray<OffsetView>& l, ViewArray<Item>& bs) {
00359     if (bs.size() == 0) {
00360       // No items to be packed
00361       for (int i=l.size(); i--; )
00362         GECODE_ME_CHECK(l[i].eq(home,0));
00363       return ES_OK;
00364     } else if (l.size() == 0) {
00365       // No bins available
00366       return ES_FAILED;
00367     } else {
00368       int s = 0;
00369       // Constrain bins 
00370       for (int i=bs.size(); i--; ) {
00371         s += bs[i].size();
00372         GECODE_ME_CHECK(bs[i].bin().gq(home,0));
00373         GECODE_ME_CHECK(bs[i].bin().le(home,l.size()));
00374       }
00375       // Constrain load
00376       for (int j=l.size(); j--; ) {
00377         GECODE_ME_CHECK(l[j].gq(home,0));
00378         GECODE_ME_CHECK(l[j].lq(home,s));
00379       }
00380       (void) new (home) Pack(home,l,bs);
00381       return ES_OK;
00382     }
00383   }
00384 
00385 }}}
00386 
00387 // STATISTICS: int-prop
00388