1

I have an AI project in which I should make a sudoku solver in Prolog but without using the clpfd package. How should I write the code and is there any way to print whenever a variable gets a value?

Jim Ashworth
  • 765
  • 6
  • 17
Kosar Kazemi
  • 65
  • 1
  • 6
  • 1
    Related OP question [How to trace backtracks of clpfd in prolog?](http://stackoverflow.com/q/41935073/1243762) – Guy Coder Jan 30 '17 at 14:18
  • Simply first define a good datastructure to represent an (unfinished) sudoko, then implement a mechanism where you set one field and propagate the constraints (ensure that you did not fill in an invalid value). By using Prologs backtracking mechanism it will work out. – Willem Van Onsem Jan 30 '17 at 14:24
  • 1
    Are you allowed to use variables? – mat Jan 30 '17 at 14:37

1 Answers1

3

Without clpfd, you have to write a classic generate-and-test search. The nice thing about clpfd is that the constraints limit the search space. You can emulate this without using clpfd though. Let's simplify the task a bit so I can illustrate. How can you find X and Y values that solve both of these equations: X + Y = 10, 2*X + Y - 1 = 15?

First, encode your two equations:

eq1(X,Y) :- 10 is X + Y.
eq2(X,Y) :- 15 is 2*X + Y - 1.

Now create your search space in a solver predicate:

solution(X, Y) :- 
  between(1, 10, X), between(1, 10, Y),
  eq1(X,Y),
  eq2(X,Y).

Now you can run it and see:

?- solution(X,Y).
X = 6,
Y = 4 ;
false.

This is less efficient than it would be with clpfd because clpfd would notice things about the equations that would help it constrain the search space:

?- [library(clpfd)].
true.

?- X + Y #= 10, 2*X + Y - 1 #= 15.
2*X+Y#=16,
X+Y#=10.

?- X + Y #= 10, 2*X + Y - 1 #= 15, X in 1..10.
X = 6,
Y = 4.

See, it has already figured out that there is only one solution and I didn't have to constrain Y at all. That's very impressive! But you can still use Prolog without clpfd, it's just worse. :) In this example, we probably tried all 10x10=100 possible combinations to find this one solution. Less efficient. But not impossible.

So, what are the constraints you have to figure out for sudoku? Probably something like this:

unique(Row) :- sort(Row, Sorted), length(Row, Length), length(Sorted, Length).
all_digits(Row) :- forall(between(1,9,X), memberchk(X, Row)).

And so forth.

Edit: Combinatorial complexity estimation

Suppose we do a totally unprincipled search: that is, we even try obviously wrong cases like a grid of all 9s. We have 9x9=81 cells and 9 possible values (1-9). This yields 9^81 = a very large number, unlikely to be checked in your lifetime. And most of those grids are going to be fruitless permutations.

Suppose you constrain your search so that each row is a permutation of 1-9. There are 9! permutations of 1-9; with nine of those, you can multiply that outcome by nine, so there should be 9!^9. This is still awful! clpfd is probably able to further winnow this down by combining the 3x3 grid constraints; I'm not sure how I would go about doing that manually, other than in a semi-procedural way, choosing a 3x3 grid permutation and then passing each 3x1 row of that on to the next 3x3 grid selection.

It's worth noting that most of the optimization in classic Prolog programs comes down to either making the generate step generate better-qualified candidates or making the test step less expensive. A more obvious implementation can still be useful for checking a more complex implementation.

Thanks to @mat for checking my math and recommending this excellent article on the combinatorial problem of Sudoku.

Daniel Lyons
  • 22,421
  • 2
  • 50
  • 77
  • The reasoning about the permutations seems a bit dubious: For every permutation of the first row, you can have (as a first approximation) an arbitrary permutation of the second row etc. – mat Jan 30 '17 at 23:15
  • (9!)^9. For many additional insights, heuristics and exact results, I recommend [Felgenhauer & Jarvis](http://www.afjarvis.staff.shef.ac.uk/sudoku/felgenhauer_jarvis_spec1.pdf). – mat Jan 30 '17 at 23:22