Same elements in lists - prolog

I'm trying to write a predicate that determines whether the first list have the same elements with either two other lists in Prolog. This is what I have tried:
same([],[],[]).
same([A|As],[B|Bs],[C|Cs]) :- A = B, A = C, common(As,Bs,Cs).
The output is supposed to be something like this:
?- same(E,[1,6,8,2,3],[3,7,9,10,2]).
E = [] ;
E = [2] ;
E = [2, 3] ;
E = [3] ;
false.
I have no idea where I went wrong here. Any help would be much appreciated!

Your procedure will succeed only when the three lists have the same length and every item from the first list unifies with the other corresponding items in the remaining lists. That is, if lists are ground it will only succeed if the three lists are the same.
You may try something like this:
same([], _, _).
same([A|As], Bs, Cs):-
append(_, [A|Bs1], Bs),
select(A, Cs, Cs1),
same(As, Bs1, Cs1).
where the recursive step "takes" an item from the second list and selects it from the the third one.
sample run:
?- same(E,[1,6,8,2,3],[3,7,9,10,2]).
E = [] ;
E = [2] ;
E = [2, 3] ;
E = [3] ;
false.

Related

Find the lower peaks of the list

Help, please, find the lower peaks of the list. For example, given an array [1,5,4,6,3] the answer would be [1,4,3]
lower_peaks([X,Y|T],[X|L]):-X<Y,lp2([Y|T],L).
lower_peaks([X,Y|T],L):-lp2([X,Y|T],L).
lp2([X,Y],[Y]):-Y<X.
lp2([_,_],[]).
lp2([X,Y,Z|T],[Y|L]):-Y<X,Y<Z,lp2([Y,Z|T],L).
lp2([X,Y,Z|T],L):-lp2([Y,Z|T],L).
The problem is multiple answers:
?- lower_peaks([1,5,4,6,3],V).
V = [1, 4, 3] ;
V = [1, 4] ;
V = [1, 3] ;
V = [1] ;
V = [4, 3] ;
V = [4] ;
V = [3] ;
V = [] ;
false.
Complete code:
lower_peaks(L,R) :-
lower_peaks_start(L,R).
lower_peaks([_],[]).
lower_peaks([],[]).
lower_peaks_start([X,Y|T],[X|L]) :-
X<Y,
lower_peaks_middle([Y|T],L).
lower_peaks_start([X,Y|T],L) :-
\+ (X<Y),
lower_peaks_middle([Y|T],L).
lower_peaks_middle([X,Y,Z|T],[Y|L]) :-
Y<X, Y<Z,
lower_peaks_middle([Y,Z|T],L).
lower_peaks_middle([X,Y,Z|T],L) :-
\+ (Y<X, Y<Z),
lower_peaks_middle([Y,Z|T],L).
lower_peaks_middle([X,Y],L) :-
lower_peaks_end([X,Y],L).
lower_peaks_end([X,Y],[Y]) :-
Y<X.
lower_peaks_end([X,Y],[]) :-
\+ (Y<X).
Example run:
?- lower_peaks([1,5,4,6,3],V).
V = [1, 4, 3] ;
false.
There were several problems with the code.
The code had guards, e.g. X<Y for the one predicate, but either a cut (!) or better a not guard \+ (X<Y) for the matching predicate was needed.
The code transitioned from the start of the list to the middle, e.g. lower_peaks then to lp2 but did not transition for the end.
The code needed base cases for a list of one or no items.
The code needed a way to transition from the start of list to the end of list if there was no middle.

Flatten list of lists of lists into single list

Trying to flatten list of lists of lists into single list with following modification. The lowest level list should merge into one item of resultant list and dash should be added between them. More you can see from following:
Input:
L = [[[A],[B]],[[C],[D]],[[E],[F]],[[G],[H]]]
Expected output:
Res = [A-B,C-D,E-F,G-H]
Here is my code:
toList([],_).
toList([H|T],Out) :-
toList1(H,Out1),
newOut2 = [Out|Out1],
toList(T,newOut2).
toList1([],newOut1).
toList1([[A],[B]],Out1) :-
newOut1 = [A-B],
toList1([],newOut1).
Should work like toList([[[A],[B]],[[C],[D]],[[E],[F]],[[G],[H]]], Res).
You can actually describe this relation with a single predicate, let's call it lists_pairs/2. There are two cases to cover:
If the list of lists is empty then the list of pairs is empty as well.
If the head of the first list is of the form [[A],[B]] then the head of the second list is A-B and the relation has to hold for the tails of the lists as well.
You can express this in Prolog like so:
lists_pairs([],[]). % case 1
lists_pairs([[[A],[B]]|Ls],[A-B|Ps]) :- % case 2
lists_pairs(Ls,Ps).
Your example query yields the desired answer:
?- lists_pairs([[[A],[B]],[[C],[D]],[[E],[F]],[[G],[H]]], Res).
Res = [A-B, C-D, E-F, G-H].
You can also use this predicate in the other direction:
?- lists_pairs(L, [A-B, C-D, E-F]).
L = [[[A], [B]], [[C], [D]], [[E], [F]]].
And the most general query works as well:
?- lists_pairs(L, P).
L = P, P = [] ;
L = [[[_G22], [_G28]]],
P = [_G22-_G28] ;
L = [[[_G22], [_G28]], [[_G43], [_G49]]],
P = [_G22-_G28, _G43-_G49] ;
L = [[[_G22], [_G28]], [[_G43], [_G49]], [[_G64], [_G70]]],
P = [_G22-_G28, _G43-_G49, _G64-_G70] ;
.
.
.

Filter list in prolog

I'm trying to rewrite code from Haskell to Prolog.
count :: Eq a => a -> [a] -> Int
count x = length . filter (x==)
f :: [Integer] -> [Integer]
f [] = []
f list = filter (\x -> count x list == 1) list
This code return list that contains elements that appears only once in the list.
So if I have list [1,1,2,2,3,4,4,5] this function returns [3,5]
I tried to find filter construction in Prolog but seems there no such thing. How can I make similar function in Prolog ?
To the existing answers, I would like to add an answer that is quite general in the sense that you can use it in multiple directions.
Building block: list_element_number/3
I start with the following predicate, defining a relation between:
a list Ls0
an element E
the number N of occurrences of E in Ls0
Here it is:
list_element_number(Ls0, E, N) :-
tfilter(=(E), Ls0, Ls),
length(Ls, N).
This solution uses tfilter/3 from library(reif). The predicate subsumes the function count you have posted. The main benefit of this predicate over the function is that the predicate can be used not only in those cases that even Haskell can do easily, such as:
?- list_element_number([a,b,c], a, N).
N = 1.
No, we can use it also in other directions, such as:
?- list_element_number([a,b,c], X, 1).
X = a ;
X = b ;
X = c ;
false.
Or even:
?- list_element_number([a,b,E], X, 2).
E = X, X = a ;
E = X, X = b ;
false.
Or even:
?- list_element_number([A,B,C], X, 3).
A = B, B = C, C = X ;
false.
And even in the most general case, in which all arguments are fresh variables:
?- list_element_number(Ls, E, N).
Ls = [],
N = 0 ;
Ls = [E],
N = 1 ;
Ls = [E, E],
N = 2 ;
Ls = [E, E, E],
N = 3 .
We can fairly enumerate all answers like this:
?- length(Ls, _), list_element_number(Ls, E, N).
Ls = [],
N = 0 ;
Ls = [E],
N = 1 ;
Ls = [_160],
N = 0,
dif(E, _160) ;
Ls = [E, E],
N = 2 .
Main predicate: list_singletons/2
Using this building block, we can define list_singletons/2 as follows:
list_singletons(Ls, Singles) :-
tfilter(count_one(Ls), Ls, Singles).
count_one(Ls, E, T) :-
list_element_number(Ls, E, Num),
cond_t(Num=1, true, T).
This uses cond_t/3 and (again) tfilter/3 from library(reif).
Sample queries
Here are a few sample queries. First, the test case you have posted:
?- list_singletons([1,1,2,2,3,4,4,5], Singles).
Singles = [3, 5].
It works as desired.
Now a case involving variables:
?- list_singletons([A,B], Singles).
A = B,
Singles = [] ;
Singles = [A, B],
dif(A, B).
On backtracking, all possibilities are generated: Either A = B holds, and in that case, there is no element that occurs only once. Or A is different from B, and in that case both A and B occur exactly once.
As a special case of the above query, we can post:
?- list_singletons([A,A], Singles).
Singles = [].
And as a generalization, we can post:
?- length(Ls, _), list_singletons(Ls, Singles).
Ls = Singles, Singles = [] ;
Ls = Singles, Singles = [_7216] ;
Ls = [_7216, _7216],
Singles = [] ;
Ls = Singles, Singles = [_7828, _7834],
dif(_7828, _7834) ;
Ls = [_7216, _7216, _7216],
Singles = [] ;
Ls = [_7910, _7910, _7922],
Singles = [_7922],
dif(_7910, _7922) .
Enjoy the generality of this relation, obtained via logical-purity.
A more simple version :
filter_list(L,OutList):-findall(X, (select(X,L, L1),\+member(X, L1)) , OutList).
?- filter_list([1,1,2,2,3,4,4,5],L).
L = [3, 5].
Without findall, you can try
filter_list(In, Out) :- filter_list(In, _, Out).
filter_list([], [], []).
filter_list([H|T], L1, L2) :-
filter_list(T, LL1, LL2),
( member(H, LL1)
-> L1 = LL1, L2 = LL2
; (select(H, LL2, L2)
-> L1 = [H|LL1]
; L1 = LL1, L2 = [H|LL2])).
without counting...
filter_uniques([],[]).
filter_uniques([H|T],F) :-
delete(T,H,D),
( D=T -> F=[H|R],S=T ; F=R,S=D ),
filter_uniques(S,R).
a more direct rewrite of your code, with library(yall) support for inlining of the filter predicate (the first argument to include/3)
filt_uniq(L,F) :-
include({L}/[E]>>aggregate(count,member(E,L),1),L,F).
A simple version:
(see the comment by #false below, the version with findall/3 has some inconsistency problems in more complex queries but second version looks ok however it is definitely not so efficient ).
filter_list(L,OutList):-findall(X, (member(X,L),count(X,L,N),N=:=1) , OutList).
count(_,[],0).
count(X,[X|T],N):-count(X,T,N1),N is N1+1.
count(X,[X1|T],N):-dif(X,X1),count(X,T,N).
The predicate filter_list/2 uses findall/3 and simply states find all X that belong to the list L and count returns 1 and store them in OutList.
Example:
?- filter_list([1,1,2,2,3,4,4,5],L).
L = [3, 5].
You could write filter_list/2 without using findall/3 like:
filter_list(L,OutList):- filter_list(L,OutList,L).
filter_list([],[],_).
filter_list([H|T],[H|T1],L):-count(H,L,N), N=:=1, filter_list(T,T1,L).
filter_list([H|T],T1,L):-count(H,L,N), N > 1, filter_list(T,T1,L).

How to generate every [X,Y] possible for a given list?

I'm trying to generate every combination possible given a list. I want every [X,Y] combination possible.
Here's an example :
?- arguments(A,[1,2,3]).
A = [1,2] ; A = [1,3] ; A = [2,1] ; A = [2,3] ; A = [3,1] ;
A = [3,2]
I have tried multiple things, but I've yet to find a working one.
I am pretty sure the idea is to use prolog's ability to try every possibility as such :
element(X,[X|_],1).
element(X,[_|Q],N) :- element(X,Q,NewN), N is NewN + 1.
This predicate can return the element at the position N, or return the position of the element X, or generate every possibility. Exemple :
?- element(X,[a,b,c],N).
N = 1
X = a
N = 2
X = b
N = 3
X = c
Thanks for the help.
Edit following gusbro answer :
I can't use already existing predicates, it's part of a course.
Reading your answer, I came up with this :
remove_element_x(X, [X|Q], Q).
remove_element_x(X, [T|Q], [T|Res]) :- remove_element_x(X,Q,Res).
arguments([X,Y],L) :-
element(X,L,_),
remove_element_x(X,L,L2),
element(Y,L2,_).
remove_element_x/3 remove the element x from the list and returns the new list.
But the backtracking is not working :
?- arguments(A,[1,2,3]).
A = [1,2] ?
yes
You can use select/3 to select an element from a list (and get the remaining list), then do it again to select another element from the remaining list).
i.e.:
arguments([A,B], L):-
select(A, L, L1),
select(B, L1,_).
Test case:
?- arguments(A,[1,2,3]).
A = [1, 2] ;
A = [1, 3] ;
A = [2, 1] ;
A = [2, 3] ;
A = [3, 1] ;
A = [3, 2]

Prolog sublists generation, multiply empty list - don't know why

I want to make prolog returning me all possible sublists of given list so I wrote:
subSet(L,S):- append(_,L2,L),append(S,_,L2).
In that way I get result like:
Out = [] ;
Out = [a] ;
Out = [a, b] ;
Out = [a, b, c] ;
Out = [] ;
Out = [b] ;
Out = [b, c] ;
Out = [] ;
Out = [c] ;
Out = [] ;
What I have to do to get rid of repeating empty list?
Rule out that you are describing the empty list at all and add it manually once.
list_subseq(_,[]).
list_subseq(L, S) :- S = [_|_], ....
Nevertheless, expressing subsequences is often better done with DCGs. See the first definition in this response. Using append/3 might work, but leads to code that is quite difficult to read.
Note that there is a sublist predicate among the standard list predicates already (which only lists [] once). I'll assume that you're implementing this as an exercise...
An empty list is always a sublist, so this can be specified explicitly. You can then avoid the empty list by using [S|T] instead of S:
subSet(_, []).
subSet(L, [S|T]) :- append(_, L2,L), append([S|T], _, L2).
Example run:
| ?- subSet([a, b, c], Out).
Out = [] ? ;
Out = [a] ? ;
Out = [a,b] ? ;
Out = [a,b,c] ? ;
Out = [b] ? ;
Out = [b,c] ? ;
Out = [c] ? ;

Resources