Lumaktaw sa pangunahing nilalaman
Ang proyektong ito ay nasa beta. Nakakita ng bug? Mag-bukas ng GitHub issue. May tanong o ideya? Magtanong sa Discussions — gusto naming marinig ang iyong feedback!
Gaano kaganda ang kalidad ng pagsasalin sa pahinang ito?

PEC na may SLC

Ang Probabilistic error cancellation (PEC) ay isang teknik para bawasan ang quantum noise sa mga kalkulasyon ng observable expectation value. Pinapahintulutan ka nitong makakuha ng unbiased na tantiya ng mga expectation value. Gumagana ang teknik na ito sa pagpapatakbo ng isang ensemble ng mga noisy na circuit na may inject na inverse ng isang natutunang noise model. Ang noise model ay tinatantiya pagkatapos bilang isang Pauli channel gamit ang Pauli twirling (kilala rin bilang randomized compiling). Ang ganitong mga noise model ay mahusay na matututunan at maaaring ma-mitigate gamit ang PEC (tingnan ang Probabilistic error cancellation with sparse Pauli-Lindblad models on noisy quantum processors para sa higit pang detalye).

Nangangailangan ang PEC ng exponential na shot overhead para makakuha ng unbiased na tantiya. Ang Shaded Lightcones (SLC) ay isang teknik na gumagamit ng mga classical na resource para i-bound ang sensitivity sa mga error sa buong circuit. Gamit ang mga bound na ito, maaaring kontroladong i-tune ng user ang bias sa pagtantiya ng observable.

Shaded Lightcones

Ipinapakita ng gabay na ito kung paano gamitin ang PEC kasama ng SLC para bawasan ang gate noise nang may mas mababang shot overhead kumpara sa vanilla PEC.

Ganito ang workflow:

  1. Tukuyin ang isang circuit at observable.
  2. Kalkulahin ang mga noisy, unmitigated na expectation value.
  3. Kalkulahin ang forward at backward na mga bound sa bias.
  4. Alamin ang noise ng mga entangling layer gamit ang qiskit-noise-learning.
  5. Gamitin ang natutunang noise para pagsamahin ang mga kinalkulang bound sa isang local scales matrix.
  6. Piliin ang nais na bias bound batay sa trade-off ng shot overhead at bias.
  7. Maghanda ng PEC + SLC program, patakbuhin ang programa, at mag-post-process.
  8. Ihambing ang mga mitigated na expectation value at shot overhead.

Tukuyin ang isang circuit at observable​

Maghanda ng mirror circuit ng Trotterized na time evolution ng isang 1D Ising chain Hamiltonian sa walong qubit. I-mirror ang circuit para kanselahin ang unitary nito at bumuo ng identity circuit, kaya alam nang 1 ang ideal na expectation value ng bawat observable nang hindi na kailangang kalkulahin. Bukod dito, dinodoble ng mirroring ang circuit depth, na dinodoble rin ang epekto ng noise.

Gamitin ang anggulong θ=π4\theta= \frac{\pi}{4} para maging non-Clifford ang dynamics.

# 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_slc": "qiskit-addon-slc", "qiskit_aer": "qiskit-aer", "qiskit_ibm_runtime": "qiskit-ibm-runtime", "qiskit_mitigation": "qiskit-mitigation", "qiskit_noise_learning": "qiskit-noise-learning", "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")
import warnings

import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit_mitigation.utils import get_measurement_bases

warnings.filterwarnings("ignore")

def construct_ising_circuit(
num_qubits: int,
num_trotter_steps: int,
rx_angle: float,
) -> QuantumCircuit:
circuit = QuantumCircuit(num_qubits)

for _ 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)

return circuit

def prepare_basis(
circuit: QuantumCircuit, basis: list[int]
) -> QuantumCircuit:
# basis is a list of integer values from 0 to 3. These map to the basis measurement as:
# 0 = I; 1 = Z; 2 = X; 3 = Y
assert len(basis) == circuit.num_qubits

out_circ = circuit.copy_empty_like()
for qb, bas in enumerate(basis):
if bas == 2:
out_circ.h(qb)
elif bas == 3:
out_circ.rx(-np.pi / 2, qb)

out_circ.barrier()
out_circ.compose(circuit, inplace=True)
return out_circ

def mirror_circuit(circuit: QuantumCircuit) -> QuantumCircuit:
mirror_circ = circuit.copy_empty_like()
mirror_circ.compose(circuit.inverse(), inplace=True)
mirror_circ.barrier()
mirror_circ.compose(circuit, inplace=True)
mirror_circ.measure_active()
return mirror_circ

# define observables
num_qubits = 8 # Width of the Ising chain
# The observable to measure: one X component (on qubit 2) and one Z component (on qubit 5)
target_obs_sparse = [("XZ", [2, 5], 1.0)]
observable = SparsePauliOp.from_sparse_list(
target_obs_sparse, num_qubits=num_qubits
)

# Determine the measurement basis each qubit requires for this observable.
bases, _ = get_measurement_bases(observable)

# Instantiate the mirrored circuit and prepend the basis-preparation gates
num_trotter_steps = 6
rx_angle = np.pi / 4
circuit = construct_ising_circuit(num_qubits, num_trotter_steps, rx_angle)
mirrored_circuit = mirror_circuit(circuit)
mirrored_circuit = prepare_basis(mirrored_circuit, bases[0])
print("Visualization of 1 mirrored Trotter step")
prepare_basis(
mirror_circuit(construct_ising_circuit(num_qubits, 1, rx_angle)), bases[0]
).draw("mpl", scale=0.6, fold=-1)
Visualization of 1 mirrored Trotter step

Output of the previous code cell

Kalkulahin ang mga noisy, unmitigated na expectation value​

Ang QuantumProgram ay naglalaman ng isang quantum circuit at isang samplex sa format na angkop para sa Executor primitive. Binubuo ng MitigationTask.prepare ang isang QuantumProgram mula sa circuit, mga observable at mga parameter value, at ibinabox ang circuit gamit ang ibinigay na mga boxing option. Itakda ang boxing option na measure_annotations sa "change_basis" para i-rotate ang mga measurement sa kinakailangang mga basis, at idagdag ang add_tags: "unique_box" para maimapa ng simulator ang isang noise model sa mga box ng circuit. Pauli twirled ang programa bilang default, na sa hardware ay ginagawang Pauli noise ang coherent noise na ipinapalagay ng mga paraan ng mitigation. Itinatakda ng num_randomizations kung ilang twirled na instance ng bawat circuit ang sina-sample at itinatakda ng shots_per_randomization kung ilang shot ang natatanggap ng bawat instance, kaya ang kanilang produkto ang shot limit bawat circuit.

Kung may access ka sa QPU, maaari mong patakbuhin ang programa gamit ang Executor na binuo mula sa isang backend ng QiskitRuntimeService. Gumagamit ang halimbawang ito ng AerSimulator para patakbuhin ang programa nang lokal. Ang simulator option nitong layer_noise_model ay nag-i-inject ng noise mula sa isang ibinigay na Pauli-Lindblad noise model sa bawat layer ng entangling gates. Dito, bumubuo tayo ng random na Pauli-Lindblad noise model na may error per layered gate (EPLG) na 0.01, halos isang order of magnitude na mas mataas kaysa sa tipikal na kasalukuyang Heron QPU, para palakihin ang epekto ng paggamit ng SLC kahit sa maliit na problema.

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
from samplomatic import Tag
from samplomatic.utils import get_annotation

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 = 400
shots_per_randomization = 16

boxing_options = {"add_tags": "unique_box"}

# find the unique layers to generate the layered noise for
box_layers = find_combined_unique_layers(
[mirrored_circuit], custom_boxing_options=boxing_options
)
layer_noise_model = generate_random_pauli_lindblad_noise(
box_layers, num_qubits, eplg=1e-2, 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=mirrored_circuit,
observables=observable,
parameters=None,
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
job_unmit_res = noisy_executor.run(program).result()
unmitigated_res = task.postprocess(job_unmit_res)

print(f"unmitigated result: {unmitigated_res.data.evs[0]}")
unmitigated result: 0.63125

Kalkulahin ang forward at backward na mga bound sa bias​

Bago gumugol ng anumang oras ng QPU sa noise learning, gumagamit ang SLC ng classical simulation para i-bound ang kontribusyon ng bawat posibleng error sa bias ng observable. Ginagawa ito sa dalawang magkatuwang na pass:

  • Forward propagation: ipinapakalat pasulong ang bawat Pauli error sa natitirang bahagi ng circuit at sinusuri ang commutator nito sa observable. Ang error na anti-commute sa observable ang tanging uri na maaaring magdulot ng bias sa resulta, kaya nagbibigay ang pass na ito ng upper bound sa forward impact ng bawat error.

  • Backward propagation: ipinapakalat paurong ang bawat error hanggang sa simula ng circuit at sinusuri ang commutator nito sa initial state. Dahil nagsisimula ang circuit sa all-zero state, ang mga error na nag-commute rito ay hindi makakaapekto sa kalalabasan, kaya humihigpit ang bound mula sa kabilang direksyon.

Magkasamang bumubuo ang dalawang bound ng mahigpit na bracket sa paligid ng worst-case na kontribusyon ng bawat error sa bias. Sa susunod na hakbang, pinagsasama ang mga bound na ito sa mga natutunang noise rate para i-rank kung aling mga error ang sulit itama at alin ang ligtas na iwan. Kailangan dito ang boxing option na inject_noise_strategy="individual_modification" para ang bawat InjectNoise annotation sa naka-box na circuit ay may natatanging identity kung saan maiuugnay ang mga SLC bound.

Para sa mas malalaking problema, maaaring mangailangan ang mga kalkulasyong ito ng malaking classical na computational resource.

from qiskit_addon_slc.bounds import (
compute_backward_bounds,
compute_forward_bounds,
tighten_with_speed_limit,
)
from qiskit_mitigation import PEC

slc_boxing_options = {
"add_tags": "unique_box",
"inject_noise_strategy": "individual_modification",
}

slc_pec_task = PEC()

boxed_circuit, noise_model_paulis = (
slc_pec_task.generate_slc_bounds_computation_input(
mirrored_circuit, custom_boxing_options=slc_boxing_options
)
)

forward_bounds = compute_forward_bounds(
boxed_circuit, noise_model_paulis, observable
)
tighten_forward_bounds = tighten_with_speed_limit(
forward_bounds, boxed_circuit, noise_model_paulis, observable
)
backward_bounds = compute_backward_bounds(boxed_circuit, noise_model_paulis)

Alamin ang noise ng mga entangling layer​

Para makalkula ang pinal na pagtantiya kung gaano naaapektuhan ng bawat error ang bias ng expectation value, pati kung gaano kamahal itong itama, inaalam natin ang mga noise rate at inilalapat ang mga ito sa mga tinatayang noise bound na kinalkula natin kanina.

Ipinapalagay ng PEC (pati ng PEC+SLC) ang twirled na noise model ng bawat layer ng entangling gates sa circuit. Kung ipinapalagay mo ang Markovian na noise model, ipinapalagay na hindi naaapektuhan ng depth ng circuit ang noise channel ng isang entangling layer. Kaya, ang noise model lang ng bawat natatanging layer ng entangling gates ang kailangang matutunan. Ang circuit na ginamit sa gabay na ito ay maaaring hatiin sa dalawang natatanging layer. Mahalagang idisenyo ang mga circuit na may pinakamaliit na set ng natatanging entangling layer kung gusto mong matutunan ang isang noise model, dahil kailangang matutunan nang hiwalay ang mga natatanging layer. Kung masyadong marami ang natatanging layer sa circuit mo, maaaring maging imposible ang noise learning dahil sa sampling cost ng pag-aaral ng maraming layer.

Ginagamit ang qiskit-noise-learning para matutunan ang noise. Inuulit ng learner ang bawat layer nang fragment_depths beses sa mga learning circuit nito, nagta-twirl ng bawat circuit nang num_randomizations beses, at ifi-fit ang pagbaba ng mga nasukat na fidelity sa isang Pauli-Lindblad model. Maaaring makaapekto ang mga parameter na ito sa katumpakan ng natutunang model. Kung mas tumpak ang natutunang noise model, mas tumpak din ang pagkansela ng noise.

Ipinapakita ng sumusunod na code ang natutunang noise model kung saan pinagsama sa isang mapa ang dalawang layer. Ang bawat qubit ay isang pie ng weight-1 na X, Y at Z rate nito na pinagsama sa dalawang layer, at ipinapakita ng bawat edge ang mga natutunang weight-2 rate. Halimbawa, ang rate na 3e-4 ay nangangahulugang nagaganap ang error na iyon sa humigit-kumulang tatlo sa bawat 10,000 gamit ng layer.

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_noise_learning.aer_executor import AerExecutor
from qiskit_noise_learning.noise_learner import LearningOptions, NoiseLearner
from samplomatic import InjectNoise

line_coupling = [(i, i + 1) for i in range(num_qubits - 1)]
backend = GenericBackendV2(
num_qubits=num_qubits,
basis_gates=["id", "rz", "sx", "x", "cz"],
coupling_map=line_coupling,
)

# first learn only the layers PEC will inject noise into, i.e. not the measurement layer
pec_layers = [
layer
for layer in slc_pec_task.find_unique_layers(
mirrored_circuit, slc_boxing_options
)
if get_annotation(layer.operation, InjectNoise)
]
layers = slc_pec_task.find_unique_layers(mirrored_circuit, slc_boxing_options)

learning_options = LearningOptions(
fragment_depths=[2, 4, 8, 16],
num_randomizations=250,
shots_per_randomizations=16,
)

# 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(pec_layers).result().to_dict()
) # keyed by InjectNoise reference

# Draw the learned model on the line, laid out as a line with the qubits in order.
# Composing the two layers' maps sums their rates, giving one map over all the edges.
embedding = Embedding(
[(0, 0), (0, 2), (0, 4), (2, 4), (4, 4), (4, 2), (4, 0), (2, 0)],
line_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

Gamitin ang natutunang noise para pagsamahin ang mga kinalkulang bound sa local scales matrix​

Dahil hawak na natin ang mga classical bound (mula sa nakaraang hakbang) at ang mga natutunang noise rate, maaari na nating kalkulahin ang isang local scales matrix — isang bigat bawat error na nagtatakda kung gaano kagalit dapat kanselahin ng PEC ang bawat indibidwal na noise term.

Ang pangunahing ideya ng SLC ay hindi lahat ng error ay kailangang ganap na kanselahin. Ang error na maliit ang forward at backward bound ay may bale-walang epekto sa observable anuman ang rate nito, kaya maaari itong iwang bahagya o ganap na un-mitigated. Pinagsasama ng merge_bounds ang mga classical bound sa mga natutunang Pauli-Lindblad rate, tapos nagtatalaga ang compute_local_scales sa bawat error ng scale sa pagitan ng 0 (ganap na binabalewala) at 1 (ganap na kinakansela), alinsunod sa bias_tolerance na itinakda ng user. Ang mga error na may malaking tinatayang kontribusyon sa bias ay tumatanggap ng scale na malapit sa 1 (buong PEC treatment), habang ang mga error na maliit ang kontribusyon ay tumatanggap ng mas mababang scale, na nagpapababa sa sampling overhead na dala nila.

Nagbibigay ang SLC ng tuloy-tuloy na knob sa pagitan ng dalawang sukdulan — vanilla PEC (zero bias, pinakamataas na overhead) at walang mitigation (zero overhead, buong noise bias). Kinokontrol ng parameter na bias_tolerance ang knob na ito: ang pagtatakda nito sa 0 ay nagbabalik ng buong PEC, habang ang mas malalaking value ay nagpapahintulot ng mas maraming natitirang bias kapalit ng mas mababang sampling overhead na γ².

Sinusuri ng hakbang na ito ang bias_tolerance sa isang hanay ng mga value at kinakalkula ang resultang sampling overhead para sa bawat isa. Ang pag-plot ng mga puntong ito laban sa overhead ng buong PEC ay tumutulong sa iyong pumili ng working point na akma sa shot budget mo. Halimbawa, ang pagtanggap sa 5 % na natitirang bias ay maaaring magpababa ng sampling overhead nang isang order of magnitude kumpara sa buong PEC, na nagpapagawang posible ang kalkulasyon sa mga QPU ngayon na kung hindi ay hindi magagawa.

import matplotlib.pyplot as plt
from qiskit_addon_slc.bounds import compute_local_scales, merge_bounds

merged_bounds = merge_bounds(
boxed_circuit,
tighten_forward_bounds,
backward_bounds,
noise_rates=learned_noise,
)

biases = []
costs = []
for bias in [0.0, *np.arange(0.01, 0.11, 0.01).tolist()]:
_, cost_, bias_ = compute_local_scales(
boxed_circuit,
merged_bounds,
noise_rates=learned_noise,
bias_tolerance=bias,
)
biases.append(bias_)
costs.append(cost_)

# Compute tha full PEC overhead and compare it with the overhead and bias of different SLC configurations
vanilla_gamma = slc_pec_task.calculate_gamma(
slc_pec_task.boxed_circuit, learned_noise, 1
)

xticks = np.arange(0, 11, 2)

fig, ax = plt.subplots()
ax.scatter(
[0], [vanilla_gamma**2], marker="D", c="tab:orange", label="full PEC"
)
ax.plot(
100 * np.array(biases),
np.array(costs),
"o-",
c="tab:blue",
label="PEC+SLC",
)
ax.set_xticks(xticks, [f"{x:.2f}" for x in xticks])

ax.set_xlabel("Remaining bias [%]")
ax.set_ylabel(r"Sampling overhead, $\gamma^2$")
ax.grid()
ax.legend()
fig.suptitle("PEC sampling overhead reduction due to SLC")
Optimal spacetime partitioning not implemented! Just partitioning list of noisy boxes.
Text(0.5, 0.98, 'PEC sampling overhead reduction due to SLC')

Output of the previous code cell

Piliin ang nais na bias bound batay sa trade-off ng shot overhead at bias​

Sa gabay na ito, pumipili tayo ng bias tolerance na 5%. Tandaan na nakabatay ang kalkulasyon ng bias na ito sa natutunang noise model, na maaaring hindi lubos na tugma sa totoong noise ng device.

chosen_bias_threshold = 0.05
local_scales, sampling_cost, bias = compute_local_scales(
boxed_circuit, merged_bounds, learned_noise, bias_tolerance=bias
)
slc_pec_task.set_slc_local_scales(
local_scales, float(np.sqrt(sampling_cost)), bias
)

Maghanda ng PEC + SLC program, patakbuhin ang programa, at mag-post-process​

Kapag napili na ang mga local scale, maaari na nating buuin ang buong PEC+SLC execution program. Bumubuo ang tawag na PEC.prepare ng QuantumProgram na nag-e-encode ng anti-noise injection strategy sa mga box annotation ng circuit. Ang pagpasa ng noise_gain="slc_local_scales" ay nag-uutos sa executor na gamitin ang mga bigat bawat error na itinakda ng set_slc_local_scales, sa halip na ilapat ang parehong buong inverse-noise gain sa bawat error gaya ng gagawin ng vanilla PEC.

Para makagawa ng patas na paghahambing, naghahanda ng pangalawang PEC task na may noise_gain=0, na tumutugma sa buong PEC cancellation nang walang SLC bias allowance. Idinaragdag ang dalawang programa sa iisang QuantumProgram para iisang execution job ang pagbabahagian nila — pinagsasalitan at sabay na pinapatakbo ang mga circuit nila, kaya parehong naaapektuhan ang dalawa ng anumang hardware drift.

Pagkatapos makumpleto ang job, kino-convert ng postprocess ang mga raw na measurement bitstring sa mga expectation value, na inilalapat ang angkop na PEC rescaling factor na γ para sa bawat task.

program_pec = slc_pec_task.prepare(
circuit=mirrored_circuit,
observables=[observable],
parameters=None,
num_randomizations=num_randomizations,
shots_per_randomization=shots_per_randomization,
custom_boxing_options=slc_boxing_options,
noise_maps=learned_noise, # PEC option
noise_gain="slc_local_scales", # PEC option. Defines the usage of SLC
max_sampling_overhead=100, # PEC option
)

full_pec_task = PEC()
program_pec = full_pec_task.prepare(
circuit=mirrored_circuit,
observables=[observable],
parameters=None,
num_randomizations=num_randomizations,
shots_per_randomization=shots_per_randomization,
custom_boxing_options=boxing_options,
quantum_program=program_pec,
noise_maps=learned_noise, # PEC option
noise_gain=0, # PEC option
max_sampling_overhead=100, # PEC option
)

# Execute
program_pec._semantic_role = (
"simulation" # flag the program for the simulator
)
job_pec_results = noisy_executor.run(program_pec).result()

# post-processing
pec_slc_res = slc_pec_task.postprocess(job_pec_results)
full_pec_res = full_pec_task.postprocess(job_pec_results)

Ihambing ang mga mitigated na expectation value at shot overhead​

Ang ideal na expectation value ng mirrored na circuit ay 1 sa konstruksyon, kaya ang bias ng anumang tantiya ay simpleng |1 - result|. Inililimbag ng huling cell na ito ang bias at kabuuang bilang ng shot para sa tatlong senaryo nang magkakatabi:

  • Unmitigated: ang raw na noisy na expectation value na walang inilapat na error cancellation.

  • Full PEC: zero-bias na error cancellation gamit ang kumpletong inverse noise model sa bawat layer, sa buong γ² na sampling overhead.

  • PEC+SLC: error cancellation na ginagabayan ng mga local scale ng shaded-lightcone, na tumatanggap ng napiling bias_tolerance kapalit ng mas mababang bilang ng shot.

Ipinapakita ng paghahambing ng tatlong hanay ang konkretong benepisyo ng SLC: ang mitigated na bias ng PEC+SLC ay nananatiling mas mababa nang malayo sa unmitigated na bias habang mas maliit nang husto ang kabuuang bilang ng shot kaysa sa kinailangan ng buong PEC.

print(
f"Unmitigated result bias: {np.abs(1 - unmitigated_res.data.evs[0]) * 100:.2f}%, \
total shots ran: {job_unmit_res[0]['_meas'].shape[0] * job_unmit_res[0]['_meas'].shape[2]}"
)

print(
f"Full PEC final result bias: {np.abs(1 - full_pec_res.data.evs[0]) * 100:.2f}%, \
total shots ran: {job_pec_results[1]['_meas'].shape[0] * job_pec_results[1]['_meas'].shape[2]}"
)

print(
f"PEC+SLC final result bias: {np.abs(1 - pec_slc_res.data.evs[0]) * 100:.2f}%, \
total shots ran: {job_pec_results[0]['_meas'].shape[0] * job_pec_results[0]['_meas'].shape[2]}"
)
Unmitigated result bias: 36.88%, total shots ran: 6400
Full PEC final result bias: 0.97%, total shots ran: 48528
PEC+SLC final result bias: 1.46%, total shots ran: 24480