按照规则,一些好的答案,但不能全部得到

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).

为了确定问题,我将使用 。在此我将 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 失败切片,那些最小的是最有趣的。有关更多信息,请参阅


1 实际上,精确的前置条件有点复杂。大致来说,得到的片段必须是一定程度的纯净。