I am a prolog beginner and I want to create the "brother" relation.
The relation should be symmetric as in if brother(alin, alex) is true, brother(alex, alin) should be as well.
It should also be transitive as in if brother(alin, alex) and brother(alex, claudiu) are true, brother(alin, claudiu) should be as well.
Combining the to properties, if brother(alex, alin) and brother(alex, claudiu) are true, brother(alin, claudiu) should also be true.
Here is my code:
r_brother(alin, alex).
r_brother(alin, ciprian).
r_brother(alex, claudiu).
s_brother(X, Y) :- r_brother(X, Y).
s_brother(X, Y) :- r_brother(Y, X).
brother(L1, L2) :-
t_brother(L1, L2, []).
t_brother(L1, L2, _) :-
s_brother(L1, L2).
t_brother(L1, L2, IntermediateNodes) :-
s_brother(L1, L3),
\+ member(L3, IntermediateNodes),
t_brother(L3, L2, [L3 | IntermediateNodes]).
r_brother - is the basic relation
s_brother - is the symmetric brother relation(this works well)
t_brother - this should be the transitive and symmetric relation, I keep the intermediate nodes so I don't get a loop
The problem is that the answer for:
?- brother(X, alin).
is:
X = alex ;
X = ciprian ;
X = alin ;
X = alin ;
X = alin ;
X = alin ;
X = alex ;
X = alex ;
X = alex ;
X = alex ;
X = ciprian ;
X = ciprian ;
X = claudiu ;
X = claudiu ;
false.
I looked through the trace and I understand what the problem is, but I don't know how to solve it.
alin should not be a possible answer and the others should appear a single time.
I think the basic problem is that you do not check if L2 is already found in the first clause of t_brother/3. And the initial L1 should be added to the list in brother/2:
brother(L1, L2) :-
t_brother(L1, L2, [L1]). % <-- [L1] instead of []
t_brother(L1, L2, IntermediateNodes) :-
s_brother(L1, L2),
\+ member(L2, IntermediateNodes). % <-- added this check
t_brother(L1, L2, IntermediateNodes) :- % <-- this clause is unchanged
s_brother(L1, L3),
\+ member(L3, IntermediateNodes),
t_brother(L3, L2, [L3 | IntermediateNodes]).
You can still shorten the solution by using a disjunction:
t_brother(L1, L2, IntermediateNodes) :-
s_brother(L1, L3),
\+ member(L3, IntermediateNodes),
( L2=L3
; t_brother(L3, L2, [L3 | IntermediateNodes])).