huff_table 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. #!/bin/sh
  2. ###########################################################################
  3. ## ##
  4. ## Language Technologies Institute ##
  5. ## Carnegie Mellon University ##
  6. ## Copyright (c) 2004 ##
  7. ## All Rights Reserved. ##
  8. ## ##
  9. ## Permission is hereby granted, free of charge, to use and distribute ##
  10. ## this software and its documentation without restriction, including ##
  11. ## without limitation the rights to use, copy, modify, merge, publish, ##
  12. ## distribute, sublicense, and/or sell copies of this work, and to ##
  13. ## permit persons to whom this work is furnished to do so, subject to ##
  14. ## the following conditions: ##
  15. ## 1. The code must retain the above copyright notice, this list of ##
  16. ## conditions and the following disclaimer. ##
  17. ## 2. Any modifications must be clearly marked as such. ##
  18. ## 3. Original authors' names are not deleted. ##
  19. ## 4. The authors' names are not used to endorse or promote products ##
  20. ## derived from this software without specific prior written ##
  21. ## permission. ##
  22. ## ##
  23. ## CARNEGIE MELLON UNIVERSITY AND THE CONTRIBUTORS TO THIS WORK ##
  24. ## DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ##
  25. ## ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT ##
  26. ## SHALL CARNEGIE MELLON UNIVERSITY NOR THE CONTRIBUTORS BE LIABLE ##
  27. ## FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ##
  28. ## WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN ##
  29. ## AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ##
  30. ## ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF ##
  31. ## THIS SOFTWARE. ##
  32. ## ##
  33. ###########################################################################
  34. ## Author: Alan W Black (awb@cs.cmu.edu) ##
  35. ## Date: December 2004 ##
  36. ###########################################################################
  37. ## ##
  38. ## Make a Huffman table data ##
  39. ## done by finding the top singletons, bigrams, trigrams ... and byte ##
  40. ## coding them ##
  41. ## ##
  42. ## But this isn't full huffman coding yet ##
  43. ## ##
  44. ## Hmm, this should probably be written in something other than shell ##
  45. ###########################################################################
  46. ## There are N stages
  47. ## Find the alphabet (usually 256 things)
  48. ## This is done by finding the top singletons, bigrams, trigrams ...
  49. ## Find the frequencies (currently ignored, as codes are always 1 byte)
  50. ## Compress the data, and output the lookup tables
  51. ## There is some octal conversion in here that probably is unnecessary
  52. # Tidy up the tmp files if we get interrupted
  53. trap 'rm -f huff.tmp.corpus.[0-9]* ; exit' 0 2 3 5 10 13 15
  54. # Newer versions of Linux have a not very useful value for LANG by default
  55. LANG=C
  56. export LANG
  57. ## 0 is reserved, 1 is reserved too
  58. ALPHABET_SIZE=254
  59. # if [ $1 = "xentries" ]
  60. # then
  61. # infile=$2
  62. # outfile=$3
  63. # # Normalize the string to be compressed
  64. # cat $infile | awk '{print $1}' |
  65. # tr "A-Z" "a-z" |
  66. # awk '{for (i=1; i<=length($1); i++)
  67. # printf("%s ",substr($1,i,1));
  68. # printf("\n");}' >huff.tmp.corpus
  69. # fi
  70. if [ $1 = "entries" ]
  71. then
  72. # actually works for non-utf8 entries too
  73. infile=$2
  74. outfile=$3
  75. # Normalize the string to be compressed
  76. cat $infile | awk '{printf("\"%s\"\n",$1)}' |
  77. cat >huff.entries.corpus
  78. $ESTDIR/../festival/bin/festival -b $FLITEDIR/tools/make_lex.scm '(utf8entries "huff.entries.corpus" "huff.tmp.corpus")'
  79. fi
  80. if [ $1 = "phones" ]
  81. then
  82. infile=$2
  83. outfile=$3
  84. # Normalize the text to be compressed
  85. cat $infile | awk '{print $NF}' |
  86. sed 's/\\/ /g' >huff.tmp.corpus
  87. fi
  88. if [ $1 = "residual" ]
  89. then
  90. # This really doesn't work: just some tests to see what's worthwhile
  91. infile=$2
  92. outfile=$3
  93. # Normalized the text to be compressed
  94. cat $infile |
  95. awk '{if ($5 ~ /.*_res_/)
  96. n=1;
  97. else if (n==1)
  98. {
  99. printf("%s ",$i);
  100. b=$i;
  101. for (i=2; i<=NF; i++)
  102. {
  103. q=b-$i;
  104. if (q < 0)
  105. q+=256;
  106. printf("%s ",q);
  107. b=$i
  108. }
  109. printf("\n");
  110. n=0
  111. }}' |
  112. sed 's/,//g;s/};//' >huff.tmp.corpus
  113. fi
  114. if [ $1 = "other" ]
  115. then
  116. infile=$2
  117. outfile=$3
  118. cat $infile >huff.tmp.corpus
  119. fi
  120. CORPUS_SIZE=`cat huff.tmp.corpus | wc -w`
  121. echo "Original Corpus size = $CORPUS_SIZE"
  122. # Find the base alphabet
  123. cat huff.tmp.corpus |
  124. awk '{for (i=1; i<=NF; i++)
  125. printf("%s\n",$i);}' |
  126. sort -u >huff.tmp.base.alphabet
  127. BASE_ALPHABET_SIZE=`cat huff.tmp.base.alphabet | wc -l`
  128. echo "Base alphabet = $BASE_ALPHABET_SIZE"
  129. # Find the additional best n grams
  130. PASS=000
  131. cp -p huff.tmp.corpus huff.tmp.corpus.$PASS
  132. PASS_ALPHABET_SIZE=$BASE_ALPHABET_SIZE
  133. while [ $PASS_ALPHABET_SIZE != $ALPHABET_SIZE ]
  134. do
  135. # Loop until we get to the desired alphabet size
  136. cat huff.tmp.corpus.$PASS |
  137. awk '{for (i=1; i<NF; i++)
  138. {
  139. bb = sprintf("%s_%s",$i,$(i+1));
  140. freq[bb]++;
  141. part1[bb] = $i;
  142. part2[bb] = $(i+1);
  143. }}
  144. END {best="";
  145. bestscore=0;
  146. for (i in freq)
  147. {
  148. score = freq[i];
  149. if (score > bestscore)
  150. {
  151. bestscore = score;
  152. best = i;
  153. }
  154. }
  155. printf("%s %s %d %d\n",part1[best],part2[best],bestscore,freq[best])
  156. }' >huff.tmp.corpus.$PASS.best
  157. # Substitute the best bigram to give next corpus
  158. NPASS=`echo $PASS | awk '{printf("%03d",$1+1)}'`
  159. cat huff.tmp.corpus.$PASS |
  160. awk 'BEGIN {p1="'`cat huff.tmp.corpus.$PASS.best | awk '{print $1}'`'";
  161. p2="'`cat huff.tmp.corpus.$PASS.best | awk '{print $2}'`'";
  162. }
  163. {for (i=1; i<=NF; i++)
  164. {
  165. if (($i == p1) && ($(i+1) == p2))
  166. {
  167. printf("%s+%s ",$i,$(i+1));
  168. i++;
  169. }
  170. else
  171. printf("%s ",$i);
  172. }
  173. printf("\n");}' >huff.tmp.corpus.$NPASS
  174. # Summary
  175. echo $PASS joining `cat huff.tmp.corpus.$PASS.best`
  176. echo " PAS $PASS_ALPHABET_SIZE AS $ALPHABET_SIZE"
  177. echo " Corpus was "`cat huff.tmp.corpus.$PASS | wc -w`
  178. echo " Corpus is "`cat huff.tmp.corpus.$NPASS | wc -w`
  179. CORPUS_IS=`cat huff.tmp.corpus.$NPASS | wc -w`
  180. echo $CORPUS_SIZE $CORPUS_IS |
  181. awk '{printf(" Compression %0.2f\n",100*($2*1.0)/$1)}'
  182. PASS=$NPASS
  183. PASS_ALPHABET_SIZE=`cat huff.tmp.corpus.$NPASS |
  184. awk '{for (i=1; i<=NF; i++)
  185. printf("%s\n",$i);}' | sort -u | wc -l`
  186. done
  187. # Now build the map
  188. mv huff.tmp.corpus.$NPASS huff.tmp.corpus.best
  189. rm -f huff.tmp.corpus.[0-9]*
  190. cat huff.tmp.corpus.best |
  191. awk 'BEGIN {tot=0;}
  192. { for (i=1; i<=NF; i++)
  193. {
  194. freq[$i]++
  195. tot++;
  196. }
  197. }
  198. END { for (i in freq)
  199. printf("%f %s\n",freq[i]/tot,i);}' |
  200. sort -n |
  201. awk '{printf("map[\"%s\"] = %d; unmap[%d] = \"%s\";\n",$2,NR,NR,$2)}' >huff.tmp.corpus.maptable
  202. maptable=`cat huff.tmp.corpus.maptable`
  203. # compress the corpus
  204. cat huff.tmp.corpus.best |
  205. awk 'BEGIN {'"$maptable"'}
  206. function enoctal(x)
  207. {
  208. units = x % 8;
  209. eights = ((x - units) / 8) % 8;
  210. sixtyfours = ((((x - units) / 8) - eights) / 8) % 8;
  211. return sprintf("%d%d%d", sixtyfours, eights, units);
  212. }
  213. {
  214. for (i=1; i<=NF; i++)
  215. printf("\\%s",enoctal(map[$i]));
  216. printf("\n");
  217. }' > huff.tmp.corpus.compressed
  218. # uncompress the corpus
  219. cat huff.tmp.corpus.compressed |
  220. sed 's/\\/ /g' |
  221. awk 'BEGIN {'"$maptable"'}
  222. function unenoctal(x)
  223. {
  224. y = ((substr(x,1,1)+0)*64) + ((substr(x,2,1)+0)*8) + (substr(x,3,1)+0);
  225. return y;
  226. }
  227. {
  228. for (i=1; i<=NF; i++)
  229. printf("%s ",unmap[unenoctal($i)]);
  230. printf("\n");
  231. }' > huff.tmp.corpus.uncompressed
  232. if [ $1 = "phones" ]
  233. then
  234. cat huff.tmp.corpus.best |
  235. sed 's/+/\\/g' |
  236. awk '{ for (i=1; i<=NF; i++)
  237. {
  238. freq[$i]++
  239. tot++;
  240. }
  241. }
  242. END { for (i in freq)
  243. printf("%f %s\n",freq[i]/tot,i);}' |
  244. sort -n |
  245. awk '{printf(" \"\\%s\" , /* %f */ \n",$2,$1);}' >$outfile
  246. mv huff.tmp.corpus.compressed huff.phones.compressed
  247. fi
  248. if [ $1 = "entries" ]
  249. then
  250. cat huff.tmp.corpus.best |
  251. sed 's/+//g' |
  252. awk '{ for (i=1; i<=NF; i++)
  253. {
  254. freq[$i]++
  255. tot++;
  256. }
  257. }
  258. END { for (i in freq)
  259. printf("%f %s\n",freq[i]/tot,i);}' |
  260. sort -n |
  261. awk '{printf(" \"%s\" , /* %f */ \n",$2,$1);}' >$outfile
  262. mv huff.tmp.corpus.compressed huff.entries.compressed
  263. fi
  264. exit