Vstupy a výstupy primitiv
Beta verze nového modelu spouštění je nyní k dispozici. Řízený model spouštění poskytuje větší flexibilitu při přizpůsobování pracovního postupu pro zmírnění chyb. Více informací najdeš v průvodci Řízený model spouštění.
Verze balíčků
Kód na této stránce byl vyvinut s použitím následujících požadavků. Doporučujeme používat tyto verze nebo novější.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
Tato stránka poskytuje přehled vstupů a výstupů primitiv Qiskit Runtime, které spouštějí úlohy na výpočetních zdrojích IBM Quantum®. Tato primitiva ti umožňují efektivně definovat vektorizované úlohy pomocí datové struktury zvané Primitive Unified Bloc (PUB). Tyto PUBs jsou základní jednotkou práce, kterou QPU potřebuje ke spuštění těchto úloh. Používají se jako vstupy do metody run() primitiv Sampler a Estimator, které spustí definovanou úlohu jako job. Po dokončení jobu jsou výsledky vráceny ve formátu, který závisí jak na použitých PUBs, tak na možnostech runtime zadaných pro primitiva Sampler nebo Estimator.
Přehled PUBs
Při volání metody run() primitiva je hlavním požadovaným argumentem list jedné nebo více n-tic – jedna pro každý Circuit spouštěný primitivem. Každá z těchto n-tic je považována za PUB a požadované prvky každé n-tice v seznamu závisí na použitém primitivu. Data poskytnutá těmto n-ticím mohou být také uspořádána v různých tvarech, což umožňuje flexibilitu v úloze prostřednictvím broadcastingu – jehož pravidla jsou popsána v následující části.
Estimator PUB
Pro primitiv Estimator by formát PUB měl obsahovat nejvýše čtyři hodnoty:
- Jediný
QuantumCircuit, který může obsahovat jeden nebo více objektůParameter - Seznam jednoho nebo více pozorovatelných veličin, které určují střední hodnoty k odhadnutí, uspořádaných do pole (například jedna pozorovatelná veličina reprezentovaná jako 0-d pole, seznam pozorovatelných veličin jako 1-d pole atd.). Data mohou být v libovolném formátu
ObservablesArrayLike, napříkladPauli,SparsePauliOp,PauliListnebostr.poznámkaPokud máš dvě komutující pozorovatelné veličiny v různých PUBs, ale se stejným Circuit, nebudou odhadovány pomocí stejného měření. Každý PUB představuje jiný základ pro měření, a proto jsou pro každý PUB nutná samostatná měření. Aby byly komutující pozorovatelné veličiny odhadovány pomocí stejného měření, musí být seskupeny v rámci stejného PUB.
- Kolekce hodnot parametrů, na které se Circuit naváže. Tuto kolekci lze zadat jako jediný objekt podobný poli, kde poslední index odpovídá objektům
ParameterCircuit, nebo ji lze vynechat (případně nastavit naNone), pokud Circuit neobsahuje žádné objektyParameter. - (Volitelně) cílová přesnost pro odhadování středních hodnot
Sampler PUB
Pro primitiv Sampler obsahuje formát n-tice PUB nejvýše tři hodnoty:
- Jediný
QuantumCircuit, který může obsahovat jeden nebo více objektůParameterPoznámka: Tyto Circuits by měly také obsahovat instrukce pro měření každého z Qubitů, které mají být vzorkovány. - Kolekce hodnot parametrů, na které se Circuit naváže (potřebná pouze tehdy, pokud jsou použity nějaké objekty
Parameter, které musí být navázány za běhu) - (Volitelně) počet shotů, se kterými se Circuit změří
Následující kód demonstruje příkladnou sadu vektorizovaných vstupů pro primitiv Estimator a spouští je na backend IBM® jako jediný objekt RuntimeJobV2 .
# 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()
Pravidla broadcastingu
PUBy agregují prvky z více polí (observables a hodnoty parametrů) podle stejných pravidel broadcastingu jako NumPy. Tato sekce tato pravidla stručně shrnuje. Podrobné vysvětlení najdeš v dokumentaci NumPy k pravidlům broadcastingu.
Pravidla:
- Vstupní pole nemusí mít stejný počet dimenzí.
- Výsledné pole bude mít stejný počet dimenzí jako vstupní pole s největším počtem dimenzí.
- Velikost každé dimenze je největší velikost odpovídající dimenze.
- Chybějící dimenze se považují za dimenze o velikosti jedna.
- Porovnávání tvarů začíná od nejpravější dimenze a pokračuje doleva.
- Dvě dimenze jsou kompatibilní, pokud jsou jejich velikosti stejné nebo pokud je jedna z nich 1.
Příklady dvojic polí, u nichž broadcasting funguje:
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
Příklady dvojic polí, u nichž broadcasting nefunguje:
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.
EstimatorV2 vrátí jeden odhad střední hodnoty pro každý prvek broadcastovaného tvaru.
Níže jsou uvedeny příklady běžných vzorů vyjádřených pomocí broadcastingu polí. Jejich vizu ální reprezentace je zobrazena na obrázku, který za nimi následuje:
Sady hodnot parametrů jsou reprezentovány poli n x m a pole observables jsou reprezentovány jedním nebo více jednosloupcovými poli. Pro každý příklad v předchozím kódu jsou sady hodnot parametrů kombinovány s příslušným polem observables za účelem vytvoření výsledných odhadů střední hodnoty.
-
Příklad 1: (broadcast jednoho observable) má sadu hodnot parametrů tvaru 5x1 a pole observables tvaru 1x1. Jeden prvek v poli observables je kombinován s každým prvkem sady hodnot parametrů, čímž vznikne jedno pole 5x1, kde každý prvek je kombinací původního prvku sady hodnot parametrů s prvkem pole observables.
-
Příklad 2: (zip) má sadu hodnot parametrů 5x1 a pole observables 5x1. Výstupem je pole 5x1, kde každý prvek je kombinací n-tého prvku sady hodnot parametrů s n-tým prvkem pole observables.
-
Příklad 3: (outer/product) má sadu hodnot parametrů 1x6 a pole observables 4x1. Jejich kombinací vznikne pole 4x6, vytvořené zkombinováním každého prvku sady hodnot parametrů s každým prvkem pole observables – každá hodnota parametru se tak stane celým sloupcem ve výstupu.
-
Příklad 4: (standardní nd zobecnění) má pole sady hodnot parametrů 3x6 a dvě pole observables 3x1. Tato pole se kombinují a vznikají dvě výstupní pole 3x6 podobným způsobem jako v předchozím příkladu.
# 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)
Každý SparsePauliOp se v tomto kontextu počítá jako jeden prvek, bez ohledu na počet Pauliho operátorů, které SparsePauliOp obsahuje. Pro účely těchto pravidel broadcastingu mají tedy všechny následující prvky stejný tvar:
a = SparsePauliOp("Z") # shape ()
b = SparsePauliOp("IIIIZXYIZ") # shape ()
c = SparsePauliOp.from_list(["XX", "XY", "IZ"]) # shape ()
Následující seznamy operátorů, ačkoli jsou z hlediska obsažených informací ekvivalentní, mají různé tvary:
list1 = SparsePauliOp.from_list(["XX", "XY", "IZ"]) # shape ()
list2 = [SparsePauliOp("XX"), SparsePauliOp("XY"), SparsePauliOp("IZ")] # shape (3, )
Přehled výstupů primitiv
Jakmile jsou jeden nebo více PUBů odeslány na QPU k vykonání a úloha se úspěšně dokončí, data se vrátí jako kontejnerový objekt PrimitiveResult, ke kterému se přistupuje zavoláním metody RuntimeJobV2.result(). PrimitiveResult obsahuje iterovatelný seznam objektů PubResult, které obsahují výsledky vykonání pro každý PUB. Podle použitého primitivu budou tato data buď očekávané hodnoty a jejich chybové úsečky v případě Estimatoru, nebo vzorky výstupu Circuit v případě Sampleru.
Každý prvek tohoto seznamu odpovídá jednomu PUBu odeslanému metodě run() primitivu (například úloha odeslaná s 20 PUBy vrátí objekt PrimitiveResult obsahující seznam 20 PubResultů, přičemž každý odpovídá jednomu PUBu).
Každý z těchto objektů PubResult má atribut data i metadata. Atribut data je přizpůsobený DataBin, který obsahuje skutečné naměřené hodnoty, směrodatné odchylky apod. Tento DataBin má různé atributy v závislosti na tvaru nebo struktuře příslušného PUBu a na možnostech zmírnění chyb zadaných primitivem použitým k odeslání úlohy (například ZNE nebo PEC). Atribut metadata pak obsahuje informace o možnostech běhového prostředí a zmírnění chyb (vysvětleno v sekci Metadata výsledku na této stránce).
Níže je znázorněna vizuální struktura dat PrimitiveResult:
- Výstup Estimatoru
- Výstup Sampleru
└── 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
├── ...
├── ...
└── ...
└── PrimitiveResult
├── PubResult[0]
│ ├── metadata
│ └── data ## In the form of a DataBin object
│ ├── NAME_OF_CLASSICAL_REGISTER
│ │ └── BitArray of count data (default is 'meas')
| |
│ └── NAME_OF_ANOTHER_CLASSICAL_REGISTER
│ └── BitArray of count data (exists only if more than one
| ClassicalRegister was specified in the circuit)
├── PubResult[1]
| ├── metadata
| └── data ## In the form of a DataBin object
| └── NAME_OF_CLASSICAL_REGISTER
| └── BitArray of count data for second pub
├── ...
├── ...
└── ...
Jednoduše řečeno, jedna úloha vrací objekt PrimitiveResult a obsahuje seznam jednoho nebo více objektů PubResult. Tyto objekty PubResult pak uchovávají data měření pro každý PUB, který byl odeslán do úlohy.
Každý PubResult má různé formáty a atributy v závislosti na typu primitivu, který byl pro úlohu použit. Podrobnosti jsou vysvětleny níže.
Výstup Estimatoru
Každý PubResult pro primitiv Estimator obsahuje alespoň pole očekávaných hodnot (PubResult.data.evs) a příslušné směrodatné odchylky (buď PubResult.data.stds, nebo PubResult.data.ensemble_standard_error v závislosti na použitém resilience_level), ale může obsahovat i další data v závislosti na zadaných možnostech zmírnění chyb.
Níže uvedený úryvek kódu popisuje formát PrimitiveResult (a příslušného PubResult) pro výše vytvořenou úlohu.
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 ]]
Jak Estimator počítá chybu
Kromě odhadu střední hodnoty observabilit předaných ve vstupních PUBech (pole evs objektu DataBin) se Estimator snaží dodat také odhad chyby spojené s těmito hodnotami očekávání. Všechny dotazy Estimatoru naplní pole stds hodnotou podobnou standardní chybě střední hodnoty pro každou hodnotu očekávání, ale některé možnosti chybové mitigace produkují další informace, například ensemble_standard_error.
Uvažujme jednu observabilu . Bez použití ZNE si můžeš každý shot provádění Estimatoru představit jako bodový odhad hodnoty očekávání . Pokud jsou bodové odhady uloženy ve vektoru Os, pak hodnota vrácená v ensemble_standard_error je ekvivalentní následujícímu (kde je standardní odchylka odhadu hodnoty očekávání a je počet shotů):
což zachází se všemi shoty jako s částí jediného souboru. Pokud jsi požádal/a o gate twirling (twirling.enable_gates = True), můžeš třídit bodové odhady do skupin sdílejících společný twirl. Tyto skupiny odhadů nazvi O_twirls a je jich num_randomizations (počet twurlů). Pak stds je standardní chyba střední hodnoty O_twirls, jako v
kde je standardní odchylka O_twirls a je počet twurlů. Pokud twirling není povolen, stds a ensemble_standard_error jsou si rovny.
Pokud povolíš ZNE, pak výše popsané stds se stanou vahami v nelineární regresi na extrapolační model. To, co se nakonec vrátí v stds v tomto případě, je nejistota fitovacího modelu vyhodnoceného při nulovém šumovém faktoru. Při špatném fitu nebo velké nejistotě fitu mohou nahlášené stds nabývat velmi vysokých hodnot. Když je ZNE povoleno, jsou také naplněny pub_result.data.evs_noise_factors a pub_result.data.stds_noise_factors, takže si můžeš provést vlastní extrapolaci.
Výstup Sampleru
Po úspěšném dokončení úlohy Sampleru vrácený objekt PrimitiveResult obsahuje seznam SamplerPubResultů, jeden na každý PUB. Datové koše těchto objektů SamplerPubResult jsou objekty podobné slovníkům, které obsahují jeden BitArray pro každý ClassicalRegister v obvodu.
Třída BitArray je kontejner pro uspořádaná data shotů. Konkrétněji ukládá vzorkované bitové řetězce jako bajty ve dvourozměrném poli. Levá osa tohoto pole prochází přes uspořádané shoty, zatímco pravá osa prochází přes bajty.
Jako první příklad se podívejme na následující desetiqubitový 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]]
Někdy je vhodné převést z bajtového formátu v BitArray na bitové řetězce. Metoda get_count vrací slovník mapující bitové řetězce na počet jejich výskytů.
# 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}
Pokud Circuit obsahuje více než jeden klasický registr, výsledky jsou uloženy v různých objektech BitArray. Následující příklad upravuje předchozí ukázku tím, že rozděluje klasický registr do dvou oddělených registrů:
# 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>)
Využití objektů BitArray pro výkonné následné zpracování
Protože pole obecně nabízejí lepší výkon ve srovnání se slovníky, je doporučeno provádět veškeré následné zpracování přímo na objektech BitArray, nikoli na slovnících četností. Třída BitArray nabízí řadu metod pro provádění běžných operací následného zpracování:
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 výsledků
Kromě výsledků spuštění obsahují objekty PrimitiveResult i PubResult atribut metadata o odeslaném úloze. Metadata obsahující informace pro všechny odeslané PUBy (například různé volby runtime) jsou k dispozici v PrimitiveResult.metatada, zatímco metadata specifická pro každý PUB se nacházejí v PubResult.metadata.
V poli metadata mohou implementace primitiv vracet jakékoli informace o spuštění, které jsou pro ně relevantní, a neexistují žádné páry klíč–hodnota, které by byly garantovány základní primitivou. Vrácená metadata se tedy mohou lišit v závislosti na konkrétní implementaci primitiv.
# 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' : {},
U úloh Sampleru můžeš také zkontrolovat metadata výsledku, abys pochopil(a), kdy byla určitá data spuštěna; tomu se říká execution span.