Generated on Wed Nov 1 15:04:31 2006 for Gecode by doxygen 1.4.5

val.icc

Go to the documentation of this file.
00001 /*
00002  *  Main authors:
00003  *     Mikael Lagerkvist <lagerkvist@gecode.org>
00004  *
00005  *  Copyright:
00006  *     Mikael Lagerkvist, 2005
00007  *
00008  *  Last modified:
00009  *     $Date: 2006-08-04 16:03:26 +0200 (Fri, 04 Aug 2006) $ by $Author: schulte $
00010  *     $Revision: 3512 $
00011  *
00012  *  This file is part of Gecode, the generic constraint
00013  *  development environment:
00014  *     http://www.gecode.org
00015  *
00016  *  See the file "LICENSE" for information on usage and
00017  *  redistribution of this file, and for a
00018  *     DISCLAIMER OF ALL WARRANTIES.
00019  *
00020  */
00021 
00022 /* This is the propagation algorithm of the cumulatives constraint as presented in
00023    @inproceedings{DBLP:conf/cp/BeldiceanuC02,
00024      author    = {Nicolas Beldiceanu and Mats Carlsson},
00025      title     = {A New Multi-resource cumulatives Constraint with Negative Heights.},
00026      booktitle = {CP},
00027      year      = {2002},
00028      pages     = {63-79},
00029      ee        = {http://link.springer.de/link/service/series/0558/bibs/2470/24700063.htm},
00030      crossref  = {DBLP:conf/cp/2002},
00031      bibsource = {DBLP, http://dblp.uni-trier.de}
00032    }
00033    @proceedings{DBLP:conf/cp/2002,
00034      editor    = {Pascal Van Hentenryck},
00035      title     = {Principles and Practice of Constraint Programming - CP 2002,
00036                   8th International Conference, CP 2002,
00037                   Ithaca, NY, USA, September 9-13, 2002, Proceedings},
00038      booktitle = {CP},
00039      publisher = {Springer},
00040      series    = {Lecture Notes in Computer Science},
00041      volume    = {2470},
00042      year      = {2002},
00043      isbn      = {3-540-44120-4},
00044      bibsource = {DBLP, http://dblp.uni-trier.de}
00045    }
00046 
00047  */
00048 
00049 #include <vector>
00050 #include <list>
00051 #include <algorithm>
00052 
00053 
00054 namespace Gecode { namespace Int { namespace Cumulatives {
00055 
00056   template <class ViewM, class ViewD, class ViewH, class View>
00057   forceinline
00058   Val<ViewM,ViewD,ViewH,View>::Val(Space* home, const ViewArray<ViewM>& _machine,
00059                                    const ViewArray<View>& _start,
00060                                    const ViewArray<ViewD>& _duration,
00061                                    const ViewArray<View>& _end,
00062                                    const ViewArray<ViewH>& _height,
00063                                    const IntArgs& _limit,
00064                                    bool _at_most) :
00065     Propagator(home,true),
00066     machine(_machine), start(_start), duration(_duration),
00067     end(_end), height(_height), limit(_limit.size()), at_most(_at_most) {
00068     for(int i = _limit.size(); i--; ) {
00069       limit[i] = _limit[i];
00070     }
00071 
00072     machine.subscribe(home,this,PC_INT_DOM);
00073     start.subscribe(home,this,PC_INT_BND);
00074     duration.subscribe(home,this,PC_INT_BND);
00075     end.subscribe(home,this,PC_INT_BND);
00076     height.subscribe(home,this,PC_INT_BND);
00077   }
00078 
00079   template <class ViewM, class ViewD, class ViewH, class View>
00080   ExecStatus
00081   Val<ViewM,ViewD,ViewH,View>
00082   ::post(Space* home, const ViewArray<ViewM>& machine,
00083          const ViewArray<View>& start, const ViewArray<ViewD>& duration,
00084          const ViewArray<View>& end, const ViewArray<ViewH>& height,
00085          const IntArgs& limit, bool at_most) {
00086     (void) new (home) Val(home, machine, start, duration,
00087                           end, height, limit, at_most);
00088 
00089     return ES_OK;
00090   }
00091 
00092   template <class ViewM, class ViewD, class ViewH, class View>
00093   forceinline
00094   Val<ViewM,ViewD,ViewH,View>::Val(Space* home, bool share,
00095                                    Val<ViewM,ViewD,ViewH,View>& p)
00096     : Propagator(home,share,p), at_most(p.at_most) {
00097     machine.update(home,share,p.machine);
00098     start.update(home, share, p.start);
00099     duration.update(home, share, p.duration);
00100     end.update(home, share, p.end);
00101     height.update(home, share, p.height);
00102     limit.update(share, p.limit);
00103   }
00104 
00105   template <class ViewM, class ViewD, class ViewH, class View>
00106   size_t
00107   Val<ViewM,ViewD,ViewH,View>::dispose(Space* home) {
00108     if (!home->failed()) {
00109       machine.cancel(home,this,PC_INT_DOM);
00110       start.cancel(home,this,PC_INT_BND);
00111       duration.cancel(home,this,PC_INT_BND);
00112       end.cancel(home,this,PC_INT_BND);
00113       height.cancel(home,this,PC_INT_BND);
00114     }
00115     limit.~SharedArray();
00116     (void) Propagator::dispose(home);
00117     return sizeof(*this);
00118   }
00119 
00120   template <class ViewM, class ViewD, class ViewH, class View>
00121   PropCost
00122   Val<ViewM,ViewD,ViewH,View>::cost(void) const {
00123     return cost_hi(start.size(), PC_QUADRATIC_LO);
00124   }
00125 
00126   template <class ViewM, class ViewD, class ViewH, class View>
00127   Actor*
00128   Val<ViewM,ViewD,ViewH,View>::copy(Space* home, bool share) {
00129     return new (home) Val<ViewM,ViewD,ViewH,View>(home,share,*this);
00130   }
00131 
00133   typedef enum {EVENT_CHCK, EVENT_PROF, EVENT_PRUN} ev_t;
00135   class Event
00136   {
00137   public:
00139     ev_t e;
00141     int task;
00143     int date;
00145     int inc;
00150     bool first_prof;
00151 
00153     Event(ev_t _e, int _task, int _date, int _inc = 0, bool _first_prof = false)
00154       : e(_e), task(_task), date(_date), inc(_inc), first_prof(_first_prof)
00155     {}
00156 
00158     bool operator<(const Event& e) {
00159       return date < e.date;
00160     }
00161   };
00162 
00163 
00164   template <class ViewM, class ViewD, class ViewH, class View>
00165   ExecStatus
00166   Val<ViewM,ViewD,ViewH,View>::prune(Space * home, int low, int up, int r,
00167                    int ntask, int sheight,
00168                    const std::vector<int>& contribution,
00169                    std::list<int>& prune_tasks) {
00170 
00171     if (ntask > 0 &&
00172         (at_most ? sheight > limit[r]
00173          : sheight < limit[r])) {
00174       return ES_FAILED;
00175     }
00176 
00177     std::list<int>::iterator it = prune_tasks.begin();
00178     while (it != prune_tasks.end()) {
00179       int t = *it;
00180       // Algorithm 2.
00181       // Prune the machine, start, and end for required
00182       // tasks for machine r that have heights possibly greater than 0.
00183       if (ntask != 0 &&
00184           (at_most ? height[t].min() < 0
00185            : height[t].max() > 0) &&
00186           (at_most ? sheight-contribution[t] > limit[r]
00187            : sheight-contribution[t] < limit[r])) {
00188         if (me_failed(machine[t].eq(home, r))||
00189             me_failed(start[t].gq(home, up-duration[t].max()+1))||
00190             me_failed(start[t].lq(home, low))||
00191             me_failed(end[t].lq(home,low+duration[t].max()))||
00192             me_failed(end[t].gq(home, up+1))||
00193             me_failed(duration[t].gq(home,std::min(up-start[t].max()+1,
00194                                                    end[t].min()-low)))
00195             )
00196           return ES_FAILED;
00197       }
00198 
00199       // Algorithm 3.
00200       // Remove values that prevent us from reaching the limit
00201       if (at_most ? height[t].min() < std::min(0, limit[r])
00202           : height[t].max() < std::max(0, limit[r])) {
00203         if (at_most ? sheight-contribution[t]+height[t].min() > limit[r]
00204             : sheight-contribution[t]+height[t].max() < limit[r]) {
00205           if (end[t].min() > low  &&
00206               start[t].max() <= up &&
00207               duration[t].min() > 0) {
00208             if (me_failed(machine[t].nq(home, r)))
00209               return ES_FAILED;
00210           } else if (machine[t].assigned()) {
00211             int dtmin = duration[t].min();
00212             if (dtmin > 0) {
00213               Iter::Ranges::Singleton
00214                 a(low-dtmin+1, up), b(low+1, up+dtmin);
00215               if (me_failed(start[t].minus(home,a)) ||
00216                   me_failed(end[t].minus(home, b)))
00217                 return ES_FAILED;
00218             }
00219             if (me_failed(duration[t].lq(home,
00220                                          std::max(std::max(low-start[t].min(),
00221                                                            end[t].max()-up-1),
00222                                                   0))))
00223               return ES_FAILED;
00224           }
00225         }
00226       }
00227 
00228       // Algorithm 4.
00229       // Remove bad negative values from for-sure heights.
00230       /* \note "It is not sufficient to only test for assignment of machine[t]
00231        *         since Algorithm 3 can remove the value." Check this against
00232        *         the conditions for Alg3.
00233        */
00234       if (machine[t].assigned() &&
00235           machine[t].val() == r &&
00236           end[t].min() > low    &&
00237           start[t].max() <= up  &&
00238           duration[t].min() > 0 ) {
00239         if (me_failed(at_most
00240                       ? height[t].lq(home, limit[r]-sheight+contribution[t])
00241                       : height[t].gq(home, limit[r]-sheight+contribution[t])))
00242           return ES_FAILED;
00243       }
00244 
00245       // Remove tasks that are no longer relevant.
00246       /* @todo check condition more thouroughly - is
00247        *        \f$max(end_r)\geq up+1\f$  CORRECT?
00248        */
00249       if ((!machine[t].in(r)) ||
00250           end[t].max() <= up+1) {
00251         // @todo more than one *it (probably not) ? ==> remove(*it)
00252         std::list<int>::iterator old = it++;
00253         prune_tasks.erase(old);
00254       } else {
00255         ++it;
00256       }
00257     }
00258 
00259     return ES_OK;
00260   }
00261 
00262   template <class ViewM, class ViewD, class ViewH, class View>
00263   ExecStatus
00264   Val<ViewM,ViewD,ViewH,View>::propagate(Space* home) {
00265     ExecStatus res = ES_NOFIX;
00266     // Check for subsumption
00267     bool nnft = true; // no non-fixed tasks.
00268     for (int t = start.size(); t--; )
00269       if(!(duration[t].assigned() && end[t].assigned()   &&
00270            machine[t].assigned()  && start[t].assigned() &&
00271            height[t].assigned())) {
00272         nnft = false;
00273         break;
00274       }
00275     if(nnft) res = ES_SUBSUMED;
00276 
00277 
00278     // Propagate information for machine r
00279     for (int r = limit.size(); r--; ) {
00280       std::list<Event> events;
00281 
00282       // Find events for sweep-line
00283       for (int t = start.size(); t--; ) {
00284         if (machine[t].assigned() &&
00285             machine[t].val() == r &&
00286             start[t].max() < end[t].min()) {
00287           if (at_most
00288               ? height[t].min() > std::min(0, limit[r])
00289               : height[t].max() < std::max(0, limit[r])) {
00290             events.push_back(Event(EVENT_CHCK, t, start[t].max(), 1));
00291             events.push_back(Event(EVENT_CHCK, t, end[t].min(), -1));
00292           }
00293           if (at_most
00294               ? height[t].min() > 0
00295               : height[t].max() < 0) {
00296             events.push_back(Event(EVENT_PROF, t, start[t].max(),
00297                                    at_most ? height[t].min()
00298                                    : height[t].max(), true));
00299             events.push_back(Event(EVENT_PROF, t, end[t].min(),
00300                                    at_most ? -height[t].min()
00301                                    : -height[t].max()));
00302           }
00303         }
00304         
00305         if (machine[t].in(r)) {
00306           if (at_most
00307               ? height[t].min() < 0
00308               : height[t].max() > 0) {
00309             events.push_back(Event(EVENT_PROF, t, start[t].min(),
00310                                    at_most ? height[t].min()
00311                                    : height[t].max(), true));
00312             events.push_back(Event(EVENT_PROF, t, end[t].max(),
00313                                    at_most ? -height[t].min()
00314                                    : -height[t].max()));
00315           }
00316           if (!(machine[t].assigned() &&
00317                  height[t].assigned() &&
00318                   start[t].assigned() &&
00319                     end[t].assigned())) {
00320             events.push_back(Event(EVENT_PRUN, t, start[t].min()));
00321           }
00322         }
00323       }
00324 
00325       // If there are no events, continue with next machine
00326       if (events.size() == 0)
00327         continue;
00328 
00329       // Sort the events according to date
00330       events.sort();
00331 
00332       // Sweep line along d, starting at 0
00333       int d        = 0;
00334       int ntask    = 0;
00335       int sheight  = 0;
00336       std::list<Event>::iterator it = events.begin();
00337       std::list<int> prune_tasks;
00338       std::vector<int> contribution(start.size(), at_most
00339                                     ? Limits::Int::int_max
00340                                     : Limits::Int::int_min);
00341 
00342       d = it->date;
00343       while (it != events.end()) {
00344         if (it->e != EVENT_PRUN) {
00345           if (d != it->date) {
00346             GECODE_ES_CHECK(prune(home, d, it->date-1, r,
00347                                   ntask, sheight,
00348                                   contribution, prune_tasks));
00349             d = it->date;
00350           }
00351           if (it->e == EVENT_CHCK) {
00352             ntask += it->inc;
00353           } else /* if (it->e == EVENT_PROF) */ {
00354             sheight += it->inc;
00355             if(it->first_prof)
00356               contribution[it->task] = at_most
00357                 ? std::min(contribution[it->task], it->inc)
00358                 : std::max(contribution[it->task], it->inc);
00359           }
00360         } else /* if (it->e == EVENT_PRUN) */ {
00361           prune_tasks.push_back(it->task);
00362         }
00363         ++it;
00364       }
00365 
00366       GECODE_ES_CHECK(prune(home, d, d, r,
00367                             ntask, sheight,
00368                             contribution, prune_tasks));
00369     }
00370 
00371     return res;
00372   }
00373 
00374 }}}
00375 
00376 // STATISTICS: int-prop
00377