Computing the Histogram of a Signal as a Collection of Bins
Forward Tail Recursion in Prolog
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Computing the Histogram of a Signal as a Collection of Bins
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Nicolaie Popescu-Bodorin
% http://fmi.spiruharet.ro/bodorin/
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% PROLOG, TP 2.0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% USAGE:
% rndlist(10,100,L), freq(L,HIST)
% ie: L contains 100 elements between 0 and 10 and the histogran of L is HIST
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DOMAINS
i=integer
r=real
li=i*
lr=r*
fr=f(integer,integer)
% structured data for histogram encoding.
% f(Who,Occ) encodes the height (Occ) of the bin at a certain value (Who)
lfr=fr* % data type for the histogram (collection/list of bins)
PREDICATES
% freq(S,HIST) :: (i,o) :: Compute the histogram HIST of signal S (forward tail recursion)
freq(lr,lfr)
freq(lr,lfr,lfr)
% occno(E,L,N) :: (i,i,o) :: Count the occurences N of an element E within a list L (forward tail recursion)
occno(r,lr,r)
occno(r,lr,r,r)
% delel(E,L,R) :: (i,i,o) :: Delete the occurences of an element E within a list L (forward tail recursion)
delel(r,lr,lr)
delel(r,lr,lr,lr)
% lrev(I,O) :: (i,o) :: Reverse a list I (forward tail recursion)
lrev(lfr,lfr)
lrev(lr,lr)
lrev(lfr,lfr,lfr)
lrev(lr,lr,lr)
% rndlist(Max,N,L) :: (i,i,o) :: Generate a list L with N random integers taken between 0 and Max (backward tail recursion)
rndlist(r,i,lr)
CLAUSES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Signal Histogram (forward tail recursion):
% freq([1,2,3,2,4,5,1,1,4],[f(1,3),f(2,2),f(3,1),f(4,2),f(5,1)])
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
freq([X],[f(X,1)]).
freq(L,R):-freq(L,[],R). % change arity in order to introduce the second parameter as Accumulator
freq([],Ri,R):-lrev(Ri,R). % the Accumulator is reversed and is fully grown when the first parameter becomes an empty list
freq([H|T],Ri,R):-
occno(H,[H|T],Occ), % count the occurences of H in [H|T];
delel(H,[H|T],La), % delete the occurences of H in [H|T];
freq(La,[f(H,Occ)|Ri],R). % forward tail recursive call;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Count the occurences of an element within a list (forward tail recursion):
% occ(Element,List,Result), (i,i,o)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
occno(E,L,R):-occno(E,L,0,R). % change arity in order to introduce the third parameter as Accumulator
occno(_,[],Ri,Ri). % the Accumulator is reversed and is fully grown when the second parameter becomes an empty list
occno(E,[E|T],Ri,R):-Ria=Ri+1,occno(E,T,Ria,R),!. % if E is found in the head of the list, count the occurence and make forward tail recursive call on the tail
occno(E,[_|T],Ri,R):-occno(E,T,Ri,R). % if E is not the head of the list (see the previous cut), make forward tail recursion call on the tail without updating the Accumulator
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Delete the occurences of an element within a list (forward tail recursion):
% delel(1,[1,2,4,3,5,1,3,1],[2,4,3,5,3]), (i,i,o)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
delel(E,L,R):-delel(E,L,[],R). % change arity in order to introduce the third parameter as Accumulator
delel(_,[],Ri,R):-lrev(Ri,R). % the Accumulator is reversed and is fully grown when the second parameter becomes an empty list
delel(E,[E|T],Ri,R):-delel(E,T,Ri,R),!. % if E equals the head of the second list, make forward tail recursion call on the tail without updating the Accumulator (E is not collected in the Accumulator)
delel(E,[H|T],Ri,R):-delel(E,T,[H|Ri],R). % if E is not H (the head of the second list), update the Accumulator by collecting H. Make forward tail recursive call on the tail and send the updated Accumulator forward.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Reverse a list (forward tail recursion):
% lrev([1,2,3],[3,2,1])
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
lrev(L,R):-lrev(L,[],R). % change arity in order to introduce the second parameter as Accumulator
lrev([],Ri,Ri). % in the most inner call, the Accumulator is "copied as" (unified with) final result
lrev([H|T],Ri,R):-lrev(T,[H|Ri],R). % forward tail recursive call
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Generate a list L with N random integers taken between 0 and Max (backward tail recursion):
% rndlist(Max,N,L)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
rndlist(_,0,[]):-!. % result in the most inner call
rndlist(Max,N,[H|T]):- % backward tail recursive call
random(Max,H),Ni=N-1,rndlist(Max,Ni,T).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% HOMEWORK ASSIGNMENT:
% The number of list traversals in the above implementation may decrease. How? What is redundant in the above approach?
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%