Implementation of predicate similar to Transpose in Prolog - list

I am pretty new to Prolog, actually 4 days into it and I came across an exercise that states :
Given a list of N lists with N size each implement a predicate called reshape(X,Y)
so that it :
Collects the first elements of all lists into a list.
Collects the second elements of all lists lists into a list.
...
Collects the N elements of all lists into a list.
Collects all lists mentioned above into a new list.
An example would be :
reshape([[1,2,3],[4,5,6],[7,8,9]],X)
X = [[1,4,7],[2,5,8],[3,6,9]]
So here is my implementation :
% Insert at the end of a list
insert([],X,[X]).
insert([H|T1],X,[H|T2]) :- insert(T1,X,T2).
% Length of list
len([],L,L).
len([_|T],L,X) :-
L1 is L + 1,
len(T,L1,X).
len(L,X) :- len(L,0,X).
% Create a list of N empty lists
init_list(L,0,L) :- !.
init_list(L,N,X) :-
N1 is N-1,
insert(L,[],Y),
init_list(Y,N1,X).
init_list(N,X) :- init_list([],N,X).
% Assign each element of a list to the corresponding list.
assign([],[],[]).
assign([H1|T1],[H2|T2],[Y|T3]) :-
insert(H2,H1,Y),
assign(T1,T2,T3).
% Reshape :
reshape([],L,L).
reshape([H1|T1],X,Result):-
assign(H1,X,Y),
reshape(T1,Y,Result).
reshape(Input,Result) :-
len(Input,N),
init_list(N,X),
reshape(Input,X,Result).
So the basic idea is that I start by creating a list of N empty lists and then for each list say L of the input I assign/add each element of L to the corresponding list.
Now I would appreciate some input as I already said I am new to Prolog and can't even tell what the time complexity of my predicate is.The only thing I know for a fact is that it works.
Howerever is there a better way I can implement it?
What's the time complexity of my implementation ? It seems like polynomial time but I can't really tell.
Thanks in advance.

You can code an O(N) algorithm that just goes through each element once:
reshape([[]|Tail], []):-
maplist(=([]), Tail).
reshape(Input, [Result|RTail]):-
reshape(Input, LTail, Result),
reshape(LTail, RTail).
reshape([], [], []).
reshape([[Item|Tail]|LTail], [Tail|MTail], [Item|RTail]):-
reshape(LTail, MTail, RTail).
reshape/3 gets the list with every first element of the list of lists. Then reshape/2 builds all such lists recursively.
Test case:
?- reshape([[1,2,3],[4,5,6],[7,8,9]],X).
X = [[1, 4, 7], [2, 5, 8], [3, 6, 9]] ;
false.

Related

Counting Elements in a List of Lists and Outputting Answer as a List in Prolog

I'm new to Prolog, and struggling to do the following:
I need to write a predicate which outputs the number of list elements inside a list of lists, and output the answer itself as a list.
As an example, I would want:
clistoflists([[a,b,c,d],[e,f,g],[h,i][j,k,l]], N).
N = (4,3,2,3)
I am able to write a predicate to count the elements of a simple list:
count_list([],0).
count_list([_|T], C) :- count_list(T, CNT), C is CNT + 1.
I'm just very unsure how to proceed with the more complicated list of lists, and especially providing for the desired output list.
Any guidance would be very welcome. I've been toying with this for far too long.
The simplest solution is to use the predicates length/2 and maplist/3 as follows:
?- maplist(length, [[a,b,c,d],[e,f,g],[h,i],[j,k,l]], L).
L = [4, 3, 2, 3].
Another alternative is to create your own versions of those predicates:
maplen([], []).
maplen([X|Xs], [Y|Ys]) :-
len(X, Y),
maplen(Xs, Ys).
len([], 0).
len([_|Xs], N) :-
len(Xs, M),
N is M + 1.
Example:
?- maplen([[a,b,c,d],[e,f,g],[h,i],[j,k,l]], L).
L = [4, 3, 2, 3].

Removing Duplicates while maintaining order in Prolog

I am trying to create a predicate that removes duplicates from a list while maintaining its relative order. For example a list that is [1,2,2,3,4,5,5,2] should return [1,2,3,4,5]. However, my code is only able to remove consecutive duplicates and for instance, not the 2 at the end.
remove_duplicates([],[]).
remove_duplicates([H],[H]).
remove_duplicates([H,H|T],[H|List]) :- remove_duplicates(T,List).
remove_duplicates([H,X|T],[H|T1]):- X\=H, remove_duplicates([X|T],T1).
Another approach I was thinking of was to use member to see if the Tail contains the Head. However, the only way I can think of solving it that way is where I would remove the head, if head is a member of tail. This would however keep the last instance of the number only and break the relative order of the numbers in the list.
For instance:
[1,2,2,3,4,5,5,2]
[1,3,4,5,2]
When I actually want
[1,2,3,4,5]
You can make use of an accumulator: an extra parameter, here a list that is initially empty and when new elements arise will grow. Each recursive call the list is passed (or an updated copy).
For example:
remove_duplicates(LA, LB) :-
remove_duplicates(LA, LB, []).
remove_duplicates([], [], _).
remove_duplicates([H|T], R, Seen) :-
( member(H, Seen)
-> (R = S, Seen1 = Seen)
; (R = [H|S], Seen1 = [H|Seen])
),
remove_duplicates(T, S, Seen1).
This then gives us:
?- remove_duplicates([1,2,2,3,4,5,5,2], L).
L = [1, 2, 3, 4, 5].
Of course you can make use of more effective datastructures than a list. I leave that as an exercise.

Prolog bigger from list element pairs to new list

I want to find the bigger value from a list's element's pairs.
Ie. list=[5,7,4,5,6,8] the pairs are [5,7], [7,4], [4,5] etc.
Right now I have this little code snippet:
bigger([],X).
bigger([E1],[H|E1]).
bigger([E1,E2|T],[H|_]):-
(E1>E2,bigger([E2|T],[H|E1]));
(E1<E2,bigger([E2|T],[H|E2])).
The solution should look like:
?- bigger([5,7,4,5,6,8],X).
X = [7,7,5,6,8,8]
EDIT:
Deleted the remove/3 lines, since they're wrong.
I'll give MY understanding of how the code works.
Empty given list check.
One element list check, adds it to output list end ([H|E1])
More than one element in given list, output list
3.1 First two element check (E1 >/< E2)
3.2 New recursive query without E1 (first element)
3.3 Whichever is bigger is output list's last element now.
First I'll show you my solution of your problem (and the result shouldn't be X = [7,7,5,6,8]? I'll make this version.)
gtr(X,Y,Y) :-
Y>=X.
gtr(X,_,X).
bigger([],[]).
bigger([_], []).
bigger([X,Y|R], [Z|H]) :-
bigger([Y|R],H), gtr(X,Y,Z),!.
If you want to have last element appear in this list anyway than just change second bigger function.
Since the relation is describing lists you could opt to use DCGs for the task:
max_of(X,X,Y) :- X >= Y. % X is maximum if X>=Y
max_of(Y,X,Y) :- Y > X. % Y is maximum if Y>X
list_biggers(L,B) :-
phrase(biggers(L),B). % the DCG biggers//1 describes B based on L
biggers([]) --> % if the list is empty
[]. % there's no element in the biggers list
biggers([X]) --> % if the list contains just one element
[X]. % it is in the biggers list
biggers([X,Y|Xs]) --> % if the list contains at least two elements
{max_of(M,X,Y)}, % the maximum of them
[M], % is in the biggers list
biggers([Y|Xs]). % the same holds for [Y|Xs]
This definition is sticking to your reading of the task, that is, in the case of a one-element list the only element is in the list of bigger elements:
?- list_biggers([5,7,4,5,6,8],B).
B = [7, 7, 5, 6, 8, 8] ;
false.
?- list_biggers([1],B).
B = [1] ;
false.
If you prefer the reading suggested by #Armatorix, just change the second DCG-rule to
biggers([_X]) -->
[].
This way the queries above yields the following results:
?- list_biggers([5,7,4,5,6,8],B).
B = [7, 7, 5, 6, 8] ;
false.
?- list_biggers([1],B).
B = [] ;
false.
Note that the list has to be sufficiently instantiated. Otherwise you get an error:
?- list_biggers([X,Y,Z],B).
ERROR: >=/2: Arguments are not sufficiently instantiated
If the list only contains integers, you can remedy this problem by using CLP(FD). Add a line to include the library and change max_of/2 like so:
:- use_module(library(clpfd)).
max_of(X,X,Y) :- X #>= Y.
max_of(Y,X,Y) :- Y #> X.
Now the query above delivers all 4 expected solutions:
?- list_biggers([X,Y,Z],B).
B = [X, Y, Z],
X#>=Y,
Y#>=Z ;
B = [X, Z, Z],
X#>=Y,
Y#=<Z+ -1 ;
B = [Y, Y, Z],
X#=<Y+ -1,
Y#>=Z ;
B = [Y, Z, Z],
X#=<Y+ -1,
Y#=<Z+ -1 ;
false.
In order to construct logical programs, one needs to think logical. Based on the problem statement, there are three possibilities here:
we have an empty list, in that case the result is an empty list as well:
bigger([],[]).
in case we have a list with one element, the problem is underspecified. I would say that the result should be an empty list, but your example seems to suggest that we return that number, since we then have a 1-tuple, and the maximum of a 1-tuple is of course the single element in the tuple:
bigger([H],[H]).
in case the list contains two or more elements [H1,H2|T], then H1 and H2 are the first two elements. In that case we construct a vitual tuple in our head [H1,H2] and calculate the maximum, which is thus M is max(H1,H2). We prepend M to the resulting list of the recursion. That recursion is done on the list [H2|T]: the list where we popped H1 from:
bigger([H1,H2|T],[M|U]) :-
M is max(H1,H2),
bigger([H2|T],U).
Or putting this all together:
bigger([],[]).
bigger([H],[H]).
bigger([H1,H2|T],[M|U]) :-
M is max(H1,H2),
bigger(T,U).

Recursive list predicate in prolog

I'm having difficulty with my assignment, I have to write 2 predicates:
remove_all/3 which removes all instances of a given element out of a list and output the list without the given variable, e.g.:
remove_all(a, [b,a,c,a,d], X)
gives
X = [b,c,d])
and
remove_list/3 which removes all elements of a given list out of another list and outputs the resulting list, e.g.:
remove_list([a,b], [b,a,c,a,d], X)
gives
X=[c,d].
This is what I have:
remove_all(Rema,[],[]).
remove_all(Rema,[Rema|X],Res) :-
remove_all(Rema,X,Res).
remove_all(Rema,[L|P],Res) :-
remove_all(Rema,P,NR), Res=[L|NR].
remove_list([],ListB, ListRes).
remove_list([H|Taila],ListB,ListRes) :-
member(H,ListB),
remove_all(H,ListB,ListRes),
remove_list(Taila,ListRes,ListRes) .
remove_list([S|Tailb],ListB,ListRes) :-
remove_list(Tailb, ListB, ListRes).
Now, my remove_all works fine, but not when I use it in my remove_list predicate, it will then only remove all the instances of the first element of the list which specifies which element are to be removed, for example:
?- remove_list([1,2],[1,2,3,2,1],F).
F = [2, 3, 2]
It only removes the 1's.
Anybody have any idea what to do?

Prolog List Predicates

I need some help with three prolog predicates for checking and manipulating lists. I'm new to prolog and any help would be much appreciated.
The three predicates are:
double_up(+List1, -List2) is true when List2 has each element of List1 twice. The query double_up([a,b,c],X) should give X=[a,a,b,b,c,c]. The order of the elements in the output list does not matter.
pivot(+List1, +Pivot, -Smaller, -GreaterEq) is true when Smaller is the list of numbers in List1 smaller than Pivot, and GreaterEq is the list of numbers in List1 bigger than or equal to Pivot.
fancy_replace(+List, +Takeout,+Putin, -NewList, -Count) is true when NewList is the same list as the input List, but where each Takeout element in the list is replaced with the Putin element. Count should be the number of Takeouts that got replaced. For example, the query fancy_replace([9,10,1,9,2],9,0, X, C) should give X = [0,10,1,0,2] and C = 2. The order of the elements in the output list does not matter.
The simpler pattern to process lists in Prolog imposes a recursive predicate with 2 arguments, matching - conventionally - input and output data, and a base case, stopping the recursion, matching the empty list. Then
double_up([X|Xs], [X,X|Ys]) :- double_up(Xs, Ys).
double_up([], []).
This predicate it's a bit more general than what's required, because it works also in mode double_up(-List1, +List2). For instance
?- double_up(L,[1,1,2,2]).
L = [1, 2].
To restrict its mode as required, I think it's necessary to uselessly complicate the code, moving that clean loop in a service predicate, and leaving double_up just to test the arguments:
double_up(I, O) :- is_list(I), var(O), double_up_(I, O).
double_up_([X|Xs], [X,X|Ys]) :- double_up_(Xs, Ys).
double_up_([], []).
pivot/4 could be 'one-liner' in SWI-Prolog:
pivot(List1, Pivot, Smaller, GreaterEq) :-
partition(>(Pivot), List1, Smaller, GreaterEq).
like partition, foldl from library(apply) it's an easy inplementation of the last required predicate:
fancy_replace(List, Takeout, Putin, NewList, Count) :-
foldl(swap_n_count(Takeout, Putin), List, NewList, 0, Count).
swap_n_count(Takeout, Putin, L, N, C0, C) :-
( L == Takeout
-> N = Putin, C is C0 + 1
; N = L, C = C0
).
to be honest, i hate prolog... even though it is fun and easy after you learn it
i think this is a good reference as I was having trouble understanding how prolog works couple weeks ago.
what does the follow prolog codes do?
anyway.. this is the answer for your first problem; Hopefully you could solve the rest yourself :D
double([]).
double([H|[]], [H,H|[]]).
double([H|T],[H,H|T1]):- double(T, T1).
btw, this might not the only solution...but it works