0

这些是我的规则,我的问题出在哪里:

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 个好的答案,但之后它进入了无限循环。第一条规则中有一个调试写入。

它写出像这样的行(总是改变数字),同时无限循环:

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

1 回答 1

3

为了确定问题,我将使用。在此,我将false目标插入到您的程序中。通过插入这些目标,我将减少您的程序需要执行的推理次数。如果该数字仍然是无限的,则可见部分包含错误1 ​​。

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

good_by_coulmns(解决方案):-
   长度(解决方案,长度),forall((之间(1,长度,X),get_column(解决方案,X,Y)),all_distinct(Y))。

createRow(解决方案,域,行):-
   maplist(成员,行,域),
   all_distinct(Row), % false, % 在这里终止
   good_by_coulmns(解决方案),。

tryToSolve(域,解决方案):-
   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目标的?嗯,这有点直觉和反复试验。严格来说,任何1个目标位置false都是可以的,这会导致仍然循环的片段。在考虑所有可能性时,即约 2条线路故障切片,最小的那些是最有趣的。有关更多信息,请参阅


1实际上,精确的前提条件要复杂一些。粗略地说,获得的片段必须在一定程度上是纯净的。

于 2017-11-13T13:55:43.523 回答