Prolog堆栈外错误

Prolog堆栈外错误,prolog,permutation,combinatorics,backtracking,failure-slice,Prolog,Permutation,Combinatorics,Backtracking,Failure Slice,我正在从以下位置处理问题26: P26(**)生成从中选择的K个不同对象的组合 列表的N个元素 例如: ?- combination(3,[a,b,c,d,e,f],L). L = [a,b,c] ; L = [a,b,d] ; L = [a,b,e] ; 所以我的计划是: :- use_module(library(clpfd)). combination(0, _, []). combination(Tot, List, [H|T]) :- length(List, Le

我正在从以下位置处理问题26:

P26(**)生成从中选择的K个不同对象的组合 列表的N个元素

例如:

?- combination(3,[a,b,c,d,e,f],L).

L = [a,b,c] ;

L = [a,b,d] ;

L = [a,b,e] ;
所以我的计划是:

:- use_module(library(clpfd)).

combination(0, _, []).
combination(Tot, List, [H|T]) :- 
    length(List, Length), Tot in 1..Length,
    append(Prefix, [H], Stem), 
    append(Stem, Suffix, List), 
    append(Prefix, Suffix, SubList),
    SubTot #= Tot-1,
    combination(SubTot, SubList, T).
我的查询结果开始时很好,但随后返回全局堆栈外错误:

?- combination(3,[a,b,c,d,e,f],L).
L = [a, b, c] ;
L = [a, b, d] ;
L = [a, b, e] ;
L = [a, b, f] ;
Out of global stack
我不明白为什么它一开始是有效的,但后来一直挂起,直到它给出全局堆栈错误。在终端中的SWISH和swi prolog上都发生。

在这种情况下使用库(clpfd)非常可疑。在
length(List,length)
之后,
length
肯定会绑定到一个非负整数,那么为什么要绑定这个约束呢?你的
Tot in 1..Length也很奇怪,因为你在递归的每一步都不断地创建一个新的约束变量,并且你试图用0来统一它。我不确定我是否完全理解您的逻辑:-(

如果我理解这个练习的要求,我会建议以下更简单的方法。首先,确保你的K不大于元素总数。然后,一次只选择一个元素,直到你有足够的元素。它可以是这样的:

k_comb(K, L, C) :-
    length(L, N),
    length(C, K),
    K =< N,
    k_comb_1(C, L).

k_comb_1([], _).
k_comb_1([X|Xs], L) :-
    select(X, L, L0),
    k_comb_1(Xs, L0).
以你为例:

?- k_comb(3, [a,b,c,d,e,f], C).
C = [a, b, c] ;
C = [a, b, d] ;
C = [a, b, e] ;
C = [a, b, f] ;
C = [a, c, b] ;
C = [a, c, d] ;
C = [a, c, e] ;
C = [a, c, f] ;
C = [a, d, b] ;
C = [a, d, c] ;
C = [a, d, e] ;
C = [a, d, f] ;
C = [a, e, b] ;
C = [a, e, c] . % and so on
注意,这并不检查第二个参数中列表的元素是否确实是唯一的;它只是从不同的位置获取元素


此解决方案仍然存在终止问题,但我不知道这是否与您相关。

如果您尝试在控制台提示下输入这行代码,并请求回溯:

?- append(Prefix, [H], Stem).
Prefix = [],
Stem = [H] ;
Prefix = [_6442],
Stem = [_6442, H] ;
Prefix = [_6442, _6454],
Stem = [_6442, _6454, H] ;
...
也许你对(主要)问题有一个线索。所有3个变量都是免费的,然后Prolog在回溯时不断生成越来越长的列表。正如Boris已经建议的,你应该让你的程序简单得多…例如

combination(0, _, []).
combination(Tot, List, [H|T]) :- 
    Tot #> 0,
    select(H, List, SubList),
    SubTot #= Tot-1,
    combination(SubTot, SubList, T).
这就产生了

?- aggregate(count,L^combination(3,[a,b,c,d,e],L),N).
N = 60.
恕我直言,库(clpfd)不会让您的生活变得更简单,因为您正在将您的第一步移到Prolog中。使用可用的基本构造对普通Prolog进行建模和调试已经很困难,而CLP(FD)是一种高级功能

我不明白为什么它一开始是有效的,但后来一直挂起,直到它给出全局堆栈错误

Prolog为特定查询生成的答案以增量方式显示。也就是说,实际答案是根据需要延迟生成的。首先,有一些您期望的答案,然后遇到了一个循环。为了确保查询完全终止,您必须遍历所有答案,始终按空格/或;键。但有一个更简单的方法方式:

只需在查询结束时添加
false
。现在,所有答案都被抑制:

?- combination(3,[a,b,c,d,e,f],L), false. ERROR: Out of global stack
要消除非终止问题,您必须修改剩余可见部分中的某些内容。显然,
前缀
词干
都是第一次出现在这里。

您是否尝试过执行
跟踪
?您可能会发现,一旦您的程序找到解决方案,它就会不断生成新的、不断增长的列表e> 追加
它可以尝试找到它永远无法满足的附加解决方案。您的第一个
追加(前缀[H],词干)
有两个变量,所以它们会无限增长。@Lougler,是的,我似乎有
跟踪
d、
debug
ged、
guitrace
d所有的变量,并且程序在生成
L=[a,b,f];
直到出现堆栈外错误为止(实际上,将
debug
作为查询的第一个子句,那么错误永远不会出现,它将永远挂起)。如果我将
trace
放在
append(前缀,[H],词干)
之前,我会得到以下输出:
Call:list:append(\u 14580,[\u 14486],\u 14584)
Call:list:append(\u 14592,[\u 14498],\u 14596)
Call:list:append(\u 14604,[\u 14510],\u 14608)
L=[a,b,c]
L=[a,b,d]
L=[a,b,e]
退出全局堆栈谢谢。首先我选择这个答案是为了信息查询
?-append(前缀,[H],词干)
这有助于说明问题。第二,我不知道
select
谓词肯定有帮助。第三,为什么CLP(FD)是一种高级功能?SWI Prolog文档实际上说的是相反的,即CPL(FD)是一个很好的默认值,较低级别的谓词应该留给高级用户:Prolog它本身值得研究。CLP(FD)基于不同的概念,在许多Prolog实现中不可用。我认为对Prolog的良好理解是使用CLP(FD)的先决条件,因为几个基本功能不能很好地混合。用Prolog解决问题并不能教你如何在CLP(FD)和viceversa中解决问题。事实上,存在许多其他CP(约束编程)实现,由(通常)过程语言托管。这真是一件大事。…@RobertL.SimioneII关于CLP(FD)的整个章节在SWI中,Prolog实现是由library(clpfd)的作者编写的。我不认为CLP(FD)是否是整数算术的良好默认值有普遍的一致性;它肯定会对
is/2
的情况施加运行时惩罚,朋友就足够了。我个人和偏见的观点是CLP(FD)如果您了解它的局限性和权衡,并且知道何时以及为什么要使用它,那么这是非常棒的。@RobertL.SimioneII让我们这样说,就像任何有用的抽象一样,CLP(FD)是一个漏洞百出的抽象概念。出于哲学和意识形态领域的原因,一些计算机科学家认为只教授漏洞百出的抽象概念是可以的。@Boris:谢谢你向我介绍这个概念。它很好地总结了我对这个话题的感受(我总是羡慕你对英语的控制:)。谢谢Boris。
Tot in 1..Length
是一种检查,以确保您从列表中请求的项目不超过列表中的项目,正如您指出的“首先,确保您的K不大于元素总数”。此外,我不知道select谓词,这是确定的 ?- combination(3,[a,b,c,d,e,f],L), false. ERROR: Out of global stack combination(0, _, []) :- false. % 1st combination(Tot, List, [H|T]) :- length(List, Length), Tot in 1..Length, % 4th terminating append(Prefix, [H], Stem), false, % 3rd loops append(Stem, Suffix, List), false, % 2nd loops append(Prefix, Suffix, SubList), SubTot #= Tot-1, false, % 1st loops combination(SubTot, SubList, T).