Sudoku revisited
From
minforth@21:1/5 to
All on Mon Oct 16 01:20:14 2023
For the rainy autumn days to come ;-)
A few years ago there were some discussions and somewhat complicated program concepts here on c.l.f for solving Sudoku puzzles. I wondered if the Forth CLP methods developed for the Hexagon puzzle could be applied to Sudokus as well to improve
performance.
Recently I came across a puzzle that claimed to be particularly difficult to solve using backtracking methods. So it can be used as benchmark. It took about 1s to solve with Prolog on my old laptop, which is quite slow indeed. Can Forth do better?
The puzzle is:
_,_,_, _,_,_, _,_,_,
_,_,_, _,_,3, _,8,5,
_,_,1, _,2,_, _,_,_,
_,_,_, 5,_,7, _,_,_,
_,_,4, _,_,_, 1,_,_,
_,9,_, _,_,_, _,_,_,
5,_,_, _,_,_, _,7,3,
_,_,2, _,1,_, _,_,_,
_,_,_, _,4,_, _,_,9
Another hard one:
8,_,_, _,_,_, _,_,_,
_,_,3, 6,_,_, _,_,_,
_,7,_, _,9,_, 2,_,_,
_,5,_, _,_,7, _,_,_,
_,_,_, _,4,5, 7,_,_,
_,_,_, 1,_,_, _,3,_,
_,_,1, _,_,_, _,6,8,
_,_,8, 5,_,_, _,1,_,
_,9,_, _,_,_, 4,_,_
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)
From
Marcel Hendrix@21:1/5 to
minforth on Mon Oct 16 12:28:52 2023
On Monday, October 16, 2023 at 10:20:16 AM UTC+2, minforth wrote:
For the rainy autumn days to come ;-)
Recently I came across a puzzle that claimed to be particularly difficult to solve using backtracking
methods. So it can be used as benchmark. It took about 1s to solve with Prolog on my old laptop,
which is quite slow indeed. Can Forth do better?
One second? How old is that laptop?
AMD Ryzen 7 5800X 8-Core Processor
TICKS-GET uses os time & PROCESSOR-CLOCK 4192MHz
I do not use parallel tricks here (on my Z840 a speedup of 88 times would be expected)
The puzzle is:
_,_,_, _,_,_, _,_,_,
_,_,_, _,_,3, _,8,5,
_,_,1, _,2,_, _,_,_,
_,_,_, 5,_,7, _,_,_,
_,_,4, _,_,_, 1,_,_,
_,9,_, _,_,_, _,_,_,
5,_,_, _,_,_, _,7,3,
_,_,2, _,1,_, _,_,_,
_,_,_, _,4,_, _,_,9
Another hard one:
8,_,_, _,_,_, _,_,_,
_,_,3, 6,_,_, _,_,_,
_,7,_, _,9,_, 2,_,_,
_,5,_, _,_,7, _,_,_,
_,_,_, _,4,5, 7,_,_,
_,_,_, 1,_,_, _,3,_,
_,_,1, _,_,_, _,6,8,
_,_,8, 5,_,_, _,1,_,
_,9,_, _,_,_, 4,_,_
FORTH> speedthem
0.032 milliseconds (originally 4.36 ms for the computer)
0.028 milliseconds (45 minutes human)
0.140 milliseconds (2 hours human)
0.029 milliseconds (2 hours for a human, maybe impossible)
0.003 milliseconds (unknown source)
0.004 milliseconds (Paul Hsieh's example #1)
0.003 milliseconds (Paul Hsieh's example #2)
0.003 milliseconds (Paul Hsieh's example #3)
0.302 milliseconds (A `minimal' Sudoku (thought impossible for humans))
0.006 milliseconds (Ertl #1)
0.014 milliseconds (Ertl #2)
0.432 milliseconds (Ertl #3)
0.002 milliseconds (Ertl #4)
0.004 milliseconds (Ertl #5)
0.015 milliseconds (Ertl #6)
0.002 milliseconds (Ertl #7)
0.009 milliseconds (Ertl #8)
0.006 milliseconds (Rickman ExtraHard)
0.029 milliseconds (Albert van der Horst's Python example)
112.000 milliseconds (Sudoku17.txt line 527)
348.000 milliseconds (Sudoku17.txt line 6361)
0.993 milliseconds (Arto Inkala, unsolvable to all but the sharpest minds) 5.345 milliseconds (David Filmer, rated above extreme)
16.000 milliseconds (W_a_x_man's challenge)
3.857 milliseconds (minforth's challenge #1)
0.993 milliseconds (minforth's challenge #2) ok
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)
From
Marcel Hendrix@21:1/5 to
minforth on Wed Oct 18 12:10:16 2023
On Wednesday, October 18, 2023 at 3:27:16 PM UTC+2, minforth wrote:
[..]
The majority of Marcel's timings were in the sub-milliseconds range,
while some puzzles took substantially longer. I wondered if this "discrepancy" was caused by where in the matrix the algorithm started.
A really good deduction.
I changed SOLVER to test for 9 to 1 instead of from 1 to 9 in sudoku_fast
: solver ( -- bool )
findnextmove dup 0< IF DROP morespaces? 0= EXIT THEN
\ #10 1
1 9 DO I OVER try
IF I OVER addnumber
recurse IF DROP TRUE UNLOOP EXIT
ELSE DUP removenumber
ENDIF
ENDIF
\ LOOP
-1 +LOOP DROP FALSE ; PRIVATE
This gave the following substantial differences:
FORTH> speedthem
0.170 milliseconds (originally 4.36 ms for the computer)
0.014 milliseconds (45 minutes human)
0.016 milliseconds (2 hours human)
0.017 milliseconds (2 hours for a human, maybe impossible)
0.002 milliseconds (unknown source)
0.005 milliseconds (Paul Hsieh's example #1)
0.003 milliseconds (Paul Hsieh's example #2)
0.002 milliseconds (Paul Hsieh's example #3)
0.023 milliseconds (A `minimal' Sudoku (thought impossible for humans))
0.003 milliseconds (Ertl #1)
0.002 milliseconds (Ertl #2)
0.289 milliseconds (Ertl #3)
0.002 milliseconds (Ertl #4)
0.007 milliseconds (Ertl #5)
0.020 milliseconds (Ertl #6)
0.003 milliseconds (Ertl #7)
0.009 milliseconds (Ertl #8)
0.006 milliseconds (Rickman ExtraHard)
0.013 milliseconds (Albert van der Horst's Python example)
1.000 milliseconds (Sudoku17.txt line 527)
72.000 milliseconds (Sudoku17.txt line 6361)
0.689 milliseconds (Arto Inkala, unsolvable to all but the sharpest minds) 7.418 milliseconds (David Filmer, rated above extreme)
8.000 milliseconds (W_a_x_man's challenge)
2.079 milliseconds (minforth's challenge #1)
0.689 milliseconds (minforth's challenge #2) ok
It does not really explain explain why challenge #2 is easier
than challenge #1, but a different starting value definitely
makes a difference.
If I had to beat Go, a parallel program (9 threads) might be worth a try.
-marcel
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)
From
Marcel Hendrix@21:1/5 to
minforth on Wed Oct 18 12:15:06 2023
On Wednesday, October 18, 2023 at 3:27:16 PM UTC+2, minforth wrote:
[..]
The majority of Marcel's timings were in the sub-milliseconds range,
while some puzzles took substantially longer. I wondered if this "discrepancy" was caused by where in the matrix the algorithm started.
A really good deduction.
I changed SOLVER to test for 9 to 1 instead of from 1 to 9 in sudoku_fast
: solver ( -- bool )
findnextmove dup 0< IF DROP morespaces? 0= EXIT THEN
\ #10 1
1 9 DO I OVER try
IF I OVER addnumber
recurse IF DROP TRUE UNLOOP EXIT
ELSE DUP removenumber
ENDIF
ENDIF
\ LOOP
-1 +LOOP DROP FALSE ; PRIVATE
This gave the following substantial differences:
FORTH> speedthem
0.170 milliseconds (originally 4.36 ms for the computer)
0.014 milliseconds (45 minutes human)
0.016 milliseconds (2 hours human)
0.017 milliseconds (2 hours for a human, maybe impossible)
0.002 milliseconds (unknown source)
0.005 milliseconds (Paul Hsieh's example #1)
0.003 milliseconds (Paul Hsieh's example #2)
0.002 milliseconds (Paul Hsieh's example #3)
0.023 milliseconds (A `minimal' Sudoku (thought impossible for humans))
0.003 milliseconds (Ertl #1)
0.002 milliseconds (Ertl #2)
0.289 milliseconds (Ertl #3)
0.002 milliseconds (Ertl #4)
0.007 milliseconds (Ertl #5)
0.020 milliseconds (Ertl #6)
0.003 milliseconds (Ertl #7)
0.009 milliseconds (Ertl #8)
0.006 milliseconds (Rickman ExtraHard)
0.013 milliseconds (Albert van der Horst's Python example)
1.000 milliseconds (Sudoku17.txt line 527)
72.000 milliseconds (Sudoku17.txt line 6361)
0.689 milliseconds (Arto Inkala, unsolvable to all but the sharpest minds) 7.418 milliseconds (David Filmer, rated above extreme)
8.000 milliseconds (W_a_x_man's challenge)
2.079 milliseconds (minforth's challenge #1)
0.689 milliseconds (minforth's challenge #2) ok
It does not really explain why challenge #2 is easier
than challenge #1, but a different starting value definitely
makes a difference.
If I had to beat Go, a parallel program (9 threads) might be worth a try.
-marcel
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)