Zum Haubtinhald schringsn

Wiederhoolungscodes

Laufzeidschätzung: wenicher als 1 Minute uff nem Heron-Brozessor (HINWEIS: Des is nur e Schätzung. Eiern tatsächliche Laufzeit gann abweichen.)

Hintergrund

Damitt echtzeidliche Quantenfehlergorrektur (QEC) funggsjooniert, muss mer den Brogrammfluss während der Ausfierung dynamisch steiern gennen, sodass Quantum Gates von Messkresultaten abhängich gemacht werd'n gennen. Des Tutorial fiert den Bit-Flip-Code aus, ne sehr eenfache Form von QEC. Es zeigt nen dynamischen Quantenschaltkrees, der en godierten Qubit vor enem einzelnen Bit-Flip-Fehler schiedzt, un bewertet dann de Leistung von dem Bit-Flip-Code.

Mer gann zusätzliche Ancilla-Qubits un Verschränggung nutzen, um Stabilisatoren zu messen, die de godierten Quanteninformatschjoon nich verändern, uns aber trotzdem ieeber bestimmde Fehlerglassen informieren. En Quanten-Stabilisator-Code godiert kk logische Qubits in nn physikalische Qubits. Stabilisatorcodes konzentrier'n sich dabei uff de Gorrektur enes disgreden Fehlersatzes mit Unterstietzing von der Pauli-Gruppe Πn\Pi^n.

Fier mehr Informatschjoon'n zu QEC guggt eich Quantum Error Correction for Beginners an.

Voraussetzung'n

Befor ihr mit dem Tutorial anfangt, guckt, dass folgendes installjert is:

  • Qiskit SDK v2.0 oder neier, mit Unterstietzing fier Visualisierung
  • Qiskit Runtime v0.40 oder neier (pip install qiskit-ibm-runtime)

Einrichttung

# Qiskit imports
from qiskit import (
QuantumCircuit,
QuantumRegister,
ClassicalRegister,
)

# Qiskit Runtime
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler

from qiskit_ibm_runtime.circuit import MidCircuitMeasure

service = QiskitRuntimeService()

Schritt 1. Glassische Eingaben uff s Quantenproblem abbilden

Nen Bit-Flip-Stabilisator-Circuit bau'n

Der Bit-Flip-Code gehert zu de eenfachstn Beispiele eenes Stabilisatorcodes. Er schietzte den Zustand vor enem einzelnen Bit-Flip-(X)-Fehler uff eenm von de Godierungsqubits. Betrachten mer den Bit-Flip-Fehler XX, der 01|0\rangle \rightarrow |1\rangle un 10|1\rangle \rightarrow |0\rangle uff eenm von unsre Qubits abbildet, dann gild ϵ={E0,E1,E2}={IIX,IXI,XII}\epsilon = \{E_0, E_1, E_2 \} = \{IIX, IXI, XII\}. Der Code braucht fienf Qubits: drei werd'n zum Godieren des geschitzdtn Zustands verwendet, die restlichen zwei als Ancillas fier de Stabilisatormessung.

# Choose the least busy backend that supports `measure_2`.

backend = service.least_busy(
filters=lambda b: "measure_2" in b.supported_instructions,
operational=True,
simulator=False,
dynamic_circuits=True,
)
qreg_data = QuantumRegister(3)
qreg_measure = QuantumRegister(2)
creg_data = ClassicalRegister(3, name="data")
creg_syndrome = ClassicalRegister(2, name="syndrome")
state_data = qreg_data[0]
ancillas_data = qreg_data[1:]

def build_qc():
"""Build a typical error correction circuit"""
return QuantumCircuit(qreg_data, qreg_measure, creg_data, creg_syndrome)

def initialize_qubits(circuit: QuantumCircuit):
"""Initialize qubit to |1>"""
circuit.x(qreg_data[0])
circuit.barrier(qreg_data)
return circuit

def encode_bit_flip(circuit, state, ancillas) -> QuantumCircuit:
"""Encode bit-flip. This is done by simply adding a cx"""
for ancilla in ancillas:
circuit.cx(state, ancilla)
circuit.barrier(state, *ancillas)
return circuit

def measure_syndrome_bit(circuit, qreg_data, qreg_measure, creg_measure):
"""
Measure the syndrome by measuring the parity.
We reset our ancilla qubits after measuring the stabilizer
so we can reuse them for repeated stabilizer measurements.
Because we have already observed the state of the qubit,
we can write the conditional reset protocol directly to
avoid another round of qubit measurement if we used
the `reset` instruction.
"""
circuit.cx(qreg_data[0], qreg_measure[0])
circuit.cx(qreg_data[1], qreg_measure[0])
circuit.cx(qreg_data[0], qreg_measure[1])
circuit.cx(qreg_data[2], qreg_measure[1])
circuit.barrier(*qreg_data, *qreg_measure)
circuit.append(MidCircuitMeasure(), [qreg_measure[0]], [creg_measure[0]])
circuit.append(MidCircuitMeasure(), [qreg_measure[1]], [creg_measure[1]])

with circuit.if_test((creg_measure[0], 1)):
circuit.x(qreg_measure[0])
with circuit.if_test((creg_measure[1], 1)):
circuit.x(qreg_measure[1])
circuit.barrier(*qreg_data, *qreg_measure)
return circuit

def apply_correction_bit(circuit, qreg_data, creg_syndrome):
"""We can detect where an error occurred and correct our state"""
with circuit.if_test((creg_syndrome, 3)):
circuit.x(qreg_data[0])
with circuit.if_test((creg_syndrome, 1)):
circuit.x(qreg_data[1])
with circuit.if_test((creg_syndrome, 2)):
circuit.x(qreg_data[2])
circuit.barrier(qreg_data)
return circuit

def apply_final_readout(circuit, qreg_data, creg_data):
"""Read out the final measurements"""
circuit.barrier(qreg_data)
circuit.measure(qreg_data, creg_data)
return circuit
def build_error_correction_sequence(apply_correction: bool) -> QuantumCircuit:
circuit = build_qc()
circuit = initialize_qubits(circuit)
circuit = encode_bit_flip(circuit, state_data, ancillas_data)
circuit = measure_syndrome_bit(
circuit, qreg_data, qreg_measure, creg_syndrome
)

if apply_correction:
circuit = apply_correction_bit(circuit, qreg_data, creg_syndrome)

circuit = apply_final_readout(circuit, qreg_data, creg_data)
return circuit

circuit = build_error_correction_sequence(apply_correction=True)
circuit.draw(output="mpl", style="iqp", cregbundle=False)

Output of the previous code cell

Output of the previous code cell

Schritt 2. Des Problem fier de Quantenausfierung optimier'n

Damitt de gesämde Job-Ausfierungszeit gürzer werd, aggzeptier'n Qiskit-Primitiven nur Circuits un Observablen, die de Anweisungen un de Gonnektivität von'm Zielsystem entsprechen (auch als ISA-Circuits un -Observablen bekannt). Mehr zur Transpilatschjoon erfahr'n.

ISA-Circuits erzeing'n

from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)

isa_circuit.draw("mpl", style="iqp", idle_wires=False)

Output of the previous code cell

Output of the previous code cell

no_correction_circuit = build_error_correction_sequence(
apply_correction=False
)

isa_no_correction_circuit = pm.run(no_correction_circuit)

Schritt 3. Mit Qiskit-Primitiven ausfier'n

Fiert de Version mit Gorrektur un de Version ohne Gorrektur aus.

sampler_no_correction = Sampler(backend)
job_no_correction = sampler_no_correction.run(
[isa_no_correction_circuit], shots=1000
)
result_no_correction = job_no_correction.result()[0]
sampler_with_correction = Sampler(backend)

job_with_correction = sampler_with_correction.run([isa_circuit], shots=1000)
result_with_correction = job_with_correction.result()[0]
print(f"Data (no correction):\n{result_no_correction.data.data.get_counts()}")
print(
f"Syndrome (no correction):\n{result_no_correction.data.syndrome.get_counts()}"
)
Data (no correction):
{'111': 878, '011': 42, '110': 35, '101': 40, '100': 1, '001': 2, '000': 2}
Syndrome (no correction):
{'00': 942, '10': 33, '01': 22, '11': 3}
print(f"Data (corrected):\n{result_with_correction.data.data.get_counts()}")
print(
f"Syndrome (corrected):\n{result_with_correction.data.syndrome.get_counts()}"
)
Data (corrected):
{'111': 889, '110': 25, '000': 11, '011': 45, '101': 17, '010': 10, '001': 2, '100': 1}
Syndrome (corrected):
{'00': 929, '01': 39, '10': 20, '11': 12}

Schritt 4. Nachbearbeitung, Erchebnis in glassischem Format zurieggeb'n

Mer siehd, dass der Bit-Flip-Code viele Fehler erkannt un gorrericht hat, was insgesämd zu wenicher Fehler gefiehrd hat.

def decode_result(data_counts, syndrome_counts):
shots = sum(data_counts.values())
success_trials = data_counts.get("000", 0) + data_counts.get("111", 0)
failed_trials = shots - success_trials
error_correction_events = shots - syndrome_counts.get("00", 0)
print(
f"Bit flip errors were detected/corrected on {error_correction_events}/{shots} trials."
)
print(
f"A final parity error was detected on {failed_trials}/{shots} trials."
)
# non-corrected marginalized results
data_result = result_no_correction.data.data.get_counts()
marginalized_syndrome_result = result_no_correction.data.syndrome.get_counts()

print(
f"Completed bit code experiment data measurement counts (no correction): {data_result}"
)
print(
f"Completed bit code experiment syndrome measurement counts (no correction): {marginalized_syndrome_result}"
)
decode_result(data_result, marginalized_syndrome_result)
Completed bit code experiment data measurement counts (no correction): {'111': 878, '011': 42, '110': 35, '101': 40, '100': 1, '001': 2, '000': 2}
Completed bit code experiment syndrome measurement counts (no correction): {'00': 942, '10': 33, '01': 22, '11': 3}
Bit flip errors were detected/corrected on 58/1000 trials.
A final parity error was detected on 120/1000 trials.
# corrected marginalized results
corrected_data_result = result_with_correction.data.data.get_counts()
corrected_syndrome_result = result_with_correction.data.syndrome.get_counts()

print(
f"Completed bit code experiment data measurement counts (corrected): {corrected_data_result}"
)
print(
f"Completed bit code experiment syndrome measurement counts (corrected): {corrected_syndrome_result}"
)
decode_result(corrected_data_result, corrected_syndrome_result)
Completed bit code experiment data measurement counts (corrected): {'111': 889, '110': 25, '000': 11, '011': 45, '101': 17, '010': 10, '001': 2, '100': 1}
Completed bit code experiment syndrome measurement counts (corrected): {'00': 929, '01': 39, '10': 20, '11': 12}
Bit flip errors were detected/corrected on 71/1000 trials.
A final parity error was detected on 100/1000 trials.

Tutorial-Umfrage

Macht doch bitte de gurze Umfrage, damitt ihr Rieggemeldung zu dem Tutorial geb'n gennt. Eier Einschätzung'n helf'n uns, unsre Inhalte un de Benutzererfahrung zu verbessern.

Link zur Umfrage