Generated on Mon Aug 25 11:35:36 2008 for Gecode by doxygen 1.5.6

val.icc

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: 2008-08-20 18:29:46 +0200 (Wed, 20 Aug 2008) $ by $Author: tack $
00011  *     $Revision: 7668 $
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 /* This is the propagation algorithm of the cumulatives constraint as presented in
00039    @inproceedings{DBLP:conf/cp/BeldiceanuC02,
00040      author    = {Nicolas Beldiceanu and Mats Carlsson},
00041      title     = {A New Multi-resource cumulatives Constraint with Negative Heights.},
00042      booktitle = {CP},
00043      year      = {2002},
00044      pages     = {63-79},
00045      ee        = {http://link.springer.de/link/service/series/0558/bibs/2470/24700063.htm},
00046      crossref  = {DBLP:conf/cp/2002},
00047      bibsource = {DBLP, http://dblp.uni-trier.de}
00048    }
00049    @proceedings{DBLP:conf/cp/2002,
00050      editor    = {Pascal Van Hentenryck},
00051      title     = {Principles and Practice of Constraint Programming - CP 2002,
00052                   8th International Conference, CP 2002,
00053                   Ithaca, NY, USA, September 9-13, 2002, Proceedings},
00054      booktitle = {CP},
00055      publisher = {Springer},
00056      series    = {Lecture Notes in Computer Science},
00057      volume    = {2470},
00058      year      = {2002},
00059      isbn      = {3-540-44120-4},
00060      bibsource = {DBLP, http://dblp.uni-trier.de}
00061    }
00062 
00063  */
00064 
00065 #include <vector>
00066 #include <list>
00067 #include <algorithm>
00068 
00069 
00070 namespace Gecode { namespace Int { namespace Cumulatives {
00071 
00072   template <class ViewM, class ViewD, class ViewH, class View>
00073   forceinline
00074   Val<ViewM,ViewD,ViewH,View>::Val(Space* home, 
00075                                    const ViewArray<ViewM>& _machine,
00076                                    const ViewArray<View>& _start,
00077                                    const ViewArray<ViewD>& _duration,
00078                                    const ViewArray<View>& _end,
00079                                    const ViewArray<ViewH>& _height,
00080                                    const IntArgs& _limit,
00081                                    bool _at_most) :
00082     Propagator(home),
00083     machine(_machine), start(_start), duration(_duration),
00084     end(_end), height(_height), limit(_limit.size()), at_most(_at_most) {
00085     force(home);    
00086     for(int i = _limit.size(); i--; )
00087       limit[i] = _limit[i];
00088 
00089     machine.subscribe(home,this,PC_INT_DOM);
00090     start.subscribe(home,this,PC_INT_BND);
00091     duration.subscribe(home,this,PC_INT_BND);
00092     end.subscribe(home,this,PC_INT_BND);
00093     height.subscribe(home,this,PC_INT_BND);
00094   }
00095 
00096   template <class ViewM, class ViewD, class ViewH, class View>
00097   ExecStatus
00098   Val<ViewM,ViewD,ViewH,View>
00099   ::post(Space* home, const ViewArray<ViewM>& machine,
00100          const ViewArray<View>& start, const ViewArray<ViewD>& duration,
00101          const ViewArray<View>& end, const ViewArray<ViewH>& height,
00102          const IntArgs& limit, bool at_most) {
00103     (void) new (home) Val(home, machine, start, duration,
00104                           end, height, limit, at_most);
00105 
00106     return ES_OK;
00107   }
00108 
00109   template <class ViewM, class ViewD, class ViewH, class View>
00110   forceinline
00111   Val<ViewM,ViewD,ViewH,View>::Val(Space* home, bool share,
00112                                    Val<ViewM,ViewD,ViewH,View>& p)
00113     : Propagator(home,share,p), at_most(p.at_most) {
00114     machine.update(home,share,p.machine);
00115     start.update(home, share, p.start);
00116     duration.update(home, share, p.duration);
00117     end.update(home, share, p.end);
00118     height.update(home, share, p.height);
00119     limit.update(home, share, p.limit);
00120   }
00121 
00122   template <class ViewM, class ViewD, class ViewH, class View>
00123   size_t
00124   Val<ViewM,ViewD,ViewH,View>::dispose(Space* home) {
00125     unforce(home);
00126     if (!home->failed()) {
00127       machine.cancel(home,this,PC_INT_DOM);
00128       start.cancel(home,this,PC_INT_BND);
00129       duration.cancel(home,this,PC_INT_BND);
00130       end.cancel(home,this,PC_INT_BND);
00131       height.cancel(home,this,PC_INT_BND);
00132     }
00133     limit.~SharedArray();
00134     (void) Propagator::dispose(home);
00135     return sizeof(*this);
00136   }
00137 
00138   template <class ViewM, class ViewD, class ViewH, class View>
00139   PropCost
00140   Val<ViewM,ViewD,ViewH,View>::cost(ModEventDelta) const {
00141     return cost_hi(start.size(), PC_QUADRATIC_LO);
00142   }
00143 
00144   template <class ViewM, class ViewD, class ViewH, class View>
00145   Support::Symbol
00146   Val<ViewM,ViewD,ViewH,View>::ati(void) {
00147     return 
00148       Reflection::mangle<ViewM,ViewD,ViewH,View>("Gecode::Int::Cumulatives::Val");
00149   }
00150 
00151   template <class ViewM, class ViewD, class ViewH, class View>
00152   Reflection::ActorSpec
00153   Val<ViewM,ViewD,ViewH,View>::spec(const Space* home,
00154                                     Reflection::VarMap& m) const {
00155     Reflection::ActorSpec s(ati());
00156 
00157     return s << machine.spec(home, m)
00158              << start.spec(home, m)
00159              << duration.spec(home, m)
00160              << end.spec(home, m)
00161              << height.spec(home, m)
00162              << Reflection::Arg::newIntArray(limit)
00163              << at_most;
00164   }
00165 
00166   template <class ViewM, class ViewD, class ViewH, class View>
00167   void
00168   Val<ViewM,ViewD,ViewH,View>::post(Space* home, Reflection::VarMap& vars,
00169                                     const Reflection::ActorSpec& spec) {
00170     spec.checkArity(7);
00171     ViewArray<ViewM> machine(home, vars, spec[0]);
00172     ViewArray<View>  start(home, vars, spec[1]);
00173     ViewArray<ViewD> duration(home, vars, spec[2]);
00174     ViewArray<View>  end(home, vars, spec[3]);
00175     ViewArray<ViewH> height(home, vars, spec[4]);
00176     Reflection::IntArrayArg* limitA = spec[5]->toIntArray();
00177     IntArgs limit(limitA->size());
00178     for (int i=limitA->size(); i--; )
00179       limit[i] = (*limitA)[i];
00180     bool at_most = spec[6]->toInt();
00181     (void) new (home) Val(home,machine,start,duration,
00182                           end,height,limit,at_most);
00183   }
00184 
00185   template <class ViewM, class ViewD, class ViewH, class View>
00186   Actor*
00187   Val<ViewM,ViewD,ViewH,View>::copy(Space* home, bool share) {
00188     return new (home) Val<ViewM,ViewD,ViewH,View>(home,share,*this);
00189   }
00190 
00192   typedef enum {EVENT_CHCK, EVENT_PROF, EVENT_PRUN} ev_t;
00194   class Event
00195   {
00196   public:
00198     ev_t e;
00200     int task;
00202     int date;
00204     int inc;
00209     bool first_prof;
00210 
00212     Event(ev_t _e, int _task, int _date, int _inc = 0, bool _first_prof = false)
00213       : e(_e), task(_task), date(_date), inc(_inc), first_prof(_first_prof)
00214     {}
00215 
00217     bool operator<(const Event& ev) const {
00218       if (date == ev.date) {
00219         if (e == EVENT_PROF && ev.e != EVENT_PROF) return true;
00220         if (e == EVENT_CHCK && ev.e == EVENT_PRUN) return true;
00221         return false;
00222       }
00223       return date < ev.date;
00224     }
00225   };
00226 
00227   template <class ViewM, class ViewD, class ViewH, class View>
00228   ExecStatus
00229   Val<ViewM,ViewD,ViewH,View>::prune(Space * home, int low, int up, int r,
00230                                      int ntask, int sheight,
00231                                      int* contribution,
00232                                      int* prune_tasks, int& prune_tasks_size) {
00233 
00234     if (ntask > 0 &&
00235         (at_most ? sheight > limit[r]
00236          : sheight < limit[r])) {
00237       return ES_FAILED;
00238     }
00239 
00240     //    std::list<int>::iterator it = prune_tasks.begin();
00241     //    while (it != prune_tasks.end()) {
00242     //      int t = *it;
00243     int pti = 0;
00244     while (pti != prune_tasks_size) {
00245       int t = prune_tasks[pti];
00246       // Algorithm 2.
00247       // Prune the machine, start, and end for required
00248       // tasks for machine r that have heights possibly greater than 0.
00249       if (ntask != 0 &&
00250           (at_most ? height[t].min() < 0
00251            : height[t].max() > 0) &&
00252           (at_most ? sheight-contribution[t] > limit[r]
00253            : sheight-contribution[t] < limit[r])) {
00254         if (me_failed(machine[t].eq(home, r))||
00255             me_failed(start[t].gq(home, up-duration[t].max()+1))||
00256             me_failed(start[t].lq(home, low))||
00257             me_failed(end[t].lq(home,low+duration[t].max()))||
00258             me_failed(end[t].gq(home, up+1))||
00259             me_failed(duration[t].gq(home,std::min(up-start[t].max()+1,
00260                                                    end[t].min()-low)))
00261             ) {
00262           return ES_FAILED;
00263         }
00264       }
00265 
00266       // Algorithm 3.
00267       // Remove values that prevent us from reaching the limit
00268       if (at_most ? height[t].min() > std::min(0, limit[r])
00269           : height[t].max() < std::max(0, limit[r])) {
00270         if (at_most ? sheight-contribution[t]+height[t].min() > limit[r]
00271             : sheight-contribution[t]+height[t].max() < limit[r]) {
00272           if (end[t].min() > low  &&
00273               start[t].max() <= up &&
00274               duration[t].min() > 0) {
00275             if (me_failed(machine[t].nq(home, r))) {
00276               return ES_FAILED;
00277             }
00278           } else if (machine[t].assigned()) {
00279             int dtmin = duration[t].min();
00280             if (dtmin > 0) {
00281               Iter::Ranges::Singleton
00282                 a(low-dtmin+1, up), b(low+1, up+dtmin);
00283               if (me_failed(start[t].minus_r(home,a,false)) ||
00284                   me_failed(end[t].minus_r(home, b,false))) {
00285                 return ES_FAILED;
00286               }
00287             }
00288             if (me_failed(duration[t].lq(home,
00289                                          std::max(std::max(low-start[t].min(),
00290                                                            end[t].max()-up-1),
00291                                                   0)))) {
00292               return ES_FAILED;
00293             }
00294           }
00295         }
00296       }
00297 
00298       // Algorithm 4.
00299       // Remove bad negative values from for-sure heights.
00300       /* \note "It is not sufficient to only test for assignment of machine[t]
00301        *         since Algorithm 3 can remove the value." Check this against
00302        *         the conditions for Alg3.
00303        */
00304       if (machine[t].assigned() &&
00305           machine[t].val() == r &&
00306           end[t].min() > low    &&
00307           start[t].max() <= up  &&
00308           duration[t].min() > 0 ) {
00309         if (me_failed(at_most
00310                       ? height[t].lq(home, limit[r]-sheight+contribution[t])
00311                       : height[t].gq(home, limit[r]-sheight+contribution[t]))) {
00312           return ES_FAILED;
00313         }
00314       }
00315 
00316       // Remove tasks that are no longer relevant.
00317       if ((!machine[t].in(r)) ||
00318           end[t].max() <= up+1) {
00319         prune_tasks[pti] = prune_tasks[--prune_tasks_size];
00320       } else {
00321         ++pti;
00322       }
00323     }
00324 
00325     return ES_OK;
00326   }
00327 
00328   namespace {
00329     template <class C>
00330     class LT {
00331     public:
00332       bool operator()(const C& lhs, const C& rhs) {
00333         return lhs < rhs;
00334       }
00335     };
00336   }
00337 
00338   template <class ViewM, class ViewD, class ViewH, class View>
00339   ExecStatus
00340   Val<ViewM,ViewD,ViewH,View>::propagate(Space* home, ModEventDelta) {
00341     // Check for subsumption
00342     bool subsumed = true;
00343     for (int t = start.size(); t--; )
00344       if (!(duration[t].assigned() && end[t].assigned()   &&
00345             machine[t].assigned()  && start[t].assigned() &&
00346             height[t].assigned())) {
00347         subsumed = false;
00348         break;
00349       }
00350     // Propagate information for machine r
00351     for (int r = limit.size(); r--; ) {
00352       // std::list<Event> events;
00353       GECODE_AUTOARRAY(Event, events, start.size()*8);
00354       int events_size = 0;
00355 #define GECODE_PUSH_EVENTS(E) assert(events_size<start.size()*8);\
00356       events[events_size++] = E;
00357 
00358       // Find events for sweep-line
00359       for (int t = start.size(); t--; ) {
00360         if (machine[t].assigned() &&
00361             machine[t].val() == r &&
00362             start[t].max() < end[t].min()) {
00363           if (at_most
00364               ? height[t].min() > std::min(0, limit[r])
00365               : height[t].max() < std::max(0, limit[r])) {
00366             GECODE_PUSH_EVENTS(Event(EVENT_CHCK, t, start[t].max(), 1));
00367             GECODE_PUSH_EVENTS(Event(EVENT_CHCK, t, end[t].min(), -1));
00368           }
00369           if (at_most
00370               ? height[t].min() > 0
00371               : height[t].max() < 0) {
00372             GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, start[t].max(),
00373                                    at_most ? height[t].min()
00374                                    : height[t].max(), true));
00375             GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, end[t].min(),
00376                                    at_most ? -height[t].min()
00377                                    : -height[t].max()));
00378           }
00379         }
00380         
00381         if (machine[t].in(r)) {
00382           if (at_most
00383               ? height[t].min() < 0
00384               : height[t].max() > 0) {
00385             GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, start[t].min(),
00386                                    at_most ? height[t].min()
00387                                    : height[t].max(), true));
00388             GECODE_PUSH_EVENTS(Event(EVENT_PROF, t, end[t].max(),
00389                                    at_most ? -height[t].min()
00390                                    : -height[t].max()));
00391           }
00392           if (!(machine[t].assigned() &&
00393                  height[t].assigned() &&
00394                   start[t].assigned() &&
00395                     end[t].assigned())) {
00396             GECODE_PUSH_EVENTS(Event(EVENT_PRUN, t, start[t].min()));
00397           }
00398         }
00399       }
00400 #undef GECODE_PUSH_EVENTS
00401       // If there are no events, continue with next machine
00402       if (events_size == 0)
00403         continue;
00404 
00405       // Sort the events according to date
00406       LT<Event> lt;
00407       Support::insertion(&events[0], events_size, lt);
00408 
00409       // Sweep line along d, starting at 0
00410       int d        = 0;
00411       int ntask    = 0;
00412       int sheight  = 0;
00413       int ei = 0;
00414 
00415       GECODE_AUTOARRAY(int, prune_tasks, start.size());
00416       int prune_tasks_size = 0;
00417       GECODE_AUTOARRAY(int, contribution, start.size());
00418       for (int i = start.size(); i--; ) contribution[i] = 0;
00419 
00420       d = events[ei].date;
00421       while (ei < events_size) {
00422         if (events[ei].e != EVENT_PRUN) {
00423           if (d != events[ei].date) {
00424             GECODE_ES_CHECK(prune(home, d, events[ei].date-1, r,
00425                                   ntask, sheight,
00426                                   contribution, prune_tasks, prune_tasks_size));
00427             d = events[ei].date;
00428           }
00429           if (events[ei].e == EVENT_CHCK) {
00430             ntask += events[ei].inc;
00431           } else /* if (it->e == EVENT_PROF) */ {
00432             sheight += events[ei].inc;
00433             if(events[ei].first_prof)
00434               contribution[events[ei].task] = at_most
00435                 ? std::max(contribution[events[ei].task], events[ei].inc)
00436                 : std::min(contribution[events[ei].task], events[ei].inc);
00437           }
00438         } else /* if (it->e == EVENT_PRUN) */ {
00439           assert(prune_tasks_size<start.size());
00440           prune_tasks[prune_tasks_size++] = events[ei].task;
00441         }
00442         ei++;
00443       }
00444 
00445       GECODE_ES_CHECK(prune(home, d, d, r,
00446                             ntask, sheight,
00447                             contribution, prune_tasks, prune_tasks_size));
00448     }
00449     return subsumed ? ES_SUBSUMED(this,home): ES_NOFIX;
00450   }
00451 
00452 }}}
00453 
00454 // STATISTICS: int-prop
00455