Related
I have a question to you:
I have an exercise that says:
Let there be given edges in the directed graph arc (a, b), arc (b, c), arc (a, d), arc (d, e), arc (d, f), arc (f, a) and arc (f, g). Test go / 2, go1 / 3 predicates.
I need to know why Prolog answers false for the following query:
? - go1 (a, b, X).
I have a graph illustrated below and a code pasted below.
The code is here:
arc(a,b).%these are the edges.
arc(b,c).
arc(a,d).
arc(d,e).
arc(d,f).
arc(f,a).
arc(f,g).
go(X,X).
go(X,Y):-arc(X,Z),go(Z,Y).
% without arc(f,a):
% yes ?- go(a,c).
% no ?- go(d,c).
% no ?- go(f,a).
% yes ?- go(a,g).
%
% with arc(f,a):
% yes ?- go(a,c).
% out of local stack ?- go(a,g).
member1(H,[H|_]).
member1(H,[_|T]):-member1(H,T).
go1(X,X,_).
go1(X,Y,T):-arc(X,Z),not(member1(Z,[X|T])),go1(Z,Y,[X|T]).
% with arc(f,a):
% yes ?- go1(a,c,[]).
% yes ?- go1(a,g,[]).
So guys, please help me to figure out why it happens? Why does Prolog answer false for the following query:
? - go1 (a, b, X).
I've tried to trace the query and I've gotten the answer that is below:
[trace] ?- go1(a,b,X).
Call: (8) go1(a, b, _982) ? creep
Call: (9) arc(a, _1202) ? creep
Exit: (9) arc(a, b) ? creep
^ Call: (9) not(member1(b, [a|_982])) ? creep
Call: (10) member1(b, [a|_982]) ? creep
Call: (11) member1(b, _982) ? creep
Exit: (11) member1(b, [b|_1206]) ? creep
Exit: (10) member1(b, [a, b|_1206]) ? creep
^ Fail: (9) not(user:member1(b, [a|_982])) ? creep
Redo: (9) arc(a, _1202) ? creep
Exit: (9) arc(a, d) ? creep
^ Call: (9) not(member1(d, [a|_982])) ? creep
Call: (10) member1(d, [a|_982]) ? creep
Call: (11) member1(d, _982) ? creep
Exit: (11) member1(d, [d|_1206]) ? creep
Exit: (10) member1(d, [a, d|_1206]) ? creep
^ Fail: (9) not(user:member1(d, [a|_982])) ? creep
Fail: (8) go1(a, b, _982) ? creep
false.
Well, what I don't understand is why we have here the answer below:
Exit: (11) member1(b, [b|_1206]) ? creep
Exit: (10) member1(b, [a, b|_1206]) ? creep
^ Fail: (9) not(user:member1(b, [a|_982])) ? creep
Why does the Prolog not recognize that there is an edge from a to b? Why does it say that b is in the list that there is only [a] after all. Why does this call fail there? What's the reason of the query failure?
You pass it a free variable X, so that means that the:
member(b, [a|X]).
call will succeed, indeed:
?- member(b, [a|X]).
X = [b|_2142] ;
X = [_2140, b|_2148] ;
X = [_2140, _2146, b|_2154]
Now not(member(Z, [X|T])) will succeed, given that the search of member(Z, [X|T]) fails, but here it will always succeed, since a free variable can always be grounded to a list that contains Z, hence it fails.
If you call it with:
go1 (a, b, [])
it will succeed, since then member(b, [a]) will indeed fail.
You can define a predicate that will reconstruct the path with:
go1(A, B, P) :-
go1(A, B, P, []).
go1(A, A, [A], _).
go1(A, C, [A|T], V) :-
arc(A, B),
\+ member(B, [A|V]),
go1(B, C, T, [A|V]).
and thus call it with go1(A, B, P) to obtain the path P.
I need to find elements which exist in both lists S1 and S2 and I need to print out these elements (R).
The problem is that when I type bendri([a,b,c,d],[d,b,e],R), it returns the correct result [b,d], but it doesn't stop. If you press ; symbol, then it keeps on checking again and returns b, after that - d.
Why is this happening? It should only return [b,d] and end its job.
bendri(S1,S2,R) :-
skaiciavimai(S1,S2,R).
skaiciavimai([],_,[]).
skaiciavimai([First|Tail], S2, [First|Rest]) :-
member(First, S2),
skaiciavimai(Tail, S2, Rest).
skaiciavimai([_|Tail], S2, Rest) :-
skaiciavimai(Tail, S2, Rest).
Your problem is that the third clause of skaiciavimai/3 also succeeds on backtracking even if the second clause succeeded. I guess you want to skip the third clause if the second clause succeeds.
To do that you can add a check in the third clause:
skaiciavimai([First|Tail], S2, Rest) :-
\+ (member(First, S2)),
skaiciavimai(Tail, S2, Rest).
so that the third clause fails if the head of the first list is found in S2.
Simple story: ; means that Prolog should look for alternatives, and since bendri(A,B,C) is defined as "C is a list of elements that occur in both A and B" (according to your definition), it will print all possible results. You can see this on the trace below (added below because the trace is rather long).
Resolution
The problem is that you introduce a decision point in your skaiciavimai/3 predicate: indeed given the first argument is a list with at least one element (of the form [_|_]), the Prolog environment can select both the second and third clause: after it has tried the skaiciavimai([First|Tail], S2, [First|Rest]) clause successfully, it can also aim to select the next clause skaiciavimai([_|Tail], S2, Rest). Since there is no predicate that prevents that selection from being successful, it will also find a solution omitting the head element. You can solve this by adding an additional constraint in the last clause:
skaiciavimai([],_,[]).
skaiciavimai([First|Tail], S2, [First|Rest]) :-
member(First, S2),
skaiciavimai(Tail, S2, Rest).
skaiciavimai([First|Tail], S2, Rest) :-
\+ member(First,S2),
skaiciavimai(Tail, S2, Rest).
The \+ means something like the logical not (although one must be careful, because not is a problematic topic in Logic Programming). So now we prevent Prolog from selecting the third clause successfully given First is a member of S2. When you use this code the result of your query is:
?- bendri([a,b,c,d],[d,b,e],R).
R = [b, d] ;
false.
We have thus altered the definition of skaiciavimai/3 it now reads something like: "C is a list of all elements that occur in A that occur in B as well." since in order to omit an element from A (third clause), it should not be a member of B.
Towards a better predicate
In Prolog the aim is to make predicate multidirectional. Indeed, you want to be able to call predicates in different directions. bendri/3 can be implemented such that bendri(A,B,[a,c]) also returns A = [a, c], B = [a, c] ;, etc. (which is the case here). In designing predicates one needs to take into account multiple uses of the predicate.
Trace
?- trace.
true.
[trace] ?- bendri([a,b,c,d],[d,b,e],R).
Call: (6) bendri([a, b, c, d], [d, b, e], _G360) ? creep
Call: (7) skaiciavimai([a, b, c, d], [d, b, e], _G360) ? creep
Call: (8) lists:member(a, [d, b, e]) ? creep
Fail: (8) lists:member(a, [d, b, e]) ? creep
Redo: (7) skaiciavimai([a, b, c, d], [d, b, e], _G360) ? creep
Call: (8) skaiciavimai([b, c, d], [d, b, e], _G360) ? creep
Call: (9) lists:member(b, [d, b, e]) ? creep
Exit: (9) lists:member(b, [d, b, e]) ? creep
Call: (9) skaiciavimai([c, d], [d, b, e], _G448) ? creep
Call: (10) lists:member(c, [d, b, e]) ? creep
Fail: (10) lists:member(c, [d, b, e]) ? creep
Redo: (9) skaiciavimai([c, d], [d, b, e], _G448) ? creep
Call: (10) skaiciavimai([d], [d, b, e], _G448) ? creep
Call: (11) lists:member(d, [d, b, e]) ? creep
Exit: (11) lists:member(d, [d, b, e]) ? creep
Call: (11) skaiciavimai([], [d, b, e], _G451) ? creep
Exit: (11) skaiciavimai([], [d, b, e], []) ? creep
Exit: (10) skaiciavimai([d], [d, b, e], [d]) ? creep
Exit: (9) skaiciavimai([c, d], [d, b, e], [d]) ? creep
Exit: (8) skaiciavimai([b, c, d], [d, b, e], [b, d]) ? creep
Exit: (7) skaiciavimai([a, b, c, d], [d, b, e], [b, d]) ? creep
Exit: (6) bendri([a, b, c, d], [d, b, e], [b, d]) ? creep
R = [b, d] ;
Redo: (11) lists:member(d, [d, b, e]) ? creep
Fail: (11) lists:member(d, [d, b, e]) ? creep
Redo: (10) skaiciavimai([d], [d, b, e], _G448) ? creep
Call: (11) skaiciavimai([], [d, b, e], _G448) ? creep
Exit: (11) skaiciavimai([], [d, b, e], []) ? creep
Exit: (10) skaiciavimai([d], [d, b, e], []) ? creep
Exit: (9) skaiciavimai([c, d], [d, b, e], []) ? creep
Exit: (8) skaiciavimai([b, c, d], [d, b, e], [b]) ? creep
Exit: (7) skaiciavimai([a, b, c, d], [d, b, e], [b]) ? creep
Exit: (6) bendri([a, b, c, d], [d, b, e], [b]) ? creep
R = [b] ;
This answer follows up on #gusbro's answer... Why not preserve logical purity? It's easy!
Simply replace the third clause by:
skaiciavimai([First|Tail], S2, Rest) :-
non_member(First, S2),
skaiciavimai(Tail, S2, Rest).
And define non_member/2 like this:
non_member(X, Es) :-
maplist(dif(X), Es).
This is a follow-up to this logically-pure answer presented earlier.
:- use_module(library(lambda)).
bendri(Es, Fs, Xs) :-
% ^^
% ||
% |+----------------+\
% || ||
% vv vv
tfilter(Fs+\E^memberd_t(E,Fs), Es, Xs).
% ^^
% ||
% \+------------------ Fs has global scope
Sample query given by the OP:
?- bendri([a,b,c,d], [d,b,e], Xs).
Xs = [b,d].
Many predicates define some kind of an acyclic path built from edges defined via a binary relation, quite similarly to defining transitive closure. A generic definition is thus called for.
Note that the notions defined in graph theory do not readily match what is commonly expected. Most notably, we are not interested in the edges' names.
Worse, also graph theory has changed a bit, introducing the notion of walk, noting
Traditionally, a path referred to what is now usually known as an open walk. Nowadays, when stated without any qualification, a path is usually understood to be simple, meaning that no vertices (and thus no edges) are repeated. (The term chain has also been used to refer to a walk in which all vertices and edges are distinct.)
So my question is: How to name and define this functionality?
What I have done so far is to define:
path(Rel_2, Path, X0,X)
The first argument has to be the continuation of the relation which is an incomplete goal that lacks two further arguments. Then comes either the Path or the pair of vertices.
Example usage
n(a, b).
n(b, c).
n(b, a).
?- path(n,Xs, a,X).
Xs = [a], X = a
; Xs = [a, b], X = b
; Xs = [a, b, c], X = c
; false.
Implementation
:- meta_predicate(path(2,?,?,?)).
:- meta_predicate(path(2,?,?,?,+)).
path(R_2, [X0|Ys], X0,X) :-
path(R_2, Ys, X0,X, [X0]).
path(_R_2, [], X,X, _).
path(R_2, [X1|Ys], X0,X, Xs) :-
call(R_2, X0,X1),
non_member(X1, Xs),
path(R_2, Ys, X1,X, [X1|Xs]).
non_member(_E, []).
non_member(E, [X|Xs]) :-
dif(E,X),
non_member(E, Xs).
How about defining path/4 like this?
path(R_2, Xs, A,Z) :- % A path `Xs` from `A` to `Z` is ...
walk(R_2, Xs, A,Z), % ... a walk `Xs` from `A` to `Z` ...
all_dif(Xs). % ... with no duplicates in `Xs`.
To aid universal termination, we swap the two goals in above conjunction ...
path(R_2, Xs, A,Z) :-
all_dif(Xs), % enforce disequality ASAP
walk(R_2, Xs, A,Z).
... and use the following lazy implementation of all_dif/1:
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)
walk/4 is defined like path/4 and path/5 given by the OP:
:- meta_predicate walk(2, ?, ?, ?).
walk(R_2, [X0|Xs], X0,X) :-
walk_from_to_step(Xs, X0,X, R_2).
:- meta_predicate walk_from_to_step(?, ?, ?, 2).
walk_from_to_step([], X,X, _).
walk_from_to_step([X1|Xs], X0,X, R_2) :-
call(R_2, X0,X1),
walk_from_to_step(Xs, X1,X, R_2).
IMO above path/4 is simpler and more approachable, particularly for novices. Would you concur?
I want to focus on naming the predicate.
Unlike maplist/2,
the argument order isn't of primary importance here.
The predicate name should make the meaning of the respective arguments clear.
So far, I like path_from_to_edges best, but it has its pros and cons, too.
path_from_to_edges(Path,From,To,Edges_2) :-
path(Edges_2,Path,From,To).
Let's pick it apart:
pro: path is a noun, it cannot be mis-read a verb. To me, a list of vertices is implied.
pro: from stands for a vertex, and so does to.
con: edges is somewhat vague, but using lambdas here is the most versatile choice.
con: According to Wikipedia, a path is a trail in which all vertices (except possibly the first and last) are distinct. So that would need to be clarified in the description.
Using lambdas for a lists of neighbor vertices Ess:
?- Ess = [a-[b],b-[c,a]],
From = a,
path_from_to_edges(Path,From,To,\X^Y^(member(X-X_neibs,Ess),member(Y,X_neibs))).
Ess = [a-[b],b-[c,a]], From = a, To = a, Path = [a]
; Ess = [a-[b],b-[c,a]], From = a, To = b, Path = [a,b]
; Ess = [a-[b],b-[c,a]], From = a, To = c, Path = [a,b,c]
; false.
Edit 2015-06-02
Another shot at better naming! This leans more on the side of maplist/2...
graph_path_from_to(P_2,Path,From,To) :-
path(P_2,Path,From,To).
Here, graph, of course, is a noun, not a verb.
Regarding the meaning of "path": paths definitely should allow From=To and not exclude that by default (with pairwise term inequalities). It is easy to exclude this with an additional dif(From,To) goal, but not the other way round.
I do not see the reason to define in path/4 the arguments "start node" and "end node". It seems that a simple path/2 with the rule and the list of nodes must be enough.
If the user wants a list starting with some node (by example, 'a'), he can query the statement as: path( some_rule, ['a'|Q] ).
A user could, by example, request for path that have length 10 in the way: length(P,10), path( some_rule, P).
* Addendum 1 *
Some utility goals can be easily added, but they are not the main subject. Example, path/3 with start node is:
path( some_rule, [start|Q], start ) :-
path ( some_rule, [start|Q ] ).
* Addendum 2 *
Addition of last node as argument could give the false idea that this argument drives the algorithm, but it doesn't. Assume by example:
n(a, b).
n(a, c).
n(a, d).
and trace algorithm execution for the query:
[trace] ?- path( n, P, X, d ).
Call: (6) path(n, _G1025, _G1026, d) ? creep
Call: (7) path(n, _G1107, _G1026, d, [_G1026]) ? creep
Exit: (7) path(n, [], d, d, [d]) ? creep
Exit: (6) path(n, [d], d, d) ? creep
P = [d],
X = d ;
Redo: (7) path(n, _G1107, _G1026, d, [_G1026]) ? creep
Call: (8) n(_G1026, _G1112) ? creep
Exit: (8) n(a, b) ? creep
Call: (8) non_member(b, [a]) ? creep
Call: (9) dif:dif(b, a) ? creep
Exit: (9) dif:dif(b, a) ? creep
Call: (9) non_member(b, []) ? creep
Exit: (9) non_member(b, []) ? creep
Exit: (8) non_member(b, [a]) ? creep
Call: (8) path(n, _G1113, b, d, [b, a]) ? creep
Call: (9) n(b, _G1118) ? creep
Fail: (9) n(b, _G1118) ? creep
Fail: (8) path(n, _G1113, b, d, [b, a]) ? creep
Redo: (9) non_member(b, []) ? creep
Fail: (9) non_member(b, []) ? creep
Fail: (8) non_member(b, [a]) ? creep
Redo: (8) n(_G1026, _G1112) ? creep
Exit: (8) n(a, c) ? creep
Call: (8) non_member(c, [a]) ? creep
Call: (9) dif:dif(c, a) ? creep
Exit: (9) dif:dif(c, a) ? creep
Call: (9) non_member(c, []) ? creep
Exit: (9) non_member(c, []) ? creep
Exit: (8) non_member(c, [a]) ? creep
Call: (8) path(n, _G1113, c, d, [c, a]) ? creep
Call: (9) n(c, _G1118) ? creep
Fail: (9) n(c, _G1118) ? creep
Fail: (8) path(n, _G1113, c, d, [c, a]) ? creep
Redo: (9) non_member(c, []) ? creep
Fail: (9) non_member(c, []) ? creep
Fail: (8) non_member(c, [a]) ? creep
Redo: (8) n(_G1026, _G1112) ? creep
Exit: (8) n(a, d) ? creep
Call: (8) non_member(d, [a]) ? creep
Call: (9) dif:dif(d, a) ? creep
Exit: (9) dif:dif(d, a) ? creep
Call: (9) non_member(d, []) ? creep
Exit: (9) non_member(d, []) ? creep
Exit: (8) non_member(d, [a]) ? creep
Call: (8) path(n, _G1113, d, d, [d, a]) ? creep
Exit: (8) path(n, [], d, d, [d, a]) ? creep
Exit: (7) path(n, [d], a, d, [a]) ? creep
Exit: (6) path(n, [a, d], a, d) ? creep
P = [a, d],
X = a .
as you can see, in this case algorithm fails to brute force.
For this reason, if algorithm is not improved, I suggest do not add "end node" as "path" argument.
I´ve got this code, prolog code. It´s purpose is to obtain the transpose matrix of a given square matrix. Can somebody explain to me what does this code do step by step?
trans([], []).
trans([F|Fs], Ts) :-
trans(F, [F|Fs], Ts).
trans([], _, []).
trans([_|Rs], Ms, [Ts|Tss]) :-
lists_firsts_rests(Ms, Ts, Ms1),
trans(Rs, Ms1, Tss).
lists_firsts_rests([], [], []).
lists_firsts_rests([[F|Os]|Rest], [F|Fs], [Os|Oss]) :-
lists_firsts_rests(Rest, Fs, Oss).
The key is really understanding lists_firsts_rests/3 and Boris's remark is spot on. Let's run it through trace:
?- trace.
[trace] ?- lists_firsts_rests([[a,b,c],[d,e,f],[g,h,i]], X, Y).
Call: (6) lists_firsts_rests([[a, b, c], [d, e, f], [g, h, i]], _G1914, _G1915) ? creep
Call: (7) lists_firsts_rests([[d, e, f], [g, h, i]], _G2030, _G2033) ? creep
Call: (8) lists_firsts_rests([[g, h, i]], _G2036, _G2039) ? creep
Call: (9) lists_firsts_rests([], _G2042, _G2045) ? creep
Exit: (9) lists_firsts_rests([], [], []) ? creep
Exit: (8) lists_firsts_rests([[g, h, i]], [g], [[h, i]]) ? creep
Exit: (7) lists_firsts_rests([[d, e, f], [g, h, i]], [d, g], [[e, f], [h, i]]) ? creep
Exit: (6) lists_firsts_rests([[a, b, c], [d, e, f], [g, h, i]], [a, d, g], [[b, c], [e, f], [h, i]]) ? creep
X = [a, d, g],
Y = [[b, c], [e, f], [h, i]].
So you can see what's happening here is that lists_firsts_rests/3 is just peeling off the first item in each of the lists of the argument and returning them in their own list, and another list with all of the rests. The effect here is that when it saw [[a,b,c],[d,e,f],[g,h,i]], what it really saw was [[a|X],[d|Y],[g|Z]] and it returned two things, the list [a,d,g] and [X,Y,Z].
trans/3 is just a classic Prolog inductive loop. It's folding lists_firsts_rests/3 across the matrix. It should be clear how that would produce a transposed matrix, since in the trace it clearly converted 3x3 matrix into a vector of length 3 and a 2x3 matrix "remainder."
trans/2 is another classic Prolog pattern, this one setting up the recursion for trans/3 and starting the loop. A more classic naming policy here would be to call trans/2 transpose/2 and trans/3 transpose_loop/3, because that's really what they are.
Hope this helps.
del(X,[X|Reszta],Reszta).
del(X,[Y|Ogon],[Y|Reszta]) :- del(X,Ogon,Reszta).
I don't understand this code. If I ask:
?- del(c, [a,b,c],X).
Compiler will go to the second line, and he will trigger a recursion loop del(x,[b,c],[]). Am I right?
You can see how the interpreter works by typing (well, in swi-pl at least, should be something similar in other implementations) :
?- trace, del(c, [a,b,c],X).
BTW, you certainly forgot to include a line such as :
del(_, [], []).
Else the algorithm doesn't initialize the result list.
Then it's really basic : if the first element of the list is unifiable with the one you want to remove, you skip it, else, you include it in the result list.
So basicly here, it will work like that :
del(c, [a, b, c], X) => c can't be unified with a so we will include a when constructing the list from the end.
del(c, [b, c], X) => c can't be unified with b so we will include b when constructing the list from the end.
del(c, [c], X) => c can be unified with c so we won't include c when constructing the list from the end.
del(c, [], X) => [] is true when X = [] so let's say X = [] and now let's construct our result list by climbing up the recursion :
X = [] when climbing up one step because c isn't included.
X = [b] when climbing up one step because b is included.
X = [a, b] when climbing up one step because a is included.
use trace/0 to see what will happen. in this case:
4 ?- trace.
true.
[trace] 4 ?- del(c,[a,b,c],X).
Call: (6) del(c, [a, b, c], _G531) ? creep
Call: (7) del(c, [b, c], _G607) ? creep
Call: (8) del(c, [c], _G610) ? creep
Exit: (8) del(c, [c], []) ? creep
Exit: (7) del(c, [b, c], [b]) ? creep
Exit: (6) del(c, [a, b, c], [a, b]) ? creep
X = [a, b] .
at each "turn" prolog will check if the first element is the one we want to remove.
if it is, we are done.
otherwise, we keep the head and recursively call del/3 for the tail of the list
whether or not we should think about what happens if the element is not in the given list is another matter; we might want the predicate to fail in that case, we might want to return the whole list and then we should add the del(_, [], []). as mog said