【问题标题】:Out of local stack when applying recursion应用递归时超出本地堆栈
【发布时间】:2013-06-09 05:20:00
【问题描述】:

首先是上下文。我试图用 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,我有办法解决这个问题。因为主要目标已经完成,但是还有一个次要问题我从现在开始描述它。

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

这是我在 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 %

正如我在 cmets 中所说,即使使用同一图表的某些元素(除了邻居元素),definitivefriend 也会给我错误。在某些情况下,当我执行definitivefriend(X, Y) 时,我得到了正确的结果,但是当我执行definitivefriend(Y, X) 时,我得到了错误的结果。

【问题讨论】:

  • @CapelliC,这是你问我的数据。

标签: recursion prolog stack graph-theory


【解决方案1】:

我觉得你没有以正确的方式建模,无论如何这似乎有效(滥用 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.

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

【讨论】:

  • 我认为如果不是所有的友谊都是相互的,这是行不通的。例如,对于friend(sally, bob). friend(ted, bob),Sally 和 Ted 都不是 @&lt; Bob,因此即使 Sally 和 Ted 通过 Bob 是“确定的朋友”,递归方法也不会触发。我不清楚规范中的逆 friend/2 事实是否会一直存在。
  • @DanielLyons:逆向规范是这项工作的关键。我同意这是一种表达知识的不明确且相当不寻常的方式。
  • @CapelliC 您的代码有效,但在某些情况下,即使图形元素的所有相互关系,当我检查 definitivefriend 与同一图形的某些元素时,代码返回我 false(预期返回为 true)。
  • 克里斯蒂安,你能发布数据吗?
  • @CapelliC 当然,给我一点时间,我会把它放在帖子本身,因为解释有点大,涉及到显示图表。
【解决方案2】:

对于您的第二条definitivefriend 规则,添加一个 X

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

现在,您可以:

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

导致无限递归

【讨论】:

  • 我不明白您所说的“添加 X
  • 您可能需要@&lt;/2 而不是&lt;/2,因为它适用于原子(实际上是任意术语)而不仅仅是数字。
  • @DanielLyons 我几乎不记得我上过的答案集编程课,甚至连序言都没有。如果您愿意,您可以从中窃取并发布您自己更好的答案,我不知道如何从这里开始。
【解决方案3】:

问题基本上是循环。您的图表是非循环的,但您的代码不是。这是问题。假设我给出查询:- 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]).

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-31
    • 2021-07-24
    • 2018-05-28
    相关资源
    最近更新 更多