Migrasi ke primitif Qiskit Runtime V2
Primitif asal (dirujuk sebagai primitif V1), V1 Sampler dan V1 Estimator, telah ditamatkan dalam qiskit-ibm-runtime 0.23.
Sokongan untuk primitif tersebut telah dihentikan pada 15 Ogos 2024.
Memandangkan primitif V1 telah ditamatkan, semua kod perlu dimigrasi untuk menggunakan antara muka V2. Panduan ini menerangkan apa yang berubah dalam primitif Qiskit Runtime V2 (tersedia dengan qiskit-ibm-runtime 0.21.0) dan sebabnya, menerangkan setiap primitif baru secara terperinci, dan memberikan contoh untuk membantu anda migrasi kod daripada primitif lama ke primitif V2. Contoh-contoh dalam panduan ini semuanya menggunakan primitif Qiskit Runtime, tetapi secara umumnya, perubahan yang sama juga terpakai pada implementasi primitif lain. Fungsi-fungsi yang unik untuk Qiskit Runtime seperti pengurangan ralat kekal unik untuk Qiskit Runtime.
Untuk maklumat tentang perubahan pada primitif rujukan Qiskit (kini dipanggil primitif statevector), lihat bahagian qiskit.primitives dalam halaman perubahan ciri Qiskit 1.0. Lihat StatevectorSampler dan StatevectorEstimator untuk implementasi rujukan primitif V2.
Gambaran keseluruhanβ
Versi 2 bagi primitif diperkenalkan dengan kelas asas baru untuk kedua-dua Sampler dan Estimator (BaseSamplerV2 dan BaseEstimatorV2), bersama dengan jenis baharu untuk input dan output mereka.
Antara muka baharu ini membolehkan anda menentukan satu Circuit dan berbilang observable (jika menggunakan Estimator) serta set nilai parameter untuk Circuit tersebut, supaya sapuan ke atas set nilai parameter dan observable boleh ditentukan dengan cekap. Sebelum ini, anda perlu menentukan Circuit yang sama beberapa kali untuk memadankan saiz data yang hendak digabungkan. Selain itu, walaupun anda masih boleh menggunakan resilience_level (jika menggunakan Estimator) sebagai kawalan mudah, primitif V2 memberikan anda fleksibiliti untuk menghidupkan atau mematikan kaedah pengurangan / penindasan ralat secara individu bagi memenuhi keperluan anda.
Untuk mengurangkan jumlah masa pelaksanaan kerja, primitif V2 hanya menerima Circuit dan observable yang menggunakan arahan yang disokong oleh QPU (unit pemprosesan kuantum) sasaran. Circuit dan observable sedemikian dirujuk sebagai Circuit dan observable set seni bina arahan (ISA). Primitif V2 tidak melakukan operasi reka letak, penghalaan, dan penterjemahan. Lihat dokumentasi transpilasi untuk arahan mengubah Circuit.
Sampler V2 dipermudahkan untuk menumpukan pada tugas terasnya iaitu pensampelan daftar output daripada pelaksanaan Circuit kuantum. Ia mengembalikan sampel, yang jenisnya ditentukan oleh program, tanpa pemberat. Data output juga diasingkan mengikut nama daftar output yang ditentukan oleh program. Perubahan ini membolehkan sokongan masa hadapan untuk Circuit dengan aliran kawalan klasik.
Lihat rujukan API EstimatorV2 dan rujukan API SamplerV2 untuk butiran penuh.
Perubahan utamaβ
Importβ
Untuk keserasian ke belakang, anda perlu mengimport primitif V2 secara eksplisit. Menentukan import <primitive>V2 as <primitive> tidak diwajibkan, tetapi memudahkan peralihan kod ke V2.
Selepas primitif V1 tidak lagi disokong, import <primitive> akan mengimport versi V2 bagi 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β
Kedua-dua SamplerV2 dan EstimatorV2 menerima satu atau lebih primitive unified blocs (PUB) sebagai input. Setiap PUB ialah tuple yang mengandungi satu Circuit dan data yang disiarkan ke Circuit tersebut, yang boleh merangkumi berbilang observable dan parameter. Setiap PUB mengembalikan satu keputusan.
- Format PUB Sampler V2: (
<circuit>,<parameter values>,<shots>), di mana<parameter values>dan<shots>adalah pilihan. - Format PUB Estimator V2: (
<circuit>,<observables>,<parameter values>,<precision>), di mana<parameter values>dan<precision>adalah pilihan. Peraturan penyiaran Numpy digunakan ketika menggabungkan observable dan nilai parameter.
Selain itu, perubahan berikut telah dibuat:
- Estimator V2 mempunyai hujah
precisiondalam kaedahrun()yang menentukan ketepatan sasaran bagi anggaran nilai jangkaan. - Sampler V2 mempunyai hujah
shotsdalam kaedahrun()-nya.
Contohβ
Contoh Estimator V2 yang menggunakan precision dalam 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 dalam 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 kini dalam format PubResult. PubResult ialah data dan metadata yang terhasil daripada pelaksanaan satu PUB.
-
Estimator V2 terus mengembalikan nilai jangkaan.
-
Bahagian
datadalam PubResult Estimator V2 mengandungi kedua-dua nilai jangkaan dan ralat piawai (stds). V1 mengembalikan varians dalam metadata. -
Sampler V2 mengembalikan pengukuran per-shot dalam bentuk bitstring, berbanding dengan taburan kuasi-kebarangkalian daripada antara muka V1. Bitstring menunjukkan hasil pengukuran, mengekalkan susunan shot mengikut urutan pengukuran.
-
Sampler V2 mempunyai kaedah kemudahan seperti
get_counts()untuk membantu penghijrahan. -
Objek keputusan Sampler V2 mengorganisasi data mengikut nama daftar klasik Circuit input, untuk keserasian dengan Circuit dinamik. Secara lalai, nama daftar klasik ialah
meas, seperti yang ditunjukkan dalam contoh berikut. Semasa menentukan Circuit anda, jika anda membuat satu atau lebih daftar klasik dengan nama bukan lalai, gunakan nama tersebut untuk mendapatkan keputusan. Anda boleh mencari nama daftar klasik dengan menjalankan<circuit_name>.cregs. Contohnya,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 ialah kamus bitstring (sebagai int) sebagai kunci dan kuasi-kebarangkalian sebagai nilai untuk setiap Circuit. Format V2 mempunyai kunci yang sama (tetapi sebagai string) dan bilangan sebagai nilainya. Untuk menukar format V2 ke V1, bahagikan bilangan dengan bilangan shots, di mana bilangan shots yang dipilih diterangkan dalam panduan Tentukan pilihan.
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 daftar output berbeza
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()}")
Pilihanβ
Pilihan ditentukan secara berbeza dalam primitif V2 seperti berikut:
SamplerV2danEstimatorV2kini mempunyai kelas pilihan yang berasingan. Anda boleh melihat pilihan yang tersedia dan mengemas kini nilai pilihan semasa atau selepas permulaan primitif.- Berbanding kaedah
set_options(), pilihan primitif V2 menggunakan kaedahupdate()yang menerapkan perubahan pada atributoptions. - Jika anda tidak menentukan nilai untuk sesuatu pilihan, ia diberi nilai khas
Unsetdan lalai pelayan digunakan. - Untuk primitif V2, atribut
optionsadalah jenis Pythondataclass. Anda boleh menggunakan kaedah bawaanasdictuntuk menukarnya kepada kamus.
Lihat rujukan API untuk senarai pilihan 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)
Pengurangan dan penindasan ralatβ
-
Memandangkan Sampler V2 mengembalikan sampel tanpa pasca-pemprosesan, ia tidak menyokong tahap ketahanan (resilience levels).
-
Sampler V2 tidak menyokong
optimization_level. -
Estimator V2 akan menggugurkan sokongan untuk
optimization_levelpada atau sekitar 30 September 2024. -
Estimator V2 tidak menyokong tahap ketahanan 3. Ini kerana tahap ketahanan 3 dalam V1 Estimator menggunakan Probabilistic Error Cancellation (PEC), yang terbukti memberikan keputusan tidak berat sebelah dengan kos masa pemprosesan eksponen. Tahap 3 dibuang untuk menarik perhatian kepada pertukaran tersebut. Walau bagaimanapun, anda masih boleh menggunakan PEC sebagai kaedah pengurangan ralat dengan menentukan pilihan
pec_mitigation. -
Estimator V2 menyokong
resilience_level0-2, seperti yang diterangkan dalam jadual berikut. Pilihan-pilihan ini lebih canggih berbanding rakan sejawat V1. Anda juga boleh menghidupkan / mematikan kaedah pengurangan / penindasan ralat individu secara eksplisit.Tahap 1 Tahap 2 Measurement twirling Measurement twirling Readout error mitigation Readout error mitigation 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
Transpilasiβ
Primitif V2 hanya menyokong Circuit yang mematuhi Set Seni Bina Arahan (ISA) bagi Backend tertentu. Memandangkan primitif tidak melakukan operasi reka letak, penghalaan, dan penterjemahan, pilihan transpilasi yang berkaitan daripada V1 tidak disokong.
Status kerjaβ
Primitif V2 mempunyai kelas RuntimeJobV2 baharu, yang diwarisi daripada BasePrimitiveJob. Kaedah status() bagi kelas baharu ini mengembalikan string berbanding enum JobStatus daripada Qiskit. Lihat rujukan API RuntimeJobV2 untuk butiran.
- 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β
-
Gantikan
from qiskit_ibm_runtime import Estimatordenganfrom qiskit_ibm_runtime import EstimatorV2 as Estimator. -
Buang sebarang pernyataan
from qiskit_ibm_runtime import Options, kerana kelasOptionstidak digunakan oleh primitif V2. Sebaliknya, anda boleh menghantar pilihan sebagai kamus semasa memulakan kelasEstimatorV2(contohnyaestimator = Estimator(backend, options={"dynamical_decoupling": {"enable": True}})), atau tetapkannya selepas permulaan:estimator = Estimator(backend)
estimator.options.dynamical_decoupling.enable = True -
Semak semua pilihan yang disokong dan buat kemas kini mengikutnya.
-
Kumpulkan setiap Circuit yang ingin anda jalankan bersama observable dan nilai parameter yang ingin anda terapkan pada Circuit tersebut dalam satu tuple (PUB). Contohnya, gunakan
(circuit1, observable1, parameter_set1)jika anda ingin menjalankancircuit1denganobservable1danparameter_set1. -
Anda mungkin perlu membentuk semula tatasusunan observable atau set parameter jika anda ingin menerapkan hasil darab luar mereka. Contohnya, tatasusunan observable bersaiz (4, 1) dan tatasusunan set parameter bersaiz (1, 6) akan memberikan keputusan (4, 6) nilai jangkaan. Lihat peraturan penyiaran Numpy untuk butiran lanjut.
-
Anda boleh secara pilihan menentukan ketepatan yang anda inginkan untuk PUB khusus tersebut.
-
Kemas kini kaedah
run()estimator untuk menghantar senarai PUB. Contohnya,run([(circuit1, observable1, parameter_set1)]). Anda boleh secara pilihan menentukanprecisiondi sini, yang akan terpakai pada semua PUB. -
Keputusan kerja Estimator V2 dikumpulkan mengikut PUB. Anda boleh melihat nilai jangkaan dan ralat piawai untuk setiap PUB dengan mengindeksnya. Contohnya:
pub_result = job.result()[0]
print(f">>> Expectation values: {pub_result.data.evs}")
print(f">>> Standard errors: {pub_result.data.stds}")
Contoh lengkap Estimatorβ
Jalankan satu eksperimenβ
Gunakan Estimator untuk menentukan nilai jangkaan bagi sepasang Circuit-observable tunggal.
- 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}")
Jalankan beberapa eksperimen dalam satu kerjaβ
Gunakan Estimator untuk menentukan nilai jangkaan bagi 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}")
Jalankan Circuit berparameterβ
Gunakan Estimator untuk menjalankan beberapa eksperimen dalam satu kerja, dengan memanfaatkan nilai parameter bagi meningkatkan kebolehgunaan semula Circuit. Dalam contoh berikut, perhatikan bahawa langkah 1 dan 2 adalah sama untuk V1 dan 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
Gunakan Session dan pilihan lanjutanβ
Terokai Session dan pilihan lanjutan untuk mengoptimumkan prestasi Circuit pada QPU.
Blok kod berikut akan mengembalikan ralat bagi pengguna pada Pelan Terbuka kerana ia menggunakan Session. Beban kerja pada Pelan Terbuka hanya boleh dijalankan dalam mod kerja atau mod kelompok.
- 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 untuk berpindah ke Sampler V2β
- Gantikan
from qiskit_ibm_runtime import Samplerdenganfrom qiskit_ibm_runtime import SamplerV2 as Sampler. - Buang sebarang pernyataan
from qiskit_ibm_runtime import Options, kerana kelasOptionstidak digunakan oleh primitif V2. Sebaliknya, anda boleh menghantar pilihan sebagai kamus semasa memulakan kelasSamplerV2(contohnyasampler = Sampler(backend, options={"default_shots": 1024})), atau tetapkannya selepas permulaan:sampler = Sampler(backend)
sampler.options.default_shots = 1024 - Semak semua pilihan yang disokong dan buat kemas kini yang sesuai.
- Kumpulkan setiap Circuit yang ingin anda jalankan bersama observable dan nilai parameter yang ingin anda gunakan pada Circuit itu dalam satu tuple (PUB). Contohnya, gunakan
(circuit1, parameter_set1)jika anda ingin menjalankancircuit1denganparameter_set1. Anda boleh menentukan bilangan shot yang dikehendaki untuk PUB tertentu itu secara pilihan. - Kemas kini kaedah
run()Sampler untuk menghantar senarai PUB. Contohnya,run([(circuit1, parameter_set1)]). Anda boleh menentukanshotssecara pilihan di sini, yang akan digunakan pada semua PUB. - Keputusan kerja Sampler V2 dikumpulkan mengikut PUB. Anda boleh melihat data output untuk setiap PUB dengan mengindeksnya. Walaupun Sampler V2 mengembalikan sampel tanpa pemberat, kelas keputusan mempunyai kaedah kemudahan untuk mendapatkan kiraan. Contohnya:
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()}")
Anda memerlukan nama daftar klasik untuk mendapatkan keputusan. Secara lalai, ia dinamakan meas apabila anda menggunakan measure_all(). Apabila menentukan Circuit anda, jika anda mencipta satu atau lebih daftar klasik dengan nama bukan lalai, gunakan nama tersebut untuk mendapatkan keputusan. Anda boleh mencari nama daftar klasik dengan menjalankan <circuit_name>.cregs. Contohnya, qc.cregs.
Contoh lengkap Samplerβ
Jalankan satu eksperimenβ
Gunakan Sampler untuk menentukan kiraan atau taburan kebarangkalian separuh bagi satu Circuit tunggal.
- 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}")
Jalankan beberapa eksperimen dalam satu kerjaβ
Gunakan Sampler untuk menentukan kiraan atau taburan kebarangkalian separuh bagi beberapa Circuit dalam satu kerja.
- 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}")
Jalankan Circuit berparameterβ
Jalankan beberapa eksperimen dalam satu kerja, memanfaatkan nilai parameter untuk meningkatkan kebolehgunaan semula 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}")
Gunakan Session dan pilihan lanjutanβ
Terokai Session dan pilihan lanjutan untuk mengoptimumkan prestasi Circuit pada QPU.
Blok kod berikut akan mengembalikan ralat bagi pengguna dalam Pelan Terbuka kerana ia menggunakan Session. Beban kerja dalam Pelan Terbuka hanya boleh dijalankan dalam mod kerja atau mod kelompok.
- 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 seterusnyaβ
- Ketahui lebih lanjut tentang menetapkan pilihan dalam panduan Tentukan pilihan.
- Ketahui lebih lanjut tentang Input dan output primitif.
- Cuba dengan tutorial Ketaksamaan CHSH.