home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / ddjcompr / sixpack / sixpack.doc < prev   
Text File  |  1991-04-20  |  9KB  |  283 lines

  1.  
  2. Philip G. Gage
  3. 5345 El Camino Drive
  4. Colorado Springs, CO 80918
  5.  
  6. Home: 719-593-1801
  7. Work: 719-570-8089
  8. CIS:  70541,3645
  9.  
  10.  
  11.  
  12.                                 INTRODUCTION
  13.  
  14. The Sixpack program is a file compression utility using a string copy
  15.  
  16. algorithm and adaptive Huffman encoding.  The program was written
  17.  
  18. specifically for the Data Compression contest announced in the February 1991
  19.  
  20. issue of Dr. Dobb's Journal, based on earlier compression programs that I
  21.  
  22. have developed over the past few years.  The goal was to achieve maximum
  23.  
  24. compression on a 640K PC, even if it ran slowly. 
  25.  
  26.  
  27. The main disadvantage is slow compression time, since the algorithm
  28.  
  29. repeatedly searches the last few thousand bytes looking for the longest
  30.  
  31. string that matches the current text.  Decompression is faster, involving no
  32.  
  33. text searching.  The compression speed can be adjusted somewhat by changing
  34.  
  35. the search parameters. 
  36.  
  37.  
  38. The whimsical name Sixpack was chosen because the program combines six
  39.  
  40. algorithms into a single data packing method.  The algorithms illustrate a
  41.  
  42. variety of data structures, including a binary tree, a hash table, doubly
  43.  
  44. linked lists and a circular array.  I must admit that integrating all these
  45.  
  46. concepts into a working program was quite educational.  A brief description
  47.  
  48. of each algorithm follows. 
  49.  
  50.  
  51.  
  52.  
  53.                          FINITE WINDOW COMPRESSION
  54.  
  55. The basic idea is to maintain a "finite window" buffer of the most recent
  56.  
  57. few thousand characters and search this buffer for the longest string
  58.  
  59. matching the current text.  If such a string is found and it meets or
  60.  
  61. exceeds a minimum length, then compression can be achieved by encoding the
  62.  
  63. matching section of the current text as the number of characters to copy and
  64.  
  65. the distance from which to copy them.  If no matching string of the minimum
  66.  
  67. length or longer is found, the current character is output as a literal
  68.  
  69. without compression and the algorithm proceeds to the next input character. 
  70.  
  71.  
  72. This finite window scheme generates two types of codes, single literal
  73.  
  74. characters, and string copies consisting of length and distance values.  To
  75.  
  76. avoid useless copy length/distance pairs, the distance is measured from the
  77.  
  78. last character of the string to be copied instead of the first character. 
  79.  
  80. Several distance formats with a different number of bits are used to
  81.  
  82. minimize the distance code size.  Another enhancement is not to issue a copy
  83.  
  84. if a better copy exists at the next character.  A final improvement is to
  85.  
  86. check for an alphabetized dictionary word file and restrict copies to
  87.  
  88. roughly a one word distance on such files for greater compression. 
  89.  
  90.  
  91. This algorithm is more similar to the original Lempel-Ziv approach than to
  92.  
  93. the later LZW implementation, and resembles methods described in "Data
  94.  
  95. Compression with Finite Windows", Communications of the ACM, April 1989. 
  96.  
  97. The original Lempel-Ziv idea combines each copy with a literal character,
  98.  
  99. while the ACM article uses blocks of literal characters.  The well known
  100.  
  101. LHARC/ICE program uses a similar method to achieve impressive results. 
  102.  
  103.  
  104.  
  105.  
  106.                            CIRCULAR BUFFER ARRAY
  107.  
  108. The first problem is how to store the buffer of recent text.  To maintain a
  109.  
  110. queue using a linked list would complicate searching.  Shifting the entire
  111.  
  112. contents of an array to add a new character would be too slow. 
  113.  
  114.  
  115. The buffering technique used in Sixpack is to store the text in a circular
  116.  
  117. array which wraps around on itself.  When the end of the array is reached,
  118.  
  119. the position is reset to the beginning of the array and old text is
  120.  
  121. overwritten. No additional data structures are needed and the array occupies
  122.  
  123. minimum space. 
  124.  
  125.  
  126. Since character positions are fixed during their lifetime in the array, the
  127.  
  128. linked lists described later can be allocated in parallel with the buffer
  129.  
  130. array, using the character positions as the corresponding linked list node
  131.  
  132. numbers. The disadvantage of this method is that all operations involving
  133.  
  134. text strings in the buffer must account for the wrap at the end of the
  135.  
  136. buffer.
  137.  
  138.  
  139.  
  140.  
  141.                                  HASH TABLE
  142.  
  143. The fundamental problem is finding the longest string match in a large block
  144.  
  145. of text.  A brute force search gives very slow performance.  Several search
  146.  
  147. algorithms were tested, including a binary search tree, a direct lookup
  148.  
  149. table and fast text search techniques.  For this application, the best
  150.  
  151. method seemed to be a hash table where the key is derived from the first few
  152.  
  153. characters at each location in the buffer. 
  154.  
  155.  
  156. Each entry in the hash table is a doubly linked list containing the indices
  157.  
  158. of all buffer positions with matching text.  Each list requires both a head
  159.  
  160. and tail pointer.  Since several string prefixes may generate the same hash
  161.  
  162. key, some collisions may occur and the entire string must be checked during
  163.  
  164. a search. 
  165.  
  166.  
  167.  
  168.  
  169.                             DOUBLY LINKED LISTS
  170.  
  171. Linked lists are efficient for storing string prefixes in the hash table,
  172.  
  173. since the prefixes are continually being deleted when they reach the maximum
  174.  
  175. search distance and many duplicate keys may exist in some lists.  Hash table
  176.  
  177. chaining techniques would be awkward in this situation. 
  178.  
  179.  
  180. Both successor and predecessor pointers must be kept for a doubly linked
  181.  
  182. list. New nodes are added at the head of the list and old nodes are deleted
  183.  
  184. at the tail of the list.  A singly linked list would result in slow delete
  185.  
  186. times, since the entire list must be scanned to find the last node. 
  187.  
  188. Searching begins at the head of the list, keeping track of the best matching
  189.  
  190. string seen so far.  This method has the advantage that the most recent
  191.  
  192. string match is always found, resulting in shorter distance copies that can
  193.  
  194. be encoded in fewer bits.  No actual information needs to be stored in the
  195.  
  196. lists, because the node pointers also indicate the character positions in
  197.  
  198. the buffer. 
  199.  
  200.  
  201.  
  202.  
  203.                           ADAPTIVE HUFFMAN CODING
  204.  
  205. As a final compression stage, each literal character and copy length code is
  206.  
  207. passed through an adaptive frequency filter which squeezes frequently
  208.  
  209. occurring characters into short bit strings.  The possible copy length codes
  210.  
  211. for each distance range are added to the end of the normal character set. 
  212.  
  213. The copy distance values are likely to be more random and not susceptible to
  214.  
  215. frequency encoding, so they are output using fixed length bit strings. 
  216.  
  217.  
  218. A binary prefix code tree which approximates the famous Huffman tree is
  219.  
  220. maintained by counting each character and propagating the count upward
  221.  
  222. through the tree.  During this propagation the frequency of each node is
  223.  
  224. calculated as the sum of the frequencies of both children.  The new
  225.  
  226. frequency of each traversed node is then compared to that of the node that
  227.  
  228. is up two levels and down one.  If the higher frequency is lower in the
  229.  
  230. tree, the two nodes are swapped.  To avoid overflow and provide local
  231.  
  232. adaption to changing data, the frequencies are periodically scaled down by a
  233.  
  234. factor of two. 
  235.  
  236.  
  237. The data structures and compress/uncompress routines are derived from Pascal
  238.  
  239. versions presented in "Application of Splay Trees to Data Compression",
  240.  
  241. Communications of the ACM, August 1988.  I have replaced the original
  242.  
  243. semi-splaying by frequency coding, giving better results for this
  244.  
  245. application but running slower. 
  246.  
  247.  
  248.  
  249.  
  250.                                 BIT PACKING
  251.  
  252. The final topic to be covered is packing and unpacking of variable length
  253.  
  254. bit strings.  Several different sizes of codes are used for copy distance
  255.  
  256. values, while the adaptive Huffman algorithm processes individual bits. 
  257.  
  258. Routines to handle single bits and multibit codes are used in the program. 
  259.  
  260. A flush routine writes any buffered bits to the output file before it is
  261.  
  262. closed.
  263.  
  264.  
  265.  
  266.  
  267.                                   SUMMARY
  268.  
  269. In summary, the Sixpack program provides very good compression with low
  270.  
  271. memory usage, about 200K for compression and 50K for decompression.  The
  272.  
  273. code is fairly simple and generates an executable file only 14K in size.  It
  274.  
  275. uses a one pass method suitable for large files and redirected data streams.
  276.  
  277. The main disadvantage is slow compression speed, making it more suitable for
  278.  
  279. archive distribution than for routine backups.  There is much room for
  280.  
  281. performance improvement, making this a potentially useful method. 
  282.  
  283.