In a lot of texts regarding compression you will run across various
conventions of syntax to describe the coding of data. Much of them are
used in fields like automata
theory, group theory and
statistics. Although, the field of coding
theory itself has a long
and rich
history in
the 20st century; much of the terminology is borrowed from fields that
gave rise to it.
I find the best way to demonstrate the following definitions is by
example. Let us take the text "abbcc" as a sample.
Alphabet: The set of symbols that we will be encoding.
Form:Sigma
Example:Alphabet ExamplewhereAlphabet Example
String: A permutation of symbols from our alphabet. From our
example alphabet, strings like "a", "aba", "abc" or "cccb"
could all be possible. Using regular expression syntax, we can
describe this in our example.
Form:String
Example:String Example
Probabilities: The set of probabilities for the alphabet. This
is also known as their weights and can sometimes be denoted as w
instead of p.
Form:Probability
Example:Weights ExamplewhereProbabilities Examplesince 'a' occurs once, 'b' occurs twice and 'c' occurs
twice out of 5 symbols all together.
Codewords: The set of codewords that we will create for every
symbol in our alphabet.\
Form:Codeword
Example:Codeword ExamplewhereCodeword Examplefor symbolsCodeword Examplerespectively. Another way to look at it is that we are providing
a bijective function:Symbol to Codeword Mapping.
Standard coding of information for most computers today is byte aligned.
For example, in character codes there is
ASCII, which codes the entire
English alpha-numeric system in a single byte. While UTF-8 has proven to
be a much better standard due to better localization support and
variable width codes, ASCII serves our purposes for this discussion.
ASCII is considered a fixed width coding scheme:
::: {align=“center”}ASCII Codeword:::
When performance is at stake, it is best to code information atomically
aligned to the computer architecture that it is being used for. This
means allocating and defining information in terms of bytes (defined as
8-bits) for the majority of systems today. Although, if space is the
priority, performance can take a hit to shift around
bits
along the byte boundaries and create variable width codes that do not
byte align.
::: {align=“center”}Variable Width Codewords:::
Note: The ellipses in the alphabet denote the control characters (eg.
CR, LB) and grammatical structure symbols (eg. #, $, %) contained in
the ASCII code page. The alphabets will reflect this in the ellipses.
Coming back to the example of ASCII, if we wish to encode a string, w,
like "aaabb", it will take up 5 bytes. Although we only really need
one bit to encode our information if we assign 0 to 'a' and 1 to
'b'.
::: {align=“center”}String Example 1:::
We just took a 5 byte ASCII encoded string and compressed it down to
under a byte. Now let us take another string, w, and give it
"aaabbcc". Three alphabet symbols need to be coded; it will take at
least 2 bits. At first glance, this assignment would make sense:
::: {align=“center”}String Example 2:::
Although this gives us an ambiguous string since it could either be
"aaabbcc", "aaabbabab", "aacbcc" or any other permutation of our
codeword set when we attempt to decompress it. The reason for this
ambiguity is due to the fact that the codeword for 'a' (0), is used to
start the codeword for 'c' (01).
The way to get around this ambiguity is to ensure that all of your codes
are prefix type. Something
like this would work:
::: {align=“center”}String Example 2:::
This ensures that we maintain the one-to-one mapping between our
alphabet and codewords; we can translate alphabet symbols to codewords
and codewords back to alphabet symbols without confusion.
So how do you decide which symbols, get which codewords? Also, since the
size of the codeword is critical to the compression ratio (average
codeword length to average symbol length), designing an algorithm to
weigh the more frequently used symbols is important. In our previous
example, it would be poor design to give 'a' the longest codeword
because it is the most used symbol in the string. This is where the
Huffman Coding algorithm comes into play.
If you need further examples, you can look
here,
here and
here. Once the
you get a grasp of the algorithm, you will see the simplicity and beauty
of it.
If you want to see a naive implementation of the Huffman Coding
algorithm, I posted some source code on my GitHub
account. Below is the
central code to the algorithm execution.
Introduction # I was working on implementing a simple compression tool based on naive Huffman coding and initially assumed all of my prefix codes would be at or under a byte long. Although I failed to account for the worst case of Huffman coding, which can yield codes up to 255 bits in length.
I was recently working on solving problem 64 for project Euler and one of the needed algorithms was a detection of cycles in a list. This routine works for detecting cycles in lists of cardinality greater than 2.
\
I have been working on a game where enemy characters must select a target seemingly at random but such that the distribution of selected targets is balanced. Initially I had come up with a randomization algorithm with weighted values for each target but this became cumbersome and much too complex.
Then I remembered the scheduling algorithms from my Operating Systems class. In particular, the lottery scheduling algorithm.
\