Generated on Tue Apr 18 10:21:48 2017 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: 2016-06-29 17:28:17 +0200 (Wed, 29 Jun 2016) $ by $Author: schulte $
00011  *     $Revision: 15137 $
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   void
00053   Pack::reschedule(Space& home) {
00054     l.reschedule(home,*this,PC_INT_BND);
00055     bs.reschedule(home,*this,PC_INT_DOM);
00056   }
00057 
00058   Actor*
00059   Pack::copy(Space& home, bool share) {
00060     return new (home) Pack(home,share,*this);
00061   }
00062 
00064   class TellCache {
00065   protected:
00067     int* _nq;
00069     int _n_nq;
00071     int _eq;
00072   public:
00074     TellCache(Region& region, int m);
00076     void nq(int j);
00078     void eq(int j);
00080     ExecStatus tell(Space& home, IntView x);
00081   };
00082 
00083   forceinline
00084   TellCache::TellCache(Region& region, int m)
00085     : _nq(region.alloc<int>(m)), _n_nq(0), _eq(-1) {}
00086   forceinline void
00087   TellCache::nq(int j) {
00088     _nq[_n_nq++] = j;
00089   }
00090   forceinline void
00091   TellCache::eq(int j) {
00092     // For eq: -1 mean not yet assigned, -2 means failure, positive means value
00093     if (_eq == -1)
00094       _eq = j;
00095     else
00096       _eq = -2;
00097   }
00098   ExecStatus
00099   TellCache::tell(Space& home, IntView x) {
00100     if (_eq == -2) {
00101       return ES_FAILED;
00102     } else if (_eq >= 0) {
00103       GECODE_ME_CHECK(x.eq(home,_eq));
00104     }
00105     Iter::Values::Array nqi(_nq, _n_nq);
00106     GECODE_ME_CHECK(x.minus_v(home, nqi));
00107     _n_nq=0; _eq=-1;
00108     return ES_OK;
00109   }
00110 
00111 
00112   /*
00113    * Propagation proper
00114    *
00115    */
00116   ExecStatus
00117   Pack::propagate(Space& home, const ModEventDelta& med) {
00118     // Number of items
00119     int n = bs.size();
00120     // Number of bins
00121     int m = l.size();
00122 
00123     {
00124       Region region(home);
00125 
00126       // Possible sizes for bins
00127       int* s = region.alloc<int>(m);
00128 
00129       for (int j=m; j--; )
00130         s[j] = 0;
00131 
00132       // Compute sizes for bins
00133       if (OffsetView::me(med) == ME_INT_VAL) {
00134         // Also eliminate assigned items
00135         int k=0;
00136         for (int i=0; i<n; i++)
00137           if (bs[i].assigned()) {
00138             int j = bs[i].bin().val();
00139             l[j].offset(l[j].offset() - bs[i].size());
00140             t -= bs[i].size();
00141           } else {
00142             for (ViewValues<IntView> j(bs[i].bin()); j(); ++j)
00143               s[j.val()] += bs[i].size();
00144             bs[k++] = bs[i];
00145           }
00146         n=k; bs.size(n);
00147       } else {
00148         for (int i=n; i--; ) {
00149           assert(!bs[i].assigned());
00150           for (ViewValues<IntView> j(bs[i].bin()); j(); ++j)
00151             s[j.val()] += bs[i].size();
00152         }
00153       }
00154 
00155       // Propagate bin loads and compute lower and upper bound
00156       int min = t, max = t;
00157       for (int j=m; j--; ) {
00158         GECODE_ME_CHECK(l[j].gq(home,0));
00159         GECODE_ME_CHECK(l[j].lq(home,s[j]));
00160         min -= l[j].max(); max -= l[j].min();
00161       }
00162 
00163       // Propagate that load must be equal to total size
00164       for (bool mod = true; mod; ) {
00165         mod = false; ModEvent me;
00166         for (int j=m; j--; ) {
00167           int lj_min = l[j].min();
00168           me = l[j].gq(home, min + l[j].max());
00169           if (me_failed(me))
00170             return ES_FAILED;
00171           if (me_modified(me)) {
00172             max += lj_min - l[j].min(); mod = true;
00173           }
00174           int lj_max = l[j].max();
00175           me = l[j].lq(home, max + l[j].min());
00176           if (me_failed(me))
00177             return ES_FAILED;
00178           if (me_modified(me)) {
00179             min += lj_max - l[j].max(); mod = true;
00180           }
00181         }
00182       }
00183 
00184       if (n == 0) {
00185         assert(l.assigned());
00186         return home.ES_SUBSUMED(*this);
00187       }
00188 
00189 
00190       {
00191         TellCache tc(region,m);
00192 
00193         int k=0;
00194         for (int i=0; i<n; i++) {
00195           for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) {
00196             if (bs[i].size() > l[j.val()].max())
00197               tc.nq(j.val());
00198             if (s[j.val()] - bs[i].size() < l[j.val()].min())
00199               tc.eq(j.val());
00200           }
00201           GECODE_ES_CHECK(tc.tell(home,bs[i].bin()));
00202           // Eliminate assigned bin
00203           if (bs[i].assigned()) {
00204             int j = bs[i].bin().val();
00205             l[j].offset(l[j].offset() - bs[i].size());
00206             t -= bs[i].size();
00207           } else {
00208             bs[k++] = bs[i];
00209           }
00210         }
00211         n=k; bs.size(n);
00212       }
00213 
00214     }
00215 
00216     // Only if the propagator is at fixpoint here, continue with the more
00217     // expensive stage for propagation.
00218     if (IntView::me(modeventdelta()) != ME_INT_NONE)
00219       return ES_NOFIX;
00220 
00221     // Now the invariant holds that no more assigned bins exist!
00222     {
00223       Region region(home);
00224 
00225       // Size of items
00226       SizeSetMinusOne* s = region.alloc<SizeSetMinusOne>(m);
00227 
00228       for (int j=m; j--; )
00229         s[j] = SizeSetMinusOne(region,n);
00230 
00231       // Set up size information
00232       for (int i=0; i<n; i++) {
00233         assert(!bs[i].assigned());
00234         for (ViewValues<IntView> j(bs[i].bin()); j(); ++j)
00235           s[j.val()].add(bs[i].size());
00236       }
00237 
00238       for (int j=m; j--; ) {
00239         // Can items still be packed into bin?
00240         if (nosum(static_cast<SizeSet&>(s[j]), l[j].min(), l[j].max()))
00241           return ES_FAILED;
00242         int ap, bp;
00243         // Must there be packed more items into bin?
00244         if (nosum(static_cast<SizeSet&>(s[j]), l[j].min(), l[j].min(),
00245                   ap, bp))
00246           GECODE_ME_CHECK(l[j].gq(home,bp));
00247         // Must there be packed less items into bin?
00248         if (nosum(static_cast<SizeSet&>(s[j]), l[j].max(), l[j].max(),
00249                   ap, bp))
00250           GECODE_ME_CHECK(l[j].lq(home,ap));
00251       }
00252 
00253       TellCache tc(region,m);
00254 
00255       int k=0;
00256       for (int i=0; i<n; i++) {
00257         assert(!bs[i].assigned());
00258         for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) {
00259           // Items must be removed in decreasing size!
00260           s[j.val()].minus(bs[i].size());
00261           // Can item i still be packed into bin j?
00262           if (nosum(s[j.val()],
00263                     l[j.val()].min() - bs[i].size(),
00264                     l[j.val()].max() - bs[i].size()))
00265             tc.nq(j.val());
00266           // Must item i be packed into bin j?
00267           if (nosum(s[j.val()], l[j.val()].min(), l[j.val()].max()))
00268             tc.eq(j.val());
00269         }
00270         GECODE_ES_CHECK(tc.tell(home,bs[i].bin()));
00271         if (bs[i].assigned()) {
00272           int j = bs[i].bin().val();
00273           l[j].offset(l[j].offset() - bs[i].size());
00274           t -= bs[i].size();
00275         } else {
00276           bs[k++] = bs[i];
00277         }
00278       }
00279       n=k; bs.size(n);
00280     }
00281 
00282     // Perform lower bound checking
00283     if (n > 0) {
00284       Region region(home);
00285 
00286       // Find capacity estimate (we start from bs[0] as it might be
00287       // not packable, actually (will be detected later anyway)!
00288       int c = bs[0].size();
00289       for (int j=m; j--; )
00290         c = std::max(c,l[j].max());
00291 
00292       // Count how many items have a certain size (bucket sort)
00293       int* n_s = region.alloc<int>(c+1);
00294 
00295       for (int i=c+1; i--; )
00296         n_s[i] = 0;
00297 
00298       // Count unpacked items
00299       for (int i=n; i--; )
00300         n_s[bs[i].size()]++;
00301 
00302       // Number of items and remaining bin load
00303       int nm = n;
00304 
00305       // Only count positive remaining bin loads
00306       for (int j=m; j--; )
00307         if (l[j].max() < 0) {
00308           return ES_FAILED;
00309         } else if (c > l[j].max()) {
00310           n_s[c - l[j].max()]++; nm++;
00311         }
00312 
00313       // Sizes of items and remaining bin loads
00314       int* s = region.alloc<int>(nm);
00315 
00316       // Setup sorted sizes
00317       {
00318         int k=0;
00319         for (int i=c+1; i--; )
00320           for (int j=n_s[i]; j--; )
00321             s[k++]=i;
00322         assert(k == nm);
00323       }
00324 
00325       // Items in N1 are from 0 ... n1 - 1
00326       int n1 = 0;
00327       // Items in N2 are from n1 ... n12 - 1, we count elements in N1 and N2
00328       int n12 = 0;
00329       // Items in N3 are from n12 ... n3 - 1
00330       int n3 = 0;
00331       // Free space in N2
00332       int f2 = 0;
00333       // Total size of items in N3
00334       int s3 = 0;
00335 
00336       // Initialize n12 and f2
00337       for (; (n12 < nm) && (s[n12] > c/2); n12++)
00338         f2 += c - s[n12];
00339 
00340       // Initialize n3 and s3
00341       for (n3 = n12; n3 < nm; n3++)
00342         s3 += s[n3];
00343 
00344       // Compute lower bounds
00345       for (int k=0; k<=c/2; k++) {
00346         // Make N1 larger by adding elements and N2 smaller
00347         for (; (n1 < nm) && (s[n1] > c-k); n1++)
00348           f2 -= c - s[n1];
00349         assert(n1 <= n12);
00350         // Make N3 smaller by removing elements
00351         for (; (s[n3-1] < k) && (n3 > n12); n3--)
00352           s3 -= s[n3-1];
00353         // Overspill
00354         int o = (s3 > f2) ? ((s3 - f2 + c - 1) / c) : 0;
00355         if (n12 + o > m)
00356           return ES_FAILED;
00357       }
00358     }
00359 
00360     return ES_NOFIX;
00361   }
00362 
00363   ExecStatus
00364   Pack::post(Home home, ViewArray<OffsetView>& l, ViewArray<Item>& bs) {
00365     // Sort according to size
00366     Support::quicksort(&bs[0], bs.size());
00367     // Total size of items
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     // Eliminate zero sized items (which are at the end as the size are sorted)
00376     {
00377       int n = bs.size();
00378       while ((n > 0) && (bs[n-1].size() == 0))
00379         n--;
00380       bs.size(n);
00381     }
00382     if (bs.size() == 0) {
00383       // No items to be packed
00384       for (int i=l.size(); i--; )
00385         GECODE_ME_CHECK(l[i].eq(home,0));
00386       return ES_OK;
00387     } else if (l.size() == 0) {
00388       // No bins available
00389       return ES_FAILED;
00390     } else {
00391       // Constrain load
00392       for (int j=l.size(); j--; ) {
00393         GECODE_ME_CHECK(l[j].gq(home,0));
00394         GECODE_ME_CHECK(l[j].lq(home,s));
00395       }
00396       (void) new (home) Pack(home,l,bs);
00397       return ES_OK;
00398     }
00399   }
00400 
00401 }}}
00402 
00403 // STATISTICS: int-prop
00404