Langkau ke kandungan utama
Projek ini dalam fasa beta. Jumpa pepijat? Buat isu GitHub. Ada soalan atau idea? Tanya dalam Discussions — kami suka dengar maklum balas anda!
Bagaimana kualiti terjemahan pada halaman ini?

Input dan output Sampler

Versi pakej

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

qiskit[all]~=2.5.2
qiskit-ibm-runtime~=0.47.0

Halaman ini memberikan gambaran keseluruhan input dan output primitif Sampler qiskit-ibm-runtime, yang melaksanakan beban kerja pada IBM Quantum® Compute Service. Sampler membolehkan anda mentakrifkan beban kerja yang divektorkan dengan cekap menggunakan struktur data yang dikenali sebagai Primitive Unified Bloc (PUB). PUB digunakan sebagai input kepada kaedah run() untuk primitif Sampler, yang melaksanakan beban kerja yang ditakrifkan sebagai satu kerja. Kemudian, selepas kerja selesai, hasil dikembalikan dalam format yang bergantung pada PUB yang digunakan dan juga pilihan runtime yang ditetapkan pada primitif.

Input​

Setiap PUB dalam format:

(<single circuit>, <one or more optional parameter value>, <optional shots>),

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 — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_ibm_runtime": "qiskit-ibm-runtime"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
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

# Legacy server-side primitive before qiskit-ibm-runtime 0.50.0
# from qiskit_ibm_runtime import Sampler

# Client-side primitive introduced in qiskit-ibm-runtime 0.50.0
from qiskit_ibm_runtime.executor_sampler import 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:
[[ 3 247]
[ 0 0]
[ 3 223]
...
[ 0 255]
[ 0 0]
[ 0 0]]

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: {'1111110111': 28, '0000000000': 1680, '1111011111': 35, '1111111111': 1467, '1110000000': 28, '0000000010': 15, '1111111011': 15, '1110111111': 7, '1000000000': 52, '1111101111': 16, '1111110000': 22, '0000000101': 3, '0001111101': 1, '0000000111': 17, '0000000001': 66, '1111111110': 119, '0000001000': 15, '0011111111': 24, '1111111101': 38, '0000001111': 32, '1100000000': 39, '1101111111': 51, '0000011111': 34, '1110000010': 2, '0010000000': 25, '0111111111': 21, '0001111111': 34, '1011111111': 16, '1000011111': 3, '0000001101': 1, '1111100000': 22, '1111111100': 22, '1111111000': 8, '0010001011': 1, '0011000000': 1, '0000000011': 16, '0011111100': 2, '1011110001': 1, '1101111100': 1, '1101111101': 1, '0000000110': 2, '0000000100': 2, '0001111110': 6, '0000001110': 4, '0011110111': 2, '1101111110': 3, '0111111011': 1, '0110000000': 1, '0000001011': 2, '1111110110': 3, '0111111000': 1, '1010000000': 2, '0001110111': 1, '1111101000': 1, '0010011110': 1, '1111100111': 1, '0111110111': 1, '0100000000': 5, '1101110111': 1, '0000001001': 1, '0010000001': 1, '1111000001': 1, '0000010000': 3, '1111101110': 1, '1111000000': 8, '0001011111': 3, '1000000001': 1, '1111010111': 2, '0010011111': 1, '1011111110': 1, '1101101111': 1, '1111011110': 2, '1111111010': 1, '1111010000': 1, '1101000000': 1, '1100001111': 1, '1100011111': 1, '0000111111': 4, '0010111111': 1, '1000000110': 1, '1110111110': 1, '1101011111': 2, '0000011000': 1, '1101110000': 2, '1011111011': 1, '1000111111': 1, '1011000000': 1, '1110000001': 2, '0101111111': 2, '1111110101': 1, '0010000011': 1, '0000011110': 1, '0000011101': 1, '0111000000': 1, '0001110000': 1, '0001000000': 4, '1101111000': 1, '1011111000': 1, '0111110000': 1, '1101110110': 1, '0011011111': 1, '0000100000': 2, '1111101100': 1, '1100001000': 1, '1010000011': 1, '0011111110': 1, '1010001110': 1, '1000001000': 1, '1000000011': 1, '1111101011': 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:
[[1]
[0]
[1]
...
[0]
[1]
[0]]

The shape of register `beta` is (4096, 2).
The bytes in register `beta`, shot by shot:
[[ 1 255]
[ 0 0]
[ 1 255]
...
[ 0 0]
[ 1 255]
[ 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:
[[7]
[0]
[7]
...
[0]
[7]
[0]]

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

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

The shape of the merged results is (4096, 2).
The bytes of the merged results:
[[ 3 255]
[ 0 0]
[ 3 255]
...
[ 0 0]
[ 3 255]
[ 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.

Sampler sisi klien menghantar beban kerjanya sebagai job Executor. Metadata hasil Executor yang mendasari, yang merangkumi maklumat masa pelaksanaan yang dipanggil span pelaksanaan, tersedia di bawah kunci "executor" bagi PrimitiveResult.metadata.

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-09-01 07:46:47', stop='2026-09-01 07:46:49', size=4096>)])},
'version' : 2,

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

Melihat julat pelaksanaan​

Sampler sisi klien menggunakan Executor untuk menjalankan job, yang melaksanakan kerjanya pada QPU dalam ketulan. Masa bagi setiap ketulan berada dalam result.metadata["executor"].chunk_timing, senarai objek ChunkSpan. Setiap ChunkSpan mempunyai cap masa start dan stop serta senarai parts, dengan setiap bahagian memberikan indeks item (idx_item) dan bilangan konfigurasi daripada item tersebut (size) yang dijalankan dalam ketulan.

Sampler mencipta satu item atur cara Executor bagi setiap PUB, jadi idx_item ialah indeks PUB, mengikut urutan PUB diberikan kepada run(). Jika twirling didayakan, setiap perawakan rawak bagi setiap set nilai parameter dikira sebagai konfigurasi yang berasingan.

Untuk menggambarkan masa, hantar senarai kepada draw_chunk_timings, seperti yang ditunjukkan dalam contoh berikut.

Untuk mengetahui maksud cap masa chunk, cara membaca plot, dan sebab jurang boleh muncul antara chunk, lihat View execution spans dalam panduan Executor inputs and outputs.

# Define a circuit with one parameter.
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)

# Define two PUBs, each with a different set of parameter values
sampler_pubs = [
(transpiled_circuit, np.random.uniform(size=(10, 1))),
(transpiled_circuit, np.random.uniform(size=(20, 1))),
]

job = sampler.run(sampler_pubs, shots=1024)
result = job.result()
from qiskit_ibm_runtime.visualization import draw_chunk_timings

# Note the "executor" key: the timing comes from the underlying Executor job
chunk_timing = result.metadata["executor"].chunk_timing

for idx, span in enumerate(chunk_timing):
duration = (span.stop - span.start).total_seconds()
print(f"Chunk {idx}: {span.start} to {span.stop} ({duration:.3f} s)")
for part in span.parts:
print(f" PUB {part.idx_item}: {part.size} configurations")

fig = draw_chunk_timings(chunk_timing, names="Sampler job")

# Uncomment the following line to display the figure
# fig.show(renderer="notebook")

# Save to a file
# fig.write_html("chunk_timings.html")
Chunk 0: 2026-11-06 01:36:36.203348+00:00 to 2026-11-06 01:36:45.420844+00:00 (9.217 s)
PUB 0: 10 configurations
PUB 1: 20 configurations

Julat pelaksanaan dalam Sampler warisan​

Mulai qiskit-ibm-runtime v0.50.0, Sampler warisan sebelah pelayan telah dinyahgalakkan. Sampler sebelah klien tidak mengembalikan objek ExecutionSpans; gunakan pemasaan chunk yang diterangkan sebelum ini. Lihat Migrate to client-side primitives untuk arahan penghijrahan.

Klik untuk ketahui lebih lanjut.

Keputusan kerja daripada Sampler warisan sebelah pelayan mengandungi maklumat pemasaan pelaksanaan dalam result.metadata["execution"]["execution_spans"], dalam bentuk objek ExecutionSpans. Objek ini ialah bekas seperti senarai bagi objek ExecutionSpan, setiap satu menunjukkan masa mula, masa berhenti, dan spesifikasi shot mana yang dikumpulkan dalam julat tersebut.

Julat pelaksanaan menentukan data mana yang dilaksanakan semasa tetingkapnya dengan menyediakan kaedah ExecutionSpan.mask. Kaedah ini, apabila diberikan sebarang indeks PUB, mengembalikan topeng boolean yang True untuk semua shot yang dilaksanakan semasa tetingkapnya. Jika, sebagai contoh, sebuah PUB mempunyai bentuk (2, 3) dan dijalankan dengan empat shot, bentuk topeng ialah (2, 3, 4). Lihat halaman API execution_span untuk butiran lengkap.

from qiskit.primitives import BitArray

spans = result.metadata["execution"]["execution_spans"]

# Dapatkan topeng PUB pertama untuk julat ke-0.
mask = spans[0].mask(0)

# Cipta tatasusunan bit baharu yang mengandungi hanya data PUB-0 yang dikumpulkan semasa julat ini.
bits = result[0].data.meas
filtered_data = BitArray(bits.array[mask], bits.num_bits)

# Ambil subset julat yang merujuk data dalam PUB 0 atau 2
spans.filter_by_pub([0, 2])

# Lihat maklumat global tentang koleksi 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)

Untuk memvisualkan julat pelaksanaan warisan, gunakan fungsi draw_execution_spans.

Adalah mungkin bagi tetingkap masa yang ditentukan oleh julat pelaksanaan yang berbeza untuk bertindih. Ini bukan kerana QPU melaksanakan berbilang pelaksanaan serentak, sebaliknya ia adalah artifak pemprosesan klasik tertentu yang mungkin berlaku serentak dengan pelaksanaan kuantum. Jaminannya ialah data yang dirujuk pasti berlaku dalam julat pelaksanaan yang dilaporkan, tetapi tidak semestinya bahawa had tetingkap masa adalah seketat yang mungkin.