按照规则,一些好的答案,但不能全部得到
Some good answers by the rule, but cannot get them all
这些是我的规则,我的问题所在:
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).
问题是,最后一条规则生成了大约 20 个好的答案,但是之后它进入了无限循环。第一条规则里面有debug写。
它会写出这样的行(数字总是在变化),同时无限循环:
[[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]
我们等待的解决方案是一个 4x4 矩阵。在第一行中,如果我们把前4个元素去掉,这是一个很好的解决方案。
以_开头的变量个数一直在增加,而矩阵的第一行([1,2,3,4])永远不变
你知道这里出了什么问题吗?
实际查询:
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).
为了确定问题,我将使用 failure-slice。在此我将 false
目标插入到您的程序中。通过插入这些目标,我将减少您的程序需要执行的推理数量。如果那个数字仍然是无限的,那么可见部分包含一个错误1.
?- 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).
这个片段确实已经循环了。因此,可见部分一定有错误。注意变量 Solution
!让length(Solution, Length)
终止应该是一个定长列表,毕竟Length
第一次出现在这里
建议:把目标length(Domains, L), length(Solution, L)
放在第一位。
关于您的程序的一些评论:forall/2
是一个非常有问题的结构。不惜一切代价避免它。很好,该片段不包含它 - 这会使诊断变得更加复杂。
此外,尝试先从较短的问题开始 - 这会简化对终止的观察。
我是如何设置这些 false
目标的?好吧,这是一些直觉和反复试验。严格来说,false
目标的任何 1 位置都可以导致仍在循环的片段。当考虑所有可能性时,即 ~2lines 失败切片,那些最小的是最有趣的。有关更多信息,请参阅 failure-slice。
1 实际上,精确的前置条件有点复杂。大致来说,得到的片段必须是一定程度的纯净。
这些是我的规则,我的问题所在:
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).
问题是,最后一条规则生成了大约 20 个好的答案,但是之后它进入了无限循环。第一条规则里面有debug写。
它会写出这样的行(数字总是在变化),同时无限循环:
[[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]
我们等待的解决方案是一个 4x4 矩阵。在第一行中,如果我们把前4个元素去掉,这是一个很好的解决方案。
以_开头的变量个数一直在增加,而矩阵的第一行([1,2,3,4])永远不变
你知道这里出了什么问题吗?
实际查询:
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).
为了确定问题,我将使用 failure-slice。在此我将 false
目标插入到您的程序中。通过插入这些目标,我将减少您的程序需要执行的推理数量。如果那个数字仍然是无限的,那么可见部分包含一个错误1.
?- 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).
这个片段确实已经循环了。因此,可见部分一定有错误。注意变量 Solution
!让length(Solution, Length)
终止应该是一个定长列表,毕竟Length
第一次出现在这里
建议:把目标length(Domains, L), length(Solution, L)
放在第一位。
关于您的程序的一些评论:forall/2
是一个非常有问题的结构。不惜一切代价避免它。很好,该片段不包含它 - 这会使诊断变得更加复杂。
此外,尝试先从较短的问题开始 - 这会简化对终止的观察。
我是如何设置这些 false
目标的?好吧,这是一些直觉和反复试验。严格来说,false
目标的任何 1 位置都可以导致仍在循环的片段。当考虑所有可能性时,即 ~2lines 失败切片,那些最小的是最有趣的。有关更多信息,请参阅 failure-slice。
1 实际上,精确的前置条件有点复杂。大致来说,得到的片段必须是一定程度的纯净。