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?

Tingkatkan nilai jangkaan dengan penyerapan hingar terpropagat (PNA)

Anggaran penggunaan: 10 minit pada pemproses Heron (NOTA: Ini hanyalah anggaran. Masa jalan anda mungkin berbeza.)

Hasil pembelajaran​

  • Apa itu penyerapan hingar terpropagat (PNA), dan bagaimana ia mengurangkan hingar Gate dua-Qubit dengan menyerap saluran hingar songsang yang dipelajari ke dalam boleh cerap yang diukur

  • Cara menggunakan samplomatic untuk mengkotak dan menganotasi lapisan litar untuk twirling, perubahan asas, dan suntikan hingar

  • Cara mempelajari hingar lapisan dengan [NoiseLearnerV3](/guides/directed-execution-model#noiselearnerv3) dan mempropagatkannya ke dalam pemerhati yang mengurangkan hingar dengan qiskit-addon-pna

  • Cara mempersampelkan litar rawak dengan kelas QuantumProgram dan Executor dalam qiskit-ibm-runtime, dan menggabungkan PNA dengan TREX dan pemilihan pasca

Prasyarat​

Latar belakang​

Dalam tutorial ini, kami menunjukkan cara memanfaatkan alat mitigasi ralat termaju dalam Qiskit untuk meningkatkan anggaran nilai jangkaan dalam eksperimen kuantum yang berhingar.

Apakah penyerapan hingar terpropagat (PNA)?​

Penyerapan hingar terpropagat ialah teknik untuk mengurangkan ralat get dengan mempropagatkan pemerhati melalui saluran hingar songsang yang menjejaskan get dua-qubit, menghasilkan pemerhati yang mengurangkan hingar.

Kita boleh menggunakan mitigasi ralat kuantum untuk mengekstrak nilai jangkaan yang berguna daripada perkakasan kuantum yang berhingar tanpa memerlukan toleransi kesalahan penuh. PNA secara khusus tertumpu kepada menyerap kesan hingar ke dalam pemerhati itu sendiri berbanding mengubah suai operasi litar.

Setiap get berhingar dalam litar kuantum boleh dimodelkan sebagai get ideal diikuti oleh saluran hingar. PNA mempelajari atau mencirikan saluran hingar ini dan mentakrifkan songsangannya. Berbanding memasukkan operasi songsang ke dalam pelaksanaan perkakasan (yang biasanya tidak boleh dilaksanakan), PNA mempropagatkan saluran hingar songsang ke hadapan melalui litar dan mengaplikasikannya pada pemerhati. Proses ini mengubah pemerhati OO menjadi operator baharu O~\tilde{O}, sedemikian rupa sehingga mengukur O~\tilde{O} pada litar berhingar menghasilkan nilai jangkaan yang sama seperti mengukur OO pada litar ideal yang bebas hingar.

Ini boleh dirumuskan sebagai:

  1. Modelkan setiap get berhingar uiu_i sebagai operasi ideal diikuti oleh saluran hingar Λi\Lambda_i.
  2. Pelajari atau anggarkan setiap Λi\Lambda_i menggunakan alat pencirian hingar.
  3. Takrifkan dan propagatkan peta hingar songsang Λi−1\Lambda_i^{-1} ke hadapan melalui litar menggunakan teknik pemindahan Pauli.
  4. Serap songsangan ini ke dalam pemerhati, menghasilkan operator O~\tilde{O} yang telah dikurangkan hingarnya.

Apabila hingar digambarkan sebagai saluran Pauli (atau secara lebih umum sebagai saluran Pauli-Lindblad jarang), propagasi ini boleh dilakukan dengan cekap menggunakan propagasi Pauli. Propagasi Pauli menyediakan rangka kerja untuk menghampiri bagaimana saluran hingar songsang berubah semasa melalui lapisan operasi Clifford dan bukan-Clifford, sambil mengawal kerumitan pengiraan.

Dengan mengalihkan mitigasi ke dalam pemerhati, PNA mengelakkan overhed pensampelan besar yang sebaliknya akan berlaku daripada memasukkan operasi pembetulan fizikal ke dalam litar. Sebaliknya, litar asal yang berhingar dilaksanakan, manakala pemerhati diubah menjadi operator baharu O~\tilde{O} yang nilai jangkaannya membatalkan kesan hingar.

Aliran kerja PNA​

Proses ini boleh difahami melalui peringkat konseptual berikut. Skematik pertama menggambarkan eksperimen berhingar yang standard.

Noisy experiment

Jika kita mempelajari model hingar, kita boleh mengaplikasikan songsangannya dan membatalkan hingar.

Noise-mitigated experiment

Berbanding melaksanakan saluran hingar songsang dengan mempersampelkannya pada QPU seperti dalam pembatalan ralat kebarangkalian (PEC), kita mengaplikasikannya secara klasik pada boleh cerap yang diukur menggunakan propagasi Pauli. Boleh cerap yang terhasil secara berkesan mengurangkan hingar get yang dipelajari apabila diukur.

PNA overview

Mitigasi ralat modular dengan Samplomatic dan Executor​

Pendekatan PNA dibina di atas seni bina mitigasi ralat modular dalam Qiskit. Seni bina ini menggunakan pustaka samplomatic bersama-sama kelas QuantumProgram dan Executor (ditambah kepada Qiskit Runtime dalam qiskit-ibm-runtime v0.47.0) untuk menjadikan teknik seperti penyerapan hingar terpropagat dan twirling Pauli boleh disusun dan digunakan semula merentas eksperimen berbeza.

Berbanding membenamkan logik mitigasi di dalam takrifan litar itu sendiri, mitigasi dinyatakan secara deklaratif melalui anotasi samplomatic dan diuruskan secara pengaturcaraan melalui Executor, yang mengawal bagaimana litar rawak dijana, dilaksanakan, dan diproses selepas itu.

Dalam tutorial ini kami melaksanakan corak Qiskit untuk menunjukkan bagaimana PNA boleh mempropagatkan saluran hingar Pauli songsang dan mengubah suai pemerhati mengikutnya, untuk meningkatkan anggaran nilai jangkaan pada QPU yang berhingar.

Gambaran keseluruhan aliran kerja​

  • Langkah 1: Memetakan kepada masalah kuantum

    • Bina model Ising terkejut Trotter yang dicerminkan dan pemerhati sasaran.
  • Langkah 2: Cirikan dan propagatkan hingar

    • Gunakan samplomatic untuk mengenal pasti dan menganotasi lapisan dua-qubit unik serta pengukuran dalam litar.

    • Pelajari hingar yang menjejaskan setiap lapisan unik menggunakan NoiseLearnerV3.

    • Petakan setiap anotasi InjectNoise kepada model hingar yang sepadan yang telah dipelajari.

    • Gunakan qiskit-addon-pna untuk mempropagatkan saluran hingar songsang ke hadapan melalui litar dan menyerapnya ke dalam pemerhati sasaran.

  • Langkah 3: Laksanakan eksperimen kuantum

    • Takrifkan QuantumProgram untuk menentukan pensampelan rawak melalui samplex dan laksanakan eksperimen pada backend menggunakan Executor.
  • Langkah 4: Bina semula dan analisis keputusan

    • Bandingkan strategi mitigasi (PNA, PNA+TREX, PNA+PS, PNA+PS+TREX) dan visualisasikan peningkatan berbanding keputusan yang tidak dimitigasi.

Keperluan​

Sebelum memulakan tutorial ini, pastikan anda telah memasang perkara berikut:

  • Qiskit SDK v2.2 atau lebih baharu, dengan sokongan visualisasi

  • Qiskit Runtime v0.47 atau lebih baharu (pip install qiskit-ibm-runtime)

  • Samplomatic v0.13 atau lebih baharu (pip install samplomatic)

  • Tambahan PNA Qiskit (pip install qiskit-addon-pna)

  • Utiliti tambahan Qiskit (pip install qiskit-addon-utils)

Persediaan​

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

_needed = {"matplotlib": "matplotlib", "numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_pna": "qiskit-addon-pna", "qiskit_addon_utils": "qiskit-addon-utils", "qiskit_ibm_runtime": "qiskit-ibm-runtime", "samplomatic": "samplomatic"}
_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")
from qiskit import QuantumCircuit
from qiskit.quantum_info import Pauli, SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager, PassManager
from qiskit_ibm_runtime import (
QiskitRuntimeService,
QuantumProgram,
Executor,
NoiseLearnerV3,
)
from qiskit_addon_utils.exp_vals.measurement_bases import (
get_measurement_bases,
)
from qiskit_addon_utils.exp_vals.expectation_values import (
executor_expectation_values,
)
from qiskit_addon_utils.noise_management import trex_factors
from qiskit_addon_utils.noise_management.post_selection import PostSelector
from qiskit_addon_utils.noise_management.post_selection.transpiler.passes import (
AddPostSelectionMeasures,
AddSpectatorMeasures,
)
from qiskit_addon_pna import generate_noise_mitigating_observable
import samplomatic
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic.annotations import InjectNoise
from samplomatic.utils import get_annotation, find_unique_box_instructions
import numpy as np
import matplotlib.pyplot as plt

# Selects a connected chain of low-error qubits on the target backend.
# The mirrored kicked-Ising circuit is a 1D chain, so we only need a line
# of connected physical qubits; the helper walks the backend's coupling map
# and grows a chain along the lowest-error two-qubit edges, so it works for
# any backend rather than relying on a hardcoded layout.
def find_qubit_chain(backend, length):
"""Find a connected chain of ``length`` physical qubits on ``backend``.

The chain is grown greedily along the lowest-error two-qubit edges, so it
favors better-performing qubits. Because the mirrored kicked-Ising circuit
is a 1D chain, a connected line is all we need.
"""
target = backend.target

# Identify the native two-qubit gate and build a per-edge error lookup.
two_qubit_gate = next(
name
for name in target.operation_names
if target[name]
and all(q is not None and len(q) == 2 for q in target[name])
)
edge_error = {
frozenset(qargs): (
1.0 if props is None or props.error is None else props.error
)
for qargs, props in target[two_qubit_gate].items()
}

graph = backend.coupling_map.graph.to_undirected(multigraph=False)
neighbors = {n: list(graph.neighbors(n)) for n in graph.node_indices()}

def first_chain_from(start):
path, visited = [start], {start}

def grow():
if len(path) == length:
return True
node = path[-1]
order = sorted(
neighbors[node],
key=lambda m: edge_error.get(frozenset((node, m)), 1.0),
)
for nxt in order:
if nxt not in visited:
visited.add(nxt)
path.append(nxt)
if grow():
return True
path.pop()
visited.remove(nxt)
return False

return path if grow() else None

def chain_cost(path):
return sum(
edge_error.get(frozenset((path[i], path[i + 1])), 1.0)
for i in range(len(path) - 1)
)

# Try low-degree qubits first (the natural ends of long chains) and keep
# the lowest-error chain found.
best_path, best_cost = None, float("inf")
for start in sorted(neighbors, key=lambda n: len(neighbors[n])):
chain = first_chain_from(start)
if chain is not None and (cost := chain_cost(chain)) < best_cost:
best_path, best_cost = chain, cost

if best_path is None:
raise ValueError(
f"Could not find a connected chain of {length} qubits "
f"on '{backend.name}'."
)
return best_path

Contoh penyelaku berskala kecil​

PNA mengurangkan hingar get dua-qubit fizikal bagi pemproses kuantum tertentu. Aliran kerja ini bergantung kepada dua perkhidmatan perkakasan yang tidak mempunyai analog bermakna pada penyelaku ideal:

  • NoiseLearnerV3 mencirikan secara eksperimen saluran hingar Pauli-Lindblad jarang yang terlekat pada setiap lapisan dua-qubit unik bagi litar yang telah ditranspilasi. Pada penyelaku bebas hingar, tiada hingar untuk dipelajari, dan saluran songsang yang dipropagatkan akan menjadi identiti.

  • Primitif Executor mempersampelkan litar rawak yang ditwirl, dijana oleh samplomatic pada backend.

Pada prinsipnya anda boleh menggantikan model hingar sintetik. Sebagai contoh, anda boleh melekatkan arahan PauliLindbladError dengan Qiskit Aer dan menghantar litar berhingar yang terhasil terus kepada generate_noise_mitigating_observable. Walau bagaimanapun, ini hanya mengesahkan pengurusan rekod klasik terhadap hingar yang anda sendiri suntikkan, dan mengaburkan tujuan teknik ini. Atas sebab itu kami melangkau contoh penyelaku dan menunjukkan aliran kerja PNA yang lengkap secara terus pada perkakasan, dengan setiap langkah corak Qiskit dipaparkan secara terperinci di bawah.

Contoh perkakasan berskala besar​

Kami kini menjalankan aliran kerja PNA yang lengkap pada model Ising terkejut 30-tapak yang dilaksanakan pada perkakasan IBM Quantum®, mengikuti empat langkah corak Qiskit.

Langkah 1: Memetakan kepada masalah kuantum​

Jana litar Trotter yang dicerminkan dan pemerhati

Untuk eksperimen ini, kami akan mengkaji dinamik masa model Ising terkejut 30-tapak pada rantai spin 1D. Hamiltonian yang dipertimbangkan ialah:

H=−J∑⟨i,j⟩ZiZj+h∑iXiH = -J\sum\limits_{\langle i,j \rangle} Z_iZ_j + h\sum\limits_iX_i,

di mana J>0J>0 menggambarkan gandingan spin jiran terdekat, i<ji<j, dan medan melintang global, hh, ditetapkan kepada π8\frac{\pi}{8}. Semakin jauh hh daripada sudut Clifford (iaitu, θ=nπ2,n∈Z\theta=n\frac{\pi}{2}, n \in \mathbb{Z}), semakin sukar untuk mempropagatkan penjana anti-hingar melalui litar.

Untuk pilihan pemerhati, kami akan mempertimbangkan purata magnetisasi tapak tunggal, 1N∑i=1N⟨zi⟩\frac{1}{N} \sum_{i=1}^{N} \langle z_i \rangle, di mana NN ialah bilangan tapak.

num_qubits = 30
num_trotter_steps = 10
rx_angle = np.pi / 8

# Avg single-site magnetization
id_pauli = Pauli("I" * num_qubits)
observable = (
SparsePauliOp([id_pauli.dot(Pauli("Z"), [i]) for i in range(num_qubits)])
/ num_qubits
)

# Implement Trotterized kicked-Ising model
circuit = QuantumCircuit(num_qubits)
for _step in range(num_trotter_steps):
circuit.rx(rx_angle, range(num_qubits))
for first_qubit in (1, 2):
for idx in range(first_qubit, num_qubits, 2):
# equivalent to Rzz(-pi/2):
circuit.sdg([idx - 1, idx])
circuit.cz(idx - 1, idx)
# Append the inverse circuit to complete the mirroring
circuit.compose(circuit.inverse(), inplace=True)
circuit.measure_active()
circuit.draw("mpl", fold=-1)

Output of the previous code cell

Langkah 2: Optimumkan masalah untuk pelaksanaan perkakasan​

Langkah seterusnya ialah menyediakan litar Trotter yang dicerminkan untuk pelaksanaan pada perkakasan IBM Quantum sebenar. Menjalankan pada QPU memerlukan lebih daripada sekadar membina litar abstrak, kerana kita perlu mengoptimumkannya supaya:

  1. Ia menghormati set get asli dan konektiviti backend. Transpilasi memetakan litar logik ke dalam litar ISA yang disokong oleh backend sasaran. Ini memastikan setiap interaksi get dan qubit boleh direalisasikan secara fizikal.

  2. Kita boleh mencirikan hingar pada peringkat lapisan litar. PNA bergantung kepada mempelajari dan mempropagatkan saluran hingar songsang. Untuk melakukan ini dengan cekap, kita memecahkan litar yang telah ditranspilasi kepada lapisan dua-qubit unik yang "dikotakkan". Kotak ini membolehkan kita mengaitkan setiap lapisan litar dengan model hingar yang telah dipelajari sendiri.

  3. Kita boleh memasukkan model hingar realistik ke dalam PNA. Sebaik sahaja litar telah dikotakkan, kita menggunakan perkhidmatan NoiseLearnerV3 untuk mempelajari secara eksperimen saluran hingar Pauli yang menjejaskan setiap lapisan dua-qubit unik. Model yang dipelajari ini kemudiannya dihubungkan semula kepada litar melalui anotasi Samplomatic.

Secara keseluruhan, langkah ini merapatkan jurang antara litar yang dicerminkan yang diidealkan dengan litar sedia-perkakasan dengan model hingar yang dipelajari. Dengan persediaan ini, PNA boleh mempropagatkan saluran hingar songsang melalui litar dan menyesuaikan pemerhati mengikutnya.

Sambung ke backend dan transpilasi kepada litar ISA​

Kami mula-mula memulakan IBM Quantum Compute Service dan memilih backend. Sahkan dengan akaun anda sendiri dengan mengikuti arahan untuk menyimpan kelayakan anda, selepas itu QiskitRuntimeService() akan mengambilnya secara automatik.

# Initialize IBM Quantum Compute Service using your saved credentials
service = QiskitRuntimeService()

backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=num_qubits
)
# Re-fetch with fractional gates enabled (least_busy does not forward this)
# Fractional gates are enabled so the non-Clifford Rx rotations are supported natively.
backend = service.backend(backend.name, use_fractional_gates=True)
print(f"Selected backend: {backend.name}")
Selected backend: ibm_fez

Seterusnya, kami memilih rantai qubit yang tersambung pada backend dan mentranspilasi litar ke atasnya.

Dengan menggunakan pembantu find_qubit_chain yang ditakrifkan dalam bahagian Persediaan, kami memilih satu barisan qubit fizikal num_qubits yang tersambung. Kami kemudian mentranspilasi dengan optimization_level=0 dan menetapkan rantai ini sebagai initial_layout, yang mengekalkan struktur lapisan get dua-qubit litar yang dicerminkan dengan tepat. Struktur itulah yang menjadi sandaran langkah pengotakan dan pembelajaran hingar, jadi tahap pengoptimuman yang lebih tinggi (yang akan membatalkan get yang dicerminkan) mesti dielakkan di sini.

# Find a connected, low-error chain of qubits on the chosen backend
layout = find_qubit_chain(backend, num_qubits)

# Transpile the circuit for the target backend, pinning the chain as the layout.
# optimization_level=0 preserves the mirrored two-qubit-gate layers that the
# boxing and noise-learning steps rely on.
pm = generate_preset_pass_manager(
backend=backend, optimization_level=0, initial_layout=layout
)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
isa_circuit.draw("mpl", fold=-1)

Output of the previous code cell

Twirl lapisan get dua-qubit dan pengukuran, serta cari lapisan unik​

Kami menggunakan samplomatic untuk mengotakkan litar dan mengenal pasti lapisan dua-qubit unik. Kotak ialah konstruk yang mengumpulkan arahan bersama supaya niat atau anotasi tertentu boleh diaplikasikan kemudian secara seragam kepada semua get dalam kotak yang sama.

Di sini, kami memanggil kaedah generate_boxing_pass_manager, yang melakukan lebih daripada sekadar mengenal pasti lapisan dua-qubit. Ia melaksanakan beberapa tugas utama:

  • Mengumpulkan semua lapisan dua-qubit dalam litar,

  • Mengaplikasikan anotasi Twirl dan ChangeBasis kepada lapisan tersebut,

  • Mengumpulkan operasi pengukuran ke dalam bahagian kotak mereka sendiri, dan

  • Mengaplikasikan anotasi InjectNoise kepada setiap lapisan dua-qubit.

Anotasi ini menentukan bagaimana hingar, perubahan asas, dan twirling dikendalikan sepanjang litar. Ia juga membentuk struktur yang digunakan kemudian untuk mempelajari dan mengurangkan hingar.

Pilihan konfigurasi utama ialah:

  • enable_gates/enable_measures: True: Kotakkan semua lapisan get dua-qubit dan pengukuran terminal. Get satu-qubit dibiarkan berpakaian di sebelah kiri dalam kotak.

  • measure_annotations: all: Sertakan anotasi Twirl dan ChangeBasis pada kotak pengukuran.

  • twirling_strategy: active: Twirl semua qubit aktif dalam setiap kotak yang mengandungi get keterikatan.

  • inject_noise_targets: gates: Tambah anotasi InjectNoise kepada semua kotak beranotasi Twirl yang mengandungi get keterikatan.

  • inject_noise_strategy: uniform_modification: Skalakan semua lapisan hingar secara setara merentas litar.

# Box up circuit with Twirl and InjectNoise annotations
pm = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
measure_annotations="all",
twirling_strategy="active",
inject_noise_targets="gates",
inject_noise_strategy="uniform_modification",
)
boxed_circuit = pm.run(isa_circuit)
draw_circ = QuantumCircuit(boxed_circuit.num_qubits)
draw_circ.append(boxed_circuit.data[0], qargs=boxed_circuit.data[0].qubits)
draw_circ.append(boxed_circuit.data[1], qargs=boxed_circuit.data[1].qubits)
draw_circ.draw("mpl", fold=-1, scale=0.3, idle_wires=False)

Output of the previous code cell

Jana litar templat dan samplex, yang menentukan bagaimana litar akan dipersampelkan.

Di sini kami juga menambah pengukuran penonton dan pemilihan pasca, yang diperlukan untuk melaksanakan pemilihan pasca pada sampel yang dikeluarkan daripada Executor.

# Build template circuit and samplex for later use with the "Executor"
template_circuit, samplex = samplomatic.build(boxed_circuit)

# Add post-selection instructions to the template circuit
post_selection_pm = PassManager(
[
AddSpectatorMeasures(backend.coupling_map),
AddPostSelectionMeasures(x_pulse_type="rx"),
]
)
template_circuit = post_selection_pm.run(template_circuit)
draw_circ = template_circuit.copy_empty_like()
draw_circ.data = template_circuit.data[:324]
draw_circ.draw("mpl", fold=-1, scale=0.3, idle_wires=False)

Output of the previous code cell

Pelajari hingar menggunakan NoiseLearnerV3​

Sebelum kita boleh mengaplikasikan PNA untuk mitigasi ralat, kita mula-mula perlu mencirikan hingar yang bertindak ke atas setiap lapisan dua-qubit unik dan lapisan pengukuran dalam litar kita. Untuk melakukan ini, kami menggunakan program NoiseLearnerV3 untuk mempelajari secara eksperimen model hingar bagi setiap lapisan yang dikenal pasti sebelum ini. Pempelajar melaksanakan eksperimen bergaya penanda aras yang menganggarkan saluran hingar yang menjejaskan setiap lapisan dan mengembalikan objek keputusan yang mengandungi model yang dipelajari.

Kami mulakan dengan mengenal pasti lapisan unik dalam litar kita menggunakan find_unique_box_instructions daripada samplomatic. Ini memastikan kita hanya mempelajari hingar sekali sahaja bagi setiap jenis lapisan yang berbeza, meminimumkan bilangan eksperimen dan kos tembakan keseluruhan. Senarai lapisan yang terhasil dihantar kepada pempelajar hingar.

Terdapat beberapa parameter utama yang mengawal bagaimana hingar dipelajari:

  • num_randomizations: Bilangan litar rawak yang digunakan bagi setiap konfigurasi pembelajaran.

  • shots_per_randomization: Bilangan tembakan yang diambil bagi setiap litar pembelajaran rawak.

  • layer_pair_depths: Kedalaman litar (diukur dalam bilangan pasangan) yang digunakan dalam eksperimen pembelajaran.

  • post_selection: Membolehkan pemilihan pasca berasaskan tepi menggunakan get rx untuk mengaplikasikan denyutan selepas pengukuran.

# Noise learning parameters
num_randomizations_nl = 64
shots_per_randomization_nl = 128

# Match the deepest noise-learning depth to the depth of the circuit being
# mitigated. ``layer_pair_depths`` are measured in layer pairs (a layer + its
# inverse), so the deepest value is half the circuits's two-qubit-layer depth.
# Learning to this depth improves the quality of the mitigation.

depth_2q = isa_circuit.depth(lambda instr: instr.operation.num_qubits == 2)
max_layer_pair_depth = depth_2q // 2

# Use a fixed schedule of learning depths, but drop any that exceed the circuit's
# depth and always cap the deepest value at ``max_layer_pair_depth`` so we never
# learn deeper than the circuit being mitigated
candidate_depths = [1, 2, 4, 8, 12, 16, 24, 32, 40, 48]
layer_pair_depths = sorted(
{d for d in candidate_depths if d < max_layer_pair_depth}
| {max_layer_pair_depth}
)

# Find the unique instructions (layers) from the boxed-up circuit
unique_2q_layers_and_meas = find_unique_box_instructions(
boxed_circuit, normalize_annotations=None, undress_boxes=True
)

# Configure and run the noise learner on the unique layers.
# Options can be passed directly as a dictionary.
noise_learner_options = {
"num_randomizations": num_randomizations_nl,
"shots_per_randomization": shots_per_randomization_nl,
"layer_pair_depths": layer_pair_depths,
"post_selection": {
"enable": True,
"strategy": "edge",
"x_pulse_type": "rx",
},
"environment": {"job_tags": ["TUT_PNA"]},
}

noise_learner = NoiseLearnerV3(backend, noise_learner_options)
noise_learner_job = noise_learner.run(unique_2q_layers_and_meas)
noise_learner_result = noise_learner_job.result()

Visualisasikan kadar hingar yang dipelajari​

Selepas mempelajari model hingar, kita boleh menyemak taburan kadar ralat yang disimpulkan bagi kedua-dua operasi satu-qubit dan dua-qubit. Kod di bawah mengekstrak perwakilan Pauli-Lindblad daripada keputusan hingar yang dipelajari dan mengumpulkan kadar hingar yang berkaitan.

Bagi setiap lapisan yang dipelajari:

  • Kita menukar model hingar kepada senarai jarang tuple (pstr, qubits, rate), di mana pstr ialah rentetan Pauli yang bertindak ke atas qubit tertentu dan rate ialah kadar ralat yang berkaitan.
  • Kita mengasingkan kadar tersebut kepada terma satu-qubit (len(pstr) == 1) dan dua-qubit (len(pstr) == 2).
  • Senarai kadar tersebut kemudian diisih, dan nilai medannya dikira.

Kami memplot taburan kadar hingar satu-qubit (merah) dan dua-qubit (biru) pada skala logaritma, dengan nilai median masing-masing ditandakan dengan garis menegak, supaya kita boleh membandingkan magnitud relatif penjana Pauli-Lindblad yang dipelajari. Susunan kadar satu- dan dua-qubit bergantung kepada peranti dan lapisan khusus yang dicirikan; dalam jalanan ini, penjana satu-qubit (berat-1) membawa kadar median yang lebih besar.

hw_rates_1q = []
hw_rates_2q = []
for nlr in noise_learner_result[:2]:
plm_list = nlr.to_pauli_lindblad_map().to_sparse_list()
hw_rates_1q += [
rate for (pstr, qubits, rate) in plm_list if len(pstr) == 1
]
hw_rates_2q += [
rate for (pstr, qubits, rate) in plm_list if len(pstr) == 2
]
hw_rates_1q = sorted(hw_rates_1q)
hw_rates_2q = sorted(hw_rates_2q)
median_1q = hw_rates_1q[len(hw_rates_1q) // 2]
median_2q = hw_rates_2q[len(hw_rates_2q) // 2]
fig, ax = plt.subplots(1, 1, figsize=(14, 5))
ax.scatter(
(hw_rates_1q),
[(i) / (len(hw_rates_1q) - 1) for i in range(len(hw_rates_1q))],
color="red",
label="1q rates",
)
ax.set_xscale("log")
ax.set_ylim(0, 1.1)
ax.vlines(median_1q, 0, 1, color="red")
ax.text(median_1q * 1.1, 0.1, f"{median_1q:.2e}")
ax.scatter(
(hw_rates_2q),
[(i) / (len(hw_rates_2q) - 1) for i in range(len(hw_rates_2q))],
color="blue",
label="2q rates",
)
ax.set_xscale("log")
ax.set_ylim(0, 1.1)
ax.vlines(median_2q, 0, 1, color="blue")
ax.text(median_2q * 1.1, 0.2, f"{median_2q:.2e}")
ax.set_title("Learned noise rates")
ax.set_xlabel("Noise rate")
ax.set_yticks([])
plt.legend()
<matplotlib.legend.Legend at 0x125336120>

Output of the previous code cell

Kaitkan kotak litar dengan hingar yang dipelajari​

Sebaik sahaja kita mendapat model hingar bagi setiap lapisan dua-qubit unik, kita perlu menghubungkannya kepada anotasi InjectNoise yang sepadan dalam litar yang telah dikotakkan.

Arahan InjectNoise ialah anotasi samplomatic yang menggunakan dresser satu-qubit untuk menyuntik hingar ke dalam litar dengan cara yang terkawal dan boleh dikonfigurasikan. Ia membolehkan pemodelan hingar modular merentas lapisan berbeza.

Setiap anotasi InjectNoise termasuk:

  • InjectNoise.ref - pengecam unik bagi anotasi tersebut. Ini digunakan oleh objek samplex untuk menetapkan model hingar yang sepadan dengan betul.
  • InjectNoise.modifier_ref (pilihan) - rujukan sekunder yang membolehkan penskalaan model hingar yang ditetapkan dengan faktor pendaraban.

Dalam langkah ini, kami membina pemetaan daripada setiap InjectNoise.ref kepada model hingar yang sepadan yang telah dipelajari (PauliLindbladMap). Pemetaan ini memastikan setiap lapisan get keterikatan dalam litar dipadankan dengan model hingar yang sesuai, supaya kesan hingar diaplikasikan dengan tepat semasa pensampelan dan langkah mitigasi hingar seterusnya.

# map inject noise refs to pauli lindblad maps
refs_to_noise_models = {}
for instruction, result in zip(
unique_2q_layers_and_meas, noise_learner_result, strict=False
):
if inject_noise_annot := get_annotation(
instruction.operation, InjectNoise
):
refs_to_noise_models[inject_noise_annot.ref] = (
result.to_pauli_lindblad_map()
)

Propagatkan pemerhati melalui anti-hingar yang dipelajari​

Seperti yang dibincangkan di atas, ini dilakukan dalam dua langkah. Pertama, kita mempropagatkan penjana anti-hingar ke penghujung litar. Selepas itu, kita mempropagatkan pemerhati melalui penjana yang telah berkembang itu. Proses ini diulang bagi setiap penjana anti-hingar dalam litar. Dalam pelaksanaan ini, setiap penjana dalam lapisan tertentu dipropagatkan ke penghujung litar secara selari. Selain itu, pemprosesan berbilang Python digunakan untuk melaksanakan kedua-dua propagasi ke hadapan bagi anti-hingar serta propagasi ke belakang bagi pemerhati secara selari. Ini mengelakkan longgokan penjana yang telah berkembang dalam memori dan juga memaksimumkan sumber pengiraan.

Apabila menjalankan PNA, anda sentiasa perlu menyediakan litar dan pemerhati yang berhingar. Jika litar berhingar anda ialah litar berkotak dengan anotasi InjectNoise, anda perlu menyediakan pemetaan yang kita cipta dalam langkah di atas. Anda juga boleh menghantar litar yang tidak berkotak yang mengandungi arahan PauliLindbladError daripada qiskit-aer. Dalam kes itu, refs_to_noise_models tidak perlu disediakan. Selain input utama, pertimbangkan juga perkara berikut:

  • max_err_terms: Bilangan terma yang dikekalkan dalam setiap penjana anti-hingar semasa ia dipropagatkan ke hadapan. Membenarkan ini menjadi lebih besar secara amnya meningkatkan ketepatan, tetapi tingkah laku ini tidak dijamin monoton.

  • max_obs_terms: Bilangan terma yang dikekalkan dalam pemerhati yang mengurangkan hingar, O~\tilde{O}, semasa ia dipropagatkan ke belakang melalui anti-hingar yang telah berkembang. Nilai yang lebih besar secara amnya meningkatkan ketepatan, tetapi ia tidak dijamin melakukannya secara monoton.

  • num_processes: Bilangan teras yang diperuntukkan kepada proses tersebut. Ingat, penjana dipropagatkan ke hadapan dan diaplikasikan kepada pemerhati secara selari.

  • search_step: Langkah propagasi ke belakang menggunakan kaedah tamak untuk menghampiri konjugasi dua operator dalam asas Pauli. Kaedah ini boleh dipercepatkan dengan meningkatkan search_step. Lihat dokumentasi pauli-prop untuk maklumat lanjut.

  • num_to_measure: Walaupun pemboleh ubah ini bukan input kepada generate_noise_mitigating_observable, kami menggunakannya untuk mengawal berapa banyak terma daripada O~\tilde{O} yang sebenarnya ingin kita ukur. Di sini kami hanya mengukur 30 terma teratas, yang merupakan terma asal dalam pemerhati kita. Terma-terma ini kini telah diskalakan semula sedemikian rupa sehingga mengukurnya mempunyai kesan mengurangkan hingar get yang dipelajari. Walaupun kami hanya mengukur 30 terma daripada O~\tilde{O}, ia selalunya masih berguna untuk membenarkannya berkembang besar, kerana itu meningkatkan ketepatan faktor penskalaan terma-terma utama.

# PNA parameters
num_processes = 8
max_err_terms = 10_000
max_obs_terms = 10_000
num_to_measure = num_qubits

obs_tilde_isa = generate_noise_mitigating_observable(
boxed_circuit,
isa_observable,
refs_to_noise_models,
max_err_terms=max_err_terms,
max_obs_terms=max_obs_terms,
num_processes=num_processes,
print_progress=True,
search_step=8,
)
p_2_v = {p: v for v, p in enumerate(layout)}
obs_tilde_virtual = SparsePauliOp.from_sparse_list(
[
(pstr, [p_2_v[p] for p in p_qubits], coeff)
for (pstr, p_qubits, coeff) in obs_tilde_isa.to_sparse_list()
],
num_qubits=num_qubits,
)
obs_tilde_virtual = obs_tilde_virtual[
np.argsort(np.abs(obs_tilde_virtual.coeffs))[::-1]
][:num_to_measure]
Finished! 13740 / 13740 generators propagated.
obs_tilde_isa = obs_tilde_isa[np.argsort(np.abs(obs_tilde_isa.coeffs))][::-1]
plt.xscale("log")
plt.yscale("log")
plt.title(r"$\tilde{O}$ coeff magnitudes")
plt.ylabel("Magnitude")
plt.xlabel("Pauli term index")
plt.plot(np.abs(obs_tilde_isa.coeffs), ".")
[<matplotlib.lines.Line2D at 0x124b0a120>]

Output of the previous code cell

Ubah asas pengukuran kepada bentuk kanonik​

Seterusnya, kami mencari set asas minimum untuk diukur supaya kita boleh meliputi sepenuhnya setiap terma Pauli dalam boleh cerap yang diukur (banyak boleh cerap boleh diukur secara serentak jika ia berkomut secara qubit-wise). Memandangkan kita hanya mengukur terma dalam boleh cerap asal kita, iaitu jumlah semua Pauli-Z tunggal, hanya satu asas diperlukan: asas semua-Z.

Selain mencari set asas pengukuran Pauli, kita perlu memetakan terma Pauli ini kepada bentuk kanonik yang dijangkakan oleh Executor. Untuk maklumat lanjut mengenai penyusunan qubit kanonik, lawati dokumentasi Samplomatic.

meas_box = boxed_circuit.data[-1]
canonical_qubits = [
idx
for idx, qubit in enumerate(boxed_circuit.qubits)
if qubit in meas_box.qubits
]
c_2_p = {
c: p for c, p in enumerate(canonical_qubits)
} # canonical -> physical
p_2_v = {p: v for v, p in enumerate(layout)} # physical -> virtual
c_2_v = {c: p_2_v[p] for c, p in c_2_p.items()} # canonical -> virtual
meas_bases, bases_reverser = get_measurement_bases(obs_tilde_virtual)
meas_bases_canonical = [
np.array([base[c_2_v[c]] for c in range(num_qubits)], dtype=np.uint8)
for base in meas_bases
]

Langkah 3: Laksanakan eksperimen kuantum​

Nyatakan cara mempersampelkan dalam QuantumProgram​

Kami kini menyediakan QuantumProgram, yang berfungsi sebagai bekas pusat bagi semua litar dan konfigurasi pensampelan yang akan dilaksanakan oleh Executor. Objek ini menentukan bagaimana instans litar rawak dijana, dikelompokkan, dan dilaksanakan untuk menghasilkan keputusan pengukuran yang digunakan dalam PNA.

QuantumProgram boleh mengandungi berbilang item, masing-masing terdiri daripada litar templat dan objek samplex yang sepadan yang menentukan bagaimana rawakan diaplikasikan. Abstraksi ini membolehkan Executor mengendalikan keseluruhan aliran kerja sebagai satu program modular tunggal — daripada penjanaan litar rawak sehingga pengumpulan dan pengagregatan tembakan.

Dalam langkah ini, kami mencipta QuantumProgram yang menjalankan eksperimen PNA kami menggunakan litar templat dan samplex yang kami bina sebelum ini. Konfigurasi ini termasuk elemen berikut:

  • template_circuit: Litar yang mengandungi semua get yang diperlukan untuk melaksanakan semua rawakan yang dikehendaki (daripada rawakan twirling, parameter, dan sebagainya).

  • samplex: Objek yang menentukan taburan kebarangkalian ke atas semua kemungkinan rawakan litar untuk dipersampelkan.

  • samplex_arguments: Binding yang diperlukan untuk mentakrifkan samplex sepenuhnya

    • basis_changes: Di sinilah kita menentukan set asas untuk diukur yang akan meliputi semua terma Pauli dalam boleh cerap yang diukur.

    • noise_scales.ref: Kita tetapkan skala setiap lapisan hingar kepada 0.0 untuk mengelakkan sebarang hingar tambahan daripada disuntik ke dalam sampel kita.

    • pauli_lindblad_maps: Diperlukan jika noise_scales dihantar. Ini hanya memetakan lapisan hingar kepada model hingar yang berkaitan.

  • shape: Tuple bentuk untuk memperluaskan bentuk implisit yang ditakrifkan oleh samplex_arguments. Paksi tidak remeh yang diperkenalkan oleh perluasan ini menyenaraikan rawakan.

# Control the # of shots during execution
shots_per_randomization_exec = 64
num_randomizations_exec = 6144

# Zero out the noise to prevent noise from being injected during execution.
# We only added InjectNoise annotations so PNA could associate the noise
# to layers in the circuit
samplex_inputs = {f"noise_scales.{ref}": 0.0 for ref in refs_to_noise_models}
samplex_inputs |= {"pauli_lindblad_maps": refs_to_noise_models}

# Specify the bases to measure. The samplex exposes one basis-change input per
# ChangeBasis-annotated box; here a single all-Z basis covers every term. We
# look up the basis-change interface name rather than hardcoding an index, since
# the name depends on the circuit's box structure.
bases_broadcastable = np.expand_dims(np.array(meas_bases_canonical), axis=1)
samplex_inputs |= {
spec.name: bases_broadcastable
for spec in samplex.inputs().get_specs(r"^basis_changes\.")
}

# Convert samplex_inputs into a dict to pass to QuantumProgram
samplex_arguments = (
samplex.inputs().make_broadcastable().bind(**samplex_inputs)
)

# Instantiate the QuantumProgram with the specified parameters
program = QuantumProgram(shots=shots_per_randomization_exec)
program.append_samplex_item(
circuit=template_circuit,
samplex=samplex,
samplex_arguments=samplex_arguments,
shape=(num_randomizations_exec,),
)

Sampelkan litar menggunakan Executor​

Sekarang kita telah mentakrifkan QuantumProgram kita, melaksanakan eksperimen adalah mudah. Kita hanya perlu mencipta instans objek Executor, menyediakan backend kepadanya, dan menjalankan program tersebut.

# Execute (sample) the circuit
executor = Executor(backend)
job_exec = executor.run(program)
exec_results = job_exec.result()

Langkah 4: Bina semula dan analisis keputusan​

Untuk mengira nilai jangkaan yang dikurangkan ralatnya, kita lakukan yang berikut:

  • Kira faktor penskalaan TREX berdasarkan hingar yang dipelajari yang menjejaskan pengukuran,

  • Jana mask untuk mengekalkan hanya sampel yang telah dipilih-pasca, dan

  • Gunakan fungsi executor_expectation_values daripada qiskit-addon-utils untuk menggabungkan semua data menjadi nilai jangkaan yang dikurangkan ralatnya.

# Computing the TREX factors
measurement_noise_map = noise_learner_result[2].to_pauli_lindblad_map()
trex_rescale_factors = trex_factors(measurement_noise_map, bases_reverser)

# Post-select the results
post_selector = PostSelector.from_circuit(
circuit=template_circuit, coupling_map=backend.coupling_map
)

# Compute the ps mask for filtering results
mask = post_selector.compute_mask(exec_results[0], strategy="edge")

# Compute expvals using post selected results
results = executor_expectation_values(
exec_results[0]["meas"],
bases_reverser,
meas_basis_axis=0,
avg_axis=1,
measurement_flips=exec_results[0]["measurement_flips.meas"],
pauli_signs=exec_results[0].get("pauli_signs", None),
postselect_mask=mask,
rescale_factors=trex_rescale_factors,
)

Bandingkan strategi mitigasi: PNA, PNA+TREX, PNA+PS, PNA+PS+TREX​

Kita kira dan visualisasikan nilai jangkaan untuk beberapa varian mitigasi menggunakan keputusan Executor.

bases_reverser_unmit = {Pauli("Z" * num_qubits): [observable]}
args = [
(bases_reverser_unmit, None, None),
(bases_reverser, None, None),
(bases_reverser, None, trex_rescale_factors),
(bases_reverser, mask, None),
(bases_reverser, mask, trex_rescale_factors),
]

evs = []
for reverser, postsel_mask, factors in args:
# Compute expvals using post selected results
res_ps = executor_expectation_values(
exec_results[0]["meas"],
reverser,
meas_basis_axis=0,
avg_axis=1,
measurement_flips=exec_results[0]["measurement_flips.meas"],
pauli_signs=exec_results[0].get("pauli_signs", None),
postselect_mask=postsel_mask,
rescale_factors=factors,
)
res_ps = np.array(res_ps)
evs.append(res_ps[:, 0][0])

experiments = ["PNA", "PNA+TREX", "PNA+PS", "PNA+PS+TREX"]
colors = ["#d9d9d9", "#b0b0b0", "#7f7f7f", "#4c4c4c"]
plt.bar(experiments, evs[1:], color=colors)
plt.axhline(y=1, color="green", linestyle="--", linewidth=2, label="Ideal")
plt.axhline(
y=evs[0], color="red", linestyle="--", linewidth=2, label="Unmitigated"
)
plt.ylabel("Expectation value", fontsize=14)

plt.title(
r"30q Mirrored Ising, 10 Trotter steps, $\theta_{rx}=\frac{\pi}{8}$",
fontsize=14,
)
plt.legend(loc="upper left", bbox_to_anchor=(1.05, 1), borderaxespad=0.0)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

Output of the previous code cell

Keputusan menunjukkan faedah kumulatif menggabungkan pelbagai teknik mitigasi ralat. Pendekatan PNA biasa sudah pun memulihkan nilai jangkaan hampir kepada penanda aras ideal, menunjukkan bahawa mempropagatkan saluran hingar songsang ke dalam pemerhati berkesan mengimbangi ralat get dua-qubit.

  • Menambah pemberatan semula TREX (PNA+TREX) sedikit meningkatkan anggaran dengan membetulkan ketidakseimbangan persampelan dalam litar rawak.

  • Pemilihan-pasca (PNA+PS) memberikan peningkatan yang lebih ketara dengan menapis keluar hasil pengukuran yang tidak konsisten yang berkemungkinan disebabkan oleh ralat baki.

  • Akhirnya, menggabungkan kedua-duanya (PNA+PS+TREX) menghasilkan keputusan yang paling tepat, hampir menyamai nilai ideal, menunjukkan bagaimana strategi mitigasi ini saling mengukuhkan.

Secara keseluruhannya, perbandingan ini menyerlahkan bahawa PNA berfungsi sebagai asas yang kukuh untuk anggaran nilai jangkaan sedar-hingar, manakala TREX dan pemilihan-pasca menawarkan penambahbaikan pelengkap untuk peningkatan ketepatan selanjutnya.

Langkah seterusnya​

Jika anda mendapati kerja ini menarik, anda mungkin berminat dengan bahan berikut: