简体   繁体   中英

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

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.

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 .

I want to know how to solve this.

Edit

So thanks to CapelliC I have an approach of this problem. 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. And are some cases when I execute definitivefriend(X, Y) I get true, but when I execite definitivefriend(Y, X) I get false.

I feel that you are not modelling in the right way, anyway this seems working (abusing of the suggestion by 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).

For your second definitivefriend rule, add a condition that X < Y. This will avoid cycles. 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). . What's to stop Prolog from expanding that like this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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