:- ensure_loaded( library(terms) ).
:- lib(en_list/2).
:- lib(mod_goal/2).
:- lib(kv_transpose/2).
list_frequency_defaults( Defs ) :-
Defs = [ bins(false),
order(false),
transpose(false),
variant(true),
zero(false) ].
/** list_frequency( +List, -Frequencies ).
list_frequency( +List, -Frequencies, +Opts ).
Frequencies is a list of Term-Freq -pairs with Freq being the number of times each term (and its variants)
appear in the List.
Opts
* bins(Bins=false)
if a list of values, List elements are placed in (=<) bins, if non =|false|= atom,\br
it should be predicate name that produces a bin name for the element.
Can also be a pairlist of label-break.value elements, in which case,
the last bin should also be given with something like Bin-inf.
* order(Ord=false)
order of results: true sorts by element, freq sorts by frequency, and false for no sorting
* transpose(T=false)
when true returns the elements of Frequencies as Freq-Term
* variant(Var=true)
when false compare elements with ==
* zero(Zero=false)
whether to include zero counter elements (Zero should be the list of expected elements)
==
?- list_frequency( [c,a,b,b,a,b,c,d], Freqs ).
Freqs = [c-2, a-2, b-3, d-1].
?- list_frequency( [c,a,b,b,a,b,c,d], Freqs, order(true) ).
[a-2, b-3, c-2, d-1].
?- list_frequency( [c,a,b,b,a,b,c,d], Freqs, order(freq) ).
Freqs = [b-3, a-2, c-2, d-1].
?- list_frequency( [c,a,b,b,a,b,c,d], Freqs, [order(freq),transpose(true)] ).
Freqs = [3-b, 2-a, 2-c, 1-d].
?- list_frequency( [c,a,b,b,a,b,c,d], Freqs, transpose(true) ).
Freqs = [2-c, 2-a, 3-b, 1-d].
?- list_frequency( [c,a,b,a,b,c], Freqs, zero([b,a,c,d]) ).
Freqs = [b-2, a-2, c-2, d-0].
?- list_frequency( [a(X),b(Y),a(Z)], Freqs ).
Freqs = [a(X)-2, b(Y)-1].
?- list_frequency( [a(X),b(Y),a(Z)], Freqs, variant(false) ).
Freqs = [a(X)-1, b(Y)-1, a(Z)-1].
?- list_frequency( [a(X),b(Y),a(Z),a(X)], Freqs, variant(false) ).
Freqs = [a(X)-2, b(Y)-1, a(Z)-1].
?- list_frequency( [1,2,10,11,12,21,22], Freqs, bins([10,20]) ).
Freqs = [1-3, 2-2, 3-2].
?- list_frequency( [1,2,10,11,12,21,22], Freqs, bins([bin_1-10,bin_2-20,bin_3-inf]) ).
Freqs = [bin_1-3, bin_2-2, bin_3-2].
?- assert( (let_num(Let,Num) :- atom_codes(Let,[Code]),Num is Code-96) ).
?- list_frequency( [a,b,c,c,b,a,d], Freqs, bins(let_num) ).
Freqs = [1-2, 2-2, 3-2, 4-1].
?- list_frequency( [1,2,10,11,12,21,22], Freqs, bins(0-5) ).
Freqs = ['(0-5]'-2, '(5-10]'-1, '(10-15]'-2, '(20-25]'-2].
==
NOTE: arguments changed between 0.2 and 0.3.
@author nicos angelopoulos
@version 0.2 2015/11/25, added /3 version where wnd is Expected and examples
@version 0.3 2016/12/16, changed /3 version to 3rd being the options. added options
@version 0.4 2022/12/10, option bins(Bins)
*/
list_frequency( List, Freqs ) :-
list_frequency( List, Freqs, [] ).
list_frequency( List, Freqs, ArgS ) :-
en_list( ArgS, Args ),
list_frequency_defaults( Defs ),
append( Args, Defs, Opts ),
options( order(Ord), Opts ),
options( transpose(T), Opts ),
options( variant(Vnt), Opts ),
options( zero(Zero), Opts ),
options( bins(Bins), Opts ),
( Ord == false -> Cord = false; Cord = true ),
list_frequency_initial_counts( Zero, Cord, T, Iounts, Bero ),
list_frequency_bin_goal( Bins, List, Gins ),
list_frequency( List, Gins, T, Cord, Vnt, Bero, Iounts, FreqsPrv ),
list_frequency_ord_freq( Ord, T, FreqsPrv, Freqs ).
list_frequency_ord_freq( false, _T, Prov, Freqs ) :-
Prov = Freqs.
list_frequency_ord_freq( freq, T, Prov, Freqs ) :-
( T == true ->
sort( 1, @>=, Prov, Freqs )
;
kv_transpose( Prov, Trans ),
sort( 1, @>=, Trans, Sort ),
kv_transpose( Sort, Freqs )
).
list_frequency_ord_freq( true, _T, Prov, Freqs ) :-
Prov = Freqs.
/*
*/
list_frequency( [], _Bins, _T, _Ord, _Vnt, _Bero, Freqs, Freqs ).
list_frequency( [H|Tail], Bins, T, Ord, Vnt, Bero, Iounts, Freqs ) :-
list_frequency_bin( Bins, H, Bin ),
% list_frequency_elem( Ord, T, Vnt, Bero, H, Iounts, Nounts ),
list_frequency_elem( Ord, T, Vnt, Bero, Bin, Iounts, Nounts ),
list_frequency( Tail, Bins, T, Ord, Vnt, Bero, Nounts, Freqs ).
list_frequency_bin( false, H, Bin ) :-
!,
Bin = H.
list_frequency_bin( [B|Ns], H, Bin ) :-
!,
list_frequency_nth_bin( [B|Ns], H, 1, Bin ).
list_frequency_bin( Goal, H, Bin ) :-
call( Goal, H, Bin ).
list_frequency_nth_bin( [], _H, I, Bin ) :-
Bin is I.
list_frequency_nth_bin( [Bin-Coff|_Ns], H, _I, OBin ) :-
H =< Coff,
!,
OBin = Bin.
list_frequency_nth_bin( [B|_Ns], H, I, Bin ) :-
( Bin-Coff = B ->
true
;
Coff = B
),
H =< Coff,
!,
Bin is I.
list_frequency_nth_bin( [_B|Ns], H, I, Bin ) :-
J is I + 1,
list_frequency_nth_bin( Ns, H, J, Bin ).
list_frequency_elem( true, T, Vnt, Bero, H, Iounts, Nounts ) :-
list_frequency_elem_ord( Iounts, H, T, Vnt, Bero, Nounts ).
list_frequency_elem( false, T, Vnt, Bero, H, Iounts, Nounts ) :-
list_frequency_elem_nat( Iounts, H, T, Vnt, Bero, Nounts ).
list_frequency_elem_ord( [], Elem, T, _Vnt, Bero, Counts ) :-
( Bero == false -> list_frequency_pair( T, Elem, 1, Pair ), Counts = [Pair] ; Counts = [] ).
list_frequency_elem_ord( [H|Tail], Elem, T, Vnt, Bero, Counts ) :-
list_frequency_de_pair( T, H, Kh, Vh ),
list_frequency_ord_compare( Vnt, Kh, Elem, Op ),
list_frequency_elem_ord_op( Op, H, Kh, Vh, Tail, Elem, T, Vnt, Bero, Counts ).
list_frequency_elem_ord_op( =, _H, Kh, Vh, Tail, _Elem, T, _Vnt, _Bero, Counts ) :-
list_frequency_pair_increase( T, Kh, Vh, Pair ),
Counts = [Pair|Tail].
list_frequency_elem_ord_op( <, H, _Kh, _Vh, Tail, Elem, T, Vnt, Bero, Counts ) :-
Counts = [H|TCounts],
list_frequency_elem_ord( Tail, Elem, T, Vnt, Bero, TCounts ).
list_frequency_elem_ord_op( >, H, _Kh, _Vh, Tail, Elem, T, _Vnt, Bero, Counts ) :-
( Bero == false -> list_frequency_pair( T, Elem, 1, Pair ), Counts = [Pair,H|Tail]; Counts = [H|Tail] ).
list_frequency_elem_nat( [], Elem, T, _Vnt, Bero, Counts ) :-
( Bero == false -> list_frequency_pair( T, Elem, 1, Pair ), Counts = [Pair] ; Counts = [] ).
list_frequency_elem_nat( [H|Tail], Elem, T, Vnt, Bero, Counts ) :-
list_frequency_de_pair( T, H, Kh, Vh ),
list_frequency_nat_eq( Vnt, Kh, Elem, Eq ),
list_frequency_elem_nat_eq( Eq, H, Kh, Vh, Tail, Elem, T, Vnt, Bero, Counts ).
list_frequency_elem_nat_eq( =, _H, Kh, Vh, Tail, _Elem, T, _Vnt, _Bero, Counts ) :-
list_frequency_pair_increase( T, Kh, Vh, Pair ),
Counts = [Pair|Tail].
list_frequency_elem_nat_eq( <>, H, _Kh, _Vh, Tail, Elem, T, Vnt, Bero, Counts ) :-
Counts = [H|Tounts],
list_frequency_elem_nat( Tail, Elem, T, Vnt, Bero, Tounts ).
list_frequency_ord_compare( true, H, Elem, Op ) :-
( variant(H,Elem) -> Op = (=) ; compare( Op, H, Elem ) ).
list_frequency_nat_eq( true, Seen, Elem, Eq ) :-
( variant(Seen,Elem) -> Eq = (=) ; Eq = (<>) ).
list_frequency_nat_eq( false, Seen, Elem, Eq ) :-
( Seen == Elem -> Eq = (=); Eq = (<>) ).
list_frequency_pair_increase( true, Kh, Vh, Vi-Kh ) :-
Vi is Vh + 1.
list_frequency_pair_increase( false, Kh, Vh, Kh-Vi ) :-
Vi is Vh + 1.
list_frequency_de_pair( true, Times-Elem, Elem, Times ).
list_frequency_de_pair( false, Elem-Times, Elem, Times ).
list_frequency_pair( true, Elem, Times, Times-Elem ).
list_frequency_pair( false, Elem, Times, Elem-Times ).
list_frequency_initial_counts( false, _Ord, _T, [], false ) :- !.
list_frequency_initial_counts( List, Ord, T, Counts, true ) :-
is_list( List ), ground( List ),
findall( KV, (member(Elem,List), list_frequency_pair(T,Elem,0,KV)), CountsPrv ),
list_freqency_order( Ord, T, CountsPrv, Counts ).
list_freqency_order( false, _T, Freqs, Freqs ).
list_freqency_order( true, T, CountsPrv, Counts ) :-
list_frequency_order_elem( T, CountsPrv, Counts ).
list_freqency_order( freq, T, CountsPrv, Counts ) :-
list_frequency_order_freq( T, CountsPrv, Counts ).
list_frequency_order_elem( true, Prv, Freqs ) :-
kv_transpose( Prv, ElemFreqPrs ),
sort( ElemFreqPrs, TFreqs ),
kv_transpose( TFreqs, Freqs ).
list_frequency_order_elem( false, Prv, Freqs ) :-
sort( Prv, Freqs ).
list_frequency_order_freq( true, Prv, Freqs ) :-
sort( Prv, Freqs ).
list_frequency_order_freq( false, Prv, Freqs ) :-
kv_transpose( Prv, FreqElemPrs ),
sort( FreqElemPrs, TFreqs ),
kv_transpose( TFreqs, Freqs ).
list_frequency_bin_goal( false, _List, Moal ) :-
!,
Moal = false.
list_frequency_bin_goal( [B|Ns], _List, Gins ) :-
!,
Gins = [B|Ns].
list_frequency_bin_goal( Start-Step, List, Gins ) :-
!,
max_list( List, Max ),
% First = Start + Step,
Start =< Max,
list_frequency_bin_breaks( Start, Max, Step, Gins ).
list_frequency_bin_goal( Goal, _List, Moal ) :-
mod_goal( Goal, Moal ).
list_frequency_bin_breaks( Curr, Max, Step, Gins ) :-
Cutoff is Curr + Step,
Curr > Max,
!,
atomic_list_concat( ['(',Curr,'-',Cutoff,']'], '', Bin ),
Gins = [Bin-Cutoff].
list_frequency_bin_breaks( Curr, Max, Step, Gins ) :-
Cutoff is Curr + Step,
atomic_list_concat(['(',Curr,'-',Cutoff,']'], '', Bin ),
Gins = [Bin-Cutoff|Tins],
list_frequency_bin_breaks( Cutoff, Max, Step, Tins ).
% list_frequency_bin_breaks( Curr, Max, Step, Gins ) :-
% list_frequency_bin_breaks( Cutoff, Max, Step, Tins ).
/*
list_frequency( [H|T], [H-HTimes|CountedT] ) :-
list_frequency_1( T, H, 1, HTimes, ReducedT ),
list_frequency( ReducedT, CountedT ).
list_frequency( [], [] ).
list_frequency_1( [H|T], El, Acc, Count, RedT ) :-
variant( El, H ),
!,
Acc1 is Acc + 1,
list_frequency_1( T, El, Acc1, Count, RedT ).
list_frequency_1( [H|T], El, Acc, Count, [H|RedT] ) :-
list_frequency_1( T, El, Acc, Count, RedT ).
list_frequency_1( [], _El, Acc, Acc, [] ).
list_frequency( List, Expct, Freqs ) :-
findall( Elem-0, member(Elem,Expct), Counters ),
list_frequency_expected( List, Counters, Freqs ).
list_frequency_expected( [], Freqs, Freqs ).
list_frequency_expected( [H|T], Counters, Freqs ) :-
list_frequency_expected_increase_counter( Counters, H, Next ),
list_frequency_expected( T, Next, Freqs ).
list_frequency_expected_increase_counter( [], Elem, _Next ) :-
throw( no_counter_for(Elem) ).
list_frequency_expected_increase_counter( [Elem-Curr|T], Elem, [Elem-Next|T] ) :-
!,
Next is Curr + 1.
list_frequency_expected_increase_counter( [H|T], Elem, [H|Next] ) :-
list_frequency_expected_increase_counter( T, Elem, Next ).
*/