slitherlink2formula.cpp
Go to the documentation of this file.
00001 
00010 #include <stdlib.h>
00011 
00012 #include "../libcnf/libcnf.h"
00013 #include "slitherlink.h"
00014 
00015 
00016 
00017 #define HORIZONTAL 0
00018 #define VERTICAL 1
00019 #define HORIZONTAL_EDGE_INDEX 2
00020 #define   VERTICAL_EDGE_INDEX 3
00021 #define HORIZONTAL_EDGE_SENSE 4
00022 #define   VERTICAL_EDGE_SENSE 5
00023 
00024 #define NUMBERING 2
00025 #define SENSE 4
00026 
00027 
00032 struct coord
00033 {
00037         int orientation;
00038         unsigned int x;
00039         unsigned int y;
00040 };
00041 
00042 
00043 
00044 // ===================================================================
00045 // ================================================= Continuity axioms
00046 // ===================================================================
00047 
00048 
00049 
00058 void getHneighbours(Slitherlink * sl,
00059                     unsigned int i, unsigned int j,
00060                     std::vector<coord> * neighbours1,
00061                     std::vector<coord> * neighbours2 )
00062 {
00063         neighbours1->clear();
00064         neighbours2->clear();
00065         if (i > 0) {
00066                 coord c;
00067                 c.orientation = VERTICAL;
00068                 c.x = i-1; c.y = j+1;
00069                 neighbours1->push_back(c);
00070         } // 1
00071         if (j < sl->getWidth()-1) {
00072                 coord c;
00073                 c.orientation = HORIZONTAL;
00074                 c.x = i; c.y = j+1;
00075                 neighbours1->push_back(c);
00076         } // 2
00077         if (i < sl->getHeight()) {
00078                 coord c;
00079                 c.orientation = VERTICAL;
00080                 c.x = i; c.y = j+1;
00081                 neighbours1->push_back(c);
00082         } // 3
00083         if (i < sl->getHeight()) {
00084                 coord c;
00085                 c.orientation = VERTICAL;
00086                 c.x = i; c.y = j;
00087                 neighbours2->push_back(c);
00088         } // 4
00089         if (j > 0) {
00090                 coord c;
00091                 c.orientation = HORIZONTAL;
00092                 c.x = i; c.y = j-1;
00093                 neighbours2->push_back(c);
00094         } // 5
00095         if (i > 0) {
00096                 coord c;
00097                 c.orientation = VERTICAL;
00098                 c.x = i-1; c.y = j;
00099                 neighbours2->push_back(c);
00100         } // 6
00101 }
00102 
00103 
00112 void getVneighbours(Slitherlink * sl,
00113                     unsigned int i, unsigned int j,
00114                     std::vector<coord> * neighbours1,
00115                     std::vector<coord> * neighbours2 )
00116 {
00117         neighbours1->clear();
00118         neighbours2->clear();
00119         if (j > 0) {
00120                 coord c;
00121                 c.orientation = HORIZONTAL;
00122                 c.x = i; c.y = j-1;
00123                 neighbours1->push_back(c);
00124         } // 1
00125         if (i > 0) {
00126                 coord c;
00127                 c.orientation = VERTICAL;
00128                 c.x = i-1; c.y = j;
00129                 neighbours1->push_back(c);
00130         } // 2
00131         if (j < sl->getWidth()) {
00132                 coord c;
00133                 c.orientation = HORIZONTAL;
00134                 c.x = i; c.y = j;
00135                 neighbours1->push_back(c);
00136         } // 3
00137         if ((i < sl->getHeight()) && (j < sl->getWidth())) {
00138                 coord c;
00139                 c.orientation = HORIZONTAL;
00140                 c.x = i+1; c.y = j;
00141                 neighbours2->push_back(c);
00142         } // 4
00143         if (i < sl->getHeight()-1) {
00144                 coord c;
00145                 c.orientation = VERTICAL;
00146                 c.x = i+1; c.y = j;
00147                 neighbours2->push_back(c);
00148         } // 5
00149         if (i < sl->getHeight() && j>0) {
00150                 coord c;
00151                 c.orientation = HORIZONTAL;
00152                 c.x = i+1; c.y = j-1;
00153                 neighbours2->push_back(c);
00154         } // 6
00155 }
00156 
00157 
00169 void addContinuityAxioms(cnf::Formula * form, int edgeCode,
00170                          std::vector<coord> neighbours)
00171 {
00172         // At least one of the neighbours is true if the edge is
00173         form->newClause();
00174         form->addLitCode((-1)*edgeCode);
00175         for (unsigned int k=0; k<neighbours.size(); k++)
00176                 form->addLit(neighbours[k].orientation, true,
00177                              neighbours[k].x, neighbours[k].y);
00178         form->pushClause();
00179         // They are mutually exclusive
00180         if (neighbours.size() > 1)
00181                 for (unsigned int k=0; k<neighbours.size()-1; k++)
00182                         for (unsigned int l=k+1; l<neighbours.size(); l++)
00183                         {
00184                                 form->newClause();
00185                                 form->addLitCode((-1)*edgeCode);
00186                                 form->addLit(neighbours[k].orientation,false,
00187                                              neighbours[k].x, neighbours[k].y);
00188                                 form->addLit(neighbours[l].orientation,false,
00189                                              neighbours[l].x, neighbours[l].y);
00190                                 form->pushClause();
00191                         }
00192 }
00193 
00194 
00195 // ==================================================================
00196 // ======================================================= Hint axioms
00197 // ==================================================================
00198 
00199 
00211 std::vector<int> hintNeighbours(cnf::VariableSet * vars,
00212                                 unsigned int i, unsigned int j)
00213 {
00214         std::vector<int> neighbours(4);
00215         neighbours[0] = vars->getVarCode(HORIZONTAL,i,j);   // 1
00216         neighbours[1] = vars->getVarCode(  VERTICAL,i,j+1); // 2
00217         neighbours[2] = vars->getVarCode(HORIZONTAL,i+1,j); // 3
00218         neighbours[3] = vars->getVarCode(  VERTICAL,i,j);   // 4
00219         return neighbours;
00220 }
00221 
00222 
00227 void addHintAxioms0(cnf::Formula * form, Slitherlink * sl,
00228                    cnf::VariableSet * vars, unsigned int i,
00229                    unsigned int j)
00230 {
00231         std::vector<int> neighbours = hintNeighbours(vars,i,j);
00232         for (unsigned int k=0; k<4; k++)
00233         {
00234                 form->newClause();
00235                 form->addLitCode((-1)*neighbours[k]);
00236                 form->pushClause();
00237         }
00238 }
00239 
00240 
00247 void addHintAxioms1(cnf::Formula * form, Slitherlink * sl,
00248                    cnf::VariableSet * vars, unsigned int i,
00249                    unsigned int j)
00250 {
00251         std::vector<int> neighbours = hintNeighbours(vars,i,j);
00252         // at least one is true
00253         form->newClause();
00254         for (unsigned int k=0; k<4; k++)
00255                 form->addLitCode(neighbours[k]);
00256         form->pushClause();
00257         // they are mutually exclusive
00258         for (unsigned int k=0; k<3; k++)
00259                 for (unsigned int l=k+1; l<4; l++)
00260                 {
00261                         form->newClause();
00262                         form->addLitCode((-1)*neighbours[k]);
00263                         form->addLitCode((-1)*neighbours[l]);
00264                         form->pushClause();
00265                 }
00266 }
00267 
00268 
00275 void addHintAxioms2(cnf::Formula * form, Slitherlink * sl,
00276                    cnf::VariableSet * vars, unsigned int i,
00277                    unsigned int j)
00278 {
00279         std::vector<int> neighbours = hintNeighbours(vars,i,j);
00280         // every 3-tuple of positive literals is true and so is
00281         // every 3-tuple of negative literals.
00282         for (unsigned int k=0; k<2; k++)
00283                 for (unsigned int l=k+1; l<3; l++)
00284                         for (unsigned int m=l+1; m<4; m++)
00285                         {
00286                                 // positive 3-tuple
00287                                 form->newClause();
00288                                 form->addLitCode(neighbours[k]);
00289                                 form->addLitCode(neighbours[l]);
00290                                 form->addLitCode(neighbours[m]);
00291                                 form->pushClause();
00292                                 // negative 3-tuple
00293                                 form->newClause();
00294                                 form->addLitCode((-1)*neighbours[k]);
00295                                 form->addLitCode((-1)*neighbours[l]);
00296                                 form->addLitCode((-1)*neighbours[m]);
00297                                 form->pushClause();
00298                         }
00299 }
00300 
00301 
00307 void addHintAxioms3(cnf::Formula * form, Slitherlink * sl,
00308                    cnf::VariableSet * vars, unsigned int i,
00309                    unsigned int j)
00310 {
00311         std::vector<int> neighbours = hintNeighbours(vars,i,j);
00312         // At least one is false
00313         form->newClause();
00314         for (unsigned int k=0; k<4; k++)
00315                 form->addLitCode((-1)*neighbours[k]);
00316         form->pushClause();
00317         // In every subset of size two, at least one is true
00318         for (unsigned int k=0; k<3; k++)
00319                 for (unsigned int l=k+1; l<4; l++)
00320                 {
00321                         form->newClause();
00322                         form->addLitCode(neighbours[k]);
00323                         form->addLitCode(neighbours[l]);
00324                         form->pushClause();
00325                 }        
00326 }
00327 
00328 
00329 void addHintAxioms(cnf::Formula * form, Slitherlink * sl,
00330                    cnf::VariableSet * vars, unsigned int i,
00331                    unsigned int j)
00332 {
00333         switch (sl->getHint(i,j))
00334         {
00335         case (-1): break;
00336         case (0): { addHintAxioms0(form,sl,vars,i,j); break; } 
00337         case (1): { addHintAxioms1(form,sl,vars,i,j); break; }
00338         case (2): { addHintAxioms2(form,sl,vars,i,j); break; }
00339         case (3): { addHintAxioms3(form,sl,vars,i,j); break; }
00340         }
00341 }
00342 
00343 
00344 
00345 // ===================================================================
00346 // ================================================ Single loop axioms
00347 // ===================================================================
00348 
00359 void addContinuityAndNumberingAxioms(cnf::Formula * form, int orientation,
00360                                      unsigned int i, unsigned int j,
00361                                      unsigned int maxLoopSize)
00362                                      
00363 {
00364         // If the edge is in the loop then it has to have an index
00365         form->newClause();
00366         form->addLit(orientation,false,i,j);
00367         for (unsigned int k=0; k<maxLoopSize; k++)
00368                 form->addLit(orientation+NUMBERING,true,i,j,k);
00369         form->pushClause();
00370         // If the edge has an index then it has to be in the loop
00371         for (unsigned int k=0; k<maxLoopSize; k++)
00372         {
00373                 form->newClause();
00374                 form->addLit(orientation+NUMBERING,false,i,j,k);
00375                 form->addLit(orientation,true,i,j);
00376                 form->pushClause();
00377         }
00378 }
00379 
00380 
00391 void addIncreasingIndexAxioms(cnf::Formula * form, int orientation,
00392                               unsigned int i, unsigned int j,
00393                               unsigned int index,
00394                               bool isNeighboursGreater, bool sense,
00395                               std::vector<coord> neighbours)
00396 {
00397         if ((index != 0) || (isNeighboursGreater))
00398         {
00399                 unsigned int neighboursIndex =
00400                         (isNeighboursGreater) ? index+1 : index-1;
00401                 // The neighbours must have the correct index
00402                 form->newClause();
00403                 form->addLit(orientation+NUMBERING,false,i,j,index);
00404                 form->addLit(orientation+SENSE,!sense,i,j);
00405                 for (unsigned int k=0; k<neighbours.size(); k++)
00406                 {
00407                         form->addLit(neighbours[k].orientation+NUMBERING,true,
00408                                      neighbours[k].x,neighbours[k].y,neighboursIndex);
00409                         if (isNeighboursGreater) // then maybe the next index is zero (closing the loop)
00410                                 form->addLit(neighbours[k].orientation+NUMBERING,true,
00411                                              neighbours[k].x,neighbours[k].y,0);
00412                 }
00413                 form->pushClause();
00414         }
00415         // else: nothing to do here *takes his jetpack*
00416 }
00417 
00418 
00426 void placeZero(cnf::Formula * form, Slitherlink * sl,
00427                cnf::VariableSet * vars,
00428                unsigned int i, unsigned int j)
00429 {
00430         std::vector<int> neighbours(4);
00431         neighbours[0] = vars->getVarCode(HORIZONTAL_EDGE_INDEX,i  ,j  ,0);
00432         neighbours[1] = vars->getVarCode(  VERTICAL_EDGE_INDEX,i  ,j+1,0);
00433         neighbours[2] = vars->getVarCode(HORIZONTAL_EDGE_INDEX,i+1,j  ,0);
00434         neighbours[3] = vars->getVarCode(  VERTICAL_EDGE_INDEX,i  ,j  ,0);
00435         // zero is along the side of this cell ...
00436         form->newClause();
00437         form->addLitCode(neighbours[0]);
00438         form->addLitCode(neighbours[1]);
00439         form->addLitCode(neighbours[2]);
00440         form->addLitCode(neighbours[3]);
00441         form->pushClause();
00442         // ... and there is only one ...
00443         for (unsigned int k=0; k<3; k++)
00444                 for (unsigned int l=k+1; l<4; l++)
00445                 {
00446                         form->newClause();
00447                         form->addLitCode((-1)*neighbours[k]);
00448                         form->addLitCode((-1)*neighbours[l]);
00449                         form->pushClause();
00450                 }
00451         // ... and it can't be anywhere else
00452         for (unsigned int k=0; k<=sl->getHeight(); k++)
00453                 for (unsigned int l=0; l<sl->getWidth(); l++)
00454                         if ((l!=j) || ((k!=i) && (k!=i+1)) )
00455                         {
00456                                 form->newClause();
00457                                 form->addLit(HORIZONTAL_EDGE_INDEX,false,k,l,0);
00458                                 form->pushClause();
00459                         }
00460         for (unsigned int k=0; k<sl->getHeight(); k++)
00461                 for (unsigned int l=0; l<=sl->getWidth(); l++)
00462                         if ((k!=i) || ((l!=j) && (l!=j+1)) )
00463                         {
00464                                 form->newClause();
00465                                 form->addLit(VERTICAL_EDGE_INDEX,false,k,l,0);
00466                                 form->pushClause();
00467                         }
00468 }
00469 
00470 // ===================================================================
00471 // ===================================================== Main function
00472 // ===================================================================
00473 
00474 
00475 int main(int argc, char * argv[])
00476 {
00477         // initialising input and output streams
00478         if (argc <= 2)
00479         {
00480                 std::cout<<"Wrong number of argument!"<<std::endl
00481                          <<"./i2f <slitherlink to solve> <where to put "
00482                          <<"the dimacs>"<<std::endl;
00483                 exit(1);
00484         }
00485         std::ifstream * input  = new std::ifstream(argv[1]);
00486         std::ofstream * output = new std::ofstream(argv[2]);
00487 
00488         // reading slitherlink
00489         Slitherlink * sl = new Slitherlink();        
00490         sl->parseInput(input);
00491         free(input);
00492 
00493         // ---- creating the variables
00494         unsigned int maxLoopSize = sl->getHeight()*sl->getWidth()*4;
00495         // horizontal edges continuity
00496         cnf::VariableSet * vars = new
00497                 cnf::VariableSet(sl->getHeight()+1,sl->getWidth());
00498         // vertical edges continuity
00499         vars->addVars(sl->getHeight(),sl->getWidth()+1);
00500         // horizontal edges indices
00501         vars->addVars(sl->getHeight()+1,sl->getWidth(),maxLoopSize+1);
00502         // vertical edges continuity
00503         vars->addVars(sl->getHeight(),sl->getWidth()+1,maxLoopSize+1);
00504         // horizontal edges sense
00505         vars->addVars(sl->getHeight()+1,sl->getWidth());
00506         // vertical edges sense
00507         vars->addVars(sl->getHeight(),sl->getWidth()+1);
00508         
00509         // creating the formula corresponding to the slitherlink
00510         cnf::Formula* form = new cnf::Formula(vars,output,
00511                                               "formula modeling a slitherlink");
00512 
00513         // several variables which will turn out to be useful
00514         std::vector<coord> neighbours1;
00515         std::vector<coord> neighbours2;
00516         int edgeCode;
00517         // taking care of horizontal edges
00518         for (unsigned int i=0; i <= sl->getHeight(); i++)
00519                 for (unsigned int j=0; j < sl->getWidth(); j++)
00520                 {
00521                         edgeCode = vars->getVarCode(0,i,j);
00522                         getHneighbours(sl,i,j, &neighbours1,&neighbours2);
00523                         addContinuityAxioms(form,edgeCode,neighbours1);
00524                         addContinuityAxioms(form,edgeCode,neighbours2);
00525                         addContinuityAndNumberingAxioms(form,HORIZONTAL,i,j,
00526                                                         maxLoopSize);
00527                         for (unsigned int index=0; index<maxLoopSize; index++)
00528                         {
00529                                 // positive sense
00530                                 addIncreasingIndexAxioms(form,HORIZONTAL,i,j,
00531                                                          index, false,true,
00532                                                          neighbours1);
00533                                 addIncreasingIndexAxioms(form,HORIZONTAL,i,j,
00534                                                          index, true,true,
00535                                                          neighbours2);
00536                                 // negative sense
00537                                 addIncreasingIndexAxioms(form,HORIZONTAL,i,j,
00538                                                          index, true,false,
00539                                                          neighbours1);
00540                                 addIncreasingIndexAxioms(form,HORIZONTAL,i,j,
00541                                                          index, false,false,
00542                                                          neighbours2);
00543                         }
00544                 }                        
00545         // taking care of vertical edges
00546         for (unsigned int i=0; i < sl->getHeight(); i++)
00547                 for (unsigned int j=0; j <= sl->getWidth(); j++)
00548                 {
00549                         edgeCode = vars->getVarCode(1,i,j);
00550                         getVneighbours(sl,i,j, &neighbours1,&neighbours2);
00551                         addContinuityAxioms(form,edgeCode,neighbours1);
00552                         addContinuityAxioms(form,edgeCode,neighbours2);
00553                         addContinuityAndNumberingAxioms(form,VERTICAL,i,j,
00554                                                         maxLoopSize);
00555                         for (unsigned int index=0; index<maxLoopSize; index++)
00556                         {
00557                                 // positive sense
00558                                 addIncreasingIndexAxioms(form,VERTICAL,i,j,
00559                                                          index, false,true,
00560                                                          neighbours1);
00561                                 addIncreasingIndexAxioms(form,VERTICAL,i,j,
00562                                                          index, true ,true,
00563                                                          neighbours2);
00564                                 // negative sense
00565                                 addIncreasingIndexAxioms(form,VERTICAL,i,j,
00566                                                          index, true ,false,
00567                                                          neighbours1);
00568                                 addIncreasingIndexAxioms(form,VERTICAL,i,j,
00569                                                          index, false,false,
00570                                                          neighbours2);
00571                         }
00572                 }
00573         // Adding hint axioms and forcing zero to be around a hint
00574         bool zeroHasBeenPut = false;
00575         for (unsigned int i=0; i<sl->getHeight(); i++)
00576                 for (unsigned int j=0; j<sl->getWidth(); j++)
00577                 {
00578                         addHintAxioms(form,sl,vars,i,j);
00579                         if ((!zeroHasBeenPut) && (sl->getHint(i,j)>0))
00580                         {
00581                                 placeZero(form,sl,vars,i,j);
00582                                 zeroHasBeenPut = true;
00583                         }
00584                 }
00585                                 
00586 
00587         // At last, outputing the eagerly awaited formula
00588         form->flushCNF();
00589         // Everything went as expected (or not, hahahaha) so returns 0
00590         return 0;
00591 }
 All Classes Files Functions Variables Defines