Generated on Thu Apr 11 13:58:53 2019 for Gecode by doxygen 1.6.3

sudoku-advanced.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  *     Guido Tack <tack@gecode.org>
00006  *     Christian Schulte <schulte@gecode.org>
00007  *
00008  *  Copyright:
00009  *     Mikael Lagerkvist, 2005
00010  *     Guido Tack, 2005
00011  *     Christian Schulte, 2005
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 #ifdef GECODE_HAS_SET_VARS
00043 #include <gecode/set.hh>
00044 #endif
00045 
00046 #include <string>
00047 #include <cmath>
00048 #include <cctype>
00049 
00050 using namespace Gecode;
00051 
00052 #include <examples/sudoku-instances.hh>
00053 
00055 class Sudoku : public Script {
00056 protected:
00058   const int n;
00059 public:
00060 #ifdef GECODE_HAS_SET_VARS
00061 
00062   enum {
00063     MODEL_INT,   
00064     MODEL_SET,   
00065     MODEL_MIXED  
00066   };
00067 #endif
00068   // Branching variants
00069   enum {
00070     BRANCH_NONE,        
00071     BRANCH_SIZE,        
00072     BRANCH_SIZE_DEGREE, 
00073     BRANCH_SIZE_AFC,    
00074     BRANCH_AFC          
00075   };
00076 
00078   Sudoku(const SizeOptions& opt)
00079     : Script(opt),
00080       n(example_size(examples[opt.size()])) {}
00081 
00083   Sudoku(Sudoku& s) : Script(s), n(s.n) {}
00084 
00085 };
00086 
00092 class SudokuInt : virtual public Sudoku {
00093 protected:
00095   IntVarArray x;
00096 public:
00097 #ifdef GECODE_HAS_SET_VARS
00098 
00099   enum {
00100     PROP_NONE, 
00101     PROP_SAME, 
00102   };
00103 #endif
00104 
00105   SudokuInt(const SizeOptions& opt)
00106     : Sudoku(opt), x(*this, n*n*n*n, 1, n*n) {
00107     const int nn = n*n;
00108     Matrix<IntVarArray> m(x, nn, nn);
00109 
00110     // Constraints for rows and columns
00111     for (int i=0; i<nn; i++) {
00112       distinct(*this, m.row(i), opt.ipl());
00113       distinct(*this, m.col(i), opt.ipl());
00114     }
00115 
00116     // Constraints for squares
00117     for (int i=0; i<nn; i+=n) {
00118       for (int j=0; j<nn; j+=n) {
00119         distinct(*this, m.slice(i, i+n, j, j+n), opt.ipl());
00120       }
00121     }
00122 
00123     // Fill-in predefined fields
00124     for (int i=0; i<nn; i++)
00125       for (int j=0; j<nn; j++)
00126         if (int v = sudokuField(examples[opt.size()], nn, i, j))
00127           rel(*this, m(i,j), IRT_EQ, v );
00128 
00129 #ifdef GECODE_HAS_SET_VARS
00130     if (opt.propagation() == PROP_SAME) {
00131       // Implied constraints linking squares and rows
00132       for (int b=0; b<n; b++) {
00133         int b1c = 0;
00134         int b2c = 0;
00135         IntVarArgs bc1(nn-n);
00136         IntVarArgs bc2(nn-n);
00137         IntVarArgs br1(nn-n);
00138         IntVarArgs br2(nn-n);
00139         for (int i=0; i<n; i++)
00140           for (int j=0; j<n; j++) {
00141             b1c = 0; b2c = 0;
00142             for (int k=0; k<n; k++) {
00143               if (k != j) {
00144                 IntVarArgs bc1s = block_col(m, b, i, k);
00145                 IntVarArgs br1s = block_row(m, b, i, k);
00146                 for (int count=0; count<n; count++) {
00147                   bc1[b1c] = bc1s[count];
00148                   br1[b1c] = br1s[count];
00149                   ++b1c;
00150                 }
00151               }
00152               if (k != i) {
00153                 IntVarArgs bc2s = block_col(m, b, k, j);
00154                 IntVarArgs br2s = block_row(m, b, k, j);
00155                 for (int count=0; count<n; count++) {
00156                   bc2[b2c] = bc2s[count];
00157                   br2[b2c] = br2s[count];
00158                   ++b2c;
00159                 }
00160               }
00161             }
00162             same(*this, nn, bc1, bc2);
00163             same(*this, nn, br1, br2);
00164           }
00165       }
00166     }
00167 #endif
00168     if (opt.branching() == BRANCH_NONE) {
00169       branch(*this, x, INT_VAR_NONE(), INT_VAL_SPLIT_MIN());
00170     } else if (opt.branching() == BRANCH_SIZE) {
00171       branch(*this, x, INT_VAR_SIZE_MIN(), INT_VAL_SPLIT_MIN());
00172     } else if (opt.branching() == BRANCH_SIZE_DEGREE) {
00173       branch(*this, x, INT_VAR_DEGREE_SIZE_MAX(), INT_VAL_SPLIT_MIN());
00174     } else if (opt.branching() == BRANCH_SIZE_AFC) {
00175       branch(*this, x, INT_VAR_AFC_SIZE_MAX(opt.decay()), INT_VAL_SPLIT_MIN());
00176     } else if (opt.branching() == BRANCH_AFC) {
00177       branch(*this, x, INT_VAR_AFC_MAX(opt.decay()), INT_VAL_SPLIT_MIN());
00178     }
00179   }
00180 
00182   SudokuInt(SudokuInt& s) : Sudoku(s) {
00183     x.update(*this, s.x);
00184   }
00185 
00187   virtual Space*
00188   copy(void) {
00189     return new SudokuInt(*this);
00190   }
00191 
00193   virtual void
00194   print(std::ostream& os) const {
00195     os << "  ";
00196     for (int i = 0; i<n*n*n*n; i++) {
00197       if (x[i].assigned()) {
00198         if (x[i].val()<10)
00199           os << x[i] << " ";
00200         else
00201           os << (char)(x[i].val()+'A'-10) << " ";
00202       }
00203       else
00204         os << ". ";
00205       if((i+1)%(n*n) == 0)
00206         os << std::endl << "  ";
00207     }
00208     os << std::endl;
00209   }
00210 
00211 #ifdef GECODE_HAS_SET_VARS
00212 private:
00214   void same(Space& home, int nn, IntVarArgs a, IntVarArgs b) {
00215     SetVar u(home, IntSet::empty, 1, nn);
00216     rel(home, SOT_DUNION, a, u);
00217     rel(home, SOT_DUNION, b, u);
00218   }
00219 
00221   IntVarArgs
00222   block_col(Matrix<IntVarArray> m, int bc, int i, int j) {
00223     return m.slice(bc*n+i, bc*n+i+1, j*n, (j+1)*n);
00224   }
00225 
00227   IntVarArgs
00228   block_row(Matrix<IntVarArray> m, int br, int i, int j) {
00229     return m.slice(j*n, (j+1)*n, br*n+i, br*n+i+1);
00230   }
00231 #endif
00232 };
00233 
00234 #ifdef GECODE_HAS_SET_VARS
00235 
00240 class SudokuSet : virtual public Sudoku {
00241 protected:
00243   SetVarArray y;
00244 public:
00246   SudokuSet(const SizeOptions& opt)
00247     : Sudoku(opt),
00248       y(*this,n*n,IntSet::empty,1,n*n*n*n,
00249         static_cast<unsigned int>(n*n),static_cast<unsigned int>(n*n)) {
00250 
00251     const int nn = n*n;
00252 
00253     Region r;
00254     IntSet* row = r.alloc<IntSet>(nn);
00255     IntSet* col = r.alloc<IntSet>(nn);
00256     IntSet* block = r.alloc<IntSet>(nn);
00257 
00258     // Set up the row and column set constants
00259     int* dsc = r.alloc<int>(nn);
00260     for (int i=0; i<nn; i++) {
00261       row[i] = IntSet((i*nn)+1, (i+1)*nn);
00262 
00263       for (int j=0; j<nn; j++) {
00264         dsc[j] = (j*nn)+1+i;
00265       }
00266       col[i] = IntSet(dsc, nn);
00267     }
00268 
00269     // Set up the block set constants
00270     int* dsb_arr = r.alloc<int>(nn);
00271     for (int i=0; i<n; i++) {
00272       for (int j=0; j<n; j++) {
00273 
00274         for (int ii=0; ii<n; ii++) {
00275           for (int jj=0; jj<n; jj++) {
00276             dsb_arr[ii*n+jj] = j*nn*n+i*n+jj*nn+ii+1;
00277           }
00278         }
00279         block[i*n+j] = IntSet(dsb_arr, nn);
00280       }
00281     }
00282 
00283     IntSet full(1, nn*nn);
00284     // All x must be pairwise disjoint and partition the field indices
00285     rel(*this, SOT_DUNION, y, SetVar(*this, full, full));
00286 
00287     // The x must intersect in exactly one element with each
00288     // row, column, and block
00289     for (int i=0; i<nn; i++)
00290       for (int j=0; j<nn; j++) {
00291         SetVar inter_row(*this, IntSet::empty, full, 1U, 1U);
00292         rel(*this, y[i], SOT_INTER, row[j], SRT_EQ, inter_row);
00293         SetVar inter_col(*this, IntSet::empty, full, 1U, 1U);
00294         rel(*this, y[i], SOT_INTER, col[j], SRT_EQ, inter_col);
00295         SetVar inter_block(*this, IntSet::empty, full, 1U, 1U);
00296         rel(*this, y[i], SOT_INTER, block[j], SRT_EQ, inter_block);
00297       }
00298 
00299     // Fill-in predefined fields
00300     for (int i=0; i<nn; i++)
00301       for (int j=0; j<nn; j++)
00302         if (int idx = sudokuField(examples[opt.size()], nn, i, j))
00303           dom(*this, y[idx-1], SRT_SUP, (i+1)+(j*nn) );
00304 
00305     if (opt.branching() == BRANCH_NONE) {
00306       branch(*this, y, SET_VAR_NONE(), SET_VAL_MIN_INC());
00307     } else if (opt.branching() == BRANCH_SIZE) {
00308       branch(*this, y, SET_VAR_SIZE_MIN(), SET_VAL_MIN_INC());
00309     } else if (opt.branching() == BRANCH_SIZE_DEGREE) {
00310       branch(*this, y, SET_VAR_DEGREE_SIZE_MAX(), SET_VAL_MIN_INC());
00311     } else if (opt.branching() == BRANCH_SIZE_AFC) {
00312       branch(*this, y, SET_VAR_AFC_SIZE_MAX(opt.decay()), SET_VAL_MIN_INC());
00313     } else if (opt.branching() == BRANCH_AFC) {
00314       branch(*this, y, SET_VAR_AFC_MAX(opt.decay()), SET_VAL_MIN_INC());
00315     }
00316   }
00317 
00319   SudokuSet(SudokuSet& s) : Sudoku(s) {
00320     y.update(*this, s.y);
00321   }
00322 
00324   virtual Space*
00325   copy(void) {
00326     return new SudokuSet(*this);
00327   }
00328 
00330   virtual void
00331   print(std::ostream& os) const {
00332     os << '\t';
00333     for (int i = 0; i<n*n*n*n; i++) {
00334       for (int j=0; j<n*n; j++) {
00335         if (y[j].contains(i+1)) {
00336           if (j+1<10)
00337             os << j+1 << " ";
00338           else
00339             os << (char)(j+1+'A'-10) << " ";
00340           break;
00341         }
00342       }
00343       if((i+1)%(n*n) == 0)
00344         os << std::endl << '\t';
00345     }
00346     os << std::endl;
00347   }
00348 };
00349 
00350 
00357 class SudokuMixed : public SudokuInt, public SudokuSet {
00358 public:
00360   SudokuMixed(const SizeOptions& opt)
00361   : Sudoku(opt), SudokuInt(opt), SudokuSet(opt) {
00362     const int nn = n*n;
00363 
00364     IntSet is0(0,0);
00365     SetVar dummySet0(*this, is0, is0);
00366     IntVar dummyInt0(*this, 0, 0);
00367     SetVarArgs ys(nn+1);
00368     ys[0] = dummySet0;
00369     for (int i=0; i<nn; i++)
00370       ys[i+1] = y[i];
00371     IntVarArgs xs(nn*nn+1);
00372     xs[0] = dummyInt0;
00373     for (int i=0; i<nn*nn; i++)
00374       xs[i+1] = x[i];
00375 
00376     channel(*this, xs, ys);
00377 
00378     IntArgs values(nn);
00379     for (int i=0; i<nn; i++)
00380       values[i] = i+1;
00381     count(*this, x, IntSet(nn,nn), values, IPL_DOM);
00382   }
00383 
00385   SudokuMixed(SudokuMixed& s)
00386   : Sudoku(s), SudokuInt(s), SudokuSet(s) {}
00387 
00389   virtual Space*
00390   copy(void) {
00391     return new SudokuMixed(*this);
00392   }
00393 
00395   virtual void print(std::ostream& os) const { SudokuInt::print(os); }
00396 
00397 };
00398 
00399 #endif
00400 
00404 int
00405 main(int argc, char* argv[]) {
00406   SizeOptions opt("Sudoku");
00407   opt.size(0);
00408   opt.ipl(IPL_DOM);
00409   opt.solutions(1);
00410 #ifdef GECODE_HAS_SET_VARS
00411   opt.model(Sudoku::MODEL_INT);
00412   opt.model(Sudoku::MODEL_INT, "int", "use integer constraints");
00413   opt.model(Sudoku::MODEL_SET, "set", "use set constraints");
00414   opt.model(Sudoku::MODEL_MIXED, "mixed",
00415             "use both integer and set constraints");
00416   opt.propagation(SudokuInt::PROP_NONE);
00417   opt.propagation(SudokuInt::PROP_NONE, "none", "no additional constraints");
00418   opt.propagation(SudokuInt::PROP_SAME, "same",
00419                   "additional \"same\" constraint for integer model");
00420 #endif
00421   opt.branching(Sudoku::BRANCH_SIZE_AFC);
00422   opt.branching(Sudoku::BRANCH_NONE, "none", "none");
00423   opt.branching(Sudoku::BRANCH_SIZE, "size", "min size");
00424   opt.branching(Sudoku::BRANCH_SIZE_DEGREE, "sizedeg", "min size over degree");
00425   opt.branching(Sudoku::BRANCH_SIZE_AFC, "sizeafc", "min size over afc");
00426   opt.branching(Sudoku::BRANCH_AFC, "afc", "maximum afc");
00427   opt.parse(argc,argv);
00428   if (opt.size() >= n_examples) {
00429     std::cerr << "Error: size must be between 0 and "
00430               << n_examples-1 << std::endl;
00431     return 1;
00432   }
00433 #ifdef GECODE_HAS_SET_VARS
00434   switch (opt.model()) {
00435   case Sudoku::MODEL_INT:
00436     Script::run<SudokuInt,DFS,SizeOptions>(opt);
00437     break;
00438   case Sudoku::MODEL_SET:
00439     Script::run<SudokuSet,DFS,SizeOptions>(opt);
00440     break;
00441   case Sudoku::MODEL_MIXED:
00442     Script::run<SudokuMixed,DFS,SizeOptions>(opt);
00443     break;
00444   }
00445 #else
00446   Script::run<SudokuInt,DFS,SizeOptions>(opt);
00447 #endif
00448   return 0;
00449 }
00450 
00451 // STATISTICS: example-any