Avoiding the same answer multiple times in prolog - prolog

So I have this undirected graph to traverse, and I should find all the verticies those are connected to a given vertex.
edge(a, b).
edge(b, c).
edge(c, d).
edge(d, e).
edge(e, f).
edge(f, d).
edge(d, g).
edge(g, f).
edge(g, h).
edge(h, i).
edge(i, j).
edge(j, d).
edge(d, k).
edge(l, m).
edge(m, n).
undirectedEdge(X, Y) :- edge(X, Y).
undirectedEdge(X, Y) :- edge(Y, X).
connected(X, Y) :- undirectedEdge(X, Y).
connected(X, Y) :- connected(X, Z), connected(Z, Y), X \= Y.
And once I type connected(a, X). it goes into an infinite loop.
I understand why I have it, but I have no idea how to avoid it, maybe I can find some help here?

Using closure0/3 and setof/3 we get:
connected(A,B) :-
setof(t, closure0(undirectedEdge, A, B), _).

And once I type connected(a, X). it goes into an infinite loop.
The reason this happens is because it is checking a path of the form a → b → a → b → a → b → …. So it keeps "hopping" between two nodes.
You can maintain a list of nodes that the algorithm already visisted, to prevent that like:
connected(X, Y) :-
connected(X, Y, [X]).
connected(X, X, _).
connected(X, Z, L) :-
undirectedEdge(X, Y),
\+ member(Y, L),
connected(Y, Z, [Y|L]).
You can make use of the distinct/1 predicate [swi-doc] to generate distinct answers:
?- distinct(connected(a, X)).
X = a ;
X = b ;
X = c ;
X = d ;
X = e ;
X = f ;
X = g ;
X = h ;
X = i ;
X = j ;
X = k ;
false.

Related

How to code a program in prolog, that does comparison on graphs

I'm trying to code a program in prolog that says true if all the paths from a to b are the same size. Example : we have a path from a to b and another from a to c to b, here it's false because there are two paths from a to b with different sizes, the first is 1 and the other is 2. They all must be the same size otherwise it's false.
I started doing this to get the length of each path, but I'm stuck here, I just need to compare if there are two same paths or not, if yes then we compare the two results if they are the same length then true otherwise false, but I don't know how to do it in Prolog :
chemin1(X, Y):-
arete(X,Y).
chemin1(X, Y):-
arete(X,Z),
chemin1(Z,Y).
chemin2(X, Y, N):-
arete(X, Y),
N is 1.
chemin2(X, Y, N):-
arete(X, Z),
N1 is 1,
chemin2(Z, Y, N2),
N is N1+N2.
I'm assuming you have an acyclic directed graph and that a path is represented by a vertex list.
% b
% / \
% a d
% \ / \
% c---e
arete(a, b).
arete(a, c).
arete(b, d).
arete(c, d).
arete(c, e).
arete(d, e).
chemin(X, X, [X]).
chemin(X, Z, [X|Xs]):- arete(X, Y), chemin(Y, Z, Xs).
Examples:
?- chemin(a, d, C).
C = [a, b, d] ;
C = [a, c, d] ;
false.
?- chemin(a, e, C).
C = [a, b, d, e] ;
C = [a, c, d, e] ;
C = [a, c, e] ;
false.
Then, all paths between two vertices X and Y are of the same size, if there are no two paths between vertices X and Y that are of different sizes.
% all_same_size(+X, +Y)
all_same_size(X, Y) :-
not( ( chemin(X, Y, Xs),
chemin(X, Y, Ys),
not( same_size(Xs, Ys) ) ) ).
same_size([], []).
same_size([_|Xs], [_|Ys]) :- same_size(Xs, Ys).
Examples:
?- all_same_size(a, d).
true.
?- all_same_size(a, e).
false.
chemin2(X0,X, N) :-
path(arete, Path, X0,X),
length(Path, N).
allequallength(X0, X) :-
setof(N, chemin2(X0,X, N), [_]).
Using path/4.
With this definition you can also ask a more general question using the facts you indicated:
arete(a, b).
arete(b, d).
arete(b, c).
arete(a, c).
?- allequallength(X0,X).
X0 = X
; X0 = a, X = b
; X0 = a, X = d
; X0 = b, X = c
; X0 = b, X = d.

Prolog: Order of clauses for finding path in graph

I have a cyclic graph with entry and exit nodes for which I want to find out all paths leading from any entry to any exit node.
entry(a).
exit(e).
exit(f).
next(a, b).
next(b, c).
next(b, d).
next(c, e).
next(d, f).
/* Cycle */
next(c, d).
next(d, b).
/* path(entrynode, exitnode, pathtrace) */
path(X, Y, P) :- entry(X), path2(X, Y, P).
path2(X, Y, [Y]) :- next(X, Y), exit(Y).
path2(X, Y, [P|PS]) :- next(X, P), path2(P, Y, PS).
My path2 predicate works great on a non cyclic graph. Now I want to extend it to cyclic ones. All I would have to do is check if a new possible node is already in my list of visited nodes. For this I would add not(member(X, PS)) to my last rule.
If I add it before the recursion, it always returns false. If I add it after the recursion Prolog tries to find the paths first and runs out of stack. It returns the correct answers but it tries to find more and gets stuck.
Therefore: Where should I add the check or what did I do wrong/what can I do better?
You need an additional argument for your path2/3 predicate as your third argument is the path being constructed, not a list of visited nodes. I.e. you cannot simply add the \+ member(X,Ps) goal to the last rule of the predicate as Ps is bound by the recursive call. Try instead:
path(X, Y, P) :-
entry(X),
path2(X, Y, [], P).
path2(X, Y, _Visited, [Y]) :-
next(X, Y),
exit(Y).
path2(X, Y, Visited, [P|PS]) :-
next(X, P),
\+ member(P, Visited),
path2(P, Y, [P| Visited], PS).
Sample calls:
| ?- path(X, Y, P).
P = [b,c,e]
X = a
Y = e ? ;
P = [b,c,d,f]
X = a
Y = f ? ;
P = [b,d,f]
X = a
Y = f ? ;
no

Why is the following Prolog program only returning one solution?

contains(X, L) :- [X|_] = L.
contains(X, L) :- [Y|Z] = L, Y \= X, contains(X, Z).
f(R, L1, Res) :-
(R,T) = X,
contains(X, L1),
Res = T.
?- f(1, [(1,2), (1,3)], R). gives only one value of R i.e. 2, but I expect it to return 2 values of R 2 and 3.
Answer to a similar prolog question on stackoverflow.com recommends to use SPACEor ; instead of ENTER, but I get false if I press ; or SPACE after I get the first answer.
What is going wrong?
Your contains/2 is defined as:
contains(X, L) :-
[X|_] = L.
contains(X, L) :-
[Y|Z] = L,
Y \= X,
contains(X, Z).
Your Y \= X (here in boldface) however prevents the contains/2 to recurse on the tail Z once it has found an X that unifies with the head of the list. Indeed, in case Y = X, then Y \= X is false (since Y \= X is short for \+ X = Y). If Y \= X fails, we can not call contains(X, Z), and therefore it can not check of other members of the list can be emitted.
So we can remove the statement and write:
contains(X, L) :-
[X|_] = L.
contains(X, L) :-
[Y|Z] = L,
contains(X, Z).
and now contains/2 will work like member/2 works.
The code is however not very elegantly: you do unification in the body that can be done in the head. Furthermore we now have a variable L that is not used in the first clause, and a variable Y in the second clause that is not used. We can rewrite it to:
contains(X, [X|_]).
contains(X, [_|T]) :-
contains(X, T).
and that's it. Now your f/3 will work, although again it is not very elegant. We can rewrite this as well into:
f(R, L, T) :-
contains((R,T), L).
and now our f/3 predicate works in different directions:
?- f(1, [(1,2), (1,3)], R).
R = 2 ;
R = 3 ;
false.
?- f(X, [(1,2), (1,3)], 2).
X = 1 ;
false.
?- f(X, [(1,2), (1,3)], 3).
X = 1 ;
false.
?- f(X, L, 3).
L = [ (X, 3)|_G1262] ;
L = [_G1261, (X, 3)|_G1265] ;
L = [_G1261, _G1264, (X, 3)|_G1268] ;
L = [_G1261, _G1264, _G1267, (X, 3)|_G1271] .
?- f(1, L, 3).
L = [ (1, 3)|_G1250] ;
L = [_G1249, (1, 3)|_G1253] ;
L = [_G1249, _G1252, (1, 3)|_G1256] .

How do I change position of two elements in a list(PROLOG)

predicate change_pos(E1, E2,Lin,Lout).
The Lin has any number of elements, and I need to change all occurences of E1 to E2, and vice-versa. And return in Lout.
I was thinking to do something like this:
change(X, Y, [], []).
change(X, Y, [X|L], [Y,L1]):- change(X,Y,L,L1).
change(X, Y, [Z|L], [Z,L1]:- X \== Z, change(X,Y,L,L1).
But this way is not swiping two number of the list
I'm supposing, since this is homework, it's an exercise to learn list processing and recursion. But in Prolog, a common tool for processing each term in turn in a list is maplist:
% Rule for changing one element
change_element(X, Y, X, Y).
change_element(X, Y, Y, X).
change_element(X, Y, Z, Z) :- dif(X, Z), dif(Y, Z).
% Rule for changing a list
change(X, Y, L1, L2) :-
maplist(change_element(X, Y), L1, L2).
Which yields:
?- change(a, b, [a,b,c,b,a], L).
L = [b, a, c, a, b] ? ;
no
?-
For a determinate solution, you can use if_/3:
change1(X, Y, A, B) :-
if_(=(Y, A), B = X, A = B).
change2(X, Y, A, B) :-
if_(=(X, A), B = Y, change1(X, Y, A, B)).
change(X, Y, L1, L2) :- maplist(change2(X, Y), L1, L2).
Which yields:
?- change(a, b, [a,b,c,b,a], L).
L = [b, a, c, a, b].
?-
You're almost there. Your base case (the empty lists) and your second rule (swap X for Y) are basically fine (apart from the details pointed out in the comments). However, you are missing a rule for vice-versa (swap Y for X). And in your last rule you likely want to make sure that Z differs not only from X but also from Y, otherwise Z would be subject to rule two or three.
change(X, Y, [], []).
change(X, Y, [X|L], [Y|L1]) :-
change(X,Y,L,L1).
change(X, Y, [Y|L], [X|L1]) :- % <- vice versa case
change(X,Y,L,L1).
change(X, Y, [Z|L], [Z|L1]) :-
dif(X,Z), % <- neither X=Z
dif(Y,Z), % <- nor vice versa
change(X,Y,L,L1).
Here are some example queries. What does [1,2,3,4] look like after swapping 1 with 2 and vice versa?
?- change(1,2,[1,2,3,4],L).
L = [2,1,3,4] ? ;
no
What did [2,1,3,4] look like before swapping 1 with 2 and vice versa?
?- change(1,2,L,[2,1,3,4]).
L = [1,2,3,4] ? ;
no
Which elements have been swapped in [1,2,3,4] if the resulting list is [2,1,3,4] ?
?- change(X,Y,[1,2,3,4],[2,1,3,4]).
X = 1,
Y = 2 ? ;
X = 2,
Y = 1 ? ;
no

prolog general rule for finding cousins etc

The question is to write a general rule to find any level of relative!
cousin(N,Child1,Child2).
So that it is true if Child1 and Child2 are Nth cousins. So
cousin1(Child1,Child2) = cousin(1,Child1,Child2) and
cousin2(Child1,Child2) = cousin(2,Child1,Child2) and so on
for third and fourth and even higher level cousins.
What I have so far:
/* first person is parent of second person */
parent(a, b).
parent(b, f).
parent(a, d).
parent(f, g).
parent(a, k).
parent(f, h).
parent(k, l).
parent(f, i).
parent(k, m).
parent(l, t).
parent(b, e).
sibling(X,Y) :- parent(Z,X), parent(Z,Y), not(X=Y).
grandparent(X, Z) :-
parent(X, Y),
parent(Y, Z).
greatgrandparent(X, Z) :-
parent(X, Y),
parent(Y, P),
parent(P, Z).
cousin1(Child1,Child2) :-
parent(Y1,Child1),
parent(Y2,Child2),
sibling(Y1,Y2).
cousin2(Child1,Child2) :-
greatgrandparent(Z, Child1),
greatgrandparent(Z, Child2),
\+sibling(Child1, Child2),
\+cousin1(Child1, Child2),
Child1 \= Child2.
This returns false regardless of values input, so clearly I have no idea what I am doing PLEASE help!
cousin(N,Child1,Child2) :-
nth0(N, parent(Y1,Child1),Y1),
nth0(N, parent(Y2,Child2),Y2),
cousin1(Y1,Y2).
I tried:
% first person is parent of second person
parent(a, b).
parent(b, f).
parent(a, d).
parent(f, g).
parent(a, k).
parent(f, h).
parent(k, l).
parent(f, i).
parent(k, m).
parent(l, t).
parent(b, e).
sibling(Sib1,Sib2) :- parent(SomeParent,Sib1),
parent(SomeParent,Sib2),
\+ Sib1 = Sib2.
% first person is ancestor of second person
ancestor(Older,Younger,L) :-
parent(Older,Younger),
L is 1.
ancestor(Older,Younger,Level) :-
parent(Older,Child),
ancestor(Child,Younger,L),
Level is L + 1.
%nth_cousin(Level,Cous1,Cous2) :-
% ancestor(Sib1,Cous1,Level),
% ancestor(Sib2,Cous2,Level),
% sibling(Sib1,Sib2).
nth_cousin(Level,Cous1,Cous2) :-
setof((Cous1,Cous2), Sib1^Sib2^(ancestor(Sib1,Cous1,Level),
ancestor(Sib2,Cous2,Level),
sibling(Sib1,Sib2)
),
Cousins),
member((Cous1,Cous2), Cousins),
\+ (Cous2#<Cous1, member((Cous2,Cous1), Cousins)).
Ex.
1 ?- nth_cousin(1,Cous1,Cous2).
Cous1 = e,
Cous2 = l ;
Cous1 = e,
Cous2 = m ;
Cous1 = f,
Cous2 = l ;
Cous1 = f,
Cous2 = m ;
false.
2 ?- nth_cousin(2,Cous1,Cous2).
Cous1 = g,
Cous2 = t ;
Cous1 = h,
Cous2 = t ;
Cous1 = i,
Cous2 = t ;
false.

Resources