0

These are my rules, where my problem lies:

get_row([H|_],1,H):-!.
get_row([_|T],I,X) :-
    I1 is I-1,
    get_row(T,I1,X).

get_column([],_,[]).
get_column([H|T], I, [R|X]):-
   get_row(H, I, R), 
   get_column(T,I,X).

good_by_coulmns(Solution) :-
      length(Solution, Length),
      forall((between(1, Length, X),
              get_column(Solution, X, Y)),
              all_distinct(Y)).

createRow(Solution, Domain, Row) :- 
      maplist(member, Row, Domain),
      all_distinct(Row), 
      good_by_coulmns(Solution).
      %, write(Solution), nl.

tryToSolve(Domains, Solution) :-
      maplist(createRow(Solution),
              Domains, Solution),
      length(Solution, L), 
      length(Domains, L),
      good_by_coulmns(Solution).

The problem is, that the last rule generates about 20 good answers, but, after that it goes into an infinite loop. There is a debug write in the first rule.

It writes lines like these (with always changing numbers), while looping infinitely:

[[1, 2, 3, 4], [3, 1, 4, 2], [4, 3, 2, 1], [2, 4, 1, 3], _8544, _8550, _8556, _8562]
[[1, 2, 3, 4], [3, 4, 1, 2], _8532, _8538, _8544, _8550, _8556, _8562]

The solution, we wait is a 4x4 matrix. in the first line, if we cut out the first 4 elements, it is a good solution.

The number of variables starting with _ is always increasing, while the first line of the matrix([1,2,3,4]) is never changing.

Do you have any idea, what goes wrong here?

Actual query:

tryToSolve([[[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]], [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]], [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]], [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]], L).
false
  • 10,264
  • 13
  • 101
  • 209
Falcon
  • 29
  • 6
  • 1
    @nullpointer: Such trivial edits are no help, without correcting even spelling errors – false Nov 13 '17 at 12:25
  • I've added a basic query, and added the rules. Please see it above. It is implementing a puzzle solver, at this point similar to a basic sudoku. – Falcon Nov 13 '17 at 12:49
  • 1
    [tag:clpfd] is what you need... – false Nov 13 '17 at 13:07
  • I don't know that library, can you show me, how could I use it here? – Falcon Nov 13 '17 at 13:13
  • Yes, but I have a half working solution, I want to find out why is this broken. I may rewrite it using the above library, but I want to fix this code firstly, if possible, not to learn a new library, knowing nothing about why this try is absolutely not good. Can you help me fixing this one? Or provide an alternative solution with the mentioned library? – Falcon Nov 13 '17 at 13:21
  • It showed up here only after sending my comment, sorry for that, I've added the missing rules. – Falcon Nov 13 '17 at 13:23
  • 1
    You are already using `library(clpfd)`! That's where `all_distinct/1` comes from. – false Nov 13 '17 at 13:56
  • Partial use of `library(clpfd)`, which is dangerous... If you're using SWI Prolog you must have had to manually include the library. – lurker Nov 13 '17 at 14:02
  • Thanks warning me about this! I will replace this then. I am using SICStus prolog, I did inculded it. – Falcon Nov 13 '17 at 14:18

1 Answers1

3

To identify the problem, I will use a . In this I insert false goals into your program. By inserting these goals, I will reduce the number of inferences your program needs to execute. If that number is still infinite, then the visible part contains an error1.

?- D = [1,2,3,4], D4 = [D,D,D,D], tryToSolve([D4,D4,D4,D4], L), false.

good_by_coulmns(Solution) :-
   length(Solution, Length), false,
   forall((between(1, Length, X),get_column(Solution, X, Y)), all_distinct(Y)).

createRow(Solution, Domain, Row) :-
   maplist(member, Row, Domain),
   all_distinct(Row),         % false, % terminates here
   good_by_coulmns(Solution), false.

tryToSolve(Domains, Solution) :-
   maplist(createRow(Solution), Domains, Solution), false,
   length(Solution, L),
   length(Domains, L),
   good_by_coulmns(Solution).

This fragment does loop already. Therefore, there must be an error in the visible part. Note the variable Solution! It should be a list of fixed length to make length(Solution, Length) terminate, after all Length occurs here for the first time.

Suggestion: Put the goals length(Domains, L), length(Solution, L) first.

Some remarks on your program: forall/2 is a highly problematic construct. Avoid it at all cost. Nicely, the fragment does not contain it - that would have made the diagnosis much more complex.

Also, try to start with a shorter problem first - this simplifies the observation of termination.

How have I placed those false goals? Well, it was a bit of intuition and trial-and-error. Strictly speaking, any1 placement of false goals is ok that results in a still looping fragment. When considering all possibilities, that is ~2lines failure slices, those that are minimal are most interesting. For more, see .


1 Actually, the precise preconditions are a bit more complex. Roughly, the obtained fragment must be pure to a certain degree.

false
  • 10,264
  • 13
  • 101
  • 209
  • Thank you! This is nice debugging trick to know! Now it seems to find nearly all the solutions ok, but now I am having an out of memory error at the very last solutions. I hope it will be gone by giving it more constraints. – Falcon Nov 13 '17 at 14:22
  • 1
    I get 576 solutions. In both SICStus and SWI. – false Nov 13 '17 at 14:30
  • Maybe you can help me improve this: https://stackoverflow.com/questions/47272417/sudoku-solver-is-slow-needs-considering-constraints-earlier – Falcon Nov 13 '17 at 20:41