home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 15 / CDACTUAL15.iso / cdactual / program / pascal / LZRW.ZIP / LZRW4.TXT < prev    next >
Encoding:
Text File  |  1992-01-19  |  22.8 KB  |  589 lines

  1. --<Start of LZRW4 paper>--
  2.  
  3. LZRW4: ZIV AND LEMPEL MEET MARKOV
  4. =================================
  5. Author : Ross Williams
  6. Date   : 23-Jul-1991.
  7.  
  8. This is a public domain document and may be copied freely so long as
  9. it is not modified (but text formatting transformations are permitted
  10. though).
  11.  
  12. Note: This paper has not been polished to publication-standard. It has
  13. been prepared under considerable time pressure and is released mainly
  14. to make the ideas it contains public so as to avoid others
  15. re-inventing and patenting them.
  16.  
  17. Abstract
  18. --------
  19. In 1977 and 1978, Ziv and Lempel[Ziv77][Ziv78] introduced the LZ class
  20. of adaptive dictionary data compression techniques that have become so
  21. very popular today. In competition with these techniques are the
  22. Markov algorithms that give better compression but run much more
  23. slowly. This paper compares the two classes of algorithm and shows how
  24. algorithms that combine techniques from both classes have the
  25. potential to provide higher performance (i.e. speed/ compression trade
  26. off) than we have seen so far. An algorithm called LZRW4 that combines
  27. Markov and LZ77 ideas is sketched.
  28.  
  29. Comparison of Ziv/Lempel and Markov Algorithms
  30. ----------------------------------------------
  31. To the casual observer, the Ziv/Lempel (LZ) data compression
  32. algorithms may appear to be worlds away from the lesser know Markov
  33. algorithms. LZ algorithms construct trees of strings and transmit
  34. strings as codewords. Markov algorithms construct large numbers of
  35. contexts and fiddle with arithmetic ranges and probabilities. The two
  36. kinds of algorithms seem to operate with totally different objects.
  37.  
  38. However, deep down, both classes of algorithm are using the same
  39. probabilistic engine. Deep down, both classes must be representing
  40. more common events with short codes and less common events with longer
  41. codes. This is the law of data compression. But, without some careful
  42. thought, it's hard to see how the two classes relate.
  43.  
  44. In the early eighties, Glen Langdon put in some careful thought and a
  45. lot of insight and came up with two papers[Langdon83] and [Langdon84]
  46. which for me are pivotal in my understanding of the field of data
  47. compression. I cannot recommend these papers highly enough to anyone
  48. who wishes to gain an understanding of what REALLY makes LZW tick or
  49. to anyone who wants a broader perspective of the field. The papers
  50. seem highly focused and obscure, but in fact they cast a broad soft
  51. light over the whole field of text compression, illuminating areas
  52. that for me were very dark (but might not be so dark for people who
  53. read IEEE Transactions on Information Theory like Dickens). The two
  54. papers have to be read carefully though. An earlier paper [Rissanen81]
  55. by Rissanen and Langdon gives an even more general view, but does not
  56. deal directly with LZ algorithms as the later papers do and so I have
  57. focussed on the later papers.
  58.  
  59. The idea behind the two papers is that all dictionary algorithms,
  60. including the LZ classes (LZ77 and LZ78), are subsets (can be emulated
  61. by) Markov algorithms, but the converse is not true. Langdon shows us
  62. a clear view of LZ algorithms through Markov eyes. This view is highly
  63. illuminating.
  64.  
  65. In [Langdon83], Langdon examines the LZ78 class of algorithm closely
  66. and explains the underlying engine in probabilistic terms. In
  67. [Langdon84], he has a more thorough byte at the problem, formalizing
  68. the whole case and proving that dictionary algorithms can always be
  69. emulated by Markov algorithms, but not the converse.
  70.  
  71. I will attempt to explain the idea of [Langdon83] briefly. I will
  72. review LZW but not give a detailed explanation of how it works.
  73.  
  74. LZ78/LZW builds its dictionary by parsing the input as phrases
  75. consisting of the longest dictionary match to date. At the end of each
  76. phrase parse, the algorithm adds a new phrase to the dictionary
  77. consisting of the current phrase plus the next input character. The
  78. dictionary grows forever, adding one new phrase per phrase parsed.
  79.  
  80. The dictionary may be viewed in many ways. We choose to view it as a
  81. (forwards) trie structure whose leaves are to the right and whose root
  82. is at the left. The following diagram illustrates such a tree. Each
  83. arc carries a single character label. Each node represents a single
  84. string. In the diagram, arcs are labelled in lower case and nodes in
  85. upper case.
  86.  
  87.          AA
  88.         /
  89.       a/
  90.       A
  91.     a/ \b
  92.     /   \
  93. Root     AB
  94.    b\
  95.      \
  96.       B
  97.  
  98. All dictionaries can be viewed in this way.
  99.  
  100. In LZW, each node is allocated a code value. Suppose we have two-bit
  101. code words and the codes are allocated as follows:
  102.  
  103.    0: A
  104.    1: B
  105.    2: AA
  106.    3: AB
  107.  
  108. This code allocation implies that each event has an equal probability
  109. of one quarter. We can thus label our tree with node occurrence
  110. probabilities.
  111.  
  112.          AA 1/4
  113.         /
  114.       a/
  115.       A  1/4
  116.     a/ \b
  117.     /   \
  118. Root     AB 1/4
  119.    b\
  120.      \
  121.       B 1/4
  122.  
  123. These node probabilities can then be converted into probabilities for
  124. the ARCS:
  125.  
  126.          AA
  127.         /
  128.        /a 1/3
  129.       A
  130.  3/4a/ \b 1/3
  131.     /   \
  132. Root     AB
  133.    b\
  134.   1/4\
  135.       B
  136.  
  137. (the 1/3 and 1/3 don't add up because the A node (which represents an
  138. imaginary arc labelled by the empty string) has 1/3 too.)
  139.  
  140. These probabilties are exactly the sort of fodder that we need to feed
  141. a Markov algorithm. From the above, it can be seen that the act of LZW
  142. of parsing the longest match and assigning a new codeword, can be
  143. viewed as the execution of a series of single-byte prediction
  144. decisions each with its own separate probabilities and each capable of
  145. being coded independently and with identical efficiency using
  146. arithmetic coding. You can't see this normally because LZW does the
  147. parse all in one go and outputs (for each phrased) a codeword which
  148. looks, for all the world, to be indivisible. But deep down, we all
  149. know that it isn't. Instead, it's made up of little pieces of entropy
  150. accumulated during the traversal and cleverly bundled into 16 bit
  151. codewords at the last minute.
  152.  
  153. So far, we have converted our LZW tree to a Markov-like prediction
  154. tree. Now let's analyse it.
  155.  
  156. Consider a single node in the LZW tree. Associated with the node is a
  157. string (being the characters on the arc leading from the root). Each
  158. time that the parse reaches the node, it means that the node's string
  159. has occurred at the start of a phrase boundary. LZW then goes on
  160. further to the node's child* nodes and eventually reaches a leaf where
  161. it adds a new node AND ALLOCATES A NEW CODEWORD. The result is that
  162. each node accumulates a subtree whose cardinality (=number of subnodes
  163. including itself in this paper=number of codewords allocated to the
  164. subtree) is proportional to the probability of the node's string
  165. arising as a prefix of a parse. As the number of subnodes is also the
  166. node's share of the probability space (because there is one codeword
  167. allocated to each node), we see that the amount of code space
  168. allocated to a node is proportional to the number of times it has
  169. occurred. Very neat.
  170.  
  171. All this stuff is in [Langdon83] which quantifies it.
  172.  
  173. The above explains why LZW compresses so well. Why then does it
  174. compress so badly (compared to Markov models)? Without going into
  175. details, here are some reasons:
  176.  
  177.    * Approximately half of the code space is wasted at any point of time
  178.      in unallocated codewords.
  179.    * Probability estimates are inaccurate near the leaves.
  180.  
  181. Other such reasons eat away at the compression. In particular, there
  182. is one inefficiency of LZW-type compression that stands out.
  183.  
  184. In our analysis, each LZW parse of length d consists of d
  185. single-character predictions. Each prediction is made in the context
  186. of previous predictions. Thus, after having parsed part of a phrase
  187. "ab", the LZW algorithm has two characters of Markov context with
  188. which to "predict" the next character. After having parsed
  189. "compressi", it would have nine characters of context. Thus we see
  190. that, to the extent that we can view LZ78/LZW algorithms as making
  191. predictions, they make predictions using a sawtooth context-length.
  192.  
  193. Order
  194.      ^
  195.     4|              *.
  196.     3|            *  .            *.          *.
  197.     2|    *.    *    .    *.    *  .        *  .
  198.     1|  *  .  *      .  *  .  *    .  *.  *    .
  199.     0|*    .*        .*    .*      .*  .*      .
  200.      +-----|---------|-----|-------|---|-------|-----> Characters
  201.     phrase1    phr2   phr3   phr4  phr5   phr6
  202.  
  203. In contrast, Markov algorithms make predictions using a fairly flat
  204. (or sometimes totally flat) context line. Thus, while a Markov
  205. algorithm may make all of its predictions based on a 3-character
  206. context, a LZW algorithm will make only some of its predictions from
  207. that depth.
  208.  
  209. The thing that really kills LZW's compression is the first one or two
  210. characters of each phrase, the first of which is made based on no
  211. context at all and the second of which is made based on a context of a
  212. single character. After that the context is sufficient not to
  213. introduce too much inefficiency. See Figure 64 of [WIlliams91] to get
  214. an idea of how much impact this has on compression.
  215.  
  216. To compensate for its poor performance in the first one or two
  217. characters, LZW grows an enormous tree. This has the effect of
  218. increasing the average length of a phrase so that the beginning of
  219. phrases occurs less often. This is like Pollyanna adding extra days to
  220. the week to avoid Sundays. As the length of the input increases to
  221. infinity, so does the average phrase length, with the startling result
  222. that by the time you get to infinity, LZW has converged on the entropy
  223. of the source (as Ziv and Lempel proved in their founding
  224. paper[Ziv78]). The rate of convergence depends on the average phrase
  225. length which depends on the entropy of the source. In practice, for
  226. ordinary sources (e.g. text files), the average phrase length does not
  227. rise fast enough to properly offset the effect of the
  228. low-context-length predictions at the start of each phrase.
  229.  
  230. An additional reason for the relatively poor compression performance
  231. of LZW can be found in its phrasing. Markov algorithms predict each
  232. character of the input one at a time and record contextual information
  233. at each step. In contrast LZW divides the input up into phrases each
  234. of which causes a single parse through its tree. Thus, the
  235. "zero-order" model that LZW builds up for the first character of each
  236. phrase is based only on the first character of all the previous
  237. phrases it has seen whereas a zero-order Markov model builds its
  238. model based on ALL the characters it has seen. This applies for all
  239. orders.
  240.  
  241. To summarize:
  242.  
  243.    * All dictionary algorithms can be cast into Markov form.
  244.  
  245.    * The compression grunt (order) that LZW applies is in the shape
  246.      of an irregular sawtooth.
  247.  
  248.    * LZW collects statistics for each context only on phrase boundaries.
  249.  
  250.    * A little thought reveals that all this applies to the LZ77 class
  251.      as well.
  252.  
  253. A brief discussion of all this can be found in Chapter one of my book
  254. [Williams91] and in particular section 1.13:"Dictionary Methods vs
  255. Markov Methods". However, for a full treatment, the reader is referred
  256. to [Langdon83] and [Langdon84].
  257.  
  258. Ziv and Lempel meet Markov
  259. --------------------------
  260. Currently, the field of text data compression has two separate methods
  261. being statistical (Markov) and dictionary (Ziv and Lempel). Markov
  262. algorithms inch through the input character by character, recording
  263. and using context information at each step. This yields the best
  264. compression, but makes Markov algorithms slow. Ziv and Lempel
  265. algorithms gallop through the input one phrase at a time, losing lots
  266. of non-phrase-aligned context information and using zero order models
  267. at the start of each phrase. This yields a higher speed but poorer
  268. compression.
  269.  
  270. Obviously it would be highly desirable to combine the speed of the Ziv
  271. and Lempel algorithms with the compression power of the Markov
  272. algorithms. As time goes by this seems less and less likely (without
  273. special (e.g. parallel) hardware). However, there does seem to be one
  274. way of combining the two classes of algorithm and to my surprise, I
  275. have not yet seen it used.
  276.  
  277. The idea is to create a group of contexts, but to parse phrases from
  278. each context. For example, we might create 256 1-character contexts
  279. and grow an LZW tree in each of them. Compression would proceed
  280. exactly as with LZW except that the most recent character transmitted
  281. (the last character of the previous phrase) would be used to select
  282. one of the 256 contexts, each of which would contain an LZW tree which
  283. would then be used to parse the phrase.
  284.  
  285. The result would be to take the low-order edge off LZW without losing
  286. any of its speed. Each character of the phrase would be "predicted"
  287. using a model one order higher than would have been used in LZW. At
  288. high orders this would have negligible effect, but at low orders it
  289. would have a significant effect, for the first character of each
  290. phrase, formerly predicted by a zero-order model, would now be
  291. predicted by a first-order model. Each phrase would be coded using
  292. only the range required by the size of the tree in its context.
  293.  
  294. By using contexts at the start of the LZW tree, we raise the
  295. bottom of the sawtooth a few notches.
  296.  
  297. Order
  298.      ^
  299.     6|              *.
  300.     5|            *  .            *.          *.
  301.     4|    *.    *    .    *.    *  .        *  .
  302.     3|  *  .  *      .  *  .  *    .  *.  *    .
  303.     2|*    .*        .*    .*      .*  .*      .
  304.     1|
  305.     0|
  306.      +-----|---------|-----|-------|---|-------|-----> Characters
  307.     phrase1    phr2   phr3   phr4  phr5   phr6
  308.  
  309.  
  310. This idea is not at all specific to LZW, but could be applied in
  311. dozens of ways to many different fast parsing adaptive algorithms. In
  312. fact my example algorithm, LZRW4 below uses an LZ77-like allgorithm.
  313. Here are some ideas:
  314.  
  315.    * Use a two-byte context to hash into a table of LZW trees.
  316.    * Grow backwards context trees as in DHPC, but grow LZW parsing trees
  317.      out of each node.
  318.    * Somehow use a single LZW tree BUT START PARSING ONE OR MORE
  319.      CHARACTERS BACK! This avoids having two different kinds of data structure.
  320.    * Set up a set of contexts and bolt an LZ77 compressor on the
  321.      back. Each context stores a list of pointers to strings that
  322.      occurred in that context (see LZRW4 below).
  323.    * Use context with any other dynamic dictionary scheme.
  324.    * Use a rolling hash function in hardware to avoid hash delays at the
  325.      start of phrases.
  326.  
  327. ...combinations and permuations.
  328.  
  329. There are two drawbacks to all this. First of all we are up for a lot
  330. more memory. Second, we run up against the context-depth/sample-size
  331. tradeoff encountered by Markov algorithms. The deeper the contexts we
  332. establish, the more specific they become, but the smaller the amount
  333. of information that each context has on which to base its mini-model
  334. and hence its predictions. The first problem can be overcome with more
  335. memory. The second problem requires careful tuning.
  336.  
  337. LZRW4
  338. -----
  339. To test out the idea, I devised LZRW4. I didn't implement LZRW4, but I
  340. did write a program to measure the compression that it would yield.
  341. This program is provided in Appendix A on an "as is" basis.
  342.  
  343. Note: The name LZRW4 is used here to describe an algorithm. However,
  344. the eventual official code release of LZRW4 may differ in some details
  345. from the algorithm presented here.
  346.  
  347. With a huge range of LZ algorithms from which to choose, I chose the
  348. LZ77 class with which I am familiar. This avoided patent problems.
  349.  
  350. LZRW4 uses a hash table of 4096 partitions each containing 32 pointers
  351. to the input which is held in a 1 Meg buffer. At the start of each
  352. phrase, LZRW4 hashes the previous two characters to obtain a partition
  353. number in the range 0..4095. The 32 pointers in that partition are
  354. searched for the longest match and the length 3bits=[2,3,4,5,6,7,8,16]
  355. and pointer number 5bits=[0,..,31] coded and transmitted. LZRW4 uses a
  356. single control bit for each phrase to say whether a literal byte or a
  357. copy byte is coming next. These control bits are buffered as in the
  358. other LZRW* algorithms. The equal length of literal and copy items is
  359. an interesting feature of the algorithm which seems bound to be useful
  360. to someone someday!
  361.  
  362. To update the partition, LZRW4 swaps the winning pointer with the
  363. pointer halfway towards the front of the partition. If the winning
  364. pointer matched less than 4 bytes then a pointer to the current
  365. position (start of the Ziv) is shifted into the partition.
  366.  
  367. See the code in Appendix A for the details. An understanding of the
  368. LZRW3-A algorithm may also assist.
  369.  
  370. The results of LZRW4 are not startling, but demonstrate that the idea
  371. is working. By using contexts, LZRW4 gets away with using 3-bit
  372. lengths and 5-bit "indexes" whereas its ancestor algorithm LZRW3-A
  373. uses 4-bit lengths and 12-bit "indexes", yielding comparable
  374. compression. Here are some rough results on some Calgary corpus files
  375. (percentage remaining):
  376.  
  377.            LZRW4 LZRW3-A  Unix Compress
  378.    bib     39.5    44.1   41.8
  379.    book1   51.4    54.7   43.2
  380.    book2   41.2    45.5   41.1
  381.    obj1    65.5    58.8   65.3
  382.    obj2    43.4    43.8   52.1
  383.    paper1  46.5    46.1   47.2
  384.    progc   46.4    45.2   48.3
  385.    trans   29.1    32.3   40.8
  386.  
  387. I have experiments with lots of variants of LZRW4 but have not
  388. formalized them nor written them up. One particularly interesting idea
  389. is to subdivide each partition into subpartitions based on the first
  390. character of the phrase. LZRW3-A partition management techniques can
  391. then be used.
  392.  
  393. Closing Thoughts
  394. ----------------
  395. I don't know if this idea is original or whether it will yield any
  396. benefit. However, I have not heard of any Ziv/Lempel/Markov hybrids to
  397. date, and the experiments above indicate at least that the idea works,
  398. if not that it has real competitive benefit. With the right tuning,
  399. the use of contexts could provide extra compression with little impact
  400. on speed (but usually a lot of impact on memory!). At the very least,
  401. it is another weapon in the data compression armoury.
  402.  
  403. References
  404. ----------
  405. [Langdon83] Langdon G.G., "A Note on the Ziv-Lempel Model for
  406. Compressing Individual Sequences, IEEE Transactions on Information Theory,
  407. Vol.29, No.2, pp.284-287.
  408.  
  409. [Langdon84] Langdon G.G., "On Parsing Versus Mixed-Order Model
  410. Structures for Data Compression", IBM Research Report RJ-4163 (46091)
  411. 1/18/84, IBM Research Laboratory, San Jose, CA 95193, 1984.
  412.  
  413. [Rissanen81] Rissanen J.J, Langdon G.G, "Universal Modeling and Coding",
  414. IEEE Transactions on Information Theory, Vol. 27, No. 1, pp.12-23.
  415.  
  416. [Williams91] Williams R.N., "Adaptive Data Compression", Kluwer Academic
  417. Publishers, 101 Philip Drive, Assinippi Park, Norwell, Massachusetts 02061.
  418.  
  419. [Ziv77] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data
  420. Compression", IEEE Transactions on Information Theory", Vol. 23, No. 3,
  421. pp. 337-343.
  422.  
  423. [Ziv78] Ziv J., Lempel A., "Compression of Individual Sequences via
  424. Variable-Rate Coding", IEEE Transactions on Information Theory,
  425. Vol. 24, No. 5, pp. 530-536.
  426.  
  427. Appendix: LZRW4: Experimental Code
  428. ----------------------------------
  429. The following code is public domain and is provided "as is". As most
  430. experimental code, it is poorly designed, structured, coded, and
  431. commented.
  432.  
  433. #include <stdio.h>
  434. /* #include <unix.h>    */
  435. #include <fcntl.h>
  436. #include "port.h"
  437.  
  438. #define MY_BUFFER_SIZE (1024*1024)
  439. #define HASHLENGTH  4096
  440. #define HASHDEPTH     32
  441. #define CONTEXT        2
  442. #define MEDMATCH       8 /* Expressible lengths are [2..MEDMATCH,MAXMATCH]. */
  443. #define MAXMATCH      16
  444. #define NOSHIFTTHRESH  4 /* This or longer match and we don't shift  */
  445.  
  446. main(argc,argv)
  447. int argc;
  448. char **argv;
  449. {
  450.  typedef UBYTE *queue[HASHDEPTH];
  451.  /* Element zero is most recent element. */
  452.  
  453.  UBYTE buf[MY_BUFFER_SIZE+2000];
  454.  queue hash[HASHLENGTH];
  455.  
  456.  char *input_file_name;
  457.  int infile;
  458.  
  459.  ULONG bits_in  =0;
  460.  ULONG bits_out =0;
  461.  if (argc != 2)
  462.    {
  463.     printf("To run lzcontext alg: x <filename>\n");
  464.     exit(0);
  465.    }
  466.  
  467.  printf("Welcome to LZCONTEXT\n");
  468.  printf("--------------------\n");
  469.  printf("Buffer size        = %u\n",MY_BUFFER_SIZE);
  470.  printf("Hash table length  = %u\n",HASHLENGTH    );
  471.  printf("Hash table depth   = %u\n",HASHDEPTH     );
  472.  printf("Context            = %u\n",CONTEXT       );
  473.  printf("Med match          = %u\n",MEDMATCH      );
  474.  printf("Max match          = %u\n",MAXMATCH      );
  475.  printf("No shift threshold = %u\n",NOSHIFTTHRESH   );
  476.  
  477.  input_file_name=argv[1];
  478.  
  479.  infile =open(input_file_name ,O_RDONLY); /* O_BINARY*/
  480.  while(TRUE)
  481.    {
  482.     ULONG  i,j,k;
  483.     UBYTE *p_next_byte;
  484.     ULONG bytes_in;
  485.  
  486.     /* Read in a block of bytes to compress. */
  487.     bytes_in=read(infile,buf,(unsigned int) MY_BUFFER_SIZE);
  488.     if (bytes_in == 0)
  489.        break;
  490.  
  491.     /* Initialize the hash table so all entries point to a defined string. */
  492.     for (i=0;i<HASHLENGTH;i++)
  493.        for (j=0;j<HASHDEPTH;j++)
  494.           hash[i][j]=(UBYTE *) "0123456789ABCDEF";
  495.  
  496.  
  497.     /* Get past the first few context bytes. */
  498.     bits_in +=CONTEXT*8;
  499.     bits_out+=CONTEXT*9;
  500.     p_next_byte=buf+CONTEXT;
  501.  
  502.     /* Loop once for each item. */
  503.     /* The end is sloppy but this is only approximate so who cares? */
  504.     while (p_next_byte < (buf+bytes_in))
  505.       {
  506.        ULONG index;
  507.        UWORD maxlength;
  508.        UBYTE **this_queue;
  509.        UBYTE *old_p_next_byte=p_next_byte;
  510.        ULONG longest_match_index;
  511.  
  512.        index= (*(p_next_byte-2)<<8) ^ (*(p_next_byte-1));
  513.  
  514.        /* context of 3
  515.        index= (*(p_next_byte-3)<<8) ^
  516.               (*(p_next_byte-2)<<4) ^
  517.               (*(p_next_byte-1)   );
  518.        */
  519.  
  520.        index=(40543*index) >> 4;
  521.        /* index&=0x3FFF;        */
  522.        index&=0xFFF;
  523.        this_queue=&hash[index][0];
  524.  
  525.        /* Find the longest match in the 16 recent positions.           */
  526.        /* Note: Because we are only calculating entropy here, we don't */
  527.        /* actually need to know the number of the best position.       */
  528.        maxlength=0;
  529.        for (j=0;j<HASHDEPTH;j++)
  530.          {
  531.           UBYTE *p = this_queue[j];
  532.           for (k=0;k<MAXMATCH;k++)
  533.              if (p_next_byte[k] != p[k])
  534.                break;
  535.           if (k>maxlength)
  536.             {
  537.              maxlength=k;
  538.              longest_match_index=j;
  539.             }
  540.          }
  541.  
  542.        /* Both literals and copies output one control bit and eight
  543.           data bits. They differ on how much input they consume. */
  544.        if (maxlength == 0) maxlength=1;
  545.        if (maxlength>MEDMATCH && maxlength<MAXMATCH) maxlength=MEDMATCH;
  546.  
  547.        p_next_byte+=maxlength;
  548.        bits_in  += 8*maxlength;
  549.        bits_out += 9;
  550.  
  551.        /* If there was a match of 2 or greater, swap the matching
  552.           element with the one half the distance to the head. */
  553.        if (maxlength > 1)
  554.          {
  555.           UBYTE *t;
  556.           ULONG half=longest_match_index/2;
  557.           t=this_queue[half];
  558.           this_queue[half]=this_queue[longest_match_index];
  559.           this_queue[longest_match_index]=t;
  560.          }
  561.  
  562.        /* Shift the queue and put the new value in the recent end. */
  563.        if (maxlength < NOSHIFTTHRESH)
  564.          {
  565.           for (j=HASHDEPTH-1;j>0;j--)
  566.              this_queue[j]=this_queue[j-1];
  567.           this_queue[0]=old_p_next_byte;
  568.          }
  569.       }
  570.    }
  571.  
  572.  close(infile);
  573.  printf("Bytes in  = %lu.\n",bits_in /8);
  574.  printf("Bytes out = %lu.\n",bits_out/8);
  575.  printf("Percentage remaining=%5.1f\n",100.0*((float) bits_out)/((float)
  576.  bits_in));
  577. }
  578.  
  579. void error(mess)
  580. /* Prints out the string and terminates. */
  581. char mess[];
  582. {
  583.  printf("%s\n",mess);
  584.  exit(0);
  585. }
  586.  
  587. --<End of LZRW4 paper>--
  588.  
  589.