Syndrome measurements for stabilizer codes#

We will revisit syndrome measurements now, and demonstrate a general algorithm to construct them for stabilizer codes.

Our working example will be the Steane code.

import stac
cd = stac.CommonCodes.generate_code("[[7,1,3]]")
stac.print_matrix(cd.generator_matrix, augmented=True)
$\displaystyle \left(\begin{array}{ccccccc|ccccccc} 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 1 & 1 & 0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 1 & 0 & 1 & 0 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 0 & 0 & 1 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 1 & 0 & 1 \\ \end{array}\right) $

As you might recall, we said that for stabilizer codes, one has to measure each generator in turn. This is done via the following algorithm, which creates a circuit with $n+m$ qubits.

syndrome_circuit = stac.Circuit.simple(cd.num_data_qubits + cd.num_generators)
for i in range(num_generators):
    syndrome_circuit.append("H", n+i)

for i in range(cd.num_generators):
    for j in range(cd.num_data_qubits):
        if cd.generators_x[i, j] and cd.generators_z[i, j]:
            syndrome_circuit.append("CX", n+i, j)
            syndrome_circuit.append("CZ", n+i, j)
        elif cd.generators_x[i, j]:
            syndrome_circuit.append("CX", n+i, j)
        elif cd.generators_z[i, j]:
            syndrome_circuit.append("CZ", n+i, j)

for i in range(cd.num_generators):
    syndrome_circuit.append("H", n+i)
    
for i in range(cd.num_generators):
        syndrome_circuit.append('MR', self.num_data_qubits+i)
cd.construct_syndrome_circuit();
cd.syndrome_circuit.draw()
(0, 0, 0, 0)    :  0(0, 0, 0, 1)    :  1(0, 0, 0, 2)    :  2(0, 0, 0, 3)    :  3(0, 0, 0, 4)    :  4(0, 0, 0, 5)    :  5(0, 0, 0, 6)    :  6(0, 0, 1, 0, 0) :  7(0, 0, 1, 1, 0) :  8(0, 0, 1, 2, 0) :  9(0, 0, 1, 3, 0) : 10(0, 0, 1, 4, 0) : 11(0, 0, 1, 5, 0) : 12HHHHHHXXXXXXXXXXXXZZZZZZZZZZZZHHHHHHMRMRMRMRMRMR

To use this in practice, we will

  1. Encode the zero state
  2. Introduce an error
  3. Measure the stabilizers
# Step 1
circ = cd.construct_encoding_circuit('non_ft')
circ.append('TICK')

# Step 2
circ.append('X', 1)

# Step 3
circ += cd.syndrome_circuit

circ.draw()
(0, 0, 0, 0)    :  0(0, 0, 0, 1)    :  1(0, 0, 0, 2)    :  2(0, 0, 0, 3)    :  3(0, 0, 0, 4)    :  4(0, 0, 0, 5)    :  5(0, 0, 0, 6)    :  6(0, 0, 1, 0, 0) :  7(0, 0, 1, 1, 0) :  8(0, 0, 1, 2, 0) :  9(0, 0, 1, 3, 0) : 10(0, 0, 1, 4, 0) : 11(0, 0, 1, 5, 0) : 12XXHXXXHXXXHXXXXHHHHHHXXXXXXXXXXXXZZZZZZZZZZZZHHHHHHMRMRMRMRMRMR
# we use stim to simulate this circuit
circ.sample()
[0 0 0 1 1 0]

As we can see, an $X$ error on the 2nd qubit leads to a the 3rd and 4th generators failing (counting from 0). The syndrome vector is the $n+2=9$th column (counting from 1) of the generator matrix, because as discussed previously it is the $Z$-type stabilizer generators that detect bit-flip errors. In this way, each of the $n$ $X$-type errors and $n$ $Z$-type errors correspond to one of the columns of the generator matrix.

Task 1#

Determine the syndromes for each possible one qubit $X$ error and each possible one qubit $Z$ error.

#

Task 2#

Determine the syndromes when there is a two qubit $X$ error (errors such as $X_0 X_3$). Compare the syndromes with the one-qubit error syndromes. What does this tell you about correcting two-qubit errors with the Steane code?

#