# Implement parity check gadget using stim

I want to implement the logical $$\left|00\right\rangle$$ state preparation for $$C_4$$([[4,2,2]]) code using Stim. And the circuit is as below:

I have written a piece of code that seems to be effective:

# Define the initial circuit
circuit = stim.Circuit('''
H 4 5 6 7
X_ERROR(0.5) 6
CX 4 0 5 1 6 2 7 3
CX 0 5 1 6 2 7 3 4
M 4 5 6 7
''')

# Simulate the circuit up to the first measurement
simulator = stim.TableauSimulator()
simulator.do(circuit)
first_measurements = simulator.current_measurement_record()

# Analyze the first measurement results
i_1, i_2, i_3, i_4 = first_measurements
print("First Measurement results:", first_measurements)

# Conditional operations based on measurement results
if i_1 == 1:
simulator.do(stim.Circuit("X 0"))
if i_1 + i_2 == 1:
simulator.do(stim.Circuit("X 1"))
if (i_1 + i_2 + i_3) % 2 == 1:
simulator.do(stim.Circuit("X 2"))

# Final measurement of the first four qubits
simulator.do(stim.Circuit("M 0 1 2 3"))

# Retrieve final measurement results
final_measurements = simulator.current_measurement_record()

print("Final Measurement results:", final_measurements[-4:])


The result is $$\frac{1}{\sqrt{2}}(\left|0000\right\rangle+\left|1111\right\rangle)$$

Instead of using stim.Circuit(''' '''), I want to use circuit = stim.Circuit(); circuit.append():

Total_qubits = list(range(8))
data_qubits = Total_qubits[0:4]
ancilla_qubits = Total_qubits[4:8]

circuit = stim.Circuit()
for i in range(4):
circuit.append('H', ancilla_qubits[i])
for i in range(4):
circuit.append('CNOT', [ancilla_qubits[i], data_qubits[i]])
for i in range(3):
circuit.append('CNOT', [data_qubits[i], ancilla_qubits[i+1]])
circuit.append('CNOT', [data_qubits[3], ancilla_qubits[0]])
for i in range(4):
circuit.append('M', ancilla_qubits[i])

# Simulate the circuit up to the first measurement
simulator = stim.TableauSimulator()
simulator.do(circuit)
first_measurements = simulator.current_measurement_record()

# Analyze the first measurement results
i_1, i_2, i_3, i_4 = first_measurements

# Conditional operations based on measurement results
if i_1 == 1:
circuit.append('X', [data_qubits[0]])
if i_1 + i_2 == 1:
circuit.append('X', [data_qubits[1]])
if (i_1 + i_2 + i_3) % 2 == 1:
circuit.append('X', [data_qubits[2]])

# Final measurement of the first four qubits
for i in range(4):
circuit.append('M', data_qubits[i])

# Retrieve final measurement results
simulator.do(circuit)
final_measurements = simulator.current_measurement_record()
print("Final Measurement results:", final_measurements[-4:])


But the result is different with previous one.

I need to write a state preparation function that takes data qubits and ancillas as input and outputs the prepared data qubits. However, it appears impossible to use circuit = stim.Circuit(''' Gate qubits[i] """). How can I modify my code? Additionally, is it feasible to create such a logical state preparation function using Stim?

• Have you tried looking at the contents of the circuit you built using append? You can print(circuit) to see if it matches the original. You can also use print(circuit.diagram()) on the original and the one built with append to get a text diagram of them to compare. Commented Apr 15 at 7:30
• Yes, I have tried, but these two pieces of code produce different results. I suspect this may be because I used simulator.do(circuit) twice in the latter code, which discards the previous results and implements the newly designed circuit instead. Commented Apr 15 at 7:36

Executing your second code, you will see that final_measurements is of length 12, which suggests that the simulator starts over the second time you call simulator.do, flipping the new data qubits according to old measured ancillae. If you reset circuit to the empty Circuit before appending your conditional operations, the simulator will only do 4 new measurements and update the data qubits according to the measured ancillae.

To answer your question about defining a circuit with a string while being flexible about the qubit labels, you can use Python's f-string:

import stim

def state_preparation(data_qubits, ancilla_qubits):
# Converts qubit labels to strings
data_qubits_as_str = [str(qb) for qb in data_qubits]
ancilla_qubits_as_str = [str(qb) for qb in ancilla_qubits]

circuit = stim.Circuit(f'''
RX {" ".join(ancilla_qubits_as_str)} # Maybe better than H in broader context
X_ERROR(0.5) {ancilla_qubits_as_str[2]} # Or any other error model

# Entanglement of the ancilla qubits
CX {" ".join(qb1 + " " + qb2 for qb1, qb2 in zip(ancilla_qubits_as_str, data_qubits_as_str))}
CX {" ".join(qb1 + " " + qb2 for qb1, qb2 in zip(data_qubits_as_str, ancilla_qubits_as_str[1:]))}
CX {data_qubits_as_str[-1]} {ancilla_qubits_as_str[0]}

# Ancilla Measurement
M {" ".join(ancilla_qubits_as_str)}

# Classically controlled X gate based on ancilla measurements
CX rec[-4] {data_qubits_as_str[0]}
CX rec[-4] {data_qubits_as_str[1]}
CX rec[-4] {data_qubits_as_str[2]}
CX rec[-3] {data_qubits_as_str[1]}
CX rec[-3] {data_qubits_as_str[2]}
CX rec[-2] {data_qubits_as_str[2]}

M {" ".join(data_qubits_as_str)}
''')
return circuit
circuit = state_preparation([10, 11, 12, 13], [14, 15, 16, 17])

simulator = stim.TableauSimulator()
simulator.do(circuit)

final_measurements = simulator.current_measurement_record()

print("Final Measurement results:", final_measurements[-4:])


When the f-string is evaluated (please note the f before the opening three quotes: f'''), code snippets between brackets {} are evaluated and inserted into the string (they must be strings themselves). More information here.

This method have advantages and disavantages compared to circuit appending.

In the code above, I used classically controlled $$X$$ gate to conditionally update the data qubits by using rec which stores the measurement results in order of measurement.

" ".join(...) is used to create a string from an iterable (e.g. lists). Here elements of the iterable parameter will be separated by a whitespace.

• Thanks so much!!!!! Commented Apr 15 at 9:19