Find routes in graph - prolog

I'm trying to find all possible routes and then print to the user, but since I'm kind new to prolog, I'm having some trouble.
I have to print all possible ways to go to G from A. This is what I have so far:
direct_path(pathA,pathB).
direct_path(pathA,pathC).
direct_path(pathB,pathD).
direct_path(pathC,pathE).
direct_path(pathC,pathF).
direct_path(pathE,pathD).
direct_path(pathE,pathG).
direct_path(pathF,pathG).
upward(X, Y):- direct_path(X, Y).
upward(X, Z):- direct_path(X, Y), upward(Y, Z).
This way I can check if it's possible to get from A to G, but how to I do to print this paths?

Just add a third parameter to your upward predicate to store the path:
upward(X, Y, [X, Y]):- direct_path(X, Y).
upward(X, Z, [X | Rest]):- direct_path(X, Y), upward(Y, Z, Rest).
Test run:
?- upward(pathA, pathG, Path).
Path = [pathA, pathC, pathE, pathG] ;
Path = [pathA, pathC, pathF, pathG] ;
false.
So there are two different paths from A to G.

Related

Prolog - Find second and second last elements in list

I am new to prolog and currently stuck trying to understand how to implement this.
I need a predicate to find the second and the second last elements of a list using recursion, so for example:
second_secondLast([1,2], X, Y). must return X=2, Y=1.
second_secondLast([1,2,3], X, Y). must return X=2, Y=2.
second_secondLast([1], X, Y). must print 'Error' and return false.
First, I have the error-checking clauses:
second_secondLast([], X, Y) :- print("Error"), !, fail.
second_secondLast([_], X, Y) :- print("Error"), !, fail.
Next, I tried something like this:
second_secondLast([Y,X],X,Y) :- !.
second_secondLast(L, X, Y) :-
second(L,X),
secondLast(L,Y).
second([_,S|_], X) :- X = S.
secondLast([P,_], Y) :- Y = P.
secondLast([F|R], Y) :- secondLast(R, Y).
However, the output using [1,2,3] is X=Y, Y=2.
I'm not sure if it is possible to force the output to be X=2 instead, or if there is a better method to do this.
First of all, the output X=Y, Y=2. has nothing to do with your program, it is an idiosyncracy of swipl (and maybe other interactive environments for Prolog implementations).
I think, your program looks fine, but you are asking for possible improvements.
second([_,S|_], S). is a more elegant version of your second([_,S|_], X) :- X = S..
Likewise, secondLast([P,_], P). is more elegant than your secondLast([P,_], Y) :- Y = P..
I would also prefer secondLast([_|R], Y) :- secondLast(R, Y). to your
secondLast([F|R], Y) :- secondLast(R, Y)..
Your error-checking clauses look fine to me.
You could also get rid of the predicate second and alter the definition of second_secondLast by using
second_secondLast([H,X|T], X, Y):-
secondLast([H,X|T], Y).
instead of your
second_secondLast(L, X, Y) :-
second(L,X),
secondLast(L,Y).
That change would also make it a bit more efficient.
Another possibility is to use
second_secondLast(L, X, Y):-
L= [_,X|_],
secondLast(L, Y).
Then you could also get rid of the predicate secondLast and alter the above clause to
second_secondLast(L, X, Y):-
L= [_,X|_],
append(_, [Y,_], L).
.
There is always a ton of possibilities...

How to write predicate that checks whether for two same X values there are different Y values?

I'm trying to write a predicate in Prolog that should work with a set of facts like these:
value(a,b)
value(d,f)
value(p,k)
Where the first value is X and second is Y. And it should write whether there are two same X values among those facts that have different Y values. In the example above the predicate should return true and in the example below the predicate should return false.
value(a,b)
value(d,f)
value(a,k)
My current predicate is this
have_different_Y_for_same_X :- relation(X, Y), not(relation(X, Z)).
All results I get no matter the values are true, so it's not working as it should.
So I have a problem with the negation: you want it to be true if there are no such relation for an X and two different Y. The following code gives the desired result.
different_Y_for_same_X() :-
value(X, Y),
value(X, Z),
Y #< Z.
no_different_Y_for_same_X() :-
\+ different_Y_for_same_X().
diff_2nds(X) :-
value(X, Y1), value(X, Y2),
Y1 \= Y2.
Just write exactly what you mean. value/2 must succeed twice with different values.
This gives
?- diff_2nds(X).
X = a ;
X = a ;
false.
1- First in checkX it collects all X's in XList.
2- In checkX1 For each X collects it's Y's in YList.
3- Then finally in checkX2, for each X checks if it's Y's are same or not using same predicate.
value(a,b).
value(d,f).
value(a,k).
checkX:-
findall(X1,value(X1,_),XList),
checkX1(XList,YList),
checkX2(XList,YList).
checkX1([],[]).
checkX1([H|T],[YList|List]):-
findall(Y,value(H,Y),YList),
checkX1(T,List).
checkX2([],[]).
checkX2([H|T],[H2|T2]):-
(
\+same(H2)->
write('X='),
write(H),
write(' '),
write('Y='),
writeln(H2),
writeln('true'),
checkX2(T,T2);
write('X='),
write(H),
write(' '),
write('Y='),
writeln(H2),
writeln('false'),
checkX2(T,T2)).
same([]). % You only need this one if you want the empty list to succeed
same([_]).
same([X,X|T]) :- same([X|T]).
Example:
?-checkX
X=a Y=[b, k]
true
X=d Y=[f]
false
X=a Y=[b, k]
true
1true
Here's my approach:
1- Define the facts.
2- checkX predicate finds all Y values for X using findall. It returns a list (YList=[b,k]).
3- Then check that the elements in the list are not same, using (\+) for not.
value(a,b).
value(d,f).
value(a,k).
checkX(X):-
findall(Y,value(X,Y),YList),
\+same(YList).
same([]). % You only need this one if you want the empty list to succeed
same([_]).
same([X,X|T]) :- same([X|T]).
Example:
?-checkX(a).
1true
Now suppose I have the following facts:
value(a,k).
value(d,f).
value(a,k).
?-checkX(a).
false

Finding the path length of an Acyclic Graph in Prolog

Okay, so I have the graph:
and I want to be able to create a rule to find all the paths from X to Y and their lengths (number of edges). For
example, another path from a to e exists via d, f, and g. Its length is 4.
So far my code looks like this:
edge(a,b).
edge(b,e).
edge(a,c).
edge(c,d).
edge(e,d).
edge(d,f).
edge(d,g).
path(X, Y):-
edge(X, Y).
path(X, Y):-
edge(X, Z),
path(Z, Y).
I am a bit unsure how I should approach this. I've entered a lot of rules in that don't work and I am now confused. So, I thought I would bring it back to the basics and see what you guys could come up with. I would like to know why you done what you done also if that's possible. Thank you in advance.
This situation has been asked several times already. Firstly, your edge/2 predicates are incomplete, missing edges like edge(c,d), edge(f,g), or edge(g,e).
Secondly, you need to store the list of already visited nodes to avoid creating loops.
Then, when visiting a new node, you must check that this new node is not yet visited, in the Path variable. However, Path is not yet instanciated. So you need a delayed predicate to check looping (all_dif/1). Here is a simplified version using the lazy implementation by https://stackoverflow.com/users/4609915/repeat.
go(X, Y) :-
path(X, Y, Path),
length(Path, N),
write(Path), write(' '), write(N), nl.
path(X, Y, [X, Y]):-
edge(X, Y).
path(X, Y, [X | Path]):-
all_dif(Path),
edge(X, Z),
path(Z, Y, Path).
%https://stackoverflow.com/questions/30328433/definition-of-a-path-trail-walk
%which uses a dynamic predicate for defining path
%Here is the lazy implementation of loop-checking
all_dif(Xs) :- % enforce pairwise term inequality
freeze(Xs, all_dif_aux(Xs,[])). % (may be delayed)
all_dif_aux([], _).
all_dif_aux([E|Es], Vs) :-
maplist(dif(E), Vs), % is never delayed
freeze(Es, all_dif_aux(Es,[E|Vs])). % (may be delayed)
Here are some executions with comments
?- go(a,e).
[a,b,e] 3 %%% three nodes: length=2
true ;
[a,c,d,f,g,e] 6
true ;
[a,c,f,g,e] 5
true ;
[a,d,f,g,e] 5
true ;
false. %%% no more solutions
Is this a reply to your question ?

Don't repeat solutions in Prolog

Suppose you have a database with the following content:
son(a, d).
son(b, d).
son(a, c).
son(b, c).
So a and b are sons of d and c. Now you want to know, given a bigger database, who is brother to who. A solution would be:
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y.
The problem with this is that if you ask "brother(X, Y)." and start pressing ";" you'll get redundant results like:
X = a, Y = b;
X = b, Y = a;
X = a, Y = b;
X = b, Y = a;
I can understand why I get these results but I am looking for a way to fix this. What can I do?
Prolog will always try to find every possible solution available for your statements considering your set of truths. The expansion works as depth-first search:
son(a, d).
son(b, d).
son(a, c).
son(b, c).
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y.
brother(X, Y)
_______________________|____________________________ [son(X, P)]
| | | |
X = a, P = d X = b, P = d X = a, P = c X = a, P = b
| | | |
| ... ... ...
|
| (X and P are already defined for this branch;
| the algorithm now looks for Y's)
|__________________________________________ [son(Y, d)]
| |
son(a, d) -> Y = a son(b, d) -> Y = b
| |
| | [X \= Y]
X = a, Y = a -> false X = a, Y = b -> true
|
|
solution(X = a, Y = b, P = d)
But, as you can see, the expansion will be performed in all the branches, so you'll end up with more of the same solution as the final answer. As pointed by #Daniel Lyons, you may use the setof built-in.
You may also use the ! -- cut operator -- that stops the "horizontal" expansion, once a branch has been found to be valid, or add some statement that avoids the multiple solutions.
For further information, take a look at the Unification algorithm.
First, I would advise against updating the Prolog database dynamically. For some reasons, consider the article
"How to deal with the Prolog dynamic database?".
You could use a combination of the builtin setof/3 and member/2, as #DanielLyons has suggested in his answer.
As yet another alternative, consider the following query which uses setof/3 in a rather unusual way, like this:
?- setof(t,brother(X,Y),_).
X = a, Y = b ;
X = b, Y = a.
You can eliminate one set with a comparison:
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y, X #< Y.
?- brother(X, Y).
X = a,
Y = b ;
X = a,
Y = b ;
false.
Since X and Y will be instantiated both ways, requiring X be less than Y is a good way to cut the solutions in half.
Your second problem is that X and Y are brothers by more than one parent. The easiest solution here would be to make your rules more explicit:
mother(a, d).
mother(b, d).
father(a, c).
father(b, c).
brother(X, Y) :-
mother(X, M), mother(Y, M),
father(X, F), father(Y, F),
X \= Y, X #< Y.
?- brother(X, Y).
X = a,
Y = b ;
false.
This method is very specific to this particular problem, but the underlying reasoning is not: you had two copies because a and b are "brothers" by c and also by d—Prolog was right to produce that solution twice because there was a hidden variable being instantiated to two different values.
A more elegant solution would probably be to use setof/3 to get the solutions. This can work even with your original code:
?- setof(X-Y, (brother(X, Y), X #< Y), Brothers).
Brothers = [a-b].
The downside to this approach is that you wind up with a list rather than Prolog generating different solutions, though you can recover that behavior with member/2.
This should work. But I think it can be improved (I am not a Prolog specialist):
brother(X, Y) :-
son(X, P1),
son(Y, P1),
X #< Y,
(son(X, P2), son(Y, P2), P1 #< P2 -> false; true).
If you're using Strawberry Prolog compiler,you won't get all the answers by typing this:
?- brother(X, Y),
write(X), nl,
write(Y), nl.
In order to get all the answers write this:
?- brother(X, Y),
write(X), nl,
write(Y), nl,
fail.
I hope it helps you.:)
I got to an answer.
% Include the dictionary
:- [p1]. % The dictionary with sons
:- dynamic(found/2).
brother(X, Y) :-
% Get two persons from the database to test
son(X, P),
son(Y, P),
% Test if the two persons are different and were not already used
testBrother(X, Y).
% If it got here it's because there is no one else to test above, so just fail and retract all
brother(_, _) :-
retract(found(_, _)),
fail.
testBrother(X, Y) :-
X \= Y,
\+found(X, Y),
\+found(Y, X),
% If they were not used succed and assert what was found
assert(found(X, Y)).
It always returns fails in the end but it succeeds with the following.
brother(X, Y). % Every brother without repetition
brother('Urraca', X). % Every brother of Urraca without repetition
brother('Urraca', 'Sancho I'). % True, because Urraca and Sancho I have the same father and mother. In fact, even if they only had the same mother or the same father it would return true. A little off context but still valid, if they have three or more common parents it would still work
It fails with the following:
brother(X, X). % False because it's the same person
brother('Nope', X). % False because not is not even in the database
brother('Nope', 'Sancho I'). % False, same reason
So like this I can, for example, ask: brother(X, Y), and start pressing ";" to see every brother and sister without any repetition.
I can also do brother(a, b) and brother(b, a), assuming a and b are persons in the database. This is important because some solutions would use #< to test things and like so brother(b, a) would fail.
So there it is.

What do results like Z = [_G305] mean in prolog?

I've got these definitions:
memberx(X, [X|_]).
memberx(X, [_|T]) :- memberx(X, T).
intersectionx([], _, []).
intersectionx([H|T], Y, [_|Z]) :- memberx(H, Y), !, intersectionx(T, Y, Z).
intersectionx([_|T], Y, Z) :- intersectionx(T, Y, Z).
I get the following result:
?- intersectionx([1], [1], Z).
Z = [_G305].
Why doesn't it result in Z = [1]??
Z = [_G305].
means that this answer is true for all terms. That is, it is not
only true for Z = [1] - as you expect, but it is also true for Z = [2].
Clearly, that is not what you expected.
So where is the error? A simple way to detect it is to watch out for anonymous
variables denoted _.
Consider:
intersectionx([H|T], Y, [_|Z]) :- memberx(H, Y), !, intersectionx(T, Y, Z).
^^^
What you have written means that the intersection of a list starting with
H and another list will be (provided the goals on the right hand side
are all true) a list starting with anything... Replace anything by that H!

Resources