Lumaktaw sa pangunahing nilalaman

Mga input at output ng Primitive

Bagong execution model, nasa beta release na ngayon

Available na ang beta release ng bagong execution model. Ang directed execution model ay nagbibigay ng mas maraming flexibility kapag kina-customize ang iyong error mitigation workflow. Tingnan ang gabay na Directed execution model para sa karagdagang impormasyon.

Mga bersyon ng package

Ang code sa page na ito ay binuo gamit ang mga sumusunod na requirements. Inirerekomenda naming gamitin ang mga bersyong ito o mas bago.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

Ang page na ito ay nagbibigay ng pangkalahatang-ideya ng mga input at output ng Qiskit Runtime primitives na nagpapatupad ng mga workload sa IBM Quantum® compute resources. Ang mga primitive na ito ay nagbibigay sa iyo ng kakayahang mahusay na tukuyin ang mga vectorized workload sa pamamagitan ng isang data structure na kilala bilang Primitive Unified Bloc (PUB). Ang mga PUB na ito ang pangunahing yunit ng trabaho na kailangang isagawa ng isang QPU para sa mga workload na ito. Ginagamit ang mga ito bilang mga input sa pamamaraan ng run() para sa mga Sampler at Estimator primitive, na nagpapatupad ng tinukoy na workload bilang isang job. Pagkatapos, kapag nakumpleto na ang job, ang mga resulta ay ibinalik sa isang format na depende sa parehong mga PUB na ginamit at sa mga runtime option na tinukoy mula sa mga Sampler o Estimator primitive.

Pangkalahatang-ideya ng mga PUB​

Kapag tinatawagan ang pamamaraan ng run() ng isang primitive, ang pangunahing argument na kailangan ay isang list ng isa o higit pang mga tuple — isa para sa bawat Circuit na pinapatakbo ng primitive. Ang bawat isa sa mga tuple na ito ay itinuturing na isang PUB, at ang mga kinakailangang elemento ng bawat tuple sa listahan ay nakasalalay sa primitive na ginamit. Ang data na ibinibigay sa mga tuple na ito ay maaari ring ayusin sa iba't ibang hugis upang magbigay ng flexibility sa isang workload sa pamamagitan ng broadcasting — ang mga patakaran nito ay inilarawan sa isang sumusunod na seksyon.

Estimator PUB​

Para sa Estimator primitive, ang format ng PUB ay dapat maglaman ng hindi hihigit sa apat na halaga:

  • Isang solong QuantumCircuit, na maaaring maglaman ng isa o higit pang mga Parameter na object
  • Isang listahan ng isa o higit pang mga observable, na nagtutukoy ng mga inaasahang halaga na tatantiyahin, na nakaayos sa isang array (halimbawa, isang solong observable na kinakatawan bilang isang 0-d na array, isang listahan ng mga observable bilang isang 1-d na array, at iba pa). Ang data ay maaaring nasa alinman sa ObservablesArrayLike na format tulad ng Pauli, SparsePauliOp, PauliList, o str.
    tala

    Kung mayroon kang dalawang commuting observable sa iba't ibang PUB ngunit may parehong Circuit, hindi sila tatantiyahin gamit ang parehong sukat. Ang bawat PUB ay kumakatawan sa ibang batayan para sa pagsukat, kaya naman, kinakailangan ang magkahiwalay na mga pagsukat para sa bawat PUB. Upang matiyak na ang mga commuting observable ay natantiya gamit ang parehong pagsukat, dapat silang ipangkat sa loob ng parehong PUB.

  • Isang koleksyon ng mga halaga ng parameter para i-bind ang Circuit. Maaari itong tukuyin bilang isang solong array-like na object kung saan ang huling index ay nasa mga Parameter na object ng Circuit, o maaaring alisin (o katumbas nito, itakda sa None) kung ang Circuit ay walang mga Parameter na object.
  • (Opsyonal) isang target na katumpakan para sa mga inaasahang halaga na tatantiyahin

Sampler PUB​

Para sa Sampler primitive, ang format ng PUB tuple ay naglalaman ng hindi hihigit sa tatlong halaga:

  • Isang solong QuantumCircuit, na maaaring maglaman ng isa o higit pang mga Parameter na object Tandaan: Ang mga Circuit na ito ay dapat ding maglaman ng mga tagubilin sa pagsukat para sa bawat Qubit na susukatin.
  • Isang koleksyon ng mga halaga ng parameter para i-bind ang Circuit laban sa θk\theta_k (kailangan lamang kung may mga Parameter na object na ginagamit na dapat i-bind sa runtime)
  • (Opsyonal) bilang ng mga shot para sukatin ang Circuit

Ang sumusunod na code ay nagpapakita ng isang halimbawa ng set ng mga vectorized input sa Estimator primitive at pinapatakbo ang mga ito sa isang IBM® backend bilang isang solong RuntimeJobV2 na object.

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
from qiskit.circuit import (
Parameter,
QuantumCircuit,
ClassicalRegister,
QuantumRegister,
)
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp
from qiskit.primitives.containers import BitArray

from qiskit_ibm_runtime import (
QiskitRuntimeService,
EstimatorV2 as Estimator,
SamplerV2 as Sampler,
)

import numpy as np

# Instantiate runtime service and get
# the least busy backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Define a circuit with two parameters.
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.ry(Parameter("a"), 0)
circuit.rz(Parameter("b"), 0)
circuit.cx(0, 1)
circuit.h(0)

# Transpile the circuit
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
transpiled_circuit = pm.run(circuit)
layout = transpiled_circuit.layout

# Now define a sweep over parameter values, the last axis of dimension 2 is
# for the two parameters "a" and "b"
params = np.vstack(
[
np.linspace(-np.pi, np.pi, 100),
np.linspace(-4 * np.pi, 4 * np.pi, 100),
]
).T

# Define three observables. The inner length-1 lists cause this array of
# observables to have shape (3, 1), rather than shape (3,) if they were
# omitted.
observables = [
[SparsePauliOp(["XX", "IY"], [0.5, 0.5])],
[SparsePauliOp("XX")],
[SparsePauliOp("IY")],
]
# Apply the same layout as the transpiled circuit.
observables = [
[observable.apply_layout(layout) for observable in observable_set]
for observable_set in observables
]

# Estimate the expectation value for all 300 combinations of observables
# and parameter values, where the pub result will have shape (3, 100).
#
# This shape is due to our array of parameter bindings having shape
# (100, 2), combined with our array of observables having shape (3, 1).
estimator_pub = (transpiled_circuit, observables, params)

# Instantiate the new estimator object, then run the transpiled circuit
# using the set of parameters and observables.
estimator = Estimator(mode=backend)
job = estimator.run([estimator_pub])
result = job.result()

Mga patakaran sa broadcasting​

Ang mga PUB ay nag-aahon ng mga elemento mula sa maraming array (mga observable at mga halaga ng parameter) sa pamamagitan ng pagsunod sa parehong mga patakaran sa broadcasting ng NumPy. Ang seksyong ito ay maikling buod ng mga patakarang iyon. Para sa detalyadong paliwanag, tingnan ang dokumentasyon ng broadcasting rules ng NumPy.

Mga patakaran:

  • Ang mga input array ay hindi kailangang magkaroon ng parehong bilang ng mga dimensyon.
    • Ang resulting array ay magkakaroon ng parehong bilang ng mga dimensyon katulad ng input array na may pinakamalaking dimensyon.
    • Ang laki ng bawat dimensyon ay ang pinakamalaking laki ng katumbas na dimensyon.
    • Ang mga nawawalang dimensyon ay ipinapalagay na may laki na isa.
  • Ang mga paghahambing ng hugis ay nagsisimula sa pinaka-kanang dimensyon at nagpapatuloy sa kaliwa.
  • Ang dalawang dimensyon ay tugma kung ang kanilang mga laki ay pantay o kung isa sa kanila ay 1.

Mga halimbawa ng mga pares ng array na nag-broadcast:

A1     (1d array):      1
A2 (2d array): 3 x 5
Result (2d array): 3 x 5

A1 (3d array): 11 x 2 x 7
A2 (3d array): 11 x 1 x 7
Result (3d array): 11 x 2 x 7

Mga halimbawa ng mga pares ng array na hindi nag-broadcast:

A1     (1d array):  5
A2 (1d array): 3

A1 (2d array): 2 x 1
A2 (3d array): 6 x 5 x 4 # This would work if the middle dimension were 2, but it is 5.

Ang EstimatorV2 ay nagbabalik ng isang tinatantiyahang inaasahang halaga para sa bawat elemento ng broadcasted shape.

Narito ang ilang halimbawa ng mga karaniwang pattern na ipinahayag sa mga termino ng array broadcasting. Ang kanilang kasamang visual na representasyon ay ipinapakita sa sumusunod na figure:

Ang mga set ng halaga ng parameter ay kinakatawan ng n x m na mga array, at ang mga array ng observable ay kinakatawan ng isa o higit pang single-column na mga array. Para sa bawat halimbawa sa nakaraang code, ang mga set ng halaga ng parameter ay pinagsama sa kanilang observable array upang lumikha ng mga resulting na tinatantiyahang inaasahang halaga.

  • Halimbawa 1: (broadcast single observable) ay may set ng halaga ng parameter na isang 5x1 na array at isang 1x1 na observables array. Ang isang item sa observables array ay pinagsama sa bawat item sa set ng halaga ng parameter upang lumikha ng isang solong 5x1 na array kung saan ang bawat item ay isang kombinasyon ng orihinal na item sa set ng halaga ng parameter kasama ang item sa observables array.

  • Halimbawa 2: (zip) ay may 5x1 na set ng halaga ng parameter at isang 5x1 na observables array. Ang output ay isang 5x1 na array kung saan ang bawat item ay isang kombinasyon ng ika-n na item sa set ng halaga ng parameter kasama ang ika-n na item sa observables array.

  • Halimbawa 3: (outer/product) ay may 1x6 na set ng halaga ng parameter at isang 4x1 na observables array. Ang kanilang kombinasyon ay nagbubunga ng isang 4x6 na array na nilikha sa pamamagitan ng pagsasama ng bawat item sa set ng halaga ng parameter sa bawat item sa observables array, kaya ang bawat halaga ng parameter ay nagiging isang buong column sa output.

  • Halimbawa 4: (Standard nd generalization) ay may 3x6 na array ng set ng halaga ng parameter at dalawang 3x1 na observables array. Pinagsama ang mga ito upang lumikha ng dalawang 3x6 na output array sa paraang katulad ng nakaraang halimbawa.

Ang imahe na ito ay nagpapakita ng ilang visual na representasyon ng array broadcasting

# Broadcast single observable
parameter_values = np.random.uniform(size=(5,)) # shape (5,)
observables = SparsePauliOp("ZZZ") # shape ()
# >> pub result has shape (5,)

# Zip
parameter_values = np.random.uniform(size=(5,)) # shape (5,)
observables = [
SparsePauliOp(pauli) for pauli in ["III", "XXX", "YYY", "ZZZ", "XYZ"]
] # shape (5,)
# >> pub result has shape (5,)

# Outer/Product
parameter_values = np.random.uniform(size=(1, 6)) # shape (1, 6)
observables = [
[SparsePauliOp(pauli)] for pauli in ["III", "XXX", "YYY", "ZZZ"]
] # shape (4, 1)
# >> pub result has shape (4, 6)

# Standard nd generalization
parameter_values = np.random.uniform(size=(3, 6)) # shape (3, 6)
observables = [
[
[SparsePauliOp(["XII"])],
[SparsePauliOp(["IXI"])],
[SparsePauliOp(["IIX"])],
],
[
[SparsePauliOp(["ZII"])],
[SparsePauliOp(["IZI"])],
[SparsePauliOp(["IIZ"])],
],
] # shape (2, 3, 1)
# >> pub result has shape (2, 3, 6)
SparsePauliOp

Ang bawat SparsePauliOp ay binibilang bilang isang solong elemento sa kontekstong ito, anuman ang bilang ng mga Pauli na nasa SparsePauliOp. Kaya, para sa layunin ng mga patakarang ito sa broadcasting, lahat ng sumusunod na elemento ay may parehong hugis:

a = SparsePauliOp("Z") # shape ()
b = SparsePauliOp("IIIIZXYIZ") # shape ()
c = SparsePauliOp.from_list(["XX", "XY", "IZ"]) # shape ()

Ang mga sumusunod na listahan ng mga operator, habang katumbas sa mga tuntunin ng impormasyong nilalaman, ay may iba't ibang hugis:

list1 = SparsePauliOp.from_list(["XX", "XY", "IZ"]) # shape ()
list2 = [SparsePauliOp("XX"), SparsePauliOp("XY"), SparsePauliOp("IZ")] # shape (3, )

Pangkalahatang-ideya ng mga output ng primitive​

Kapag naipadala na ang isa o higit pang PUB sa isang QPU para sa pagpapatupad at matagumpay na natapos ang isang job, ang data ay ibinabalik bilang isang PrimitiveResult na container object na ma-a-access sa pamamagitan ng pagtawag sa RuntimeJobV2.result() na method. Ang PrimitiveResult ay naglalaman ng isang iterable na listahan ng mga PubResult na object na naglalaman ng mga resulta ng pagpapatupad para sa bawat PUB. Depende sa primitive na ginamit, ang data na ito ay magiging mga expectation value at ang kanilang mga error bar sa kaso ng Estimator, o mga sample ng output ng Circuit sa kaso ng Sampler.

Ang bawat elemento ng listahang ito ay tumutugma sa bawat PUB na isinumite sa run() na method ng primitive (halimbawa, ang isang job na isinumite nang may 20 PUB ay magbabalik ng isang PrimitiveResult na object na naglalaman ng listahan ng 20 PubResult, isa para sa bawat PUB).

Ang bawat isa sa mga PubResult na object na ito ay may parehong data at metadata na attribute. Ang data attribute ay isang customized na DataBin na naglalaman ng mga aktwal na halaga ng sukat, mga standard deviation, at iba pa. Ang DataBin na ito ay may iba't ibang attribute depende sa hugis o istruktura ng kaugnay na PUB pati na rin ang mga opsyon sa error mitigation na tinukoy ng primitive na ginamit para isumite ang job (halimbawa, ZNE o PEC). Samantala, ang metadata attribute ay naglalaman ng impormasyon tungkol sa mga opsyon sa runtime at error mitigation na ginamit (ipinapaliwanag sa ibaba sa seksyong Metadata ng resulta ng pahinang ito).

Ang sumusunod ay isang visual na balangkas ng istruktura ng data ng PrimitiveResult:

└── PrimitiveResult
├── PubResult[0]
│ ├── metadata
│ └── data ## In the form of a DataBin object
│ ├── evs
│ │ └── List of estimated expectation values in the shape
| | specified by the first pub
│ └── stds
│ └── List of calculated standard deviations in the
| same shape as above
├── PubResult[1]
| ├── metadata
| └── data ## In the form of a DataBin object
| ├── evs
| │ └── List of estimated expectation values in the shape
| | specified by the second pub
| └── stds
| └── List of calculated standard deviations in the
| same shape as above
├── ...
├── ...
└── ...

Sa madaling salita, ang isang job ay nagbabalik ng isang PrimitiveResult na object at naglalaman ng listahan ng isa o higit pang PubResult na object. Ang mga PubResult na object na ito ay nag-iimbak ng data ng sukat para sa bawat PUB na isinumite sa job.

Ang bawat PubResult ay may iba't ibang format at attribute batay sa uri ng primitive na ginamit para sa job. Ang mga detalye ay ipinaliwanag sa ibaba.

Output ng Estimator​

Ang bawat PubResult para sa Estimator primitive ay naglalaman ng kahit isang array ng mga expectation value (PubResult.data.evs) at mga kaugnay na standard deviation (alinman sa PubResult.data.stds o PubResult.data.ensemble_standard_error depende sa resilience_level na ginamit), ngunit maaaring maglaman ng higit pang data depende sa mga opsyon sa error mitigation na tinukoy.

Ang code snippet sa ibaba ay nagpapaliwanag ng format ng PrimitiveResult (at kaugnay na PubResult) para sa job na ginawa sa itaas.

print(
f"The result of the submitted job had {len(result)} PUB and has a value:\n {result}\n"
)
print(
f"The associated PubResult of this job has the following data bins:\n {result[0].data}\n"
)
print(f"And this DataBin has attributes: {result[0].data.keys()}")
print(
"Recall that this shape is due to our array of parameter binding sets having shape (100, 2) -- where 2 is the\n\
number of parameters in the circuit -- combined with our array of observables having shape (3, 1). \n"
)
print(
f"The expectation values measured from this PUB are: \n{result[0].data.evs}"
)
The result of the submitted job had 1 PUB and has a value:
PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(3, 100), dtype=float64>), stds=np.ndarray(<shape=(3, 100), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(3, 100), dtype=float64>), shape=(3, 100)), metadata={'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32})], metadata={'dynamical_decoupling': {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'}, 'twirling': {'enable_gates': False, 'enable_measure': True, 'num_randomizations': 'auto', 'shots_per_randomization': 'auto', 'interleave_randomizations': True, 'strategy': 'active-accum'}, 'resilience': {'measure_mitigation': True, 'zne_mitigation': False, 'pec_mitigation': False}, 'version': 2})

The associated PubResult of this job has the following data bins:
DataBin(evs=np.ndarray(<shape=(3, 100), dtype=float64>), stds=np.ndarray(<shape=(3, 100), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(3, 100), dtype=float64>), shape=(3, 100))

And this DataBin has attributes: dict_keys(['evs', 'stds', 'ensemble_standard_error'])
Recall that this shape is due to our array of parameter binding sets having shape (100, 2) -- where 2 is the
number of parameters in the circuit -- combined with our array of observables having shape (3, 1).

The expectation values measured from this PUB are:
[[ 0.00948597 0.12163221 0.29100944 0.40535344 0.46625814 0.54716103
0.57690846 0.59809047 0.5784682 0.50924868 0.4579837 0.40035644
0.37174056 0.32887613 0.25850853 0.26396412 0.25852429 0.26074166
0.29282485 0.34388535 0.37368314 0.43562138 0.46912323 0.51955146
0.54430185 0.55467261 0.5162183 0.52744696 0.47261781 0.42613541
0.35400013 0.33217125 0.29600426 0.27561903 0.25307754 0.25672088
0.28783701 0.36612701 0.40433263 0.44428286 0.51028376 0.55034507
0.55979913 0.57160124 0.54127534 0.49753533 0.42942659 0.32552331
0.20215918 0.04303087 -0.08115732 -0.18473659 -0.34015892 -0.44489319
-0.49112115 -0.54588034 -0.60601287 -0.55869218 -0.53353861 -0.51628053
-0.44978534 -0.38090252 -0.32481576 -0.28832245 -0.27057547 -0.26542929
-0.27054473 -0.29367389 -0.31531828 -0.38462352 -0.40276794 -0.47168997
-0.48548191 -0.5382924 -0.52716406 -0.53277032 -0.50776933 -0.48512907
-0.44335198 -0.38756463 -0.34438156 -0.29199194 -0.2729216 -0.24602918
-0.23527174 -0.3019153 -0.35159518 -0.38303379 -0.42434541 -0.47743033
-0.54652609 -0.5877912 -0.59175701 -0.57386895 -0.56416812 -0.48022381
-0.3853372 -0.2639702 -0.12030502 0.02081148]
[ 0.00581765 0.0552677 0.15998546 0.20725389 0.25452232 0.34178711
0.39196437 0.47050268 0.50031815 0.527952 0.57231161 0.64066903
0.72429779 0.77011181 0.78174711 0.86610308 0.88646487 0.91337151
0.94245978 0.98100173 0.97372966 1.00936279 1.01881647 1.0544496
1.01954368 1.03699664 0.99845469 1.03845105 1.00936279 1.00354513
0.95409508 0.95264067 0.91264431 0.91846196 0.8355604 0.80283611
0.77956549 0.74102354 0.69520953 0.64575948 0.58976457 0.53231524
0.43996 0.3956004 0.32069812 0.27706572 0.22470684 0.16653032
0.07272066 -0.00218162 -0.05817653 -0.06253977 -0.15853104 -0.25015908
-0.28506499 -0.34251432 -0.44359604 -0.44432324 -0.53158804 -0.60285429
-0.637033 -0.67630215 -0.71266249 -0.76793019 -0.81519862 -0.86464867
-0.90173621 -0.93155168 -0.9337333 -0.98245614 -0.99627307 -1.01518044
-1.01590764 -1.04863194 -1.00499955 -1.02827016 -1.01663485 -1.0108172
-1.02317971 -0.97518407 -0.96500318 -0.94682302 -0.901009 -0.87846559
-0.79556404 -0.84937733 -0.78101991 -0.73811472 -0.65521316 -0.57667485
-0.59921825 -0.49813653 -0.44577766 -0.36505772 -0.33524225 -0.25888556
-0.21161713 -0.12289792 -0.03781474 0.00654486]
[ 0.01315429 0.18799671 0.42203343 0.603453 0.67799397 0.75253494
0.76185256 0.72567827 0.65661825 0.49054535 0.3436558 0.16004385
0.01918334 -0.11235955 -0.26473006 -0.33817484 -0.36941628 -0.39188819
-0.35681008 -0.29323102 -0.22636339 -0.13812003 -0.08057002 -0.01534667
0.06906002 0.07234859 0.03398191 0.01644286 -0.06412716 -0.15127432
-0.24609482 -0.28829816 -0.32063579 -0.3672239 -0.32940532 -0.28939435
-0.20389148 -0.00876953 0.11345574 0.24280625 0.43080296 0.5683749
0.67963826 0.74760208 0.76185256 0.71800493 0.63414634 0.48451631
0.3315977 0.08824335 -0.10413812 -0.30693341 -0.52178679 -0.6396273
-0.69717731 -0.74924637 -0.76842971 -0.67306111 -0.53548918 -0.42970677
-0.26253768 -0.08550288 0.06303097 0.19128528 0.27404768 0.33379008
0.36064675 0.34420389 0.30309674 0.2132091 0.19073719 0.07180049
0.04494382 -0.02795286 -0.04932858 -0.03727049 0.00109619 0.04055906
0.13647575 0.20005481 0.27624007 0.36283913 0.3551658 0.38640723
0.32502055 0.24554673 0.07782954 -0.02795286 -0.19347767 -0.3781858
-0.49383393 -0.67744588 -0.73773637 -0.78268019 -0.793094 -0.70156207
-0.55905728 -0.40504248 -0.20279529 0.0350781 ]]

Paano kinakalkula ng Estimator ang error​

Bukod sa estimate ng mean ng mga observable na ipinasa sa mga input na PUB (ang field na evs ng DataBin), sinisikap din ng Estimator na maghatid ng estimate ng error na kaugnay ng mga expectation value na iyon. Lahat ng query sa estimator ay magpapopulate ng field na stds ng isang quantity na katulad ng standard error of the mean para sa bawat expectation value, ngunit ang ilang opsyon sa error mitigation ay nagbibigay ng karagdagang impormasyon, tulad ng ensemble_standard_error.

Isaalang-alang ang isang observable na O\mathcal{O}. Sa kawalan ng ZNE, maaari mong isipin ang bawat shot ng Estimator execution bilang nagbibigay ng isang point estimate ng expectation value na ⟨O⟩\langle \mathcal{O} \rangle. Kung ang mga point estimate ay nasa vector na Os, ang halagang ibinalik sa ensemble_standard_error ay katumbas ng sumusunod (kung saan ang σO\sigma_{\mathcal{O}} ay ang standard deviation ng estimate ng expectation value at ang NshotsN_{shots} ay ang bilang ng mga shot):

σONshots,\frac{ \sigma_{\mathcal{O}} }{ \sqrt{N_{shots}} },

na itinuturing ang lahat ng shot bilang bahagi ng isang ensemble. Kung humiling ka ng gate twirling (twirling.enable_gates = True), maaari mong ayusin ang mga point estimate ng ⟨O⟩\langle \mathcal{O} \rangle sa mga set na nagbabahagi ng isang karaniwang twirl. Tawaging O_twirls ang mga set ng mga estimate na ito, at mayroon silang num_randomizations (bilang ng mga twirl). Ang stds ay ang standard error of the mean ng O_twirls, tulad ng

σONtwirls,\frac{ \sigma_{\mathcal{O}} }{ \sqrt{N_{twirls}} },

kung saan ang σO\sigma_{\mathcal{O}} ay ang standard deviation ng O_twirls at ang NtwirlsN_{twirls} ay ang bilang ng mga twirl. Kapag hindi mo pinagana ang twirling, ang stds at ensemble_standard_error ay magkapantay.

Kung pinagana mo ang ZNE, ang mga stds na inilarawan sa itaas ay magiging mga timbang sa isang non-linear regression sa isang extrapolator model. Ang halagang ibinabalik sa stds sa kasong ito ay ang uncertainty ng fit model na sinusuri sa noise factor na zero. Kapag may mahinang fit, o malaking uncertainty sa fit, ang naiulat na stds ay maaaring maging napakalaki. Kapag pinagana ang ZNE, ang pub_result.data.evs_noise_factors at pub_result.data.stds_noise_factors ay mapupunan din, upang maaari kang gumawa ng sarili mong extrapolation.

Output ng Sampler​

Kapag matagumpay na natapos ang isang Sampler job, ang ibinalik na PrimitiveResult na object ay naglalaman ng listahan ng mga SamplerPubResult, isa bawat PUB. Ang mga data bin ng mga SamplerPubResult na object na ito ay mga dict-like na object na naglalaman ng isang BitArray bawat ClassicalRegister sa Circuit.

Ang klase ng BitArray ay isang container para sa ordered na shot data. Sa mas detalyadong pagpapaliwanag, iniiimbak nito ang mga na-sample na bitstring bilang bytes sa loob ng isang two-dimensional array. Ang kaliwang pinaka-axis ng array na ito ay tumatakbo sa mga ordered na shot, habang ang kanang pinaka-axis ay tumatakbo sa mga byte.

Bilang unang halimbawa, tingnan natin ang sumusunod na sampung Qubit na Circuit:

# generate a ten-qubit GHZ circuit
circuit = QuantumCircuit(10)
circuit.h(0)
circuit.cx(range(0, 9), range(1, 10))

# append measurements with the `measure_all` method
circuit.measure_all()

# transpile the circuit
transpiled_circuit = pm.run(circuit)

# run the Sampler job and retrieve the results
sampler = Sampler(mode=backend)
job = sampler.run([transpiled_circuit])
result = job.result()

# the data bin contains one BitArray
data = result[0].data
print(f"Databin: {data}\n")

# to access the BitArray, use the key "meas", which is the default name of
# the classical register when this is added by the `measure_all` method
array = data.meas
print(f"BitArray: {array}\n")
print(f"The shape of register `meas` is {data.meas.array.shape}.\n")
print(f"The bytes in register `alpha`, shot by shot:\n{data.meas.array}\n")
Databin: DataBin(meas=BitArray(<shape=(), num_shots=4096, num_bits=10>))

BitArray: BitArray(<shape=(), num_shots=4096, num_bits=10>)

The shape of register `meas` is (4096, 2).

The bytes in register `alpha`, shot by shot:
[[ 3 254]
[ 0 0]
[ 3 255]
...
[ 0 0]
[ 3 255]
[ 0 0]]

Minsan ay maginhawa ang mag-convert mula sa bytes format sa BitArray patungong mga bitstring. Ang get_count na method ay nagbabalik ng isang dictionary na nagmamapa ng mga bitstring sa bilang ng beses na nangyari ang mga ito.

# optionally, convert away from the native BitArray format to a dictionary format
counts = data.meas.get_counts()
print(f"Counts: {counts}")
Counts: {'1111111110': 199, '0000000000': 1337, '1111111111': 1052, '1111111000': 33, '1110000000': 65, '1100100000': 2, '1100000000': 25, '0010001110': 1, '0000000011': 30, '1111111011': 58, '1111111010': 25, '0000000110': 7, '0010000001': 11, '0000000001': 179, '1110111110': 6, '1111110000': 33, '1111101111': 49, '1110111111': 40, '0000111010': 2, '0100000000': 35, '0000000010': 51, '0000100000': 31, '0110000000': 7, '0000001111': 22, '1111111100': 24, '1011111110': 5, '0001111111': 58, '0000111111': 24, '1111101110': 10, '0000010001': 5, '0000001001': 2, '0011111111': 38, '0000001000': 11, '1111100000': 34, '0111111111': 45, '0000000100': 18, '0000000101': 2, '1011111111': 11, '1110000001': 13, '1101111000': 1, '0010000000': 52, '0000010000': 17, '0000011111': 15, '1110100001': 1, '0111111110': 9, '0000000111': 19, '1101111111': 15, '1111110111': 17, '0011111110': 5, '0001101110': 1, '0111111011': 6, '0100001000': 2, '0010001111': 1, '1111011000': 1, '0000111110': 4, '0011110010': 1, '1110111100': 2, '1111000000': 8, '1111111101': 27, '0000011110': 6, '0001000000': 5, '1111010000': 3, '0000011011': 4, '0001111110': 9, '1111011110': 6, '1110001111': 2, '0100000001': 7, '1110111011': 3, '1111101101': 2, '1101111110': 5, '1110000010': 7, '0111111000': 1, '1110111000': 1, '0000100001': 2, '1110100000': 6, '1000000001': 2, '0001011111': 1, '0000010111': 1, '1011111100': 1, '0111110000': 5, '0110111111': 2, '0010000010': 1, '0001111100': 4, '0011111001': 2, '1111110011': 1, '1110000011': 5, '0000001011': 8, '0100000010': 3, '1111011111': 13, '0010111000': 2, '0100111110': 1, '1111101000': 2, '1110110000': 2, '1100000001': 1, '0001110000': 3, '1011101111': 2, '1111000001': 2, '1111110001': 8, '1111110110': 4, '1100000010': 3, '0011000000': 2, '1110011111': 3, '0011101111': 3, '0010010000': 2, '0000100010': 1, '1100001110': 1, '0001111011': 4, '1010000000': 3, '0000001110': 5, '0000001010': 2, '0011111011': 4, '0100100000': 2, '1111110100': 1, '1111100011': 3, '0000110110': 1, '0001111101': 2, '1111100001': 2, '1000000000': 5, '0010000011': 3, '0010011111': 3, '0100001111': 1, '0100000111': 1, '1011101110': 1, '0011110111': 1, '1100000111': 1, '1100111111': 3, '0001111010': 1, '1101111011': 1, '0111111100': 2, '0100000110': 2, '0100000011': 2, '0001101111': 3, '0001000001': 1, '1111110010': 1, '0010100000': 1, '0011100000': 4, '1010001111': 1, '0101111111': 2, '1111101001': 1, '1110111101': 1, '0000011101': 1, '1110001000': 2, '0001111001': 1, '0101000000': 1, '1111111001': 5, '0001110111': 2, '0000111001': 1, '0100001011': 1, '0000010011': 1, '1011110111': 1, '0011110001': 1, '0000001100': 2, '0111010111': 1, '0001101011': 1, '1110010000': 2, '1110000100': 1, '0010111111': 3, '0111011100': 1, '1010001000': 1, '0000101110': 1, '0011111100': 2, '0000111100': 2, '1110011110': 1, '0011111000': 2, '0110100000': 1, '1001101111': 1, '1011000000': 1, '1101000000': 1, '1110001011': 1, '1110110111': 1, '0110111110': 1, '0011011111': 1, '0111100000': 1, '0000110111': 1, '0000010010': 2, '1111101100': 2, '1111011101': 1, '1101100000': 1, '0010111110': 1, '1101101110': 1, '1111001111': 1, '1101111100': 1, '1011111010': 1, '0001100000': 1, '1101110111': 1, '1100001011': 1}

Kapag ang isang Circuit ay naglalaman ng higit sa isang classical register, ang mga resulta ay naka-imbak sa iba't ibang BitArray na object. Ang sumusunod na halimbawa ay binabago ang nakaraang snippet sa pamamagitan ng paghahati ng classical register sa dalawang magkaibang register:

# generate a ten-qubit GHZ circuit with two classical registers
circuit = QuantumCircuit(
qreg := QuantumRegister(10),
alpha := ClassicalRegister(1, "alpha"),
beta := ClassicalRegister(9, "beta"),
)
circuit.h(0)
circuit.cx(range(0, 9), range(1, 10))

# append measurements with the `measure_all` method
circuit.measure([0], alpha)
circuit.measure(range(1, 10), beta)

# transpile the circuit
transpiled_circuit = pm.run(circuit)

# run the Sampler job and retrieve the results
sampler = Sampler(mode=backend)
job = sampler.run([transpiled_circuit])
result = job.result()

# the data bin contains two BitArrays, one per register, and can be accessed
# as attributes using the registers' names
data = result[0].data
print(f"BitArray for register 'alpha': {data.alpha}")
print(f"BitArray for register 'beta': {data.beta}")
BitArray for register 'alpha': BitArray(<shape=(), num_shots=4096, num_bits=1>)
BitArray for register 'beta': BitArray(<shape=(), num_shots=4096, num_bits=9>)

Paggamit ng mga BitArray object para sa mahusay na post-processing​

Dahil ang mga array ay karaniwang mas maganda ang performance kumpara sa mga dictionary, ipinapayo na isagawa ang anumang post-processing nang direkta sa mga BitArray na object kaysa sa mga dictionary ng count. Ang klase ng BitArray ay nag-aalok ng iba't ibang method para magsagawa ng ilang karaniwang operasyon sa post-processing:

print(f"The shape of register `alpha` is {data.alpha.array.shape}.")
print(f"The bytes in register `alpha`, shot by shot:\n{data.alpha.array}\n")

print(f"The shape of register `beta` is {data.beta.array.shape}.")
print(f"The bytes in register `beta`, shot by shot:\n{data.beta.array}\n")

# post-select the bitstrings of `beta` based on having sampled "1" in `alpha`
mask = data.alpha.array == "0b1"
ps_beta = data.beta[mask[:, 0]]
print(f"The shape of `beta` after post-selection is {ps_beta.array.shape}.")
print(f"The bytes in `beta` after post-selection:\n{ps_beta.array}")

# get a slice of `beta` to retrieve the first three bits
beta_sl_bits = data.beta.slice_bits([0, 1, 2])
print(
f"The shape of `beta` after bit-wise slicing is {beta_sl_bits.array.shape}."
)
print(f"The bytes in `beta` after bit-wise slicing:\n{beta_sl_bits.array}\n")

# get a slice of `beta` to retrieve the bytes of the first five shots
beta_sl_shots = data.beta.slice_shots([0, 1, 2, 3, 4])
print(
f"The shape of `beta` after shot-wise slicing is {beta_sl_shots.array.shape}."
)
print(
f"The bytes in `beta` after shot-wise slicing:\n{beta_sl_shots.array}\n"
)

# calculate the expectation value of diagonal operators on `beta`
ops = [SparsePauliOp("ZZZZZZZZZ"), SparsePauliOp("IIIIIIIIZ")]
exp_vals = data.beta.expectation_values(ops)
for o, e in zip(ops, exp_vals):
print(f"Exp. val. for observable `{o}` is: {e}")

# concatenate the bitstrings in `alpha` and `beta` to "merge" the results of the two
# registers
merged_results = BitArray.concatenate_bits([data.alpha, data.beta])
print(f"\nThe shape of the merged results is {merged_results.array.shape}.")
print(f"The bytes of the merged results:\n{merged_results.array}\n")
The shape of register `alpha` is (4096, 1).
The bytes in register `alpha`, shot by shot:
[[1]
[1]
[1]
...
[0]
[0]
[1]]

The shape of register `beta` is (4096, 2).
The bytes in register `beta`, shot by shot:
[[ 0 135]
[ 0 247]
[ 1 247]
...
[ 0 0]
[ 1 224]
[ 1 255]]

The shape of `beta` after post-selection is (0, 2).
The bytes in `beta` after post-selection:
[]
The shape of `beta` after bit-wise slicing is (4096, 1).
The bytes in `beta` after bit-wise slicing:
[[7]
[7]
[7]
...
[0]
[0]
[7]]

The shape of `beta` after shot-wise slicing is (5, 2).
The bytes in `beta` after shot-wise slicing:
[[ 0 135]
[ 0 247]
[ 1 247]
[ 1 128]
[ 1 255]]

Exp. val. for observable `SparsePauliOp(['ZZZZZZZZZ'],
coeffs=[1.+0.j])` is: 0.068359375
Exp. val. for observable `SparsePauliOp(['IIIIIIIIZ'],
coeffs=[1.+0.j])` is: 0.06396484375

The shape of the merged results is (4096, 2).
The bytes of the merged results:
[[ 1 15]
[ 1 239]
[ 3 239]
...
[ 0 0]
[ 3 192]
[ 3 255]]

Metadata ng resulta​

Bukod sa mga resulta ng pagpapatupad, ang parehong PrimitiveResult at PubResult na object ay naglalaman ng isang metadata attribute tungkol sa job na isinumite. Ang metadata na naglalaman ng impormasyon para sa lahat ng isinumiteng PUB (tulad ng iba't ibang opsyon sa runtime na available) ay matatagpuan sa PrimitiveResult.metatada, habang ang metadata na tukoy sa bawat PUB ay matatagpuan sa PubResult.metadata.

tala

Sa field ng metadata, ang mga implementasyon ng primitive ay maaaring magbalik ng anumang impormasyon tungkol sa pagpapatupad na may kaugnayan sa kanila, at walang mga key-value pair na ginagarantiyahan ng base primitive. Kaya naman, ang ibinalik na metadata ay maaaring magkaiba sa iba't ibang implementasyon ng primitive.

# Print out the results metadata
print("The metadata of the PrimitiveResult is:")
for key, val in result.metadata.items():
print(f"'{key}' : {val},")

print("\nThe metadata of the PubResult result is:")
for key, val in result[0].metadata.items():
print(f"'{key}' : {val},")
The metadata of the PrimitiveResult is:
'execution' : {'execution_spans': ExecutionSpans([DoubleSliceSpan(<start='2026-01-15 08:07:33', stop='2026-01-15 08:07:36', size=4096>)])},
'version' : 2,

The metadata of the PubResult result is:
'circuit_metadata' : {},

Para sa mga Sampler job, maaari mo ring suriin ang metadata ng resulta upang maunawaan kung kailan naisakatuparan ang ilang data; ito ay tinatawag na execution span.