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

val.hpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Mikael Lagerkvist <lagerkvist@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Mikael Lagerkvist, 2005
00008  *
00009  *  Last modified:
00010  *     $Date: 2011-07-13 14:17:55 +0200 (Wed, 13 Jul 2011) $ by $Author: tack $
00011  *     $Revision: 12188 $
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 <algorithm>
00039 
00040 /*
00041  * This is the propagation algorithm of the cumulatives constraint as
00042  * presented in:
00043  *   Nicolas Beldiceanu and Mats Carlsson, A New Multi-resource cumulatives
00044  *   Constraint with Negative Heights. CP 2002, pages 63-79, Springer-Verlag.
00045  */
00046 
00047 namespace Gecode { namespace Int { namespace Cumulatives {
00048 
00049   template<class ViewM, class ViewP, class ViewU, class View>
00050   forceinline
00051   Val<ViewM,ViewP,ViewU,View>::Val(Home home,
00052                                    const ViewArray<ViewM>& _m,
00053                                    const ViewArray<View>& _s,
00054                                    const ViewArray<ViewP>& _p,
00055                                    const ViewArray<View>& _e,
00056                                    const ViewArray<ViewU>& _u,
00057                                    const SharedArray<int>& _c,
00058                                    bool _at_most) :
00059     Propagator(home),
00060     m(_m), s(_s), p(_p), e(_e), u(_u), c(_c), at_most(_at_most) {
00061     home.notice(*this,AP_DISPOSE);
00062 
00063     m.subscribe(home,*this,Int::PC_INT_DOM);
00064     s.subscribe(home,*this,Int::PC_INT_BND);
00065     p.subscribe(home,*this,Int::PC_INT_BND);
00066     e.subscribe(home,*this,Int::PC_INT_BND);
00067     u.subscribe(home,*this,Int::PC_INT_BND);
00068   }
00069 
00070   template<class ViewM, class ViewP, class ViewU, class View>
00071   ExecStatus
00072   Val<ViewM,ViewP,ViewU,View>
00073   ::post(Home home, const ViewArray<ViewM>& m,
00074          const ViewArray<View>& s, const ViewArray<ViewP>& p,
00075          const ViewArray<View>& e, const ViewArray<ViewU>& u,
00076          const SharedArray<int>& c, bool at_most) {
00077     (void) new (home) Val(home, m,s,p,e,u,c,at_most);
00078     return ES_OK;
00079   }
00080 
00081   template<class ViewM, class ViewP, class ViewU, class View>
00082   forceinline
00083   Val<ViewM,ViewP,ViewU,View>::Val(Space& home, bool share,
00084                                    Val<ViewM,ViewP,ViewU,View>& vp)
00085     : Propagator(home,share,vp), at_most(vp.at_most) {
00086     m.update(home,share,vp.m);
00087     s.update(home, share, vp.s);
00088     p.update(home, share, vp.p);
00089     e.update(home, share, vp.e);
00090     u.update(home, share, vp.u);
00091     c.update(home, share, vp.c);
00092   }
00093 
00094   template<class ViewM, class ViewP, class ViewU, class View>
00095   size_t
00096   Val<ViewM,ViewP,ViewU,View>::dispose(Space& home) {
00097     home.ignore(*this,AP_DISPOSE);
00098     if (!home.failed()) {
00099       m.cancel(home,*this,Int::PC_INT_DOM);
00100       s.cancel(home,*this,Int::PC_INT_BND);
00101       p.cancel(home,*this,Int::PC_INT_BND);
00102       e.cancel(home,*this,Int::PC_INT_BND);
00103       u.cancel(home,*this,Int::PC_INT_BND);
00104     }
00105     c.~SharedArray();
00106     (void) Propagator::dispose(home);
00107     return sizeof(*this);
00108   }
00109 
00110   template<class ViewM, class ViewP, class ViewU, class View>
00111   PropCost
00112   Val<ViewM,ViewP,ViewU,View>::cost(const Space&, const ModEventDelta&) const {
00113     return PropCost::quadratic(PropCost::LO, s.size());
00114   }
00115 
00116   template<class ViewM, class ViewP, class ViewU, class View>
00117   Actor*
00118   Val<ViewM,ViewP,ViewU,View>::copy(Space& home, bool share) {
00119     return new (home) Val<ViewM,ViewP,ViewU,View>(home,share,*this);
00120   }
00121 
00123   typedef enum {EVENT_CHCK, EVENT_PROF, EVENT_PRUN} ev_t;
00125   class Event
00126   {
00127   public:
00129     ev_t e;
00131     int task;
00133     int date;
00135     int inc;
00140     bool first_prof;
00141 
00143     Event(ev_t _e, int _task, int _date, int _inc = 0, bool _first_prof = false)
00144       : e(_e), task(_task), date(_date), inc(_inc), first_prof(_first_prof)
00145     {}
00146 
00147     // Default constructor for region-allocated memory
00148     Event(void) {}
00149 
00151     bool operator <(const Event& ev) const {
00152       if (date == ev.date) {
00153         if (e == EVENT_PROF && ev.e != EVENT_PROF) return true;
00154         if (e == EVENT_CHCK && ev.e == EVENT_PRUN) return true;
00155         return false;
00156       }
00157       return date < ev.date;
00158     }
00159   };
00160 
00161   template<class ViewM, class ViewP, class ViewU, class View>
00162   ExecStatus
00163   Val<ViewM,ViewP,ViewU,View>::prune(Space& home, int low, int up, int r,
00164                                      int ntask, int su,
00165                                      int* contribution,
00166                                      int* prune_tasks, int& prune_tasks_size) {
00167 
00168     if (ntask > 0 && (at_most ? su > c[r] : su < c[r])) {
00169       return ES_FAILED;
00170     }
00171 
00172     int pti = 0;
00173     while (pti != prune_tasks_size) {
00174       int t = prune_tasks[pti];
00175 
00176       // Algorithm 2.
00177       // Prune the machine, start, and end for required
00178       // tasks for machine r that have heights possibly greater than 0.
00179       if (ntask != 0 &&
00180           (at_most ? u[t].min() < 0
00181            : u[t].max() > 0) &&
00182           (at_most ? su-contribution[t] > c[r]
00183            : su-contribution[t] < c[r])) {
00184         if (me_failed(m[t].eq(home, r))||
00185             me_failed(s[t].gq(home, up-p[t].max()+1))||
00186             me_failed(s[t].lq(home, low))||
00187             me_failed(e[t].lq(home,low+p[t].max()))||
00188             me_failed(e[t].gq(home, up+1))||
00189             me_failed(p[t].gq(home,std::min(up-s[t].max()+1,e[t].min()-low)))
00190             ) {
00191           return ES_FAILED;
00192         }
00193       }
00194 
00195       // Algorithm 3.
00196       // Remove values that prevent us from reaching the limit
00197       if (at_most ? u[t].min() > std::min(0, c[r])
00198           : u[t].max() < std::max(0, c[r])) {
00199         if (at_most ? su-contribution[t]+u[t].min() > c[r]
00200             : su-contribution[t]+u[t].max() < c[r]) {
00201           if (e[t].min() > low  &&
00202               s[t].max() <= up &&
00203               p[t].min() > 0) {
00204             if (me_failed(m[t].nq(home, r))) {
00205               return ES_FAILED;
00206             }
00207           } else if (m[t].assigned()) {
00208             int ptmin = p[t].min();
00209             if (ptmin > 0) {
00210               Iter::Ranges::Singleton
00211                 a(low-ptmin+1, up), b(low+1, up+ptmin);
00212               if (me_failed(s[t].minus_r(home,a,false)) ||
00213                   me_failed(e[t].minus_r(home, b,false)))
00214                 return ES_FAILED;
00215             }
00216             if (me_failed(p[t].lq(home,std::max(std::max(low-s[t].min(),
00217                                                          e[t].max()-up-1),
00218                                                 0)))) {
00219               return ES_FAILED;
00220             }
00221           }
00222         }
00223       }
00224 
00225       // Algorithm 4.
00226       // Remove bad negative values from for-sure heights.
00227       /* \note "It is not sufficient to only test for assignment of machine[t]
00228        *         since Algorithm 3 can remove the value." Check this against
00229        *         the conditions for Alg3.
00230        */
00231       if (m[t].assigned() &&
00232           m[t].val() == r &&
00233           e[t].min() > low    &&
00234           s[t].max() <= up  &&
00235           p[t].min() > 0 ) {
00236         if (me_failed(at_most
00237                       ? u[t].lq(home, c[r]-su+contribution[t])
00238                       : u[t].gq(home, c[r]-su+contribution[t]))) {
00239           return ES_FAILED;
00240         }
00241       }
00242 
00243       // Remove tasks that are no longer relevant.
00244       if (!m[t].in(r) || (e[t].max() <= up+1)) {
00245         prune_tasks[pti] = prune_tasks[--prune_tasks_size];
00246       } else {
00247         ++pti;
00248       }
00249     }
00250 
00251     return ES_OK;
00252   }
00253 
00254   namespace {
00255     template<class C>
00256     class Less {
00257     public:
00258       bool operator ()(const C& lhs, const C& rhs) {
00259         return lhs < rhs;
00260       }
00261     };
00262   }
00263 
00264   template<class ViewM, class ViewP, class ViewU, class View>
00265   ExecStatus
00266   Val<ViewM,ViewP,ViewU,View>::propagate(Space& home, const ModEventDelta&) {
00267     // Check for subsumption
00268     bool subsumed = true;
00269     for (int t = s.size(); t--; )
00270       if (!(p[t].assigned() && e[t].assigned()   &&
00271             m[t].assigned()  && s[t].assigned() &&
00272             u[t].assigned())) {
00273         subsumed = false;
00274         break;
00275       }
00276     // Propagate information for machine r
00277     Region region(home);
00278     Event *events = region.alloc<Event>(s.size()*8);
00279     int  events_size;
00280     int *prune_tasks = region.alloc<int>(s.size());
00281     int  prune_tasks_size;
00282     int *contribution = region.alloc<int>(s.size());
00283     for (int r = c.size(); r--; ) {
00284       events_size = 0;
00285 #define GECODE_PUSH_EVENTS(E) assert(events_size < s.size()*8);     \
00286         events[events_size++] = E
00287 
00288       // Find events for sweep-line
00289       for (int t = s.size(); t--; ) {
00290         if (m[t].assigned() &&
00291             m[t].val() == r &&
00292             s[t].max() < e[t].min()) {
00293           if (at_most
00294               ? u[t].min() > std::min(0, c[r])
00295               : u[t].max() < std::max(0, c[r])) {
00296             GECODE_PUSH_EVENTS(Event(EVENT_CHCK, t, s[t].max(), 1));
00297             GECODE_PUSH_EVENTS(Event(EVENT_CHCK, t, e[t].min(), -1));
00298           }
00299           if (at_most
00300               ? u[t].min() > 0
00301               : u[t].max() < 0) {
00302             GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, s[t].max(),
00303                                      at_most ? u[t].min() : u[t].max(), true));
00304             GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, e[t].min(),
00305                                      at_most ? -u[t].min() : -u[t].max()));
00306           }
00307         }
00308 
00309         if (m[t].in(r)) {
00310           if (at_most
00311               ? u[t].min() < 0
00312               : u[t].max() > 0) {
00313             GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, s[t].min(),
00314                                      at_most ? u[t].min() : u[t].max(), true));
00315             GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, e[t].max(),
00316                                      at_most ? -u[t].min() : -u[t].max()));
00317           }
00318           if (!(m[t].assigned() &&
00319                 u[t].assigned() &&
00320                 s[t].assigned() &&
00321                 e[t].assigned())) {
00322             GECODE_PUSH_EVENTS(Event(EVENT_PRUN, t, s[t].min()));
00323           }
00324         }
00325       }
00326 #undef GECODE_PUSH_EVENTS
00327 
00328       // If there are no events, continue with next machine
00329       if (events_size == 0) {
00330         continue;
00331       }
00332 
00333       // Sort the events according to date
00334       Less<Event> less;
00335       Support::insertion(&events[0], events_size, less);
00336 
00337       // Sweep line along d, starting at 0
00338       int d        = 0;
00339       int ntask    = 0;
00340       int su  = 0;
00341       int ei = 0;
00342 
00343       prune_tasks_size = 0;
00344       for (int i = s.size(); i--; ) contribution[i] = 0;
00345 
00346       d = events[ei].date;
00347       while (ei < events_size) {
00348         if (events[ei].e != EVENT_PRUN) {
00349           if (d != events[ei].date) {
00350             GECODE_ES_CHECK(prune(home, d, events[ei].date-1, r,
00351                                   ntask, su,
00352                                   contribution, prune_tasks, prune_tasks_size));
00353             d = events[ei].date;
00354           }
00355           if (events[ei].e == EVENT_CHCK) {
00356             ntask += events[ei].inc;
00357           } else /* if (events[ei].e == EVENT_PROF) */ {
00358             su += events[ei].inc;
00359             if(events[ei].first_prof)
00360               contribution[events[ei].task] = at_most
00361                 ? std::max(contribution[events[ei].task], events[ei].inc)
00362                 : std::min(contribution[events[ei].task], events[ei].inc);
00363           }
00364         } else /* if (events[ei].e == EVENT_PRUN) */ {
00365           assert(prune_tasks_size<s.size());
00366           prune_tasks[prune_tasks_size++] = events[ei].task;
00367         }
00368         ei++;
00369       }
00370 
00371       GECODE_ES_CHECK(prune(home, d, d, r,
00372                             ntask, su,
00373                             contribution, prune_tasks, prune_tasks_size));
00374     }
00375     return subsumed ? home.ES_SUBSUMED(*this): ES_NOFIX;
00376   }
00377 
00378 }}}
00379 
00380 // STATISTICS: int-prop