Sudoku Programmers Forum Index

 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister   ProfileProfile   Log inLog in          Games  Calendar

Log in to check your private messagesLog in to check your private messages   

Limited Implication Trees (Edited Title)

 
Post new topic   Reply to topic    Sudoku Programmers Forum Index -> Solving sudoku
View previous topic :: View next topic  
Author Message
Doug

Joined: 28 May 2005
Posts: 42
:

Items
PostPosted: Wed Jun 01, 2005 4:29 am    Post subject: Limited Implication Trees (Edited Title) Reply with quote

This is an algorithm which can solve certain difficult problems. It is a way of tracking value implications easily.

The idea uses labeled directed graphs. (Edit: In fact, it generates a tree.) The vertices are cell locations. The edges are ordered pairs, where the first element is a possible value for the first cell and the second value is a forced value for the second cell. To keep the algorithm from being the same as "guessing", the second forced value must follow direclty by the new second cell either having only two possible values, or by the first cell having the value of the first element of the ordered pair leaves only one location in the row, column, or block for the second value of the ordered pair, that location being the second cell.

The algorithm is to choose a value for a cell and inductively generating the graph (Edit: tree) of forced values. When a cycle is created, say starting with vertex (cell) x and coming back to x, the second element of the ordered pair leading into x is compared with the first value on the outgoing edge from x. If these dissagree, then the cell can have the first value in the ordered pair leading to that value for x eliminated as a possibility. (Edit: More clearly, when looking at values forced from a particular vertex, if a value is forced on a vertex already visited, and so having a value, the new forced value is checked against the previous value. If it is consistent, then an edge is not added between these vertices. In this way cycles are avoided and a tree is created. This guarentees termination of the algorithm.)

If no cycles are created, or all cycles are consistent, then the next permissable value for that cell is tried and so on. After all (Edit: permissable) values for a cell are tried, the algorithm moves on to the next cell.

Notes:

1) Cycle detection is easy. One makes a table of vertices that have occured in the algorithm. A repeat indicates a cycle. Edit: The algorithm should not add cycles to the graph, rather only including new vertices and forming a tree. When a vertex gets visited again, it is mearly checked for consistency.

2) Labeled directed graphs can easily be represented as a data structures.

---------------

Below are two examples of "challenge" problems which this algorithm resolves.

The first example is from

http://www.sudokusolver.co.uk/codeit.html

*43|98*|25*
6**|425|***
2**|**1|*94
------------
9**|**4|*7*
3**|6*8|***
41*|2*9|**3
------------
82*|5**|***
***|*4*|**5
534|89*|71*

After applying standard techniques this problem acquires the following permissions matrix
Code:


   1    2     3      4   5     6     7      8    9
-------------------------------------------------------------------
A| 17   4     3      9   8     67    2      5     167
B| 6    789   1789   4   2     5     138    38    178   
C| 2    578   578    37  36    1     68     9     4
D| 9    568   2568   13  135   4     1568   7     1268
E| 3    57    257    6   157   8     49     24    129   
F| 4    1     5678   2   57    9     568    68    3
G| 8    2     17     5   16    367   49     346   69
H| 17   69    69     17  4     23    38     238   5
I| 5    3     4      8   9     26    7      1     26




Starting with vertex A1 and the possible value 7 we get the following directed graph. (I only give the relevent part of the graph. The ordered pairs represent edges and the direction is from left to right.)

A1 (7,1) H1 (1,7) H4 (7,3) C4 (3,6) C5 (6,7) A6 (7,1) A1.

So there is a cycle from A1 to A1 with the edges going in and coming out of A1 being: (7,1) A1 (7,1). Since A1 cannot have both values 1 and 7, it follows that A1 cannot have value 7.

Note that this example was also resolved by a different suggested technique by Mark Summerville. The difference between the techniques is that this suggested algorithm does not require the search for "cyclical groups". On the other hand, using cyclical groups would strengthen the algorithm under discussion. (Knowing them would in some cases allow for more outward edges from a given vertex, namely to those other vertices in the cyclical group.)

Example 2

This is also a challenge problem from:

http://www.sudokusolver.co.uk/challenge.html

*2*|***|***
***|6**|**3
*74|*8*|***
------------
***|**3|**2
*8*|*4*|*1*
6**|5**|***
------------
***|*1*|78*
5**|**9|***
***|***|*4*

After standard techniques this give rise to the following permissions matrix:

Code:


   1   2   3   4   5   6   7    8   9
-------------------------------------------------------------------
A| 13  2   6   349 35  7   149  59  8
B| 8   9   5   6   2   14  14   7   3
C| 13  7   4   39  8   15  1269 259 169
D| 4   5   7   1   9   3   8    6   2
E| 9   8   3   2   4   6   5    1   7
F| 6   1   2   5   7   8   39   39  4
G| 2   36  9   34  1   45  7    8   56
H| 5   4   8   7   36  9   1236 23  16
I| 7   36  1   8   356 2   369  4   569



This problem is resolved by the following directed graph:

A1 (3,1) C1 (1,5) C6 (5,3) A5 (3,1) A1.

Here the edge leading into A1 gives the value 1, while the edge leading out has the value 3. This implies that 3 is not possible for A1 and so it must have the value 1. Giveing A1 the value 1 resolves the problem after standard techniques.

Note in this example, using cyclical groups does not give the implication C1 (1,5) C6 as C1 and C6 are not part of a cyclical group. On the other hand, in other situations, the cyclical groups will give implications that this method misses.
-----------

This algorithm can be improved by initially making a table of cyclical groups and adding edges for them to the directed graph.

These kinds of algorithms (Edit: could be viewed as) a limited form of guessing. But it is likely that certain problems can only be solved using such techniques.

Edit: One thing that is not clear above is whether the permissions matrix is updated after possible values are assigned in the tree generation. (Permissions being updated by just excluding values in rows, columns and blocks.) If this is done, then this algorithm should contain the Nishio rule as a special case. Thinking about this more, is this method just what is refered to as Nishio? The contradiction being the impossibility of placing the value in the first cell of the tree? Hmm. I looked at the Nishio definition thread and it seems to concern itself with only one possible value at a time throughout the grid. This algorithm considers many different values. The contradiction may not be with the initial possibility considered. So it looks more general than Nishio to me.
_________________
Doug Bowman
www.flickr.com/photos/bistrosavage
Back to top
View user's profile Send private message Send e-mail
MadOverlord

Joined: 01 Jun 2005
Posts: 80
:
Location: Wilmington, NC, USA

Items
PostPosted: Thu Jun 02, 2005 6:43 pm    Post subject: Coded it, I think... Reply with quote

I've implemented a solver that I think gets to the core of limited implication chains. I call it Simple Forcing Chains. LIC might be a superset of SFC, or they might be equivalent.

My algorithm is to start at a square, make a choice for it, and then wander around the other 2-possibility squares in its row/col/block that are affected by it, building a chain of "if square A is X that means square B is Y which means square C is Z" until it gets back to square A. If the loop is inconsistant (the square before we get back is the same as the original choice we made for the first square). then we can eliminate a possibility.

This one solves sudokusolver.co.uk's challenge #1 puzzle, but not the #2

Code:
SudokuSolve.deduce_rule9:
Function deduce_rule9(puzzle() As Integer) As moveList
 
  Dim i,j As Integer
  Dim s As String
  Dim ml As new moveList
  Dim squares(-1),choices(-1) As Integer
 
  // This is the simple forced chains rule.  Basically,
  // we ask ourselves, "what are the consequences of
  // setting a square to a particular value?" and
  // follow the chain of consequences, trying to find
  // a contradiction.  If we do find one, then we know
  // our original choice must be incorrect, and we can
  // remove it.
 
  // To emulate typical human reasoning capabilities,
  // we only look at moves that force other squares
  // that have 2 possible values to go to one value.
 
  // Look at each square in turn
 
  for i = 0 to 80
   
    // if it has more than one possibility
   
    if bitCount(puzzle(i)) > 1 then
     
      // for each possibility, explore the consequences
     
      for j = 0 to 8
       
        if bitwise.bitAnd(puzzle(i),bits(j)) = 1 then
         
          // squares and choices are arrays of squares we've already
          // visited, and choices we've already made.  We use them
          // to keep track of the chain; they start out empty.
         
          // note that we are passing our new square choice as
          // a bitmap, not a bit number
         
          ml = deduce_rule9_chain(squares,choices,i,bits(j))
         
          // return if successful
         
          if ml.foundMoves then
            return ml
          end if
         
        end if
       
      next j
     
    end if
   
  next i
 
  // fail
 
  return ml
 
 
End Function

SudokuSolve.deduce_rule9_chain:
Function deduce_rule9_chain(squares() As Integer,choices() As Integer,square As Integer,choice As Integer) As moveList
 
  // Simple forcing chains
 
  Dim i,j,k,cs,cv As Integer
  Dim s As String
  Dim ml As new moveList
 
  // In this algorithm, I'll maintain the squares and choices arrays
  // without copying, by expanding them before recursing, and cutting
  // them back before returning.  I could do this in the other recursive
  // routines, but they are sufficiently complex that it was clearer
  // not to.  But I want to show the programmers out there that I knew
  // I could do this... (grin)
 
  // so the first step is to add the new move and choice
  // to the squares and choices
 
  squares.append square
  choices.append choice
 
  // For our chosen square, look at all its buddies in the rows,
  // columns and groups to find another candidate.  The candidate
  // must be a 2-possibility square that contains the previous
  // choice.
 
  // I have some arrays rowBuds(80,7), colBuds(80,7) and blockBuds(80,7)
  // that store, for each square, the other members of the row, column
  // or block.  And from that it is easy to precompute a list of all
  // the squares that share a row,col or block with a square, which
  // I've stored in allBuds(80,19) [there are always 20 such buddy squares]
 
  for i = 0 to 19
   
    // Get the current square and its value.  Note that in this algorithm
    // we don't update the possibilities for each square after each choice;
    // we keep them the way they currently are, just like a normal non-braniac
    // human would.
   
    cs = allBuds(square,i)
    cv = puzzle(cs)
   
    // If the square contains the previous choice
   
    if bitWise.bitAnd(cv,choice) <> 0  then
     
      // Then it is not in the current chain of squares
     
      j = squares.indexOf(cs)
     
      if j = -1 then
       
        // And only if the square has 2 possible choices, we can continue
       
        if bitCount(cv) = 2 then
         
          // We haven't visited this square before, so we can
          // go deeper, selecting the new square, and using the choice
          // remaining after eliminating the last one.
         
          ml = deduce_rule9_chain(squares,choices,cs,bitwise.bitAnd(cv,bitwise.onesComplement(choice)))
         
          // if we found a valid move, then we need to return with it
         
          if ml.foundMoves then
           
            // Remember to shorten the arrays.  Technically, since we are exiting
            // out of the nesting all the way, we don't need to do this, but I
            // think it's sloppy not to do so, and being "clean" tends to prevent
            // bugs from creeping into your code, so it's a good habit.
           
            redim squares(uBound(squares)-1)
            redim choices(uBound(choices)-1)
           
            return ml
           
          end if
         
        end if
       
      else
       
        // We've run into a square that's already in our chain, which forms
        // a loop.  If that square happens to be the first one, then we
        // check to see if we have a logical inconsistency.
       
        if j = 0 then
         
          // yep, we've looped back to the beginning.  Now, we decided that
          // that first square had value choices(0).  So if the last choice
          // we made is also choices(0), we've got an inconsistent loop
          // and can clean things up.
         
          // To make things more clear, consider a square with possibilities
          // 1234.  We chose 1 to test.  When we got back to the original
          // square, if the previous square was a 4, the
          // possibilities left are 123, and it isn't inconsistent.  But
          // if the previous square was a 1, the original square cannot be
          // a 1, so it's a bad cycle!
         
          if choices(0) = choice then
           
            ml.foundMoves = true
           
            // figure out what the new possibilities are;  this is the old ones
            // less the original choice we made, which we now know cannot be
            // true
           
            k = bitwise.bitAnd(puzzle(squares(0)),bitwise.onesComplement(choices(0)))
           
            // add this change to our movelist
           
            ml.s.append squares(0)
            ml.v.append k
           
            // if actually solved a square, trigger a reconstraint run
           
            ml.reconstrain = (bitCount(k) = 1)
           
            // tell them what happened
           
            ml.comment = " Rule 9 : Found a simple forcing chain.  If we assume that square" + chr(13)
            ml.comment = ml.comment + "  " + theSquare(squares(0)) + " is <" + showbits(choices(0)) + "> then we can make the"
            ml.comment = ml.comment + "  following chain of conclusions:" + chr(13) + chr(13)
           
            for k = 1 to uBound(squares)
              ml.comment = ml.comment + "   " + theSquare(squares(k)) + " must be <" + showbits(choices(k)) + ">, which means that" + chr(13)
            next k
           
            ml.comment = ml.comment + "   " + theSquare(cs) + " must be <" + showbits(bitwise.bitAnd(cv,bitwise.onesComplement(choice))) + ">." + chr(13) + chr(13)
           
            ml.comment = ml.comment + "  Since this is logically inconsistent, " + theSquare(squares(0)) + " cannot be <" + showbits(choices(0)) + ">." + chr(13)
           
            // trim back those squares (neatness counts!)
           
            redim squares(uBound(squares)-1)
            redim choices(uBound(choices)-1)
           
            // and return our victory
           
            return ml
           
          end if
         
        end if
       
      end if
     
    end if
   
  next i
 
  // return failure; remember to cut back the arrays
 
  redim squares(uBound(squares)-1)
  redim choices(uBound(choices)-1)
 
  return ml
 
End Function
Back to top
View user's profile Send private message Visit poster's website AIM Address
MadOverlord

Joined: 01 Jun 2005
Posts: 80
:
Location: Wilmington, NC, USA

Items
PostPosted: Sat Jun 04, 2005 2:33 pm    Post subject: Reply with quote

Doug, I started playing with an extension of Simple Forcing Chains this morning.

It occurred to me that if I could find a valid forcing loop in the puzzle, then if I could find a loop that hangs off it (a chain that exits the main loop via one vertex and re-enters at another) that was self-contradictary, it would invalidate the main loop.

However, after thinking about it for a bit, it seems to me that the new subchain, plus the segment of the original loop it connects to, would itself form a simple forcing loop that we would already have detected as self-contradictary, so nothing is gained.

If I am wrong and there's something to be gained from this, please let me know.
Back to top
View user's profile Send private message Visit poster's website AIM Address
someone_somewhere

Joined: 28 Aug 2005
Posts: 1
:

Items
PostPosted: Sun Aug 28, 2005 10:34 am    Post subject: Re: Limited Implication Trees (Edited Title) Reply with quote

[quote="Doug"]

Below are two examples of "challenge" problems which this algorithm resolves.

The first example is from

http://www.sudokusolver.co.uk/codeit.html

*43|98*|25*
6**|425|***
2**|**1|*94
------------
9**|**4|*7*
3**|6*8|***
41*|2*9|**3
------------
82*|5**|***
***|*4*|**5
534|89*|71*

After applying standard techniques this problem acquires the following permissions matrix
[code]

1 2 3 4 5 6 7 8 9
-------------------------------------------------------------------
A| 17 4 3 9 8 67 2 5 167
B| 6 789 1789 4 2 5 138 38 178
C| 2 578 578 37 36 1 68 9 4
D| 9 568 2568 13 135 4 1568 7 1268
E| 3 57 257 6 157 8 49 24 129
F| 4 1 5678 2 57 9 568 68 3
G| 8 2 17 5 16 367 49 346 69
H| 17 69 69 17 4 23 38 238 5
I| 5 3 4 8 9 26 7 1 26

Hi,
I think that if you take a look at the number 6 that can be in row A columns 6 and 9 only and in row I columns 6 and 9 only, we have a
X-wing situation and this means that number 6 can't be in row G column 6 and can't be in row D column 9 and can't be in row G column 9.
This X-wing will solved much easy this example.

P.S. nothing against your nice algorithm, but no need for your first example.

see u,
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Sudoku Programmers Forum Index -> Solving sudoku All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
Sudoku Programmers topic RSS feed 


Powered by phpBB © 2001, 2005 phpBB Group

Igloo Theme Version 1.0 :: Created By: Andrew Charron