Need to re-structure prolog code - prolog

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

Related

Encoding program in prolog

I am currently working on an encoding program in prolog.
In the first place I want to cut a word in pieces
For example: friends should look like:
[[F,R,I][R,I,E][I,E,N][E,N,D][N,D,S]]
For the moment I have something like this but can't understand why is the program not working when I try on a word.
It is always answering false.
couper([X1,X2,X3|L],[L1|ResQ]):-
L1 = [X1,X2,X3],
couper([X2,X3|L],ResQ).
couper([_,_|[]] , []).
couper([] , []).
couper([_|[]] , []).
Your program seems to work:
?- atom_chars(alpha,L),couper(L,Triplets).
L = [a, l, p, h, a],
Triplets = [[a, l, p], [l, p, h], [p, h, a]] ;
Although it can be written easier:
couper([X1,X2,X3|L],[[X1,X2,X3]|ResQ]):-
couper([X2,X3|L],ResQ).
couper([_,_] , []). % Only two chars left or only two to begin with
couper([_] , []). % Only one char to begin with
couper([] , []). % No chars to begin with
You can also try:
?- findall([A,B,C], append(_,[A,B,C|_],[f,r,i,e,n,d,s]), T).
T = [[f, r, i], [r, i, e], [i, e, n], [e, n, d], [n, d, s]].
As a rule:
couper(L, T) :-
findall([A,B,C], append(_, [A,B,C|_], L), T).
Examples:
?- couper([f,r,i,e,n,d,s], T).
T = [[f, r, i], [r, i, e], [i, e, n], [e, n, d], [n, d, s]].
?- couper([e,x,a,m,p,l,e,s], T).
T = [[e, x, a], [x, a, m], [a, m, p], [m, p, l], [p, l, e], [l, e, s]].
?- couper([t,w,o], T).
T = [[t, w, o]].
?- couper([t,o], T).
T = [].
NOTE In Prolog, uppercase letters are variables. Thus, the predicate must be called with a list of lowercase letters (perhaps, this is the cause of your problem).

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.

Finding a cycle in a simple Prolog graph

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.

Prolog lists transforming

I want to transform a list in this format:
C=[via(A,B,C,D),via(G,T,H,U),via(J,O,L,P)]
into the following:
F=[(C,D),(H,U),(L,P)]
The letters from F correspond to the letters from C.
It could be something like:
transform([], []).
transform([via(_, _, X, Y)|T)], [(X, Y)|TT) :-
transform(T, TT).
Using library(lambda) it comes down to:
..., maplist(\via(_,_,X,Y)^(X,Y)^true, C, F), ...
several Prologs (like SWI-Prolog I'm using here, in library(apply)) have maplist:
1 ?- [user].
|: transform(via(_,_,C,D),(C,D)).
(ctrl+D here)
true.
2 ?- X = [via(A,B,C,D),via(G,T,H,U),via(J,O,L,P)], maplist(transform,X,Y).
X = [via(A, B, C, D), via(G, T, H, U), via(J, O, L, P)],
Y = [ (C, D), (H, U), (L, P)].

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