Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
NVIDIA
GitHub Repository: NVIDIA/cuda-q-academic
Path: blob/main/qec101/05_QEC_MSD.ipynb
1128 views
Kernel: Python 3 (ipykernel)
# SPDX-License-Identifier: Apache-2.0 AND CC-BY-NC-4.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

QEC 101

Lab 5- TT gates and Magic State Distillation

Fault tolerant quantum computing (FTQC) requires a universal gate set from which any quantum algorithm can be implemented. The T-gate is a challenging gate to implement fault tolerantly, yet holds the key to unlocking the power of quantum computing.

A common procedure for producing T-gates is called magic state distillation (MSD), and will likely consume the lion's share of the resources necessary to realize FTQC. Much quantum research is currently directed at finding ways to efficiently implement MSD.

In a recent paper titled Experimental Demonstration of the Logical Magic State Distillation, researchers from QuEra, MIT, and Harvard showcased MSD on QuEra's neutral atom quantum processor.

Prerequisites:

If you have completed the previous labs in this series (1-4), you should have a good foundation for the basics of QEC and the fundamentals of stabilizer codes, and have already coded up the Steane code which is used in the QuEra MSD implementation.

This lab will introduce the importance of T-gates, how MSD works, and allow you to implement a version of it yourself.

The list below outlines what you'll be doing in each section of this lab:

  • 5.1 Learn about the Clifford + TT gate set.

  • 5.2 Learn how fault tolerant TT gates are applied.

  • 5.3 Learn how magic state distillation works.

  • 5.4 Learn how QuEra performed MSD in their recent experimental paper.

  • 5.5 Write a CUDA-Q code to perform MSD distillation.

Terminology and notation you'll use:

  • universal gate set, T-gates, transversal gates

  • Eastin-Knill Theorem

  • magic state, magic state distillation, [[5,1,3]] code.

  • color code

To get started, run the cell below to install the prerequisite libraries and then restart the kernel.

💻 Just a heads-up: This notebook is designed to be run on an environment with a GPU. If you don't have access to a GPU, feel free to read through the cells and explore the content without executing them. Enjoy learning! ⭐

import cudaq from cudaq import spin from cudaq.qis import * import numpy as np import matplotlib.pyplot as plt from typing import List import sys try: import numpy as np import qutip except ImportError: print("Tools not found, installing. Please restart your kernel after this is done.") !{sys.executable} -m pip install --upgrade pip !{sys.executable} -m pip install qutip print("\nNew libraries have been installed. Please restart your kernel!") import cudaq cudaq.set_target('nvidia')

5.1 Clifford + TT Gates

So far in this QEC series, all of the QEC procedures have been contextualized as critical for realizing FTQC. However, FTQC is broader than QEC and involves careful consideration of all operations such that errors are not propagated through a computation. That is to say, implementing syndrome extraction of a QEC code correctly is a key step for preserving quantum memory, but still requires a set of FT operations (state prep, gate, measurement, etc) to perform computations in a way that ensures a single errors do not propogate uncontrollably.

For example, proper FT implementation of the Steane code would require logically encoded ancilla qubits to measure the stabilizers to make sure an ancilla qubit error does not become an uncorrectable error itself.

There are many aspects of FTQC that will not be covered here. However, the concept of a universal gate set needs to be introduced before the MSD protocol can be understood. A universal gate set is a set of quantum gates from which any unitary operation can be approximated to arbitrary precision. The is analogous to classical computing where any digital computation can be constructed from AND, NOT, and OR gates.

Certain gates, known as transversal gates, are nice to have in a gate set, because they are already fault tolerant. A transversal gate can be applied individually to every data qubit encoding a logical qubit such that if any of them have an error, it only affects the target data qubit. An example of a transversal get would be the XX operation in the Steane code. A logical XX is obtained by performing an XX on each data qubit and if any of those result in an error, it is correctable and will not propagate to the other data qubits.

So, all that is needed for FTQC to be easy is a universal gate set consisting only of transversal gates. Unfortunately, no such set exists. The Eastin-Knill Theorem proves that no quantum error-correcting code can implement a universal set of gates using only transversal operations.

The most common universal gate set is the Clifford + T gates. The Clifford gates, such as HH, SS, and CNOT, are the gates that map Pauli operators to other Pauli operators under conjugation. The TT gate, while not part of the Clifford group, is necessary to promote the Clifford gate set to a universal gate set. In most quantum error-correcting codes, the TT gate cannot be implemented transversally. In the case of the Steane code, the Clifford gates can be implemented transversally (see figure below), but the TT gate is not.

Consider why the TT-gate is necessary for the universal gate set. For any logical operation Uˉ\bar{U}, it must transform all stabilizers siSs_i \in S into another sjSs_j \in S.

HH does this fine as HXH=ZSH \otimes X \otimes H ^{\dagger} = Z \in S and HZH=XSH \otimes Z \otimes H ^{\dagger} = X \in S.

TT does transform ZZ into a valid stabilizer, but not the XX stabilizers.

TZT=ZST \otimes Z \otimes T ^{\dagger} = Z \in STXT=eiπ/4SZXST \otimes X \otimes T ^{\dagger} = e^{i \pi/4}SZX \notin S

The TT gate ends up being the key to any advantage realized by quantum algorithms. This is because without TT gates, the other gates could only jump between the six pole states of the Bloch sphere, which can be simulated efficiently with classical computing. Explore this fact with the widget linked here. Notice how the T gate is the only operation capable of producing a non-pole state.

5.2 Fault Tolerant TT Gate Application

Thankfully, there is a way to implement a fault-tolerant TT gate, it is just difficult and resource intensive. The procedure involves the circuit below.

It begins with an encoded 0\ket{0} qubit (bottom wire) and an arbitrary logical qubit state ψ\ket{\psi} (top wire). Then, the bottom wire is prepared in a so called magic state, 0+eiπ/412\frac{\ket{0} + e^{i\pi/4}\ket{1}}{\sqrt{2}}. A fault tolerant CNOT gate is then applied with the magic state qubit as the control. The target qubit is then measured and if the result is a 0, TT was successfully applied to ψ\ket{\psi}. If measurement produces a 1, then a FT SX gate is applied to the qubit and the result becomes TT applied to ψ\ket{\psi}.

The "Prepare Magic State" subcircuit is deceptively simple. It consists of a single logical Hadamard gate followed by a noisy TT gate to form T\ket{T}. This process may seem circular as a TT gate is required in the process to apply a fault tolerant TT gate. However, the procedure is a bit more nuanced. A "good enough" (high enough fidelity) magic state is the output of an onerous process called magic state distillation (MSD). MSD will be discussed more in the next section.

Another distinction is that the magic state can only be produced from an easy to prepare logical 0 state. Only by performing the fault tolerant circuit above, can the TT gate act on an arbitrary qubit state ψL\ket{\psi_L}.

The math is instructive for why the above circuit works. After the CNOT is applied to the magic state and ψ\ket{\psi} qubits, the resulting state is

12[0(a0+b1)+eiπ/41(a1+b0)]\frac{1}{\sqrt{2}} [ \ket{0}(a\ket{0} +b\ket{1}) + e^{i\pi/4}\ket{1}(a\ket{1} + b\ket{0})]

Then, if the second qubit is measured (fault tolerantly) and is a 0, the intended TψLT\ket{\psi_L} state is prepared.

a0+beiπ/41a\ket{0} +b*e^{i\pi/4}\ket{1}

Otherwise, if 1 is measured, the following state is prepared.

b0+aeiπ/41b\ket{0} + a*e^{i\pi/4}\ket{1}

In the latter case, the objective state can be obtained with a Clifford correction consisting of an SS and XX operation to flip the bits and amplitudes. such a process ensures that the TT gate is implemented fault tolerantly and will not propagate through the computation if it introduces an error.

5.3 Magic State Distillation

Preparing the magic state is a very resource intensive process. First, the process will be explained at a high level and then in terms of the details used in Experimental Demonstration of the Logical Magic State Distillation.

Magic states are produced by magic state factories which follow a procedure like the one pictured below. This process is decoupled from any quantum application and can be used to build and store magic states which are consumed as an application needs TT gates applied.

  1. Select a QEC code to encode a collection of logical qubits

  2. Prepare each logical qubit in a noisy T\ket{T} state.

  3. Apply a second MSD QEC code on the logical qubits. In the figure below, the [[5,1,3]] code used by QuEra is represented.

  4. Measure all but one of the logical qubits to produce a syndrome to determine if the remaining qubit is in a good magic state or not. If the syndrome indicates no error, the process worked and proceed to 5), if an error is flagged, the process restarts at 1).

  5. A less noisy (high fidelity) magic state has been prepared. It can now be used, or input into another round of MSD.

It should be noted that this is one approach to producing TT gates, but others exits.

Usually, one round of MSD is not enough, even if the resulting state does have higher fidelity. To fix this, the output from the first round can be combined with other output magic states and the procedure repeated. Each round exponentially grows the overhead required to produce a single magic state. This is likely the greatest challenge facing FTQC and will consume most of the resources for any quantum application.

5.4 Performing MSD with the Color Code

It is helpful to look at a concrete example of MSD in practice to better understand the above process. This section will follow the procedure from the QuEra paper and explain the steps they took, preparing you to code up a similar example in the following section.

Each magic state is prepared using the [[7,1,3]] color code, also known as the Steane code which was covered in the second lab of this QEC series. The image below shows the procedure which QuEra used based on the gate set of their neutral atom QPU. The bottom data qubit can be set to an arbitrary qubit state and will "inject" that state into the logical qubit. The circuit is slightly different from the circuit used to encode the Steane code in lab 2, but enforces equivalent stabilizer constraints.

In this case, the prepared state is a noisy TT state created by starting in the 0\ket{0} state and applying a rotation of arccos(1/3)\arccos(1/\sqrt{3}) about the (-1,1,0) axis.

This is repeated five times to create five logically encoded noisy magic states. They are then input into a [[5, 1, 3]] code which produces one magic state with high fidelity from five low fidelity ones. This is an example, like the Shor code, where QEC codes are concatenated. That is to say, the logical qubits are themselves used in a QEC code. The circuit below demonstrates what logical operations need to be performed on each logical qubit to complete the MSD process.

All but the first logical qubit are measured to produce as syndrome. If the correct syndrome (which can vary by implementation) is measured, a magic state with less error has been produced. QuEra's experimental results found that a raw logically encoded magic state had a fidelity of 94.1% which increased to 98.9% when postselected based on syndrome measurements, demonstrating the procedure worked.

Exercise 1:

Write a simple script to calculate the number of physical qubits needed to perform NN rounds of MSD given an arbitrary QEC code and MSD procedure. Assuming the [[5,1,3]] code is used for the MSD, plot how many data qubits are needed for up to 5 rounds of MSD when the Steane code is used and the other [[17,1,5]] color code shown below, also used by QuEra in the paper.

Is it clear why FTQC is so hard? This entire process must happen for every single TT gate applied in a quantum circuit, which could require millions or more TT gates.

def qubits_for_MSD(dataq_per_logicalq, ancilla_per_logicalq, max_msd_rounds, ms_per_msd_round): """Function that calculates the number of physical qubits required for n rounds of MSD and plots them Parameters ---------- dataq_per_logicalq: int The number of data qubits required to encode a logical qubit for the QEC code you selected ancilla_per_logicalq : int The number of ancilla qubits required to measure the stabilizers of a logical qubit (assume no reuse) max_msd_rounds: int The number of MSD distillation rounds to perform ms_per_msd_round: int The number of magic states that must be input for the MSD protocol selected Returns ------- """ rounds = [] qubits= [] #TODO - Write the body of the function plt.plot(rounds, qubits, 'b-o') plt.autoscale(tight=True) plt.xlabel('MSD Rounds') plt.ylabel('Physical Qubits Required') plt.title('Qubits Needed for MSD') plt.show() qubits_for_MSD(7,3,6,5)

5.5 Using CUDA-Q to perform MSD

This section will walk you through an example using CUDA-Q to perform MSD. You will be coding the [[7,1,3]] code and following the MSD protocol of Bravyi and Kitaev. Because this procedure only requires seven qubits, it can be simulated with a state vector simulator. However, remember that in practice each qubit would be a logical qubit and the procedure below would need to be performed with logical operations.

Exercise 2:

The first step of this protocol is to prepare a kernel that produces a noisy T0\ket{T_0} state.

T0=cos(θ2)0+eiπ4sin(θ2)1\ket{T_0} = \cos (\frac{\theta}{2}) \ket{0} + e^{\frac{i\pi}{4}}\sin (\frac{\theta}{2}) \ket{1}

Where θ=12cos1(13)=0.4776583090622546\theta = \frac{1}{2}\cos^{-1}(\frac{1}{\sqrt{3}}) = 0.4776583090622546. Let the kernel take a single float as an input which applies an error to θ\theta. The code underneath the kernel creates a list of perturbed θ\thetas over a suggested range.

cudaq.set_target("nvidia") #Build t0 with some error @cudaq.kernel def noisy_t0(y:float): #TODO Write the CUDA-Q kernel # Perturbation to y gate angles epsilon = 0.005 initial_thetay = [0.4776583090622546 + epsilon*i for i in range(75)]

Exercise 3:

Next, initialize a perfect T0\ket{T_0} state and a second state with some error (It is suggested to use element 30 from the list above to get a noticeable amount of noise but still allows MSD to work). Use CUDA-Q's get_state\texttt{get\_state} and overlap\texttt{overlap} commands to compute the fidelity of the noisy state and visualize both states using the Bloch spheres below. Note that fidelity is the overlap squared.

#TODO Save the state of the initial T0 state #TODO Save the state of the error free T0 state #TODO compute the fidelity between them print("Initial Fidelity") print(initial_fidelity) print("Initial T0") cudaq.show(cudaq.add_to_bloch_sphere(initial_t0)) print("Perfect T0") cudaq.show(cudaq.add_to_bloch_sphere(perfect_t0))

Exercise 4:

Now prepare a kernel to perform the [[5,1,3]] QEC code. The kernel should prepare each qubit as a noisy T0\ket{T_0} state, all with the same angle perturbation. Then, implement the circuit below. This circuit essentially maps the stabilizer measurements of the code to qubits 1,2,3 and 4 which need to be measured to produce a syndrome. Note that this version of the [[5,1,3]] code is slightly different from the version used by QuEra, but is more amenable to gate operations native to CUDA-Q. It is the implementation from A study of the robustness of magic state distillation against Clifford gate faults.


One caveat to this code. It actually produces a distilled T1\ket{T_1}. Add a Pauli Y operation followed by a Hadamard gate to the first qubit to convert back to T0\ket{T_0}. Play around with this in the Bloch spheres above to understand what the transformation does.

#Kernel implementing [[5,1,3]] code @cudaq.kernel def msd(y: float): #TODO Write the kernel for the [[5,1,3]] code h(reg[0]) #Apply to swap from T1 to T0 y(reg[0])

Now, select an entry from the perturbed angle you created above and use it to run the code below. This will produce ten shots and for each print the syndrome, state, and fidelity with respect to the perfect T0\ket{T_0} state. How does the initial fidelity compare to the results? For results with improved fidelity, what is the resulting syndrome? If you do not get a 0000 syndrome, rerun the code. Take one of these improved states and visualize it using the Bloch sphere. Notice how it is closer to the perfect T0\ket{T_0} state than the state you started with.

print("\n") for i in range(10): print("\n") print(f"shot: {i}") distilled_ms = cudaq.get_state(msd, initial_thetay[30]) # uses arbitrary selection distilled_ms = np.array(distilled_ms) indices = np.nonzero(distilled_ms)[0] for j in np.nonzero(distilled_ms)[0]: syndrome=j print(f"syndrome: {np.binary_repr(syndrome, width=5)[0:4]}") distilled_ms = distilled_ms[np.nonzero(distilled_ms)] print(f"state:\n{distilled_ms}") print(f"fidelity: {perfect_t0.overlap(distilled_ms)**2}") print("\n")

Exercise 5:

Now, build a loop below that performs the MSD protocol for initial states corresponding to each error in the initial list of θ\theta's. Plot this against the line y=xy=x to determine the threshold required for the input state? That is, the minimum fidelity of the input state such that the procedure works and does not produce worse results. From the graph, estimate how many rounds of MSD would be needed (assuming the same procedure) to distill a state above .98 starting from .94.

input_fidelity = [] output_fidelity = [] for error in initial_thetay: # TODO Write a loop to perform MSD for each error in the list of thetas import matplotlib.pyplot as plt # Create the plot plt.figure(figsize=(8, 6)) plt.plot(input_fidelity, input_fidelity, label="Y=X", marker='.') # First series: y=x plt.plot(input_fidelity, output_fidelity, label="Input vs Output", marker='x') # Second series: input vs output # Add labels, title, and legend plt.xlabel("X-axis") plt.ylabel("Y-axis") plt.title("Plot of Two Series") plt.legend() # Show the plot plt.grid(True) plt.show()

Conclusion

after completing this notebook you should now have a sense of how MSD works, why it is needed, and what makes it so challenging. As you continue with QEC 101 content, remember that there are many aspects of FTQC beyond simply the QEC code selected.