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

car-sequencing.cpp

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, 2009
00008  *
00009  *  Last modified:
00010  *     $Date: 2011-09-19 14:02:26 +0200 (Mon, 19 Sep 2011) $ by $Author: schulte $
00011  *     $Revision: 12400 $
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/driver.hh>
00039 #include <gecode/int.hh>
00040 #include <gecode/minimodel.hh>
00041 
00042 #include <iomanip>
00043 
00044 using namespace Gecode;
00045 
00046 // Problems
00047 namespace {
00048   // Problem data
00049   extern const int* problems[];
00050   // Number of problems
00051   extern const unsigned int n_problems;
00052 }
00053 
00054 namespace {
00060   class CarOptions : public SizeOptions {
00061   private:
00063     Driver::UnsignedIntOption _maxstall;
00064 
00065   public:
00067     CarOptions(const char* s)
00068       : SizeOptions(s),
00069         _maxstall("-maxstall", "Maximum numbere of stalls", 30)
00070     {
00071       // Add options
00072       add(_maxstall);
00073     }
00075     void parse(int& argc, char* argv[]) {
00076       SizeOptions::parse(argc,argv);
00077     }
00079     int maxstall(void) const { return _maxstall.value(); }
00080   };
00081 
00082 
00100   template <class View>
00101   class PushToEnd : public NaryOnePropagator<View,Int::PC_INT_BND> {
00102   protected:
00103     using NaryOnePropagator<View,Int::PC_INT_BND>::x;
00104     using NaryOnePropagator<View,Int::PC_INT_BND>::y;
00105     int val;
00106 
00108     PushToEnd(Space& home, bool share, PushToEnd& p);
00110     PushToEnd(Space& home, ViewArray<View>& x0, View y0, int val0);
00111   public:
00113     PushToEnd(Space& home, bool share, Propagator& p, 
00114               ViewArray<View>& x0, View y0, int val0);
00116     virtual Actor* copy(Space& home, bool share);
00118     virtual ExecStatus propagate(Space& home, const ModEventDelta& med);
00120     static  ExecStatus post(Space& home, 
00121                             ViewArray<View>& x0, View y0, int val0);
00122   };
00123 
00124   template <class View>
00125   inline
00126   PushToEnd<View>::PushToEnd(Space& home, 
00127                              ViewArray<View>& x0, View y0, int val0)
00128     : NaryOnePropagator<View,Int::PC_INT_BND>(home,x0,y0), val(val0) {}
00129 
00130   template <class View>
00131   ExecStatus
00132   PushToEnd<View>::post(Space& home, 
00133                         ViewArray<View>& x0, View y0, int val0) {
00134     (void) new (home) PushToEnd<View>(home,x0,y0,val0);
00135     return ES_OK;
00136   }
00137 
00138   template <class View>
00139   inline
00140   PushToEnd<View>::PushToEnd(Space& home, bool share, PushToEnd<View>& p)
00141     : NaryOnePropagator<View,Int::PC_INT_BND>(home,share,p), val(p.val) {}
00142 
00143   template <class View>
00144   inline
00145   PushToEnd<View>::PushToEnd(Space& home, bool share, Propagator& p,
00146                              ViewArray<View>& x0, View y0, int val0)
00147   : NaryOnePropagator<View,Int::PC_INT_BND>(home,share,p,x0,y0), val(val0) {}
00148 
00149   template <class View>
00150   Actor*
00151   PushToEnd<View>::copy(Space& home, bool share) {
00152     return new (home) PushToEnd<View>(home,share,*this);
00153   }
00154 
00155   template <class View>
00156   ExecStatus
00157   PushToEnd<View>::propagate(Space& home, const ModEventDelta&) {
00158     // Find number of required positions
00159     int min = 0;
00160     for (int i = x.size(); i-- && x[i].min() >= val-1; ) {
00161       ++min;
00162     }
00163     // Find number of possible positions
00164     int max = 0;
00165     {
00166       int i = x.size();
00167       while (i--) {
00168         if (x[i].max() != val) break;
00169         ++max;
00170         if (max >= y.max()) break;
00171       }
00172       // No variables later than max can have value val
00173       while (i--) {
00174         GECODE_ME_CHECK(x[i].le(home, val));
00175       }
00176     }
00177 
00178     // Constrain y to be in {min..max}
00179     GECODE_ME_CHECK(y.gq(home, min));
00180     GECODE_ME_CHECK(y.lq(home, max));
00181 
00182     // At least the y.min() last values have value val
00183     for (int i = 0, pos = x.size()-1; i < y.min(); ++i, --pos) {
00184       GECODE_ME_CHECK(x[pos].eq(home, val));
00185     }
00186     
00187     return y.assigned() ? home.ES_SUBSUMED(*this) : ES_FIX;
00188   }
00189 
00192   void pushtoend(Space& home, IntVarArgs x, IntVar y, int val) {
00193     ViewArray<Int::IntView> vx(home, x);
00194     Int::IntView vy(y);
00195     GECODE_ES_FAIL(PushToEnd<Int::IntView>::post(home, vx, vy, val));
00196   }
00197 
00198 }
00199 
00200 
00212 class CarSequencing : public Script {
00213 public:
00215   enum {
00216     SEARCH_BAB,    
00217     SEARCH_RESTART 
00218   };
00220   enum {
00221     BRANCH_INORDER,  
00222     BRANCH_MIDDLE  
00223   };
00225   enum {
00226     PROP_REGULAR,  
00227     PROP_CUSTOM    
00228   };
00229 protected:
00231   const int problem;
00233   const int ncars;
00235   const int noptions; 
00237   const int nclasses;
00239   const int maxstall;
00241   const int stallval;
00243   const int endval;
00245   IntVar nstall;
00247   IntVar nend;
00249   IntVarArray s;
00250 public:
00252   CarSequencing(const CarOptions& opt)
00253     : problem(opt.size()),
00254       ncars(problems[problem][0]), 
00255       noptions(problems[problem][1]), 
00256       nclasses(problems[problem][2]),
00257       maxstall(opt.maxstall()),
00258       stallval(nclasses),
00259       endval(nclasses+1),
00260       nstall(*this, 0, maxstall),
00261       nend(*this, 0, maxstall),
00262       s(*this, ncars+maxstall, 0, nclasses+1)
00263   {
00264     // Read problem
00265     const int* probit = problems[problem] + 3;
00266 
00267     // Sequence requirements for the options.
00268     IntArgs max(noptions), block(noptions);
00269     for (int i = 0; i < noptions; ++i ) {
00270       max[i] = *probit++;
00271     }
00272     for (int i = 0; i < noptions; ++i ) {
00273       block[i] = *probit++;
00274     }
00275     // Number of cars per class
00276     IntArgs ncc(nclasses);
00277     // What classes require an option
00278     IntSetArgs classes(noptions);
00279     int** cdata = new int*[noptions]; 
00280     for (int i = noptions; i--; ) cdata[i] = new int[nclasses];
00281     int* n = new int[noptions];
00282     for (int i = noptions; i--; ) n[i] = 0;
00283     // Read data
00284     for (int c = 0; c < nclasses; ++c) {
00285       *probit++;
00286       ncc[c] = *probit++;
00287       for (int o = 0; o < noptions; ++o) {
00288         if (*probit++) {
00289           cdata[o][n[o]++] = c;
00290         }
00291       }
00292     }
00293     // Transfer specification data to int-sets
00294     for (int o = noptions; o--; ) {
00295       classes[o] = IntSet(cdata[o], n[o]);
00296       delete [] cdata[o];
00297     }
00298     delete [] cdata;
00299     delete [] n;
00300 
00301     // Count the cars
00302     {
00303       IntSetArgs c(nclasses+2);
00304       for (int i = nclasses; i--; ) {
00305         c[i] = IntSet(ncc[i], ncc[i]);
00306       }
00307       c[stallval] = IntSet(0, maxstall);
00308       c[  endval] = IntSet(0, maxstall);
00309       count(*this, s, c);
00310     }
00311 
00312     // Count number of end and stalls
00313     count(*this, s, stallval, IRT_EQ, nstall);
00314     count(*this, s,   endval, IRT_EQ,   nend);
00315     rel(*this, nstall+nend == maxstall);
00316 
00317     // Make sure nothing is overloaded
00318     IntSet one(1, 1);
00319     for (int o = noptions; o--; ) {
00320       // sb[i] reflects if car s[i] has option o
00321       BoolVarArgs sb(s.size());
00322       for (int i = s.size(); i--; ) {
00323         BoolVar b(*this, 0, 1);
00324         dom(*this, s[i], classes[o], b);
00325         sb[i] = b;
00326       }
00327       sequence(*this, sb, one, block[o], 0, max[o]);
00328     }
00329 
00330     // End-markers located at end only
00331     switch (opt.propagation()) {
00332     case PROP_REGULAR: {
00333       IntArgs notend(nclasses), notstallend(nclasses+1);
00334       for (int i = nclasses; i--; ) {
00335         notend[i] = i;
00336         notstallend[i] = i;
00337       }
00338       notstallend[nclasses] = stallval;
00339       REG r = *REG(notend) + REG(notstallend) + *REG(endval);
00340       extensional(*this, s, r);
00341       for (int pos = s.size()-1, i = 0; i < maxstall; ++i, --pos) {
00342         rel(*this, (nend > i) >> (s[pos]==endval));
00343       }
00344     } break;
00345     case PROP_CUSTOM: {
00346       pushtoend(*this, s, nend, endval);
00347     } break;
00348     }
00349     
00350 
00351     // Branching
00352     switch (opt.branching()) {
00353     case BRANCH_INORDER:
00354       branch(*this, s, INT_VAR_NONE, INT_VAL_MIN);
00355       break;
00356     case BRANCH_MIDDLE: {
00357       IntVarArgs m(s.size());
00358       int mid = s.size() / 2;
00359       int pos = 0;
00360       m[pos++] = s[mid];
00361       for (int i = 1; i <= m.size()/2; ++i) {
00362         if (mid-i >= 0)
00363           m[pos++] = s[mid-i];
00364         if (mid+i < s.size())
00365           m[pos++] = s[mid+i];
00366       }
00367       assert(pos == m.size());
00368       branch(*this, m, INT_VAR_NONE, INT_VAL_MIN);
00369       break;
00370     }
00371     }
00372   }
00373         
00375   virtual void constrain(const Space& _best) {
00376     const CarSequencing& best = static_cast<const CarSequencing&>(_best);
00377     rel(*this, nstall, IRT_LE, best.nstall.val());
00378   }
00379 
00381   virtual void
00382   print(std::ostream& os) const {
00383     int width = nclasses > 9 ? 2 : 1;
00384     const char* space = nclasses > 9 ? " " : "";
00385     os << "Stall slots=" << nstall 
00386        << ", End slots=" << nend << std::endl;
00387     int i = 0;
00388     for (; i < s.size(); ++i) {
00389       if (s[i].assigned()) {
00390         int v = s[i].val();
00391         if (v == endval) break;
00392         if (v == stallval) os << space << "_ ";
00393         else               os << std::setw(width) << v << " ";
00394       } else {
00395         os << space << "? ";    
00396       }
00397       if ((i+1)%20 == 0) os << std::endl;
00398     }
00399     if (i%20)
00400       os << std::endl;
00401     os << std::endl;
00402   }
00403 
00405   CarSequencing(bool share, CarSequencing& cs)
00406     : Script(share,cs), 
00407       problem(cs.problem),
00408       ncars(cs.ncars),
00409       noptions(cs.noptions),
00410       nclasses(cs.nclasses),
00411       maxstall(cs.maxstall),
00412       stallval(cs.stallval),
00413       endval(cs.endval)
00414   {
00415     nstall.update(*this, share, cs.nstall);
00416     nend.update(*this, share, cs.nend);
00417     s.update(*this, share, cs.s);
00418   }
00420   virtual Space*
00421   copy(bool share) {
00422     return new CarSequencing(share,*this);
00423   }
00424 };
00425 
00429 int
00430 main(int argc, char* argv[]) {
00431   CarOptions opt("CarSequencing");
00432   opt.solutions(0);
00433   opt.size(0);
00434   opt.search(CarSequencing::SEARCH_BAB);
00435   opt.search(CarSequencing::SEARCH_BAB, "bab");
00436   opt.search(CarSequencing::SEARCH_RESTART, "restart");
00437   opt.branching(CarSequencing::BRANCH_INORDER);
00438   opt.branching(CarSequencing::BRANCH_INORDER,  "inorder");
00439   opt.branching(CarSequencing::BRANCH_MIDDLE, "middle");
00440   opt.propagation(CarSequencing::PROP_CUSTOM);
00441   opt.propagation(CarSequencing::PROP_REGULAR, "regular");
00442   opt.propagation(CarSequencing::PROP_CUSTOM,  "custom");
00443   opt.parse(argc,argv);
00444   if (opt.size() >= n_problems) {
00445     std::cerr << "Error: size must be between 0 and "
00446               << n_problems-1 << std::endl;
00447     return 1;
00448   }
00449 
00450   switch (opt.search()) {
00451   case CarSequencing::SEARCH_BAB:
00452     Script::run<CarSequencing,BAB,CarOptions>(opt); break;
00453   case CarSequencing::SEARCH_RESTART:
00454     Script::run<CarSequencing,Restart,CarOptions>(opt); break;
00455   }
00456   return 0;
00457 }
00458 
00459 
00460 namespace {
00462 
00464   const int p0[] = {
00465     10, 5, 6,
00466     1, 2, 1, 2, 1,
00467     2, 3, 3, 5, 5,
00468     0, 1, 1, 0, 1, 1, 0, 
00469     1, 1, 0, 0, 0, 1, 0, 
00470     2, 2, 0, 1, 0, 0, 1, 
00471     3, 2, 0, 1, 0, 1, 0, 
00472     4, 2, 1, 0, 1, 0, 0, 
00473     5, 2, 1, 1, 0, 0, 0
00474   };
00475 
00476   // ---------------------------------
00477   //  Problem 4/72  (Regin & Puget   // 1)
00478   // ---------------------------------
00479   const int p1[] = {
00480     100, 5, 22,
00481     1, 2, 1, 2, 1,
00482     2, 3, 3, 5, 5,
00483     0, 6, 1, 0, 0, 1, 0, 
00484     1, 10, 1, 1, 1, 0, 0, 
00485     2, 2, 1, 1, 0, 0, 1, 
00486     3, 2, 0, 1, 1, 0, 0, 
00487     4, 8, 0, 0, 0, 1, 0, 
00488     5, 15, 0, 1, 0, 0, 0, 
00489     6, 1, 0, 1, 1, 1, 0, 
00490     7, 5, 0, 0, 1, 1, 0, 
00491     8, 2, 1, 0, 1, 1, 0, 
00492     9, 3, 0, 0, 1, 0, 0, 
00493     10, 2, 1, 0, 1, 0, 0, 
00494     11, 1, 1, 1, 1, 0, 1, 
00495     12, 8, 0, 1, 0, 1, 0, 
00496     13, 3, 1, 0, 0, 1, 1, 
00497     14, 10, 1, 0, 0, 0, 0, 
00498     15, 4, 0, 1, 0, 0, 1, 
00499     16, 4, 0, 0, 0, 0, 1, 
00500     17, 2, 1, 0, 0, 0, 1, 
00501     18, 4, 1, 1, 0, 0, 0, 
00502     19, 6, 1, 1, 0, 1, 0, 
00503     20, 1, 1, 0, 1, 0, 1, 
00504     21, 1, 1, 1, 1, 1, 1, 
00505   };
00506 
00507   // --------------------------------
00508   //  Problem 6/76, (Regin & Puget   // 2)
00509   // --------------------------------
00510   const int p2[] = {
00511     100, 5, 22,
00512     1, 2, 1, 2, 1,
00513     2, 3, 3, 5, 5,
00514     0, 13, 1, 0, 0, 0, 0, 
00515     1, 8, 0, 0, 0, 1, 0, 
00516     2, 7, 0, 1, 0, 0, 0, 
00517     3, 1, 1, 0, 0, 1, 0, 
00518     4, 12, 0, 0, 1, 0, 0, 
00519     5, 5, 0, 1, 0, 1, 0, 
00520     6, 5, 0, 0, 1, 1, 0, 
00521     7, 6, 0, 1, 1, 0, 0, 
00522     8, 3, 1, 0, 0, 0, 1, 
00523     9, 12, 1, 1, 0, 0, 0, 
00524     10, 8, 1, 1, 0, 1, 0, 
00525     11, 2, 1, 0, 0, 1, 1, 
00526     12, 2, 1, 1, 1, 0, 0, 
00527     13, 1, 0, 1, 0, 1, 1, 
00528     14, 4, 1, 0, 1, 0, 0, 
00529     15, 4, 0, 1, 0, 0, 1, 
00530     16, 1, 1, 1, 0, 1, 1, 
00531     17, 2, 1, 0, 1, 1, 0, 
00532     18, 1, 0, 0, 0, 0, 1, 
00533     19, 1, 1, 1, 1, 1, 0, 
00534     20, 1, 1, 1, 0, 0, 1, 
00535     21, 1, 0, 1, 1, 1, 0, 
00536   };
00537 
00538   // ---------------------------------
00539   //  Problem 10/93, (Regin & Puget   // 3)
00540   // ---------------------------------
00541   const int p3[] = {
00542     100, 5, 25,
00543     1, 2, 1, 2, 1,
00544     2, 3, 3, 5, 5,
00545     0, 7, 1, 0, 0, 1, 0,
00546     1, 11, 1, 1, 0, 0, 0,
00547     2, 1, 0, 1, 1, 1, 1,
00548     3, 3, 1, 0, 1, 0, 0,
00549     4, 15, 0, 1, 0, 0, 0,
00550     5, 2, 1, 0, 1, 1, 0,
00551     6, 8, 0, 1, 0, 1, 0,
00552     7, 5, 0, 0, 1, 0, 0,
00553     8, 3, 0, 0, 0, 1, 0,
00554     9, 4, 0, 1, 1, 1, 0,
00555     10, 5, 1, 0, 0, 0, 0,
00556     11, 2, 1, 1, 1, 0, 1,
00557     12, 6, 0, 1, 1, 0, 0,
00558     13, 2, 0, 0, 1, 0, 1,
00559     14, 2, 0, 1, 0, 0, 1,
00560     15, 4, 1, 1, 1, 1, 0,
00561     16, 3, 1, 0, 0, 0, 1,
00562     17, 5, 1, 1, 0, 1, 0,
00563     18, 2, 1, 1, 1, 0, 0,
00564     19, 4, 1, 1, 0, 0, 1,
00565     20, 1, 1, 0, 0, 1, 1,
00566     21, 1, 1, 1, 0, 1, 1,
00567     22, 1, 0, 1, 0, 1, 1,
00568     23, 1, 0, 1, 1, 0, 1,
00569     24, 2, 0, 0, 0, 0, 1,
00570   };
00571 
00572   // --------------
00573   //  Problem 16/81,
00574   // --------------
00575   const int p4[] = {
00576     100, 5, 26,
00577     1, 2, 1, 2, 1,
00578     2, 3, 3, 5, 5,
00579     0, 10, 1, 0, 0, 0, 0,
00580     1, 2, 0, 0, 0, 0, 1,
00581     2, 8, 0, 1, 0, 1, 0,
00582     3, 8, 0, 0, 0, 1, 0,
00583     4, 6, 0, 1, 1, 0, 0,
00584     5, 11, 0, 1, 0, 0, 0,
00585     6, 3, 0, 0, 1, 0, 0,
00586     7, 2, 0, 0, 1, 1, 0,
00587     8, 7, 1, 1, 0, 0, 0,
00588     9, 2, 1, 0, 0, 1, 1,
00589     10, 4, 1, 0, 1, 0, 0,
00590     11, 7, 1, 0, 0, 1, 0,
00591     12, 1, 1, 1, 1, 0, 1,
00592     13, 3, 0, 1, 1, 1, 0,
00593     14, 4, 0, 1, 0, 0, 1,
00594     15, 5, 1, 1, 1, 0, 0,
00595     16, 2, 1, 1, 0, 0, 1,
00596     17, 1, 1, 0, 1, 1, 1,
00597     18, 2, 1, 0, 1, 1, 0,
00598     19, 3, 1, 0, 0, 0, 1,
00599     20, 2, 0, 1, 1, 0, 1,
00600     21, 1, 0, 1, 0, 1, 1,
00601     22, 3, 1, 1, 0, 1, 0,
00602     23, 1, 0, 0, 1, 1, 1,
00603     24, 1, 1, 1, 1, 1, 1,
00604     25, 1, 1, 1, 1, 1, 0,
00605   };
00606 
00607   // ----------------------------------
00608   //  Problem 19/71,  (Regin & Puget   // 4)
00609   // ----------------------------------
00610   const int p5[] = {
00611     100, 5, 23,
00612     1, 2, 1, 2, 1,
00613     2, 3, 3, 5, 5,
00614     0, 2, 0, 0, 0, 1, 1,
00615     1, 2, 0, 0, 1, 0, 1,
00616     2, 5, 0, 1, 1, 1, 0,
00617     3, 4, 0, 0, 0, 1, 0,
00618     4, 4, 0, 1, 0, 1, 0,
00619     5, 1, 1, 1, 0, 0, 1,
00620     6, 3, 1, 1, 1, 0, 1,
00621     7, 4, 0, 0, 1, 0, 0,
00622     8, 19, 0, 1, 0, 0, 0,
00623     9, 7, 1, 1, 0, 1, 0,
00624     10, 10, 1, 0, 0, 0, 0,
00625     11, 1, 0, 0, 1, 1, 0,
00626     12, 5, 1, 1, 1, 1, 0,
00627     13, 2, 1, 0, 1, 1, 0,
00628     14, 6, 1, 1, 0, 0, 0,
00629     15, 4, 1, 1, 1, 0, 0,
00630     16, 8, 1, 0, 0, 1, 0,
00631     17, 1, 1, 0, 0, 0, 1,
00632     18, 4, 0, 1, 1, 0, 0,
00633     19, 2, 0, 0, 0, 0, 1,
00634     20, 4, 0, 1, 0, 0, 1,
00635     21, 1, 1, 1, 0, 1, 1,
00636     22, 1, 0, 1, 1, 0, 1,
00637   };
00638 
00639   const int* problems[] = {
00640     &p0[0],
00641     &p1[0],
00642     &p2[0],
00643     &p3[0],
00644     &p4[0],
00645     &p5[0],
00646   };
00647 
00649   const unsigned int n_problems = sizeof(problems)/sizeof(int*);
00650 };
00651 
00652 // STATISTICS: example-any
00653