Langkau ke kandungan utama

Input dan output Sampler

Versi pakej

Kod di halaman ini dibangunkan menggunakan keperluan berikut. Kami mengesyorkan penggunaan versi ini atau yang lebih baharu.

qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1

Halaman ini memberikan gambaran keseluruhan input dan output primitif Sampler Qiskit Runtime, yang melaksanakan beban kerja pada sumber pengkomputeran IBM Quantum®. Sampler membolehkan anda mentakrifkan beban kerja yang divektorkan secara cekap menggunakan struktur data yang dikenali sebagai Primitive Unified Bloc (PUB). Ia digunakan sebagai input kepada kaedah run() untuk primitif Sampler, yang melaksanakan beban kerja yang ditakrifkan sebagai kerja. Kemudian, selepas kerja selesai, keputusan dikembalikan dalam format yang bergantung pada PUB yang digunakan serta pilihan runtime yang ditentukan daripada primitif.

Input

Setiap PUB dalam format:

(<litar tunggal>, <satu atau lebih nilai parameter pilihan>, <shots pilihan>),

Boleh ada berbilang item parameter values, dan setiap item boleh berupa tatasusunan atau parameter tunggal, bergantung pada litar yang dipilih. Selain itu, input mesti mengandungi pengukuran.

Untuk primitif Sampler, PUB boleh mengandungi paling banyak tiga nilai:

  • Satu QuantumCircuit, yang mungkin mengandungi satu atau lebih objek Parameter Nota: Litar ini juga harus menyertakan arahan pengukuran untuk setiap qubit yang akan disampel.
  • Koleksi nilai parameter untuk mengikat litar terhadap θk\theta_k (hanya diperlukan jika terdapat objek Parameter yang mesti diikat pada masa runtime)
  • (Pilihan) bilangan shots untuk mengukur litar

Kod berikut menunjukkan contoh set input yang divektorkan kepada primitif Sampler dan melaksanakannya 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,
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)
circuit.measure_all()

# 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

sampler_pub = (transpiled_circuit, params)

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

Output

Selepas satu atau lebih PUB dihantar ke QPU untuk pelaksanaan dan kerja berjaya diselesaikan, data dikembalikan sebagai objek bekas PrimitiveResult yang diakses dengan memanggil kaedah RuntimeJobV2.result(). PrimitiveResult mengandungi senarai yang boleh diulang daripada objek SamplerPubResult yang mengandungi keputusan pelaksanaan untuk setiap PUB. Data ini adalah sampel output litar.

Setiap elemen dalam senarai ini sepadan dengan PUB yang diserahkan kepada kaedah run() primitif (contohnya, kerja yang diserahkan dengan 20 PUB akan mengembalikan objek PrimitiveResult yang mengandungi senarai 20 objek SamplerPubResult, satu untuk setiap PUB).

Setiap objek SamplerPubResult mempunyai atribut data dan metadata.

  • Atribut data ialah DataBin yang disesuaikan mengandungi nilai pengukuran sebenar, sisihan piawai, dan sebagainya. Kotak data ialah objek seperti dict yang mengandungi satu BitArray bagi setiap ClassicalRegister dalam litar.
  • Kelas BitArray ialah bekas untuk data shot yang tersusun. Ia menyimpan bitstring yang disampel sebagai bait di dalam tatasusunan dua dimensi. Paksi paling kiri tatasusunan ini berjalan merentasi shot yang tersusun, manakala paksi paling kanan berjalan merentasi bait.
  • Atribut metadata mengandungi maklumat tentang pilihan runtime yang digunakan (diterangkan kemudian dalam bahagian Metadata keputusan di halaman ini).

Berikut ialah garis besar visual struktur data PrimitiveResult:

└── PrimitiveResult
├── SamplerPubResult[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)
├── SamplerPubResult[1]
| ├── metadata
| └── data ## In the form of a DataBin object
| └── NAME_OF_CLASSICAL_REGISTER
| └── BitArray of count data for second pub
├── ...
├── ...
└── ...

Ringkasnya, satu kerja mengembalikan objek PrimitiveResult dan mengandungi senarai satu atau lebih objek SamplerPubResult. Objek SamplerPubResult ini kemudian menyimpan data pengukuran untuk setiap PUB yang diserahkan kepada kerja.

Sebagai contoh pertama, mari lihat litar 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:
[[ 0 0]
[ 3 255]
[ 0 0]
...
[ 3 255]
[ 2 255]
[ 3 255]]

Kadangkala lebih mudah untuk menukar daripada format bait dalam BitArray kepada bitstring. Kaedah get_count mengembalikan kamus yang memetakan bitstring kepada bilangan kemunculannya.

# optionally, convert away from the native BitArray format to a dictionary format
counts = data.meas.get_counts()
print(f"Counts: {counts}")
Counts: {'0000000000': 1649, '1111111111': 1344, '1111111000': 26, '1101111111': 40, '1111110000': 20, '0010000000': 32, '1000000000': 67, '1111110110': 4, '0000011110': 4, '0000000001': 78, '0010100000': 1, '1100000000': 37, '1111111110': 126, '1111110111': 35, '1111011111': 32, '0011111000': 1, '1011110111': 1, '0000011111': 48, '1111000000': 14, '0110000000': 1, '1110111110': 2, '1110011111': 4, '1111100000': 19, '1101111000': 1, '1111111011': 8, '0001011111': 3, '1110000000': 31, '0000000111': 25, '1110000001': 3, '0011111111': 24, '0000100000': 7, '1111111101': 30, '1111101111': 16, '0111111111': 37, '0000011101': 4, '0101111111': 4, '1011111110': 2, '0000000010': 17, '1011111111': 20, '0000100111': 1, '0010000111': 1, '1011010000': 1, '1101101111': 2, '1011110000': 1, '1000000001': 4, '0000001000': 23, '0011111110': 8, '1111111001': 1, '1100111111': 2, '0000011000': 2, '0001111110': 2, '0000111111': 20, '0001111111': 33, '1110111111': 11, '1010000000': 3, '0111011111': 2, '0000000100': 2, '0000000110': 2, '0000001111': 22, '0111101111': 1, '0000010111': 1, '0000000011': 15, '0001000010': 1, '1111111100': 19, '1111101000': 1, '0000001110': 2, '1011110100': 1, '0001000000': 11, '1001111111': 2, '0100000000': 6, '1100000011': 2, '1000001110': 1, '1100001111': 1, '0000010000': 3, '1101111110': 5, '0001111101': 1, '0001110111': 1, '0011000000': 2, '0111101110': 1, '1100000001': 1, '1111000001': 1, '0000000101': 1, '1101110111': 2, '0011111011': 1, '0000111110': 1, '1111101110': 3, '1111001000': 1, '1011111100': 1, '1111110101': 2, '1101001111': 1, '1111011110': 3, '1000011111': 1, '0000001001': 2, '1111010000': 1, '1110100010': 1, '1111110001': 2, '1101110000': 2, '0000010100': 1, '0111111110': 2, '0001000001': 1, '1000010000': 1, '1111011100': 1, '0111111100': 1, '1011101111': 1, '0000111101': 1, '1100011111': 2, '1101100000': 1, '1111011011': 1, '0010011111': 1, '0000110111': 3, '1111100010': 1, '1110111101': 1, '0000111001': 1, '1111100001': 1, '0001111100': 1, '1110011110': 1, '1100000010': 1, '0011110000': 1, '0001100111': 1, '1111010111': 1, '0010000001': 1, '0010000011': 1, '1101000111': 1, '1011111101': 1, '0000001100': 1}

Apabila litar mengandungi lebih daripada satu daftar klasik, keputusan disimpan dalam objek BitArray yang berbeza. Contoh berikut mengubah suai petikan sebelumnya dengan membahagikan daftar klasik kepada dua daftar yang berbeza:

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

Menggunakan objek BitArray untuk post-processing yang cekap

Memandangkan tatasusunan umumnya menawarkan prestasi yang lebih baik berbanding kamus, adalah dinasihatkan untuk melakukan sebarang post-processing terus pada objek BitArray dan bukannya pada kamus kiraan. Kelas BitArray menawarkan pelbagai kaedah untuk melakukan beberapa operasi post-processing yang biasa:

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:
[[0]
[0]
[0]
...
[0]
[0]
[0]]

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

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:
[[0]
[0]
[0]
...
[0]
[0]
[0]]

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

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

The shape of the merged results is (4096, 2).
The bytes of the merged results:
[[ 0 0]
[ 3 240]
[ 0 0]
...
[ 0 0]
[ 0 0]
[ 0 0]]

Metadata keputusan

Selain keputusan pelaksanaan, kedua-dua objek PrimitiveResult dan SamplerPubResult mengandungi atribut metadata tentang kerja yang diserahkan. Metadata yang mengandungi maklumat untuk semua PUB yang diserahkan (seperti pelbagai pilihan runtime yang tersedia) boleh didapati dalam PrimitiveResult.metatada, manakala metadata yang khusus untuk setiap PUB terdapat dalam SamplerPubResult.metadata.

Metadata keputusan Sampler juga termasuk maklumat pemasaan pelaksanaan yang dipanggil julat pelaksanaan.

nota

Dalam medan metadata, pelaksanaan primitif boleh mengembalikan sebarang maklumat yang berkaitan dengan pelaksanaan yang relevan bagi mereka, dan tiada pasangan kunci-nilai yang dijamin oleh primitif asas. Oleh itu, metadata yang dikembalikan dalam pelaksanaan primitif yang berbeza mungkin berbeza.

# 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-05-13 14:23:00', stop='2026-05-13 14:23:02', size=4096>)])},
'version' : 2,

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

Melihat julat pelaksanaan

Keputusan kerja SamplerV2 yang dilaksanakan dalam Qiskit Runtime mengandungi maklumat pemasaan pelaksanaan dalam metadatanya. Maklumat pemasaan ini boleh digunakan untuk menetapkan had masa atas dan bawah pada masa pelaksanaan shots tertentu pada QPU. Shots dikumpulkan ke dalam objek ExecutionSpan, setiap satu menunjukkan masa mula, masa berhenti, dan shots mana yang dikumpulkan dalam julat tersebut.

Julat pelaksanaan mengenal pasti data yang dilaksanakan semasa tetingkap masanya dengan menyediakan kaedah ExecutionSpan.mask. Kaedah ini, apabila diberikan sebarang indeks Primitive Unified Block (PUB), mengembalikan topeng boolean yang True untuk semua shots yang dilaksanakan semasa tetingkap masanya. PUB diindeks mengikut urutan ia diberikan kepada panggilan run Sampler. Jika PUB mempunyai bentuk (2, 3) dan dijalankan dengan empat shots, bentuk topeng adalah (2, 3, 4). Lihat halaman API execution_span untuk butiran lengkap.

Untuk melihat maklumat julat pelaksanaan, semak metadata keputusan yang dikembalikan oleh SamplerV2, yang datang dalam bentuk objek ExecutionSpans. Objek ini ialah bekas seperti senarai yang mengandungi contoh subkelas ExecutionSpan, seperti SliceSpan.

Contoh:

# Define two circuits, each with one parameter with two parameters.
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.ry(Parameter("a"), 0)
circuit.cx(0, 1)
circuit.h(0)
circuit.measure_all()

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
transpiled_circuit = pm.run(circuit)

params = np.random.uniform(size=(2, 3)).T

sampler_pub = (transpiled_circuit, params)

# Instantiate the new Estimator object, then run the transpiled circuit
# using the set of parameters and observables.

job = sampler.run([sampler_pub], shots=4)

result = job.result()
spans = job.result().metadata["execution"]["execution_spans"]
print(spans)
ExecutionSpans([DoubleSliceSpan(<start='2026-05-13 14:23:20', stop='2026-05-13 14:23:21', size=24>)])
from qiskit.primitives import BitArray

# Get the mask of the 1st PUB for the 0th span.
mask = spans[0].mask(0)

# Decide whether the 0th shot of parameter set (1, 2) occurred in this span.
in_this_span = mask[2, 1, 0]

# Create a new bit array containing only the PUB-1 data collected during this span.
bits = result[0].data.meas
filtered_data = BitArray(bits.array[mask], bits.num_bits)

Julat pelaksanaan boleh ditapis untuk menyertakan maklumat yang berkaitan dengan PUB tertentu, yang dikenal pasti dengan indeksnya:

# take the subset of spans that reference data in PUBs 0 or 2
spans.filter_by_pub([0, 2])
ExecutionSpans([DoubleSliceSpan(<start='2026-05-13 14:23:20', stop='2026-05-13 14:23:21', size=24>)])

Paparkan maklumat umum tentang set julat pelaksanaan:

print("Number of execution spans:", len(spans))
print(" Start of the first span:", spans.start)
print(" End of the last span:", spans.stop)
print(" Total duration (s):", spans.duration)
Number of execution spans: 1
Start of the first span: 2026-05-13 14:23:20.441518
End of the last span: 2026-05-13 14:23:21.564845
Total duration (s): 1.123327

Ekstrak dan periksa julat tertentu:

spans.sort()
print(" Start of first span:", spans[0].start)
print(" End of first span:", spans[0].stop)
print("#shots in first span:", spans[0].size)
Start of first span: 2026-05-13 14:23:20.441518
End of first span: 2026-05-13 14:23:21.564845
#shots in first span: 24
nota

Ada kemungkinan bahawa tetingkap masa yang ditentukan oleh julat pelaksanaan yang berbeza boleh bertindih. Ini bukan kerana QPU sedang melaksanakan berbilang operasi secara serentak, sebaliknya ia adalah hasil daripada pemprosesan klasik tertentu yang mungkin berlaku secara serentak dengan pelaksanaan kuantum. Jaminan yang diberikan ialah data yang dirujuk pasti berlaku dalam julat pelaksanaan yang dilaporkan, tetapi tidak semestinya bahawa had tetingkap masa adalah sesempit mungkin.