road(london, paris, 135).
road(paris, london, 135).
road(paris, madrid, 250).
road(madrid, paris, 250).
road(madrid, barcelona, 70).
road(barcelona, madrid, 70).
route(X, Y, [X|Y], N) :-
road(X, Y, N).
route(X, Y, [X|T], N) :-
road(X, Z, A),
route(Z, Y, [_|T], B),
N is A + B.
This is a sample code of the problem I am facing. My test input is
?- route(london, barcelona, R, 455).
This input will keep re-iterating through london-paris and paris-london, however I have noticed that it will find the route from london-barcelona if I remove, the cycle paris-london.
My question is if there is any way I can implement a predicate which will allow me to ignore a cycle.
You can do these modifications:
road(london, paris, 135).
road(paris, madrid, 250).
road(madrid, paris, 250).
road(madrid, barcelona, 70).
road(barcelona, madrid, 70).
path(From, To, List, N) :-
route(From, To, [From], N).
route(X, Y, Passed_city, N) :-
road(X, Y, N).
route(X, Y, Passed_city, N) :-
road(X, Z, A),
\+ member(Z, Passed_city),
route(Z, Y, [Z|Passed_city], B),
N is A + B.
and call the query
?- path(london, barcelona, R, 455).
What I did is to create a new rule for path/4
to insert the first city From in the list which contains all the cities you passed, like so: route(From, To, [From], N)
.
Then I've inserted the goal \+ member(Z, Passed_city)
in the body of the second rule.
\+
means "not provable", so
\+ member(Z, Passed_city)
is true if member(Z, Passed_city)
fails, that is, if Z
is not in Passed_city
.
Now work..
road(london, paris, 135).
road(paris, madrid, 250).
road(madrid, paris, 250).
road(madrid, barcelona, 70).
road(barcelona, madrid, 70).
path(From, To, List, N) :-
route(From, To, [From], N).
route(X, Y, Passed_city, N) :-
road(X, Y, N), Passed_city = [Passed_city|Y].
route(X, Y, Passed_city, N) :-
road(X, Z, A),
\+ member(Z, Passed_city),
route(Z, Y, [Z|Passed_city], B),
N is A + B.