QEC 101 Lab 1 - The Basics of Classical and Quantum Error Correction
Overview
One of the biggest challenges in realizing practical quantum computing is the noisy nature of qubits, making quantum error correction (QEC) essential for detecting and fixing errors in real time. In this lab, you’ll explore the fundamentals of error correction (EC) concepts and terminology, walk through examples of classical EC codes, examine how QEC differs from classical methods, and ultimately get hands-on experience coding your first QEC procedure.
Prerequisites: Learners should have familiarity with Jupyter notebooks and programming in Python and CUDA-Q. It is assumed the reader has some familiarity already with quantum computation and is comfortable with braket notation and the concepts of qubits, quantum circuits, measurement, and circuit sampling. The CUDA-Q Academic course entitled "Quick Start to Quantum Computing with CUDA-Q" provide a walkthrough of this prerequisite knowledge if the reader is new to quantum computing and CUDA-Q or needs refreshing.
The list below outlines what you'll be doing in each section of this lab:
1.1 Define the basics of EC, including the 5 aspects common to EC procedures
1.2 Code the classical repetition code
1.3 Code the classical Hamming code
1.4 Experiment with noisy qubits to understand what makes QEC challenging
1.5 Explore why there is still hope for QEC
1.6 Learn the theory for the quantum repetition code
1.7 Implement the quantum repetition code in CUDA-Q
Terminology and notation you'll use
encoder, decoder, logical codewords, codespace, error space, noisy channel, logical error, logical error rate
repetition code, Hamming code, -codes
syndrome
Execute the cells below to load all the necessary packages for this lab.
1.1 The Basics of Error Correction
Classical Error correction (EC) is the practice of redundantly encoding data using additional bits such that if some of the data bits are corrupted (flipped from a 0 to a 1 or vice versa) by external noise, the error can be fixed and the integrity of the original data preserved. There are many potential ways to accomplish this and any specific procedure is referred to as an EC code.
It is thanks to EC that you can still watch a DVD that has many scratches, enjoy a clear telephone conversation despite the signal becoming noisy after transmission over long distances, or scan a QR code at a restaurant that is partially obscured. Try it yourself. Pull up a QR code and try covering different parts with your hand and notice that your phone can still interpret the link despite obfuscation of some parts of the grid. EC has its limits, but in many cases can essentially eliminate any negative impacts of noise.
There are five aspects to any general EC procedure:
All EC procedures assume there is some initial information that needs to be preserved or transmitted. The sender and recipient need to interact with the same information even if it is stored in different ways throughout an EC procedure.
An EC procedure first encodes the information across data bits such that is larger than the minimum number of bits necessary to store the information. For example, the repitition code that we'll cover in the next section uses 3 bits to encode some binary information stored on a single bit by simply repeating the information stored on the single bit three times.
The encoding procedure produces logical codewords which are the redundant encodings that map to the logical states. For example, logical 1 could be defined with the codeword 111.
A logical codeword then proceeds through a noisy channel. A noisy channel has some probability of randomly corrupting (flipping) any of the data bits.
The recipient then receives the encoded data and needs to decode it to determine if an error occurred and how they might fix it. Another way to say this, is that the decoder takes the message the recipient receives and determines which logical codeword is "closest" to it. If the decoder produces the correct logical codeword, the EC procedure worked. If not, a logical error occurred and the recipient incorrectly interprets the message - the worst case scenario.
No EC procedure is perfect, and is usually benchmarked against Shannon's limit which is the theoretical limit of the rate of noise free data transfer that can occur through a channel with a given bandwidth and noise level.
In practice, and EC code need to be just "good enough" to ensure that errors do not usually impede the target application. Generally speaking, the more redundancy (extra bits) used in the encoding process, the better the EC will be, but this also comes at the cost of more memory and time to perform more sophisticated encoding and decoding. Thus, there is always a tension between the resources available for error correction and the logical error rate of the procedure necessary for a given application.
1.2 The Repetition Code
The most basic EC code is called the repetition code.
Consider encoding the information in a single bit (0 or 1). The repetition code simply adds more bits which are in the same state. So a 3-bit repetition code encodes the logical 0 state () as 000 and the logical 1 state () as 111, making 000 and 111 the logical codewords.
Now, assume is transmitted through a noisy channel such that each data qubit has a probability p=0.1 of flipping erroneously. This means there are eight possible states the encoded message could be in after proceeding through the noisy channel. The states can be sorted into two groups. The space of all logical codewords (000 and 111) is called the codespace:
| Codespace (as bitstrings) | Codespace (as logical states)| | ----------- | ----------- | | 000 | | | 111 | |
while the rest of all the potentially received messages belong to the error space as shown in the table below.
The job of the decoder is to map encodings in the error space back to a logical codeword in the codespace. This is usually done through the help of a calculated property that describes the state called a syndrome. In this case, the syndrome is a majority count of the bits. So, the syndrome of the 101 state would be 2 (the count of how many 1's) and corresponds to logical 1 and the syndrome of 001 would be 1. Additionally, the syndrome of 111 is 3 and the syndrome of 000 os 0. So we can apply the decoding rule that a message with a syndrome of 2 or 3 would be decoded as 111, and message with a syndrome of 0 or 1 would be decoded as 000.
| Error Space | Closest logical state to the received message | Error, if only one error occurred in transmission | Syndrome | | ----------- | ----------- | ----------- | ----------- | | 001 | 000 | right most bit | 1| | 010 | 000 | middle bit | 1| | 100 | 000 | left most bit | 1 | | 110 | 111 | right most bit | 2| | 101 | 111 | middle bit | 2 | | 011 | 111 |left most bit | 2 |
Any single bit error can be correctly identified and corrected, but two or more bit flips will result in a logical error. There is no way to know for certain if 110, for example, is a single error from the codeword or two bit errors from the codeword. However, the repetition code still greatly reduces the probability of a logical error compared to no encoding. To be very conservative you could discard results where any error was detected and resend the message. In this error detection (not correction) case, a logical error will only occur in the highly unlikely case of three bit flip errors, where 000 was transmitted but 111 was received. This approach requires additional data transfers to compensate for the cases where errors occurred. Error correction can eliminate the need for extra data transfers at the expense of possibly mistaking a 2-bit error for a 1-bit error. This hints at an important property of error correction codes: distance.
Codes are characterized with the so called [n,k,d] notation where n is the number of data bits used to encode k logical bits and d is the distance. The distance is the number of errors that must occur for one logical codeword to become the next closest codeword. In our example of the three bit repetition code , , and , so we refer to this as a [3,1,3] code. The number of errors a code can correct is a function of code distance and can be calculated as
The table below shows the likelihood of the four possible scenarios below. Notice the three bit repetition code with majority count will transmit the message with 0.972 probability of success, a significant improvement over the original probability of 0.9. The logical error rate is equal to , where is the probability of success. In the case of the 3-bit repetition code, the logical error rate is 0.028.

Exercise 1 - The repetition code:
You now know enough to code up the repetition code. The exercise below will require you to generalize the repetition code so it will work with bits. Fill in the #TODO sections and then observe the plots that are generated. What conclusions can you draw from the code performance using more bits? What do you notice about the logical error rate relative to the physical error rate?
1.3 More Efficient EC Codes (The Hamming Code)
There are many clever ways to improve the efficiency of EC codes. One common way is to make use of a concept called parity checks. Parity checks provide a clever way to index where errors occur, without a brute force statistical approach like the repetition code.
The Hamming code is a great example of a parity check code. The [7,4,3] Hamming code consists of four data bits () and three additional parity check bits (). This example will only consider single bit errors as this is another distance 3 code and can only correct single bit errors.
This is accomplished by each parity bit encoding a parity, or the mod2 sum of a subset of the data bits. The Venn diagram below depicts the encoding. In this example, encodes the parity of , , and . If our data bits () were 0110, then would be calculated to be 1.
Either using the static Venn diagram above or the interactive one generated by executing the cell below, reason through the following example:
If you wanted to send the message 0110 (here , , , and ), appending the three parity bits to the end of the original bitstring would produce the logical codeword: 0110110 (where , , and ). Note, this is a slight deviation from the traditional placement of the bits in the Hamming code done for simplicity.
Errors could occur on any of the data or parity bits. Assume an error occurs on and the recipient receives 0010110. To produce the syndrome, the recipient can take the received data bits, 0010, and compute the expected parity. This is then compared to the parity that was sent, 110. The parity bits that disagree flag an error.
In this case, the received message has parity bits 011 which disagrees with 110. Here, and are flagged. This syndrome can only correspond to an error on based on the Venn diagram.
The Hamming code takes advantage of the fact that the parity bits can encode up to syndromes, more than enough to consider the seven possible single bit flip errors that could occur. This means, 4 bits can be encoded with 7 bits which is an improvement over the to 1 encoding of the repetition code.
Checkpoint: Suppose you sent the logical code word 0110110, but the recipient received the message 0110100. We'll assume that at most only one error occurred. Would the recipient be able to identify if there was an error? If so, could they locate the error? Hint: errors could occur on any of the data or the parity bits.
In practice, a large message can be broken into blocks with each block is encoded using the Hamming code. The code scales much better than the repetition code. A Hamming code can be produced for any integer greater than 1, such that the code is characterized as . So for a message of size , the Hamming code would require only bits while a three bit repetition code would require bits.
Exercise 2 - The matrix form of the Hamming code:
The Hamming code is commonly constructed with special matrices so a few simple linear algebra operations can encode and decode messages. The next two cells will have you define these matrices and see if you can reproduce the example above.
First, define the generator matrix such that a dot product between the message and mod2 performs the valid encoding. Hint: G should be a 4x7 matrix.
Now, define the parity check matrix such that produces a syndrome, where is the received message vector.
1.4 What Makes QEC so Hard?
QEC shares the same goal as classical EC, but comes with a number of unique challenges thanks to the properties of quantum mechanics. This section will list the primary differences, and the following section will explain how these challenges can be addressed.
Continuous Errors - Classical errors are always discrete bit flips. Quantum errors are continuous and can manifest in an infinite number of ways, potentially shifting a qubit's state to any point on the Bloch sphere. For instance, the figure below illustrates many possible errors that affect a qubit starting in the state. Errors can perturb states incoherently (from environmental effects) or coherently from slight hardware imperfections. This invites the question, "Does QEC require an infinite amount of resources to correct errors?"

No Cloning - Quantum states cannot be copied. That is to say that the following expression holds:. This means we cannot just send multiple copies of the quantum state through the noisy channel like the classical repetition code.
Destructive Measurement - In classical EC, the state can be accessed at any time, making decoding much easier. Measuring a quantum state collapses it, making the EC moot if the state is destroyed. Therefore, more clever ways to extract syndromes are required. A secondary consequence of this fact is sampling error. Even if an algorithm could perform perfectly ensuring no sources of error, many applications require statistical sampling of the resulting state. If we sampled the frequency of 0's would be close to but deviate based on the number of samples per the Central Limit Theorem.
Scalability - Though scalability is an issue for classical EC, it is far more severe for QEC. Today's noisy intermediate scale quantum devices are very difficult to control, so each additional qubit required for QEC comes at great cost. Qubits also have short coherence times, so QEC procedures must complete within strict time constraints which gets harder at scale. Finally, the threshold theorem is in play. In classical EC, adding more bits always reduces the logical error rate. This is not true for quantum - physical qubits must have noise below a specific threshold in order for scaling the code to improve the error rates, otherwise, the results just get worse.
1.5 There is still hope for QEC!
The challenges discussed above are daunting but there are many ingenious techniques developed to help circumvent them. That said, practical QEC remains difficult to realize and is an extremely active research field - viewed as one of the most important prerequisites for useful quantum computing. This section will begin to bridge the gap between classical EC and QEC.
Digitization of errors
Errors can perturb states incoherently from environmental effects or coherently from slight hardware imperfections. While both types of errors can be addressed, we’ll focus on coherent errors first because they’re often easier to isolate and analyze.
For instance, a rotation gate that should be at an angle of ends up being more like 0.17. This may seem inconsequential, but imperfections like this accumulate and quickly ruin the outcome of a quantum algorithm. Execute the code block below and use the slider to change the number of rotation gates executed to see how the error can become substantial. Feel free to experiment with different values for the angle, noisy_angle, and the rotation axis in the rotation_kernel.
Among the various coherent errors that can occur on a qubit storing the quantum state , we will focus on three specific types:
Bit flip errors swap a qubit's amplitudes, transforming to .
Phase flip errors introduce a sign change in one of the amplitudes, transforming to .
Combining a bit flip with a phase flip error swaps amplitudes and applies a sign change, transforming to .
Run the cell below to open an interactive tool that allows you to visualize the impact of different error types on various quantum states. Observe how some error types may not alter the state. Why do you think that happens? What patterns can you identify?
Once we have identified one of these errors, we can correct it. For instance, if a qubit has undergone a bit flip error, we can correct it by applying an gate. Similarly, to correct a qubit that has experienced a phase flip error, we simply apply a gate. How would you correct a qubit that has been identified as having undergone a bit flip error followed by a phase flip error?
We can address all coherent errors with a key insight: although the Bloch sphere suggests errors can occur through infinitely many possible rotations, all such errors can be broken down into three basic forms — bit flips, phase flips, or a combination of both bit flips and phase flips.
If you'd like an explanation of why this decomposition works, consult the optional section below. For now, remember that by detecting and correcting these three core error types, we can effectively handle any coherent noise.
Optional: Consider a qubit in the following normalized state. Coherent errors can be represented by the application of a Unitary which acts on the ideal state and perturbs it. Using the fact that the Pauli matrices form a basis for any 2x2 unitary matrix and taking advantage of the identity , the operation can be rewritten as This means that any coherent error can be digitized into X-type bit flip errors (), Z-type phase flip errors (), or a combination of the two (XZ). This makes correction much more tractable, as there are only three types of errors to consider.
Syndrome Extraction
The no cloning principle means quantum states cannot be copied for QEC. We'll need a clever way to extract syndromes from the logical state that does not rely on repetition. But, how is this done without destroying the information that is being protected?
The solution involves stabilizers which are specially designed operators that act on a logical state without changing it, but still enable us to learn about errors by performing projective measurement of ancilla qubits. The next notebook in this series will introduce stabilizers with more mathematical rigor, and the example in section 1.6 of this lab will provide a more concrete example of a simple stabilizer in action.
Better QEC codes and AI solutions
Finally, overcoming the QEC scaling challenges will require breakthroughs on many fronts. Significant research efforts are targeting discovery of more efficient QEC codes that require fewer qubits. AI is already showing great promise as a tool to help find new QEC codes, and accelerate decoding. Later notebooks will explore AI for QEC applications.
1.6 The Quantum Repetition Code
A quantum state cannot be cloned, but it can be redundantly encoded across additional entangled qubits. Let's start with a generic normalized qubit state :
The 0 and 1 states can be encoded into a logical state making use of the larger 8-dimensional Hilbert space of three qubits:
Note that this is not equivalent to .
Consider now the entire Hilbert space spanned by the eight basis states. The basis states are separated into the logical codewords that make up the codespace:
| Codespace | Notation for the logical codewords| | ----------- | ----------- | | | | | | |
and the remaining basis states make up the error space:
| Error space | | ----------- | | | | | | | | | | | | |
Assume that the state is transmitted through a noisy channel and becomes ? How might it be decoded to tell which logical codeword it is closest to? Remember, you cannot simply examine the state and perform a majority count as no information about the state is accessible without some sort of measurement that induces wavefunction collapse.
Consider the operators and . (Remember that returns an eigenvalue of +1 if the nth qubit in a ket is a 0 and -1 if it is a 1). It turns out that these operators have special properties such that the eigenvalues produced when they act on any of the states in the codespace or error space can be extracted with ancilla qubits without disturbing the state. This means, there is a way to extract parity check information just like the classical Hamming code!
Note: Operators with these "special properties" are called stabilizers and will be rigorously introduced in the next lab.
The details of this extraction process are described shortly, but the implication is that syndromes can be produced from the parity check results and used to identify corrections to the quantum repetition code without destroying the encoded state. Considering only single bit flip errors, the table below shows the possible syndromes, the corresponding errors, and the operation that can be applied to correct the error assuming is the transmitted message.
| Syndrome | Syndrome| Encoded State | Single Bit Flip Correction | ----------- | ----------- | ----------- | ----------- | | 0 | 0 | | none | | 1 | 0 | | | | 0 | 1 | | | | 1 | 1 | | |
Like the classical repetition code, there is no way to know for certain if a 10 syndrome corresponds to a single bit flip error from the codeword or a two bit flip error from the codeword. However, it is always prudent to assume that the case with fewer errors is more likely.
The entire quantum circuit for the three qubit repetition code is shown below, where the ancilla qubits are used to compute the and syndromes.

It is helpful to explore in greater detail how the syndromes can be extracted using the ancilla qubits without disturbing the state. First, consider the initial state of the first ancilla after application of a Hadamard gate and the encoded state after a bit flip has occurred on the first data qubit.
Next, a controlled operation is applied to the data qubits resulting in
followed by an application of the second Hadamard:
Now, if is evaluated, the result is and the entire state simplifies to meaning upon measurement, the first ancilla qubit will be measured as 1 with certainty and the data qubits remain undisturbed in the state:
A similar analysis will show that the second ancilla qubit will be measured as 0 with certainty without distubring the data qubits. Accordoing to the syndrome table, this will trigger an application of the gate on the first qubit to correct the error.
1.7 Exercise 3: Coding the Quantum Repetition Code
Exercise 3 - The matrix form of the Hamming code:
Now that you understand the quantum repetition code, try to code it using CUDA-Q. Fill in each of the steps below marked "#TODO". CUDA-Q contains a couple of features particularly helpful for building QEC workflows. First, and already completed for you, is the definition of a custom noise model which produces custom identity operations that can randomly perform bit flips on specific qubits. Second, you can measure the ancilla qubits within the kernel and use the result to perform a correction operation. The documentation example on building kernels and mid-circuit measurement may be helpful for this exercise.
Try to code all the steps and then sample the kernel to determine the logical error rate.
Conclusion
You now have a basic understanding of EC and QEC. The next lab will explore stabilizers in more detail and equip you to code two of the most famous and fundamental QEC codes: the Shor code and the Steane code.