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

black-hole.cc

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, 2006
00008  *
00009  *  Last modified:
00010  *     $Date: 2008-02-05 10:52:04 +0100 (Tue, 05 Feb 2008) $ by $Author: schulte $
00011  *     $Revision: 6052 $
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 "examples/support.hh"
00039 
00040 #include "gecode/minimodel.hh"
00041 
00042 #include <vector>
00043 #include <algorithm>
00044 #include <sstream>
00045 
00046 namespace {
00047   using std::vector;
00048 
00050   vector<vector<int> > layout;
00052   vector<int> layer, pile;
00053 
00060   void generate(int seed) {
00061     // The layout consists of 17 piles of 3 cards each
00062     layout = vector<vector<int> >(17, vector<int>(3));
00063     // Deck without the Ace of Spades
00064     vector<int> deck(51);
00065     for (int i = 51; i--; ) deck[i] = i+1;
00066     Support::RandomGenerator rnd(seed+1);
00067     std::random_shuffle(deck.begin(), deck.end(), rnd);
00068 
00069     // Place cards from deck
00070     int pos = 0;
00071     for (int i = 17; i--; )
00072       for (int j = 3; j--; )
00073         layout[i][j] = deck[pos++];
00074 
00075     // Location-information for each card
00076     layer = vector<int>(52);
00077     pile  = vector<int>(52);
00078     for (int i = 17; i--; ) {
00079       for (int j = 3; j--; ) {
00080         layer[layout[i][j]] = j;
00081         pile[ layout[i][j]] = i;
00082       }
00083     }
00084   }
00085 }
00086 
00087 
00096 class BlackHoleBranch : Branching {
00098   ViewArray<Int::IntView> x;
00100   mutable int pos, val;
00101  
00103   BlackHoleBranch(Space* home, ViewArray<Int::IntView>& xv) 
00104     : Branching(home), x(xv), pos(-1), val(-1) {}
00106   BlackHoleBranch(Space* home, bool share, BlackHoleBranch& b) 
00107     : Branching(home, share, b), pos(b.pos), val(b.val) {
00108     x.update(home, share, b.x);
00109   }
00110   
00111 public:
00113   virtual bool status(const Space*) const {
00114     for (pos = 0; pos < x.size(); ++pos) {
00115       if (!x[pos].assigned()) {
00116         int w = 4;
00117         for (Int::ViewValues<Int::IntView> vals(x[pos]); vals(); ++vals) {
00118           if (layer[vals.val()] < w) {
00119             val = vals.val();
00120             if ((w = layer[vals.val()]) == 0) break;
00121           }
00122         }
00123         return true;
00124       }
00125     }
00126     // No non-assigned variables left
00127     return false;
00128   }
00130   virtual BranchingDesc* description(const Space*) const {
00131     assert(pos >= 0 && pos < x.size() && val >= 1 && val < 52);
00132     return new PosValDesc<int,2>(this, pos, val);
00133   }
00135   virtual ExecStatus commit(Space* home, const BranchingDesc* d, 
00136                             unsigned int a) {
00137     const PosValDesc<int,2> *desc = static_cast<const PosValDesc<int,2>*>(d);
00138     pos = val = -1;
00139     if (a)
00140       return me_failed(x[desc->pos()].nq(home, desc->val())) 
00141         ? ES_FAILED : ES_OK;
00142     else 
00143       return me_failed(x[desc->pos()].eq(home, desc->val())) 
00144         ? ES_FAILED : ES_OK;
00145   }
00147   virtual Actor* copy(Space *home, bool share) {
00148     return new (home) BlackHoleBranch(home, share, *this);
00149   }
00151   virtual const char* name(void) const {
00152     return "BlackHoleBranch";
00153   }
00155   static void post(Space* home, IntVarArgs x) {
00156     ViewArray<Int::IntView> xv(home, x);
00157     (void) new (home) BlackHoleBranch(home, xv);
00158   }
00159 };
00160 
00161 
00178 class BlackHole : public Example {
00179 protected:
00180   IntVarArray x, 
00181     y; 
00182 
00184   std::string
00185   card(int val) {
00186     const char* suit = "SCHD";
00187     std::ostringstream o;
00188     o << std::setw(2) << (1 + (val%13)) << suit[val/13];
00189     return o.str();
00190   }
00191 
00192 public:
00194   enum {
00195     MODEL_NONE,    
00196     MODEL_SYMMETRY 
00197   };
00199   enum {
00200     PROPAGATION_REIFIED,  
00201     PROPAGATION_DFA,      
00202     PROPAGATION_TUPLE_SET 
00203   };
00205   BlackHole(const SizeOptions& opt) 
00206     : x(this, 52, 0,51), y(this, 52, 0,51) 
00207   {
00208     // Black ace at bottom
00209     rel(this, x[0], IRT_EQ, 0);
00210 
00211     // x is order and y is placement
00212     channel(this, x, y, opt.icl());
00213 
00214     // The placement rules: the absolute value of the difference
00215     // between two consecutive cards is 1 or 12.
00216     if (opt.propagation() == PROPAGATION_REIFIED) {
00217       // Build table for accessing the rank of a card
00218       IntArgs modtable(52);
00219       for (int i = 0; i < 52; ++i) {
00220         modtable[i] = i%13;
00221       }
00222       for (int i = 0; i < 51; ++i) {
00223         IntVar x1(this, 0, 12), x2(this, 0, 12);
00224         element(this, modtable, x[i], x1);
00225         element(this, modtable, x[i+1], x2);
00226         const int dr[2] = {1, 12};
00227         IntVar diff(this, IntSet(dr, 2));
00228         post(this, abs(this, minus(this, x1, x2, ICL_DOM), ICL_DOM) 
00229              == diff, ICL_DOM);
00230       }
00231     } else if (opt.propagation() == PROPAGATION_DFA) {
00232       // Build table for allowed tuples
00233       REG expression;
00234       for (int r = 13; r--; ) {
00235         for (int s1 = 4; s1--; ) {
00236           for (int s2 = 4; s2--; ) {
00237             for (int i = -1; i <= 1; i+=2) {
00238               REG r1 = REG(r+13*s1);
00239               REG r2 = REG((r+i+52+13*s2)%52);
00240               REG r = r1 + r2;
00241               expression |= r;
00242             }
00243           }
00244         }
00245       }
00246       DFA table(expression);
00247 
00248       for (int i = 51; i--; ) {
00249         IntVarArgs iva(2);
00250         iva[0] = x[i]; iva[1] = x[i+1];
00251         extensional(this, iva, table);
00252       }
00253 
00254     } else { // opt.propagation() == PROPAGATION_TUPLE_SET)
00255       // Build table for allowed tuples
00256       TupleSet tupleSet;
00257       for (int r = 13; r--; ) {
00258         for (int s1 = 4; s1--; ) {
00259           for (int s2 = 4; s2--; ) {
00260             for (int i = -1; i <= 1; i+=2) {
00261               IntArgs t(2);
00262               t[0] = r+13*s1;
00263               t[1] = (r+i+52+13*s2)%52;
00264               tupleSet.add(t);
00265             }
00266           }
00267         }
00268       }
00269 
00270       for (int i = 51; i--; ) {
00271         IntVarArgs iva(2);
00272         iva[0] = x[i]; iva[1] = x[i+1];
00273         extensional(this, iva, tupleSet, ICL_DOM, opt.pk());
00274       }
00275     }
00276     // A card must be played before the one under it.
00277     for (int i = 17; i--; )
00278       for (int j = 2; j--; )
00279         post(this, y[layout[i][j]] < y[layout[i][j+1]]);
00280 
00281     // Compute and break the conditional symmetries that are dependent
00282     // on the current layout.
00283     if (opt.model() == MODEL_SYMMETRY) {
00284       // For all ranks
00285       for (int r = 13; r--; ) {
00286         // For all pairs of suits
00287         for (int s1 = 4; s1--; ) {
00288           for (int s2 = s1; s2--; ) {
00289             int c1 = 13*s1 + r,
00290               c2 = 13*s2 + r;
00291             // The ace of spades is already placed
00292             if (c1 == 0 || c2 == 0) continue;
00293             // Piles are handled by the rules of the game
00294             if (pile[c1] == pile[c2]) continue;
00295             // Get the right order of the cards
00296             int o1 = c1, o2 = c2;
00297             if (pile[c1] > pile[c2] && layer[c2] >= layer[c1]) 
00298               std::swap(o1, o2);
00299             // cond is the condition for the symmetry
00300             BoolVarArgs ba(4);
00301             int pos = 0;
00302             // Both cards played after the ones on top of them
00303             for (int i = 0; i < layer[o1]; ++i)
00304               ba[pos++] = post(this, ~(y[layout[pile[o1]][i]] < y[o2]));
00305             for (int i = 0; i < layer[o2]; ++i)
00306               ba[pos++] = post(this, ~(y[layout[pile[o2]][i]] < y[o1]));
00307             // Both cards played before the ones under them
00308             for (int i = layer[o1]+1; i < 3; ++i)
00309               ba[pos++] = post(this, ~(y[o2] < y[layout[pile[o1]][i]]));
00310             for (int i = layer[o2]+1; i < 3; ++i)
00311               ba[pos++] = post(this, ~(y[o1] < y[layout[pile[o2]][i]]));
00312             // Cond holds when all the above holds
00313             BoolVar cond(this, 0, 1);
00314             rel(this, BOT_AND, ba, cond);
00315             
00316             // If cond is fulfilled, then we can order the cards
00317             // cond -> (y[o1] < y[o2])
00318             post(this, tt(!cond || ~(y[o1] < y[o2])));
00319           }
00320         }
00321       }
00322     }
00323     
00324     // Install custom branching
00325     BlackHoleBranch::post(this, x);      
00326   }
00327 
00329   virtual void
00330   print(std::ostream& os) {
00331     os << "Layout:" << std::endl;
00332     for (int i = 0; i < 17; i++) {
00333       for (int j = 0; j < 3; j++)
00334         os << card(layout[i][j]) << " ";
00335       if ((i+1) % 3 == 0) 
00336         os << std::endl;
00337       else
00338         os << "\t";
00339     }
00340     os << std::endl << std::endl;
00341     
00342     os << "Solution:" << std::endl;
00343     for (int i = 0; i < 52; ++i) {
00344       os << card(x[i].min()) << " ";
00345       if ((i + 1) % 13 == 0)
00346         os << std::endl;
00347     }
00348     os << std::endl;
00349     os << std::endl;
00350   }
00351 
00353   BlackHole(bool share, BlackHole& s) : Example(share,s) {
00354     x.update(this, share, s.x);
00355     y.update(this, share, s.y);
00356   }
00358   virtual Space*
00359   copy(bool share) {
00360     return new BlackHole(share,*this);
00361   }
00362 };
00363 
00367 int
00368 main(int argc, char* argv[]) {
00369   SizeOptions opt("Black Hole patience");
00370   opt.model(BlackHole::MODEL_SYMMETRY);
00371   opt.model(BlackHole::MODEL_NONE,"none");
00372   opt.model(BlackHole::MODEL_SYMMETRY,"symmetry");
00373   opt.propagation(BlackHole::PROPAGATION_DFA);
00374   opt.propagation(BlackHole::PROPAGATION_REIFIED,
00375                   "reified", "use reified propagation");
00376   opt.propagation(BlackHole::PROPAGATION_DFA,
00377                   "dfa", "use DFA-based extensional propagation");
00378   opt.propagation(BlackHole::PROPAGATION_TUPLE_SET,
00379                   "tuple-set", "use TupleSet-based extensional propagation");
00380   opt.icl(ICL_DOM);
00381   opt.pk(PK_SPEED);
00382   opt.parse(argc,argv);
00383   // Generates the new board
00384   generate(opt.size());
00385   Example::run<BlackHole,DFS,SizeOptions>(opt);
00386   return 0;
00387 }
00388 
00389 // STATISTICS: example-any