Lewati ke konten utama

Migrasi ke primitif V2 Qiskit Runtime

peringatan

Primitif asli (disebut sebagai primitif V1), V1 Sampler dan V1 Estimator, telah didepresiasi di qiskit-ibm-runtime 0.23. Dukungannya dihapus pada 15 Agustus 2024.

Dengan depresiasi primitif V1, semua kode harus dimigrasi untuk menggunakan antarmuka V2. Panduan ini menjelaskan apa yang berubah di primitif V2 Qiskit Runtime (tersedia dengan qiskit-ibm-runtime 0.21.0) dan alasannya, menjelaskan setiap primitif baru secara detail, serta memberikan contoh untuk membantu kamu memigrasikan kode dari primitif lama ke primitif V2. Contoh-contoh dalam panduan ini semuanya menggunakan primitif Qiskit Runtime, tapi secara umum, perubahan yang sama juga berlaku untuk implementasi primitif lainnya. Fungsi-fungsi yang unik untuk Qiskit Runtime seperti mitigasi error tetap unik untuk Qiskit Runtime.

Untuk informasi tentang perubahan pada primitif referensi Qiskit (sekarang disebut primitif statevector), lihat bagian qiskit.primitives di halaman perubahan fitur Qiskit 1.0. Lihat StatevectorSampler dan StatevectorEstimator untuk implementasi referensi primitif V2.

Ikhtisar​

Versi 2 dari primitif diperkenalkan dengan kelas dasar baru untuk Sampler dan Estimator (BaseSamplerV2 dan BaseEstimatorV2), bersama dengan tipe baru untuk input dan outputnya.

Antarmuka baru memungkinkan kamu menentukan satu Circuit dan beberapa observabel (jika menggunakan Estimator) serta kumpulan nilai parameter untuk Circuit tersebut, sehingga sweeping atas kumpulan nilai parameter dan observabel bisa ditentukan secara efisien. Sebelumnya, kamu harus menentukan Circuit yang sama berkali-kali untuk menyesuaikan ukuran data yang akan digabungkan. Selain itu, meskipun kamu masih bisa menggunakan resilience_level (jika menggunakan Estimator) sebagai knop sederhana, primitif V2 memberi kamu fleksibilitas untuk mengaktifkan atau menonaktifkan metode mitigasi/supresi error individual agar bisa disesuaikan dengan kebutuhanmu.

Untuk mengurangi total waktu eksekusi job, primitif V2 hanya menerima Circuit dan observabel yang menggunakan instruksi yang didukung oleh QPU (quantum processing unit) target. Circuit dan observabel seperti itu disebut sebagai Circuit dan observabel instruction set architecture (ISA). Primitif V2 tidak melakukan operasi layout, routing, dan translasi. Lihat dokumentasi transpilasi untuk instruksi transformasi Circuit.

Sampler V2 disederhanakan untuk fokus pada tugasnya yang utama, yaitu sampling register output dari eksekusi Circuit kuantum. Sampler mengembalikan sampel yang tipenya didefinisikan oleh program, tanpa bobot. Data output juga dipisahkan berdasarkan nama register output yang didefinisikan oleh program. Perubahan ini memungkinkan dukungan masa depan untuk Circuit dengan classical control flow.

Lihat referensi API EstimatorV2 dan referensi API SamplerV2 untuk detail lengkapnya.

Perubahan besar​

Import​

Untuk kompatibilitas mundur, kamu harus mengimport primitif V2 secara eksplisit. Menentukan import <primitive>V2 as <primitive> tidak wajib, tapi memudahkan transisi kode ke V2.

peringatan

Setelah primitif V1 tidak lagi didukung, import <primitive> akan mengimport versi V2 dari primitif yang ditentukan.

from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit_ibm_runtime import SamplerV2 as Sampler

Input dan output​

Input​

Baik SamplerV2 maupun EstimatorV2 menerima satu atau lebih primitive unified blocs (PUB) sebagai input. Setiap PUB adalah tuple yang berisi satu Circuit dan data yang di-broadcast ke Circuit tersebut, yang bisa berupa beberapa observabel dan parameter. Setiap PUB mengembalikan satu hasil.

  • Format PUB Sampler V2: (<circuit>, <parameter values>, <shots>), di mana <parameter values> dan <shots> bersifat opsional.
  • Format PUB Estimator V2: (<circuit>, <observables>, <parameter values>, <precision>), di mana <parameter values> dan <precision> bersifat opsional. Aturan broadcasting Numpy digunakan saat menggabungkan observabel dan nilai parameter.

Selain itu, perubahan berikut telah dilakukan:

  • Estimator V2 mendapatkan argumen precision pada metode run() yang menentukan presisi target dari estimasi nilai ekspektasi.
  • Sampler V2 memiliki argumen shots pada metode run()-nya.
Contoh​

Contoh Estimator V2 yang menggunakan precision pada run():

# Estimate expectation values for two PUBs, both with 0.05 precision.
estimator.run([(circuit1, obs_array1), (circuit2, obs_array_2)], precision=0.05)

Contoh Sampler V2 yang menggunakan shots pada run():

# Sample two circuits at 128 shots each.
sampler.run([circuit1, circuit2], shots=128)

# Sample two circuits at different amounts of shots.
# The "None"s are necessary as placeholders
# for the lack of parameter values in this example.
sampler.run([
(circuit1, None, 123),
(circuit2, None, 456),
])

Output​

Output sekarang dalam format PubResult. Sebuah PubResult adalah data dan metadata yang dihasilkan dari eksekusi satu PUB.

  • Estimator V2 tetap mengembalikan nilai ekspektasi.

  • Bagian data dari PubResult Estimator V2 berisi nilai ekspektasi dan standar error (stds). V1 mengembalikan variansi di metadata.

  • Sampler V2 mengembalikan pengukuran per-shot dalam bentuk bitstring, alih-alih distribusi kuasi-probabilitas dari antarmuka V1. Bitstring menampilkan hasil pengukuran, mempertahankan urutan shot saat diukur.

  • Sampler V2 memiliki metode bantuan seperti get_counts() untuk memudahkan migrasi.

  • Objek hasil Sampler V2 mengorganisasi data berdasarkan nama register klasikal dari Circuit input, untuk kompatibilitas dengan dynamic circuit. Secara default, nama register klasikal adalah meas, seperti yang ditunjukkan pada contoh berikut. Saat mendefinisikan Circuit-mu, jika kamu membuat satu atau lebih register klasikal dengan nama non-default, gunakan nama itu untuk mendapatkan hasilnya. Kamu bisa menemukan nama register klasikal dengan menjalankan <circuit_name>.cregs. Misalnya, qc.cregs.

    # Define a quantum circuit with 2 qubits
    circuit = QuantumCircuit(2)
    circuit.h(0)
    circuit.cx(0, 1)
    circuit.measure_all()
    circuit.draw()
            β”Œβ”€β”€β”€β”      β–‘ β”Œβ”€β”
    q_0: ─ H β”œβ”€β”€β– β”€β”€β”€β–‘β”€β”€Mβ”œβ”€β”€β”€
    β””β”€β”€β”€β”˜β”Œβ”€β”΄β”€β” β–‘ β””β•₯β”˜β”Œβ”€β”
    q_1: ────── X β”œβ”€β–‘β”€β”€β•«β”€β”€Mβ”œ
    β””β”€β”€β”€β”˜ β–‘ β•‘ β””β•₯β”˜
    meas: 2/══════════════╩══╩═
    0 1

Contoh Estimator (input dan output)​

# Estimator V1: Execute 1 circuit with 4 observables
job = estimator_v1.run([circuit] * 4, [obs1, obs2, obs3, obs4])
evs = job.result().values

# Estimator V2: Execute 1 circuit with 4 observables
job = estimator_v2.run([(circuit, [obs1, obs2, obs3, obs4])])
evs = job.result()[0].data.evs

Contoh Sampler (input dan output)​

  # Sampler V1: Execute 1 circuit with 3 parameter sets
job = sampler_v1.run([circuit] * 3, [vals1, vals2, vals3])
dists = job.result().quasi_dists

# Sampler V2: Executing 1 circuit with 3 parameter sets
job = sampler_v2.run([(circuit, [vals1, vals2, vals3])])
counts = job.result()[0].data.meas.get_counts()

Contoh yang menggunakan register output berbeda

from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler

alpha = ClassicalRegister(5, "alpha")
beta = ClassicalRegister(7, "beta")
qreg = QuantumRegister(12)

circuit = QuantumCircuit(qreg, alpha, beta)
circuit.h(0)
circuit.measure(qreg[:5], alpha)
circuit.measure(qreg[5:], beta)

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=12)
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)

sampler = Sampler(backend)
job = sampler.run([isa_circuit])
result = job.result()
# Get results for the first (and only) PUB
pub_result = result[0]
print(f" >> Counts for the alpha output register: {pub_result.data.alpha.get_counts()}")
print(f" >> Counts for the beta output register: {pub_result.data.beta.get_counts()}")

Options​

Options ditentukan secara berbeda di V2 primitives dengan cara-cara berikut:

  • SamplerV2 dan EstimatorV2 sekarang punya kelas options terpisah. Kamu bisa melihat options yang tersedia dan memperbarui nilai option selama atau setelah inisialisasi primitive.
  • Alih-alih metode set_options(), V2 primitive options punya metode update() yang menerapkan perubahan ke atribut options.
  • Kalau kamu tidak menentukan nilai untuk sebuah option, option tersebut diberi nilai khusus Unset dan default server yang digunakan.
  • Untuk V2 primitives, atribut options adalah tipe Python dataclass. Kamu bisa menggunakan metode bawaan asdict untuk mengonversinya ke dictionary.

Lihat referensi API untuk daftar options yang tersedia.

from dataclasses import asdict
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Setting options during primitive initialization
estimator = Estimator(backend, options={"resilience_level": 2})

# Setting options after primitive initialization
# This uses auto complete.
estimator.options.default_shots = 4000
# This does bulk update.
estimator.options.update(default_shots=4000, resilience_level=2)

# Print the dictionary format.
# Server defaults are used for unset options.
print(asdict(estimator.options))
from dataclasses import asdict
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as Sampler

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Setting options during primitive initialization
sampler = Sampler(backend, options={"default_shots": 4096})

# Setting options after primitive initialization
# This uses auto complete.
sampler.options.dynamical_decoupling.enable = True
# Turn on gate twirling. Requires qiskit_ibm_runtime 0.23.0 or later.
sampler.options.twirling.enable_gates = True

# This does bulk update. The value for default_shots is overridden if you specify shots with run() or in the PUB.
sampler.options.update(default_shots=1024, dynamical_decoupling={"sequence_type": "XpXm"})

# Print the dictionary format.
# Server defaults are used for unset options.
print(asdict(sampler.options))

Mitigasi dan supresi error​

  • Karena Sampler V2 mengembalikan sampel tanpa postprocessing, ia tidak mendukung resilience levels.

  • Sampler V2 tidak mendukung optimization_level.

  • Estimator V2 akan menghentikan dukungan untuk optimization_level pada atau sekitar 30 September 2024.

  • Estimator V2 tidak mendukung resilience level 3. Ini karena resilience level 3 di V1 Estimator menggunakan Probabilistic Error Cancellation (PEC), yang terbukti memberikan hasil yang tidak bias dengan biaya waktu pemrosesan eksponensial. Level 3 dihapus untuk menarik perhatian pada trade-off tersebut. Namun, kamu tetap bisa menggunakan PEC sebagai metode mitigasi error dengan menentukan option pec_mitigation.

  • Estimator V2 mendukung resilience_level 0-2, sebagaimana dijelaskan dalam tabel berikut. Options ini lebih canggih dari rekan-rekan V1-nya. Kamu juga bisa secara eksplisit mengaktifkan/menonaktifkan metode mitigasi/supresi error individual.

    Level 1Level 2
    Measurement twirlingMeasurement twirling
    Mitigasi readout errorMitigasi readout error
    ZNE
from dataclasses import asdict
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Setting options during primitive initialization
estimator = Estimator(backend)

# Set resilience_level to 0
estimator.options.resilience_level = 0

# Turn on measurement error mitigation
estimator.options.resilience.measure_mitigation = True
from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(backend)
# Turn on dynamical decoupling with sequence XpXm.
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XpXm"

print(f">> dynamical decoupling sequence to use: {sampler.options.dynamical_decoupling.sequence_type}")

Transpilation​

V2 primitives hanya mendukung circuit yang mengikuti Instruction Set Architecture (ISA) dari backend tertentu. Karena primitives tidak melakukan operasi layout, routing, dan translation, option transpilasi yang terkait dari V1 tidak didukung.

Status job​

V2 primitives punya kelas RuntimeJobV2 baru, yang mewarisi dari BasePrimitiveJob. Metode status() dari kelas baru ini mengembalikan string alih-alih enum JobStatus dari Qiskit. Lihat referensi API RuntimeJobV2 untuk detailnya.

job = estimator.run(...)

# check if a job is still running
print(f"Job {job.job_id()} is still running: {job.status() == "RUNNING"}")

Langkah-langkah migrasi ke Estimator V2​

  1. Ganti from qiskit_ibm_runtime import Estimator dengan from qiskit_ibm_runtime import EstimatorV2 as Estimator.

  2. Hapus semua statement from qiskit_ibm_runtime import Options, karena kelas Options tidak digunakan oleh V2 primitives. Sebagai gantinya kamu bisa mengoper options sebagai dictionary saat menginisialisasi kelas EstimatorV2 (misalnya estimator = Estimator(backend, options={"dynamical_decoupling": {"enable": True}})), atau mengaturnya setelah inisialisasi:

    estimator = Estimator(backend)
    estimator.options.dynamical_decoupling.enable = True
  3. Tinjau semua options yang didukung dan lakukan pembaruan yang diperlukan.

  4. Kelompokkan setiap circuit yang ingin kamu jalankan dengan observables dan nilai parameter yang ingin kamu terapkan pada circuit tersebut dalam sebuah tuple (sebuah PUB). Misalnya, gunakan (circuit1, observable1, parameter_set1) jika kamu ingin menjalankan circuit1 dengan observable1 dan parameter_set1.

  5. Kamu mungkin perlu me-reshape array observables atau parameter sets jika ingin menerapkan outer product-nya. Misalnya, array observables berbentuk (4, 1) dan array parameter sets berbentuk (1, 6) akan menghasilkan (4, 6) expectation values. Lihat aturan broadcasting Numpy untuk detailnya.

  6. Kamu bisa secara opsional menentukan presisi yang kamu inginkan untuk PUB tertentu tersebut.

  7. Perbarui metode run() estimator untuk mengoper daftar PUB. Misalnya, run([(circuit1, observable1, parameter_set1)]). Kamu bisa secara opsional menentukan precision di sini, yang akan berlaku untuk semua PUB.

  8. Hasil job Estimator V2 dikelompokkan berdasarkan PUB. Kamu bisa melihat expectation value dan standard error untuk setiap PUB dengan mengindeksnya. Misalnya:

pub_result = job.result()[0]
print(f">>> Expectation values: {pub_result.data.evs}")
print(f">>> Standard errors: {pub_result.data.stds}")

Contoh lengkap Estimator​

Menjalankan satu eksperimen​

Gunakan Estimator untuk menentukan nilai ekspektasi dari satu pasangan circuit-observable.

import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import SparsePauliOp, random_hermitian
from qiskit_ibm_runtime import EstimatorV2 as Estimator, QiskitRuntimeService

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)
estimator = Estimator(backend)

n_qubits = 127

mat = np.real(random_hermitian(n_qubits, seed=1234))
circuit = IQP(mat)
observable = SparsePauliOp("Z" * n_qubits)

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)

job = estimator.run([(isa_circuit, isa_observable)])
result = job.result()

print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")

Menjalankan beberapa eksperimen dalam satu job​

Gunakan Estimator untuk menentukan nilai ekspektasi dari beberapa pasangan circuit-observable.

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)

n_qubits = 3
rng = np.random.default_rng()
mats = [np.real(random_hermitian(n_qubits, seed=rng)) for _ in range(3)]
circuits = [IQP(mat) for mat in mats]
observables = [
SparsePauliOp("X" * n_qubits),
SparsePauliOp("Y" * n_qubits),
SparsePauliOp("Z" * n_qubits),
]

isa_circuits = pm.run(circuits)
isa_observables = [ob.apply_layout(isa_circuits[0].layout) for ob in observables]

estimator = Estimator(backend)
job = estimator.run([(isa_circuits[0], isa_observables[0]),(isa_circuits[1], isa_observables[1]),(isa_circuits[2], isa_observables[2])])
job_result = job.result()
for idx in range(len(job_result)):
pub_result = job_result[idx]
print(f">>> Expectation values for PUB {idx}: {pub_result.data.evs}")
print(f">>> Standard errors for PUB {idx}: {pub_result.data.stds}")

Menjalankan circuit terparameterisasi​

Gunakan Estimator untuk menjalankan beberapa eksperimen dalam satu job, dengan memanfaatkan nilai parameter untuk meningkatkan kemampuan reuse circuit. Pada contoh berikut, perhatikan bahwa langkah 1 dan 2 sama untuk V1 maupun V2.

import numpy as np

from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService

# Step 1: Map classical inputs to a quantum problem

theta = Parameter("ΞΈ")

chsh_circuit = QuantumCircuit(2)
chsh_circuit.h(0)
chsh_circuit.cx(0, 1)
chsh_circuit.ry(theta, 0)

number_of_phases = 21
phases = np.linspace(0, 2 * np.pi, number_of_phases)
individual_phases = [[ph] for ph in phases]

ZZ = SparsePauliOp.from_list([("ZZ", 1)])
ZX = SparsePauliOp.from_list([("ZX", 1)])
XZ = SparsePauliOp.from_list([("XZ", 1)])
XX = SparsePauliOp.from_list([("XX", 1)])
ops = [ZZ, ZX, XZ, XX]

# Step 2: Optimize problem for quantum execution.

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
chsh_isa_circuit = pm.run(chsh_circuit)
isa_observables = [operator.apply_layout(chsh_isa_circuit.layout) for operator in ops]

from qiskit_ibm_runtime import EstimatorV2 as Estimator

# Step 3: Execute using Qiskit primitives.

# Reshape observable array for broadcasting
reshaped_ops = np.fromiter(isa_observables, dtype=object)
reshaped_ops = reshaped_ops.reshape((4, 1))

estimator = Estimator(backend, options={"default_shots": int(1e4)})
job = estimator.run([(chsh_isa_circuit, reshaped_ops, individual_phases)])
# Get results for the first (and only) PUB
pub_result = job.result()[0]
print(f">>> Expectation values: {pub_result.data.evs}")
print(f">>> Standard errors: {pub_result.data.stds}")
print(f">>> Metadata: {pub_result.metadata}")

Menggunakan sessions dan opsi lanjutan​

Jelajahi sessions dan opsi lanjutan untuk mengoptimalkan performa circuit di QPU.

perhatian

Blok kode berikut akan menghasilkan error bagi pengguna Open Plan karena menggunakan sessions. Workload di Open Plan hanya bisa berjalan dalam job mode atau batch mode.

import numpy as np
from qiskit.circuit.library import IQP
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp, random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, Session, EstimatorV2 as Estimator

n_qubits = 127

rng = np.random.default_rng(1234)
mat = np.real(random_hermitian(n_qubits, seed=rng))
circuit = IQP(mat)
mat = np.real(random_hermitian(n_qubits, seed=rng))
another_circuit = IQP(mat)
observable = SparsePauliOp("X" * n_qubits)
another_observable = SparsePauliOp("Y" * n_qubits)

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
another_isa_circuit = pm.run(another_circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
another_isa_observable = another_observable.apply_layout(another_isa_circuit.layout)

service = QiskitRuntimeService()

backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)

with Session(backend=backend) as session:
estimator = Estimator()

estimator.options.resilience_level = 1

job = estimator.run([(isa_circuit, isa_observable)])
another_job = estimator.run([(another_isa_circuit, another_isa_observable)])
result = job.result()
another_result = another_job.result()

# first job
print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")

# second job
print(f" > Another Expectation value: {another_result[0].data.evs}")
print(f" > More Metadata: {another_result[0].metadata}")

Langkah-langkah migrasi ke Sampler V2​

  1. Ganti from qiskit_ibm_runtime import Sampler dengan from qiskit_ibm_runtime import SamplerV2 as Sampler.
  2. Hapus semua pernyataan from qiskit_ibm_runtime import Options, karena kelas Options tidak digunakan oleh primitif V2. Kamu bisa meneruskan opsi sebagai dictionary saat menginisialisasi kelas SamplerV2 (misalnya sampler = Sampler(backend, options={"default_shots": 1024})), atau mengaturnya setelah inisialisasi:
    sampler = Sampler(backend)
    sampler.options.default_shots = 1024
  3. Tinjau semua opsi yang didukung dan lakukan pembaruan yang diperlukan.
  4. Kelompokkan setiap Circuit yang ingin kamu jalankan bersama observable dan nilai parameter yang ingin kamu terapkan ke Circuit tersebut dalam sebuah tuple (sebuah PUB). Misalnya, gunakan (circuit1, parameter_set1) jika ingin menjalankan circuit1 dengan parameter_set1. Kamu bisa secara opsional menentukan shots yang diinginkan untuk PUB tertentu tersebut.
  5. Perbarui metode run() Sampler untuk meneruskan daftar PUB. Misalnya, run([(circuit1, parameter_set1)]). Kamu bisa secara opsional menentukan shots di sini, yang akan berlaku untuk semua PUB.
  6. Hasil job Sampler V2 dikelompokkan berdasarkan PUB. Kamu bisa melihat data output untuk setiap PUB dengan mengindeksnya. Sementara Sampler V2 mengembalikan sampel yang tidak berbobot, kelas hasil memiliki metode kemudahan untuk mendapatkan counts sebagai gantinya. Misalnya:
pub_result = job.result()[0]
print(f">>> Counts: {pub_result.data.meas.get_counts()}")
print(f">>> Per-shot measurement: {pub_result.data.meas.get_counts()}")
catatan

Kamu perlu nama classical register untuk mendapatkan hasilnya. Secara default, namanya adalah meas saat kamu menggunakan measure_all(). Saat mendefinisikan Circuit, jika kamu membuat satu atau lebih classical register dengan nama non-default, gunakan nama tersebut untuk mendapatkan hasilnya. Kamu bisa menemukan nama classical register dengan menjalankan <circuit_name>.cregs. Misalnya, qc.cregs.

Contoh lengkap Sampler​

Menjalankan satu eksperimen​

Gunakan Sampler untuk menentukan counts atau distribusi quasi-probabilitas dari satu Circuit.

import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

service = QiskitRuntimeService()

backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)

n_qubits = 127

mat = np.real(random_hermitian(n_qubits, seed=1234))
circuit = IQP(mat)
circuit.measure_all()

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

sampler = Sampler(backend)
job = sampler.run([isa_circuit])
result = job.result()

Menjalankan beberapa eksperimen dalam satu job​

Gunakan Sampler untuk menentukan counts atau distribusi quasi-probabilitas dari beberapa Circuit dalam satu job.

import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler

service = QiskitRuntimeService()

backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)

n_qubits = 127

rng = np.random.default_rng()
mats = [np.real(random_hermitian(n_qubits, seed=rng)) for _ in range(3)]
circuits = [IQP(mat) for mat in mats]
for circuit in circuits:
circuit.measure_all()

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuits = pm.run(circuits)

sampler = Sampler(backend)
job = sampler.run(isa_circuits)
result = job.result()

for idx, pub_result in enumerate(result):
print(f" > Counts for pub {idx}: {pub_result.data.meas.get_counts()}")

Menjalankan Circuit berparameter​

Jalankan beberapa eksperimen dalam satu job, memanfaatkan nilai parameter untuk meningkatkan keterbacaan Circuit.

import numpy as np
from qiskit.circuit.library import RealAmplitudes
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService

# Step 1: Map classical inputs to a quantum problem
num_qubits = 127
circuit = RealAmplitudes(num_qubits=num_qubits, reps=2)
circuit.measure_all()

# Define three sets of parameters for the circuit
rng = np.random.default_rng(1234)
parameter_values = [
rng.uniform(-np.pi, np.pi, size=circuit.num_parameters) for _ in range(3)
]

# Step 2: Optimize problem for quantum execution.

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=num_qubits)

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

# Step 3: Execute using Qiskit primitives.

from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(backend)
job = sampler.run([(isa_circuit, parameter_values)])
result = job.result()
# Get results for the first (and only) PUB
pub_result = result[0]
# Get counts from the classical register "meas".
print(f" >> Counts for the meas output register: {pub_result.data.meas.get_counts()}")

Menggunakan Session dan opsi lanjutan​

Jelajahi Session dan opsi lanjutan untuk mengoptimalkan performa Circuit pada QPU.

perhatian

Blok kode berikut akan mengembalikan error bagi pengguna dengan Open Plan karena menggunakan Session. Workload pada Open Plan hanya bisa berjalan dalam mode job atau mode batch.

import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler, Session

n_qubits = 127

rng = np.random.default_rng(1234)
mat = np.real(random_hermitian(n_qubits, seed=rng))
circuit = IQP(mat)
circuit.measure_all()
mat = np.real(random_hermitian(n_qubits, seed=rng))
another_circuit = IQP(mat)
another_circuit.measure_all()

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)
another_isa_circuit = pm.run(another_circuit)

service = QiskitRuntimeService()

# Turn on dynamical decoupling with sequence XpXm.
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XpXm"

backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)

with Session(backend=backend) as session:
sampler = Sampler()
job = sampler.run([isa_circuit])
another_job = sampler.run([another_isa_circuit])
result = job.result()
another_result = another_job.result()

# first job
print(f" > Counts for job 1: {result[0].data.meas.get_counts()}")

# second job
print(f" > Counts for job 2: {another_result[0].data.meas.get_counts()}")

Langkah selanjutnya​

Rekomendasi
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