应用递归时超出局部堆栈

时间:2013-06-12 22:43:53

标签: recursion graph prolog stack

首先是上下文。我想用prolog审核的是两个分开的图都代表一群朋友,所以在这两个中我都可以放置关系friend(X,Y),而且,因为在这个模型中没有意义,友谊不是相互的,所以我也把关系friend(Y, X)

所以这意味着两个图表的元素之间都存在双向关系

例如:

friend(foo1, foo2).
friend(foo2, foo1).

friend(foo3, foo4).
friend(foo4, foo3).

其中foo1foo2相关,foo3foo4也是如此,但前两个与另外两个无关。

因为它是一群朋友,所以在同一组朋友中,同一组中的两个人不是朋友也没有意义,所以我正在使用递归确定是否有一个人是另一个人的朋友

definitivefriend(X, Z) :- friend(X, Z). 
definitivefriend(X, Z) :- friend(X, Y), definitivefriend(Y, Z). 

问题我有我尝试来检查一个群组中的一个人是否是另一个群体的某个人的朋友。换句话说,检查图表的一个元素是否与另一个图表的另一个元素相关

编译器(在本例中为SWI-Prolog)给出了错误超出本地堆栈,而不是错误,这是预期的结果。

我想知道如何解决这个问题。

修改

感谢CapelliC,我有办法解决这个问题。因为主要目标是完整的,但是我将从现在开始描述它的次要问题。

Graph1 Graph2

这是我正在使用的两个图表。请记住,我之前说过,两个图都是双向的。

这是我的prolog程序:

writeit :- write('Frienship').
definitivefriend(X, Z) :- friend(X, Z), friend(Z, X).   
definitivefriend(X, Y) :- friend(X, Z), X @< Z, definitivefriend(Z, Y), Y \= X.
friend(amanda, ryan).       % graph1 %
friend(ryan, amanda).
friend(ryan, lisa).
friend(lisa, ryan).
friend(bryan, ryan).
friend(ryan, bryan).
friend(sara, ryan).
friend(ryan, sara).
friend(sara, simone).
friend(simone, sara).       % graph2 %
friend(sandra, jeff).
friend(jeff, sandra).
friend(betty, jeff).
friend(jeff, betty).
friend(jeff, antonia).
friend(antonia, jeff).
friend(jeff, oskar).
friend(oskar, jeff). 
friend(jeff, leslie).
friend(leslie, jeff). 

以下是我得到的一些输出

?- definitivefriend(amanda, ryan).
true .                         % It's correct, both nodes are neighbours %

?- definitivefriend(amanda, simone).
true .                         % It's correct, both nodes are in the same graph %

?- definitivefriend(ryan, simone).
true .                         % It's correct, same explanation as before %

?- definitivefriend(simone, amanda).
false.                         % It's wrong, expected result is true %

?- definitivefriend(ryan, jeff).
false.                         % It's correct, nodes are in different graphs %

?- definitivefriend(amanda, leslie).
false.                         % It's correct, same explanation as before %

?- definitivefriend(sandra, oskar).
false.                         % It's wrong, expected result is true %

?- definitivefriend(oskar, sandra).
false.                         % It's wrong, expected result is true %

?- definitivefriend(betty, oskar).
true .                         % It's correct, both nodes are in the same graph %

?- definitivefriend(oskar, betty).
false.                         % It's wrong, expected result is true %

正如我在评论中所说,即使使用相同图形的某些元素(除了邻居图形),definitivefriend也会给我错误。在某些情况下,当我执行definitivefriend(X, Y)时,我得到了真相,但当我执行definitivefriend(Y, X)时,我就会变错。

3 个答案:

答案 0 :(得分:2)

我觉得你没有以正确的方式进行建模,无论如何这似乎有效(滥用Jean-Bernard的建议,+1)

definitivefriend(X, Y) :-
    friend(X, Y),
    friend(Y, X).

definitivefriend(X, Y) :-
    friend(X, Z), X @< Z,
    definitivefriend(Z, Y), Y \= X.

编辑:这不适用于您的模型。除了遵循丹尼尔的建议(+1)之外,我看不到任何其他方式。

答案 1 :(得分:1)

对于您的第二个definitivefriend规则,添加一个X&lt;是的。这将避免周期。然后只需添加以下规则:

definitivefriend(X,Y) :- definitivefriend(Y,X)

就像现在一样,你可以:

definitivefriend(1,2) :- friend(1,3), definitivefriend(3,2)
definitivefriend(3,2) :- friend(2,1), definitivefriend(1,2)

导致无限递归

答案 2 :(得分:1)

问题基本上就是周期。您的图表是非循环的,但您的代码不是。这是问题所在。假设我提供了查询:- definitivefriend(foo1, foo2).。什么阻止Prolog扩展这样:

definitivefriend(foo1, foo2) 
:- friend(foo1, foo2), definitivefriend(foo2, foo2).                     % by clause 2
:- friend(foo1, foo2), friend(foo2, foo1), definitivefriend(foo1, foo2). % by clause 2

:- friend(foo1, foo2), friend(foo2, foo1), friend(foo1, foo2), 
   definitivefriend(foo2, foo2).                                         % by clause 2

@ Jean-Bernard Pellerin提供了一种通过强制总排序来预防周期的有用方法。我不认为这是正确的方法,但我不能完全理解为什么。但是,您可以做的一件事是提供访问列表以进行检查,而不是重新输入您已经访问过的节点。该代码看起来像这样:

definitivefriend(X, Z) :- definitivefriend(X, Z, [X]).

definitivefriend(X, Y, Visited) :- 
    friend(X, Y), \+ memberchk(Y, Visited).
definitivefriend(X, Z, Visited) :- 
    friend(X, Y), \+ memberchk(Y, Visited), 
    definitivefriend(Y, Z, [Y|Visited]).