Quantum noise at pagpapagaan ng error
Toshinari Itoko (28 June 2024)
I-download ang pdf ng orihinal na lektura. Tandaan na maaaring maging deprecated ang ilang code snippet dahil mga static na imahe ang mga ito.
Ang tinatayang QPU time para patakbuhin ang eksperimentong ito ay 1 m 40 s.
1. Panimulaβ
Sa araling ito, titingnan natin ang ingay (noise) at kung paano ito mapagagaan sa mga quantum computer. Magsisimula tayo sa pamamagitan ng pagtingin sa mga epekto ng ingay gamit ang isang simulator na kayang gayahin ang ingay sa ilang paraan, kasama na ang paggamit ng mga noise profile mula sa mga tunay na quantum computer. Pagkatapos, lilipat tayo sa mga tunay na quantum computer, kung saan likas ang ingay. Titingnan natin ang mga epekto ng pagpapagaan ng error, kabilang ang mga kombinasyon tulad ng zero-noise extrapolation (ZNE) at gate-twirling.
Magsisimula tayo sa pag-load ng ilang package.
# Added by doQumentation β required packages for this notebook
!pip install -q matplotlib qiskit qiskit-aer qiskit-ibm-runtime
# !pip install qiskit qiskit_aer qiskit_ibm_runtime
# !pip install jupyter
# !pip install matplotlib pylatexenc
import qiskit
qiskit.__version__
'2.0.2'
import qiskit_aer
qiskit_aer.__version__
'0.17.1'
import qiskit_ibm_runtime
qiskit_ibm_runtime.__version__
'0.40.1'
2. Maingay na simulation nang walang pagpapagaan ng errorβ
Ang Qiskit Aer ay isang classical simulator para sa quantum computing. Kaya nitong i-simulate hindi lang ang ideal na pagpapatupad kundi pati na rin ang maingay na pagpapatupad ng mga quantum circuit. Ipinapakita ng notebook na ito kung paano magpatakbo ng maingay na simulation gamit ang Qiskit Aer:
- Bumuo ng noise model
- Bumuo ng maingay na sampler (simulator) gamit ang noise model
- Patakbuhin ang quantum circuit sa maingay na sampler
noise_model = NoiseModel()
...
noisy_sampler = Sampler(options={"backend_options": {"noise_model": noise_model}})
job = noisy_sampler.run([circuit])
2.1 Bumuo ng test circuitβ
Isinasaalang-alang natin ang simpleng 1-qubit na mga circuit na paulit-ulit lamang ang X gates nang d beses (d=0 ... 100) at sinusukat ang Z observable.
from qiskit.circuit import QuantumCircuit
MAX_DEPTH = 100
circuits = []
for d in range(MAX_DEPTH + 1):
circ = QuantumCircuit(1)
for _ in range(d):
circ.x(0)
circ.barrier(0)
circ.measure_all()
circuits.append(circ)
display(circuits[3].draw(output="mpl"))
from qiskit.quantum_info import SparsePauliOp
obs = SparsePauliOp.from_list([("Z", 1.0)])
obs
SparsePauliOp(['Z'],
coeffs=[1.+0.j])
2.2 Bumuo ng noise modelβ
Para sa maingay na simulation, kailangan nating tukuyin ang NoiseModel. Ipinakita namin dito kung paano bumuo ng NoiseModel.
Una, kailangan nating tukuyin ang mga quantum (o readout) error upang idagdag sa noise model.
from qiskit_aer.noise.errors import (
coherent_unitary_error,
amplitude_damping_error,
ReadoutError,
)
from qiskit.circuit.library import RXGate
# Coherent (unitary) error: Over X-rotation error
# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.coherent_unitary_error.html#qiskit_aer.noise.coherent_unitary_error
OVER_ROTATION_ANGLE = 0.05
coherent_error = coherent_unitary_error(RXGate(OVER_ROTATION_ANGLE).to_matrix())
# Incoherent error: Amplitude dumping error
# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.amplitude_damping_error.html#qiskit_aer.noise.amplitude_damping_error
AMPLITUDE_DAMPING_PARAM = 0.02 # in [0, 1] (0: no error)
incoherent_error = amplitude_damping_error(AMPLITUDE_DAMPING_PARAM)
# Readout (measurement) error: Readout error
# https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.noise.ReadoutError.html#qiskit_aer.noise.ReadoutError
PREP0_MEAS1 = 0.03 # P(1|0): Probability of preparing 0 and measuring 1
PREP1_MEAS0 = 0.08 # P(0|1): Probability of preparing 1 and measuring 0
readout_error = ReadoutError(
[[1 - PREP0_MEAS1, PREP0_MEAS1], [PREP1_MEAS0, 1 - PREP1_MEAS0]]
)
from qiskit_aer.noise import NoiseModel
noise_model = NoiseModel()
noise_model.add_quantum_error(coherent_error.compose(incoherent_error), "x", (0,))
noise_model.add_readout_error(readout_error, (0,))
2.3 Bumuo ng maingay na sampler gamit ang noise modelβ
from qiskit_aer.primitives import SamplerV2 as Sampler
noisy_sampler = Sampler(options={"backend_options": {"noise_model": noise_model}})
2.4 Patakbuhin ang mga quantum circuit sa maingay na samplerβ
job = noisy_sampler.run(circuits, shots=400)
result = job.result()
result[0].data.meas.get_counts()
{'0': 389, '1': 11}
2.5 I-plot ang mga resultaβ
import matplotlib.pyplot as plt
plt.title("Noisy simulation")
ds = list(range(MAX_DEPTH + 1))
plt.plot(
ds,
[result[d].data.meas.expectation_values(["Z"]) for d in ds],
color="gray",
linestyle="-",
)
plt.scatter(ds, [result[d].data.meas.expectation_values(["Z"]) for d in ds], marker="o")
plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors="black")
plt.ylim(-1, 1)
plt.xlabel("Circuit depth")
plt.ylabel("Measured <Z>")
plt.show()
2.6 Ideal na simulationβ
ideal_sampler = Sampler()
job_ideal = ideal_sampler.run(circuits)
result_ideal = job_ideal.result()
plt.title("Ideal simulation")
ds = list(range(MAX_DEPTH + 1))
plt.plot(
ds,
[result_ideal[d].data.meas.expectation_values(["Z"]) for d in ds],
color="gray",
linestyle="-",
)
plt.scatter(
ds, [result_ideal[d].data.meas.expectation_values(["Z"]) for d in ds], marker="o"
)
plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors="black")
plt.xlabel("Circuit depth")
plt.ylabel("Measured <Z>")
plt.show()

2.7 Ehersisyoβ
Sa pamamagitan ng pagbabago ng code sa ibaba,
- Subukan ang 25x na bilang ng shots (= 10_000 shots) at tiyaking makukuha ang mas maayos na graph
- Baguhin ang mga noise parameter (OVER_ROTATION_ANGLE, AMPLITUDE_DAMPING_PARAM, PREP0_MEAS1, o PREP1_MEAS0) at tingnan kung paano nagbabago ang graph
OVER_ROTATION_ANGLE = 0.05
coherent_error = coherent_unitary_error(RXGate(OVER_ROTATION_ANGLE).to_matrix())
AMPLITUDE_DAMPING_PARAM = 0.02 # in [0, 1] (0: no error)
incoherent_error = amplitude_damping_error(AMPLITUDE_DAMPING_PARAM)
PREP0_MEAS1 = 0.1 # P(1|0): Probability of preparing 0 and measuring 1
PREP1_MEAS0 = 0.05 # P(0|1): Probability of preparing 1 and measuring 0
readout_error = ReadoutError(
[[1 - PREP0_MEAS1, PREP0_MEAS1], [PREP1_MEAS0, 1 - PREP1_MEAS0]]
)
noise_model = NoiseModel()
noise_model.add_quantum_error(coherent_error.compose(incoherent_error), "x", (0,))
noise_model.add_readout_error(readout_error, (0,))
options = {
"backend_options": {"noise_model": noise_model},
}
noisy_sampler = Sampler(options=options)
job = noisy_sampler.run(circuits, shots=400)
result = job.result()
plt.title("Noisy simulation")
ds = list(range(MAX_DEPTH + 1))
plt.plot(
ds,
[result[d].data.meas.expectation_values(["Z"]) for d in ds],
marker="o",
linestyle="-",
)
plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors="black")
plt.ylim(-1, 1)
plt.xlabel("Depth")
plt.ylabel("Measured <Z>")
plt.show()
2.8 Mas makatotohanang maingay na simulationβ
from qiskit_aer import AerSimulator
from qiskit_ibm_runtime import SamplerV2 as Sampler, QiskitRuntimeService
service = QiskitRuntimeService()
real_backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
) # Eagle
<IBMBackend('ibm_strasbourg')>
aer = AerSimulator.from_backend(real_backend)
noisy_sampler = Sampler(mode=aer)
job = noisy_sampler.run(circuits)
result = job.result()
plt.title("Noisy simulation with noise model from real backend")
ds = list(range(MAX_DEPTH + 1))
plt.plot(
ds,
[result[d].data.meas.expectation_values(["Z"]) for d in ds],
marker="o",
linestyle="-",
)
plt.hlines(0, xmin=0, xmax=MAX_DEPTH, colors="black")
plt.ylim(-1, 1)
plt.xlabel("Depth")
plt.ylabel("Measured <Z>")
plt.show()

3. Tunay na quantum computation na may pagpapagaan ng errorβ
Sa bahaging ito, ipinakita namin kung paano makakuha ng mga resulta na may pagpapagaan ng error (mga expected value) gamit ang Qiskit Estimator. Isinasaalang-alang natin ang 6-qubit Trotterized circuits para sa pag-simulate ng time evolution ng one-dimensional Ising model at tinitingnan kung paano lumalaki ang error kaugnay ng bilang ng mga time step.
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
) # Eagle
backend
<IBMBackend('ibm_strasbourg')>
NUM_QUBITS = 6
NUM_TIME_STEPS = list(range(8))
RX_ANGLE = 0.1
RZZ_ANGLE = 0.1
3.1 Bumuo ng mga circuitβ
# Build circuits with different number of time steps
circuits = []
for n_steps in NUM_TIME_STEPS:
circ = QuantumCircuit(NUM_QUBITS)
for i in range(n_steps):
# rx layer
for q in range(NUM_QUBITS):
circ.rx(RX_ANGLE, q)
# 1st rzz layer
for q in range(1, NUM_QUBITS - 1, 2):
circ.rzz(RZZ_ANGLE, q, q + 1)
# 2nd rzz layer
for q in range(0, NUM_QUBITS - 1, 2):
circ.rzz(RZZ_ANGLE, q, q + 1)
circ.barrier() # need not to optimize the circuit
# Uncompute stage
for i in range(n_steps):
for q in range(0, NUM_QUBITS - 1, 2):
circ.rzz(-RZZ_ANGLE, q, q + 1)
for q in range(1, NUM_QUBITS - 1, 2):
circ.rzz(-RZZ_ANGLE, q, q + 1)
for q in range(NUM_QUBITS):
circ.rx(-RX_ANGLE, q)
circuits.append(circ)
Para malaman nang maaga ang ideal na output, gumagamit tayo ng compute-uncompute circuits na binubuo ng unang yugto kung saan inilalapat ang orihinal na circuit , at pangalawang yugto kung saan binaliktad ito . Tandaan na ang ideal na resulta ng ganitong mga circuit ay palaging magiging ang input state , na may trivial na expected value para sa anumang Pauli observable, halimbawa, .
# Print the circuit with 2 time steps
circuits[2].draw(output="mpl")
Tandaan: Tulad ng makikita sa itaas, ang circuit na may time steps ay magtataglay ng na two-qubit gate layers.
obs = SparsePauliOp.from_sparse_list([("Z", [0], 1.0)], num_qubits=NUM_QUBITS)
obs
SparsePauliOp(['IIIIIZ'],
coeffs=[1.+0.j])
3.2 I-transpile ang mga circuitβ
Ini-transpile natin ang mga circuit para sa Backend na may optimization (optimization_level=1).
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuits = pm.run(circuits)
display(isa_circuits[2].draw("mpl", idle_wires=False, fold=-1))

3.3 Isagawa gamit ang Estimator (na may iba't ibang antas ng resilience)β
Ang pagtatakda ng resilience level (estimator.options.resilience_level) ang pinakamadaling paraan upang ilapat ang pagpapagaan ng error kapag gumagamit ng Qiskit Estimator. Sinusuportahan ng Estimator ang mga sumusunod na resilience level (mula noong 2024/06/28). Tingnan ang higit pang detalye sa gabay na I-configure ang pagpapagaan ng error.

from qiskit_ibm_runtime import Batch
from qiskit_ibm_runtime import EstimatorV2 as Estimator
jobs = []
job_ids = []
with Batch(backend=backend):
for resilience_level in [0, 1, 2]:
estimator = Estimator()
estimator.options.resilience_level = resilience_level
job = estimator.run(
[(circ, obs.apply_layout(circ.layout)) for circ in isa_circuits]
)
job_ids.append(job.job_id())
print(f"Job ID (rl={resilience_level}): {job.job_id()}")
jobs.append(job)
Job ID (rl=0): d146vcnmya70008emprg
Job ID (rl=1): d146vdnqf56g0081sva0
Job ID (rl=2): d146ven5z6q00087c61g
# check job status
for job in jobs:
print(job.status())
DONE
DONE
DONE
# REPLACE WITH YOUR OWN JOB IDS
jobs = [service.job(job_id) for job_id in job_ids]
# Get results
results = [job.result() for job in jobs]
3.4 I-plot ang mga resultaβ
plt.title("Error mitigation with different resilience levels")
labels = ["0 (No mitigation)", "1 (TREX)", "2 (ZNE + Gate twirling)"]
steps = NUM_TIME_STEPS
for result, label in zip(results, labels):
plt.errorbar(
x=steps,
y=[result[s].data.evs for s in steps],
yerr=[result[s].data.stds for s in steps],
marker="o",
linestyle="-",
capsize=4,
label=label,
)
plt.hlines(
1.0, min(steps), max(steps), linestyle="dashed", label="Ideal", colors="black"
)
plt.xlabel("Time steps")
plt.ylabel("Mitigated <IIIIIZ>")
plt.legend()
plt.show()
4. (Opsyonal) I-customize ang mga opsyon ng pagpapagaan ng errorβ
Maaari nating i-customize ang paglalapat ng mga teknik sa pagpapagaan ng error sa pamamagitan ng mga opsyon tulad ng ipinapakita sa ibaba.
# TREX
estimator.options.twirling.enable_measure = True
estimator.options.twirling.num_randomizations = "auto"
estimator.options.twirling.shots_per_randomization = "auto"
# Gate twirling
estimator.options.twirling.enable_gates = True
# ZNE
estimator.options.resilience.zne_mitigation = True
estimator.options.resilience.zne.noise_factors = [1, 3, 5]
estimator.options.resilience.zne.extrapolator = ("exponential", "linear")
# Dynamical decoupling
estimator.options.dynamical_decoupling.enable = True # Default: False
estimator.options.dynamical_decoupling.sequence_type = "XX"
# Other options
estimator.options.default_shots = 10_000
Tingnan ang mga sumusunod na gabay at API reference para sa mga detalye ng mga opsyon ng pagpapagaan ng error.