home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume24 / yabbawhap / part01 / ycoding.4b < prev   
Text File  |  1991-10-09  |  32KB  |  718 lines

  1. Y coding
  2.  
  3. Daniel J. Bernstein
  4.  
  5. Copyright 1991. All rights reserved.
  6. Draft 4b, March 19, 1991.
  7.  
  8. This is a draft. That means it's supposed to be unreadable, misleading,
  9. boring, useless, and generally wrong. Any deviations from the norm are
  10. accidents---happy accidents, but accidents nonetheless. End of warning.
  11.  
  12.  
  13. ----- 1. Introduction
  14.  
  15. --- LZW coding
  16.  
  17. Fix an alphabet A, and take a string I over that alphabet. Construct a
  18. ``dictionary'' D---a one-to-one mapping from strings to integers---as
  19. follows:
  20.  
  21.   0. Start by mapping each symbol of A to a unique integer.
  22.   1. Find the longest prefix p of I contained in D. (Rather, contained
  23.      in the domain of D. It is convenient to ignore this distinction.)
  24.   2. Take the next symbol c after p in I.
  25.   3. Add pc to the dictionary, mapping to another unique integer.
  26.   4. Strip p from the front of I, so that I begins with c.
  27.   5. Repeat from step 1 until I is empty (i.e., until step 2 fails).
  28.  
  29. For example, say A is the set abcdefghijklmnopqrstuvwxyz, and say I is
  30. the string yabbadabbadabbadoo. D starts with all single characters from
  31. A. Now the longest match between I and D is I's first character, y; and
  32. the charater after that is a. So we add ya to the dictionary and strip y
  33. from the front of I.
  34.  
  35. Now I is abbadabbadabbadoo, and D has all single characters plus ya. The
  36. longest match between D and I is a, so we add ab to the dictionary and
  37. remove the a. We continue in this manner until I is empty:
  38.  
  39.   I                     match  add    new dictionary
  40.   yabbadabbadabbadoo    y      ya     ya (plus all single characters)
  41.    abbadabbadabbadoo    a      ab     ya ab
  42.     bbadabbadabbadoo    b      bb     ya ab bb
  43.      badabbadabbadoo    b      ba     ya ab bb ba
  44.       adabbadabbadoo    a      ad     ya ab bb ba ad
  45.        dabbadabbadoo    d      da     ya ab bb ba ad da
  46.     abbadabbadoo    ab     abb    ya ab bb ba ad da abb
  47.       badabbadoo    ba     bad    ya ab bb ba ad da abb bad
  48.         dabbadoo    da     dab    ya ab bb ba ad da abb bad dab
  49.           bbadoo    bb     bba    ya ab bb ba ad da abb bad dab bba
  50.         adoo    ad     ado    ya ab bb ba ad da abb bad dab bba ado
  51.           oo    o      oo     ya ab bb ba ad da abb bad dab bba ado oo
  52.            o    o
  53.  
  54. While we construct the dictionary we can output the value of each match
  55. under the dictionary. This produces a sequence of numbers which, as we
  56. will see below, is sufficient to reconstruct the original string. This
  57. mapping from strings to sequences of numbers is called LZW coding.
  58.  
  59. Typically the numbers in the dictionary are chosen sequentially, from 0
  60. to |A| - 1 for the initial single-character strings and then from |A| on
  61. up. In the above example, the matches are y a b b a d ab ba da bb ad o o,
  62. which have numbers 24 0 1 1 0 3 27 29 31 28 30 14 14. That sequence is
  63. the result of yabbadabbadabbadoo under LZW coding.
  64.  
  65.  
  66. --- LZW decoding
  67.  
  68. How do we reconstruct the original string if we're given the coded
  69. sequence? The secret is to reconstruct the dictionary.
  70.  
  71.   0. Start by mapping each symbol of A to a unique integer. Set I to the
  72.      empty string. Read a number from the input, and set p to the
  73.      corresponding single-character string.
  74.   1. Append p to I.
  75.   2. Read a number from the input, and let c be the first character of
  76.      the corresponding string in the dictionary.
  77.   3. Add pc to the dictionary, mapping to the next unique integer.
  78.   4. Set p to the dictionary string corresponding to the number read.
  79.   5. Repeat from step 1 until end-of-input (i.e., until step 2 fails).
  80.  
  81. For example, take the input sequence 24 0 1 1 0 3 27 29 31 28 30 14 14.
  82. D starts with all single characters from A; p starts as the single
  83. character y; and I starts empty.
  84.  
  85. Now p is appended to I, so that I contains y. The 0 in the input means
  86. that the next character of I is an a; and ya is added to the dictionary.
  87. p is then set to a.
  88.  
  89. Next, p is appended to I, so that I contains ya. The 1 in the input
  90. means that the next character of I is b; and ab is added to the
  91. dictionary. p is then set to b. We continue this way through the entire
  92. input:
  93.  
  94.   input  c   added    new p   I
  95.   24                  y       y
  96.   0      a   (ya,26)  a       ya
  97.   1      b   (ab,27)  b       yab
  98.   1      b   (bb,28)  b       yabb
  99.   0      a   (ba,29)  a       yabba
  100.   3      d   (ad,30)  d       yabbad
  101.   27    *a*  (da,31)  ab      yabbadab      27 is ab, so *a* is the 1st char
  102.   29    _b_  (abb,32) ba      yabbadabba    29 is ba, so _b_ is the 1st char
  103.   31     d   (bad,33) da      yabbadabbada
  104.   28     b   (dab,34) bb      yabbadabbadabb
  105.   30     a   (bba,35) ad      yabbadabbadabbad
  106.   14     o   (ado,36) o       yabbadabbadabbado
  107.   14     o   (oo,37)  o       yabbadabbadabbadoo
  108.  
  109. Notice the slightly twisted statement of steps 2 through 4. p is set to
  110. the dictionary string corresponding to the number read from the input,
  111. but first c is set to the first character of that string, and the old pc
  112. is added to the dictionary. This roundabout presentation is necessary
  113. because the number on the input may be the number of the very last
  114. dictionary string added---and that last string depends on the first
  115. character of the current string. This overlap is always safe but is one
  116. of the first problems to look out for in a new implementation.
  117.  
  118.  
  119. --- So who cares about this LZW stuff anyway?
  120.  
  121. What's the point of LZW coding? When the input string has lots of the
  122. same characters or sequences of characters, the dictionary will rapidly
  123. grow to include those sequences. Then a single number in the output
  124. sequence might represent several characters of input, and will use less
  125. space.
  126.  
  127. For example, take the simplest natural encoding of a string over our
  128. lowercase alphabet A. There are 26 symbols, so we can represent each
  129. with 5 bits. Our string yabbadabbadabbadoo has 18 characters and takes
  130. 90 bits under this encoding.
  131.  
  132. On the other hand, the string after encoding has just 13 numbers:
  133. 24 0 1 1 0 3 27 29 31 28 30 14 14. For these values there are 26 27 28
  134. 29 30 31 32 33 34 35 36 37 38 choices respectively, so they take 5 5 5 5
  135. 5 5 5 6 6 6 6 6 6 bits in the natural way, for a total of just 71 bits.
  136.  
  137. Most strings that come up in practice have similar redundancy, and LZW
  138. coding will produce an output that takes less space than its input. This
  139. is why LZW coding is usually called LZW compression. It often reduces
  140. longer strings to 50% or even 30% of their original size, so that they
  141. take a fraction as much disk space and communication time as they would
  142. in their uncompressed form.
  143.  
  144.  
  145. --- A bit of jargon
  146.  
  147. Many audio and video compression methods throw away some information.
  148. They don't reconstruct exactly the original pictures and sounds, but
  149. nobody really notices. These are called inexact, or sometimes lossy,
  150. compressors. In contrast, LZW always lets you get back exactly the
  151. original string. It is an exact, or lossless, compressor.
  152.  
  153. Any compressor that splits its input into substrings and codes the
  154. strings with a dictionary is called (logically enough) a dictionary
  155. compressor.
  156.  
  157. A substring of an input string---particularly a substring that is coded
  158. as a single output number---is called a ``phrase.'' In LZW, one string
  159. is added to the dictionary per phrase.
  160.  
  161. Some compression methods use fixed tables: ``the'' becomes a special,
  162. single character, ``of'' becomes another, etc. They're called static, or
  163. nonadaptive, compressors. Others, like LZW, build their dictionaries
  164. dynamically to adapt to any input; LZW is an example of an adaptive
  165. compressor. Somewhere in between are compressors that make two passes
  166. over the input, building a dictionary the first time through and then
  167. producing output the second time through. They're called semiadaptive.
  168.  
  169. One useless theoretical property of LZW is that it is universal. This
  170. means that on a certain wide class of inputs it will give as close as
  171. you want to the best possible compression of any method. The longer your
  172. strings are, the closer it comes to optimal. Universality doesn't make
  173. one whit of difference in practice---to get within 1% of optimal with
  174. LZW you'd have to start compressing the planet---but it generally
  175. indicates that a method is both simple and trustworthy. Non-universal
  176. compressors are usually much more complicated, and will fail miserably
  177. on inputs they weren't designed specifically to handle.
  178.  
  179.  
  180.  
  181. ----- 2. Implementing LZW
  182.  
  183. --- Encoding
  184.  
  185. The most natural way to find the longest match between I and strings in
  186. D is one character at a time. Start with p as the first character of I
  187. (or as the null string if that is more convenient). Read the next
  188. character, c. If pc is in the dictionary, set p to pc and repeat.
  189. Otherwise p and c are set.
  190.  
  191. So the dictionary has to support two basic operations: searching for pc
  192. if p is known to be there already, and adding pc if it is not there.
  193. Most implementors use some form of trie---array trie, list trie, hash
  194. trie, huptrie---for this job. The array trie, as in Woods' ``hyper-LZ''
  195. [9], offers extreme speed at the expense of |A| (typically 256) words
  196. of memory for each string in the trie. The huptrie and straight hash
  197. trie use only a small amount of memory per string but still allow
  198. reasonably fast searches in the average case. We will not consider these
  199. structures in further detail.
  200.  
  201. In any case at most a fixed number of operations happen for every input
  202. character, so LZW coding takes linear time no matter how long the input
  203. is. Unfortunately, computers don't have infinite memory. Implementations
  204. typically limit the dictionary to some size, usually between 1024 and
  205. 65536 strings. When the dictionary reaches that size it can either
  206. remain fixed for the rest of the input, or it can be cleared and start
  207. from single characters again. The second strategy effectively breaks the
  208. input into ``blocks'' with independent dictionaries. If the input
  209. ``feels'' different in different blocks, blocking will produce good
  210. results, because it will weed useless strings out of the dictionary.
  211.  
  212. The ``compress'' program [8] introduced an important blocking variant.
  213. Instead of clearing the dictionary as soon as it reaches its maximum
  214. size, compress periodically checks how well it is doing. It will only
  215. clear the dictionary when its compression ratio deteriorates. This way
  216. the blocks adapt to the input. Note that all of these blocking
  217. techniques require space for a special output code to clear the
  218. dictionary.
  219.  
  220. Another variant is LRU replacement: the least-recently-used strings are
  221. removed from the dictionary at some opportune time. This provides a
  222. smoother transition between blocks than clearing the dictionary.
  223. Unfortunately, it is difficult to find good heuristics for when to
  224. remove what strings. Blocking is still more of an art than a science.
  225.  
  226.  
  227. --- Preparing for encryption
  228.  
  229. It is very useful to compress a message before encrypting it, as
  230. compression removes much of the statistical regularity of straight text.
  231. However, the usual coding leaves a lot of redundancy. If the dictionary
  232. has 33 strings, for example, and 6 bits are used to represent a choice
  233. among those strings, then the high bit will almost always be 0. These
  234. high bits come in predictable locations, so an attacker can almost
  235. always figure out the key given a long enough stretch of compressed
  236. text.
  237.  
  238. To prevent this, the compressor should introduce random bits as follows:
  239. Given a choice between 0 and 40, 0 through 22 are encoded as either
  240. themselves or from 41 through 63. The choice should be made with a
  241. high-delay random number generator such as a subtractive generator.
  242. 23 through 40 are always encoded as themselves. This method greatly
  243. reduces the amount of extra information available per bit without
  244. appreciably slowing down the coding. Because random bits are used at
  245. unpredictable times, an attacker cannot easily take advantage of the
  246. determinism of the pseudo-random generator.
  247.  
  248. Most implementations also add a recognizable header to compressed text.
  249. This header should be removed before encryption.
  250.  
  251.  
  252. --- Decoding
  253.  
  254. LZW decoding is even easier than encoding: the dictionary does not have
  255. to support searching. The easiest (and generally fastest) method is to
  256. keep I in memory as it is reconstructed, and to keep track of which
  257. substring of I a given dictionary number corresponds to. To add pc to
  258. the dictionary means to add the pair (pointer to start of pc within I,
  259. length of pc) at the right spot in an array indexed by dictionary
  260. numbers. There are methods which take slightly less memory than this,
  261. but they are slower.
  262.  
  263.  
  264.  
  265. ----- 3. MW and AP coding
  266.  
  267. --- MW: Adapting better
  268.  
  269. LZW adapts to its input relatively slowly: strings in the dictionary
  270. only get one character longer at a time. If LZW is fed a million
  271. consecutive x's, its longest dictionary string will only have around
  272. 1400 x's, and it will only achieve around 1000:1 compression. Is there
  273. any better way for it to notice the redundancy?
  274.  
  275. The answer is yes. Instead of adding p plus one character of the next
  276. phrase to the dictionary, we can add p plus the entire next phrase to
  277. the dictionary. This defines MW coding. For example:
  278.  
  279.   I                     match  added to dictionary
  280.   yabbadabbadabbadoo    y        
  281.    abbadabbadabbadoo    a      ya (concatenation of last two matches)
  282.     bbadabbadabbadoo    b      ab
  283.      badabbadabbadoo    b      bb
  284.       adabbadabbadoo    a      ba
  285.        dabbadabbadoo    d      ad
  286.     abbadabbadoo    ab     dab
  287.       badabbadoo    ba     abba
  288.         dabbadoo    dab    badab
  289.            badoo    ba     dabba
  290.          doo    d      bad
  291.           oo    o      do
  292.            o    o
  293.  
  294. Even such a short example shows how quickly MW begins to adapt. By the
  295. fifteenth character ``dabba'' is already established as a dictionary
  296. phrase. On the other hand, MW will miss shorter phrases where there is
  297. less redundancy, so it generally performs only somewhat better than LZW
  298. in practice. In this example it outputs 13 numbers, just like LZW. But
  299. given a million x's it will end up with a dictionary string of length
  300. around half a million, and it will output just 30 bytes.
  301.  
  302.  
  303.  
  304.  
  305. --- Problems of MW
  306.  
  307. MW lacks some properties of LZW that we don't realize are so helpful
  308. until they are taken away. Most importantly, not every prefix of a
  309. dictionary string is in the dictionary. This means that the
  310. character-at-a-time search method we saw for LZW doesn't work. Instead,
  311. every prefix of a string in the dictionary must be added to the trie,
  312. and every node in the trie must be given a tag saying whether it is in
  313. the dictionary or not. Furthermore, finding the longest string may
  314. require backtracking: if the dictionary contains xxxx and xxxxxxxx, we
  315. don't know until we've read to the eighth character of xxxxxxxy that we
  316. have to choose the shorter string. This seems to imply that MW coding
  317. requires backtracking and hence is fundamentally slower than LZW coding.
  318. (Decoding can be made reasonably fast, though.)
  319.  
  320. Another problem is that a string may be added to the dictionary twice.
  321. This rules out certain implementations and requires extra care in
  322. others. It also makes MW a little less safe than LZW before encryption.
  323.  
  324.  
  325. --- AP: Adapting faster
  326.  
  327. There is a natural way to preserve the good adaptation of MW while
  328. eliminating its need for backtracking: instead of just concatenating the
  329. last two phrases and putting the result into the dictionary, put all
  330. prefixes of the concatenation into the dictionary. (More precisely, if S
  331. and T are the last two matches, add St to the dictionary for every
  332. nonempty prefix t of T, including T itself.) This defines AP coding. For
  333. example:
  334.  
  335.   I                     match  added to dictionary
  336.   yabbadabbadabbadoo    y        
  337.    abbadabbadabbadoo    a      ya
  338.     bbadabbadabbadoo    b      ab
  339.      badabbadabbadoo    b      bb
  340.       adabbadabbadoo    a      ba
  341.        dabbadabbadoo    d      ad
  342.     abbadabbadoo    ab     da, dab        (d + all prefixes of ab)
  343.       badabbadoo    ba     abb, abba      (ab + all prefixes of ba)
  344.         dabbadoo    dab    bad, bada, badab
  345.            badoo    ba     dabb, dabba
  346.          doo    d      bad
  347.           oo    o      do
  348.            o    o
  349.  
  350. Since AP adds more strings to the dictionary, it takes more bits to
  351. represent a choice. However, it does provide a fuller range of matches
  352. for the input string, and in practice it achieves slightly better
  353. compression than MW in quite a bit less time.
  354.  
  355.  
  356. ----- 4. Y coding
  357.  
  358. --- Completing the square
  359.  
  360. LZW adds one dictionary string per phrase and increments strings by one
  361. character at a time. MW adds one dictionary string per phrase and
  362. increments strings by several characters at a time. AP adds one
  363. dictionary string per input character and increments strings by several
  364. characters at a time. These properties define three broad classes of
  365. methods and point naturally to a fourth: coders that add one dictionary
  366. string per input character and increment strings by one character at a
  367. time. An example of such a method is Y coding. (It is worth noting at
  368. this point that LZ77 variants are characterized by adding several
  369. dictionary strings per input character.)
  370.  
  371.  
  372. --- The incomprehensible definition
  373.  
  374. Y coding is defined as follows: The dictionary starts with all single
  375. characters. One string pc starting at each input position is added to
  376. the dictionary, where p is in the dictionary before that character and
  377. pc is not.
  378.  
  379. To put it differently, ``yowie'' appears in the dictionary as soon as
  380. the regular expression yo.*yow.*yowi.*yowie matches the text. It is
  381. added at the final e. So yabbadabbadabbadoo leads to the dictionary ya,
  382. ab, bb, ba, ad, da, abb, bba, ada, dab, abba, bbad, bado, ado, oo.
  383.  
  384. We haven't defined the coding yet. While we build the dictionary, we
  385. keep track of a current longest match (initially empty). Right after
  386. reading an input character and before integrating it into the
  387. dictionary, we see whether the longest match plus that character is
  388. still in the dictionary *constructed before the start of that longest
  389. match*. If so, we use that as the new longest match, and proceed.
  390. Otherwise, we output the number of the longest match, and set the
  391. longest match to just that new character.
  392.  
  393. To decode, we read these matches, one by one. We take each one as a
  394. sequence of characters as defined by the dictionary, and output that
  395. sequence. Meanwhile we take each character and feed it as input to the
  396. dictionary-building routine.
  397.  
  398.  
  399. --- A comprehensible example
  400.  
  401. We can run through the string keeping track of dictionary matches, as
  402. follows:
  403.  
  404.   I                        add    current matches
  405.   abcabcabcabcabcabcabcx          a
  406.    bcabcabcabcabcabcabcx   ab     b
  407.     cabcabcabcabcabcabcx   bc     c
  408.      abcabcabcabcabcabcx   ca     a
  409.       bcabcabcabcabcabcx          ab b
  410.        cabcabcabcabcabcx   abc       bc c
  411.         abcabcabcabcabcx   bca          ca a
  412.          bcabcabcabcabcx   cab             ab  b
  413.           cabcabcabcabcx            _____  abc bc  c
  414.            abcabcabcabcx   abca    / \   \___  bca ca a
  415.             bcabcabcabcx   bcab   cab ab   b \____  \_/
  416.              cabcabcabcx   cabc       abc  bc   c \__/
  417.               abcabcabcx              abca bca  ca   a
  418.                bcabcabcx   abcab           bcab cab  ab    b
  419.                 cabcabcx   bcabc                cabc abc   bc   c
  420.                  abcabcx   cabca                     abca  bca  ca  a
  421.                   bcabcx           ,-----------------abcab bcab cab ab b
  422.                    cabcx   abcabc  `--bcabc cabc  abc    bc    c
  423.             abcx   bcabca           cabca abca   bca   ca   a
  424.              bcx   cabcab                 abcab  bcab  cab  ab  b
  425.               cx                          abcabc bcabc cabc abc bc c
  426.                x   abcabcx x
  427.                 bcabcx
  428.                  cabcx
  429.                   abcx
  430.                    bcx
  431.                 cx
  432.  
  433. The strings on the right side are the current matches-so-far after each
  434. input character. We start with no matches. When we read a character, we
  435. append it to each match so far; if the results are in the dictionary, we
  436. make them the new matches, and add the character as a match by itself.
  437. If any of them are not in the dictionary we take them out of the list
  438. and add them to the dictionary.
  439.  
  440. Before reading the fifth c, for example, the matches are bcab, cab, ab,
  441. and b. We append c to each one: bcabc doesn't match, so we add it to the
  442. dictionary. The rest are still in the dictionary, so our new list is
  443. cabc, abc, bc, and a lone c. And so on.
  444.  
  445. When the x is read, the current list is abcab bcab cab ab b. Now none of
  446. abcabx bcabx cabx abx bx are in the dictionary, so we add all of them,
  447. and the list becomes just a single x.
  448.  
  449.  
  450. --- The crucial observation
  451.  
  452. It is not clear so far that Y is a linear-time algorithm: each input
  453. character demands additions to several matches. However, *every
  454. substring of a dictionary string is in the dictionary*. This is clear
  455. from the regular-expression characterization of dictionary strings: if
  456. yo.*yow.*yowi.*yowie matches the text, then ow.*owi.*owie (for example)
  457. certainly does as well.
  458.  
  459. Say the current match list is wonka onka nka ka a, and we read the
  460. character x. The next list has to be one of the following:
  461.  
  462.   wonkax onkax nkax kax ax x
  463.          onkax nkax kax ax x
  464.                nkax kax ax x
  465.                     kax ax x
  466.                         ax x
  467.                            x
  468.  
  469. If onkax matches, for example, then nkax must match as well, and so must
  470. kax and ax and x.
  471.  
  472. So the match list will always consist of one string and its suffixes.
  473. Hence we can keep track of just the longest string in the match list.
  474. For example, with the input string oompaoompapaoompaoompapa:
  475.  
  476.   input  test   add    match
  477.   o                    o
  478.   o      oo     oo     o
  479.   m      om     om     m
  480.   p      mp     mp     p
  481.   a      pa     pa     a
  482.   o      ao     ao     o
  483.   o      oo            oo
  484.   m      oom    oom    om
  485.   p      omp    omp    mp
  486.   a      mpa    mpa    pa
  487.   p      pap    pap
  488.                 ap     p
  489.   a      pa            pa
  490.   o      pao    pao    ao
  491.   o      aoo    aoo    oo
  492.   m      oom           oom
  493.   p      oomp   oomp   omp
  494.   a      ompa   ompa   mpa
  495.   o      mpao   mpao
  496.             pao    ao
  497.   o      aoo           aoo
  498.   m      aoom   aoom   oom
  499.   p      oomp          oomp
  500.   a      oompa  oompa  ompa
  501.   p      ompap  ompap
  502.             mpap   pap
  503.   a      papa   papa
  504.                 apa    pa
  505.  
  506.  
  507. --- A comprehensible definition
  508.  
  509. Here is another definition of how to construct the Y dictionary, based
  510. on the chart above.
  511.  
  512.   0. Start with the dictionary mapping every character of A to a unique
  513.      integer. Set m to the empty string.
  514.   1. Append the next character c of I to m.
  515.   2. If m is not in the dictionary, then add m to the dictionary, remove
  516.      the first character of m, and repeat this step.
  517.   3. Repeat from step 1 until the input is exhausted.
  518.  
  519. We must be careful in defining output: the output is not synchronized
  520. with the dictionary additions, and we must be careful not to have the
  521. longest output match overlap itself. To this end we split the dictionary
  522. into two parts, the first part safe to use for the output, the second
  523. part not safe.
  524.  
  525.   0. Start with S mapping each single character to a unique integer;
  526.      T empty; m empty; and o empty. (S and T are the two parts of the
  527.      dictionary.)
  528.   1. Read a character c. If oc is in S, set o to oc; otherwise output
  529.      S(o), set o to c, add T to S, and remove everything from T.
  530.   2. While mc is not in S or T, add mc to T (mapping to the next
  531.      available integer), and chop off the first character of m.
  532.   3. After m is short enough that mc is in the dictionary, set m to mc.
  533.   4. Repeat as long as there are enough input characters (i.e., until
  534.      step 1 fails).
  535.   5. Output S(o) and quit.
  536.  
  537. Here's how to decode:
  538.  
  539.   0. Initialize (D,m) as above.
  540.   1. Read D(o) from the input and take the inverse under D to find o.
  541.   2. As long as o is not the empty string, find the first character c of
  542.      o, and update (D,m) as above. Also output c and chop it off from
  543.      the front of o.
  544.   3. Repeat from step 1 until the input is exhausted.
  545.  
  546. The coding only requires two fast operations on strings in the
  547. dictionary: testing whether sc is there if s's position is known, and
  548. finding s's position given cs's position. The decoding only requires the
  549. same operations plus finding the first character of a string given its
  550. spot in the dictionary.
  551.  
  552.  
  553. --- Some properties of Y coding
  554.  
  555. We propose ``per-phrase dictionary'' to describe the dictionaries
  556. constructed by LZW and MW, ``per-character dictionary'' for AP and Y.
  557. We also propose ``phrase-increment'' to describe MW and AP,
  558. ``character-increment'' for LZW and Y. More precisely, a per-phrase
  559. dictionary is one which contains one string per output phrase, while a
  560. per-character dictionary contains one string per input character. Each
  561. string in a character-increment dictionary is exactly one character
  562. longer than a string added at a previous step; in contrast, a string in
  563. a phrase-increment dictionary can be much longer than any of its
  564. prefixes formerly in the dictionary. According to this terminology,
  565. Y is an exact character-increment per-character dictionary compressor.
  566.  
  567. Y has a similar feel to LZJ, which has a dictionary consisting of all
  568. unique substrings up to a certain length in a block of the input.
  569. However, Y can adapt much more effectively to redundant text.
  570.  
  571.  
  572.  
  573. ----- 5. Results
  574.  
  575. The author has implemented Y coding [2] along with, for instruction and
  576. amusement, AP coding. In this section we survey various implementation
  577. issues and compare the effectiveness of the coding methods explained
  578. here.
  579.  
  580. The author's implementation, yabbawhap, uses a huptrie [3] for the
  581. dictionary. yabba keeps track of the separate dictionaries S and T for Y
  582. coding by remembering the highest position within D that is ``safe''
  583. inside S; all higher positions are in T.
  584.  
  585. yabbawhap uses compress's strategy of adaptive blocking. The user may
  586. vary most aspects of compression dynamically, including two parameters
  587. of the heuristic used to control blocking.
  588.  
  589. Here are results of these methods on the Bell-Witten-Cleary text corpus,
  590. along with a highly redundant 180489-byte ``makelog'' added by the
  591. author to show an extreme case.
  592.  
  593.      __bib__book1__book2____geo_makelog___news___obj1___obj2_paper1_paper2_
  594. Z12  54094 394419 325147  78026   34757 230765  16528 160099  29433  40881
  595. Z14  46817 357387 281354  77696   25647 202594  14048 138521  25077  37196
  596. Z16__46528_332056_250759__77777___25647_182121__14048_128659__25077__36161_
  597. MW___41040_336793_230862__80296____8299_168652__13273_109266__22749__34234_
  598. AP2  47056 389702 297205  84582   20925 219665  13824 134547  26937  39415
  599. AP6  40770 338046 261270  79471   14762 190502  13824 123323  22413  34637
  600. AP3__40311_322178_228978__80106____8821_167896__13825_113296__22414__33320_
  601. Y2   46882 363339 287110  80817   28159 212617  13858 141783  26131  38037
  602. Y6   40874 320622 256578  76275   21220 185097  13858 125900  22452  33671
  603. Y3___40456_306813_229851__76695___14411_168287__13859_114323__22453__32733_
  604.  
  605.     paper3_paper4_paper5_paper6_____pic__progc__progl__progp__trans_
  606. Z12  23567   7091   6670  22333   66236  21825  31987  22936  46185
  607. Z14  22163   6957   6580  18695   63277  19143  27116  19209  39605
  608. Z16__22163___6957___6580__18695___62215__19143__27148__19209__38240_
  609. MW___21495___6697___6169__16899___65102__16976__22223__15095__27742_
  610. AP2  22293   6595   6146  19770   74061  18868  27191  17962  38781
  611. AP6  20869   6595   6146  16786   68349  16691  22716  15138  30415
  612. AP3__20870___6596___6147__16787___67980__16692__22451__15139__28056_
  613. Y2   21609   6443   6033  19418   71952  18897  27607  19429  40444
  614. Y6   20355   6443   6033  16677   66117  17063  23625  16616  33026
  615. Y3___20356___6444___6034__16678___65377__17064__23512__16617__31300_
  616.  
  617. Z12 is LZW with 12 bits (i.e., a dictionary of at most 4096 strings),
  618. using compress -b12. MW is MW using the author's squeeze program [4],
  619. with a dictionary of at most 300000 strings (roughly equivalent to
  620. 1500000 input characters). AP2 is AP with an input block size of 21000,
  621. using whap -m21000; AP6 has a block size of 65533, and AP3 has a block
  622. size of 300000. Y is like AP but using yabba.
  623.  
  624. Y is notably effective upon book1 and news.
  625.  
  626. XXX what else do people want to see in this section?
  627.  
  628.  
  629.  
  630. ----- 6. Conclusion
  631.  
  632. --- Life goes on
  633.  
  634. Y coding is not much more complex than LZW coding and produces generally
  635. better results. It is one of the most effective non-Huffman-based
  636. LZ78-style compressors.
  637.  
  638.  
  639. --- How to achieve fame and fortune
  640.  
  641. It may be possible to implement Y so that the decoding does not have to
  642. do all the work of the coding. In particular, three-fourths of the
  643. dictionary strings are typically not used at all; they should not have
  644. to be handled during decoding. Even if Y cannot be sped up, there is
  645. probably some character-increment per-character dictionary compressor
  646. that achieves similar results to Y but runs as quickly as LZW or AP.
  647. This is a area for future research.
  648.  
  649. We have not discussed different ways to code the output numbers. Huffman
  650. coding and arithmetic coding both produce quite respectable improvements
  651. over and above the compression of the basic Y method. Little is known
  652. about the best way to code a sequence from a dynamically expanding
  653. alphabet; it is a bit counterintuitive that semiadaptive Huffman coding
  654. upon an output Y sequence can produce worse results than adaptive
  655. Huffman coding.
  656.  
  657. It would be interesting to compare a straight modeller with Y plus a
  658. Huffman coder to see which produces better results.
  659.  
  660.  
  661. --- Acknowledgments
  662.  
  663. The author would like to thank James Woods for his support and
  664. encouragement, as well as for many copies of papers; Richard Stallman,
  665. for motivating the author to find Y coding; and Herbert J. Bernstein for
  666. general comments and for suggesting the order of presentation of this
  667. material.
  668.  
  669.  
  670. --- So who are these LZWMWAPY people anyway?
  671.  
  672. LZW stands for Lempel, Ziv, Welch. In 1977 Ziv and Lempel discovered the
  673. first in what are now called the LZ family of dictionary compressors.
  674. The original LZ algorithms were like LZW, but transmitted both p and c
  675. and then skipped past pc. They also started with a dictionary of just
  676. the null string. (For detailed surveys of various LZ methods, the reader
  677. should consult [1], [5], [7], [11].) Welch popularized the LZ variant,
  678. now called LZW, in which the extra character was not transmitted but
  679. became the first character of the next phrase.
  680.  
  681. Miller and Wegman independently discovered several LZ variants in 1984,
  682. including LZW and MW. In fact, Seery and Ziv had in 1978 [6] proposed an
  683. LZ variant where two adjacent phrases were concatenated; this is related
  684. to MW in approximately the same way that LZ is related to LZW. (Seery
  685. and Ziv also introduced an important improvement for binary alphabets:
  686. if 01101 and 01100 are in the dictionary, there is no way that 0110 can
  687. possibly be a longest match, so it can effectively be removed from the
  688. dictionary.)
  689.  
  690. AP stands for ``all prefixes.'' It was originally discovered by Storer
  691. in 1988 (?) and independently rediscovered by this author in 1990.
  692.  
  693. Y actually does stand for yabbadabbadoo. The author discovered Y coding
  694. on December 26, 1990; he used yabbadabbadabbadoo as an example in
  695. explaining the method to Woods the next day. Woods replied [10] ``I'll
  696. have to look at your yabbadabbadoo code again to see how it differs from
  697. LZR.'' The author promptly adopted ``Y coding'' as the official name.
  698. (Ross Williams has suggested [12] that ``LZDB coding'' might be more
  699. appropriate.)
  700.  
  701.  
  702. --- References
  703.  
  704. Yeah, yeah, I'm still writing up proper citations. XXX
  705.  
  706. [1]  Bell, Witten, Cleary, compression article, 1989
  707. [2]  Bernstein, yabbawhap program, 1990-1991
  708. [3]  Bernstein, huptrie article, 1990
  709. [4]  Bernstein, squeeze program, 1989
  710. [5]  Miller and Wegman, compression article, 1987
  711. [6]  Seery and Ziv, LZ78 extensions article, 1978
  712. [7]  Storer, compression book, 1988
  713. [8]  Woods et al., compress program, 1985
  714. [9]  Woods, private communication, 1990
  715. [10] Woods, private communication, 1990
  716. [11] Williams, compression book, 1991
  717. [12] Williams, private communication, 1991
  718.