I want to find the shortest path between two nodes in Prolog. I figured how to find all the paths between two nodes, but unfortunately the following code falls into loops:
arc(a,b).
arc(b,a).
arc(b,c).
arc(c,b).
arc(c,d).
arc(d,c).
path(X,Y,[arc(X,Y)]) :-
arc(X,Y).
path(X,Y,[arc(X,Z)|P]) :-
arc(X,Z),
path(Z,Y,P).
The code run is:
?- path(a,c,R).
R = [arc(a, b), arc(b, c)] ;
R = [arc(a, b), arc(b, a), arc(a, b), arc(b, c)] ;
R = [arc(a, b), arc(b, a), arc(a, b), arc(b, a), arc(a, b), arc(b, c)]
....
So, my question is : How to get all paths without looping infinitely?
at the end of the day, i will get the length of the list and find the minimum.
Please if possible, give solutions that are ISO Prolog.
Note: here is the updated code, by I still have problem. Apparently the member predicate doesn't work when checking against a fact rather than an atom.
xxx([]).
path(X,Y,[arc(X,Y)]) :-
arc(X,Y).
path(X,Y,[arc(X,Z)|P]) :-
arc(X,Z)
,xxx(L)
,member(arc(X,Z),L)->
!;
(member(arc(Z,X),L)->
!;
(append(L,[arc(X,Z)],R),retract(xxx(_)),assert(xxx(R)),path(Z,Y,P))).
and my member predicate is:
member(X,[X|T]).
member(X,[H|T]) :- member(X,T).
Thank you.
You could look into the cut operator "!", when you only want one solution.
To avoid falling into endless loops, you should maybe use an accumulator list storing already visited nodes.
We use meta-predicate
path/4
in combination with the definition ofarc/2
that you gave:The definition of
path/4
excludes all cycles.To get the shortest paths we need to look at all solutions!
To show this is actually so, let's expand your definition of
arc/2
like this:Let's say we want to "get all shortest paths from
a
tod
", so we query:In above query there are two distinct shortest paths from
a
tod
.To get both, we must look at all paths---or use a smarter meta-predicate (left as homework).