Migrasi ke primitif V2 Qiskit Runtime
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.
Setelah primitif V1 tidak lagi didukung, import <primitive> akan mengimport versi V2 dari primitif yang ditentukan.
- Estimator V2
- Estimator (V1)
from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit_ibm_runtime import Estimator
- Sampler V2
- Sampler (V1)
from qiskit_ibm_runtime import SamplerV2 as Sampler
from qiskit_ibm_runtime import 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
precisionpada metoderun()yang menentukan presisi target dari estimasi nilai ekspektasi. - Sampler V2 memiliki argumen
shotspada metoderun()-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
datadari 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)β
- 1 circuit, 4 observables
- 1 circuit, 4 observables, 2 parameter sets
- 2 circuits, 2 observables
# 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
# Estimator V1: Execute 1 circuit with 4 observables and 2 parameter sets
job = estimator_v1.run([circuit] * 8, [obs1, obs2, obs3, obs4] * 2, [vals1, vals2] * 4)
evs = job.result().values
# Estimator V2: Execute 1 circuit with 4 observables and 2 parameter sets
job = estimator_v2.run([(circuit, [[obs1], [obs2], [obs3], [obs4]], [[vals1], [vals2]])])
evs = job.result()[0].data.evs
# Estimator V1: Cannot execute 2 circuits with different observables
# Estimator V2: Execute 2 circuits with 2 different observables. There are
# two PUBs because each PUB can have only one circuit.
job = estimator_v2.run([(circuit1, obs1), (circuit2, obs2)])
evs1 = job.result()[0].data.evs # result for pub 1 (circuit 1)
evs2 = job.result()[1].data.evs # result for pub 2 (circuit 2)
Contoh Sampler (input dan output)β
- 1 circuit, 3 parameter sets
- 2 circuits, 1 parameter set
- Convert V2 output to V1 format
# 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()
# Sampler V1: Execute 2 circuits with 1 parameter set
job = sampler_v1.run([circuit1, circuit2], [vals1] * 2)
dists = job.result().quasi_dists
# Sampler V2: Execute 2 circuits with 1 parameter set
job = sampler_v2.run([(circuit1, vals1), (circuit2, vals1)])
counts1 = job.result()[0].data.meas.get_counts() # result for pub 1 (circuit 1)
counts2 = job.result()[1].data.meas.get_counts() # result for pub 2 (circuit 2)
Format output V1 adalah kamus dengan bitstring (sebagai int) sebagai kunci dan kuasi-probabilitas sebagai nilai untuk setiap Circuit. Format V2 memiliki kunci yang sama (tapi sebagai string) dan hitungan sebagai nilainya. Untuk mengonversi format V2 ke V1, bagi hitungan dengan jumlah shot, di mana jumlah shot yang dipilih dijelaskan dalam panduan Tentukan opsi.
v2_result = sampler_v2_job.result()
v1_format = []
for pub_result in v2_result:
counts = pub_result.data.meas.get_counts()
v1_format.append( {int(key, 2): val/shots for key, val in counts.items()} )
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:
SamplerV2danEstimatorV2sekarang 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 metodeupdate()yang menerapkan perubahan ke atributoptions. - Kalau kamu tidak menentukan nilai untuk sebuah option, option tersebut diberi nilai khusus
Unsetdan default server yang digunakan. - Untuk V2 primitives, atribut
optionsadalah tipe Pythondataclass. Kamu bisa menggunakan metode bawaanasdictuntuk mengonversinya ke dictionary.
Lihat referensi API untuk daftar options yang tersedia.
- Estimator V2
- Estimator (V1)
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 qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Options
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# Setting options during primitive initialization
options = Options()
# This uses auto complete.
options.resilience_level = 2
estimator = Estimator(backend=backend, options=options)
# Setting options after primitive initialization.
# This does bulk update.
estimator.set_options(shots=4000)
- Sampler V2
- Sampler (V1)
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))
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Options
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# Setting options during primitive initialization
options = Options()
# This uses auto complete.
options.resilience_level = 2
sampler = Sampler(backend=backend, options=options)
# Setting options after primitive initialization.
# This does bulk update.
sampler.set_options(shots=2000)
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_levelpada 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_level0-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 1 Level 2 Measurement twirling Measurement twirling Mitigasi readout error Mitigasi readout error ZNE
- Estimator V2
- Estimator (V1)
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 Estimator, Options
estimator = Estimator(backend, options=options)
options = Options()
options.resilience_level = 2
- Sampler V2
- Sampler (V1)
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}")
from qiskit_ibm_runtime import Sampler, Options
sampler = Sampler(backend, options=options)
options = Options()
options.resilience_level = 2
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.
- V2 primitives
- V1 primitives
job = estimator.run(...)
# check if a job is still running
print(f"Job {job.job_id()} is still running: {job.status() == "RUNNING"}")
from qiskit.providers.jobstatus import JobStatus
job = estimator.run(...)
#check if a job is still running
print(f"Job {job.job_id()} is still running: {job.status() is JobStatus.RUNNING}")
Langkah-langkah migrasi ke Estimator V2β
-
Ganti
from qiskit_ibm_runtime import Estimatordenganfrom qiskit_ibm_runtime import EstimatorV2 as Estimator. -
Hapus semua statement
from qiskit_ibm_runtime import Options, karena kelasOptionstidak digunakan oleh V2 primitives. Sebagai gantinya kamu bisa mengoper options sebagai dictionary saat menginisialisasi kelasEstimatorV2(misalnyaestimator = Estimator(backend, options={"dynamical_decoupling": {"enable": True}})), atau mengaturnya setelah inisialisasi:estimator = Estimator(backend)
estimator.options.dynamical_decoupling.enable = True -
Tinjau semua options yang didukung dan lakukan pembaruan yang diperlukan.
-
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 menjalankancircuit1denganobservable1danparameter_set1. -
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.
-
Kamu bisa secara opsional menentukan presisi yang kamu inginkan untuk PUB tertentu tersebut.
-
Perbarui metode
run()estimator untuk mengoper daftar PUB. Misalnya,run([(circuit1, observable1, parameter_set1)]). Kamu bisa secara opsional menentukanprecisiondi sini, yang akan berlaku untuk semua PUB. -
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.
- Estimator V2
- Estimator (V1)
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}")
import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import SparsePauliOp, random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, Estimator
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)
observable = SparsePauliOp("Z" * n_qubits)
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
estimator = Estimator(backend)
job = estimator.run(isa_circuit, isa_observable)
result = job.result()
print(f" > Observable: {observable.paulis}")
print(f" > Expectation value: {result.values}")
print(f" > Metadata: {result.metadata}")
Menjalankan beberapa eksperimen dalam satu jobβ
Gunakan Estimator untuk menentukan nilai ekspektasi dari beberapa pasangan circuit-observable.
- Estimator V2
- Estimator (V1)
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}")
import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import SparsePauliOp, random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, Estimator
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]
observables = [
SparsePauliOp("X" * n_qubits),
SparsePauliOp("Y" * n_qubits),
SparsePauliOp("Z" * n_qubits),
]
# Get ISA circuits
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
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, isa_observables)
result = job.result()
print(f" > Expectation values: {result.values}")
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.
- Estimator V2
- Estimator (V1)
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}")
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 Estimator
# Step 3: Execute using Qiskit Primitives.
num_ops = len(isa_observables)
batch_circuits = [chsh_isa_circuit] * number_of_phases * num_ops
batch_ops = [op for op in isa_observables for _ in individual_phases]
batch_phases = individual_phases * num_ops
estimator = Estimator(backend, options={"shots": int(1e4)})
job = estimator.run(batch_circuits, batch_ops, batch_phases)
expvals = job.result().values
Menggunakan sessions dan opsi lanjutanβ
Jelajahi sessions dan opsi lanjutan untuk mengoptimalkan performa circuit di QPU.
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.
- Estimator V2
- Estimator (V1)
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}")
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, Estimator, Options
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(backend=backend, optimization_level=1)
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)
options = Options()
options.optimization_level = 2
options.resilience_level = 2
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)
with Session(backend=backend) as session:
estimator = Estimator(options=options)
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 values job 1: {result.values}")
# second job
print(f" > Expectation values job 2: {another_result.values}")
Langkah-langkah migrasi ke Sampler V2β
- Ganti
from qiskit_ibm_runtime import Samplerdenganfrom qiskit_ibm_runtime import SamplerV2 as Sampler. - Hapus semua pernyataan
from qiskit_ibm_runtime import Options, karena kelasOptionstidak digunakan oleh primitif V2. Kamu bisa meneruskan opsi sebagai dictionary saat menginisialisasi kelasSamplerV2(misalnyasampler = Sampler(backend, options={"default_shots": 1024})), atau mengaturnya setelah inisialisasi:sampler = Sampler(backend)
sampler.options.default_shots = 1024 - Tinjau semua opsi yang didukung dan lakukan pembaruan yang diperlukan.
- 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 menjalankancircuit1denganparameter_set1. Kamu bisa secara opsional menentukan shots yang diinginkan untuk PUB tertentu tersebut. - Perbarui metode
run()Sampler untuk meneruskan daftar PUB. Misalnya,run([(circuit1, parameter_set1)]). Kamu bisa secara opsional menentukanshotsdi sini, yang akan berlaku untuk semua PUB. - 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()}")
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.
- Sampler V2
- Sampler (V1)
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()
import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
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()
sampler = Sampler(backend)
job = sampler.run(circuit)
result = job.result()
print(f" > Quasi-probability distribution: {result.quasi_dists}")
print(f" > Metadata: {result.metadata}")
Menjalankan beberapa eksperimen dalam satu jobβ
Gunakan Sampler untuk menentukan counts atau distribusi quasi-probabilitas dari beberapa Circuit dalam satu job.
- Sampler V2
- Sampler (V1)
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()}")
import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, 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()
sampler = Sampler(backend)
job = sampler.run(circuits)
result = job.result()
print(f" > Quasi-probability distribution: {result.quasi_dists}")
Menjalankan Circuit berparameterβ
Jalankan beberapa eksperimen dalam satu job, memanfaatkan nilai parameter untuk meningkatkan keterbacaan Circuit.
- Sampler V2
- Sampler (V1)
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()}")
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 = 5
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 Sampler
sampler = Sampler(backend)
job = sampler.run([isa_circuit] * 3, parameter_values)
result = job.result()
print(f" > Quasi-probability distribution: {result.quasi_dists}")
print(f" > Metadata: {result.metadata}")
Menggunakan Session dan opsi lanjutanβ
Jelajahi Session dan opsi lanjutan untuk mengoptimalkan performa Circuit pada QPU.
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.
- Sampler V2
- Sampler (V1)
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()}")
import numpy as np
from qiskit.circuit.library import IQP
from qiskit.quantum_info import random_hermitian
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Session, Options
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()
options = Options()
options.optimization_level = 2
options.resilience_level = 0
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)
with Session(backend=backend) as session:
sampler = Sampler(options=options)
job = sampler.run(circuit)
another_job = sampler.run(another_circuit)
result = job.result()
another_result = another_job.result()
# first job
print(f" > Quasi-probability distribution job 1: {result.quasi_dists}")
# second job
print(f" > Quasi-probability distribution job 2: {another_result.quasi_dists}")
Langkah selanjutnyaβ
- Pelajari lebih lanjut tentang pengaturan opsi di panduan Tentukan opsi.
- Pelajari lebih detail tentang Input dan output Primitif.
- Bereksperimen dengan tutorial CHSH Inequality.