Prolog - List elements in a list of lists - prolog

I have a list and a list of lists:
A = [1,2,4,5]
L = [[1,2,5],[3,4,5]]
If A contains the same elements as one of the lists, I want it to return true. As A contains the same elements (1,2,5) as the first list in L ([1,2,5]), it should return true even though there's one element in A that isn't in the first list in L.
I've tried using a couple of predicates supplied in the answer of a similar question in order to solve this:
p(X):- findall( Y, (member(Y,X), \+ have_common_element(X,Y) ), [_]).
have_common_element(A,B):- member(X,A), memberchk(X,B).
However the following query will return false:
p([[[1,2,5],[3,4,5]],[1,2,4,5]]).
I understand that this is because there is an element in A (4) that isn't in the first list of L, although I'm having difficulty figuring out how to extend the predicates to have the query return true.
Would it be possible to extend these predicates so that true will be returned even with the additional (and non-mutual) element included?

What you want to say seems to be:
p(A, Ess) :-
member(Es, Ess), % there is a list Es in Ess
maplist(A+\E^member(E,A), Es). % for all E in Es: member(E,A).
or without lambdas:
p(A, Ess) :-
member(Es, Ess),
maplist(list_member(A), Es).
list_member(L, E) :-
member(E, L).

Related

Prolog - Using append to return a single list

Write a predicate triangle(Bs, Ds) where Bs a list of the positions of the foo and Ds is the (single) list of differences in position. Use the built-in predicate append and the your own distances predicate.
This is related to this questions :
Build a list with abs() in prolog
distances([], _, []).
distances([H|T], B, [D|Ds]) :- abs(H - B, D), distances(T, B, Ds).
triangle([],[]).
triangle([H|T], [D|Dt]) :- distances(T,H,D), triangle(T,Dt).
?- triangle([1,2,3],A).
A = [[1, 2], [1], []].
The Solution I require
?- triangle([1,2,3],A).
A = [1,2,1].
The answer is correct but it is a in list of lists.
I'm having trouble turning Ds into a single list. I have tried using append in various positions within the predicate but either get repetitions or the predicate evaluates to false. How can I turn Ds into a single list [1,2,3] with append?
You can append the list D with Dt, instead of using [D|Dt] where you thus prepend the list with one element D:
triangle([],[]).
triangle([H|T], Ds) :-
distances(T, H, D),
append(D, Dt, Ds),
triangle(T, Dt).

Predicates with =.. operator in Prolog

Last time I learnt about =.. that can translate a list to term and opposite.
I have 3 predicates to do, first one is the one that translates a list to a term. I came up with sth like this:
list_to_term(List, Functor, Term) :-
Term =.. [Functor | List].
Is it okey? Enough? Or I miss something?
The other predicate is count(A,T,N) for element A, in term T with number N that is true if N is a count of elements A in term T... Can anyone help me with this one or how to start?
?- count(a,f(a),N).
N = 1
?- count(a,f(a,g(b,a),N).
N = 2.
?- count(a,f(a,g(X,a),N).
N = 2.
Looking at the answer of this post you can reuse the predicate flatten_term/2, a little bit modified to handle free variables, to sove your problem. Here is the code for a basic solution:
flatten_term(Term,[Term]):-
(atomic(Term);var(Term)),!.
flatten_term(Term,Flat):-
Term =.. TermList,
flatten_term_list(TermList,Flat),!.
flatten_term_list([],[]):-!.
flatten_term_list([H|T],List):-
flatten_term(H,HList),
flatten_term_list(T,TList),
append(HList,TList,List),!.
occurrences(_,[],N,N):-!.
occurrences(A,[H|T],N,Tot):-
A \== H,!,
occurrences(A,T,N,Tot).
occurrences(A,[H|T],N,Tot):-
A == H,!,
N1 is N+1,
occurrences(A,T,N1,Tot).
count(A,Term,N):-
flatten_term(Term,Flatten),
occurrences(A,Flatten,0,N).
?- count(a,f(a,g(X,a),d),T).
T = 2.
?- count(X,f(a,g(X,a),d),T).
T = 1
First of all you flatten the term using flatten_term/2. Then simply count the occurrences of the element you want to find using occurrences/4. You can, if you want, modify flatten_term/2 to avoid the usage of occurrences/4 and so scan the term (list) only one time... Something like: flatten_term(Term,Flatten,ElementToFind,Counter,Total).
Start by solving a more general problem of counting the terms in a list. Processing a term is processing a singleton list containing that term, after all:
count(A,T,N):- count(A, [T|Z],Z, 0,N).
count(_, [], [], C,N):- N is C, !.
count(A, [T|B],Z, C,N):- ?=(A,T), A=T, !, count(A, B,Z, C+1,N).
count(A, [T|B],Z, C,N):- ?=(A,T), T=..[_|S], !, append(S,Y,Z), count(A, B,Y, C,N).
count(A, [_|B],Z, C,N):- count(A, B,Z, C,N).
This opens up each head term in a list in succession and appends its argument terms to that list thus using it as a queue... thus processing the predicate's second argument T in a breadth-first manner.
This assumes A argument is an atom, and ?= is used to avoid instantiating the free variables we might encounter, and instead to skip over them, as your examples seem to indicate.
Is it okey? Enough? Or I miss something?
Prolog's =../2 predicate [swi-doc] can "pack" and "unpack" a list that contains the functor name and its arguments in a term and vice versa. So one can use this to construct a term, or to analyze a term. For example:
?- f(a,g(b,a)) =.. L.
L = [f, a, g(b, a)].
Here f is the functor name, and a and g(b, a) are the arguments. These arguments can be terms as well, and then we thus need to unpack these arguments further.
We can for example obtain all the subterms of a term with:
subterms(T, T) :-
\+ var(T).
subterms(T, ST) :-
\+ var(T),
T =.. [_|As],
member(A, As),
subterms(A, ST).
For example:
?- subterms(f(a,g(X,a)),N).
N = f(a, g(X, a)) ;
N = a ;
N = g(X, a) ;
N = a ;
false.
Now that we obtained all (sub)terms, we can slightly rewrite the predicate to count the number of elements that match:
subterm_query(Q, T) :-
Q == T.
subterm_query(Q, T) :-
\+ var(T),
T =.. [_|As],
member(A, As),
subterm_query(Q, A).
so we obtain if we query for a:
?- subterm_query(a, f(a,g(X,a))).
true ;
true ;
false.
If we can use the aggregate library, we can make use of the aggregate_all/3 predicate to count the number of times, the predicate was succesful:
?- aggregate_all(count, subterm_query(a, f(a,g(X,a))), Count).
Count = 2.
If not, you need to implement a mechanism that returns 1 for a match, and sums up recursively the matches of the child terms. I leave this as an exercise.

prolog generate list of numbers from a list[x,y]

Hello I want to generate a list as following. Given a list like [x,y] I want to generate a list that is x,x,...,x : y times eg [2,3]=[2,2,2] but I cannot figure out how.
This is my implementation so far:
generate([T,1],[T]).
generate([X,S],[X|T]):-S1 is S-1,generate([X,S1],[T]).
but for some reason it fails. Can you help me?
generate([E,R], Es) :-
length(Es, R),
maplist(=(E), Es).
You said that your version fails. But in fact it does not:
?- generate([a,0], Xs).
false.
?- generate([a,1], Xs).
Xs = [a]
; false.
?- generate([a,2], Xs).
Xs = [a|a]
; false.
?- generate([a,3], Xs).
false.
It doesn't work for 0, seems to work for length 1, then, produces an incorrect solution Xs = [a|a] for length 2, and finally fails from length 3 on. [a|a] is a good hint that at someplace in your definition, lists and their elements are confused. To better distinguish them, use a variable in plural for a list, like Es which is the plural of E.
The problem is in your second clause. When you have [X|T], it means that T is a list. In the body you write generate([X,S1],[T]): by writing [T] you're now saying the second argument to generate is a list of which the only element is this list T. What you want to say is that it is simply this list T:
generate([T,1], [T]).
generate([X,S], [X|T]) :- S1 is S-1, generate([X,S1], T).

prolog program : compares two lists' items and return a list of unique element that are on List1

This program compares two lists' items and returns a list with items that are members of first list and are not members of second list. For example: list1=[a,b,d], list2=[r,a,f,b] ----> result =[a,b].
go:- comp([y,h,b],[b,t],R),!.
comp([],_,_) :- !.
comp(_,[],_) :- !.
comp([H|T],B,_) :- memberchk(H,B),comp(T,B,_); comp(T,B,R),write([H]).
current result is [h][y]
result I need should be [h,y]
Your request is for a predicate which returns a list with items that are members of first list and are not members of second list. But your example:
list1=[a,b,d], list2=[r,a,f,b] ----> result =[a,b]
Is the result of returns a list with members that are in both lists (intersection). I'm assuming you want what you requested, not what your example shows.
In your original, you had:
comp(_, [], _).
Which would not give a correct result if you queried, say, comp([a], [], X) since you're using the "don't care" term, _. It's an improper expression of what you probably intended, which is comp(L, [], L) (a list is itself if you exclude elements of an empty list from it). In addition, none of your original clauses instantiates a result (all of them have the "don't care" _ in that position).
A corrected version might look like this:
comp([], _, []).
comp(L, [], L).
comp([H|T], S, R) :-
( memberchk(H, S)
-> comp(T, S, R)
; R = [H|RT],
comp(T, S, RT)
).
?- comp([y,h,b],[b,t],R).
R = [y, h] ;
false.
?-
Note that the "false" response after typing ; means there are no additional solutions.

Prolog - first list is sublist of second list?

For example:
isin([1,2,3], [1,0,1,2,3,0])
will yield true because 123 is inside of 101230
I wrote the following code:
isin([AH|AT],[AH|AT]).
isin([AH|AT],[BH|BT]):- AH = BH, isin(AT,BT),isin([AH|AT],BT).
seems not working. Try not use any built-in functions and BTW, Prolog has a built-in sublist(L1,L2) function.
How do I write a query against a built-in function using SWI-Prolog? I tried to directly write
?- sublist([1],[2]).
but it gives me underfined procedure error.
Is it possible to see how a built-in function is coded? How?
sublist( [], _ ).
sublist( [X|XS], [X|XSS] ) :- sublist( XS, XSS ).
sublist( [X|XS], [_|XSS] ) :- sublist( [X|XS], XSS ).
If you want
my_sublist( [2,3,4], [1,2,3,4,5] )
...to succeed, but
my_sublist( [1,3,5], [1,2,3,4,5] )
...to fail, you might want to consider
my_sublist( Sublist, List ) :-
append( [_, Sublist, _], List ).
Note that if you pass a variable through as Sublist, backtracking will give you a comprehensive set of all possible sublists of List, but this will in general include several repeats of the empty list (because the empty list can combine with all other sublists both ahead and behind of them in an append operation).
Since it seems to be homework I will only give you a few hints:
It seems you are missing the case where an empty list is a sublist of the other one.
You mixed the two cases "the sublist starts here" and "the sublist starts later" into one clause.
It seems the elements of the sublist should be consecutive in the larger list. For that you need two predicates. Essentially you have to remember that the sublist has started when you take apart the lists.
There is no builtin sublist/2, only a sublist/3 which does something different (filter list with a predicate).
another implementation using member is :
sublist([],_).
sublist([X|Xs],Y) :- member(X,Y) , sublist(Xs,Y).
member/2 returns true if find the element in a list
member(X,[X|_]).
member(X,[_|Ys]):-member(X,Ys).
sublist(S, L) :-length(S, N),
length(L, N1),
N2 is N1 - N,
length(P, N2),
append( _ , S, P),
append(P, _ , L).
to avoid stack overflow for failing cases we must determine the size of the list P.
sublist([],[],_):-!.
sublist(_,[],_):-!.
sublist([H1|T1],[H2|T2],LV):-
H1 = H2,!,
sublist(T1,T2,LV).
sublist([H1|T1],[H2|_],LV):-
not(H1 = H2),
sublist(T1,LV,LV).
If you try these queries:
?-sublist([1,2,3,4,5],[1,2,3],[1,2,3]).
TRUE
?-sublist([1,2,3,4,5],[1,2,4],[1,2,4]).
FALSE
With a few modifications to ДМИТРИЙ МАЛИКОВ's answer, this is something that works,
preList([], L).
preList([H_s|T_s], [H_s|Tail]):-
preList(T_s, Tail).
subList([H_s|T_s], [H_s|Tail]):-
preList(T_s, Tail).
subList([H_s|T_s], [H_s|Tail]):-
subList([H_s|T_s], Tail).
subList(Sub, [_|Tail]):-
subList(Sub, Tail).
Essentially, look for a match between the first elements of the sub-list and the main-list using the subList procedure. When a match occurs, head over to the preList procedure and check if this turns out to be a prefix for the remainder of the list. If so, the resolution ends in success.
If not, come back and continue comparing the remainder of the list for a first-element match.

Resources