Lewati ke konten utama

Input dan output primitif

Model eksekusi baru, kini dalam rilis beta

Rilis beta dari model eksekusi baru sudah tersedia. Model eksekusi terarah memberikan fleksibilitas lebih saat menyesuaikan alur kerja mitigasi kesalahan kamu. Lihat panduan Model eksekusi terarah untuk informasi lebih lanjut.

Versi paket

Kode di halaman ini dikembangkan menggunakan persyaratan berikut. Kami merekomendasikan menggunakan versi ini atau yang lebih baru.

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

Halaman ini memberikan gambaran umum tentang input dan output dari primitif Qiskit Runtime yang mengeksekusi beban kerja pada sumber daya komputasi IBM Quantum®. Primitif-primitif ini memberi kamu kemampuan untuk mendefinisikan beban kerja yang divektorisasi secara efisien menggunakan struktur data yang dikenal sebagai Primitive Unified Bloc (PUB). PUB ini merupakan unit kerja fundamental yang dibutuhkan QPU untuk mengeksekusi beban kerja tersebut. PUB digunakan sebagai input untuk metode run() pada primitif Sampler dan Estimator, yang mengeksekusi beban kerja yang telah didefinisikan sebagai sebuah job. Kemudian, setelah job selesai, hasilnya dikembalikan dalam format yang bergantung pada PUB yang digunakan serta opsi runtime yang ditentukan dari primitif Sampler atau Estimator.

Gambaran umum PUB​

Saat memanggil metode run() dari sebuah primitif, argumen utama yang diperlukan adalah list berisi satu atau lebih tuple — satu untuk setiap Circuit yang dieksekusi oleh primitif. Setiap tuple ini dianggap sebagai PUB, dan elemen yang diperlukan dalam setiap tuple bergantung pada primitif yang digunakan. Data yang diberikan ke tuple ini juga bisa disusun dalam berbagai bentuk untuk memberikan fleksibilitas dalam beban kerja melalui broadcasting — aturannya dijelaskan di bagian berikut.

Estimator PUB​

Untuk primitif Estimator, format PUB harus berisi paling banyak empat nilai:

  • Satu QuantumCircuit, yang mungkin berisi satu atau lebih objek Parameter
  • Daftar satu atau lebih observable, yang menentukan nilai ekspektasi yang akan diestimasi, disusun dalam array (misalnya, satu observable direpresentasikan sebagai array 0-d, daftar observable sebagai array 1-d, dan seterusnya). Data bisa dalam salah satu format ObservablesArrayLike seperti Pauli, SparsePauliOp, PauliList, atau str.
    catatan

    Jika kamu memiliki dua observable yang saling komuting di PUB berbeda tetapi dengan Circuit yang sama, keduanya tidak akan diestimasi menggunakan pengukuran yang sama. Setiap PUB merepresentasikan basis pengukuran yang berbeda, sehingga pengukuran terpisah diperlukan untuk setiap PUB. Untuk memastikan observable yang komuting diestimasi menggunakan pengukuran yang sama, keduanya harus dikelompokkan dalam PUB yang sama.

  • Kumpulan nilai parameter untuk diikat ke Circuit. Ini bisa ditentukan sebagai objek tunggal mirip array di mana indeks terakhir mengacu pada objek Parameter Circuit, atau dihilangkan (atau setara, diatur ke None) jika Circuit tidak memiliki objek Parameter.
  • (Opsional) presisi target untuk nilai ekspektasi yang akan diestimasi

Sampler PUB​

Untuk primitif Sampler, format tuple PUB berisi paling banyak tiga nilai:

  • Satu QuantumCircuit, yang mungkin berisi satu atau lebih objek Parameter Catatan: Circuit ini juga harus menyertakan instruksi pengukuran untuk setiap Qubit yang akan di-sampling.
  • Kumpulan nilai parameter untuk diikat ke Circuit θk\theta_k (hanya diperlukan jika ada objek Parameter yang harus diikat saat runtime)
  • (Opsional) jumlah shot untuk mengukur Circuit

Kode berikut menunjukkan contoh sekumpulan input yang divektorisasi untuk primitif Estimator dan mengeksekusinya pada Backend IBM® sebagai satu objek 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()

Aturan broadcasting​

PUB menggabungkan elemen dari beberapa array (observable dan nilai parameter) dengan mengikuti aturan broadcasting yang sama seperti NumPy. Bagian ini merangkum aturan-aturan tersebut secara singkat. Untuk penjelasan lebih rinci, lihat dokumentasi aturan broadcasting NumPy.

Aturan:

  • Array input tidak perlu memiliki jumlah dimensi yang sama.
    • Array hasil akan memiliki jumlah dimensi yang sama dengan array input yang memiliki dimensi terbesar.
    • Ukuran setiap dimensi adalah ukuran terbesar dari dimensi yang bersesuaian.
    • Dimensi yang hilang diasumsikan berukuran satu.
  • Perbandingan bentuk dimulai dari dimensi paling kanan dan berlanjut ke kiri.
  • Dua dimensi kompatibel jika ukurannya sama atau salah satunya adalah 1.

Contoh pasangan array yang bisa di-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

Contoh pasangan array yang tidak bisa di-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.

EstimatorV2 mengembalikan satu estimasi nilai ekspektasi untuk setiap elemen dari bentuk yang di-broadcast.

Berikut beberapa contoh pola umum yang diekspresikan dalam bentuk broadcasting array. Representasi visualnya ditampilkan pada gambar berikut:

Sekumpulan nilai parameter direpresentasikan oleh array n x m, dan array observable direpresentasikan oleh satu atau lebih array satu kolom. Untuk setiap contoh dalam kode sebelumnya, sekumpulan nilai parameter digabungkan dengan array observable-nya untuk menghasilkan estimasi nilai ekspektasi.

  • Contoh 1: (broadcast observable tunggal) memiliki sekumpulan nilai parameter berupa array 5x1 dan array observable 1x1. Satu item dalam array observable digabungkan dengan setiap item dalam sekumpulan nilai parameter untuk menghasilkan array 5x1 tunggal di mana setiap item merupakan kombinasi dari item asli dalam sekumpulan nilai parameter dengan item dalam array observable.

  • Contoh 2: (zip) memiliki sekumpulan nilai parameter 5x1 dan array observable 5x1. Outputnya adalah array 5x1 di mana setiap item merupakan kombinasi dari item ke-n dalam sekumpulan nilai parameter dengan item ke-n dalam array observable.

  • Contoh 3: (outer/product) memiliki sekumpulan nilai parameter 1x6 dan array observable 4x1. Kombinasinya menghasilkan array 4x6 yang dibuat dengan menggabungkan setiap item dalam sekumpulan nilai parameter dengan setiap item dalam array observable, sehingga setiap nilai parameter menjadi seluruh kolom dalam output.

  • Contoh 4: (Generalisasi nd standar) memiliki array sekumpulan nilai parameter 3x6 dan dua array observable 3x1. Keduanya digabungkan untuk menghasilkan dua array output 3x6 dengan cara yang mirip dengan contoh sebelumnya.

Gambar ini mengilustrasikan beberapa representasi visual dari broadcasting array

# 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

Setiap SparsePauliOp dihitung sebagai satu elemen dalam konteks ini, terlepas dari jumlah Pauli yang terkandung dalam SparsePauliOp. Jadi, untuk keperluan aturan broadcasting ini, semua elemen berikut memiliki bentuk yang sama:

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

Daftar operator berikut, meski setara dalam hal informasi yang terkandung, memiliki bentuk yang berbeda:

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

Gambaran umum output primitif​

Setelah satu atau lebih PUB dikirim ke QPU untuk dieksekusi dan job berhasil diselesaikan, data dikembalikan sebagai objek container PrimitiveResult yang diakses dengan memanggil metode RuntimeJobV2.result(). PrimitiveResult berisi daftar iterable objek PubResult yang berisi hasil eksekusi untuk setiap PUB. Bergantung pada primitif yang digunakan, data ini akan berupa nilai ekspektasi beserta error bar-nya dalam kasus Estimator, atau sampel dari output Circuit dalam kasus Sampler.

Setiap elemen dalam daftar ini berkorespondensi dengan setiap PUB yang dikirimkan ke metode run() primitif (misalnya, job yang dikirimkan dengan 20 PUB akan mengembalikan objek PrimitiveResult yang berisi daftar 20 PubResult, satu untuk setiap PUB).

Setiap objek PubResult ini memiliki atribut data dan metadata. Atribut data adalah DataBin yang dikustomisasi dan berisi nilai pengukuran aktual, standar deviasi, dan sebagainya. DataBin ini memiliki berbagai atribut bergantung pada bentuk atau struktur PUB terkait serta opsi mitigasi kesalahan yang ditentukan oleh primitif yang digunakan untuk mengirimkan job (misalnya, ZNE atau PEC). Sementara itu, atribut metadata berisi informasi tentang opsi runtime dan mitigasi kesalahan yang digunakan (dijelaskan nanti di bagian Metadata hasil di halaman ini).

Berikut adalah garis besar visual dari struktur data 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
├── ...
├── ...
└── ...

Singkatnya, satu job mengembalikan objek PrimitiveResult dan berisi daftar satu atau lebih objek PubResult. Objek PubResult ini kemudian menyimpan data pengukuran untuk setiap PUB yang dikirimkan ke job.

Setiap PubResult memiliki format dan atribut yang berbeda berdasarkan jenis primitif yang digunakan untuk job tersebut. Penjelasan lebih rinci ada di bawah ini.

Output Estimator​

Setiap PubResult untuk primitive Estimator berisi setidaknya array nilai ekspektasi (PubResult.data.evs) dan standar deviasi terkait (baik PubResult.data.stds maupun PubResult.data.ensemble_standard_error tergantung pada resilience_level yang digunakan), namun bisa berisi lebih banyak data tergantung pada opsi mitigasi error yang ditentukan.

Potongan kode di bawah ini menjelaskan format PrimitiveResult (dan PubResult terkait) untuk job yang dibuat di atas.

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 ]]

Cara Estimator menghitung error​

Selain estimasi rata-rata dari observable yang dimasukkan dalam PUB input (field evs dari DataBin), Estimator juga berusaha memberikan estimasi error yang terkait dengan nilai-nilai ekspektasi tersebut. Semua query estimator akan mengisi field stds dengan nilai seperti standard error of the mean untuk setiap nilai ekspektasi, namun beberapa opsi mitigasi error menghasilkan informasi tambahan, seperti ensemble_standard_error.

Pertimbangkan satu observable O\mathcal{O}. Tanpa ZNE, kamu bisa menganggap setiap shot dari eksekusi Estimator sebagai perkiraan titik dari nilai ekspektasi ⟨O⟩\langle \mathcal{O} \rangle. Jika perkiraan titik-titik tersebut ada dalam vektor Os, maka nilai yang dikembalikan di ensemble_standard_error setara dengan berikut (di mana σO\sigma_{\mathcal{O}} adalah standar deviasi dari estimasi nilai ekspektasi dan NshotsN_{shots} adalah jumlah shot):

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

yang memperlakukan semua shot sebagai bagian dari satu ensemble. Jika kamu meminta twirling Gate (twirling.enable_gates = True), kamu bisa mengelompokkan perkiraan titik dari ⟨O⟩\langle \mathcal{O} \rangle ke dalam set-set yang berbagi twirl yang sama. Sebut set-set perkiraan ini O_twirls, dan ada num_randomizations (jumlah twirl) di dalamnya. Maka stds adalah standard error of the mean dari O_twirls, seperti

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

di mana σO\sigma_{\mathcal{O}} adalah standar deviasi dari O_twirls dan NtwirlsN_{twirls} adalah jumlah twirl. Ketika kamu tidak mengaktifkan twirling, stds dan ensemble_standard_error bernilai sama.

Jika kamu mengaktifkan ZNE, maka stds yang dijelaskan di atas menjadi bobot dalam regresi non-linear ke model ekstrapolator. Yang akhirnya dikembalikan di stds dalam kasus ini adalah ketidakpastian dari model fit yang dievaluasi pada faktor noise nol. Ketika ada fit yang buruk, atau ketidakpastian yang besar dalam fit tersebut, stds yang dilaporkan bisa menjadi sangat besar. Ketika ZNE diaktifkan, pub_result.data.evs_noise_factors dan pub_result.data.stds_noise_factors juga diisi, sehingga kamu bisa melakukan ekstrapolasi sendiri.

Output Sampler​

Ketika job Sampler berhasil diselesaikan, objek PrimitiveResult yang dikembalikan berisi daftar SamplerPubResult, satu per PUB. Data bin dari objek SamplerPubResult ini adalah objek mirip dict yang berisi satu BitArray per ClassicalRegister dalam Circuit.

Kelas BitArray adalah container untuk data shot yang terurut. Lebih detailnya, ia menyimpan bitstring yang disampling sebagai byte di dalam array dua dimensi. Sumbu paling kiri dari array ini berjalan melalui shot yang terurut, sementara sumbu paling kanan berjalan melalui byte.

Sebagai contoh pertama, mari kita lihat Circuit sepuluh-Qubit berikut:

# 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]]

Kadang-kadang lebih mudah untuk mengonversi dari format byte dalam BitArray ke bitstring. Metode get_count mengembalikan dictionary yang memetakan bitstring ke jumlah kemunculannya.

# 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}

Ketika sebuah Circuit berisi lebih dari satu classical register, hasilnya disimpan dalam objek BitArray yang berbeda. Contoh berikut memodifikasi cuplikan sebelumnya dengan membagi classical register menjadi dua register yang berbeda:

# 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>)

Memanfaatkan objek BitArray untuk post-processing yang efisien​

Karena array umumnya menawarkan performa yang lebih baik dibandingkan dictionary, disarankan untuk melakukan post-processing langsung pada objek BitArray daripada pada dictionary of counts. Kelas BitArray menawarkan berbagai metode untuk melakukan beberapa operasi post-processing yang umum:

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 hasil​

Selain hasil eksekusi, baik objek PrimitiveResult maupun PubResult berisi atribut metadata tentang job yang dikirimkan. Metadata yang berisi informasi untuk semua PUB yang dikirimkan (seperti berbagai opsi runtime yang tersedia) dapat ditemukan di PrimitiveResult.metatada, sementara metadata khusus untuk setiap PUB ditemukan di PubResult.metadata.

catatan

Dalam field metadata, implementasi primitive dapat mengembalikan informasi apa pun tentang eksekusi yang relevan bagi mereka, dan tidak ada pasangan key-value yang dijamin oleh primitive dasar. Oleh karena itu, metadata yang dikembalikan mungkin berbeda pada implementasi primitive yang berbeda.

# 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' : {},

Untuk job Sampler, kamu juga bisa memeriksa metadata hasil untuk memahami kapan data tertentu dijalankan; ini disebut execution span.

Source: IBM Quantum docs — updated 27 Apr 2026
English version on doQumentation — updated 7 Mei 2026
This translation based on the English version of 11 Mar 2026