Finding a cycle in a simple Prolog graph - prolog

I am having trouble with this simple Prolog graph, i am trying to test for a cycle and have no idea why it isn't working. isPath seems to work, the problem is with cycle function which is supposed to check if there is a cycle on the given letter. Can anyone help?
path(a, b).
path(a, c).
path(a, f).
path(b, e).
path(c, d).
path(d, a).
path(d, h).
path(e, f).
path(e, g).
path(e, h).
path(f, g).
path(f, b).
path(h, g).
isPath(X, X) :-
path(X, Y).
isPath(X, Y) :-
path(X, Z),
isPath(Z, Y).
cycleIt(J) :-
isPath(J, K),
isPath(K, J).

You can use DCG !
How can you find cycles ? You need to find a node From, linked by an edge to another node Via, then from Via, you need to find a path, ending in From, and you must not have cycle during this search.
so :
cycle --> [X], {path(X, Y)},search(Y, X, []).
% the search is ended
search(From, To, _Visited)--> {path(From,To)}, [From,To].
% we try an another path using Via, which has not been already visited
search(From, To, Visited)--> {path(From,Via), \+member(Via, Visited)}, [From], search(Via, To, [Via|Visited]).
The result
?- phrase(cycle, A,[]).
A = [a, c, d, a] ;
A = [b, e, f, b] ;
A = [c, d, a, c] ;
A = [d, a, c, d] ;
A = [e, f, b, e] ;
A = [f, b, e, f] ;
false.

Related

Merge two predicates in one - Prolog

I am a beginner at prolog and required to write a predicate path(Start, Dest, Path) for metro stations application using backtracking. Given some facts: connected(x,y) describing the connected stations, I managed to do the following
%% Some facts (for illustration):
connected(a,b).
connected(b,c).
connected(c,d).
connected(d,e).
connected(e,f).
%% Direction A (e.g from b to e)
path1(Start, End, [[Start,End]]):- (connected(Start,End) ; connected(End,Start)),!.
path1(Start, End, [[Start,X]|Path]):-
connected(Start, X),
path1(X, End, Path).
%% Direction B (e.g from f to A)
path2(Start, End, [[Start,End]]):- (connected(Start,End) ; connected(End,Start)),!.
path2(Start, End, [[Start,X]|Path]):-
connected(X, Start),
path2(X, End, Path).
%% And for the required predicate:
path(Start, End, Path):-
path1(Start, End, Path)
;
path2(Start, End, Path).
The above predicates works properly and as required, but what I want to do is to merge these two predicates into a single one in a better way and I don't know exactly how to do so. Anyone can help?
Thanks in advance.
EDIT:
I modified it to the following:
path(Start, End, [[Start,End]], _):- (connected(Start,End) ; connected(End,Start)),!.
path(Start, End, [[Start,X]|Path], Direction):-
(Direction == 0,
connected(Start, X),
path(X, End, Path,0))
;
(Direction == 1,
connected(X, Start),
path(X, End, Path,1))
%% And for the required predicate:
path(Start, End, Path):-
path(Start, End, Path, 0)
;
path(Start, End, Path, 1).
but still need to remove more of the repetitive code lines.
A possible solution is:
path(Start, End, Path) :-
path(_, Start, End, Path).
path(_, Start, Start, []).
path(Direction, Start, End, [[Start,X]|Path]) :-
link(Direction, Start, X),
path(Direction, X, End, Path).
link(forward, X, Y) :- connected(X, Y).
link(backward, X, Y) :- connected(Y, X).
connected(a,b).
connected(b,c).
connected(c,d).
connected(d,e).
connected(e,f).
Examples:
?- path(c, a, P).
P = [[c, b], [b, a]] ;
false.
?- path(a, c, P).
P = [[a, b], [b, c]] ;
false.
?- path(D, a,c,P).
D = forward,
P = [[a, b], [b, c]] ;
false.
?- path(D, c, a, P).
D = backward,
P = [[c, b], [b, a]] ;
false.

How can I get my maze program to create and print two route-lists to the console?

link(entry, a).
link(a, b).
link(b, c).
link(c, d).
link(d, e).
link(b, e).
link(e, f).
link(f, c).
link(f, exit).
route(1, 2) :-
member(1, [entry,a,b,c,d,e,f,exit]),
member(2, [entry,a,b,e,f,exit]).
route(X, Z, [entry,a,b,c,d,e,f,exit]) :- route(X, Z,[R],[entry,a,b,c,d,e,f,exit]).
route(X, Z, [exit,f,e,d,c,b,a,entry], [entry,a,b,c,d,e,f,exit]) :-
reverse(X, Y, [exit,f,e,d,c,b,a,entry], [entry,a,b,c,d,e,f,exit]),
route(Y, Z),
write(X).
Despite hours of reading, I am struggling to understand how I can make my program generate and display the listed paths in the console window. Is there anyone who can provide advice? I have basically no programming experience, prolog is probably the bulk of my knowledge, and that's insufficient.
route(X, Y, [X, Y]) :- link(X,Y).
route(X, Y, [X | TY]) :-
link(X, T),
route(T, Y, TY).
With route as above, the following code searches for the path in increasing order of length.
?- length(X, _), route(entry,exit, X).
X = [entry, a, b, e, f, exit] ;
X = [entry, a, b, c, d, e, f, exit] ;
X = [entry, a, b, e, f, c, d, e, f, exit] ;
X = [entry, a, b, c, d, e, f, c, d, e, f, exit] ;
X = [entry, a, b, e, f, c, d, e, f, c, d, e, f, exit]
Since we did not constrain route predicate to disallow repeated nodes, we have loops at higher lengths of the path.
EDIT:
The following works SWI-Prolog check if your system has dif/2. Using maplist here allows us to do increasing path length search.
route(X, Y, [X, Y]) :- link(X,Y).
route(X, Y, [X|TY]) :-
link(X, T),
maplist(dif(X), TY), % X is different from all nodes in TY
route(T, Y, TY).
If you do not have dif use \+ member(X, TY) after the route(T, Y, TY).
This gives
?- route(entry, exit, X).
X = [entry, a, b, e, f, exit] ;
X = [entry, a, b, c, d, e, f, exit] ;
After the couple of solutions it will loop endlessly. If you want that to stop that happening you can constrain the length of path to number of existing nodes
?- between(2, 8, N), length(X, N), route(entry, exit, X).
N = 6,
X = [entry, a, b, e, f, exit] ;
N = 8,
X = [entry, a, b, c, d, e, f, exit] ;
false.

My Prolog program makes a list, but I can't figure out how to make it stop after 2 entries

For some practise; I'm trying to create a program that simulates a maze and shows every possible route between entry and exit. The code creates one of the lists, however it doesn't show both and doesn't stop when it's found them (route 1: entry,a,b,e,f,exit and route 2: entry,a,b,c,d,e,f,exit), and continuously loops into bigger and bigger routes.
% length(X, _), route(entry,exit, X).
%Facts, indicating an adjacent link between one room and another.
link(entry, a).
link(a, b).
link(b, c).
link(c, d).
link(d, e).
link(b, e).
link(e, f).
link(f, c).
link(f, exit).
%Searches for the path in an increasing order of length 'route'.
route(X, Y, [X, Y]) :- link(X,Y).
route(X, Y, [X | TY]) :- link(X, T), route(T, Y, TY).
Example from console:
| ?- route(entry, exit, A).
A = [entry,a,b,c,d,e,f,exit] ;
A = [entry,a,b,c,d,e,f,c,d,e,f,exit] ;
A = [entry,a,b,c,d,e,f,c,d,e,f,c,d,e,f,exit] ;
A = [entry,a,b,c,d,e,f,c,d,e,f,c,d,e,f,c,d,e,f,exit]
Can anyone help me?
The simplest way to make this iterative deepening path search stop from looking for further successes after the first one is to cut at the end of the goal:
?- length(X, _), route(entry,exit, X), !.
X = [entry,a,b,e,f,exit].
Once success brings Prolog's "finger" past the !, any attempt to redo and move the finger back leftwards is disallowed. So Prolog stops after the first success.
For multiple solutions: hopefully there is something like library(solution_sequences) around.
There we have limit(+Count,:Goal):
?- limit(2,route(entry, exit, A)).
A = [entry,a,b,c,d,e,f,exit] ;
A = [entry,a,b,c,d,e,f,c,d,e,f,exit].
The source code for limit, which is written in Prolog. It uses state-changing predicates, but can it be written without those?
1. First path predicate is the base case.
2. Second path predicate searches all possible routes for the given Start and End Node.
link(entry, a).
link(a, b).
link(b, c).
link(c, d).
link(d, e).
link(b, e).
link(e, f).
%link(f, c).
link(f, exit).
path(Node,Node,[Node]):-!.
path(StartN,EndN,[StartN|List]):-
link(StartN,NextN),
path(NextN,EndN,List).
Example:
?-path(entry,exit,Route).
Route = [entry, a, b, c, d, e, f, exit]
Route = [entry, a, b, e, f, exit]
?-path(entry,a,Route).
Route = [entry, a]
?-path(entry,b,Route).
Route = [entry, a, b]
?-path(entry,c,Route).
Route = [entry, a, b, c]
false
?-path(entry,d,Route).
Route = [entry, a, b, c, d]
false
?-path(entry,e,Route).
Route = [entry, a, b, c, d, e]
Route = [entry, a, b, e]
?-path(entry,f,Route).
Route = [entry, a, b, c, d, e, f]
Route = [entry, a, b, e, f]
Note: I had to comment link(f,c) to get the correct route for exit or else it'll give you stack limit exceeded, I'm not sure why.

Need to re-structure prolog code

I have the following code:
edge(a,b,5).
edge(b,a,5).
edge(b,c,3).
edge(c,a,2).
edge(c,d,4).
edge(d,b,6).
edge(c,f,4).
edge(f,c,4).
edge(e,c,5).
edge(f,e,7).
edge(g,a,3).
edge(d,g,8).
edge(e,g,2).
edge(f,h,3).
edge(h,i,2).
edge(i,j,3).
edge(j,h,4).
edge(d,h,1).
edge(j,f,6).
%edge(l,k,-1).
%edge(k,l,4).
%edge(a,z,-2).
vertex(a).
vertex(b).
vertex(c).
vertex(d).
vertex(e).
vertex(f).
vertex(g).
vertex(h).
vertex(i).
vertex(j).
member(A, [A|_]) :- !.
member(A, [_|Y]) :- member(A, Y).
path(X,Y) :- pathHelper(X,Y,[],0).
pathHelper(X,X,L, W) :- write([X|L]), write(W).
pathHelper(X,Y,L, W) :- edge(X,Z,C),\+member(Z,L),F is W+C,pathHelper(Z,Y,[X|L], F).
I was wondering how to turn path into a function with 4 arguments so when called like path(a, h, L, W) gives
L = [a, b, c, d, h],
W = 13 ;
L = [a, b, c, f, h],
W = 15 ;
Try to look into the concept of accumulator(they call it accumulator in prolog,Extra argument for result) it's interesting and btw it's not much work:
path(X,Y,Distance,Result):-
pathHelper(X,Y,[],0,Distance,Result).
pathHelper(X,X,L,W,W,P):-
reverse([X|L],P).
pathHelper(X,Y,L, W,Distance,Result):-
edge(X,Z,C),
\+member(Z,L),
F is W+C,
pathHelper(Z,Y,[X|L], F,Distance,Result).

Prolog creating a list of sets from ith elements of lists

I have list structure
L=[[a,b,c,d],[a,f,c,h]]
Length of L can be greater than 2.I want to unite the elements of list so that L or a NewL become
L=[a,[b,f],c,[d-h]]
This is probably what you want:
unite([[],[]], []).
unite([[X|Ls], [X|Rs]], [X|Rest]) :- unite([Ls, Rs], Rest).
unite([[L|Ls], [R|Rs]], [[L,R]|Rest]) :- L \= R, unite([Ls, Rs], Rest).
However, I agree with #false because this is a strange API and there are a lot of unhandled edge cases.
What you're requiring is an aggregation schema. I think I got it:
unite(Ls, [E|Es]) :-
aggreg(Ls, E, Ns),
unite(Ns, Es).
unite(_, []).
aggreg(L, E, LLs) :-
maplist(first, L, Fs, LLs),
setof(X, member(X, Fs), S),
( [E] = S -> true ; E = S ).
first([E|Es], E, Es).
yields
?- L=[[a,b,c,d],[a,f,c,h],[a,f,c,g]],unite(L,U).
L = [[a, b, c, d], [a, f, c, h], [a, f, c, g]],
U = [a, [b, f], c, [d, g, h]] ;
L = [[a, b, c, d], [a, f, c, h], [a, f, c, g]],
U = [a, [b, f], c] .
I think that a cut after the first solution would be well placed (use once/1 for that).
Note that the schema it's rather general: just substitute in setof/3 some more applicative task (if any) than unification (you could call into your DB, for instance).

Resources