domains
/* will allow us cooperate with better names, for me this is like #typedef in C++ */
town = symbol
distance = unsigned
rib = r(town,town,distance)
tlist = town*
rlist = rib*
predicates
nondeterm way(town,town,rlist,distance)
nondeterm route(town,town,rlist,tlist,distance)
nondeterm route1(town,tlist,rlist,tlist,distance)
nondeterm ribsmember(rib,rlist)
nondeterm townsmember(town,tlist)
nondeterm tsp(town,town,tlist,rlist,tlist,distance)
nondeterm ham(town,town,tlist,rlist,tlist,distance)
nondeterm shorterRouteExists(town,town,tlist,rlist,distance)
nondeterm alltown(tlist,tlist)
nondeterm write_list(tlist)
clauses
/*
Nothing special with write_list.
If list is empty we do nothing,
and if something there we write head and call ourselves for tail.
*/
write_list([]).
write_list([H|T]):-
write(H,' '),
write_list(T).
/* Is true if town X is in list of towns... */
townsmember(X,[X|_]).
townsmember(X,[_|L]):-
townsmember(X,L).
/* Is true if rib X is in list of ribs... */
ribsmember(r(X,Y,D),[r(X,Y,D)|_]).
ribsmember(X,[_|L]):-
ribsmember(X,L).
/* Is true if Route consists of all Towns presented in second argument */
alltown(_,[]).
alltown(Route,[H|T]):-
townsmember(H,Route),
alltown(Route,T).
/* Is true if there is a way from Town1 to Town2, and also return distance between them */
way(Town1,Town2,Ways,OutWayDistance):-
ribsmember(r(Town1,Town2,D),Ways),
OutWayDistance = D.
%/*
/* If next is uncommented then we are using non-oriented graph*/
way(Town1,Town2,Ways,OutWayDistance):-
ribsmember(r(Town2,Town1,D),Ways), /*switching direction here...*/
OutWayDistance = D.
%*/
/* Is true if we could build route from Town1 to Town2 */
route(Town1,Town2,Ways,OutRoute,OutDistance):-
route1(Town1,[Town2],Ways,OutRoute,T1T2Distance),
%SWITCH HERE
way(Town2,Town1,Ways,LasDist), /* If you want find shortest way comment this line*/
OutDistance = T1T2Distance + LasDist. /* And make this: OutDistance = T1T2Distance.*/
route1(Town1,[Town1|Route1],_,[Town1|Route1],OutDistance):-
OutDistance = 0.
/* Does the actual finding of route. We take new TownX town and if it is not member of PassedRoute,
we continue searching with including TownX in the list of passed towns.*/
route1(Town1,[Town2|PassedRoute],Ways,OutRoute,OutDistance):-
way(TownX,Town2,Ways,WayDistance),
not(townsmember(TownX,PassedRoute)),
route1(Town1,[TownX,Town2|PassedRoute],Ways,OutRoute,CompletingRoadDistance),
OutDistance = CompletingRoadDistance + WayDistance.
shorterRouteExists(Town1,Town2,Towns,Ways,Distance):-
ham(Town1,Town2,Towns,Ways,_,Other),
Other < Distance.
/* calling tsp(a,a,.... picks any one connected to a town and calls another tsp*/
tsp(Town1,Town1,Towns,Ways,BestRoute,MinDistance):-
way(OtherTown,Town1,Ways,_),
tsp(Town1,OtherTown,Towns,Ways,BestRoute,MinDistance).
/*Travelling Salesman Problem is Hammilton way which is the shortes of other ones.*/
tsp(Town1,Town2,Towns,Ways,BestRoute,MinDistance):-
ham(Town1,Town2,Towns,Ways,Route,Distance),
not(shorterRouteExists(Town1,Town2,Towns,Ways,Distance)),
BestRoute = Route,
MinDistance = Distance.
/*Hammilton route from Town1 to Town2 assuming that Town2->Town1 way exists.*/
ham(Town1,Town2,Towns,Ways,Route,Distance):-
route(Town1,Town2,Ways,Route,Distance),
%SWITCH HERE
alltown(Route,Towns), % if you want simple road without including all towns you could uncomment this line
write_list(Route),
write(" \tD = ",Distance,"\n").
% fail.
goal
/* EXAMPLE 1
AllTowns = [a,b,c,d],
AllWays = [r(a,b,1),r(a,c,10),r(c,b,2),r(b,c,2),r(b,d,5),r(c,d,3),r(d,a,4)],
*/
/* EXAMPLE 2 */
AllTowns = [a,b,c,d,e],
AllWays = [r(a,c,1),r(a,b,6),r(a,e,5),r(a,d,8),r(c,b,2),r(c,d,7),r(c,e,10),r(b,d,3),r(b,e,9),r(d,e,4)],
tsp(a,a,AllTowns,AllWays,Route,Distance),
%SWITCH HERE
% tsp(a,b,AllTowns,AllWays,Route,Distance),
write("Finally:\n"),
write_list(Route),
write(" \tMIN_D = ",Distance,"\n").
/* will allow us cooperate with better names, for me this is like #typedef in C++ */
town = symbol
distance = unsigned
rib = r(town,town,distance)
tlist = town*
rlist = rib*
predicates
nondeterm way(town,town,rlist,distance)
nondeterm route(town,town,rlist,tlist,distance)
nondeterm route1(town,tlist,rlist,tlist,distance)
nondeterm ribsmember(rib,rlist)
nondeterm townsmember(town,tlist)
nondeterm tsp(town,town,tlist,rlist,tlist,distance)
nondeterm ham(town,town,tlist,rlist,tlist,distance)
nondeterm shorterRouteExists(town,town,tlist,rlist,distance)
nondeterm alltown(tlist,tlist)
nondeterm write_list(tlist)
clauses
/*
Nothing special with write_list.
If list is empty we do nothing,
and if something there we write head and call ourselves for tail.
*/
write_list([]).
write_list([H|T]):-
write(H,' '),
write_list(T).
/* Is true if town X is in list of towns... */
townsmember(X,[X|_]).
townsmember(X,[_|L]):-
townsmember(X,L).
/* Is true if rib X is in list of ribs... */
ribsmember(r(X,Y,D),[r(X,Y,D)|_]).
ribsmember(X,[_|L]):-
ribsmember(X,L).
/* Is true if Route consists of all Towns presented in second argument */
alltown(_,[]).
alltown(Route,[H|T]):-
townsmember(H,Route),
alltown(Route,T).
/* Is true if there is a way from Town1 to Town2, and also return distance between them */
way(Town1,Town2,Ways,OutWayDistance):-
ribsmember(r(Town1,Town2,D),Ways),
OutWayDistance = D.
%/*
/* If next is uncommented then we are using non-oriented graph*/
way(Town1,Town2,Ways,OutWayDistance):-
ribsmember(r(Town2,Town1,D),Ways), /*switching direction here...*/
OutWayDistance = D.
%*/
/* Is true if we could build route from Town1 to Town2 */
route(Town1,Town2,Ways,OutRoute,OutDistance):-
route1(Town1,[Town2],Ways,OutRoute,T1T2Distance),
%SWITCH HERE
way(Town2,Town1,Ways,LasDist), /* If you want find shortest way comment this line*/
OutDistance = T1T2Distance + LasDist. /* And make this: OutDistance = T1T2Distance.*/
route1(Town1,[Town1|Route1],_,[Town1|Route1],OutDistance):-
OutDistance = 0.
/* Does the actual finding of route. We take new TownX town and if it is not member of PassedRoute,
we continue searching with including TownX in the list of passed towns.*/
route1(Town1,[Town2|PassedRoute],Ways,OutRoute,OutDistance):-
way(TownX,Town2,Ways,WayDistance),
not(townsmember(TownX,PassedRoute)),
route1(Town1,[TownX,Town2|PassedRoute],Ways,OutRoute,CompletingRoadDistance),
OutDistance = CompletingRoadDistance + WayDistance.
shorterRouteExists(Town1,Town2,Towns,Ways,Distance):-
ham(Town1,Town2,Towns,Ways,_,Other),
Other < Distance.
/* calling tsp(a,a,.... picks any one connected to a town and calls another tsp*/
tsp(Town1,Town1,Towns,Ways,BestRoute,MinDistance):-
way(OtherTown,Town1,Ways,_),
tsp(Town1,OtherTown,Towns,Ways,BestRoute,MinDistance).
/*Travelling Salesman Problem is Hammilton way which is the shortes of other ones.*/
tsp(Town1,Town2,Towns,Ways,BestRoute,MinDistance):-
ham(Town1,Town2,Towns,Ways,Route,Distance),
not(shorterRouteExists(Town1,Town2,Towns,Ways,Distance)),
BestRoute = Route,
MinDistance = Distance.
/*Hammilton route from Town1 to Town2 assuming that Town2->Town1 way exists.*/
ham(Town1,Town2,Towns,Ways,Route,Distance):-
route(Town1,Town2,Ways,Route,Distance),
%SWITCH HERE
alltown(Route,Towns), % if you want simple road without including all towns you could uncomment this line
write_list(Route),
write(" \tD = ",Distance,"\n").
% fail.
goal
/* EXAMPLE 1
AllTowns = [a,b,c,d],
AllWays = [r(a,b,1),r(a,c,10),r(c,b,2),r(b,c,2),r(b,d,5),r(c,d,3),r(d,a,4)],
*/
/* EXAMPLE 2 */
AllTowns = [a,b,c,d,e],
AllWays = [r(a,c,1),r(a,b,6),r(a,e,5),r(a,d,8),r(c,b,2),r(c,d,7),r(c,e,10),r(b,d,3),r(b,e,9),r(d,e,4)],
tsp(a,a,AllTowns,AllWays,Route,Distance),
%SWITCH HERE
% tsp(a,b,AllTowns,AllWays,Route,Distance),
write("Finally:\n"),
write_list(Route),
write(" \tMIN_D = ",Distance,"\n").
Let's take a look on the following graph:
Here is output of my program:
a e d b c D = 15
a e d b c D = 15
a d e b c D = 24
a e b d c D = 25
a b e d c D = 27
a d b e c D = 31
a e d b c D = 15
a d e b c D = 24
a e b d c D = 25
a b e d c D = 27
a d b e c D = 31
a b d e c D = 24
Finally:
a e d b c MIN_D = 15
Which is correct! :)
Finally:
a e d b c MIN_D = 15
Which is correct! :)
Also I did not mention before I faced with issue of getting minimum of the value returned from predicate.
And this link provided help for me:



This is very interesting article. You generalized this problem on oriented and not oriented graphs.
ReplyDeleteAlso I like demonstration of predicate NOT in prolog for finding shortest way.
Thanks, forensic. Do you have you explanation how NOT works in Prolog. Don't you want to share this with community?
ReplyDeleteSo, ok. Prolog uses negation as failure which is based on Closed World Assumption. This means that what is not currently known to be true and cannot be proved to be true, is false.
ReplyDeleteHey Andriy, I read most of the article in this blog and all are awesome, your software engineering perspective is really notifiable...well, Andriy did u take this problem as a graph problem and solved using Hamiltonian Circuit path finding algorithm or used some AI techniques too ( I mean A*, Minimum spanning tree as a heuristics...)? Would you tell me, please? Thanks in advance!
ReplyDelete403 Predicate name or section keyword expected.
ReplyDeleteTHIS ERROR OCCURS DURING COMPILING. PLZ SOLVE THIS,,
I'm NOT responsible for solving your compilation errors!
Delete(It worked for me perfectly at that time. It might not work for you because of dozen of errors starting with different compiler.)
i m using borland prolog compiler..
ReplyDeleteerror :-Predicate name or section keyword expected.
plz,,,mention this problem,,
it's important to me cause i have to submit this program with
output in my college submission file. this is the only program left in my file.
i searched lots on internet,,i got code here only for borland prolog.
help to solve this problem.
As far as I remember back in University days we used 'visual prolog'.
Delete