Hamming codes and error correction
3Blue1Brown
3.59M subscribers
A discovery-oriented introduction to error correction codes.
Part 2: https://youtu.be/b3NxrZOu_CE
Ben Eater:'s take: https://youtu.be/h0jloehRKas
Many thanks to these supporters: https://3b1b.co/hamming-thanks
Heavily related is the chessboard puzzle I did with Matt Parker:
https://youtu.be/as7Gkm7Y7h4
You can read Hamming's own perspective on his discovery of these codes in chapter 12 of "The Art of Doing Science and Engineering".
https://amzn.to/3lwcnmh
The viewer Harry Li made an interactive on this topic:
https://harryli0088.github.io/hamming...
These animations are largely made using manim, a scrappy open-source python library: https://github.com/3b1b/manim
If you want to check it out, I feel compelled to warn you that it's not the most well-documented tool, and it has many other quirks you might expect in a library someone wrote with only their own use in mind.
Music by Vincent Rubinetti.
Download the music on Bandcamp:
https://vincerubinetti.bandcamp.com/a...
Stream the music on Spotify:
https://open.spotify.com/album/1dVyjw...
3blue1brown is a channel about animating math, in all senses of the word animate. And you know the drill with YouTube, if you want to stay posted on new videos, subscribe: http://3b1b.co/subscribe
Various social media links:
Website: https://www.3blue1brown.com
Twitter: https://twitter.com/3blue1brown
Reddit: https://www.reddit.com/r/3blue1brown
Instagram: https://www.instagram.com/3blue1brown...
Patreon: https://patreon.com/3blue1brown
Facebook: https://www.facebook.com/3blue1brown
00:04
Have you ever wondered how it’s possible to scratch a CD or DVD and still have it play
00:08
back whatever it’s storing?
00:10
The scratch really does affect the 1’s and 0’s on the disc, so it reads off different
00:15
data from what was stored, but unless it’s really scratched up, the bits it reads are
00:20
decoded into precisely the same file that was encoded on to it, a bit-for-bit copy,
00:26
despite all those errors.
00:27
There’s a whole pile of mathematical cleverness that allows us to store data, and just as
00:32
importantly to transmit it, in a way that’s resilient to errors.
00:37
Well, actually, it doesn’t take too much cleverness to come up with a way to do this.
00:42
Any file, whether it’s a video, or sound, or text, code, an image, whatever, is ultimately
00:48
stored as a sequence of 1’s and 0’s, and a simple strategy to correct any bit that
00:53
gets flipped would be to store three copies of each bit.
00:57
Then the machine reading the file could compare these three copies and always take the best
01:02
two out of three whenever there’s a discrepancy.
01:07
But what that means is using two thirds of your space for redundancy.
01:11
And even then, for all that space given up, there’s no strong guarantee about what happens
01:15
if more than 1 bit gets flipped.
01:18
The much more interesting question is how to make it so that errors can be corrected
01:21
while giving up as little space as possible.
01:24
For example, using the method you’ll learn about in this video, you could store your
01:28
data in 256-bit blocks, where each block uses nine bits –Nine!– to act as a kind of
01:34
redundancy, the other 247 bits are free to carry whatever meaningful message or data
01:39
you want.
01:40
And it will still be the case that if a bit gets flipped, just by looking at this block
01:45
and nothing more, a machine will be able to identify that there was an error and precisely
01:50
where it was, so that it knows how to correct it.
01:52
And honestly, that feels like magic.
01:55
And for this particular scheme, if two bits get flipped, the machine will at least be
01:59
able to detect that there were two errors, though it won’t know how to fix them.
02:03
We’ll talk later about how this scales for blocks of a different size.
02:08
Methods that let you correct errors like this are known, reasonably enough, as “Error
02:11
correction code.”
02:13
For the better part of the last century, this field has been a really rich source of surprisingly
02:18
deep math being incorporated into devices we all use every day.
02:22
The goal here is to give you a very thorough understanding of one of the earliest examples,
02:27
known as a Hamming code.
02:29
And by the way, the way I’m thinking about the structure of this video is less about
02:32
explaining it as directly as possible, and more a matter of prompting you to invent it
02:37
yourself, with some a little gentle guidance here and there.
02:40
So when you feel like you see where it’s going at some point, take that moment to pause,
02:43
actively predict what the scheme is going to be before I tell you.
02:47
Also, if you want that understanding to get down to the hardware level, Ben Eater has
02:51
made a video in conjunction with this one showing you how to actually implement Hamming
02:55
codes on breadboards, which is extremely satisfying.
02:58
Now, you should know, Hamming codes are not as widely used as more modern codes, like
03:02
the Reed Solomon algorithm.
03:04
But there is a certain magic to the contrast between just how impossible the task feels
03:08
at the start, and how utterly reasonable it is once you learn about Hamming.
03:14
The basic principle of error correction is that in a vast space of all possible messages,
03:19
only some subset are going to be considered valid messages.
03:22
As an analogy, think of correctly spelled words vs incorrectly spelled words.
03:29
Whenever a valid message gets altered, the receiver is responsible for correcting what
03:33
they see back to the nearest valid neighbor, as you might do with a typo.
03:38
Coming up with a concrete algorithm to efficiently categorize messages like this, though, take
03:43
a certain cleverness.
03:47
The story begins in the 1940s, when a young Richard Hamming was working for Bell Labs
03:51
and some of his work involved using a very big very expensive punchcard computer that
03:55
he had only limited access to.
03:57
And the programs he kept putting through it kept failing because every now and then a
04:01
bit would get misread.
04:03
Frustration being the crucible for invention, he got so fed up that he invented error correction
04:08
codes.
04:09
There are many different ways to frame Hamming codes, but as a first pass, we're going to
04:13
go through it the way that Hamming himself thought about them.
04:15
Let’s use an example that’s simple, but not too simple: A block of 16 bits.
04:21
We’ll number the positions of these bits from 0 up to 15.
04:25
The actual data we want to store is only going to make up 12 of these bits, while 4 of the
04:30
positions will be reserved as a kind of redundancy.
04:33
The word “redundant” here doesn’t simply mean copy, after all those four bits don’t
04:38
give us enough room to blindly copy the data.
04:40
Instead, they'll need to be a much more nuanced and clever kind of redundancy, not adding
04:45
any new information, but adding resilience.
04:48
You might expect these four special bits to come nicely packaged together, maybe at the
04:52
end or something like that, but as you’ll see, having them sit in positions which are
04:56
powers of 2 allows for something that's really elegant by the end.
04:59
It also might give you a little hint about how this scales for larger blocks.
05:04
Also, technically it ends up being only 11 bits of data; you’ll find there’s a mild
05:09
nuance for what goes on with position 0, but don’t worry about that for now.
05:14
Like any error correction algorithm, this will involve two players: A sender who is
05:18
responsible for setting these four special bits, and then a receiver who is responsible
05:22
for performing some checks and correcting any errors.
05:26
Of course, the words “sender” and “receiver” really refer to machines or software that's
05:29
doing all these checks, and the idea of a message is meant really broadly, to include
05:33
things like storage.
05:35
After all, storing data is the thing as sending a message, just from the past to the future
05:40
instead of from one place to another.
05:42
So that’s the setup, but before we can dive in, we need to talk about a related idea which
05:46
was fresh on Hamming’s mind in the time of his discovery, a method which lets you
05:51
detect any single-bit error, but not to correct them, known in the business as a “parity
05:56
check”.
05:57
For a parity check, we separate out only a single bit that the sender is responsible
06:01
for tuning, and the rest are free to carry a message.
06:04
The only job of this special bit is to make sure the total number of 1’s in the message
06:10
is an even number.
06:12
For example, right now that total number of 1’s is 7, that's odd, so the sender needs
06:16
to flip that special bit to be a 1, making the count even.
06:20
But if the block had already started off with an even number of 1’s, then this special
06:25
bit would have been kept at a 0.
06:27
This is pretty simple, deceptively simple, but it’s an incredibly elegant way to distill
06:31
the idea of change anywhere in a message to be reflected in a single bit of information.
06:37
Notice, if any bit of this message gets flipped, either from 0 to 1 or 1 to 0, it changes the
06:43
total count of 1’s from being even to being odd.
06:48
So if you're the receiver, you look at this message, and you see an odd number of 1’s,
06:51
you can know, for sure, that some error occurred, even though you might have no idea where it
06:57
was.
06:58
In the jargon, whether a group of bits has an even or odd number of 1’s is known as
07:02
its “parity”.
07:04
You could also use numbers and say that the parity is 0 or 1, which is typically more
07:08
helpful once you start doing math with the idea.
07:11
And this special bit that the sender uses to control the parity is called a “parity
07:16
bit”.
07:17
And actually, we should be clear, if the receiver sees an odd parity, it doesn't necessarily
07:22
mean there was just 1 error.
07:23
There might have been 3 errors, or 5, or any other odd number, but they can know for sure
07:28
that it wasn’t 0.
07:29
On the other hand, if there had been 2 errors, or any even number of errors, that final count
07:35
of 1’s would still be even, so the receiver can’t have full confidence that an even
07:39
count necessarily means the message is error-free.
07:43
You might complain that a method which gets messed up by only two bit flips is pretty
07:47
weak, and you would be absolutely right!
07:49
Keep in mind, though, there is no method for error detection, or correction, that could
07:54
give you 100% confidence that the message you receive is the one the sender intended.
07:59
After all, enough random noise can always change one valid message into another valid
08:03
message just by pure chance.
08:05
Instead, the goal is to come up with a scheme that's robust up to a certain maximum number
08:10
of errors or maybe to reduce the probability of a false positive like this.
08:16
Parity checks on their own are weak, but by distilling the idea of change across a full
08:21
message down to a single bit, what they give us is a powerful building block for more sophisticated
08:26
schemes.
08:27
For example, as Hamming was searching for a way to identify where an error happened,
08:32
not just that it happened, his key insight was that if you apply some parity checks,
08:37
not to the full message, but to certain carefully selected subsets, you can ask a more refined
08:42
series of questions that pin down the location of any single-bit error.
08:46
The overall feeling is a bit like playing a game of 20 questions, asking yes or no queries
08:51
that chop the space of possibilities in half.
08:54
For example, let's say we do a parity check on just these 8 bits, all the odd-numbered
08:59
positions.
09:00
Then if an error is detected, it gives the receiver a little more information about where
09:04
specifically the error is; namely that it’s in an odd position.
09:09
If no error is detected among those 8 bits, it either means there's no error at all, or
09:14
it sits somewhere in the even position.
09:17
You might think that limiting a parity check to half the bits makes it less effective,
09:21
but when it’s done in conjunction with other well-chosen parity checks, it counterintuitively
09:25
gives us something more powerful.
09:28
To actually set up that parity check, remember, it requires earmarking some special bit that
09:34
has control for the parity of that full group.
09:37
Here let's just choose position number 1.
09:39
So for the example shown, the parity of these 8 bits is currently odd, so the sender is
09:43
responsible for toggling that parity bit, and now it's even.
09:48
This is only one out of four parity checks we’ll do.
09:51
The second check is going to be among the 8 bits on the right half of the grid, at least
09:55
as we've drawn it here.
09:56
This time, we might use position number 2 as a parity bit.
09:59
So these 8 bits already have an even parity, and the sender can feel good leaving that
10:04
bit number 2 unchanged.
10:06
Then, on the other end, if the receiver checks the parity of this group and they find that
10:11
it’s odd, they’ll know that the error is somewhere among these 8 bits on the right.
10:15
Otherwise, it means either there's no error, or the error is somewhere on the left half.
10:20
Or I guess there could have been two errors, but for right now we’re going to assume
10:24
that there’s at most one error in the entire block; things break down completely for more
10:28
than that.
10:29
Here, before looking at the next two checks, take a moment to think about what these first
10:32
two allow us to do when you consider them together.
10:35
Let's say you detect an error among the odd columns, and among the right half.
10:40
It necessarily means the error is somewhere in the last column.
10:43
If there was no error in the odd column, but there was one in the right half, well that
10:48
tells you it's in the second to last column.
10:50
Likewise, if there is an error in the odd columns but not the right half, you know that
10:54
it's somewhere in the second column.
10:56
And then, if neither of those two parity checks detects anything, it means the only place
11:00
an error could be is in that leftmost column, but it also might simply mean there’s no
11:05
error at all.
11:06
Which is all a rather belabored way to say that two parity checks let us pin down the
11:10
column.
11:11
From here, you can probably guess what follows.
11:13
We do basically the same thing, but for the rows.
11:16
There’s going to be a parity check on the odd rows, using position 4 as a parity bit.
11:21
So in this example, that group already has even parity, so bit 4 would be set to a 0.
11:26
And finally there's a parity check on the bottom two rows, using position 8 as a parity
11:31
bit.
11:32
In this case, it looks like the sender needs to turn on bit 8 on in order to give that
11:35
group an even parity.
11:37
Just as the first two checks let us pin down the column, these next two let you pin down
11:41
the row.
11:42
As an example, imagine that during transmission there’s an error at, say position 3.
11:47
Well, this affects the first parity group, and it also affects the second parity group,
11:52
so the receiver knows that there's an error somewhere in that right column.
11:56
But it doesn’t affect the third group, and it doesn't affect the fourth group.
12:01
And that lets the receiver pinpoint the error up to the first row, which necessarily means
12:05
position 3, so they can fix the error.
12:08
You might enjoy taking a moment to convince yourself that the answers to these four questions
12:12
really will always let you pin down a specific location, no matter where they turn out to
12:16
be.
12:17
In fact, the astute among you might even notice a connection between these questions and binary
12:22
counting.
12:23
And if you do, again let me emphasize, pause, try for yourself to draw the connection before
12:27
I spoil it.
12:30
If you’re wondering what happens if a parity bit itself gets affected…well you can just
12:35
try it.
12:36
Take a moment to think about how any error among these four special bits is going to
12:40
be tracked down just like any other, with the same game of 4 questions.
12:47
It doesn’t really matter, since at the end of the day what we want is to protect the
12:50
message bits, the error correction bits are just riding along, but protecting those bits
12:54
as well is something that naturally falls out of this scheme as a byproduct.
12:59
You might also enjoy anticipating how this scales.
13:02
If we used a block of size 256 bits, for example, in order to pin down a location, you need
13:08
only 8 yes or no questions to binary search your way down to some specific spot.
13:15
And remember, each question requires giving up only a single bit to set the appropriate
13:19
parity check.
13:23
Some of you may already see it, but we’ll talk later about the systematic way to find
13:26
what these questions are in just a minute or two.
13:29
Hopefully, this sketch is enough to appreciate the efficiency of what we’re developing
13:33
here.
13:34
Everything except for those 8 highlighted parity bits, can be whatever you want it to
13:38
be, carrying whatever message or data you want.
13:41
The 8 bits are “redundant” in the sense that they’re completely determined by the
13:45
rest of the message, but it’s in a much smarter way than simply copying the message
13:49
as a whole.
13:53
And still, for so little given up, you would be able to identify and fix any single bit
13:59
error.
14:00
Well...almost.
14:01
Okay, so, the one problem here is that if none of the four parity checks detect an error,
14:05
meaning that the specially selected subsets of eights bits all have even parities just
14:10
like the sender intended, then it either means there was no error at all, or it narrows us
14:15
down into position 0.
14:17
You see, with four yes or no questions, we have 16 possible outcomes for our parity checks.
14:22
And at first, that feels perfect for pinpointing 1 of the 16 positions in the block.
14:27
But you also need to communicate a 17th outcome, the “no error” condition.
14:33
The solution here is actually pretty simple: Just forget about 0th bit entirely.
14:37
So when we do our four parity checks, and we see that they're all even, it unambiguously
14:41
means that there is no error.
14:44
What that means, is that rather than working with a 16-bit block, work with a 15-bit block,
14:49
where 11 of the bits are free to carry a message, and 4 of them are there for redundancy.
14:54
And with that, we now have what people in the business would refer to as a “(15, 11)
14:58
Hamming code”.
14:59
That said, it is nice to have block size that's a clean power of 2, and there’s a clever
15:04
way that we can keep that 0th bit around and get it to do a little extra work for us.
15:08
If we use it as a parity bit across the whole block, it lets us actually detect, even though
15:13
we can't correct, 2-bit errors.
15:15
Here’s how it works.
15:17
After setting those four special error-correcting bits, we set that 0th bit so that the parity
15:21
of the full block is even, just like a normal parity check.
15:25
Now if there’s a single-bit error, then the parity of the full block toggles to be
15:29
odd, but we would catch that anyway thanks to our four error-correcting checks.
15:33
However, if there are two errors, then the overall parity is going to toggle back to
15:38
being even, but the receiver will still see that there’s been at least some error because
15:42
of what's going on with the four usual parity checks.
15:45
So if they notice an even parity overall, but something nonzero happening with the other
15:50
checks, it tells them there were at least two errors.
15:52
Isn’t that clever?
15:54
Even though we can’t correct those two-bit errors, just by putting that one little bothersome
15:58
0th bit to work, it lets us detect them.
16:02
This is pretty standard, it's known as an “extended” hamming code.
16:06
Technically speaking, you now have a full description of what a Hamming code does, at
16:10
least for the example of a 16-bit block.
16:13
But I think you'll find it more satisfying to check your understanding and solidify everything
16:17
up to this point by doing one full example from start to finish yourself.
16:21
I’ll step through it with you, though, so you can check yourself.
16:24
To set up a message, whether that’s a literal message that you’re transmitting over space,
16:29
or some data that you want to store over time, the first step is to divide it up into 11-bit
16:34
chunks.
16:35
Each chunk is going to get packaged into an error-resistant 16-bit block, so let’s take
16:40
this one as an example and actually work it out.
16:43
Go ahead, actually do it, pause and try putting together this block
16:46
....okay, you ready?
16:51
Remember, position 0 along with all the powers of 2 are reserved for error-correction duty,
16:59
so you start by placing the message bits in all of the remaining spots, in order.
17:05
You need this group to have even parity, which it already does, so you should have set the
17:10
parity bit in position 1 to be a 0.
17:13
The next group starts off with odd parity, so you should have set its parity bit to 1.
17:19
The group after that starts with odd parity, so again you should have set it’s parity
17:23
bit to 1.
17:24
And the final group also has odd parity, meaning we set that bit in position 8 to be a 1.
17:31
And then, as the final step, the full block now has even parity, meaning that you can
17:36
set that bit number 0, the overarching parity bit, to be 0.
17:41
So as this block is sent off, the parity of the four special subsets, and the block as
17:45
a whole, will all be even, or zero.
17:48
As the second part of the exercise, let’s have you play the role of the receiver.
17:53
Of course, that would mean you don’t already know what this message is; maybe some of you
17:57
memorized it but, let’s assume that you haven’t.
18:00
What I’m going to do is change either zero, one or two of the bits in that block, and
18:05
then ask you to figure out what it is that I did.
18:08
So, again, pause and try working it out.
18:15
...okay, so you as the receiver now check the first parity group and you can see that
18:23
it’s even, so any error that exists would have to be in an even column.
18:29
The next check gives us an odd number, telling us both that there’s at least one error,
18:34
and narrowing us down into this specific column.
18:38
The third check is even, chopping down the possibilities even further.
18:41
And the last parity check is odd, telling us there’s an error somewhere in the bottom,
18:46
which by now we can see must be in position number 10.
18:50
What’s more, the parity of the whole block is odd, giving us confidence that there was
18:56
one flip and not two (if it’s three or more, all bets are off).
19:01
After correcting that bit number 10, pulling out the 11 bits that were not used for correction
19:06
gives us the relevant segment of the original message, which if you rewind and compare,
19:11
is indeed exactly what we started the example with.
19:16
And now that you know how to do all this by hand, I’d like to show you how you can carry
19:19
out the core part of all of this logic with a single line of python code.
19:23
You see, what I haven’t told you yet is just how elegant this algorithm really is,
19:28
how simple it is to get a machine to point to the position of an error, how to systematically
19:32
scale it, and how we can frame all of this as one single operation rather than multiple
19:37
separate checks.
19:39
To see what I mean, come join me in part 2.