简体   繁体   English

应用递归时超出本地堆栈

[英]Out of local stack when applying recursion

The context, first.上下文,第一。 What I am trying to modelate with prolog are two separated graphs , both represent a group of friends , so in both of them I can put the relation friend(X,Y) , and, because it's doesn't have sense the friendship isn't mutual in this model, I also put the relation friend(Y, X) .我试图用 prolog 建模的是两个单独的图它们都代表一组朋友,所以在它们两个中我都可以放置friend(X,Y)关系,并且,因为它没有意义,友谊不是'在这个模型中是相互的,我也把关系放在了friend(Y, X)

So this means that both graphs have bidirectional relationships between their elements .所以这意味着两个图在它们的元素之间都有双向关系

For example:例如:

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

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

In which foo1 is related with foo2 , and the same goes for foo3 and foo4 , but the first two are not related with the another two ones.其中foo1foo2相关, foo3foo4 ,但前两个与另外两个无关。

Because it is a group of friends, it also doesn´t have sense that in the same group of friends, two people of the same group aren't friends, so I am using recursion to determine if one person is friend of another .因为是一群朋友,所以也没有感觉,在同一群朋友中,同一群的两个人不是朋友,所以我使用递归来确定一个人是否是另一个人的朋友

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

The problem I have is when I try to check if one person of one group is friend of a person of the other group.我遇到的问题是,当我尝试检查一组中的一个人是否是另一组中的一个人的朋友时。 In other words, check if one element of of a graph is related with another element of the other graph .换句话说,检查图的一个元素是否与另一个图的另一个元素相关

Instead of getting false , which is the expected result, the compiler (SWI-Prolog, in this case), gives me an error of out of local stack .编译器(在本例中为 SWI-Prolog)并没有得到 false ,这是预期的结果,而是给了我一个out of local stack错误

I want to know how to solve this.我想知道如何解决这个问题。

Edit编辑

So thanks to CapelliC I have an approach of this problem.所以多亏了 CapelliC,我有了解决这个问题的方法。 Because the main objective is complete, but there's a secondary problem I will describe it from now on.因为主要目标已经完成,但还有一个次要问题,我将从现在开始描述它。

图1图2

These are the two graphs I am working with.这是我正在使用的两个图表。 Remember that I said before, both graphs are biredirectional.记住我之前说过,两个图都是双向的。

Here's my program in 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). 

And here is some of the outputs I got这是我得到的一些输出

?- 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 %

As I said in the comments, even with some elements of the same graph (excepting the neighbour ones), definitivefriend gives me false.正如我在评论中所说的那样,即使有相同图形的某些元素(除了相邻的元素), definitivefriend也会给我错误。 And are some cases when I execute definitivefriend(X, Y) I get true, but when I execite definitivefriend(Y, X) I get false.并且在某些情况下,当我执行 expiredfriend definitivefriend(X, Y)我会得到正确的结果,但是当我 execite definitivefriend(Y, X)我会得到错误的结果。

I feel that you are not modelling in the right way, anyway this seems working (abusing of the suggestion by Jean-Bernard, +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 : this cannot work with your model.编辑:这不适用于您的模型。 I can't see any other way than following Daniel suggestion (+1).除了遵循丹尼尔的建议(+1)之外,我看不到任何其他方式。

For your second definitivefriend rule, add a condition that X < Y. This will avoid cycles.对于您的第二个definitivefriend规则,添加 X < Y 的条件。这将避免循环。 Then simply add a rule for:然后简单地添加一个规则:

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

As it is now, you could have:就像现在一样,你可以:

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

Which leads to infinite recursion这导致无限递归

The problem, basically, is cycles.问题基本上是周期。 Your graph is acyclic, but your code is not.您的图表是非循环的,但您的代码不是。 Here's the question.这是问题。 Suppose I give the query :- definitivefriend(foo1, foo2).假设我给出查询:- definitivefriend(foo1, foo2). . . What's to stop Prolog from expanding that like this:是什么阻止 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

etc.等等。

@Jean-Bernard Pellerin provides one useful way to prevent cycles, by forcing a total ordering. @Jean-Bernard Pellerin 通过强制完全排序提供了一种防止循环的有用方法。 I don't think that's the right approach here, but I can't quite put my finger on why.我不认为这是正确的方法,但我不能完全说明原因。 However, one thing you can do is provide a visited list to check against and not re-enter nodes you've already been to.但是,您可以做的一件事是提供一个访问过的列表来检查而不是重新输入您已经访问过的节点。 That code's going to look like this:该代码将如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM