How to make an array of all elements following X? - prolog

I need to write a predicate next(X, List1, List2), which returns List2, an array of elements which directly follow X.
For example,
next(v1,[v1,v2,v3,v1,v2,v1,v5],L) returns L=[v2,v2,v5]
next(b,[b,k,m,b,j],L) returns L=[k,j]
next(s,[s,b,c,d,e,f,s,c,s,g],L) returns L=[b,c,g]
....
I know that recursion and tail must be used.
I think I know the logic and how the predicate should work, but I can't get it to work. Below is how I'd expect the predicate to work if user entered next(a,[a,b,c,a,b,c],L).
[a,b,c,a,b,c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
%first letter is a, put b in array L, remove a from initial array.
[b,c,a,b,c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
% first letter is b, it is not a, so remove it from initial array
[c,a,b,c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
% first letter is c, it is not a, so remove it from initial array
[a,b,c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
% first letter is a, put b in array L, remove a from initial array.
[b,c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
% first letter is b, it is not a, so remove it from initial array
[c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
% first letter is c, it is not a, so remove it from initial array
This is what I have:
next(X, List1, List2):-
next(X,[X,X2|List1],X2).
I know the part in square brackets is wrong.
Update #1:
/* X is the head of the list */
next(X, [X,Y|T1], [Y|T2]) :-
next(X, [Y|T1], T2).
/* X is not the head of the list*/
next(X, [_|T1], [T2]) :-
next(X, T1, T2).
/* T1 contains only one element */
next(X, _, [T2]):-
true.
/* T1 is empty */
next(X,[T2]):-
true.
Trace log for Update #1:
1 ?- trace.
true.
[trace] 1 ?- next(a,[a,c,d,e,f,a,g],S).
Call: (6) next(a, [a, c, d, e, f, a, g], _G4792) ? creep
Call: (7) next(a, [c, d, e, f, a, g], _G4880) ? creep
Call: (8) next(a, [d, e, f, a, g], _G4885) ? creep
Call: (9) next(a, [e, f, a, g], _G4888) ? creep
Call: (10) next(a, [f, a, g], _G4891) ? creep
Call: (11) next(a, [a, g], _G4894) ? creep
Call: (12) next(a, [g], _G4898) ? creep
Call: (13) next(a, [], _G4903) ? creep
Exit: (13) next(a, [], [_G4906]) ? creep
Exit: (12) next(a, [g], [[_G4906]]) ? creep
Exit: (11) next(a, [a, g], [g, [_G4906]]) ? creep
Exit: (10) next(a, [f, a, g], [[g, [_G4906]]]) ? creep
Exit: (9) next(a, [e, f, a, g], [[[g, [_G4906]]]]) ? creep
Exit: (8) next(a, [d, e, f, a, g], [[[[g, [_G4906]]]]]) ? creep
Exit: (7) next(a, [c, d, e, f, a, g], [[[[[g, [_G4906]]]]]]) ? creep
Exit: (6) next(a, [a, c, d, e, f, a, g], [c, [[[[g, [_G4906]]]]]]) ? creep
S = [c, [[[[g, [_G4906]]]]]]
I have gone through a list of prolog exercises of basic level from these resources:
http://www.ic.unicamp.br/~meidanis/courses/problemas-prolog/
http://www.anselm.edu/homepage/mmalita/culpro/index.html

I think you've defined what rules you need to solve the problem, but your predicate clauses that define these rules aren't all correct. Let's look at the rules you've defined:
/* X is the head of the list */
next(X, [X,Y|T1], [Y|T2]) :-
next(X, [Y|T1], T2).
This is the one I gave in a comment where the head of the list matches the element, and it's correct.
/* X is not the head of the list*/
next(X, [_|T1], [T2]) :-
next(X, T1, T2).
This clause has an issue. It says, X is not the head of the list, but the query next(a, [a,b,c], T) will match it, since X = _ is possible. Also, and here's where all of your extra brackets came in, T2 is already a list, so you don't want to put it into brackets like, [T2]. The corrected clause is:
next(X, [Y|T1], T2) :-
dif(X, Y), % Or X \== Y if you don't have dif/2
next(X, T1, T2).
The third rule and clause:
/* T1 contains only one element */
next(X, _, [T2]):-
true.
This has an issue because _ matches anything, not just single element lists. The rule says, T1 contains only one element. But T1 doesn't even appear in the clause. The corrected version would be:
/* A list with one element has no elements "next" */
next(_, [_], []).
So in the above, it no longer matters what the first argument is, and the 2nd argument is any list of one element, no matter what it is. The result must be empty.
And your last rule & clause:
/* T1 is empty */
next(X,[T2]):-
true.
One glaring issue is that you now just have 2 arguments. Your predicate must have 3. And if T1 is empty, I would expect the middle argument to be []:
/* An empty list has no "next" values */
next(_, [], []).
You could also combine the last two clauses as:
next(_, T, []) :- T = [] ; T = [_].

Related

Prolog two list intersection - why does it keep checking?

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

Override predefined predicate in Prolog

I have written the following predicate append/3 to implement the combination of two lists:
append([L|Ls],R,[L|Result]):-append(Ls,R,Result).
append([],X,X).
It gives a correct output, yet when I trace the execution flow of the code, here is what I get:
1 ?- edit.
true.
2 ?- make.
% //dougal/cs0u$/cyw03u/desktop/lab3 compiled 0.00 sec, 3 clauses
true.
3 ?- trace.
true.
[trace] 3 ?- append([a,b,c],[d,e],X).
Call: (6) append([a, b, c], [d, e], _G554) ? creep
Call: (7) lists:append([b, c], [d, e], _G636) ? creep
Exit: (7) lists:append([b, c], [d, e], [b, c, d, e]) ? creep
Exit: (6) append([a, b, c], [d, e], [a, b, c, d, e]) ? creep
X = [a, b, c, d, e].
It seems that Prolog was using my own append predicate in the first turn, but as it enters the second level of recursion, Prolog has used its own predicate as defined in the library.
How can I override Prolog's predefined predicate (besides giving my own predicate another name)?
The append/3 predicate is not a built-in predicate in SWI-Prolog but a library predicate, defined in the module lists. This module is likely being auto-loaded when you code is executed. There are two flags that can help here. The autoload flag controls auto-loading of libraries. It can be turned off the calling set_prolog_flag(autoload, false). There's also another flag, verbose_autoload, that you can set to true so that auto-loading becomes verbose. Last but not least, you can use the listing/1 predicate to examine you code. Try listing(append/3). It should reveal the call to list:append/3 in the body of clause of your predicate.
This is what I get:
?- set_prolog_flag(verbose_autoload, true).
true.
?- [user].
append([L|Ls],R,[L|Result]):-append(Ls,R,Result).
|: append([],X,X).
|: % user://1 compiled 0.00 sec, 3 clauses
true.
?- listing(append/3).
% autoloading user:listing/1 from /Users/pmoura/lib/swipl-7.1.8/library/listing
% autoloading system:append/3 from /Users/pmoura/lib/swipl-7.1.8/library/lists
lists:append([], A, A).
lists:append([A|B], C, [A|D]) :-
append(B, C, D).
system:append([], A, A).
system:append([A|B], C, [A|D]) :-
append(B, C, D).
append([A|B], C, [A|D]) :-
append(B, C, D).
append([], A, A).
true.
?- trace.
true.
[trace] ?- append([a,b,c],[d,e],X).
Call: (6) append([a, b, c], [d, e], _G354) ? creep
Call: (7) append([b, c], [d, e], _G436) ? creep
Call: (8) append([c], [d, e], _G439) ? creep
Call: (9) append([], [d, e], _G442) ? creep
Exit: (9) append([], [d, e], [d, e]) ? creep
Exit: (8) append([c], [d, e], [c, d, e]) ? creep
Exit: (7) append([b, c], [d, e], [b, c, d, e]) ? creep
Exit: (6) append([a, b, c], [d, e], [a, b, c, d, e]) ? creep
X = [a, b, c, d, e].
[trace] ?-
Can you edit your post and tell us the exact sequence of calls that lead to the results you get?

Transpose matrix of a square matrix explanation

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.

How to implement list concatenation in Prolog?

I have the following compact example that take 3 parameter L1, L2, L3 and append L1 and L2 in L3 (verify that L3 is the concatenation of L1 and L2)
I have this code (that work well):
myappend([], L, L).
myappend([X|L1], L2, [X|L]) :- myappend(L1,L2,L).
The fact is the base case and say that when the first list is a void list, the concatenation of the first list with second list is just the second list.
Ok, this is clear...the rule is pretty clear for me (but not at all) I can think this rule as the predicate that testing whether the 1st, 2nd and 3rd argument has the relation of 1st and 2nd concatenates is the 3rd argument
Ok, I'm trying to express the previous code in an extended form in which I have the body of this rule that represents all the predicates that must be satisfied (have to be TRUE) before so that the head of the rule is itself satisfied.
I have some problem to implement this code in SWI Prolog, this is my code:
concatena([],L,L).
/* REGOLA */
concatena(L1,L2,L3) :- L1 = [_|T], /* Always true: anonymous variable: "_" unifies everything */
concatena(T,L2,L3). /* Recursively call on the tail of L1 */
[X|L1],
[X|L3].
The fact is the base case (as the previous working example)
In my experiment the rule is different.
So that the head of the rule is verified, all the predicates in it's body have to be true...
I think that my idea is good until reaching the base case, in fact doing:
L1 = [_|T], /* It is always true */
concatena(T,L2,L3) /* Call recursively on a subproblem of the original problem, this problem have one less element
OK, so in this way, the base case is reached and so L3 is correctly unified with L2
In fact in the trace I have:
[trace] 3 ?- concatena([a,b],[c,d],L3).
Call: (6) concatena([a, b], [c, d], _G1514) ? creep
Call: (7) [a, b]=[_G1592|_G1593] ? creep
Exit: (7) [a, b]=[a, b] ? creep
Call: (7) concatena([b], [c, d], _G1514) ? creep
Call: (8) [b]=[_G1595|_G1596] ? creep
Exit: (8) [b]=[b] ? creep
Call: (8) concatena([], [c, d], _G1514) ? creep
Exit: (8) concatena([], [c, d], [c, d]) ?
(This is the same thing that happens when I look to the trace of the original working example...so until here should be corrected)
The problem is when the program do backtracking, don't work !!!
In the trace in fact I have this (this is how end the previous incomplete trace):
Exit: (7) concatena([b], [c, d], [c, d]) ? creep
Exit: (6) concatena([a, b], [c, d], [c, d]) ? creep
L3 = [c, d]
I am not completely clear what you are trying to do here: rewrite the second part of the myappend rule so that all the arguments are simple variable terms? In that case, you can just rewrite the arguments of the original myappend with the = operator:
concatena(L1,L2,L3) :- L1=[X|T], L3=[X|L4], concatena(T,L2,L4).
The second part of your rule, as you've written it here,
[X|L1],
[X|L3].
isn't being counted as part of the rule since it follows the ., so there is no backtracking and nothing is happening as the recursion is unwinding.

remove element from list

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

Resources