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   

Last step in generating Sudoku Puzzles
Goto page Previous  1, 2
 
Post new topic   Reply to topic    Sudoku Programmers Forum Index -> Programming sudoku
View previous topic :: View next topic  
Author Message
Lunatic

Joined: 11 Mar 2007
Posts: 166
:
Location: Ghent - Belgium

Items
PostPosted: Fri May 15, 2009 8:05 am    Post subject: Reply with quote

PIsaacson wrote:
The ALS-XZ help states that it is not yet implemented. Any projected dates for completion??? I only ask because ALS chains and Death Blossom are my (current) special area of interest.


I wish it was allready done, ALS-XZ, but for now, i have no idea for a good approach on how to handle ALS-XZ. I asked for help on that a while ago, but there was little response: http://www.setbb.com/sudoku/viewtopic.php?t=1601&start=0&postdays=0&postorder=asc&highlight=&mforum=sudoku

PIsaacson wrote:
BTW: I had a hard time seeing the help examples in FireFox due to the back-slashed file names for the gifs.


Thanks for letting me know, I was not aware of this. I didn't even know my links had backslashes in their path. Apparently, my html-editor handles this incorrectly. I will change it as soon as possible.
_________________
Marc
~~~<><~~~<><~~~<><~~~<><~~~
Back to top
View user's profile Send private message Send e-mail Visit poster's website
m_b_metcalf

Joined: 13 Mar 2006
Posts: 210
:
Location: Berlin

Items
PostPosted: Fri May 15, 2009 12:00 pm    Post subject: Re: Recursion Reply with quote

gsf wrote:
m_b_metcalf wrote:
So I added code to the function valid that, on row 4 (box-1 in the general case), keeps a count of the number of remaining distinct values available, taking account of those already used in the first 3 rows of the box 5. If, at any point along the row, there are fewer than 5 values left available (they'll be needed for row 4 of box 5) we can back up staightaway. This brought the time to produce a 25x25 down from 155s to 11s Exclamation

this is a form of forward checking
it can be worthwhile depending on the domain
doing it at every move usually doesn't pay off
but you found a neat way to do it for groups of moves in the sudoku domain

Thanks, but it has its limitations. I had several attempts to produce a 36x36 but none even reached row 6 (one attempt lasted an hour). Given that I already have a program that can produce a 36x36 in 0.3s, this is not worth pursuing further. But it was an interesting exercise and I learned that row box-1 is a real hump with this approach. It also demonstates a very simple way of producing 9x9s at a rate of a million every 3 minutes.
Quote:

re: recursion vs goto
there's another alternative: roll your own stack via arrays
(the way fortran programmers used to do it:)

Well, I'll take your word on that Wink

Regards,

Mike Metcalf
Back to top
View user's profile Send private message
m_b_metcalf

Joined: 13 Mar 2006
Posts: 210
:
Location: Berlin

Items
PostPosted: Mon May 18, 2009 6:37 pm    Post subject: Reply with quote

Just for the record, I used the generator code posted earlier as the basis of a solver, see below. It takes 5s to solve an average 17-clue puzzle but is ten times faster for 20+ puzzles. Of course, it has no prior pruning with any logic such as singles, nor any reordering. I got it to solve two 112-clue 16x16 puzzles; one took 24s the other 1067s, although the second was simply the transpose of the first.

Regards,

Mike Metcalf

[Edited to randomize the search within each cell.]

Code:

program solve 
implicit none
integer, parameter              :: box = 3, size = box*box, size2 = size*size
integer, dimension(size2)       :: sudoku
integer, dimension(size, size2) :: order, turn
integer                         :: cell_index, j, ll 
logical                         :: complete, fix(size2)

open(1, file='c:\sudoku\hope\hope\17.txt')
do ll = 1, 10
   read(1, '(81i1)') sudoku
   call stab
   complete = .false.
   cell_index = 0
   call cell
   write(*,'(81i1)') sudoku
end do

contains

   recursive subroutine cell
      integer :: ii, jj, top
! Finds next valid value for this cell, and backs up one cell otherwise   
      cell_index = cell_index + 1   
      if(fix(cell_index)) then
         top = 1
      else
         top = size
      end if     
      do jj = 1, top
         ii = turn(jj, cell_index)
         if(order(ii, cell_index) == 0) cycle
         if(.not.valid(order(ii, cell_index))) cycle
         sudoku(cell_index) = order(ii, cell_index)
         if(cell_index == size2) then
            complete = .true.
            return
         else
            call cell      !!! <--------------The recursive call
            if(complete) return
         end if
         if(.not.fix(cell_index)) sudoku(cell_index) = 0     
      end do   
      if(.not.fix(cell_index)) sudoku(cell_index) = 0
      cell_index = cell_index - 1
   end subroutine cell
   
   logical function valid(value)
      integer, intent(in) :: value
      integer             :: r_ind, c_ind, b_ind, bb
! Checks the row/column/box constaints             
      valid = .true.
      if(fix(cell_index)) return
      r_ind = ((cell_index - 1)/size) * size
      c_ind = cell_index - r_ind
      if(any(sudoku(r_ind + 1 : r_ind + size) == value)) then
         valid = .false.
         return
      else if(any(sudoku(c_ind : c_ind + (size-1)*size : size) == value)) then
         valid = .false.
         return   
      else
         b_ind = ((cell_index -1)/(size*box))*size*box + c_ind
         b_ind =  ((b_ind - 1)/box)*box + 1
         do bb = 0, box - 1       
            if(any(sudoku(b_ind + bb * size : b_ind + bb * size + box - 1) == value)) then
               valid = .false.
               return
            end if
         end do     
      end if   
   end function valid   
   
   subroutine stab
      integer :: r_ind, c_ind, b_ind, bb, value
! Initialize the search space; random within each cell
      do j = 1, size2
         order(:, j) = (/ (ll, ll = 1, size) /)
         turn(:, j) = scatter(size)
      end do 
      fix = .false.
      where(sudoku /= 0)
         order(1, :) = sudoku
         turn(1, :) = 1
         fix = .true.
      end where
      do j = 1, size2
         if(.not.fix(j)) cycle
         value = sudoku(j)
         r_ind = ((j - 1)/size) * size
         c_ind = j - r_ind
         where(.not.fix(r_ind + 1 : r_ind + size)) order(value, r_ind + 1 : r_ind + size) = 0
         where(.not.fix(c_ind : c_ind + (size-1)*size : size))                  &
           order(value, c_ind : c_ind + (size-1)*size : size) = 0
         b_ind = ((j -1)/(size*box))*size*box + c_ind
         b_ind =  ((b_ind - 1)/box)*box + 1
         do bb = 0, box - 1                       
            where(.not.fix(b_ind + bb * size : b_ind + bb * size + box - 1))    &
              order(value, b_ind + bb * size : b_ind + bb * size + box - 1) = 0
         end do
      end do         
   end subroutine stab
   
   function scatter(num)
      integer, intent(in) :: num
      integer             :: scatter(num), ii, index
      real                :: numbers(num)
! Array-valued function that returns the integer values 1 to num in random order     
      call random_number(numbers)
      do ii = 1, num
         index = minloc(numbers, dim=1)
         scatter(ii) = index
         numbers(index) = 2.0
      end do
   end function scatter
   
end program solve


Last edited by m_b_metcalf on Tue May 19, 2009 6:22 am; edited 1 time in total
Back to top
View user's profile Send private message
PIsaacson

Joined: 17 Jan 2006
Posts: 47
:
Location: Campbell, CA

Items
PostPosted: Mon May 18, 2009 11:30 pm    Post subject: Reply with quote

Mike,

This bears repeating, even if it is well known:

Searching in a linear manner with the cell_index is not the optimal way to traverse the solution search space.

Graph theory and sudoku logical rules combine to show that the fastest way to traverse the solution tree is through a node (cell to test) list that is sorted on the number of constraints for each cell to examine, and then by random order within each equal number of constraints. Think of it this way -- each bi-value or bi-local (locality is often overlooked) should be considered in the solution search tree before any tri-value or tri-local, which should be considered before any quad-value or qual-local ...

Within each equal level (bi-value/local, tri-value/local, quad-value/local...) graph theory has pretty much proven that randomizing the order for each level will, over the long run, always lead to finding the overall shortest path through the solution tree. The same randomness should also be used for testing the individual candidate values of each cell under consideration.

All references using the cell_index would need to be modified to use the cell pointed to by this sorted+randomized redirection list. The list should be generated just after stab builds the RC constraints, but you'll also need to generate the Rn/Cn/Bn constraints at that time as well in order to test/sort by locality.

That said, I have no idea of how difficult this is to implement in VB, but it would be interesting to see the difference in timings.

Hope this is clear and forgive me again if this is presumptuous...

Cheers,
Paul
Back to top
View user's profile Send private message
m_b_metcalf

Joined: 13 Mar 2006
Posts: 210
:
Location: Berlin

Items
PostPosted: Tue May 19, 2009 6:34 am    Post subject: Reply with quote

PIsaacson wrote:
This bears repeating, even if it is well known:

A very clear and succinct statement of how it should be done.
PIsaacson wrote:

That said, I have no idea of how difficult this is to implement in VB, but it would be interesting to see the difference in timings.

Nor have I, but in Fortran 95 implementing a random search within each cell is trivial and I have edited the posted code accordingly (see the auxiliary array turn). It reduces the time for 10 17-clue puzzles by 10% and for a 16x16 from 24.1s to 18.7s.
PIsaacson wrote:

Hope this is clear and forgive me again if this is presumptuous...

m_b_metcalf wrote:

Of course, it has no prior pruning with any logic such as singles, nor any reordering.

Not at all. You may have overlooked the fact that this was merely a programming exercise in avoiding the harmful goto. Rest assured that I don't use this method when generating a 100x100 or for playing the Patterns Game!

Regards,

Mike Metcalf
Back to top
View user's profile Send private message
m_b_metcalf

Joined: 13 Mar 2006
Posts: 210
:
Location: Berlin

Items
PostPosted: Mon May 25, 2009 7:11 am    Post subject: Reply with quote

m_b_metcalf wrote:
Nor have I, but in Fortran 95 implementing a random search within each cell is trivial and I have edited the posted code accordingly (see the auxiliary array turn). It reduces the time for 10 17-clue puzzles by 10% and for a 16x16 from 24.1s to 18.7s.


I played around with this further. Changing the order of the cells only according to the number of candidates in each turns out to be disastrous as it ruins locality. Timings increased by factors of ten or more. The real improvement comes from reordering the horizontal bands by order of population and the rows within the bands similarly. Then solving ten 17-clue puzzles takes just 2.8s and the 16x16 only 2s.

It just shows how sensitive simple methods are to ordering, as Paul pointed out.

Regards,

Mike Metcalf
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Sudoku Programmers Forum Index -> Programming sudoku All times are GMT
Goto page Previous  1, 2
Page 2 of 2

 
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