1 ## Copyright (C) 2006 Muthiah Annamalai <muthiah.annamalai@uta.edu>
3 ## This program is free software; you can redistribute it and/or modify it under
4 ## the terms of the GNU General Public License as published by the Free Software
5 ## Foundation; either version 3 of the License, or (at your option) any later
8 ## This program is distributed in the hope that it will be useful, but WITHOUT
9 ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 ## You should have received a copy of the GNU General Public License along with
14 ## this program; if not, see <http://www.gnu.org/licenses/>.
17 ## @deftypefn {Function File} {} huffmandict (@var{symb}, @var{prob})
18 ## @deftypefnx {Function File} {} huffmandict (@var{symb}, @var{prob}, @var{toggle})
19 ## @deftypefnx {Function File} {} huffmandict (@var{symb}, @var{prob}, @var{toggle}, @var{minvar})
21 ## Builds a Huffman code, given a probability list. The Huffman codes
22 ## per symbol are output as a list of strings-per-source symbol. A zero
23 ## probability symbol is NOT assigned any codeword as this symbol doesn't
24 ## occur in practice anyway.
26 ## @var{toggle} is an optional argument with values 1 or 0, that starts
27 ## building a code based on 1's or 0's, defaulting to 0. Also @var{minvar}
28 ## is a boolean value that is useful in choosing if you want to optimize
29 ## buffer for transmission in the applications of Huffman coding, however
30 ## it doesn't affect the type or average codeword length of the generated
31 ## code. An example of the use of @code{huffmandict} is
35 ## huffmandict(symbols, [0.5 0.25 0.15 0.1]) => CW(0,10,111,110)
36 ## huffmandict(symbols, 0.25*ones(1,4)) => CW(11,10,01,00)
38 ## prob=[0.5 0 0.25 0.15 0.1]
39 ## dict=huffmandict(1:5,[0.5 0 0.25 0.15 0.1],1)
41 ## laverage(dict,prob)
43 ## x = [0.20000 0.40000 0.20000 0.10000 0.10000];
44 ## #illustrates the minimum variance thing.
45 ## huffmandict(1,x,0,true) #min variance tree.
46 ## huffmandict(1,x) #normal huffman tree.
50 ## Reference: Dr.Rao's course EE5351 Digital Video Coding, at UT-Arlington.
51 ## @seealso{huffmandeco, huffmanenco}
54 ## Huffman code algorithm.
55 ## while (uncombined_symbols_remain)
56 ## combine least probable symbols into one with,
57 ## their probability being the sum of the two.
58 ## save this result as a stage at lowest order rung.
59 ## (Moving to lowest position possible makes it non-minimum variance
64 ## Walk the tree we built, and assign each row either 1,
68 ## reverse each symbol, and dump it out.
71 function cw_list = huffmandict (sym, source_prob, togglecode = 0, minvar = 0)
74 ## need to compare to 1
75 elseif((sum(source_prob)-1.0) > 1e-7 )
76 error("source probabilities must add up to 1.0");
80 %need to find & eliminate the zero-probability code words.
81 %in practice we donot need to assign anything to them. Reasoning
82 %being that if_ it doesnt occur why bother saving its value anyway?
83 %--(Oct 9) Actually some experts in the area dont agree to this,
84 %and being a generic implementation we should stick to generating
85 %CW's for_ zero symbols. Why impose a bad implementation? --Muthu
88 origsource_prob=source_prob;
91 %sort the list and know the index transpositions. kills the speed O(n^2).
93 L=length(source_prob);
97 if(source_prob(itr1) < source_prob(itr2))
99 source_prob(itr1)=source_prob(itr2);
103 index(itr1)=index(itr2);
113 stage_curr.prob_list=source_prob;
114 stage_curr.sym_list={};
115 S=length(source_prob);
117 stage_curr.sym_list{i}=[i];
122 % another O(n^2) part.
126 L=length(stage_curr.prob_list);
127 nprob=stage_curr.prob_list(L-1)+stage_curr.prob_list(L);
128 nsym=[stage_curr.sym_list{L-1}(1:end),stage_curr.sym_list{L}(1:end)];
131 %archive old stage list.
132 stage_list{I}=stage_curr;
135 %insert the new probability into the list, at the
136 %first-position (greedy?) possible.
139 if((minvar && stage_curr.prob_list(i)<=nprob) || \
140 stage_curr.prob_list(i) < nprob)
147 stage_curr.prob_list=[stage_curr.prob_list(1:i-1) nprob stage_curr.prob_list(i:L-2)];
148 stage_curr.sym_list={stage_curr.sym_list{1:i-1}, nsym, stage_curr.sym_list{i:L-2}};
163 % another O(n^2) part.
165 %printf("Exit Loop");
168 stage_curr=stage_list{I};
169 L=length(stage_curr.sym_list);
171 clist=stage_curr.sym_list{L};
172 for k=1:length(clist)
173 cw_list{1,clist(k)}=[cw_list{1,clist(k)} one_cw];
176 clist=stage_curr.sym_list{L-1};
177 for k=1:length(clist)
178 cw_list{1,clist(k)}=[cw_list{1,clist(k)}, zero_cw];
186 %zero all the code-words of zero-probability length, 'cos they
189 S=length(source_prob);
190 for itr=(S+1):length(origsource_prob)
194 %disp('Before resorting')
199 % Re-sort the indices according to the probability list.
201 L=length(source_prob);
203 t=cw_list{index(itr)};
204 nw_list{index(itr)}=cw_list{itr};
208 %zero all the code-words of zero-probability length, 'cos they
212 % if(origsource_prob(itr)==0)
220 %!assert(huffmandict(1:4,[0.5 0.25 0.15 0.1],1), {[0],[1 0],[1 1 1],[1 1 0]},0)
221 %!assert(huffmandict(1:4,0.25*ones(1,4),1),{[1 1],[1 0],[0 1],[0 0]},0)
222 %!assert(huffmandict(1:4,[1 0 0 0 ]),{[1],[0 1],[0 0 0],[0 0 1]},0)