Langkau ke kandungan utama
Projek ini dalam fasa beta. Jumpa pepijat? Buat isu GitHub. Ada soalan atau idea? Tanya dalam Discussions — kami suka dengar maklum balas anda!
Bagaimana kualiti terjemahan pada halaman ini?

Ekstrapolasi hingar sifar dengan penguatan ralat probabilistik

Ekstrapolasi hingar sifar (ZNE) ialah teknik untuk mengurangkan hingar kuantum dalam pengiraan nilai jangkaan observable. Ia berfungsi dengan melaksanakan litar kuantum pada skala hingar yang meningkat, mengambil nilai jangkaan berkenaan skala hingar tersebut, dan mengekstrapolasi untuk menganggar nilai jangkaan hingar sifar. Kedua-dua peringkat penguatan hingar dan ekstrapolasi boleh dilaksanakan dengan cara yang berbeza. Dalam panduan ini anda akan menguatkan hingar dengan penguatan ralat probabilistik (PEA), seperti yang dicadangkan dalam "Evidence for the utility of quantum computing before fault tolerance". Untuk menguatkan dengan PEA, anda mesti terlebih dahulu memodelkan hingar yang menjejaskan gate berbelit litar. Anda juga boleh melaksanakan penguatan dengan digital gate folding, yang tidak memerlukan model hingar dan diliputi dalam panduan gate folding. Anda akan mempelajari hingar dengan qiskit-noise-learning dan mengekstrapolasi dengan strategi penyuaian eksponen terbina dalam.

Perlu diingat, walaupun ZNE boleh berkesan dalam mengurangkan hingar kuantum dengan kos pensampelan yang lebih rendah daripada kaedah lain, ia tidak mempunyai sempadan pada pincang.

ZNE extrapolation

Aliran kerjanya adalah seperti berikut:

  1. Tentukan litar dan observable
  2. Kira nilai jangkaan tepat menggunakan simulator statevector Qiskit
  3. Kira nilai jangkaan berhingar yang tidak dikurangkan
  4. Pelajari hingar lapisan berbelit dengan qiskit-noise-learning
  5. Sediakan program ZNE dengan penguatan ralat probabilistik dan litar sampel pada skala hingar yang berbeza
  6. Ekstrapolasi ke had hingar sifar
  7. Bandingkan nilai jangkaan yang dikurangkan

Tentukan litar dan observable​

Dalam panduan ini anda akan mengira magnetisasi purata-tapak ⟨Z⟩avg=1N∑i=1N⟨Zi⟩\langle Z \rangle_{\text{avg}} = \frac{1}{N} \sum_{i=1}^{N} \langle Z_i \rangle bagi model Ising medan melintang (TFIM) Trotter pada lapan qubit dalam topologi cincin. Anda akan menyapu beberapa nilai kekuatan medan melintang dan memplot magnetisasi sebagai fungsi kekuatan medan. Dalam topologi cincin pada bilangan qubit genap, lapisan gate dua qubit boleh dibahagikan kepada dua lapisan unik, seperti yang ditunjukkan oleh warna merah dan hijau dalam peta gandingan di bawah. Mereka bentuk litar supaya mempunyai set minimum lapisan berbelit unik adalah penting jika anda ingin mempelajari model hingar, kerana lapisan unik mesti dipelajari secara bebas. Jika litar anda mempunyai terlalu banyak lapisan unik, pembelajaran hingar boleh menjadi tidak praktikal disebabkan kos pensampelan untuk mempelajari banyak lapisan.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"IPython": "IPython", "matplotlib": "matplotlib", "numpy": "numpy", "qiskit": "qiskit", "qiskit_aer": "qiskit-aer", "qiskit_ibm_runtime": "qiskit-ibm-runtime", "qiskit_mitigation": "qiskit-mitigation", "qiskit_noise_learning": "qiskit-noise-learning", "samplomatic": "samplomatic", "scipy": "scipy"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
import warnings

import IPython.display
import numpy as np
from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.visualization import plot_coupling_map

warnings.filterwarnings("ignore")

def trotter_circuit(num_qubits, theta, layers, num_steps):
"""Trotterized transverse-field Ising evolution: RX on every site, then a CZ layer per coupling layer."""
circuit = QuantumCircuit(num_qubits)
for _ in range(num_steps):
circuit.rx(theta, range(num_qubits))
for layer in layers:
circuit.barrier()
for edge in layer:
circuit.cz(*edge)
circuit.sdg(edge)
circuit.barrier()
return circuit

num_qubits = 8
trotter_steps = 15
ring_coupling = [(i, (i + 1) % num_qubits) for i in range(num_qubits)]
layers = [
ring_coupling[0::2],
ring_coupling[1::2],
] # two disjoint layers of CZ gates
theta = Parameter("theta")
circuit = trotter_circuit(num_qubits, theta, layers, trotter_steps)

# Parameter values: theta in [0, 0.25 pi] - values for the transverse-field sweep
data_points = 6
parameter_values = np.linspace(0, 0.25 * np.pi, data_points).reshape(
(data_points, 1)
)

# Define observables - Z on each site
observables = [
SparsePauliOp("I" * (num_qubits - q - 1) + "Z" + "I" * q)
for q in range(num_qubits)
]

print("Edges of the same color may execute their gates simultaneously.")
IPython.display.display(
plot_coupling_map(
num_qubits=num_qubits,
qubit_coordinates=None,
coupling_map=ring_coupling,
figsize=(4, 4),
qubit_size=150,
line_width=5,
line_color=[
"red" if edge in layers[0] else "green" for edge in ring_coupling
],
font_size=90,
)
)
print("Visualization of 1 Trotter step")
trotter_circuit(num_qubits, theta, layers, 1).draw("mpl", scale=0.7)
Edges of the same color may execute their gates simultaneously.

Output of the previous code cell

Visualization of 1 Trotter step

Output of the previous code cell

Kira nilai jangkaan tepat menggunakan simulator statevector Qiskit​

Gunakan kelas Statevector Qiskit untuk mengira nilai jangkaan tepat ZiZ_i pada setiap tapak bagi setiap nilai θ\theta.

from qiskit.quantum_info import Statevector
import matplotlib.pyplot as plt

exact_evs = np.array(
[
[
Statevector(circuit.assign_parameters([value]))
.expectation_value(obs)
.real
for value in parameter_values.ravel()
]
for obs in observables
]
) # shape (observables, parameter values)

x_vals = parameter_values.ravel() / np.pi
fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(x_vals, exact_evs.mean(axis=0), "ko-", label="Exact")
ax.set_xlabel(r"$\theta/\pi$")
ax.set_ylabel(r"$\langle Z \rangle_{\text{avg}}$")
ax.legend()
plt.tight_layout()
plt.show()

Output of the previous code cell

Kira nilai jangkaan berhingar yang tidak dikurangkan​

QuantumProgram mengandungi litar kuantum dan samplex dalam format yang sesuai untuk primitif Executor. MitigationTask.prepare membina QuantumProgram daripada litar, observable, dan nilai parameter, serta mengotakkan litar dengan pilihan pengotakan yang diberikan. Tetapkan pilihan pengotakan measure_annotations kepada "change_basis", yang memutarkan pengukuran ke dalam asas yang diperlukan, dan tambah add_tags: "unique_box" supaya simulator dapat memetakan model hingar ke atas kotak litar. Program ini di-twirl Pauli secara lalai, yang pada perkakasan menukar hingar koheren kepada hingar Pauli yang diandaikan oleh kaedah mitigasi. num_randomizations menetapkan berapa banyak contoh twirl bagi setiap litar yang disampel, dan shots_per_randomization menetapkan berapa banyak shot yang diterima setiap contoh, jadi hasil darabnya ialah bajet shot bagi setiap litar.

Pengguna yang mempunyai akses QPU akan melaksanakan atur cara dengan Executor yang dibina daripada backend QiskitRuntimeService. Di sini anda akan menghantar AerSimulator kepada Executor, yang menjalankan atur cara secara setempat, dan menggunakan pilihan simulator layer_noise_model miliknya untuk menyuntik model hingar Pauli-Lindblad rawak pada setiap lapisan gate berbelit, yang dijana dengan random_pauli_lindblad_noise daripada qiskit-mitigation dengan ralat bagi setiap gate berlapis (EPLG) sebanyak 0.003, lazim bagi QPU Heron semasa.

from qiskit.circuit import CircuitInstruction
from qiskit.quantum_info import PauliLindbladMap, pauli_basis
from qiskit_aer import AerSimulator
from qiskit_ibm_runtime import Executor
from qiskit_mitigation import MitigationTask, find_combined_unique_layers

def generate_random_pauli_lindblad_noise(
layers,
num_qubits: int,
eplg: float = 3e-3,
seed: int | None = None,
) -> list[tuple[CircuitInstruction, PauliLindbladMap]]:
"""Generate random Pauli-Lindblad noise over the full Pauli basis."""
layer_noise_model = []
for layer in layers:
layer_instructions = layer.operation.params[0]
contain_measurement = any(
inst.name.startswith("measure") for inst in layer_instructions
)
if contain_measurement: # do not add measurement noise
layer_noise = PauliLindbladMap.identity(num_qubits)
else:
edges = [
(inst.qubits[0]._index, inst.qubits[1]._index)
for inst in layer_instructions
] # extract the edges of the layer

basis_paulis = [p for p in pauli_basis(2) if np.sum(p.x + p.z)]
rng = np.random.default_rng(seed=seed)
num_generators = len(basis_paulis)
rates = rng.random(len(basis_paulis)) * eplg / num_generators

layer_noise = PauliLindbladMap.from_sparse_list(
[
(pauli.to_label(), edge, rate)
for pauli, rate in zip(basis_paulis, rates, strict=True)
for edge in edges
],
num_qubits=num_qubits,
)
layer_noise_model.append((layer, layer_noise))
return layer_noise_model

num_randomizations = 50
shots_per_randomization = 64

boxing_options = {
"measure_annotations": "change_basis",
"add_tags": "unique_box",
}

# find the unique layers to generate the layered noise for
box_layers = find_combined_unique_layers(
[circuit], custom_boxing_options=boxing_options
)
layer_noise_model = generate_random_pauli_lindblad_noise(
box_layers, num_qubits, seed=42
)

# a local noisy simulator in place of a QPU backend
noisy_executor = Executor(
AerSimulator(),
options={"simulator": {"layer_noise_model": layer_noise_model}},
)

task = MitigationTask()
program = task.prepare(
circuit=circuit,
observables=observables,
parameters=parameter_values,
num_randomizations=num_randomizations,
shots_per_randomization=shots_per_randomization,
custom_boxing_options=boxing_options,
)
program._semantic_role = "simulation" # flag the program for the simulator
unmitigated_res = task.postprocess(noisy_executor.run(program).result())

fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(x_vals, exact_evs.mean(axis=0), "k-", label="Exact")
ax.errorbar(
x_vals,
np.mean(unmitigated_res.data.evs, axis=0),
np.mean(unmitigated_res.data.stds, axis=0),
fmt="o-",
label="Unmitigated",
)
ax.set_xlabel(r"$\theta/\pi$")
ax.set_ylabel(r"$\langle Z \rangle_{\text{avg}}$")
ax.legend()
plt.tight_layout()
plt.show()

Output of the previous code cell

Pelajari hingar lapisan berbelit dengan qiskit-noise-learning​

PEA bermula dengan mempelajari model hingar twirled bagi setiap lapisan gate berbelit dalam litar. Kita menganggap model hingar Markovian, dan oleh itu hanya model hingar bagi setiap lapisan gate berbelit yang unik perlu dipelajari, kerana kedalaman litar diandaikan tidak menjejaskan saluran hingar bagi sesuatu lapisan berbelit. Semakin tepat model hingar yang dipelajari, semakin tepat penguatan tersebut.

Kami menggunakan qiskit-noise-learning untuk mempelajari hingar. Pembelajar mengulang setiap lapisan sebanyak fragment_depths kali dalam litar pembelajarannya, melakukan twirl pada setiap litar sebanyak num_randomizations kali, dan memadankan pereputan fidelity yang diukur kepada model Pauli-Lindblad. Kod berikut melukis model hingar yang dipelajari, dengan kedua-dua lapisan digabungkan menjadi satu peta. Setiap qubit ialah carta pai bagi kadar X, Y dan Z berpemberat-1 yang dijumlahkan merentas kedua-dua lapisan, dan setiap sisi menunjukkan kadar berpemberat-2 yang dipelajari; kadar 3e-4 bermaksud ralat itu berlaku pada kira-kira tiga daripada setiap 10,000 penggunaan lapisan tersebut.

from qiskit.providers.fake_provider import GenericBackendV2
from qiskit.quantum_info import PauliList
from qiskit_ibm_runtime.results import LayerError, PauliLindbladError
from qiskit_ibm_runtime.visualization.embeddings import Embedding
from qiskit_mitigation import PEA
from qiskit_noise_learning.aer_executor import AerExecutor
from qiskit_noise_learning.noise_learner import LearningOptions, NoiseLearner
from samplomatic import InjectNoise, Tag
from samplomatic.utils import get_annotation

backend = GenericBackendV2(
num_qubits=num_qubits,
basis_gates=["id", "rz", "sx", "x", "cz"],
coupling_map=ring_coupling,
)

task_pea = PEA()
# learn only the layers PEA will inject noise into, i.e. not the measurement layer
pea_layers = [
layer
for layer in task_pea.find_unique_layers(circuit, boxing_options)
if get_annotation(layer.operation, InjectNoise)
]

learning_options = LearningOptions(
fragment_depths=[2, 4, 8, 16],
num_randomizations=50,
shots_per_randomizations=64,
)
# qiskit-noise-learning is not compatible with the Executor in local mode,
# and requires the simulator present in the package for running simulation
noise_dict = {
get_annotation(layer.operation, Tag).ref: noise_layer
for layer, noise_layer in layer_noise_model
}
noise_learner_simulator = AerExecutor(
qasm_simulator=AerSimulator(), noise_dict=noise_dict
)
learner = NoiseLearner(
backend, options=learning_options, executor=noise_learner_simulator
)
learned_noise = (
learner.run(pea_layers).result().to_dict()
) # keyed by InjectNoise reference

# Draw the learned model on the ring, laid out as a square with the qubits in ring order.
# Composing the two layers' maps sums their rates, giving one map over all the ring's edges.
embedding = Embedding(
[(0, 0), (0, 2), (0, 4), (2, 4), (4, 4), (4, 2), (4, 0), (2, 0)],
ring_coupling,
)
first, second = learned_noise.values()
learned_model = first.compose(second).simplify()
error = PauliLindbladError(
PauliList(
learned_model.get_qubit_sparse_pauli_list_copy().to_pauli_list()
),
learned_model.rates,
)
fig = LayerError(circuit, list(range(num_qubits)), error).draw_map(
embedding, radius=0.4, height=460, width=620
)
fig.update_traces(
marker={
"cmin": 0,
"cmax": max(learned_model.rates),
"colorbar": {"tickformat": ".1e", "title": "rate"},
},
selector={"mode": "markers"},
)
fig.show()

Output of the previous code cell

Sediakan atur cara ZNE dengan penguatan ralat probabilistik dan sampel litar dengan skala hingar yang berbeza-beza​

Di sini anda akan menyediakan atur cara ZNE yang mengandungi litar dengan skala hingar yang semakin meningkat. Dengan PEA, setiap faktor hingar mewakili gandaan hingar yang dipelajari yang dialami litar: faktor hingar 2.0 menyuntik satu salinan tambahan saluran hingar yang dipelajari bagi setiap lapisan selepas lapisan itu, di atas hingar yang sedia ada pada lapisan tersebut. Oleh sebab PEA menskalakan kadar hingar yang dipelajari secara langsung dan bukannya mengulang gate, sebarang faktor hingar boleh digunakan, termasuk yang bukan integer, dan litar itu sendiri tidak diubah suai: item atur cara berkongsi satu litar templat dan hanya berbeza pada hingar yang disuntik oleh samplex. Hingar yang disuntik disampel sekali bagi setiap perawakan rawak, jadi ralat statistik PEA dikawal oleh bilangan perawakan rawak dan bukannya bilangan shot bagi setiap perawakan rawak; oleh itu kami menggunakan banyak perawakan rawak dengan beberapa shot sahaja bagi setiap satu, dengan mengekalkan jumlah shot yang sama seperti atur cara tanpa mitigasi. Adalah penting untuk tidak menggunakan terlalu sedikit perawakan rawak, jika tidak anda mungkin menghadapi bias persampelan dalam suntikan hingar.

Jumlah overhed persampelan meningkat secara linear dengan bilangan faktor hingar.

noise_factors = [1, 2, 3]
program_pea = task_pea.prepare(
circuit=circuit,
observables=observables,
parameters=parameter_values,
num_randomizations=200,
shots_per_randomization=16,
custom_boxing_options=boxing_options,
noise_maps=learned_noise,
noise_factors=noise_factors,
)

Akhir sekali, jalankan atur cara pada simulator berhingar. Keputusannya digunakan untuk ekstrapolasi pada langkah seterusnya.

program_pea._semantic_role = (
"simulation" # flag the program for the simulator
)
job_pea_results = noisy_executor.run(program_pea).result()

Ekstrapolasi kepada had hingar sifar​

Setelah anda mempunyai data bagi setiap skala hingar, anda boleh memadankan satu fungsi kepada data tersebut dan mengekstrapolasi kembali kepada nilai hingar sifar untuk menganggar nilai jangkaan bagi observable bebas hingar. Di bawah hingar Pauli, sesuatu observable mereput secara eksponen dengan faktor hingar, jadi anda akan memilih pengekstrapolasi eksponen sebagai pilihan pertama, dan beralih kepada yang linear jika padanan eksponen gagal. Untuk memvisualisasikan ekstrapolasi, plotkan magnetisasi purata tapak yang dikira pada setiap faktor hingar, padanan eksponen, dan purata tapak bagi nilai jangkaan terekstrapolasi pada titik hingar sifar. Kita melihat padanan itu sedikit kurang menganggar bagi observable tertentu ini.

from scipy.optimize import curve_fit

pea_mitigated_res = task_pea.postprocess(
job_pea_results, extrapolator=["exponential", "linear"]
)

# The result holds the expectation value at each noise factor and the extrapolated value for
# every observable; we average them over the sites and fit the same model to draw the curve.
angle = 3 # theta = 0.15 pi, the angle with the largest unmitigated error
amplifications = pea_mitigated_res.data.evs_noise_factors[:, angle, :].mean(
axis=0
)
x_fit = np.linspace(0, max(noise_factors), 51)
params, _ = curve_fit(
lambda x, a, b: a * np.exp(b * x),
noise_factors,
amplifications,
p0=[1.0, -0.1],
)

plt.plot(
noise_factors, amplifications, "o", color="red", label="amplifications"
)
plt.plot(
x_fit,
params[0] * np.exp(params[1] * x_fit),
"--",
color="black",
label="exponential fit",
)
plt.plot(
[0],
pea_mitigated_res.data.evs[:, angle].mean(),
"*",
color="black",
markersize=15,
label="extrapolation",
)
plt.plot(
[0],
exact_evs[:, angle].mean(),
"_",
color="red",
markersize=15,
markeredgewidth=3,
label="exact",
)
plt.xlabel("noise factor")
plt.ylabel(r"$\langle Z \rangle_{\text{avg}}$")
plt.legend()
plt.show()

Output of the previous code cell

Bandingkan nilai jangkaan yang dimitigasi​

Plotkan magnetisasi purata tapak bagi setiap kaedah merentas sapuan sudut putaran Ising. PEA memulihkan magnetisasi tepat dalam julat ralatnya, manakala keputusan tanpa mitigasi berbias jauh di bawahnya.

results = {
"Unmitigated": unmitigated_res,
"PEA": pea_mitigated_res,
}

fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(x_vals, exact_evs.mean(axis=0), "k-", label="Exact")
for label, res in results.items():
ax.errorbar(
x_vals,
np.mean(res.data.evs, axis=0),
np.mean(res.data.stds, axis=0),
fmt="o-",
label=label,
)
ax.set_xlabel(r"$\theta/\pi$")
ax.set_ylabel(r"$\langle Z \rangle_{\text{avg}}$")
ax.legend()
ax.set_title(
f"Error-Mitigated Magnetization [{num_qubits}-qubit, {trotter_steps} Trotter steps]"
)
plt.tight_layout()
plt.show()

Output of the previous code cell