1
votes

I am trying to create a prolog rule which will generate all the people in a social network using S number degrees of separation.

This is the rule that i have made but it is only printing empty lists. Can somebody please help me into helping me understand why this is happening and me where i am going wrong?:

socialN(_,N):- N<1,!.
socialN(_,N,_,_):- N<1,!.
socialN(P1,Separation,S1,S):-
    (message(P1,P2,_); message(P2,P1,_)),
    D is Separation-1,
    \+(member(P2,S1)),
    append(P2,S1,S2),socialN(P1,D,S2,S),!.
socialN(P2,Separation,S,S).

These are the facts:

message(allan, steve, 2013-09-03).
message(nayna, jane, 2013-09-03).
message(steve, jane, 2013-09-04).
message(steve, allan, 2013-09-04).
message(mark, martin, 2013-09-04).
message(martin, steve, 2013-09-04).
message(allan, martin, 2013-09-05).

E.g. Mark’s network includes just Martin for 1 degree of separation; it includes Martin, Steve and Allan for 2 degrees of separation; and Martin, Steve, Allan and Jane for 3.

1
Wnat's the meaning or purpose of the socialN/2 predicate? - lurker
It stands for social Network...ive just labelled it socialN - 235
I mean socialN/2 versus socialN/4. You have one which has 2 parameters, and the others have 4. - lurker
Ive tried to link the one with two parameters to the one with four to show the user that they cannot insert 0 or less degrees of separation- They an only insert 1 or more degrees of separation. Then i have tried to link the one with four to the main rule to show what we are trying to find out/ get the result of - 235
append(P2,...) will always fail since P2 is not a list. Also, watch for your D parameter. Note that if you want to pre-pend one element P2 to a list S1, you can just say [P2|S1] and don't need append. Your predicate subtracts one, but what should happen when it goes to zero? - lurker

1 Answers

1
votes

I see you are using append and member, so I suppose you are trying to build up a list of people. I was a bit surprised that you were not using findall. Like this:

allDirectLinks(P1, L) :- findall(P2, directlyLinked(P1, P2), L).

directlyLinked(P1, P1).
directlyLinked(P1, P2) :- message(P1, P2, _).
directlyLinked(P1, P2) :- message(P2, P1, _).

From there, you can write a recursive function to find the indirect links:

socialN(0, P, [P]) :- !.
socialN(N, P1, L3) :-
    N>0, !,
    N1 is N-1,
    socialN(N1, P1, L1)
    maplist(allDirectLinks, L1, L2),
    append(L2, L3).

For example, this yields in Y a list of people separated 2 steps or less from Mark:

socialN(2, mark, X), list_to_set(X, Y).

Please note, Mark himself is included in the resulting list (being a 'level 0' link); I suppose it cannot be too hard to filter that out afterwards.

I hope this makes sense; I am a bit rusty, haven't done any Prolog in 25 years.

EDIT: explanation of the rules I defined:

  • directlyLinked: true if there is a message between two persons (regardless of the direction of the message)
  • allDirectLinks: accumulates into list L all persons directly linked to a given person P1; just read the manual about findall
  • socialN: builds up a list of people connected to a given person (P) at a distance less than or equal to a given distance (N)
    • socialN(0, ...): at distance 0, every person is linked to himself
    • socialN(N, ...): makes a recursive call to get a list of connections at distance N-1, then uses maplist to apply allDirectLinks to every connection found, and finally uses append to concatenate the results together.