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 ?
Related
Is there any way to prevent cycle in this code.
move(a,b).
move(b,a).
move(a,c).
move(b,d).
move(b,e).
move(d,h).
move(d,i).
move(e,j).
move(e,k).
move(c,f).
move(c,g).
move(f,l).
move(f,m).
move(g,n).
move(g,o).
goal(n).
goSolveTheMaze(Start,Way) :-
dfs(Start, Way),!.
dfs(Goal, [Goal]) :-
goal(Goal),!.
dfs(Start, [Start|Way]) :-
move(Start, N),
dfs(N, Way).
so when move(a,b) move to (b,c) dont go back to (b,a),
when run goSolveTheMaze(a,path).
The output should be path=[a,c,g,n].
What if you add a third argument to dfs which is a list of where you've already visited? You could then use \+/1 and member/2 to avoid returning to places you've already been.
For example, if you use the following:
move(a,b).
move(b,a).
move(a,c).
move(b,d).
move(b,e).
move(d,h).
move(d,i).
move(e,j).
move(e,k).
move(c,f).
move(c,g).
move(f,l).
move(f,m).
move(g,n).
move(g,o).
goal(n).
goSolveTheMaze(Start,Way) :-
dfs(Start, Way, [Start]),!.
dfs(Goal, [Goal], _) :-
goal(Goal),!.
dfs(Start, [Start|Way], Visited) :-
move(Start, N),
\+ member(N, Visited),
dfs(N, Way, [N|Visited]).
Then the query:
?- goSolveTheMaze(a, X).
Will produce the result:
X = [a, c, g, n]
Update in response to comment "can you tell me what \+ do?":
The \+ predicate is true when its argument cannot be proven. Therefore in the above example the line \+ member(N, Visited) means "when N is not a member of the list Visited".
See: https://www.swi-prolog.org/pldoc/man?predicate=%5C%2B/1
I am trying to wrote a predicate isway(A, B) which should work for cyclic graphs. The expected outcome I am trying to get is, if there a path exists between 2 nodes or not. example: if I ask isway(a, f), expect it to answer either yes or no. below is my code but it never works and always gives me false as an output.
%given facts
edge(a,b).
edge(a,c).
edge(b,c).
edge(c,d).
edge(c,e).
edge(d,e).
edge(f,g).
edge(g,h).
edge2(d,a).
edge2(h,f).
edge2(X,Y) :- edge(X,Y).
%my implementation
isway(A,B) :- edge2(A,B,[]).
edge2(A,B,V) :- edge(A,X), not(member(X,V)), (B = X ; edge2(X,B,[A|V])).
%my output
?- isway(b,a). %I expect true for this one
false
?- isway(a,f). %False for this is ok but I am not confident about my logic
false.
You can use tabling for computing the transitive closure of the edge relation:
edge(a,b).
edge(a,c).
edge(b,c).
edge(c,d).
edge(c,e).
edge(d,e).
edge(f,g).
edge(g,h).
edge(d,a). % acyclic
edge(h,f). % acyclic
:- table path/2.
path(X, Y) :- edge(X, Y).
path(X, Y) :- path(X, Z), path(Z, Y).
Then, the queries work as you expect:
?- path(a, f).
false.
?- path(b, a).
true.
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.
I'm trying to write a rule in my prolog program that determines if someone is the brother of someone else.
For example, if I type brother_of(chris, X) it will return christy because chris is the brother of christy. However, when I type this I get an existence exception. I've included facts to cover everything, but maybe it's a problem in my rule definition? The code is below.
/* Facts */
female(ella).
female(jodi).
female(sonya).
female(jane).
female(christy).
female(mary).
male(arnold).
male(chris).
male(louis).
male(mark).
father(arnold).
father(louis).
father(mark).
mother(ella).
mother(jodi).
mother(jane).
mother(mary).
father_of(arnold, chris). /* arnold is the father of chris */
father_of(arnold, christy).
father_of(louis, mark).
father_of(mark, arnold).
mother_of(mary, chris).
mother_of(mary, christy).
mother_of(jane, arnold).
mother_of(ella, sonya).
mother_of(jodi, ella).
mother_of(jodi, mark).
/* Rules */
brother_of(X, Y) :-
male(X),
((father_of(Z, X), father_of(Z, Y));
(mother_of(W, X), mother_of(W, Y))),
X =\= Y.
The operator =\= is used in arithmetic only (AFAIK), to see if two terms are different (non-unifiable) use the operator \=:
X \= Y.
Update: a brief introduction to the cut (!) goal: when the cut is used in a predicate, it means no more answers should be searched besides the already found ones (i.e. you are "cutting the remaining branches" in the search tree). Example:
first_child(X,Y) :-
father_of(X,Y), !.
?- first_child(arnold,Y).
Y = chris ;
no
After the cut is reached, all choice points before the cut are discarded (but new ones can be created after it). In you example, you know that if X and Y have the same father, it's irrelevant if they also have the same mother. So you can place the cut right after the "common father" part succeeds:
brother_of(X, Y) :-
male(X),
((father_of(Z, X), father_of(Z, Y), X \= Y, !); # If cut is reached, will not run the next line
(mother_of(W, X), mother_of(W, Y), X \= Y)).
Note however that using cut has many pitfalls (refer to "green cut" vs "red cut" in the linked Wikipedia article), but it's too much to describe here. (note how I repeated X \= Y - if I didn't do that the program would fail sometimes)
Lastly, I'd also like to point out that using ; is often discouraged when writing Prolog code (you can use when needed though). Instead, write it in two clauses:
brother_of(X, Y) :-
male(X),
father_of(Z, X),
father_of(Z, Y),
X \= Y,
!.
brother_of(X, Y) :-
male(X),
mother_of(W, X),
mother_of(W, Y),
X \= Y.
(this ; vs two clauses is a bit subjective, though, so I won't argue too much about it... just know that both ways are possible, and will produce the same result)
I've made the rules to obtain a path of a graph with the edges defined as follows:
graph(a,b).
graph(a,a).
graph(b,c).
but now I need to do it when the facts being, for example:
graph(a,[a,b,e]).
graph(b,[c,d]).
graph(d,[]).
I had this:
path(Origin, Dest, List) :- path(Origin, Dest, List, [Origin]).
path(X, X, List, Temp) :- reverse(Temp, List).
path(Origin, Dest, List, Temp) :- graph(Origin, Inter),
not(member(Inter, Temp)),
path(Inter, Dest, List, [Inter|Temp]).
and I know that problem is in graph(Origin, Inter), but I don't know how to tweak it so it can go inside the list, I've tried graph(Origin, [Inter|_]) but obviously it just checks the first one. Any help (even if it's not code) would be greatly appreciated.
Assuming directed graphs:
edge(X,Y) :- graph(X,Nodes), member(Y,Nodes).
I managed to solve it, in case someone else has the same problem:
node(X) :- graph(X,_).
allnodes(Nodes) :- setof(X, node(X), Nodes).
path(Origin,Dest,List) :- allnodes(X),
path(Origin, Dest, List1, X, X),
reverse(List1,List),!.
path(X,X,[X],_,_).
path(Origin,Dest,[Dest|List],[X|_],AN) :- graph(X, Inter),
member(Dest, Inter),
path(Origin,X,List,AN,AN).
path(Origin,Dest,List,[X|Y],AN) :- graph(X, Inter),
\+ member(Dest, Inter),
path(Origin,Dest,List,Y,AN).
Here's my solution that works on directed or undirected graphs, with or without cycles.
Using #larsmans suggestion you can make this work with adjacency-list like input.
edge(X,Y) :- graph(X,Nodes), member(Y,Nodes).
It also tries to find all paths, without revisiting.
c(1,2).
% ... c(X,Y) means X and Y are connected
d(X,Y):- c(X,Y).
d(X,Y):- c(Y,X).
% Use d instead of c to allow undirected graphs
findPathHelper(_, Begin, [], End):- d(Begin, End).
findPathHelper(Front, Begin, [Next|NMiddle], End):-
not(member(Begin,Front)),
d(Begin, Next),
append([Front,[Begin]], NFront),
findPathHelper(NFront, Next, NMiddle, End).
findPath(Start, End, Path):-
findPathHelper([], Start, Middle, End),
append([[Start],Middle,[End]], Path).