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?

Input dan output Samplex

Pengenalan​

Samplex ialah jenis teras pustaka samplomatic. Samplex mewakili taburan kebarangkalian berparameter ke atas parameter sesuatu litar templat, dengan medan bernilai tatasusunan lain untuk digunakan semasa pascapemprosesan data yang dikumpulkan daripada pelaksanaan litar templat yang telah diikat. Antara muka utamanya ialah kaedah sample() yang mengambil sampel daripada taburan ini untuk menghasilkan koleksi tatasusunan.

Panduan ini menerangkan cara menggunakan antara muka sample(), cara menyoal dan menentukan input yang diperlukan, dan cara memeriksa output yang dijangkakan. Tatasusunan yang dibekalkan kepada dan dikembalikan daripada sample() bertaip kuat. Maksudnya, bagi sesuatu instans samplex, nama, jenis dan bentuknya tetap serta boleh disoal sebelum pensampelan dilakukan. Input dan output yang terdapat dalam samplex bergantung pada banyak faktor. Contohnya, sama ada twirling pengukuran hadir dan sama ada suntikan hingar diperlukan. Oleh sebab itu, secara amnya, dua instans samplex tidak dijangka mempunyai input dan output yang sama.

Persediaan​

Mula-mula, bina litar yang telah di-box dan bina ia menjadi pasangan samplex dan templat. Ini akan digunakan dalam contoh seterusnya. Perhatikan bahawa apabila melakukan box pada litar secara manual, panduan ini menggunakan nama alpha, beta, ref1, ref2, mod_ref1, mod_ref2, mod_ref3, dan conclude. Selain itu, litar tersebut mempunyai empat objek Parameter. Panduan ini menunjukkan bagaimana setiap satunya memainkan peranan dalam input dan output samplex. Lihat panduan transpiler untuk maklumat tentang melakukan box pada litar secara automatik.

import matplotlib.pyplot as plt
import numpy as np
from qiskit.circuit import ClassicalRegister, Parameter, QuantumCircuit, QuantumRegister
from qiskit.quantum_info import Operator, Pauli, PauliLindbladMap

from samplomatic import ChangeBasis, InjectNoise, Twirl, build

# our circuit has two classical registers named alpha and beta
circuit = QuantumCircuit(
QuantumRegister(4), alpha := ClassicalRegister(3, "alpha"), beta := ClassicalRegister(1, "beta")
)

# the first box is only twirled
with circuit.box([Twirl()]):
for idx in range(4):
circuit.rx(Parameter(f"a{idx}"), idx)
circuit.cz(0, 1)
circuit.cz(1, 2)

# the second box is twirled, and has noise injected
with circuit.box([Twirl(), InjectNoise(ref="ref1", modifier_ref="mod_ref1")]):
circuit.h(1)
circuit.cz(1, 2)

# the third box is twirled, and has different noise injected
with circuit.box([Twirl(), InjectNoise(ref="ref2", modifier_ref="mod_ref2")]):
circuit.rx(0.1, range(4))
circuit.cz(0, 1)
circuit.cz(1, 2)

# the fourth box is the same as the second, but with a different modifer ref
with circuit.box([Twirl(), InjectNoise(ref="ref1", modifier_ref="mod_ref3")]):
circuit.h(1)
circuit.cz(1, 2)

circuit.barrier()

# the final two boxes twirl, and add a basis change in one case
with circuit.box([Twirl(), ChangeBasis(ref="conclude")]):
circuit.measure(range(3), alpha)

with circuit.box([Twirl()]):
circuit.measure([3], beta)

circuit.draw("mpl")

../_images/88f6576d7e2fd76bfb52d5133c6bc07e908a28941c6538f5251ac508cfb202f7.png

Seterusnya, panggil build() pada litar ber-box untuk membina pasangan templat dan samplex. Anda akan melihat bagaimana setiap box ditukar menjadi “sandwic” barrier yang merangkumi serpihan rz-sx-rz-sx-rz untuk melaksanakan dressing.

template, samplex = build(circuit)

template.draw("mpl", fold=100)

../_images/ec8456d0d0a5928c5d056184cbd1842dcf7aefdc7cdba428f62092b27646d601.png

Plotkan DAG samplex dan lalukan tetikus di atas nod untuk melihat perkara berikut:

  • Semua nod pensampelan (bintang) bertanggungjawab menjana perawakan untuk twirling, mengambil sampel daripada model hingar, atau menyuntik pengubahan basis.

  • Semua nod pengumpulan (tali leher kupu-kupu) bertanggungjawab merender hirisan output, iaitu pembalikan pengukuran atau sudut parameter.

  • Semua nod perantara (bulatan) bertanggungjawab untuk pelbagai jenis manipulasi data.

samplex.draw()

Menyoal input yang diperlukan dan output yang dijangkakan​

Cara paling mudah untuk melihat input yang diperlukan dan output yang dijangkakan ialah dengan mencetak objek Samplex. Item tatasusunan diformatkan sebagai '{name}' <{type}[{shape}...]>, dan input yang diperlukan mendahului input pilihan.

print(samplex)
Samplex(<58 nodes>)
Inputs:
- 'basis_changes.conclude' <uint8[3]>: Basis changing gates, in the symplectic ordering
I=0, Z=1, X=2, and Y=3.
- 'parameter_values' <float64[4]>: Input parameter values to use during sampling.
- 'pauli_lindblad_maps.ref1' <PauliLindbladMap>: A PauliLindblad map acting on 2 qubits,
with 'num_terms_ref1' terms.
- 'pauli_lindblad_maps.ref2' <PauliLindbladMap>: A PauliLindblad map acting on 4 qubits,
with 'num_terms_ref2' terms.

- 'local_scales.mod_ref1' <float64['num_terms_ref1']>: (Optional) An array of factors by
which to scale individual rates of a Pauli Lindblad map, where the order should match the
corresponding list of terms.
- 'local_scales.mod_ref2' <float64['num_terms_ref2']>: (Optional) An array of factors by
which to scale individual rates of a Pauli Lindblad map, where the order should match the
corresponding list of terms.
- 'local_scales.mod_ref3' <float64['num_terms_ref1']>: (Optional) An array of factors by
which to scale individual rates of a Pauli Lindblad map, where the order should match the
corresponding list of terms.
- 'noise_scales.mod_ref1' <float64[]>: (Optional) A scalar factor by which to scale rates
of a Pauli Lindblad map.
- 'noise_scales.mod_ref2' <float64[]>: (Optional) A scalar factor by which to scale rates
of a Pauli Lindblad map.
- 'noise_scales.mod_ref3' <float64[]>: (Optional) A scalar factor by which to scale rates
of a Pauli Lindblad map.
Outputs:
* 'measurement_flips.alpha' <bool['num_randomizations', 1, 3]>: Bit-flip corrections
for measurement twirling.
* 'measurement_flips.beta' <bool['num_randomizations', 1, 1]>: Bit-flip corrections for
measurement twirling.
* 'parameter_values' <float32['num_randomizations', 48]>: Parameter values valid for an
associated template circuit.
* 'pauli_signs' <bool['num_randomizations', 3]>: Signs from sampled Pauli Lindblad
maps, where boolean values represent the parity of the number of non-trivial factors in the
sampled error that arise from negative rates. In other words, in order to implement basic
PEC, the sign used to correct expectation values should be ``(-1)**bool_value``. The order
matches the iteration order of boxes in the original circuit with noise injection
annotations.

inputs() dan outputs() samplex, serta maklumat yang lebih terperinci seperti nama, bentuk, jenis dan perihalannya, juga boleh disoal secara programatik. Jenis pulangan kedua-dua kaedah ini ialah TensorInterface. Contohnya, kod berikut menyenaraikan semua spesifikasi antara muka input:

samplex.inputs().specs
[TensorSpecification('basis_changes.conclude', (3,), dtype('uint8'), 'Basis changing gates, in the symplectic ordering I=0, Z=1, X=2, and Y=3.'),
TensorSpecification('local_scales.mod_ref1', ('num_terms_ref1',), dtype('float64'), 'An array of factors by which to scale individual rates of a Pauli Lindblad map, where the order should match the corresponding list of terms.', optional=True),
TensorSpecification('local_scales.mod_ref2', ('num_terms_ref2',), dtype('float64'), 'An array of factors by which to scale individual rates of a Pauli Lindblad map, where the order should match the corresponding list of terms.', optional=True),
TensorSpecification('local_scales.mod_ref3', ('num_terms_ref1',), dtype('float64'), 'An array of factors by which to scale individual rates of a Pauli Lindblad map, where the order should match the corresponding list of terms.', optional=True),
TensorSpecification('noise_scales.mod_ref1', (), dtype('float64'), 'A scalar factor by which to scale rates of a Pauli Lindblad map.', optional=True),
TensorSpecification('noise_scales.mod_ref2', (), dtype('float64'), 'A scalar factor by which to scale rates of a Pauli Lindblad map.', optional=True),
TensorSpecification('noise_scales.mod_ref3', (), dtype('float64'), 'A scalar factor by which to scale rates of a Pauli Lindblad map.', optional=True),
TensorSpecification('parameter_values', (4,), dtype('float64'), 'Input parameter values to use during sampling.'),
PauliLindbladMapSpecification('pauli_lindblad_maps.ref1', num_qubits=2, num_terms=num_terms_ref1),
PauliLindbladMapSpecification('pauli_lindblad_maps.ref2', num_qubits=4, num_terms=num_terms_ref2)]

Contoh seterusnya mencetak sedikit maklumat tentang spesifikasi output yang namanya mengandungi rentetan "flips".

for spec in samplex.outputs().get_specs("flips"):
print(spec.name, spec.shape, spec.dtype)
measurement_flips.alpha ('num_randomizations', 1, 3) bool
measurement_flips.beta ('num_randomizations', 1, 1) bool

Ikat nilai input dan sampel​

Untuk sample(), samplex memerlukan nilai bagi sekurang-kurangnya inputs() yang ditandakan sebagai diperlukan. Nilai ini mula-mula diikat kepada antara muka input supaya ia dapat melakukan semua semakan jenis yang diperlukan (atau paksaan jenis dalam sesetengah kes) dan analisis bentuk. Jika terdapat sesuatu yang salah pada jenis atau bentuk, atau jika nilai yang diperlukan tiada, ralat yang terperinci akan dibangkitkan.

Ikat input​

Dalam contoh berikut, kaedah sample() diberikan nilai input yang diperlukan. Ia kemudian digunakan untuk mengambil tiga perawakan daripada samplex. Pengikatan yang diperlukan daripada dressing ialah peta Pauli Lindblad untuk suntikan hingar dan tatasusunan pengubahan basis. Selain itu, nilai bagi empat parameter dalam litar ber-box asal diperlukan, yang dalam kes ini ditetapkan kepada np.linspace(0, 1, 4). Samplex menggubah parameter ini ke dalam dressing, jadi ia secara berkesan menjadi pengubahsuaian kepada nilai parameter output samplex.

inputs = samplex.inputs().bind(
# bind() concatenates nested dicts with a '.' so that we can
# set 'pauli_lindblad_maps.noise0/1' as follows. note that the
# names 'ref1' and 'ref2' derive from the names in the InjectNoise
# annotation.
pauli_lindblad_maps={
"ref1": PauliLindbladMap.identity(2),
"ref2": PauliLindbladMap.identity(4),
},
# likewise, we can set all basis changes as follows, where
# the name 'conclude' comes from our basis change annotation
basis_changes={"conclude": [0, 1, 2]},
# we must provide values for all parameters in the original circuit
parameter_values=np.linspace(0, 1, 4),
)

outputs = samplex.sample(inputs, num_randomizations=3)
print(outputs)
SamplexOutput(<
- Dimension constraints: num_randomizations=3

* 'measurement_flips.alpha' <bool['num_randomizations', 1, 3]>: Bit-flip corrections for
measurement twirling.
* 'measurement_flips.beta' <bool['num_randomizations', 1, 1]>: Bit-flip corrections for
measurement twirling.
* 'parameter_values' <float32['num_randomizations', 48]>: Parameter values valid for an
associated template circuit.
* 'pauli_signs' <bool['num_randomizations', 3]>: Signs from sampled Pauli Lindblad maps,
where boolean values represent the parity of the number of non-trivial factors in the sampled
error that arise from negative rates. In other words, in order to implement basic PEC, the
sign used to correct expectation values should be ``(-1)**bool_value``. The order matches the
iteration order of boxes in the original circuit with noise injection annotations.
>)

Input boleh diikat kepada antara muka melalui beberapa panggilan bind() atau melalui penugasan item secara langsung. Walaupun format kamus bersarang yang dibenarkan oleh bind() demi kemudahan, ia ialah objek pemetaan rata, dan menyokong semua sintaks pemetaan biasa. Sebaik sahaja semua input yang diperlukan ditemui, fully_bound menjadi benar.

inputs = (
samplex.inputs()
.bind(
pauli_lindblad_maps={
"ref1": PauliLindbladMap.identity(2),
"ref2": PauliLindbladMap.identity(4),
}
)
.bind(parameter_values=np.linspace(0, 1, 4))
)

# once the final requirement is bound, fully_bound becomes True
print("Fully bound?", inputs.fully_bound)
inputs["basis_changes.conclude"] = [0, 2, 3]
print("Fully bound?", inputs.fully_bound)

# setting optional values does not affect whether the interface is fully bound
inputs["noise_scales.mod_ref1"] = 3
print("Fully bound?", inputs.fully_bound)
Fully bound? False
Fully bound? True
Fully bound? True

Semua objek TensorInterface, termasuk subkelas SamplexOutput, memetakan objek kepada data yang telah diikat kepadanya. Ini bermakna anda boleh mendapatkan, sebagai contoh, nilai parameter templat seperti berikut. Dalam kes ini, ia mempunyai bentuk (3, 48) kerana tiga perawakan diminta dan litar templat mempunyai 48 parameter.

print("(num_randomizations, num_template_params) =", outputs["parameter_values"].shape)
print(outputs["parameter_values"][0, :])
(num_randomizations, num_template_params) = (3, 48)
[ 0.0000000e+00 0.0000000e+00 0.0000000e+00 1.5707964e+00
3.3333334e-01 1.5707964e+00 -1.5707964e+00 2.4749260e+00
-1.5707964e+00 1.5707964e+00 1.0000000e+00 1.5707964e+00
0.0000000e+00 1.5707964e+00 0.0000000e+00 3.1415927e+00
0.0000000e+00 0.0000000e+00 1.5707964e+00 3.0415926e+00
-1.5707964e+00 -1.5707964e+00 3.0415926e+00 -1.5707964e+00
-1.5707964e+00 1.0000000e-01 1.5707964e+00 1.5707964e+00
1.0000000e-01 1.5707964e+00 3.1415927e+00 1.5707964e+00
0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
0.0000000e+00 3.1415927e+00 0.0000000e+00 3.1415927e+00
0.0000000e+00 0.0000000e+00 3.1415927e+00 1.5707964e+00
0.0000000e+00 4.4408921e-16 3.1415927e+00 0.0000000e+00]

Menentukan input sebagai kamus​

Sebagai ganti menyediakan TensorInterface yang terikat sepenuhnya, anda boleh menentukan input sebagai kamus piawai, seperti yang ditunjukkan dalam sel di bawah. Dalam kes ini, kaedah sample() secara dalaman mengikat item kamus kepada antara muka input samplex untuk mengesahkan bahawa semua input yang diperlukan hadir dan serasi.

inputs = {
"pauli_lindblad_maps": {
"ref1": PauliLindbladMap.identity(2),
"ref2": PauliLindbladMap.identity(4),
},
"basis_changes": {"conclude": [0, 1, 2]},
"parameter_values": np.linspace(0, 1, 4),
}
outputs = samplex.sample(inputs, num_randomizations=3)

Jenis input​

Pada masa ini, terdapat dua jenis nilai antara muka:

  • Bernilai tatasusunan: Ini mempunyai bentuk dan jenis data. Nilai terikat dipaksa kepada jenis data jika boleh. Mana-mana dimensi boleh menjadi dimensi bebas.

  • Peta Pauli Lindblad: Ini mestilah berjenis qiskit.quantum_info.PauliLindbladMap dan mesti bertindak pada bilangan qubit yang ditetapkan. Bilangan sebutan dalam peta ialah dimensi bebas.

# up to precision loss, these are equivalent via automatic type coersion of array inputs
samplex.inputs()["parameter_values"] = [1, 2, 8, 9]
samplex.inputs()["parameter_values"] = np.array([1, 2, 8, 9], dtype=np.float16)

Dimensi bebas​

Kelas TensorInterface mempunyai konsep dimensi bebas, iaitu saiz integer bernama yang nilainya tidak ditentukan sehingga sesetengah data diikat kepada antara muka yang mengekangnya. Semua dimensi bebas yang bernama sama mesti diselesaikan kepada saiz yang konsisten apabila mengikat data, jika tidak ralat akan dibangkitkan. Contohnya, dalam outputs() mana-mana samplex, paksi tatasusunan yang sepadan dengan perawakan ialah parameter bebas yang bernama "num_randomizations" mengikut konvensyen. Apabila sample() dipanggil, ia mengikat nilai kepada output

print("All free dimensions:", outputs.free_dimensions)
print("Current constraints:", outputs.bound_dimensions)
All free dimensions: {'num_randomizations'}
Current constraints: {'num_randomizations': 3}

Satu lagi senario dimensi bebas yang lazim ialah perkongsian kekangan sebutan antara spesifikasi peta Pauli lindblad dan pengubahsuainya. qiskit.quantum_info.PauliLindbladMap ialah jujukan tertib sebutan, di mana setiap sebutan mengandungi kadar titik terapung dan perwakilan Pauli jarang. Fungsi build() menambah penentu "pauli_lindblad_maps.<ref>" untuk jenis ini bagi setiap anotasi InjectNoise, dan jika ia mengandungi modifier_ref, penentu "local_scales.<modifier_ref>" turut ditambah. Kedua-duanya berkongsi dimensi bebas "num_terms_<ref>" yang menentukan berapa banyak sebutan Pauli Lindblad yang terdapat dalam model hingar kerana yang kedua perlu dizip dengan kadar yang pertama untuk menskalakannya.

# both the PauliLindbladMap and the local scales imply 2 terms, so that the free dimension
# 'num_terms_noise2' is satisfied
inputs = samplex.inputs().bind(
pauli_lindblad_maps={"ref2": PauliLindbladMap.from_list([("XXYZ", 0.1), ("IIXX", 0.2)])},
local_scales={"mod_ref2": [1, 2]},
)
print("All free dimensions:", inputs.free_dimensions)
print("Current constraints:", inputs.bound_dimensions)
All free dimensions: {'num_terms_ref1', 'num_terms_ref2'}
Current constraints: {'num_terms_ref2': 2}

Konvensyen susunan qubit​

Samplex yang dibina daripada litar ber-box oleh fungsi build() boleh memerlukan input bernilai tatasusunan kepada sample(), di mana satu indeks sepadan dengan qubit dalam box litar. Bahagian ini menerangkan konvensyen susunan yang harus digunakan untuk paksi sedemikian. Ringkasnya: gunakan susunan qubit litar ber-box, terhad kepada qubit milik box.

Contohnya, andaikan anda ingin mengetahui cara menentukan peta Pauli Lindblad untuk "noise1". Maka susunan qubit dalam peta hingar adalah berkenaan dengan qubit berikut:

box_of_interest = circuit[1]
qubit_ordering_convention = [qubit for qubit in circuit.qubits if qubit in box_of_interest.qubits]
qubit_ordering_convention
[<Qubit register=(4, "q0"), index=1>, <Qubit register=(4, "q0"), index=2>]

Maksudnya, jika anda mahu <Qubit register=(4, "q0"), index=2> berhingar dengan hingar X, maka anda harus mentakrifkan peta Pauli Lindblad seperti ini kerana ia berada pada indeks 1 bagi qubit_ordering_convention.

samplex.inputs().bind(
pauli_lindblad_maps={
"ref1": (noise1 := PauliLindbladMap.from_sparse_list([("X", [1], 0.12)], num_qubits=2))
}
)
noise1
<PauliLindbladMap with 1 term on 2 qubits: (0.12)L(X_1)>

Perkara yang sama berlaku untuk pengubahan basis. Jika anda mahu memutar ke dalam keadaan eigen +1 bagi pengendali X, Y dan Z untuk qubit 0, 1 dan 2 circuit, masing-masing, maka anda harus menggunakan tatasusunan berikut, sambil mengingati bahawa konvensyen I=0I=0, Z=1Z=1, X=2X=2, dan Y=3Y=3 digunakan dalam pustaka ini (dan Qiskit).

samplex.inputs().bind(basis_changes={"conclude": (basis_change := [2, 3, 1])})
basis_change
[2, 3, 1]

Perhatikan bahawa konvensyen susunan qubit bukan susunan yang ditakrifkan oleh mana-mana daripada yang berikut:

  • box_instruction.qubits, di mana box_instruction ialah qiskit.circuit.CircuitInstruction yang operasinya ialah qiskit.circuit.BoxOp, kerana susunan senarai qubit ini mungkin bergantung pada susunan arahan ditambah ke dalam konteks box, yang akan menjadi konvensyen yang mmengelirukan. Contohnya, with box(): circuit.x([0, 1]) dan with box(): circuit.x([1, 0]) akan menghasilkan susunan yang berbeza.

  • box_instruction.operation.body.qubits kerana qubit ini mungkin tidak muncul pun dalam litar luar. Qubit di dalam badan sebenar arahan BoxOp (atau operasi aliran kawalan lain seperti IfElseOp) hanya dijamin mempunyai makna yang konsisten dalam skop tersebut. Ini akan menjadi konvensyen yang tidak jelas takrifannya, dan sukar digunakan secara amnya.

Pengujian setempat dengan litar templat​

Jika Samplex dibina dengan menggunakan fungsi build(), nilai parameter output harus serasi secara langsung dengan parameter litar templat yang berkaitan. Contohnya, anda boleh mengikat nilai bagi salah satu perawakan kepada templat untuk pemeriksaan setempat.

inputs = samplex.inputs().bind(
pauli_lindblad_maps={
"ref1": PauliLindbladMap.identity(2),
"ref2": PauliLindbladMap.identity(4),
},
basis_changes={"conclude": [0, 0, 0]},
parameter_values=np.linspace(0, 1, 4),
)

outputs = samplex.sample(inputs, num_randomizations=3)

bound_template = template.assign_parameters(outputs["parameter_values"][2])
bound_template.draw("mpl", fold=1000)

../_images/1d82c46209f8648a2df572cfef8ca256f47952566d34386761ab942aa6e50afd.png

Ini membolehkan anda mengesahkan bahawa samplex mengeluarkan sampel yang dijangkakan. Contohnya, kod berikut menukar litar terikat kepada objek qiskit.quantum_info.Operator dan menggubah dengan Pauli pembalikan bit untuk memeriksa secara visual bahawa ketiga-tiga perawakan setara secara logik dengan litar asas.

from samplomatic.utils import unbox

# Operator requires that we unpack all of the boxes first
unboxed = unbox(circuit).assign_parameters(inputs["parameter_values"])
# We want to plot unitary matrix amplitudes, so we need to remove the non-unitary measurements
unboxed.remove_final_measurements()
unboxed_unitary = Operator(unboxed)

# Plot magnitudes of the unitary matrix represenation of the circuit
plt.subplot(1, 4, 1)
plt.imshow(np.abs(unboxed_unitary))
plt.title("Base Circuit")

# For each randomization we sampled, plot the unitary matrix representation
for idx in range(3):
bound_template = template.assign_parameters(outputs["parameter_values"][idx])
bound_template.remove_final_measurements()

# The example does measurement twirling by compiling random bitflip gates before the
# measurements, so we need to undo these at the operator level for each randomization.
# We do this by casting them to Paulis and composing with the bound circuit's unitary
alpha_flips = Pauli(([0, 0, 0], outputs["measurement_flips.alpha"][idx, 0]))
beta_flips = Pauli(([0], outputs["measurement_flips.beta"][idx, 0]))
flips = beta_flips ^ alpha_flips
bound_unitary = Operator(bound_template) & flips

# Plot magnitudes of the unitary matrix represenation of the circuit
plt.subplot(1, 4, idx + 2)
plt.imshow(np.abs(bound_unitary))
plt.title(f"Randomization {idx}")

plt.tight_layout()

../_images/af1aa74f8a0e8abed673d4cd43ff8b810c44297d2f3a42fcfb49ade811e51c58.png

Begitu juga, kod berikut menghantar nilai parameter output dan templat kepada sampler untuk mensimulasikan 10,000 shot bagi semua perawakan, dan membandingkan nilai jangkaan yang terhasil (hanya bagi register alpha) dengan nilai jangkaan simulasi litar asas.

from qiskit.primitives import StatevectorEstimator as Estimator
from qiskit.primitives import StatevectorSampler as Sampler
from qiskit.primitives.containers import BitArray

# simulate some expectation values direction from the base circuit
estimator_job = Estimator().run([(unboxed, ["IZII", "IIZI", "IIIZ"])])
evs = estimator_job.result()[0].data["evs"]

# get the sampler data from each randomization, and do bitflip correction
sampler_job = Sampler().run([(template, outputs["parameter_values"])], shots=10_000)
alpha_data = sampler_job.result()[0].data["alpha"]
alpha_data ^= BitArray.from_bool_array(outputs["measurement_flips.alpha"], "little")

# compare the results
print(" EVs from base circuit:", evs)
print("EVs from randomizations:", alpha_data.expectation_values(["ZII", "IZI", "IIZ"]))
EVs from base circuit: [0.7819611 0.93553883 0.99500417]
EVs from randomizations: [0.789 0.9366 0.995 ]