Lewati ke konten utama
Proyek ini masih dalam tahap beta. Menemukan bug? Buat isu GitHub. Punya pertanyaan atau ide? Tanya di Discussions — kami sangat menghargai masukan kamu!
Bagaimana kualitas terjemahan di halaman ini?

Input dan output Executor

Versi paket

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

qiskit[all]~=2.6.1
qiskit-ibm-runtime~=0.50.0
samplomatic~=0.21.0

Primitive Executor adalah bagian dari model eksekusi terarah, yang memberikan fleksibilitas lebih saat menyesuaikan alur kerja mitigasi error.

Input dan output primitif Executor sangat berbeda dari primitif Sampler dan Estimator. Misalnya, alih-alih mengambil daftar PUB sebagai input, Executor mengambil QuantumProgram, yang berisi daftar objek QuantumProgramItem. Kelas kontainer ini memberikan lebih banyak fleksibilitas daripada PUB, yang merupakan struktur data tuple sederhana.

Output Executor adalah QuantumProgramResult, yang merupakan iterable dan berisi satu elemen untuk setiap QuantumProgramItem input.

Input: Program quantum​

Seperti yang disebutkan sebelumnya, input ke primitif Executor adalah QuantumProgram, yang merupakan iterable dari objek QuantumProgramItem. Objek-objek ini bisa berupa dua tipe:

  • CircuitItem, yang biasanya menyimpan circuit dan nilai parameternya (jika ada).
  • SamplexItem, yang biasanya menyimpan hal-hal berikut:
    • Template circuit
    • Objek samplex, yang digunakan untuk menghasilkan sekumpulan parameter teracak saat runtime (misalnya untuk melakukan twirling atau menyuntikkan noise)
    • Argumen untuk samplex, yang mungkin mencakup nilai parameter untuk circuit asli

Setiap item ini merepresentasikan tugas berbeda yang harus dilakukan Executor.

Sebelum kamu mulai​

Beberapa contoh kode di halaman ini menggunakan samplex, yang merupakan bagian dari paket Samplomatic. Karena itu, sebelum menjalankan blok kode tersebut, kamu harus menginstal Samplomatic, seperti yang ditunjukkan di blok kode berikut. Untuk informasi lebih lanjut, lihat dokumentasi Samplomatic.

pip install samplomatic

# For visualization support, include the visualization dependencies.
# pip install samplomatic[vis]

Contoh: Buat QuantumProgram dengan dua tugas berbeda​

Pertama, inisialisasi program kuantum kamu, lalu tambahkan item program ke dalamnya menggunakan append_circuit_item atau append_samplex_item (jika ada samplex), seperti yang ditunjukkan dalam contoh berikut.

Sel berikut menginisialisasi QuantumProgram dan menentukan bahwa ia harus menjalankan 1024 shot untuk setiap konfigurasi dari setiap item dalam program.

catatan

Tidak seperti Sampler, QuantumProgram hanya mengambil satu nilai shot. Jika kamu ingin nilai shot yang berbeda, kamu perlu QuantumProgram terpisah, yang akan menjadi job terpisah.

# 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", "samplomatic": "samplomatic"}
_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.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.quantum_program import QuantumProgram
from qiskit_ibm_runtime import Executor, QiskitRuntimeService
from qiskit.circuit import Parameter, QuantumCircuit
import numpy as np
from samplomatic import build
from samplomatic.transpiler import generate_boxing_pass_manager

# Initialize an empty program
program = QuantumProgram(shots=1024)

# Initialize and transpile a 3-qubit quantum circuit with 2 parameters.
circuit = QuantumCircuit(3)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.rz(Parameter("theta"), 0)
circuit.rz(Parameter("phi"), 1)

# `measure_all` adds a 3-bit classical register named "meas"
circuit.measure_all()

# Choose the least busy backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Generate a preset pass manager
# This will be used to convert the abstract circuit to an
# equivalent Instruction Set Architecture (ISA) circuit.
preset_pass_manager = generate_preset_pass_manager(
backend=backend, optimization_level=0
)

# Transpile the circuit
isa_circuit = preset_pass_manager.run(circuit)

Tambahkan CircuitItem​

Selanjutnya, tambahkan circuit target, yang sudah ditranspile sesuai dengan instruction set architecture (ISA) backend, ke QuantumProgram. Karena circuit ini memiliki dua parameter, kita juga harus menyediakan nilai parameter (10 set dalam contoh ini). Menjalankan CircuitItem ini adalah tugas pertama yang akan dilakukan program.

# Append the transpiled circuit and an array
# containing 10 sets of parameter values to the program
program.append_circuit_item(
isa_circuit,
circuit_arguments=np.random.rand(
10, 2
), # 10 sets of parameter values and 2 parameters
)

Tambahkan SamplexItem​

Item circuit dieksekusi tanpa jenis pengacakan apapun. Sebaliknya, item samplex memungkinkan kamu menentukan cara mengacak kontennya. Sel berikut menggunakan fungsi generate_boxing_pass_manager() untuk mengelompokkan gate dan pengukuran circuit ke dalam kotak dan menambahkan anotasi twirling ke setiap kotak. Kemudian ia menghasilkan pasangan template circuit dan samplex menggunakan fungsi build().

Menjalankan SamplexItem ini adalah tugas kedua yang akan dilakukan program.

Lihat dokumentasi API Samplomatic untuk detail lengkap tentang samplex dan argumen-argumennya. Lihat panduan Transpiler Samplomatic untuk informasi tentang penggunaan fungsi generate_boxing_pass_manager().

# Transpile the circuit, additionally grouping gates and measurements into annotated boxes
preset_pass_manager = generate_preset_pass_manager(
backend=backend, optimization_level=0
)

# Use the boxing pass manager to group gates
# and measurements into boxes and add
# a`Twirl` annotation.
preset_pass_manager.post_scheduling = generate_boxing_pass_manager(
# Add gate twirling
enable_gates=True,
# Add measurement twirling
enable_measures=True,
)
boxed_circuit = preset_pass_manager.run(circuit)

# Build the template circuit and the samplex. The template circuit has parametric gates
# without fixed values and the samplex randomly generates the parameter
# values on the server side at runtime to perform twirling.
template_circuit, samplex = build(boxed_circuit)

# Determine what arguments are required by the samplex.
# Input the arguments in samplex_arguments.
print(samplex.inputs())
TensorInterface(<
- 'parameter_values' <float64[2]>: Input parameter values to use during sampling.
>)
# Append the template circuit and samplex as a samplex item
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
# the arguments required by the samplex.sample method
"parameter_values": np.random.rand(10, 2),
},
shape=(28, 10), # 28 randomizations and 10 sets of parameter values
)
# Initialize an Executor with the default options
executor = Executor(mode=backend)

# Submit the job
job = executor.run(program)

# Retrieve the result
result = job.result()

Output​

Output Executor adalah QuantumProgramResult, yang merupakan iterable. Ini berisi satu entri per QuantumProgramItem input dengan urutan yang sama seperti item input. Masing-masing item output ini adalah dictionary di mana key-nya (antara lain) adalah string yang sesuai dengan nama register klasik dalam circuit input, sehingga kamu tidak perlu lagi menghafal nama-nama ini seperti yang kamu lakukan dengan output Sampler. Nilai dictionary bertipe np.ndarray.

Hasil dari contoh sebelumnya berisi item-item ini:

Hasil CircuitItem​

Item pertama berisi hasil menjalankan tugas pertama (sebuah CircuitItem) dalam program. Item ini berisi satu key tunggal, meas, yaitu nama register klasik dalam circuit input. Nilai dari key ini dipetakan ke sebuah np.ndarray dengan bentuk (parameter sets, shots, register bits), yang merupakan (10, 1024, 3) untuk contoh di atas.

Kode berikut mengilustrasikan cara mengakses informasi ini:

# Access the results of the classical register of task #0, a CircuitItem
result_0 = result[0]["meas"]
print(f"Result shape: {result_0.shape}")
Result shape: (10, 1024, 3)

Sumbu paling kanan dari result_0 mencakup bit klasik dalam urutan little-endian. Jadi, indeks 0 menyimpan hasil bit klasik 0, yaitu bit paling tidak signifikan.

Hasil SamplexItem​

Item kedua berisi hasil menjalankan tugas kedua (sebuah SamplexItem) dalam program. Item ini berisi beberapa key. Key meas, yang merupakan nama register klasik Circuit input, dipetakan ke array hasil register tersebut. Array ini memiliki bentuk (randomizations, parameter sets, shots, classical bits), atau (28, 10, 1024, 3) dalam contoh ini.

Selain itu, output berisi key measurement_flips.meas, yang merupakan koreksi bit-flip untuk membatalkan measurement twirling untuk register meas. Bentuk output ini akan menjadi (28, 10, 1, 3) untuk contoh kita karena hanya satu shot yang diperlukan untuk melakukan bit-flip.

Perhatikan bahwa sumbu paling kanan dari result_1 mencakup bit klasik dalam urutan little-endian.

# Access the results of the classical register of task #1
result_1 = result[1]["meas"]
print(f"Result shape: {result_1.shape}")

# Access the bit-flip corrections
flips_1 = result[1]["measurement_flips.meas"]
print(f"Bit-flip corrections shape: {flips_1.shape}")

# Undo the bit flips via classical XOR
unflipped_result_1 = result_1 ^ flips_1
Result shape: (28, 10, 1024, 3)
Bit-flip corrections shape: (28, 10, 1, 3)

Lihat execution spans​

Satu panggilan Executor.run() mengirimkan satu job. Namun di sisi server, layanan tidak selalu menjalankan setiap konfigurasi program kuantum pada waktu yang sama. Sebaliknya, layanan mengelompokkan Circuit terikat dari item program ke dalam chunk, dan menjalankan satu chunk dalam satu waktu di QPU. Kamu tidak perlu memecah programmu atau mengirim job tambahan; chunking terjadi otomatis dalam satu job tersebut. Atribut metadata pada hasil berisi informasi waktu tentang chunk-chunk ini di result.metadata.chunk_timing. Timestamp ini adalah waktu mulai dan berhenti sebenarnya dari setiap chunk di QPU. Kamu bisa menggunakan informasi ini untuk melihat kapan data tertentu dikumpulkan di QPU, memahami bagaimana Executor mendistribusikan pekerjaan, atau mendiagnosis masalah performa.

chunk_timing adalah daftar yang berisi satu ChunkSpan untuk setiap chunk yang dieksekusi. Setiap ChunkSpan memiliki atribut berikut:

  • start dan stop: Timestamp UTC saat chunk mulai dan berhenti dieksekusi di QPU.

  • parts: Daftar objek ChunkPart yang menjelaskan item program mana yang berkontribusi pada chunk. Setiap ChunkPart berisi hal berikut:

    • idx_item: Indeks item program, sesuai urutan item ditambahkan ke QuantumProgram.

    • size: Jumlah konfigurasi (elemen dari shape item) dari item tersebut yang dieksekusi di chunk ini. Misalnya, SamplexItem pada contoh sebelumnya memiliki shape (28, 10), jadi totalnya ada 280 konfigurasi.

Kode berikut mencetak durasi setiap chunk dan isi setiap chunk untuk job yang dikirim sebelumnya:

for idx, span in enumerate(result.metadata.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" Item {part.idx_item}: {part.size} configurations")
Chunk 0: 2026-11-06 01:47:46.009718+00:00 to 2026-11-06 01:49:05.577720+00:00 (79.568 s)
Item 0: 10 configurations
Item 1: 280 configurations

Properti QuantumProgramResult.timing membungkus daftar yang sama dalam objek ChunkTiming, yang juga melaporkan informasi global tentang kumpulan chunk:

timing = result.timing

print("Number of chunks:", len(timing))
print(" Start of the first chunk:", timing.start)
print(" End of the last chunk:", timing.stop)
print(" Total duration (s):", timing.duration)
Number of chunks: 1
Start of the first chunk: 2026-11-06 01:47:46.009718+00:00
End of the last chunk: 2026-11-06 01:49:05.577720+00:00
Total duration (s): 79.568002

Visualisasikan execution spans​

Gunakan fungsi draw_chunk_timings untuk memvisualisasikan waktu chunk pada bar plot interaktif. Sumbu x adalah waktu, dan setiap chunk digambar sebagai segmen horizontal yang membentang dari waktu mulai hingga waktu berhentinya. Sumbu y menunjukkan jumlah kumulatif konfigurasi yang selesai (atau persentase dari total beban kerja, jika kamu mengatur normalize_y=True). Arahkan kursor ke sebuah segmen untuk melihat timestamp, durasi, dan part dari chunk tersebut.

Fungsi ini mengembalikan figure plotly, yang bisa kamu tampilkan langsung, simpan ke file, atau keduanya. Fungsi ini menerima daftar chunk_timing atau objek ChunkTiming. Kamu bisa memberikan beberapa sekaligus, misalnya dari job yang berbeda, untuk digambar di plot yang sama. Atur common_start=True untuk menyelaraskannya pada waktu mulai yang sama sebagai perbandingan.

Plotly diperlukan

draw_chunk_timings membutuhkan plotly. Kamu bisa menginstalnya dengan menjalankan pip install plotly.

Celah antar chunk

Visualisasi mungkin menunjukkan celah di antara eksekusi chunk. Semua job yang dikirim ke QPU nyata melewati beberapa praproses klasik, seperti penerjemahan ke pulsa yang bisa dikirim ke hardware. Karena praproses ini bisa dilakukan secara paralel, layanan mengeluarkan dari antrean dan memulai beberapa job secara bersamaan. Namun, QPU hanya bisa memproses satu unit pekerjaan dalam satu waktu. Karena itu, jika sebuah job menghasilkan beberapa chunk, chunk-nya mungkin berselang-seling dengan chunk dari job pengguna lain, dan setiap chunk mungkin harus menunggu gilirannya di QPU. Inilah sebabnya celah bisa muncul di antara chunk.

from qiskit_ibm_runtime.visualization import draw_chunk_timings

fig = draw_chunk_timings(result.timing, names="Executor job")

# Alternatively, call the `draw()` method of the ChunkTiming object
# fig = result.timing.draw()

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

# Save to a file
# fig.write_html("chunk_timings.html")

Langkah selanjutnya​

Rekomendasi