[PYTHON] Basics of Quantum Information Theory: Quantum Error Correction (CSS Code)

\def\bra#1{\mathinner{\left\langle{#1}\right|}} \def\ket#1{\mathinner{\left|{#1}\right\rangle}} \def\braket#1#2{\mathinner{\left\langle{#1}\middle|#2\right\rangle}}

Introduction

Since I understood the classical linear code in previous article, this time it is a class of quantum error correction based on it, "CSS code (Calderbank-). We will study "Shor-Steane code)". We will also look at the "Steane code" as a specific code method. Now that you have a general understanding, let's check the operation of the "Steane code" using the quantum calculation simulator qlazy.

By the way, "CSS code" corresponds to a subclass of "Stabilizer code" which is a more general class of quantum error correction. This article is also positioned as a stepping stone to that.

The following documents were used as references.

  1. Nielsen, Chan "Quantum Computer and Quantum Communication (3)" Ohmsha (2005)

Explanation of theory

Definition of CSS code

$ C_1 $ and $ C_2 $ are the classical linear codes $ [n, k_1] $ and $ [n, k_2] $, and are $ C_2 \ subset C_1 $. Also assume that $ C_1 $ and $ C_ {2} ^ {\ perp} $ can both handle $ t $ errors. At this time, the CSS code $ CSS (C_1, C_2) $ can be constructed as the quantum code of $ [n, k_1 --k_2] $ that can handle $ t $ errors. Suppose $ x \ in C_1 $ is an arbitrary code word in the code $ C_1 $. At this time, the quantum state $ \ ket {x + C_2} $,

\ket{x+C_2} \equiv \frac{1}{\sqrt{|C_{2}|}} \sum_{y \in C_2} \ket{x+y}  \tag{1}

It is defined as. Here, $ + $ on the right side represents the sum of each bit modulo 2 (the same applies hereinafter). The code represented by the superposition of these $ \ ket {x + C_2} $ is the CSS code.

I don't know what it is. Chew.

xIs[n,k_1]CodeC_1Because it is an element ofk_1All binary vectors of dimension (0またIs1Generated from a vector whose elements arenA dimensional binary vector. Therefore,xTotal number of|C_1|Is2^{k_1}It is an individual. on the other hand,yIs[n,k_2]CodeC_2Because it is an element ofk_2Generated from all binary vectors of dimensionnA dimensional binary vector. Therefore,yTotal number of|C_2|Is2^{k_2}It is an individual. Also,C_2 \subset C_1So that's whyk_2 < k_1is.Previous articleで「古典線形Code」が理解できていれば、ここまでIs全然難しくないですね。

Now, on the right side of equation (1), the state vector $ \ ket {x + y} $, which is the sum of the element $ x $ of $ C_1 $ and the element $ y $ of $ C_2 $, is used as an index for all $. It looks like adding about y \ in C_2 $. It is defined by the symbol $ \ ket {x + C_2} $. In other words, $ \ ket {x + C_2} $ seeds a $ \ ket {x} \ space (x \ in C_1) $, whereas all $ y \ in C_2 $ It is a superposed state where all the conversions (adding $ y $ to the contents of the ket) performed by mobilizing all of them are combined.

Note that even if you add the elements of the linear code together, they will be the elements of the same linear code [^ 1], so the contents of all the kets on the right side are the elements of $ C_1 $. Let's do it. That is, each of the seeds of $ x \ in C_1 $ plus all $ y \ in C_2 \ subset C_1 $ is a code that belongs to $ C_1 $. Each of the results of adding all $ y \ in C_2 $ to another $ x ^ {\ prime} \ in C_1 $ is also a code belonging to $ C_1 $. Here's a question. Is there anything to do with the two sets of codes (each $ 2 ^ {k_2} $ set) generated from $ x $ and $ x ^ {\ prime} $? In fact, they are either "all the same" or "all different" and do not partially overlap.

[^ 1]: Consider $ [n, k] $ sign $ C $ and let its generator matrix be $ G $. For any $ x_1, x_2 \ in \ {0,1 \} ^ {k} $, if $ y_1 = Gx_1, y_2 = Gx_2 $, then $ y_1, y_2 \ in C $. Adding the two equations gives $ y_1 + y_2 = G (x_1 + x_2) $, which is $ x_1 + x_2 \ in \ {0,1 \} ^ {k} $, so $ y_1 + y_2 \ in C $ Holds.

What do you mean?

It's not exactly the set we're thinking about, but to get a feel for it, here's a similar example. Imagine a set of integers from $ 0 $ to $ 99 $. Let this be the set $ C_1 $. Next, extract a multiple of $ 3 $ from $ C_1 $. Let's call it $ C_2 $. Now, take a specific integer from $ C_1 $ and use it as $ x $. Using this as a seed, mobilize all $ y \ in C_2 $ and add each to $ x $ (but add $ 100 $ as a law). All the results obtained are integers from $ 0 $ to $ 99 $, so they are elements of $ C_1 $. For example, let's say $ x = 6 $. At this time, all the integers created by adding $ y $ are multiples of $ 3 $. Consider $ x ^ {\ prime} = 15 $ and use $ y \ in C_2 $ in the same way to generate a set of integers. As you can see, this is also a multiple of $ 3 $. In other words, the set of integers generated by seeding $ x = 6, x ^ {\ prime} = 15 $ is an exact match. As another example, what if $ x = 7, x ^ {\ prime} = 31 $? The generated integers are a set of $ 1 $ when divided by $ 3 $. So, in this case as well, the two are exactly the same. As yet another example, what if $ x = 11,x ^ {\ prime} = 52 $? In this case, what is generated from $ x = 11 $ is an integer set of $ 2 $ with the remainder divided by $ 3 $, and what is generated from $ x ^ {\ prime} = 52 $ is divided by $ 3 $. The remainder is a set of integers of $ 1 $. So, the two are completely inconsistent. In other words, it is possible to classify the set generated by using the set $ C_2 $ with $ x \ in C_1 $ as the seed, according to the remainder obtained by dividing by $ 3 $. For that matter, $ C_2 $ allows you to classify $ x \ in C_1 $ into three groups. This classification is called a "coset" (for example, "$ 7 $ and $ 31 $ belong to the same coset"). You can tell if they belong to the same coset by subtracting them, without having to generate them all one by one. Let's try with this example. $ 15-6 $ is $ 9 $ and $ 31-7 $ is $ 24 $, both of which are multiples of $ 3 $. On the other hand, $ 52-11 $ becomes $ 41 $, which is not a multiple of $ 3 $. You can tell if it belongs to the same coset in this way by doing a subtraction and seeing if it belongs to $ C_2 $.

Well, the analogy is up to this point. Forget the definitions of $ C_1 and C_2 $ in the previous section. So, looking at the definition of equation (1) again, I feel that something similar to this is likely to hold true. Let me show below that not only does it feel like it, but it does.

First, if they belong to the same coset, that is, $ x, x ^ {\ prime} \ in C_1 $ and $ x-x ^ {\ prime} \ in C_2 $

\ket{x + C_2} = \ket{x^{\prime} + C_2}  \tag{2}

Is established. Let's prove it.

[Proof]

Prove that $ \ ket {x + C_2}-\ ket {x ^ {\ prime} + C_2} $ becomes $ 0 $.

\ket{x+C_2} - \ket{x^{\prime}+C_2} = \frac{1}{|C_2|} (\sum_{y \in C_2} \ket{x+y} - \sum_{y \in C_2} \ket{x^{\prime}+y})  \tag{3}

Set $ x-x ^ {\ prime} = y ^ {\ prime} \ in C_2 $.

\ket{x+C_2} - \ket{x^{\prime}+C_2} = \frac{1}{|C_2|} (\sum_{y \in C_2} \ket{x^{\prime}+y^{\prime}+y} - \sum_{y \in C_2} \ket{x^{\prime}+y})  \tag{4}

Set $ y ^ {\ prime \ prime} = y ^ {\ prime} + y $. Note that $ y ^ {\ prime} $ and $ y $ are elements of the same code $ C_2 $, so they are $ y ^ {\ prime \ prime} \ in C_2 $.

\ket{x+C_2} - \ket{x^{\prime}+C_2} = \frac{1}{|C_2|} (\sum_{y^{\prime\prime} \in C_2} \ket{x^{\prime}+y^{\prime\prime}} - \sum_{y \in C_2} \ket{x^{\prime}+y}) = 0 \tag{5}

It will be. (End of proof)

Then, if they belong to different cosets, that is, $ x, x ^ {\ prime} \ in C_1 $ and $ x-x ^ {\ prime} \ notin C_2 $

\braket{x + C_2}{x^{\prime} + C_2} = 0 \tag{6}

Is established. Let's prove it.

[Proof]

First, you can't bring any two $ y, y ^ {\ prime} \ in C_2 $ to $ x + y = x ^ {\ prime} + y ^ {\ prime} $. In other words

x+y \neq x^{\prime} + y^{\prime}  \tag{7}

is. Because, if the equal sign holds, then $ x-x ^ {\ prime} = y ^ {\ prime} -y \ in C_2 $ [^ 2], denying the premise. Therefore, equation (7) holds. Then

[^ 2]: Note that bitwise addition modulo 2 is equal to subtraction. $ y ^ {\ prime} -y = y {\ prime} + y $ and $ y ^ {\ prime} -y \ in due to the nature of the linear code that even if you add things that belong to the same code, they belong to the same code. I can say C_2 $.

\begin{align}
\ket{x+C_2} &= \frac{1}{|C_2|} \sum_{y \in C_2} \ket{x+y} \\
\ket{x^{\prime}+C_2} &= \frac{1}{|C_2|} \sum_{y^{\prime} \in C_2} \ket{x^{\prime}+y^{\prime}} \tag{8}
\end{align}

These two states are superpositions of states that do not overlap each other at all.

\braket{x+C_2}{x^{\prime}+C_2} = 0 \tag{9}

Is established. (End of proof)

\ket{x+C_2}ofxIsC_1of要素なofで、そof総数Is2^{k_1}なofですが、上に示した性質があるofで、ケットとしてof総数Isそれより少なくなります。簡単にわかると思いますが、y \in C_2of総数で割り算すれば良いです。つまり、\ket{x+C_2}of総数Is、|C_1|/|C_2|=2^{k_1}/2^{k_2}=2^{k_1 - k_2}です。ということで、こofCSS符号Is、量子ビット長k_1 - k_2of状態から生成される[n, k_1 - k_2]It will be a code.

Bit inversion and phase inversion

Now let's see why and how error correction can be done with the quantum code defined in this way. But first, let's check what happens when bit inversion and phase inversion are added.

Now, let's represent the vector that represents the bit inversion error with the following vector that has a binary value as an element.

e_1 = (0, \cdots , 0,1,0, \cdots, 0,1,0, \cdots, 0)^T  \tag{10}

Imagine that the dimension of the vector is $ n $, only the element corresponding to the qubit number to which the error is added is $ 1 $, and the others are $ 0 $. Similarly, the vector representing the error of phase inversion is also the same.

e_2 = (0, \cdots , 0,1,0, \cdots, 0,1,0, \cdots, 0)^T  \tag{11}

I will express it as. How does the CSS code change due to such an error?

\ket{x+C_2} = \frac{1}{|C_2|} \sum_{y \in C_2} (-1)^{(x+y)e_2} \ket{x+y+e_1} \tag{12}

It will be. It is good that the effect of bit inversion is expressed by adding $ e_1 $ to the contents of the ket on the right side. I think that the effect of phase inversion is $ (-1) ^ {(x + y) e_2} $, which is a little difficult to understand, so I will add a little explanation.

$ x + y $ was a binary vector of $ n $ dimension. Because it's in the ket

x+y = (q_1, q_2, \cdots , q_n)^{T}  \tag{13}

By the way, $ \ ket {x + y} $ is

\ket{x+y} = \ket{q_1}\ket{q_2} \cdots \ket{q_n}  \tag{14}

Can be written. Where $ \ ket {q_i} $ is either $ \ ket {0} $ or $ \ ket {1} $. Since the phase inversion was a conversion that leaves $ \ ket {0} $ as it is and changes $ \ ket {1} $ to $-\ ket {1} $, the $ n $ components of equation (11) When $ q_i $ in the place where it is $ 1 $ is $ 1 $, the sign of equation (14) is inverted. In other words, only the internal integral of $ x + y $ and $ e_2 $ costs $ -1 $, so the coefficient $ (-1) ^ {(x + y) as shown in equation (12). e_2} $ will be applied before the state.

Correction of bit inversion error

I will explain how to correct such an error. First, the correction of bit inversion error. Pay attention to $ \ ket {x + y + e_1} $ on the right side of equation (12). Since it was $ x + y \ in C_1 $, if the parity check matrix of $ C_1 $ is set to $ H_1 $ and it is applied to the contents of the ket to calculate the error syndrome, the qubit with bit inversion there. It should contain information about the number. To do this, we need an ansila to store the results of the quantum error syndrome. That is,

\ket{x+y+e_1}\ket{0} \rightarrow \ket{x+y+e_1}\ket{H_1(x+y+e_1)} = \ket{x+y+e_1}\ket{H_1 e_1}  \tag{15}

If the conversion can be realized, the information about the error bit number will be entered in the ansila $ \ ket {H_1 e_1} $ on the right side.

Then, what kind of quantum circuit can realize the conversion of Eq. (15)?

It's difficult to explain in general suddenly, so let's consider a simple example. Suppose you want to achieve the conversion $ \ ket {x} \ ket {0} \ rightarrow \ ket {x} \ ket {Hx} $. Specifically, $ \ ket {x} $ is a 3-qubit code, $ H $ is a parity check matrix,

H =
\begin{pmatrix}
1 & 1 & 0 \\
0 & 1 & 1
\end{pmatrix}  \tag{16}

will do. At this time, the generator matrix $ G $ is

G =
\begin{pmatrix}
1\\
1\\
1
\end{pmatrix}  \tag{17}

is. So this is nothing more than a repeating code that makes one qubit redundant to three qubits. That is, it achieves encoding such as $ \ ket {0} \ rightarrow \ ket {000}, \ ket {1} \ rightarrow \ ket {111} $. The result of calculating $ H $ on the input vector $ x = (x_1, x_2, x_3) ^ {T} $ should be transferred to Ansila, so the quantum circuit is as follows.

     [The first line]  [2nd line]
|x1> --*-------------
|x2> --|--*----*-----
|x3> --|--|----|--*--
       |  |    |  |
 |0> --X--X----|--|--
 |0> ----------X--X--

The part marked [1st line] is the calculation corresponding to the 1st line of $ H $. Since the matrix elements of the first and second columns are 1, the first ansila is $ \ ket {x_1 + x_2} $. The part marked [2nd line] is the calculation corresponding to the 2nd line of $ H $. Since the matrix elements of the 2nd and 3rd columns are 1, this time, the 2nd Ansila is $ \ ket {x_2 + x_3} $.

This idea can also be generalized when any $ H $ is defined for any $ \ ket {x} $. When the $ j $ column of the $ i $ th row of $ H $ is $ 1 $, the CNOT gate with the $ j $ th sign qubit as the control bit and the $ i $ th ansila qubit as the target bit Deploy. Repeat this for a few minutes when the matrix element is $ 1 $. So, I think you know how to make a quantum circuit that realizes the conversion of equation (15) [^ 3].

[^ 3]: This is "Practice Exercise 10.26" from Nielsen, Chan.

Since the original error-bearing state was Eq. (12), the result through the quantum error syndrome is

\begin{align}
\ket{x+C_2} &= \frac{1}{|C_2|} \sum_{y \in C_2} (-1)^{(x+y)e_2} \ket{x+y+e_1} \\
& \rightarrow \frac{1}{|C_2|} \sum_{y \in C_2} (-1)^{(x+y)e_2} \ket{x+y+e_1} \ket{0} \\
& \rightarrow \frac{1}{|C_2|} \sum_{y \in C_2} (-1)^{(x+y)e_2} \ket{x+y+e_1} \ket{H_1(x+y+e_1)} \\
& \rightarrow \frac{1}{|C_2|} \sum_{y \in C_2} (-1)^{(x+y)e_2} \ket{x+y+e_1} \ket{H_1 e_1} \tag{18}
\end{align}

It will be. If the error is limited to one qubit, there is only one last $ \ ket {H_1 e_1} $ that is not $ \ ket {0} $. Let's call it $ \ ket {z_1} $. Invert the qubit number corresponding to $ z_1 $ (that is, the column number where the column vector of the parity check matrix is $ z_1 $) only for the term on the right side where Ansila is $ \ ket {z_1} $ If you do, you can correct the error. If there is an error in 2 qubits, it means that there are two types of ansila states other than $ \ ket {0} $. Let it be $ \ ket {z_1}, \ ket {z_2} $, then $ z_1 $ and $ only for the right-hand term where the ansila is $ \ ket {z_1} $ or $ \ ket {z_2} $ Error correction can be performed by inverting the qubit number corresponding to z_2 $. If there is an error of 3 qubits or more, the error can be corrected in the same way. Therefore, the correction of the bit inversion error is completed [^ 4]. However, since $ C_1 $ was a code that can correct up to $ t $ of errors, the number of qubits that can be supported is up to $ t $.

[^ 4]: It is possible to build a circuit that measures to obtain the value of $ z_1, z_2, \ cdots $ and inverts the sign qubit accordingly. In that case, you will feel like using a conditional X gate (an X gate that stores the measurement result in a classical register and turns it on and off depending on whether the value is 0 or 1). However, if there is more than one erroneous qubit, I think you have to make multiple measurements to get multiple $ z_1, z_2, \ cdots $. So I'm not so happy. It is also possible to combine an X gate and a CNOT gate so that they react only to $ \ ket {z_i} $ instead of making measurements, and a circuit that achieves the same thing is possible. , I think it is possible to correct errors in multiple qubits. The simulation shown later in the article was implemented in this direction.

As a result of correcting the bit inversion error, the state is as follows.

\frac{1}{|C_2|} \sum_{y \in C_2} (-1)^{(x+y)e_2} \ket{x+y} \tag{19}

Correction of phase inversion error

Next, consider the correction of phase inversion errors. The hint is the Hadamard transform.

\begin{align}
\ket{+} \rightarrow \ket{-}  \\
\ket{-} \rightarrow \ket{+}  \tag{20}
\end{align}

Considering the phase inversion in the Hadamard transform world

\begin{align}
\ket{0} \rightarrow \ket{1}  \\
\ket{1} \rightarrow \ket{0}  \tag{21}
\end{align}

It becomes bit inversion. From here, I feel that if I somehow perform the Hadamard transform, correct the bit inversion error, and then perform the Hadamard transform again, it will work. In fact it is correct and can be neatly expressed in mathematical formulas as follows:

First, the Hadamard transform $ H ^ {\ otimes n} $ for the $ n $ qubit state is

H^{\otimes n} \ket{x} = \frac{1}{\sqrt{2^{n}}} \sum_{z} (-1)^{xz} \ket{z}  \tag{22}

It becomes [^ 5]. Using this, the Hadamard transform for equation (19)

[^ 5]: I think it's good to remember it officially.

\begin{align}
& \frac{1}{|C_2|} \sum_{y \in C_2} (-1)^{(x+y)e_2} \ket{x+y} \\
& \rightarrow \frac{1}{|C_2|} \sum_{y \in C_2} (-1)^{(x+y)e_2} H^{\otimes n} \ket{x+y} \\
&= \frac{1}{\sqrt{|C_2| 2^{n}}} \sum_{z} \sum_{y \in C_2} (-1)^{(x+y)e_2} (-1)^{(x+y)z} \ket{z} \\
&= \frac{1}{\sqrt{|C_2| 2^{n}}} \sum_{z} \sum_{y \in C_2} (-1)^{(x+y)(e_2+z)} \ket{z} \tag{23}
\end{align}

If you set $ z ^ {\ prime} = z + e_2 $, the above formula will be

\begin{align}
& \frac{1}{\sqrt{|C2| 2^{n}}} \sum_{z^{\prime}} \sum_{y \in C_2} (-1)^{(x+y)z^{\prime}} \ket{z^{\prime} + e_2} \\
&= \frac{1}{\sqrt{|C2| 2^{n}}} \sum_{z^{\prime}} (-1)^{xz^{\prime}} \sum_{y \in C_2} (-1)^{yz^{\prime}} \ket{z^{\prime} + e_2} \tag{24}
\end{align}

Can be transformed. Here, paying attention to $ \ sum_ {y \ in C_2} (-1) ^ {yz ^ {\ prime}} $, previous article Uses the properties of the dual sign explained around equation (46). When reprinted in the current situation, its nature is

\begin{align}
& z^{\prime} \in C_{2}^{\perp} \Rightarrow \sum_{y \in C_2} (-1)^{yz^{\prime}} = |C_2| \\
& z^{\prime} \notin C_{2}^{\perp} \Rightarrow \sum_{y \in C_2} (-1)^{yz^{\prime}} = 0 \tag{25}
\end{align}

Is expressed as. Applying this to equation (24),

\sqrt{\frac{|C_2|}{2^{n}}} \sum_{z^{\prime} \in C_{2}^{\perp}} (-1)^{xz^{\prime}} \ket{z^{\prime} + e_2}  \tag{26}

It will be. In other words, as a result of performing the Hadamard transform, the effect of phase inversion $ e_2 $ will appear as an addition in the ket. If this happens, the effect of $ e_2 $ can be eliminated by the error correction procedure for bit inversion as before. result,

\sqrt{\frac{|C_2|}{2^{n}}} \sum_{z^{\prime} \in C_{2}^{\perp}} (-1)^{xz^{\prime}} \ket{z^{\prime}}  \tag{27}

It means that. If you run the Hadamard transform again, it should be completely restored. I'll try.

\begin{align}
& \sqrt{\frac{|C_2|}{2^{n}}} \sum_{z^{\prime} \in C_{2}^{\perp}} (-1)^{xz^{\prime}} \ket{z^{\prime}} \\
& \rightarrow \sqrt{\frac{|C_2|}{2^{n}}} \sum_{z^{\prime} \in C_{2}^{\perp}} (-1)^{xz^{\prime}} \frac{1}{\sqrt{2^{n}}} \sum_{w} (-1)^{z^{\prime} w} \ket{w} \\
&= \frac{\sqrt{|C_2|}}{2^{n}} \sum_{w} \sum_{z^{\prime} \in C_{2}^{\perp}} (-1)^{(x+w)z^{\prime}} \ket{w} \tag{28}
\end{align}

again,\sum_{z^{\prime} \in C_{2}^{\perp}} (-1)^{(x+w)z^{\prime}}For, we use the dual sign property.x+w \in C_2Only when|C_2|And the others0Therefore, it can be transformed as follows.

\frac{\sqrt{|C_2|}}{2^{n}} \sum_{w,x+w \in C_2} |C_{2}^{\perp}| \ket{w} \tag{29}

here,

\begin{align}
& |C_2| = 2^{k_2}, |C_{2}^{\perp}| = 2^{n-k_2} \\
& |C_2| |C_{2}^{\perp}| = 2^{n} \tag{30}
\end{align}

Therefore, equation (29)

\frac{1}{\sqrt{|C_2|}} \sum_{w,x+w \in C_2} \ket{w} \tag{31}

It will be. Here, if you set $ x + w = x-w = y \ in C_2 $, after all,

\frac{1}{\sqrt{|C_2|}} \sum_{y \in C_2} \ket{x+y} \tag{32}

This will completely restore the original state.

It was explained in the previous article that even if there is a continuous error other than bit inversion or phase inversion, it can be dealt with by itself. So, the explanation of how the CSS code is constructed and what kind of quantum circuit should be passed to correct the error is completed for the time being.

But one last word.

There are variations of CSS codes with parameters $ u, v $.

\ket{x+C_2} \equiv \frac{1}{|C_2|} \sum_{y \in C_2} (-1)^{uy} \ket{x+y+v}  \tag{33}

It is defined in and is called the $ CSS_ {u, v} (C_1, C_2) $ sign. Although it contains extra parameters, error correction can be performed with the same quantum circuit as the $ CSS (C_1, C_2) $ code mentioned earlier. Since it is said that it will be useful in quantum key distribution, only the definition is posted here and the proof is omitted [^ 6].

[^ 6]: I've found some amazing proof of this, but it's a lie that this margin is too narrow to write (laughs, I wanted to say it once. I don't know the source. Click here [https://ja.m.wikipedia.org/wiki/%E3%83%95%E3%82%A7%E3%83%AB%E3%83%9E%E3%83%BC % E3% 81% AE% E6% 9C% 80% E7% B5% 82% E5% AE% 9A% E7% 90% 86)). This is "Practice Exercise 10.27" from Nielsen, Chan. I felt like I was doing almost the same formula transformation as I did above, so I omitted it.

Steane code

Now that you know the general theory of CSS codes, I'd like to give you some concrete examples to further ensure your understanding. There is a "Steane code". This is a CSS code with $ C_1 = C, C_2 = C ^ {\ perp} $ and $ C $ as the Hamming code. Let the parity check matrix of $ C_1 $ be $ H_1 $ and the generator matrix be $ G_1 $. For the sake of simplicity, if we use the $ [7,3] $ Hamming code, $ H_1 and G_1 $ will be

H_1 =
\begin{pmatrix}
0 & 1 & 1 & 1 & 1 & 0 & 0 \\
1 & 0 & 1 & 1 & 0 & 1 & 0 \\
1 & 1 & 0 & 1 & 0 & 0 & 1
\end{pmatrix}  \tag{34}
G_1 =
\begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1 \\
0 & 1 & 1 & 1 \\
1 & 0 & 1 & 1 \\
1 & 1 & 0 & 1
\end{pmatrix}  \tag{35}

Can be expressed as (written in standard form). On the other hand, $ C_2 $ is its dual code, so from the definition,

H_2 = G_{1}^{T} =
\begin{pmatrix}
1 & 0 & 0 & 0 & 0 & 1 & 1 \\
0 & 1 & 0 & 0 & 1 & 0 & 1 \\
0 & 0 & 1 & 0 & 1 & 1 & 0 \\
0 & 0 & 0 & 1 & 1 & 1 & 1
\end{pmatrix}  \tag{36}
G_2 = H_{1}^{T} =
\begin{pmatrix}
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
1 & 1 & 1 \\
1 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 1
\end{pmatrix}  \tag{37}

Can be written as.

By the way, in order to say that the quantum code based on the linear code defined in this way is certainly a CSS code, $ C_1 $ and $ C_ {2} ^ {\ perp} $ are the same $ t $. It is necessary to be able to deal with individual errors, that is, the code distances (minimum distances) are equal, and $ C_2 \ subset C_1 $.

The former is self-explanatory because both $ C_1 $ and $ C_ {2} ^ {\ perp} $ are $ C $ by definition. The latter can be understood by using what was explained around equation (45) in Previous article. I will post it again.

G^{T} G = 0 \Leftrightarrow C \subseteq C^{\perp}  \tag{38}

In other words, if $ G_ {2} ^ {T} G_2 = 0 $ can be shown, then $ C_2 \ subseteq C_ {2} ^ {\ perp} $, that is, $ C_2 \ subseteq C_1 $ can be proved. .. I'll try.

G_{2}^{T} G_2 =
\begin{pmatrix}
0 & 1 & 1 & 1 & 1 & 0 & 0 \\
1 & 0 & 1 & 1 & 0 & 1 & 0 \\
1 & 1 & 0 & 1 & 0 & 0 & 1
\end{pmatrix}
\begin{pmatrix}
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
1 & 1 & 1 \\
1 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 1
\end{pmatrix} =
\begin{pmatrix}
0 & 0 & 0 \\
0 & 0 & 0 \\
0 & 0 & 0
\end{pmatrix}  \tag{39}

So, I was able to confirm that it was $ C_2 \ subseteq C_ {2} ^ {\ perp} $ [^ 7].

[^ 7]: [7,3] I was able to confirm in the case of the Hamming code, but I can't say yet whether it holds for the general Hamming code (I think it holds). .. For a moment, I thought I could use $ HG = 0 $, but I was wrong.

Now that we know the base classical linear code, let's build a CSS code. Let's look at equation (1) again.

\ket{x+C_2} \equiv \frac{1}{\sqrt{|C_{2}|}} \sum_{y \in C_2} \ket{x+y}  \tag{1}

You can build the code according to this.

Now $ C_1 $ is the [7,4] code and $ C_2 $ is the [7,3] code. Therefore, the resulting CSS code is the [7,1] code. Since it is a quantum code that makes 1 qubit redundant to 7 qubits, you can bring two $ x $ and mobilize all $ y $ as shown on the right side of equation (1) and superimpose them. .. Since $ y $ is a [7,3] sign, you can bring all the 3D binary vectors and calculate the generator matrix $ G_2 $ in equation (35). Now, the question is what $ x $ to bring. If you bring two $ x $ that belong to the same coset, it doesn't make sense because the right-hand sides are exactly the same. You need to bring in two $ x $ that belong to different cosets. Since the difference between the two $ x $ should not belong to $ C_2 $, $ x = (0,0,0,0,0,0,0) ^ {T} $ and $ x Bring two things: ^ {\ prime} = (1,1,1,1,1,1,1) ^ {T} $. This way the diff doesn't seem to be an element of $ C_2 $. Let $ \ ket {0_L} $ be the seed generated by $ x $ and $ \ ket {1_L} $ be the seed generated by $ x ^ {\ prime} $.

\begin{align}
\ket{0_L} &= \frac{1}{\sqrt{8}} (\ket{0000000} + \ket{1101001} + \ket{1011010} + \ket{0110011} + \ket{0111100} + \ket{1010101} + \ket{1100110} + \ket{0001111}) \\
\ket{1_L} &= \frac{1}{\sqrt{8}} (\ket{1111111} + \ket{0010110} + \ket{0100101} + \ket{1001100} + \ket{1000011} + \ket{0101010} + \ket{0011001} + \ket{1110000}) \tag{40}
\end{align}

And now we have a quantum code. In fact, when encoding the 1 qubit state of $ \ ket {\ psi} = \ alpha \ ket {0} + \ beta \ ket {1} $,

\ket{\psi} \rightarrow \ket{\psi_{L}} = \alpha \ket{0_L} + \beta \ket{1_L} \tag{41}

Build a suitable quantum circuit to realize.

Next, assuming that an error is added to this state, execute the circuit that calculates the error syndrome as explained earlier. That is, add ancilla and for each state

\ket{x} \ket{0} \rightarrow \ket{x} \ket{H_1 x}  \tag{42}

By executing the quantum circuit that realizes, the effect of the bit inversion error of $ H_1 e_1 $ is transferred to Ansila. In this case, prepare ancilla for 3 qubits. As mentioned earlier, line up the CNOT gates, noting the $ 1 $ location in each row of the parity check matrix.

|x1> -----------*--------*-------- ...
|x2> --*--------|--------|-*------ ...
|x3> --|-*------|-*------|-|------ ...
|x4> --|-|-*----|-|-*----|-|-*---- ...
|x5> --|-|-|-*--|-|-|----|-|-|---- ...
|x6> --|-|-|-|--|-|-|-*--|-|-|---- ...
|x7> --|-|-|-|--|-|-|-|--|-|-|-*-- ...
       | | | |  | | | |  | | | |       
 |0> --X-X-X-X--|-|-|-|--|-|-|-|-- ...
 |0> -----------X-X-X-X--|-|-|-|-- ...
 |0> --------------------X-X-X-X-- ...

Next, bit inversion is performed according to the state of Ansila. Inverts the bit corresponding to where the state of the ancilla matches the value of the column vector in the parity check matrix $ H_1 $. In other words, if Ansila is $ \ ket {011} $, the first qubit, $ \ ket {101} $ is the second qubit, $ \ ket {110} $ is the third qubit, and so on. , Bit inversion error can be corrected. Continuing from the previous circuit, do the following.

|x1> ... ----X--------------------------------------------- ...
|x2> ... ----|------X-------------------------------------- ...
|x3> ... ----|------|------X------------------------------- ...
|x4> ... ----|------|------|------X------------------------ ...
|x5> ... ----|------|------|------|------X----------------- ...
|x6> ... ----|------|------|------|------|------X---------- ...
|x7> ... ----|------|------|------|------|------|------X--- ...
             |      |      |      |      |      |      |
 |0> ... --X-*-X----*------*------*------*----X-*-X--X-*-X-
 |0> ... ----*----X-*-X----*------*----X-*-X----*----X-*-X-
 |0> ... ----*------*----X-*-X----*----X-*-X--X-*-X----*---

Now that the bit inversion error has been corrected, the next step is to deal with the phase inversion error. First, use the Hadamard transform. At the same time, the ansila for bit inversion error correction has finished its role and is initialized. Following the circuit above, do the following:

|x1> ... --H-------------*--------*-------- ...
|x2> ... --H----*--------|--------|-*------ ...
|x3> ... --H----|-*------|-*------|-|------ ...
|x4> ... --H----|-|-*----|-|-*----|-|-*---- ...
|x5> ... --H----|-|-|-*--|-|-|----|-|-|---- ...
|x6> ... --H----|-|-|-|--|-|-|-*--|-|-|---- ...
|x7> ... --H----|-|-|-|--|-|-|-|--|-|-|-*-- ...
                | | | |  | | | |  | | | |       
 |0> ... -------X-X-X-X--|-|-|-|--|-|-|-|-- ...
 |0> ... ----------------X-X-X-X--|-|-|-|-- ...
 |0> ... -------------------------X-X-X-X-- ...

Now that we have calculated the error syndrome, we correct the phase inversion error (actually, correct the bit inversion error), and finally perform the Hadamard transform to restore it.

|x1> ... ----X---------------------------------------------H--
|x2> ... ----|------X--------------------------------------H--
|x3> ... ----|------|------X-------------------------------H--
|x4> ... ----|------|------|------X------------------------H--
|x5> ... ----|------|------|------|------X-----------------H--
|x6> ... ----|------|------|------|------|------X----------H--
|x7> ... ----|------|------|------|------|------|------X---H--
             |      |      |      |      |      |      |
 |0> ... --X-*-X----*------*------*------*----X-*-X--X-*-X----
 |0> ... ----*----X-*-X----*------*----X-*-X----*----X-*-X----
 |0> ... ----*------*----X-*-X----*----X-*-X--X-*-X----*------

This completes the error correction [^ 8].

[^ 8]: There may be a more efficient circuit configuration, but please forgive it because it is a beginner course for the time being. At least consecutive X gates can be erased. Then, I really wanted to create a 7-qubit Steane code from a 1-qubit state, but I couldn't think of a good circuit, so I omitted that in this article as well. I think that if you study more, you can write a neat and cool circuit.

simulation

Implementation

Now let's implement the Steane code described above. In qlazy, quantum circuit calculations are performed by creating instances of classes corresponding to quantum states or density operators and performing gate operations. Either the quantum state or the density operator can be used, but I will try the density operator that can use quantum channels (polarization elimination, amplitude damping, etc.) for noise addition [^ 9].

[^ 9]: Since it is a calculation of the density operator of 10 qubits and uses abundant multi-control NOT (CNOT with multiple control bits), it takes more processing time than executing it in the quantum state. ..

The whole code is below.

import numpy as np
from qlazypy import QState, DensOp

Hamming   = np.array([[0,1,1,1,1,0,0], [1,0,1,1,0,1,0], [1,1,0,1,0,0,1]])
Hamming_T = Hamming.T

Steane_0 = ['0000000', '1101001', '1011010', '0110011',
            '0111100', '1010101', '1100110', '0001111']
Steane_1 = ['1111111', '0010110', '0100101', '1001100',
            '1000011', '0101010', '0011001', '1110000']

def generate_qstate(qid_C, qid_S):

    a = np.random.rand() + np.random.rand() * 1.j
    b = np.random.rand() + np.random.rand() * 1.j

    print("== quantum state (a |0L> + b |1L>) ==")
    print("- a = {:.4f}".format(a))
    print("- b = {:.4f}".format(b))

    qvec = np.full(2**len(qid_C), 0.+0.j)
    for s in Steane_0: qvec[int(s, 2)] = a
    for s in Steane_1: qvec[int(s, 2)] = b

    norm = np.linalg.norm(qvec)
    qvec = qvec / norm

    qs_C = QState(vector=qvec)
    qs_S = QState(len(qid_S))
    qs = qs_C.tenspro(qs_S)
    de_ini = DensOp(qstate=[qs])
    de_fin = de_ini.clone()

    QState.free_all(qs_C, qs_S, qs)
    return de_ini, de_fin

def noise(self, kind='', prob=0.0, qid=[]):

    print("== noise ({:}) ==".format(kind))
    print("- qubit = {:}".format(qid))
    print("- prob  = {:}".format(prob))
    
    qchannel = {'bit_flip':self.bit_flip, 'phase_flip':self.phase_flip,
                'bit_phase_flip':self.bit_phase_flip,
                'depolarize':self.depolarize, 'amp_dump':self.amp_dump,
                'phase_dump':self.phase_dump}
    [qchannel[kind](i,prob=prob) for i in qid]
    return self

def correct(self, kind, qid_C, qid_S):

    self.reset(qid=qid_S)

    if kind == 'phase_flip': [self.h(q) for q in qid_C]

    # syndrome
    for i, row in enumerate(Hamming):
        [self.cx(qid_C[j], qid_S[i]) if row[j] == 1 else False for j in range(len(row))]

    # correction
    for i, row in enumerate(Hamming_T):
        [self.x(qid_S[j]) if row[j] == 0 else False for j in range(len(row))]
        self.mcx(qid=qid_S+[qid_C[i]])
        [self.x(qid_S[j]) if row[j] == 0 else False for j in range(len(row))]
    
    if kind == 'phase_flip': [self.h(q) for q in qid_C]
        
    return self
    
if __name__ == '__main__':

    # add custom gates
    DensOp.add_method(noise)
    DensOp.add_method(correct)

    # set registers
    qid_C = DensOp.create_register(7) # registers for code space
    qid_S = DensOp.create_register(3) # registers for error syndrome
    DensOp.init_register(qid_C, qid_S)

    # generate initial quantum state (density operator)
    de_ini, de_fin = generate_qstate(qid_C, qid_S)

    # add noise
    de_fin.noise(kind='depolarize', qid=[qid_C[3]], prob=1.0)

    # error correction
    de_fin.correct('bit_flip', qid_C, qid_S)
    de_fin.correct('phase_flip', qid_C, qid_S)

    # print result
    print("== result ==")
    print("- fidelity = {:.6f}".format(de_fin.fidelity(de_ini, qid=qid_C)))

    DensOp.free_all(de_ini, de_fin)

I will briefly explain what you are doing. Basically, you are just performing the error correction with the Steane code described above. Now, take a look at the main processing section.

# add custom gates
DensOp.add_method(noise)
DensOp.add_method(correct)

So, we define a custom gate with noise addition and error correction as one block, and set it as a method. The processing content is defined as a function at the top.

# set registers
qid_C = DensOp.create_register(7) # registers for code space
qid_S = DensOp.create_register(3) # registers for error syndrome
DensOp.init_register(qid_C, qid_S)

Defines the quantum register to be used. At this level, it may be faster to write it by hand without using such a class method. Now qid_C is in the list [0,1,2,3,4,5,6] and qid_S is in the list [7,8,9].

# generate initial quantum state (density operator)
de_ini, de_fin = generate_qstate(qid_C, qid_S)

Quantum states (density operators) using Steane codes are randomly prepared. As you can see by looking at the function definition, create a 7-qubit quantum state $ a \ ket {0_L} + b \ ket {1_L} $ by randomly setting complex numbers $ a, b $. Then create a 10 qubit state by performing a tensor product with a 3 qubit ancilla. Create a density operator based on it and return. I made two duplicates that are exactly the same, but this is at the end of the program, in order to compare and evaluate the initial state and the state of the operation result.

# add noise
de_fin.noise(kind='depolarize', qid=[qid_C[3]], prob=1.0)

Then add noise. The noise (qubit channel) installed as standard in qlazy is "bit inversion (bit_flip)", "phase inversion (phase_flip)", and "bit phase inversion (bit_phasee_flip)". There are 6 types, "depolarize", "amplitude dumping (amp_dump)", and "phase dumping (phase_dump)", and each of them gives a list of qubit numbers to be applied and a probability representing noise intensity as arguments. I am. The function (custom gate) noise is applied to the density operator by specifying a character string indicating the type of the quantum channel, a list of qubit numbers, and a probability as arguments. See the function definition for details.

# error correction
de_fin.correct('bit_flip', qid_C, qid_S)
de_fin.correct('phase_flip', qid_C, qid_S)

Is performing bit inversion error correction and phase inversion error correction. The function (custom gate) correct specifies a string indicating whether the argument supports bit inversion or phase inversion, and a list of qubit numbers corresponding to the code space and ancilla. Let's take a look at the contents of correect.

self.reset(qid=qid_S)

Now initialize Ansila. Initialization is required first for error syndrome calculation.

if kind == 'phase_flip': [self.h(q) for q in qid_C]

If you want to support phase inversion, you have to execute Hadamard first, so I am doing it here.

# syndrome
for i, row in enumerate(Hamming):
    [self.cx(qid_C[j], qid_S[i]) if row[j] == 1 else False for j in range(len(row))]

Now, perform the calculation of the error syndrome. In order to execute the circuit described above, we are running a loop that properly applies CNOT to each row of the Hamming code parity check matrix.

# correction
for i, row in enumerate(Hamming_T):
    [self.x(qid_S[j]) if row[j] == 0 else False for j in range(len(row))]
    self.mcx(qid=qid_S+[qid_C[i]])
    [self.x(qid_S[j]) if row[j] == 0 else False for j in range(len(row))]

Then, depending on the result of the error syndrome, the bit is inverted and restored. Depending on each column of the parity check matrix of the Hamming code, we are running a loop that appropriately applies multi-control NOT (mcx method).

if kind == 'phase_flip': [self.h(q) for q in qid_C]

So, if it supports phase inversion, apply Hadamard at the end to restore it. This completes error correction.

Return to the main processing section again.

# print result
print("== result ==")
print("- fidelity = {:.6f}".format(de_fin.fidelity(de_ini, qid=qid_C)))

In order to compare and evaluate the first density operator and the density operator after performing error correction processing, the fidelity method calculates and displays the fidelity of both. By specifying the quantum bit number list of interest in the argument qid, the fidelity of only the relevant part can be calculated.

DensOp.free_all(de_ini, de_fin)

Free the used memory. If you specify multiple DensOp instances as arguments to the class method free_all, you can free the memory of multiple instances with one line (you can specify any number of instances as arguments).

Confirmation of operation

The execution result is shown. This is the result of applying the depolarization channel to the third qubit with a probability of 1.0.

== quantum state (a |0L> + b |1L>) ==
- a = 0.4835+0.0654j
- b = 0.2558+0.9664j
== noise (depolarize) ==
- qubit = [3]
- prob  = 1.0
== result ==
- fidelity = 1.000000

Since the fidelity is 1.0, the error correction was successful. I tried changing the qubit number, quantum channel, and probability, and found that the fidelity was 1.0 in any case, and error correction was possible.

However, of course, it was useless if there was noise in the two qubits. It is as follows.

== quantum state (a |0L> + b |1L>) ==
- a = 0.4749+0.4393j
- b = 0.5424+0.6672j
== noise (depolarize) ==
- qubit = [3, 4]
- prob  = 1.0
== result ==
- fidelity = 0.864784

And, of course, it didn't work if I omitted the error correction for phase inversion.

# error correction
de_fin.correct('bit_flip', qid_C, qid_S)
# de_fin.correct('phase_flip', qid_C, qid_S)

If you comment out the phase inversion compatible part like this,

== quantum state (a |0L> + b |1L>) ==
- a = 0.2903+0.1936j
- b = 0.8322+0.4586j
== noise (depolarize) ==
- qubit = [3]
- prob  = 1.0
== result ==
- fidelity = 0.707107

And this also causes error correction to fail.

So, I was able to confirm the expected operation.

in conclusion

It turns out that if you bring two classical linear codes that satisfy a certain condition, you can always construct one quantum code from them. In other words, we have one of the powerful tools that can concretely construct various quantum codes. Moreover, the "Steane code" can be executed with 7 qubits. Since "Shor's code" required 9 qubits, we were able to reduce 2 qubits (although we also needed ancilla of 3 qubits)!

As mentioned in the "Introduction", "CSS code" is also equivalent to a subclass of the more general "stabilizer code". Next time, I would like to study this "stabilizer code" (planned).

that's all

Recommended Posts

Basics of Quantum Information Theory: Quantum Error Correction (CSS Code)
Basics of Quantum Information Theory: Quantum Error Correction (Shor's Code)
Basics of Quantum Information Theory: Quantum Error Correction (Stabilizer Code: 4)
Basics of Quantum Information Theory: Quantum Error Correction (Classical Linear Code)
Basics of Quantum Information Theory: Topological Toric Code
Basics of Quantum Information Theory: Entropy (2)
Basics of Quantum Information Theory: Universal Quantum Calculation by Toric Code (1)
Basics of Quantum Information Theory: Data Compression (1)
Basics of Quantum Information Theory: Horebaud Limits
Basics of Quantum Information Theory: Trace Distance
Basics of Quantum Information Theory: Quantum State Tomography
Basics of Quantum Information Theory: Data Compression (2)
Basics of Quantum Information Theory: Logical Operation by Toric Code (Brading)
Basics of Quantum Information Theory: Fault Tolerant Quantum Computation
Read "Basics of Quantum Annealing" Day 5
Read "Basics of Quantum Annealing" Day 6
Basics of Tableau Basics (Visualization Using Geographic Information)