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).
To identify the problem, I will use a failure-slice. 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 failure-slice.
1 Actually, the precise preconditions are a bit more complex. Roughly, the obtained fragment must be pure to a certain degree.