Mag-migrate sa Qiskit Runtime V2 primitives
Ang mga orihinal na primitives (tinatawag na V1 primitives), V1 Sampler at V1 Estimator, ay na-deprecate na sa qiskit-ibm-runtime 0.23.
Tinanggal na ang suporta para sa mga ito noong 15 Agosto 2024.
Dahil sa deprecation ng mga V1 primitives, dapat na i-migrate ang lahat ng code para gamitin ang mga V2 interface. Inilalarawan ng gabay na ito kung ano ang nagbago sa Qiskit Runtime V2 primitives (available sa qiskit-ibm-runtime 0.21.0) at kung bakit, inilarawan nang detalyado ang bawat bagong primitive, at nagbibigay ng mga halimbawa para matulungan kang i-migrate ang code mula sa paggamit ng mga legacy primitive patungo sa mga V2 primitive. Lahat ng halimbawa sa gabay ay gumagamit ng Qiskit Runtime primitives, pero sa pangkalahatan, ang parehong mga pagbabago ay naaangkop din sa iba pang mga implementasyon ng primitive. Ang mga function na natatangi sa Qiskit Runtime tulad ng error mitigation ay nananatiling natatangi sa Qiskit Runtime.
Para sa impormasyon tungkol sa mga pagbabago sa Qiskit reference primitives (tinatawag na ngayon na statevector primitives), tingnan ang seksyon ng qiskit.primitives sa pahina ng Qiskit 1.0 feature changes. Tingnan ang StatevectorSampler at StatevectorEstimator para sa mga V2 primitive reference implementation.
Pangkalahatang-ideyaβ
Ipinakilala ang Bersyon 2 ng mga primitives na may bagong base class para sa parehong Sampler at Estimator (BaseSamplerV2 at BaseEstimatorV2), kasama ang mga bagong uri para sa kanilang mga input at output.
Pinahihintulutan ng bagong interface na tukuyin mo ang isang Circuit at maraming observables (kung gumagamit ng Estimator) at mga set ng parameter value para sa Circuit na iyon, para ang mga sweep sa mga set ng parameter value at observables ay maaaring tukuyin nang mahusay. Dati, kailangan mong tukuyin nang paulit-ulit ang parehong Circuit para tumugma sa laki ng data na pagsamasamahin. Gayundin, habang maaari ka pa ring gumamit ng resilience_level (kung gumagamit ng Estimator) bilang simpleng kontrol, binibigyan ka ng V2 primitives ng kakayahang i-on o i-off ang mga indibidwal na paraan ng error mitigation / suppression para i-customize ang mga ito ayon sa iyong pangangailangan.
Para mabawasan ang kabuuang oras ng pagsasagawa ng job, tinatanggap lamang ng V2 primitives ang mga Circuit at observable na gumagamit ng mga instruction na sinusuportahan ng target na QPU (quantum processing unit). Ang mga Circuit at observable na ito ay tinutukoy bilang instruction set architecture (ISA) circuits at observables. Hindi nagsasagawa ang V2 primitives ng mga operasyon ng layout, routing, at translation. Tingnan ang dokumentasyon ng transpilation para sa mga tagubilin sa pag-transform ng mga Circuit.
Ang Sampler V2 ay pinahusay para makatutok sa pangunahing gawain nito na pag-sample ng output register mula sa pagpapatupad ng mga quantum circuit. Ibinabalik nito ang mga sample, ang uri nito ay tinukoy ng programa, nang walang mga timbang. Ang output data ay pinaghiwalay din ayon sa mga pangalan ng output register na tinukoy ng programa. Ang pagbabagong ito ay nagbibigay-daan sa hinaharap na suporta para sa mga Circuit na may classical control flow.
Tingnan ang EstimatorV2 API reference at SamplerV2 API reference para sa buong detalye.
Mga pangunahing pagbabagoβ
Importβ
Para sa backward compatibility, kailangan mong explicitly i-import ang mga V2 primitives. Ang pagtukoy ng import <primitive>V2 as <primitive> ay hindi required, pero mas pinapadali nito ang pag-transition ng code sa V2.
Pagkatapos na hindi na sinusuportahan ang mga V1 primitives, ang import <primitive> ay mag-i-import ng V2 na bersyon ng tinukoy na primitive.
- 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 at outputβ
Inputβ
Parehong SamplerV2 at EstimatorV2 ay tumatanggap ng isa o higit pang primitive unified blocs (PUBs) bilang input. Ang bawat PUB ay isang tuple na naglalaman ng isang Circuit at ang data na ibino-broadcast sa Circuit na iyon, na maaaring maraming observables at mga parameter. Bawat PUB ay nagbabalik ng resulta.
- Format ng Sampler V2 PUB: (
<circuit>,<parameter values>,<shots>), kung saan ang<parameter values>at<shots>ay opsyonal. - Format ng Estimator V2 PUB: (
<circuit>,<observables>,<parameter values>,<precision>), kung saan ang<parameter values>at<precision>ay opsyonal. Ginagamit ang Numpy broadcasting rules kapag pinagsama ang mga observable at parameter value.
Bukod dito, ginawa rin ang mga sumusunod na pagbabago:
- Ang Estimator V2 ay may bagong
precisionna argument sarun()na paraan na tumutukoy sa target na precision ng mga estimate ng expectation value. - Ang Sampler V2 ay may
shotsna argument sarun()na paraan nito.
Mga halimbawaβ
Halimbawa ng Estimator V2 na gumagamit ng precision sa run():
# Estimate expectation values for two PUBs, both with 0.05 precision.
estimator.run([(circuit1, obs_array1), (circuit2, obs_array_2)], precision=0.05)
Halimbawa ng Sampler V2 na gumagamit ng shots sa 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β
Ang output ay nasa format na PubResult na ngayon. Ang PubResult ay ang data at metadata na nagmumula sa pagpapatupad ng isang PUB.
-
Patuloy na nagbabalik ng mga expectation value ang Estimator V2.
-
Ang
datana bahagi ng isang Estimator V2 PubResult ay naglalaman ng parehong mga expectation value at standard error (stds). Ang V1 ay nagbabalik ng variance sa metadata. -
Ang Sampler V2 ay nagbabalik ng per-shot na mga measurement sa anyo ng mga bitstring, sa halip na ang mga quasi-probability distribution mula sa V1 na interface. Ipinapakita ng mga bitstring ang mga resulta ng measurement, pinapanatili ang pagkakasunud-sunod ng shot kung paano ito nasukat.
-
Ang Sampler V2 ay may mga convenience method tulad ng
get_counts()para makatulong sa migration. -
Inaayos ng mga result object ng Sampler V2 ang data ayon sa mga pangalan ng classical register ng mga input circuit, para sa compatibility sa mga dynamic circuit. Sa default, ang pangalan ng classical register ay
meas, tulad ng ipinakita sa sumusunod na halimbawa. Kapag tinutukoy ang iyong Circuit, kung gumawa ka ng isa o higit pang classical register na may hindi default na pangalan, gamitin ang pangalang iyon para makuha ang mga resulta. Mahahanap mo ang pangalan ng classical register sa pamamagitan ng pagpapatakbo ng<circuit_name>.cregs. Halimbawa,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
Mga halimbawa ng Estimator (input at output)β
- 1 circuit, 4 observable
- 1 circuit, 4 observable, 2 set ng parameter
- 2 circuit, 2 observable
# 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)
Mga halimbawa ng Sampler (input at output)β
- 1 circuit, 3 set ng parameter
- 2 circuit, 1 set ng parameter
- I-convert ang V2 output sa 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)
Ang V1 output format ay isang dictionary ng mga bitstring (bilang int) bilang key at mga quasi-probability bilang value para sa bawat Circuit. Ang V2 format ay may parehong key (pero bilang string) at mga count bilang value. Para i-convert ang V2 format sa V1, hatiin ang mga count sa bilang ng shots, kung saan ang napiling bilang ng shots ay inilarawan sa gabay na Mag-specify ng options.
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()} )
Halimbawa na gumagamit ng iba't ibang output register
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()}")
Mga opsyonβ
Iba ang paraan ng pagtukoy ng mga opsyon sa mga V2 primitives:
- Ang
SamplerV2atEstimatorV2ay may magkahiwalay na mga klase ng opsyon. Makikita mo ang mga available na opsyon at ma-update ang mga value ng opsyon sa panahon ng o pagkatapos ng primitive initialization. - Sa halip na ang
set_options()na paraan, ang mga opsyon ng V2 primitive ay mayupdate()na paraan na nag-a-apply ng mga pagbabago saoptionsna attribute. - Kung hindi mo tinukoy ang value para sa isang opsyon, bibigyan ito ng espesyal na value na
Unsetat gagamitin ang mga default ng server. - Para sa mga V2 primitives, ang
optionsna attribute ay angdataclassna uri sa Python. Maaari mong gamitin ang built-in naasdictna paraan para i-convert ito sa isang dictionary.
Tingnan ang API reference para sa listahan ng mga available na opsyon.
- 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)
Error mitigation at suppressionβ
-
Dahil ang Sampler V2 ay nagbabalik ng mga sample nang walang postprocessing, hindi nito sinusuportahan ang mga resilience level.
-
Hindi sinusuportahan ng Sampler V2 ang
optimization_level. -
Ang Estimator V2 ay mag-aalis ng suporta para sa
optimization_levelsa o bandang 30 Setyembre 2024. -
Hindi sinusuportahan ng Estimator V2 ang resilience level 3. Ito ay dahil ang resilience level 3 sa V1 Estimator ay gumagamit ng Probabilistic Error Cancellation (PEC), na napatunayang nagbibigay ng unbiased na mga resulta sa halaga ng exponential na oras ng pagpoproseso. Tinanggal ang Level 3 para mapansin ang trade-off na iyon. Gayunpaman, maaari ka pa ring gumamit ng PEC bilang paraan ng error mitigation sa pamamagitan ng pagtukoy ng opsyon na
pec_mitigation. -
Sinusuportahan ng Estimator V2 ang
resilience_level0-2, tulad ng inilarawan sa sumusunod na talahanayan. Ang mga opsyong ito ay mas advanced kaysa sa mga katapat nito sa V1. Maaari ka ring explicitly mag-on / mag-off ng mga indibidwal na paraan ng error mitigation / suppression.Level 1 Level 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
Transpilationβ
Ang mga V2 primitives ay sumusuporta lamang sa mga Circuit na sumusunod sa Instruction Set Architecture (ISA) ng isang partikular na backend. Dahil hindi nagsasagawa ang mga primitives ng mga operasyon ng layout, routing, at translation, ang mga kaukulang opsyon ng transpilation mula sa V1 ay hindi sinusuportahan.
Katayuan ng jobβ
Ang mga V2 primitives ay may bagong RuntimeJobV2 na klase, na nagmamana mula sa BasePrimitiveJob. Ang status() na paraan ng bagong klaseng ito ay nagbabalik ng string sa halip na isang JobStatus enum mula sa Qiskit. Tingnan ang RuntimeJobV2 API reference para sa mga detalye.
- 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}")
Mga hakbang para mag-migrate sa Estimator V2β
-
Palitan ang
from qiskit_ibm_runtime import Estimatorngfrom qiskit_ibm_runtime import EstimatorV2 as Estimator. -
Alisin ang anumang
from qiskit_ibm_runtime import Optionsna mga statement, dahil hindi ginagamit ng mga V2 primitives ang klase ngOptions. Sa halip, maaari kang magpasa ng mga opsyon bilang dictionary kapag nagsi-initialize ng klase ngEstimatorV2(halimbawaestimator = Estimator(backend, options={"dynamical_decoupling": {"enable": True}})), o itakda ang mga ito pagkatapos ng initialization:estimator = Estimator(backend)
estimator.options.dynamical_decoupling.enable = True -
Suriin ang lahat ng sinusuportahang opsyon at gumawa ng mga update ayon sa pagkakailangan.
-
Pagsamahin ang bawat Circuit na gusto mong patakbuhin kasama ang mga observable at parameter value na gusto mong ilapat sa Circuit sa isang tuple (isang PUB). Halimbawa, gamitin ang
(circuit1, observable1, parameter_set1)kung gusto mong patakbuhin angcircuit1na mayobservable1atparameter_set1. -
Maaaring kailanganin mong baguhin ang hugis ng iyong mga array ng observable o mga set ng parameter kung gusto mong ilapat ang outer product ng mga ito. Halimbawa, ang isang array ng mga observable na may hugis (4, 1) at isang array ng mga set ng parameter na may hugis (1, 6) ay magbibigay sa iyo ng resulta na (4, 6) na mga expectation value. Tingnan ang Numpy broadcasting rules para sa higit pang detalye.
-
Maaari mong opsyonal na tukuyin ang precision na gusto mo para sa partikular na PUB na iyon.
-
I-update ang
run()na paraan ng estimator para maipasa ang listahan ng mga PUB. Halimbawa,run([(circuit1, observable1, parameter_set1)]). Maaari kang opsyonal na tukuyin ang isangprecisiondito, na ilalapat sa lahat ng PUB. -
Ang mga resulta ng Estimator V2 job ay napangkat ayon sa mga PUB. Makikita mo ang expectation value at standard error para sa bawat PUB sa pamamagitan ng pag-index dito. Halimbawa:
pub_result = job.result()[0]
print(f">>> Expectation values: {pub_result.data.evs}")
print(f">>> Standard errors: {pub_result.data.stds}")
Mga kumpletong halimbawa ng Estimatorβ
Magpatakbo ng isang eksperimentoβ
Gamitin ang Estimator para alamin ang expectation value ng isang circuit-observable pair.
- 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}")
Magpatakbo ng maraming eksperimento sa iisang jobβ
Gamitin ang Estimator para alamin ang mga expectation value ng maraming circuit-observable pair.
- 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}")
Magpatakbo ng mga parameterized na circuitβ
Gamitin ang Estimator para magpatakbo ng maraming eksperimento sa iisang job, gamit ang mga parameter value para mapataas ang muling paggamit ng circuit. Sa sumusunod na halimbawa, pansinin na ang mga hakbang 1 at 2 ay pareho para sa V1 at 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
Gumamit ng mga session at advanced na opsyonβ
Tuklasin ang mga session at advanced na opsyon para ma-optimize ang pagganap ng circuit sa mga QPU.
Ang sumusunod na code block ay magbabalik ng error para sa mga user na nasa Open Plan dahil gumagamit ito ng mga session. Ang mga workload sa Open Plan ay maaari lamang tumakbo sa job mode o 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}")
Mga hakbang para mag-migrate sa Sampler V2β
- Palitan ang
from qiskit_ibm_runtime import Samplerngfrom qiskit_ibm_runtime import SamplerV2 as Sampler. - Alisin ang anumang
from qiskit_ibm_runtime import Optionsna statement, dahil hindi ginagamit ng V2 primitives ang klase ngOptions. Sa halip, maaari kang magpasa ng mga opsyon bilang dictionary kapag sini-initialize ang klase ngSamplerV2(halimbawa,sampler = Sampler(backend, options={"default_shots": 1024})), o itakda ang mga ito pagkatapos ng initialization:sampler = Sampler(backend)
sampler.options.default_shots = 1024 - Suriin ang lahat ng mga sinusuportahang opsyon at gumawa ng mga pagbabago kung kinakailangan.
- Pangkatin ang bawat circuit na gusto mong patakbuhin kasama ang mga observable at parameter value na gusto mong ilapat sa circuit sa isang tuple (isang PUB). Halimbawa, gamitin ang
(circuit1, parameter_set1)kung gusto mong patakbuhin angcircuit1kasama angparameter_set1. Maaari kang opsyonal na tukuyin ang shots na gusto mo para sa partikular na PUB na iyon. - I-update ang sampler na
run()na method para ipasa ang listahan ng mga PUB. Halimbawa,run([(circuit1, parameter_set1)]). Maaari kang opsyonal na tukuyin angshotsdito, na mag-aaplai sa lahat ng PUB. - Ang mga resulta ng Sampler V2 job ay naka-grupo ayon sa mga PUB. Makikita mo ang output data para sa bawat PUB sa pamamagitan ng pag-index dito. Habang nagbabalik ang Sampler V2 ng mga unweighted na sample, ang result class ay may convenience method para makakuha ng mga count. Halimbawa:
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()}")
Kailangan mo ang pangalan ng classical register para makuha ang mga resulta. Sa default, ito ay pinangalanang meas kapag ginamit mo ang measure_all(). Kapag tinukoy mo ang iyong circuit, kung gumawa ka ng isa o higit pang classical register na may hindi default na pangalan, gamitin ang pangalan na iyon para makuha ang mga resulta. Mahahanap mo ang pangalan ng classical register sa pamamagitan ng pagpapatakbo ng <circuit_name>.cregs. Halimbawa, qc.cregs.
Mga kumpletong halimbawa ng Samplerβ
Magpatakbo ng isang eksperimentoβ
Gamitin ang Sampler para malaman ang mga counts o quasi-probability distribution ng isang 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}")
Magpatakbo ng maraming eksperimento sa iisang jobβ
Gamitin ang Sampler para malaman ang mga counts o quasi-probability distribution ng maraming Circuit sa iisang 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}")
Magpatakbo ng mga parameterized na Circuitβ
Magpatakbo ng ilang eksperimento sa iisang job, gamit ang mga parameter value para mapataas ang muling paggamit ng 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}")
Gumamit ng mga session at advanced na opsyonβ
Tuklasin ang mga session at advanced na opsyon para ma-optimize ang performance ng Circuit sa mga QPU.
Ang sumusunod na code block ay magbabalik ng error para sa mga gumagamit ng Open Plan dahil gumagamit ito ng mga session. Ang mga workload sa Open Plan ay maaari lamang tumakbo sa job mode o batch mode.
- 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}")
Mga susunod na hakbangβ
- Matuto pa tungkol sa pagtatakda ng mga opsyon sa gabay na Mag-specify ng mga opsyon.
- Matuto pa ng mga detalye tungkol sa Mga input at output ng Primitive.
- Mag-eksperimento sa tutorial na CHSH Inequality.