Want to print the path,but getting errors - prolog

domains
list=symbol*
predicates
path(symbol,symbol)
solve(symbol,symbol,list)
insert(symbol,list,list)
clauses
path(a,b).
path(b,c).
path(c,d).
path(d,e).
path(a,d).
path(c,e).
solve(X, Z, P):-
path(X,Z),
insert(Z,Temp,P),
P=Temp.
solve(X,Z,P):-
path(X,Y),
insert(Y,Temp,P),
P=Temp,
solve(Y,Z,P).
insert(X,[X|Tail],Tail).
insert(X,[Y|Tail],[Y|Tail1]):-
insert(X,Tail,Tail1).
Want to print the path which i have followed in going from one point to another.But getting errors.For examples, i want:
goal
solve(a,c,P).
Answer:P=[a,b,c]

I don't get what your solve predicate does. Here is my guess about how it should be :
solve(Start, End, [Start|PathMinusStart]) :-
solve_(Start, End, PathMinusStart).
solve_(Start, End, [End]) :-
path(Start, End).
solve_(Start, End, [Waypoint|Path]) :-
path(Start, Waypoint),
solve_(Waypoint, End, Path).
solve will give you the paths one after another using the ; to browse them (well, I guess at least since I don't know anything about the prolog implementation you're using).

search_path(Node, End, Temp, Path) :- path(Node,End),reverse([End | [Node | Temp]], Path).
search_path(Node, End, Temp, Path) :-
path(Node, Next),
not(member(Node, Temp)),
search_path(Next, End, [Node | Temp], Path).
solve(Start, End, Path) :- search_path(Start, End, [], Path).

Related

Prevent cycle in Depth first search using prolog

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

Finding the path length of an Acyclic Graph in Prolog

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 ?

Traversal through Room

I keep getting false for path_to_phone(1, 16, Path). and cannot figure out where the error is in the code.
door(1,2).
door(1,7).
door(2,1).
door(2,8).
door(3,8).
door(4,8).
door(4,9).
door(5,9).
door(5,6).
door(6,9).
door(7,1).
door(7,8).
door(7,9).
door(7,10).
door(7,11).
door(7,12).
door(7,13).
door(7,14).
door(8,2).
door(8,3).
door(8,4).
door(8,7).
door(9,4).
door(9,5).
door(9,6).
door(9,7).
door(10,7).
door(11,7).
door(12,7).
door(13,7).
door(14,7).
door(14,15).
door(15,16).
door(16,15).
phone(5).
phone(9).
phone(16).
rooms_connected(X, Y) :- door(X, Y), door(Y, X).
path_to_phone(Start, End, Path) :-
move(Start, End,[Start], Room),
reverse(Room,Path).
move(Start, End, Path, [End|Path]) :-
rooms_connected(Start, End),
phone(End).
move(Start, Middle, Visit, Path) :-
rooms_connected(Start, End),
End \== Middle,
\+member(End, Visit),
move(End, Middle, [End|Visit], Path).
From an aesthetical point of view, it would look better like this:
move(Start, End, Visit, Path) :- rooms_connected(Start, Middle),
End \== Middle,
\+member(Middle, Visit),
move(Middle, End, [Middle|Visit], Path).
The problem is your definition of rooms_connected because it forces to have the connection both ways. If thats what you intended you have to put in the file doors(15,14) and others, because as it is now, it cannot find a path.
If not you can change it to:
rooms_connected(X, Y) :- door(X, Y); door(Y, X).
This means either door(X,Y) or door(Y,X).
I think should be simpler, no need to pass around the confusing Middle:
path_to_phone(Start, End, Path) :-
move(Start, [Start], [End|RPath]),
reverse([End|RPath], Path).
move(From, Visit, [Phone|Visit]) :-
door(From, Phone),
phone(Phone).
move(From, Visit, Path) :-
door(From, Next),
\+memberchk(Next, Visit),
move(Next, [Next|Visit], Path).

Breadth First Search in Prolog

I'm new to Prolog and currently implementing DFS (depth-first search) and BFS (breadth-first search) algorithms. My DFS works fine as the code below, but the BFS is terminated and aborted when it reaches the leaf node (it doesn't backtrack and continue searching).
I also read some sample code about this but there are some functions they don't define like s(Node, NewNode)... so it's hard to understand, or the version use Queue is too complicated.
Here is my code:
Some ground functions:
%connected(+Start, +Goal, -Weight)
connected(1,7,1).
connected(1,8,1).
connected(1,3,1).
connected(7,4,1).
connected(7,20,1).
connected(7,17,1).
connected(8,6,1).
connected(3,9,1).
connected(3,12,1).
connected(9,19,1).
connected(4,42,1).
connected(20,28,1).
connected(17,10,1).
connected2(X,Y,D) :- connected(X,Y,D).
connected2(X,Y,D) :- connected(Y,X,D).
next_node(Current, Next, Path) :-
connected2(Current, Next, _),
not(member(Next, Path)).
DFS implement:
depth_first(Goal, Goal, _, [Goal]).
depth_first(Start, Goal, Visited, [Start|Path]) :-
next_node(Start, Next_node, Visited),
write(Visited), nl,
depth_first(Next_node, Goal, [Next_node|Visited], Path).
BFS implement:
breadth_first(Goal, Goal, _,[Goal]).
breadth_first(Start, Goal, Visited, Path) :-
findall(X,
(connected2(X,Start,_),not(member(X,Visited))),
[T|Extend]),
write(Visited), nl,
append(Visited, [T|Extend], Visited2),
append(Path, [T|Extend], [Next|Path2]),
breadth_first(Next, Goal, Visited2, Path2).
The Path is something like the Queue list.
For example when call DFS:
?- depth_first(1, 28, [1], P).
BFS:
?- breadth_first(1, 28, [1], []).
First, the usual notion of s(A,B) is just like your connect2(A,B,_).
You should make your interface predicates explicit:
depth_first( Start, Goal, Path):-
depth_first( Start, Goal, [Start], Path).
Maintaining a queue in BFS is not complicated at all. Instead of Visited, have VisitedLists queue (pop from front; add at end; thus FIFO):
consed( A, B, [B|A]).
bfs( Goal, [Visited|Rest], Path) :- % take one from front
Visited = [Start|_],
Start \== Goal,
findall( X,
( connected2(X, Start, _), \+ member(X, Visited) ),
[T|Extend]),
maplist( consed(Visited), [T|Extend], VisitedExtended), % make many
append( Rest, VisitedExtended, UpdatedQueue), % put them at the end
bfs( Goal, UpdatedQueue, Path ).
When the goal is reached, Path is instantiated:
bfs(Goal, [[Goal|Visited]|_], Path):-
reverse([Goal|Visited], Path).
The interface call needs to be adjusted correspondingly. It should be
breadth_first( Start, Goal, Path):- bfs( Goal, [[Start]], Path).
later note: repeated appending of course causes quadratic slowdown, so for efficiency this should be re-written with difference lists (also a straightforward task).

graph path in prolog

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).

Resources