Přeskočit na hlavní obsah

Migrace na primitiva V2 Qiskit Runtime

varování

Původní primitiva (označovaná jako primitiva V1), V1 Sampler a V1 Estimator, byla v qiskit-ibm-runtime 0.23 označena jako zastaralá. Jejich podpora byla ukončena 15. srpna 2024.

V důsledku zastarání primitiv V1 by měl být veškerý kód migrován na rozhraní V2. Tento průvodce popisuje, co se změnilo v primitivech V2 Qiskit Runtime (dostupných od qiskit-ibm-runtime 0.21.0) a proč, podrobně popisuje každé nové primitivum a uvádí příklady, které ti pomohou migrovat kód z původních primitiv na primitiva V2. Příklady v průvodci všechny používají primitiva Qiskit Runtime, ale obecně platí stejné změny i pro ostatní implementace primitiv. Funkce jedinečné pro Qiskit Runtime, jako je potlačení chyb, zůstávají jedinečné pro Qiskit Runtime.

Informace o změnách v referenčních primitivech Qiskit (nyní nazývaných statevector primitiva) najdeš v sekci qiskit.primitives na stránce změn Qiskit 1.0. Referenční implementace primitiv V2 jsou StatevectorSampler a StatevectorEstimator.

Přehled

Verze 2 primitiv je zavedena s novou základní třídou pro Sampler i Estimator (BaseSamplerV2 a BaseEstimatorV2) spolu s novými typy pro jejich vstupy a výstupy.

Nové rozhraní ti umožňuje zadat jeden Circuit a více observablů (při použití Estimatoru) a sady hodnot parametrů pro daný Circuit, takže průchody přes sady hodnot parametrů a observably lze efektivně specifikovat. Dříve bylo nutné stejný Circuit zadávat vícekrát, aby odpovídal velikosti kombinovaných dat. Navíc, přestože stále můžeš používat resilience_level (při použití Estimatoru) jako jednoduchý přepínač, primitiva V2 ti dávají flexibilitu zapínat nebo vypínat jednotlivé metody potlačení nebo zmírnění chyb a přizpůsobit je svým potřebám.

Za účelem zkrácení celkové doby provádění úloh přijímají primitiva V2 pouze Circuit a observably, které používají instrukce podporované cílovým QPU (kvantovou procesorovou jednotkou). Takové Circuit a observably se označují jako ISA (instruction set architecture) Circuit a observably. Primitiva V2 neprovádějí operace rozvržení, směrování a překladu. Pokyny k transformaci Circuit najdeš v dokumentaci k transpilaci.

Sampler V2 je zjednodušen tak, aby se zaměřil na svůj hlavní úkol: vzorkování výstupního registru při spuštění kvantových Circuit. Vrací vzorky, jejichž typ je definován programem, bez vah. Výstupní data jsou také rozdělena podle názvů výstupních registrů definovaných programem. Tato změna umožňuje budoucí podporu Circuit s klasickým řízením toku.

Úplné podrobnosti najdeš v referenci API EstimatorV2 a referenci API SamplerV2.

Hlavní změny

Import

Z důvodu zpětné kompatibility musíš primitiva V2 explicitně importovat. Zápis import <primitive>V2 as <primitive> není povinný, ale usnadňuje přechod kódu na V2.

varování

Poté, co primitiva V1 přestanou být podporována, příkaz import <primitive> importuje verzi V2 daného primitivu.

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

Vstup a výstup

Vstup

SamplerV2 i EstimatorV2 přijímají jako vstup jeden nebo více primitive unified blocs (PUB). Každý PUB je n-tice obsahující jeden Circuit a data vysílaná do tohoto Circuit, což může být více observabilů a parametrů. Každý PUB vrátí výsledek.

  • Formát PUB pro Sampler V2: (<circuit>, <hodnoty parametrů>, <shots>), kde <hodnoty parametrů> a <shots> jsou volitelné.
  • Formát PUB pro Estimator V2: (<circuit>, <observables>, <hodnoty parametrů>, <precision>), kde <hodnoty parametrů> a <precision> jsou volitelné. Při kombinování observabilů a hodnot parametrů se používají pravidla broadcastingu z knihovny Numpy.

Dále byly provedeny následující změny:

  • Estimator V2 získal argument precision v metodě run(), který určuje cílovou přesnost odhadů střední hodnoty.
  • Sampler V2 má argument shots ve své metodě run().
Příklady

Příklad Estimator V2 používající precision v run():

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

Příklad Sampler V2 používající shots v 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),
])

Výstup

Výstup je nyní ve formátu PubResult. PubResult obsahuje data a metadata vzniklá spuštěním jednoho PUB.

  • Estimator V2 nadále vrací střední hodnoty.

  • Část data výsledku PubResult pro Estimator V2 obsahuje jak střední hodnoty, tak standardní chyby (stds). V1 vracela rozptyl v metadatech.

  • Sampler V2 vrací měření pro každý shot ve formě bitstring, místo kvazi-pravděpodobnostních distribucí z rozhraní V1. Bitstring zobrazují výsledky měření a zachovávají pořadí shotů, ve kterém byly změřeny.

  • Sampler V2 obsahuje pomocné metody jako get_counts(), které usnadňují migraci.

  • Výsledné objekty Sampler V2 organizují data podle názvů klasických registrů vstupních Circuit, kvůli kompatibilitě s dynamickými Circuit. Ve výchozím nastavení je název klasického registru meas, jak ukazuje následující příklad. Pokud při definování svého Circuit vytvoříš jeden nebo více klasických registrů s jiným než výchozím názvem, použij tento název pro získání výsledků. Název klasického registru zjistíš spuštěním <název_circuit>.cregs. Například 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

Příklady Estimatoru (vstup a výstup)

# 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

Příklady Sampleru (vstup a výstup)

  # 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()

Příklad s různými výstupními registry

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

Možnosti jsou v primitívech V2 zadávány odlišným způsobem:

  • SamplerV2 a EstimatorV2 mají nyní samostatné třídy možností. Dostupné možnosti si můžeš prohlédnout a hodnoty aktualizovat během inicializace primitívu nebo po ní.
  • Místo metody set_options() mají možnosti primitívů V2 metodu update(), která aplikuje změny na atribut options.
  • Pokud nezadáš hodnotu pro některou možnost, dostane speciální hodnotu Unset a použijí se výchozí hodnoty serveru.
  • U primitívů V2 je atribut options datový typ dataclass v Pythonu. Můžeš použít vestavěnou metodu asdict pro převod na slovník.

Seznam dostupných možností najdeš v referenci API.

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

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

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

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

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

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

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

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

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

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

Zmírnění a potlačení chyb

  • Protože Sampler V2 vrací vzorky bez následného zpracování, nepodporuje úrovně odolnosti.

  • Sampler V2 nepodporuje optimization_level.

  • Estimator V2 přestane podporovat optimization_level přibližně 30. září 2024.

  • Estimator V2 nepodporuje úroveň odolnosti 3. Důvodem je, že úroveň odolnosti 3 v Estimatoru V1 využívá metodu Probabilistic Error Cancellation (PEC), která je prokázaně schopna poskytovat nezkreslené výsledky za cenu exponenciální doby zpracování. Úroveň 3 byla odstraněna, aby upozornila na tento kompromis. Metodu PEC ale stále můžeš používat jako metodu zmírnění chyb tím, že zadáš možnost pec_mitigation.

  • Estimator V2 podporuje resilience_level 0–2, jak popisuje následující tabulka. Tyto možnosti jsou pokročilejší než jejich protějšky ve V1. Jednotlivé metody zmírnění / potlačení chyb lze také explicitně zapnout nebo vypnout.

    Úroveň 1Úroveň 2
    Measurement twirlingMeasurement twirling
    Zmírnění chyb čteníZmírnění chyb čtení
    ZNE
from dataclasses import asdict
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator

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

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

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

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

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

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

Transpilace

Primitiva V2 podporují pouze obvody (Circuit), které odpovídají instrukční sadě architektury (ISA) daného Backend. Protože primitiva neprovádějí operace rozmístění, směrování a překladu, nejsou příslušné možnosti transpilace z V1 podporovány.

Stav jobu

Primitiva V2 mají novou třídu RuntimeJobV2, která dědí z BasePrimitiveJob. Metoda status() této nové třídy vrací řetězec namísto výčtu JobStatus z Qiskitu. Podrobnosti najdeš v referenci API pro RuntimeJobV2.

job = estimator.run(...)

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

Kroky pro migraci na Estimator V2

  1. Nahraď from qiskit_ibm_runtime import Estimator za from qiskit_ibm_runtime import EstimatorV2 as Estimator.

  2. Odstraň všechny příkazy from qiskit_ibm_runtime import Options, protože třída Options není primitivy V2 používána. Místo toho můžeš předávat volby jako slovník při inicializaci třídy EstimatorV2 (například estimator = Estimator(backend, options={"dynamical_decoupling": {"enable": True}})), nebo je nastavit až po inicializaci:

    estimator = Estimator(backend)
    estimator.options.dynamical_decoupling.enable = True
  3. Projdi všechny podporované volby a podle potřeby je aktualizuj.

  4. Seskup každý Circuit, který chceš spustit, spolu s observablemi a hodnotami parametrů, jež chceš na Circuit aplikovat, do n-tice (PUB). Například použij (circuit1, observable1, parameter_set1), pokud chceš spustit circuit1 s observable1 a parameter_set1.

  5. Možná budeš muset změnit tvar svých polí observablů nebo sad parametrů, pokud chceš aplikovat jejich vnější součin. Například pole observablů tvaru (4, 1) a pole sad parametrů tvaru (1, 6) ti dají výsledek (4, 6) očekávaných hodnot. Podrobnosti najdeš v pravidlech broadcastingu Numpy.

  6. Pro daný konkrétní PUB můžeš volitelně určit požadovanou přesnost.

  7. Aktualizuj metodu run() Estimatoru tak, aby přijímala seznam PUBů. Například run([(circuit1, observable1, parameter_set1)]). Volitelně zde můžeš zadat precision, která se aplikuje na všechny PUBy.

  8. Výsledky úlohy Estimatoru V2 jsou seskupeny podle PUBů. Očekávanou hodnotu a standardní chybu pro každý PUB zobrazíš indexováním. Například:

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

Úplné příklady pro Estimator

Spuštění jediného experimentu

Pomocí Estimatoru urči očekávanou hodnotu jediného páru Circuit–observable.

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

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

n_qubits = 127

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

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

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

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

Spuštění více experimentů v rámci jedné úlohy

Pomocí Estimatoru zjisti očekávané hodnoty více dvojic okruh–pozorovatelná.

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}")

Spuštění parametrizovaných Circuit

Použij Estimator ke spuštění více experimentů v rámci jedné úlohy, přičemž hodnoty parametrů zvyšují znovupoužitelnost Circuit. V následujícím příkladu si všimni, že kroky 1 a 2 jsou stejné pro V1 i V2.

import numpy as np

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

# Step 1: Map classical inputs to a quantum problem

theta = Parameter("θ")

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

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

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

# Step 2: Optimize problem for quantum execution.

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

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

from qiskit_ibm_runtime import EstimatorV2 as Estimator

# Step 3: Execute using Qiskit primitives.

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

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

Použití Session a pokročilých možností

Prozkoumej Session a pokročilé možnosti pro optimalizaci výkonu Circuit na QPU.

pozor

Následující blok kódu vrátí chybu uživatelům na Open Plánu, protože využívá Session. Úlohy na Open Plánu mohou běžet pouze v job mode nebo batch mode.

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

n_qubits = 127

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

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

service = QiskitRuntimeService()

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

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

estimator.options.resilience_level = 1

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

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

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

Postup migrace na Sampler V2

  1. Nahraď from qiskit_ibm_runtime import Sampler za from qiskit_ibm_runtime import SamplerV2 as Sampler.
  2. Odstraň veškeré příkazy from qiskit_ibm_runtime import Options, protože třída Options není v primitivech V2 používána. Místo toho můžeš předat volby jako slovník při inicializaci třídy SamplerV2 (například sampler = Sampler(backend, options={"default_shots": 1024})), nebo je nastavit po inicializaci:
    sampler = Sampler(backend)
    sampler.options.default_shots = 1024
  3. Projdi si všechny podporované volby a proveď příslušné úpravy.
  4. Seskup každý Circuit, který chceš spustit, s observablemi a hodnotami parametrů, které chceš na Circuit použít, do n-tice (PUB). Například použij (circuit1, parameter_set1), pokud chceš spustit circuit1 s parameter_set1. Pro daný konkrétní PUB můžeš volitelně zadat počet shots.
  5. Aktualizuj metodu run() Sampleru tak, aby přijímala seznam PUBů. Například run([(circuit1, parameter_set1)]). Volitelně zde můžeš zadat shots, které se uplatní na všechny PUBů.
  6. Výsledky jobu Sampleru V2 jsou seskupeny podle PUBů. Výstupní data pro každý PUB zobrazíš indexováním na příslušný PUB. Zatímco Sampler V2 vrací nevážené vzorky, třída výsledků obsahuje pohodlnou metodu pro získání počtů. Například:
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()}")
poznámka

Pro získání výsledků potřebuješ název klasického registru. Ve výchozím nastavení se jmenuje meas, pokud použiješ measure_all(). Pokud při definování Circuitu vytvoříš jeden nebo více klasických registrů s jiným než výchozím názvem, použij k získání výsledků tento název. Název klasického registru zjistíš spuštěním <circuit_name>.cregs. Například qc.cregs.

Úplné příklady použití Sampleru

Spuštění jediného experimentu

Pomocí Sampleru zjistíš počty nebo kvázi-pravděpodobnostní rozdělení pro jediný Circuit.

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

service = QiskitRuntimeService()

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

n_qubits = 127

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

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

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

Spusť více experimentů v jedné úloze

Použij Sampler k určení počtů nebo kvazi-pravděpodobnostních rozdělení pro více Circuit v jedné úloze.

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()}")

Spusť parametrizované Circuit

Spusť několik experimentů v jedné úloze a využij hodnoty parametrů ke zvýšení znovupoužitelnosti Circuit.

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

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

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

# Step 2: Optimize problem for quantum execution.

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

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

# Step 3: Execute using Qiskit primitives.

from qiskit_ibm_runtime import SamplerV2 as Sampler

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

Použití Sessions a pokročilých možností

Prozkoumej Sessions a pokročilé možnosti pro optimalizaci výkonu Circuit na QPU.

pozor

Následující blok kódu vrátí chybu uživatelům na Open Plánu, protože využívá Sessions. Úlohy na Open Plánu mohou běžet pouze v job módu nebo v dávkovém módu.

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()}")

Další kroky

Doporučení