shortest path in GNU PROLOG - prolog

need help with PROLOG, if anyone can give direction to any of the questions:
introduction:
I have a water supply network, two water sources (river and lake).
Three repositories.
Three automatic sampling stations.
I converted the raw data to PROLOG information.
Now I need to write down a code to find the following:
1.What is the water source of each point - river or lake (assuming the source is the closest).
The user enters a point number. The answer is the source of the water.
What are the shortest routes from each point to each of the sources.
The user enters a point number. The answer is two lists.
What is the total consumer from the water source to each point.
The user enters a point number. The answer is total consumption.
Assuming a water quality alert was received from a monitoring station, which nodes should be stopped at
Water supply.
j-junction ,r-river, l-lake ,p-pump, t-tank
/* Water junction's database */
flowcalc(source,l,0).
flowcalc(source,r,0).
flowcalc(l,p10,0).
flowcalc(p10,j10,0).
flowcalc(r,p335,1231).
flowcalc(p335,j61,0).
flowcalc(t3,j20,99).
flowcalc(t1,j40,99).
flowcalc(t2,j50,99).
flowcalc(r,j60,1231).
flowcalc(j10,j101,14200).
flowcalc(j101,j103,1350).
flowcalc(j101,j105,2540).
flowcalc(j105,j107,1470).
flowcalc(j103,j109,3940).
flowcalc(j109,j111,2000).
flowcalc(j111,j115,1160).
flowcalc(j111,j113,1680).
flowcalc(j113,j115,2000).
flowcalc(j107,j115,1950).
flowcalc(j113,j193,1660).
flowcalc(j105,j263,2725).
flowcalc(j115,j117,2180).
flowcalc(j120,j119,730).
flowcalc(j117,j120,1870).
flowcalc(j120,j121,2050).
flowcalc(j121,j119,2000).
flowcalc(j121,j123,1500).
flowcalc(j121,j125,930).
flowcalc(j125,j127,3240).
flowcalc(j127,j20,785).
flowcalc(j127,j129,900).
flowcalc(j129,j131,6480).
flowcalc(j129,j139,2750).
flowcalc(j139,j141,2050).
flowcalc(j141,j143,1400).
flowcalc(j15,j143,1650).
flowcalc(j141,j145,3510).
flowcalc(j145,j147,2200).
flowcalc(j147,j149,880).
flowcalc(j149,j151,1020).
flowcalc(j151,j153,1170).
flowcalc(j153,j125,4560).
flowcalc(j151,j119,3460).
flowcalc(j119,j157,2080).
flowcalc(j157,j159,2910).
flowcalc(j159,j161,2000).
flowcalc(j161,163,430).
flowcalc(j163,j164,150).
flowcalc(j164,j166,490).
flowcalc(j265,j169,590).
flowcalc(j169,j167,60).
flowcalc(j187,j204,99.9).
flowcalc(j169,j171,1270).
flowcalc(j171,j173,50).
flowcalc(j171,j271,760).
flowcalc(j181,j35,30).
flowcalc(j181,j177,30).
flowcalc(j177,j179,30).
flowcalc(j179,j183,210).
flowcalc(j179,j40,1190).
flowcalc(j185,j184,99.9).
flowcalc(j185,183,510).
flowcalc(j184,j205,4530).
flowcalc(j185,j204,1325).
flowcalc(j189,j183,1350).
flowcalc(j187,j189,500).
flowcalc(j169,j269,646).
flowcalc(j191,j187,2560).
flowcalc(j267,j189,1230).
flowcalc(j191,j193,520).
flowcalc(j193,j195,360).
flowcalc(j195,j161,2300).
flowcalc(j197,j191,1150).
flowcalc(j111,j197,2790).
flowcalc(j173,j199,4000).
flowcalc(j199,j201,630).
flowcalc(j201,j203,120).
flowcalc(j199,j273,725).
flowcalc(j205,j207,1200).
flowcalc(j207,j206,450).
flowcalc(j207,j275,1430).
flowcalc(j206,j208,510).
flowcalc(j208,j209,885).
flowcalc(j209,j211,1210).
flowcalc(j211,j213,990).
flowcalc(j213,j215,4285).
flowcalc(j215,j217,1660).
flowcalc(j217,j219,2050).
flowcalc(j217,j225,1560).
flowcalc(j213,j229,2200).
flowcalc(j229,j231,1960).
flowcalc(j211,j237,2080).
flowcalc(j237,j229,790).
flowcalc(j237,j239,510).
flowcalc(j239,j241,35 ).
flowcalc(j241,j243,2200).
flowcalc(j241,j247,445).
flowcalc(j239,j249,430).
flowcalc(j247,j249,10).
flowcalc(j247,j255,1390).
flowcalc(j255,j50,925).
flowcalc(j255,j253,1100).
flowcalc(j255,j251,1100).
flowcalc(j251,j249,1450).
flowcalc(j257,j120,645).
flowcalc(j259,j257,350).
flowcalc(j259,j263,1400).
flowcalc(j257,j261,1400).
flowcalc(j161,j117,645).
flowcalc(j261,j263,350).
flowcalc(j267,j265,1580).
flowcalc(j267,j163,1170).
flowcalc(j189,j269,646).
flowcalc(j181,j271,260).
flowcalc(j273,j275,2230).
flowcalc(j205,j273,645).
flowcalc(j265,j163,1200).
flowcalc(j201,j275,300).
flowcalc(j269,j271,1290).
flowcalc(j61,j123,45500).
flowcalc(j60,j601,1).
flowcalc(j601,j61,1).
/* best route Finding (use shortest distance) */
/* Stage one find all possible routes */
go:- write('Enter place to start from:'),read(Start),
write('Enter place to end at:'),read(End),
getroute(Start,[End],route,Dist),
assert(route(route,Dist)),nl,fail.
/* Chose the best one */
go:- findall(Dist,route(_,Dist),Distlist),
min(Distlist,Min),route(route,Min),
write('best rout is:'),nl,
writelist(route),retracall(route(_,_)).
/* find routes sections */
getroute(Start,[Start|rest],[Start|rest],0).
getroute(Start,[junction|rest],route,Dist):-flowcalc(Next,junction,D1),not_member(Next,rest),getroute(Start,[Next,junction|rest],route,D2),Dist is D1 + D2.
getroute(Start,[junction|rest],route,Dist):-flowcalc(junction,Next,D1),not_member(Next,rest),getroute(Start,[Next,junction|rest],route,D2),Dist is D1 + D2.
/* Check if not member */
not_member(_,[]):-!.
not_member(X,[Y|l]):-X\=Y,not_member(X,l).
/* find the minimum length route */
min(last,last).
min([l|lt],Min):-min(lt,SubMin),(l<SubMin,Min=l);Min=SubMin.
/* display the route */
writelist([]).
writelist([l|lt]):-write(l),nl,writelist(lt).

Friends I was able to answer the first 3 questions, but I have a very difficult performance problem, each time it takes the software to search for a route and a lot of time. I would love if you could direct, maybe change search method?
for sample check connection between two water sources
water_shortest_path(l, r, MinCost, Path).
takes hour to response.
path(X, Y, N, Path) :- path(X, Y, N, [], Path).
path(X, Y, N, Seen, [X]) :-
\+ check_member(X, Seen),
edge(X, Y, N).
path(X, Z, N, Seen, [X|T]) :-
\+ check_member(X, Seen),
edge(X, Y, N0),
path(Y, Z, N1, [X|Seen], T),
\+ check_member(X, T),
N is N0 + N1.
check_member(X, L) :- once(member(X, L)).
member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs).
water_shortest_path(X, Y, MinCost, Path) :-
path(X, Y, MinCost, Path),
\+ (path(X, Y, LowerCost, OtherPath),
OtherPath \= Path,
LowerCost =< MinCost).
edge(l,l,0).
edge(r,r,0).
edge(l,p10,0).
edge(p10,j10,0).
edge(r,p335,1231).
edge(p335,j61,0).
edge(t3,j20,99).
edge(t1,j40,99).
edge(t2,j50,99).
edge(r,j60,1231).
edge(j10,j101,14200).
edge(j101,j103,1350).
edge(j101,j105,2540).
edge(j105,j107,1470).
edge(j103,j109,3940).
edge(j109,j111,2000).
edge(j111,j115,1160).
edge(j111,j113,1680).
edge(j113,j115,2000).
edge(j107,j115,1950).
edge(j113,j193,1660).
edge(j105,j263,2725).
edge(j115,j117,2180).
edge(j120,j119,730).
edge(j117,j120,1870).
edge(j120,j121,2050).
edge(j121,j119,2000).
edge(j121,j123,1500).
edge(j121,j125,930).
edge(j125,j127,3240).
edge(j127,j20,785).
edge(j127,j129,900).
edge(j129,j131,6480).
edge(j129,j139,2750).
edge(j139,j141,2050).
edge(j141,j143,1400).
edge(j15,j143,1650).
edge(j141,j145,3510).
edge(j145,j147,2200).
edge(j147,j149,880).
edge(j149,j151,1020).
edge(j151,j153,1170).
edge(j153,j125,4560).
edge(j151,j119,3460).
edge(j119,j157,2080).
edge(j157,j159,2910).
edge(j159,j161,2000).
edge(j161,j163,430).
edge(j163,j164,150).
edge(j164,j166,490).
edge(j265,j169,590).
edge(j169,j167,60).
edge(j187,j204,99.9).
edge(j169,j171,1270).
edge(j171,j173,50).
edge(j171,j271,760).
edge(j181,j35,30).
edge(j181,j177,30).
edge(j177,j179,30).
edge(j179,j183,210).
edge(j179,j40,1190).
edge(j185,j184,99.9).
edge(j185,j183,510).
edge(j184,j205,4530).
edge(j185,j204,1325).
edge(j189,j183,1350).
edge(j187,j189,500).
edge(j169,j269,646).
edge(j191,j187,2560).
edge(j267,j189,1230).
edge(j191,j193,520).
edge(j193,j195,360).
edge(j195,j161,2300).
edge(j197,j191,1150).
edge(j111,j197,2790).
edge(j173,j199,4000).
edge(j199,j201,630).
edge(j201,j203,120).
edge(j199,j273,725).
edge(j205,j207,1200).
edge(j207,j206,450).
edge(j207,j275,1430).
edge(j206,j208,510).
edge(j208,j209,885).
edge(j209,j211,1210).
edge(j211,j213,990).
edge(j213,j215,4285).
edge(j215,j217,1660).
edge(j217,j219,2050).
edge(j217,j225,1560).
edge(j213,j229,2200).
edge(j229,j231,1960).
edge(j211,j237,2080).
edge(j237,j229,790).
edge(j237,j239,510).
edge(j239,j241,35 ).
edge(j241,j243,2200).
edge(j241,j247,445).
edge(j239,j249,430).
edge(j247,j249,10).
edge(j247,j255,1390).
edge(j255,j50,925).
edge(j255,j253,1100).
edge(j255,j251,1100).
edge(j251,j249,1450).
edge(j257,j120,645).
edge(j259,j257,350).
edge(j259,j263,1400).
edge(j257,j261,1400).
edge(j161,j117,645).
edge(j261,j263,350).
edge(j267,j265,1580).
edge(j267,j163,1170).
edge(j189,j269,646).
edge(j181,j271,260).
edge(j273,j275,2230).
edge(j205,j273,645).
edge(j265,j163,1200).
edge(j201,j275,300).
edge(j269,j271,1290).
edge(j61,j123,45500).
edge(j60,j601,1).
edge(j601,j61,1).
edge(p10,l,0).
edge(j10,p10,0).
edge(p335,r,1231).
edge(j61,p335,0).
edge(j20,t3,99).
edge(j40,t1,99).
edge(j50,t2,99).
edge(j60,r,1231).
edge(j101,j10,14200).
edge(j103,j101,1350).
edge(j105,j101,2540).
edge(j107,j105,1470).
edge(j109,j103,3940).
edge(j111,j109,2000).
edge(j115,j111,1160).
edge(j113,j111,1680).
edge(j115,j113,2000).
edge(j115,j107,1950).
edge(j193,j113,1660).
edge(j263,j105,2725).
edge(j117,j115,2180).
edge(j119,j120,730).
edge(j120,j117,1870).
edge(j121,j120,2050).
edge(j119,j121,2000).
edge(j123,j121,1500).
edge(j125,j121,930).
edge(j127,j125,3240).
edge(j20,j127,785).
edge(j129,j127,900).
edge(j131,j129,6480).
edge(j139,j129,2750).
edge(j141,j139,2050).
edge(j143,j141,1400).
edge(j143,j15,1650).
edge(j145,j141,3510).
edge(j147,j145,2200).
edge(j149,j147,880).
edge(j151,j149,1020).
edge(j153,j151,1170).
edge(j125,j153,4560).
edge(j119,j151,3460).
edge(j157,j119,2080).
edge(j159,j157,2910).
edge(j161,j159,2000).
edge(j163,j161,430).
edge(j164,j163,150).
edge(j166,j164,490).
edge(j169,j265,590).
edge(j167,j169,60).
edge(j204,j187,99.9).
edge(j171,j169,1270).
edge(j173,j171,50).
edge(j271,j171,760).
edge(j35,j181,30).
edge(j177,j181,30).
edge(j179,j177,30).
edge(j183,j179,210).
edge(j40,j179,1190).
edge(j184,j185,99.9).
edge(j183,j185,510).
edge(j205,j184,4530).
edge(j204,j185,1325).
edge(j183,j189,1350).
edge(j189,j187,500).
edge(j269,j169,646).
edge(j187,j191,2560).
edge(j189,j267,1230).
edge(j193,j191,520).
edge(j195,j193,360).
edge(j161,j195,2300).
edge(j191,j197,1150).
edge(j197,j111,2790).
edge(j199,j173,4000).
edge(j201,j199,630).
edge(j203,j201,120).
edge(j273,j199,725).
edge(j207,j205,1200).
edge(j206,j207,450).
edge(j275,j207,1430).
edge(j208,j206,510).
edge(j209,j208,885).
edge(j211,j209,1210).
edge(j213,j211,990).
edge(j215,j213,4285).
edge(j217,j215,1660).
edge(j219,j217,2050).
edge(j225,j217,1560).
edge(j229,j213,2200).
edge(j231,j229,1960).
edge(j237,j211,2080).
edge(j229,j237,790).
edge(j239,j237,510).
edge(j241,j239,35 ).
edge(j243,j241,2200).
edge(j247,j241,445).
edge(j249,j239,430).
edge(j249,j247,10).
edge(j255,j247,1390).
edge(j50,j255,925).
edge(j253,j255,1100).
edge(j251,j255,1100).
edge(j249,j251,1450).
edge(j120,j257,645).
edge(j257,j259,350).
edge(j263,j259,1400).
edge(j261,j257,1400).
edge(j117,j161,645).
edge(j263,j261,350).
edge(j265,j267,1580).
edge(j163,j267,1170).
edge(j269,j189,646).
edge(j271,j181,260).
edge(j275,j273,2230).
edge(j273,j205,645).
edge(j163,j265,1200).
edge(j275,j201,300).
edge(j271,j269,1290).
edge(j123,j61,45500).
edge(j601,j60,1).
edge(j61,j601,1).

Related

Prolog Domino Solution

I need an algorithm that given a set of domino pieces, returns every possible end to the game.
I have already found this one, Prolog domino game, but it only adds pieces to the beggining of the set, so it doesn't give you every possible solution.
I replaced this [5-4, 4-3, 3-2, 2-1], with this [[5,4], [4,3], [3,2], [2,1]], and tried adding this line domino_order(In, X, [Out|[X,Y]]) :- select(Piece, In, Remaining), swap_or_not(Piece, [X,Y]), domino_order(Remaining, Y, Out)., but it doesn't work.
writing down the detailed logic would lead to somewhat complex code.
I suggest instead to have a quick check for validity, and let Prolog work out the insertion points.
domino :-
Spare = [4-7,3-4], Curr = [1-2,2-3],
domino_row_add_spare(Curr, Spare, R),
writeln(R).
domino_row_add_spare(C, [], C).
domino_row_add_spare(C, Sps, U) :-
append(L, R, C),
select(X-Y, Sps, Rest),
(append(L, [X-Y|R], C1) ; append(L, [Y-X|R], C1)),
valid(C1),
domino_row_add_spare(C1, Rest, U).
valid([_]).
valid([_-X,X-Y|R]) :- valid([X-Y|R]).

Cycle route program in prolog

I have created a program in prolog which should give me all possible routes between two stations. In each route each station should only get visited once. My code so far is:
% facts
connection(s1,s2).
connection(s1,s4).
connection(s2,s3).
connection(s2,s5).
connection(s3,s4).
connection(s4,s5).
connection(s5,s6).
connection(s6,s1).
% predicates
direction1(X,Y) :- connection(X,Y).
direction2(X,Y) :- connection(Y,X).
route1(X,Y,R):- route1(X,Y,[],R).
route1(X,Y,_,[X,Y]) :- direction1(X,Y).
route1(X,Y,L,R) :- \+direction1(X,Y), direction1(X,Z), \+member(Z,L), route1(Z,Y,[Z|L],RZ), R=[X|RZ].
route2(X,Y,R):- route2(X,Y,[],R).
route2(X,Y,_,[X,Y]) :- direction2(X,Y).
route2(X,Y,L,R) :- \+direction2(X,Y), direction2(X,Z), \+member(Z,L), route2(Z,Y,[Z|L],RZ), R=[X|RZ].
route(X,Y,R) :- route1(X,Y,R); route2(X,Y,R).
The problem is that prolog doesn't give me all routes, for exampel when I ask for route[s1,s4,R], prolog doesn't give me the route [s1,s2,s3,s4]. I think it is caused by "+direction1(X,Y)" and "+direction2(X,Y)". But I need this to prevent prolog visiting a station multiple times in a route. Any ideas how to fix this?
Thanks in advance!
A minimally invasive fix would be to remove the \+direction1(X,Y) that you correctly identified as the source of this failure, and to add another \+ member(X, L) guard in the definition of route1/4.
EDIT: The above does not suffice. Here is a cleaner rewrite of the whole thing, with more readable formatting and variable names:
route1(X,Y,R):- route1(X,Y,[X],R). % note that X is visited immediately
route1(X,Y,_,[X,Y]) :- direction1(X,Y).
route1(X, Y, Visited, Route) :-
direction1(X, Z),
Z \= Y,
\+ member(Z, Visited),
route1(Z, Y, [Z|Visited], Route1),
Route = [X|Route1].
You should then probably unify the two variants of the route predicates: One of them only finds routes that are only along "direction 1" edges and the other only the ones along "direction 2" edges. In general, you will want to be able to traverse any edge in any direction.

Easy prolog queries

I am very new to prolog and although I’ve read some books I can definitely tell that my programming brain can’t think the Prolog way. The problem I would like to solve is pretty simple (I believe). I will describe it via an example.
Let’s say that I have a graph that contains 4 “types” of nodes and 3 edges that connect the nodes. The types can be A, B, C or D and as you can see from the image below (see Figure 1), A can be connected with B and C (A_To_B and A_To_C edges respectively), while C can be connected to D (C_To_D edge). There’s also an additional rule not shown on the picture: A can be connected to at most 1 C.
I would like to express these simple rules in Prolog to solve the problem shown in the second picture. There are 3 nodes which type is missing (labeled X?, Y? and Z?). By applying the above rules in my mind I can easily find that X? and Z? are of B type (as A can connect to no more than 1 Cs) and Y? is of type D as C can only connect to D.
Could please provide me any help on that? I am not writing just to pick the solution. I would like to learn Prolog as well so any suggestion on a book that explains Prolog to people who have never worked on such concepts before like me would be very welcome.
EDIT: Example that fails
I came up with the following two examples:
For example 1, the rules are
can_connect(a,b,_).
can_connect(a,c,1).
link(1,2).
type(1,a).
type(2,_).
The possible solutions returned are [b,c] which is correct as we request at most 1 link from A to C meaning that 0 links is also acceptable.
In example 2 the rules change to the following:
can_connect(a,b,_).
can_connect(a,c,**2**).
link(1,2).
link(1,3).
type(1,a).
type(2,_).
type(3,c).
Running the code here returns [c] which is wrong. b is also an acceptable solution as we require again at most 2 A to C links which means that having only 1 is OK.
I spent this weekend trying to figure out the solution. First of all, I believe that it works as intended in Example 1 simply because there's no link from A to C instantiated in the proposed solution (where checking if 2 can be b), so the can_connect(a,c,1) is not checked so the proposed solution is getting accepted. In Example 2, there's one A to C link already there so the can_connect(a,c,2) is checked and the solution where node 2 has type b is rejected as the rule checks if there are exactly 2 and not at most 2 links from A to C.
I find a solution which works at these scenarios but fails at some others. Here it is:
% value #3 is the lower bound and #4 is the upper bound.
can_connect(a,b,0,500).
% A C node can be connected by 0, 1 or 2 A nodes
can_connect(a,c,0,2).
can_connect(d,c,1,1).
can_connect(c,e,0,1).
%The same as previous solution
link(1,2).
link(1,3).
% No change here
type(1,a).
type(2,_).
type(3,c).
% No change here
node_type(N, NT) :-
type(N, NT),
nonvar(NT),
!. % assume a node has only one type
% No change here
node_type(N, NT) :-
assoc_types(Typed),
maplist(check_connections(Typed), Typed),
memberchk(N:NT, Typed).
% No change here
assoc_types(Typed) :-
findall(N, type(N, _), L),
maplist(typed, L, Typed).
% No change here
typed(N, N:T) :-
type(N, T),
member(T, [a,b,c]).
% Changes here
check_connections(Graph, N:NT) :-
forall(link(N, M), (
memberchk(M:MT, Graph),
can_connect(NT, MT, L, U),
findall(X, (link(N, X), memberchk(X:MT, Graph)), Ts),
mybetween(L, U, Ts),
forall(can_connect(NT, Y, LM, UM), (
findall(P, (link(N,P),memberchk(P:Y, Graph)), Ss),
length(Ss, SsSize ),
SsSize>=LM,
SsSize=<UM
))
)).
% It is used to find if the length of a list is between two limits.
mybetween(Lower, Upper, MyList) :-
length(MyList, MySize),
MySize=<Upper,
MySize>=Lower.
This solution fails in this example
In this example, X? must be always b, Y? must always be C and Z? must always be D. It finds X? and Y? correctly but not Z?. I believe after some debugging that this is due the fact that in the current implementation I only check the can_connect rules that are related with links that start from a node and not that end to a node. However, I am not sure at all about that.
Any help is appreciated.
the representation of the problem needs to disambiguate nodes names, so we can express the links appropriately
now we can write
can_connect(a,b,_).
can_connect(a,c,1).
can_connect(c,d,_).
link(1,2).
link(1,3).
link(1,4).
link(4,5).
link(4,6).
link(7,4).
link(7,8).
type(1,a).
type(2,b).
type(3,_).
type(4,c).
type(5,d).
type(6,_).
type(7,a).
type(8,_).
The underscore (anonymous variable) in Prolog plays a role similar to NULL in SQL, it can assume any value.
So, a first snippet
node_type(N, NT) :- type(N, NT), nonvar(NT), !. % assume a node has only one type
can be used to express what we know about the problem.
Facts can_connect/3 then can be read like
a can connect to any number of b
a can connect to just 1 c
etc
Where we don't know the node type, a complex rule is needed, that infers the type of source node from the type of target node, and accounts for the counting constraint, something like
node_type(N, NT) :-
link(M, N),
type(M, MT),
can_connect(MT, NT, C),
aggregate(count, Y^(link(M, Y), type(Y, NT)), C).
?- forall(between(1,8,N), (node_type(N,T),writeln(N:T))).
1:a
2:b
3:b
4:c
5:d
6:d
7:a
8:b
true.
edit if your Prolog doesn't have library(aggregate), from where aggregate/3 has been loaded, you can try
node_type(N, NT) :-
link(M, N),
type(M, MT),
can_connect(MT, NT, C),
findall(t, (link(M, Y), type(Y, NT)), Ts), length(Ts, C).
edit first of all, the updated graph, marked with types where known:
my previous code worked only under very restricted assumptions. Here is something more general, that checks the constraints over the full graph (as was suggested by #false comment), with a 'generate and test' approach.
node_type(N, NT) :-
assoc_types(Typed),
maplist(check_connections(Typed), Typed),
memberchk(N:NT, Typed).
assoc_types(Typed) :-
findall(N, type(N, _), L),
maplist(typed, L, Typed).
typed(N, N:T) :- type(N, T), member(T, [a,b,c,d]).
check_connections(Graph, N:NT) :-
forall(link(N, M), (
memberchk(M:MT, Graph),
can_connect(NT, MT, C),
aggregate(count, X^(link(N, X), memberchk(X:MT, Graph)), C)
)).
now ?- node_type(4,X). fails...

Route goes infinite loop prolog

Just begin for prolog and have a practice for route question
train(a,b).
train(b,a).
train(b,c).
train(c,b).
route(X,Y,[]) :-
train(X,Y)
; train(Y,X).
route(X,Y,[H|T]) :-
route(X,H,[]),
route(H,Y,T).
by doing this route/3 The first rule give two direct connected places an empty set states that there is a route. Second rule states the case where there are intermediate places to reach from one to another. but when I query this and I got a loop route.
Someone said to have a helper predicate visited_route/4 to keep track of the places already visited, but don't know how this way works. Hints or example would be help.
The problem with your current solution is that the Prolog solver generates infinite tracks like [a,b,a,b,a,b,a...] never reaching the end.
You may want to do, is to exclude cases, where X, Y, or H is a member of T (this may be the visited_route/4 predicate). This way, you won't ever pass the same node twice.
Edit
I've sat down and freshened my Prolog knowledge a little bit, creating such code, which seems to work:
train(a,b).
%train(b,a). Your predicate is symmetric, you don't need to specify both directions
train(b,c).
%train(c,b).
train(c,d).
train(c,e).
train(d,f).
train(e,f).
visited_route(X, Y, [], V) :-
( train(X,Y) ; train(Y,X) ),
not(member(Y, V)).
visited_route(X, Y, [H | T], V) :-
visited_route(X, H, [], [X | V]),
visited_route(H, Y, T, [X | V]).
route(X,Y,R) :-
visited_route(X, Y, R, []).
Visited route has an additional list containing all nodes visited on a way from X to Y (not counting Y). When solver finds a way leading from X to Y in first visited_route predicate, it then checks if the route doesn't go through already visited node, and discards the candidate if so.

Find All Relatives with Prolog

I'm having trouble wrapping my head around how I would return a list of everyone related to a certain person. So, if I say relatives(A,B), A would be a person and B is a list of all of the people related to that person. I can write any additional rules needed to assist in doing this. Here is what I have so far.
man(joe).
man(tim).
man(milan).
man(matt).
man(eugene).
woman(mary).
woman(emily).
woman(lily).
woman(rosie).
woman(chris).
parent(milan, mary).
parent(tim, milan).
parent(mary, lily).
parent(mary, joe).
parent(mary, matt).
parent(chris, rosie).
parent(eugene, mary).
parent(eugene, chris).
cousins(A, B) :- parent(C, A), parent(D, B), parent(E, C), parent(E, D), not(parent(C, B)), not(parent(D, A)), A \=B.
paternalgrandfather(A, C) :- man(A), man(B), parent(B, C), parent(A, B).
sibling(A, B) :- parent(C, A), parent(C, B), A \= B.
Can someone guide me as to how I would go about doing this? Thanks.
I think that you should concentrate on the 'true' relation, i.e. parent(Old,Jung), other predicates are irrelevant here. The obvious assumption it's that atoms occurring in parent/2 are identifiers (i.e. names are unique). From this picture seems that all persons here are relatives:
Then your problem should be equivalent to find all connected vertices in parent relation. You can implement a depth first visit, passing down the list of visited nodes to avoid loops (note that you need to go back to parents and down to children!), something like
relatives(Person, Relatives) :-
relatives([], Person, [Person|Relatives]).
relatives(Visited, Person, [Person|Relatives]) :-
findall(Relative, immediate(Person, Visited, R), Immediates),
... find relatives of immediates and append all in relatives.
immediate(Person, Visited, R) :-
(parent(Person, R) ; parent(R, Person)),
\+ member(R, Visited).
See if you can complete this snippet. Note the order of arguments in relatives/3 is choosen to easy maplist/3.
If you are willing to study more advanced code, SWI-Prolog library(ugraph) offers a reachable(+Vertex, +Graph, -Vertices) predicate that does it on a list based graph representation.
Here the SWI-Prolog snippet to get the image (a file to be feed to dot):
graph(Fact2) :-
format('digraph ~s {~n', [Fact2]),
forall(call(Fact2, From, To), format(' ~s -> ~s;~n', [From, To])),
format('}\n').
you can call in this way:
?- tell('/tmp/parent.gv'),graph(parent),told.
and then issue on command line dot -Tjpg /tmp/parent.gv | display
I think you should use builtin predicate findall/3 and maybe sort/2 to avoid duplicates
It would go along these lines:
relatives(Person, Relatives):-
findall(Relative, is_relative(Person, Relative), LRelatives),
sort(LRelatives, Relatives).
is_relative(Person, Relative):-
(cousins(Person, Relative) ; paternalgrandfather(Person, Relative) ; sibling(Person, Relative)).
You might want to add more clauses to is_relative to get more relationships.

Resources