Přeskočit na hlavní obsah

Migrace ze Sampler na Executor

Tento průvodce popisuje, jak přesunout úlohy kvantového vzorkování z primitiva Sampler IBM Quantum® na primitivum Executor.

Beta verze

Primitivum Executor je součástí modelu řízeného provádění. Všechny součásti modelu řízeného provádění jsou aktuálně ve fázi beta a nemusí být stabilní. Jsi zván je otestovat a poskytnout zpětnou vazbu otevřením issue v repozitářích Samplomatic nebo qiskit-ibm-runtime na GitHubu.

Měl bys migrovat?

Ne každý by měl migrovat ze Sampler na Executor. Mezi primitivy existuje mnoho rozdílů, ale následující doporučení ti mohou pomoci rozhodnout se, zda migrovat:

Migruj na Executor, pokud jsi vědec v oboru kvantové informace, který provádí experimenty v měřítku utility a potřebuje jemně odstupňovanou, reprodukovatelnou kontrolu nad technikami, jako je Pauliho twirling, učení a injektáž modelu šumu a změny báze — nebo pokud potřebuješ některou z dalších schopností, které Executor poskytuje.

Pokračuj v používání Sampler, pokud chceš jednoduché rozhraní na vysoké úrovni a chceš, aby primitivum za tebe spravovalo potlačení a zmírnění chyb.

Omezení a upozornění

Protože Executor a model řízeného provádění jsou ve fázi beta, než se rozhodneš migrovat, vezmi na vědomí následující:

  • Zatím žádná podpora simulátoru: Na rozdíl od Sampler, který má implementaci AerSampler v qiskit-aer pro lokální simulaci, aktuálně pro Executor neexistuje žádný backend simulátoru. Podpora simulátoru se očekává brzy. Mezitím si stále můžeš prohlédnout a vzorkovat šablonový obvod lokálně, abys ověřil svůj pracovní postup před odesláním na hardware.

  • Tento průvodce se týká pouze Sampler, nikoli Estimator. Migrace z Estimator na Executor je podstatně náročnější než migrace ze Sampler, protože Estimator počítá očekávané hodnoty místo toho, aby vracel surové vzorky. Reprodukování chování Estimator s Executor vyžaduje dodatečné následné zpracování. Pomocné funkce usnadňující migraci z Estimator na Executor jsou stále ve vývoji, takže tento průvodce záměrně popisuje pouze pracovní postup se Sampler.

Klíčové rozdíly mezi Executor a Sampler

Sampler i Executor vzorkují výstupní registry kvantových obvodů, ale jsou určeny pro různé uživatele:

  • Sampler je abstrakce na vysoké úrovni. Má následující vlastnosti:

    • Má vestavěné potlačení chyb (dynamické oddělení a twirling).

    • Dělá za tebe implicitní rozhodnutí.

    • Je navrženo tak, aby se vývojáři algoritmů mohli soustředit na inovace spíše než na převod dat.

  • Executor je součástí modelu řízeného provádění. Od Sampler se liší v mnoha ohledech a má následující vlastnosti:

    • Nemá žádné vestavěné potlačení ani zmírnění chyb. Místo toho zachytíš svůj záměr návrhu na straně klienta (pomocí anotací obvodu a samplexu) a nákladné generování variant obvodu se přesouvá na stranu serveru.

    • Nedělá žádná implicitní rozhodnutí. Přesně se řídí tvými pokyny, což poskytuje plnou kontrolu a transparentnost.

    • Executor a Samplomatic společně nabízejí další schopnosti, které Sampler neposkytuje, mimo jiné včetně následujících:

      • Více skupin twirlingu: Samplomatic ti umožňuje zvolit, kterou skupinu twirlingu použít pro jednotlivý box, místo omezení na jedinou strategii, kterou za tebe aplikuje Sampler. Podporuje také jiné skupiny twirlingu než Pauliho, jako je skupina twirlingu "local_c1".
      • Kernelovaná a klasifikovaná měření společně: Nastavení QuantumProgram.meas_level = "both" (přidáno v qiskit-ibm-runtime v0.48.0) vyžaduje, aby ve výsledcích byla přítomna jak klasifikovaná, tak kernelovaná měření, místo volby jediného typu měření na úlohu.
      • Twirling pro obvody s frakčními hradly: Executor může aplikovat twirling na obvody, které obsahují frakční hradla.
      • Jemně odstupňované, skládatelné zmírnění chyb: Například volba toho, které vrstvy obvodu zmírnit, a úprava úrovní šumu vkládaných do obvodu.
      Poznámky
      • Očekává se, že budoucí nové schopnosti budou nejprve vydány pro Executor a nemusí být portovány do Sampler. Pokud se spoléháš na přístup k nejnovějším funkcím, Executor je volbou s lepší budoucí kompatibilitou.
      • Základní balíček Qiskit zatím neposkytuje základní třídu pro primitivum Executor (proSamplerV2 ji poskytuje).

Koncepční mapování

Následující tabulka ukazuje, jak se koncepty Sampler mapují na Executor.

KonceptSamplerExecutor
Importfrom qiskit_ibm_runtime import SamplerV2from qiskit_ibm_runtime import Executor
VstupSeznam PUBů (n-tice)QuantumProgram objektů QuantumProgramItem
Obvod a parametryn-tice (circuit, params, shots)program.append_circuit_item(circuit, circuit_arguments=...)
TwirlingTwirlingOptionsExplicitně pomocí anotovaných boxů a samplexu (append_samplex_item)
Volání spuštěnísampler.run([pub, ...])executor.run(program)
Typ výsledkuPrimitiveResult objektů SamplerPubResultQuantumProgramResult (iterovatelný)
Přístup k datůmresult[0].data.<register> (BitArray)result[0]["<register>"] (np.ndarray)
Správa šumuVestavěné možnostiMusí být sestaveno ručně (anotace, samplex, NoiseLearnerV3)

Přehled kroků migrace

  1. Nainstaluj Samplomatic.

  2. Změň importy.

  3. Nahraď n-tice PUB.

  4. Změň, jak jsou vyjádřeny shoty.

  5. Aktualizuj další možnosti dle potřeby.

  6. Aktualizuj příkaz run.

  7. Aktualizuj zpracování výsledků.

  8. Zruš twirling.

Krok 1. Nainstaluj požadované balíčky

Executor a model řízeného provádění vyžadují balíček samplomatic:

pip install qiskit qiskit-ibm-runtime samplomatic

# For visualization support:
# pip install samplomatic[vis]
Poznámky k verzím
  • Doporučuje se qiskit-ibm-runtime v0.48.0, protože přidává možnost meas_level = "both" a skupinu twirlingu local_c1.
  • Je vyžadován qiskit >= 2.3.0.
  • Je vyžadován samplomatic >= 0.18.0.

Krok 2. Změň importy

Sampler:

from qiskit_ibm_runtime import SamplerV2 as Sampler

Executor:

from qiskit_ibm_runtime import Executor, QuantumProgram

Krok 3. Nahraď n-tice PUB objektem QuantumProgram

Místo předávání seznamu n-tic (PUB) při použití Executor sestavíš QuantumProgram a připojíš k němu položky.

QuantumProgram přijímá položky typu circuit a samplex:

  • append_circuit_item: Připojí CircuitItem, což je obvod a (volitelně) jeho hodnoty parametrů. Provádí se tak, jak je, bez jakékoli randomizace.

    Použij toto, když chceš pouze vzorkovat obvod, přesně jako by to udělal Sampler s PUB bez twirlingu; například při odesílání jednoduché úlohy vzorkování, nebo když jsi již ručně zahrnul veškeré varianty, které chceš.

  • append_samplex_item: Připojí samplexItem, což je šablonový obvod plus samplex, který generuje randomizované sady parametrů na straně serveru.

    Použij toto, když chceš, aby byl obsah obvodu randomizován. Hlavním případem je twirling (hradlový nebo měřicí) nebo injektáž šumu. Tato schopnost nahrazuje vestavěný twirling Sampler.

Jediný QuantumProgram může přijmout oba typy položek; každá připojená položka se provádí jako nezávislá úloha a vytváří svůj vlastní záznam ve výsledcích. Obecně použij append_circuit_item, když tvůj obvod nepotřebuje být randomizován. Jinak použij append_samplex_item.

Následující sekce ukazují postupně obojí: parametrizované obvody, které používají append_circuit_item, a migraci twirlingu pomocí append_samplex_item.

V následujících ukázkách kódu isa_circuit odkazuje na obvod, který byl transpilován tak, aby vyhovoval architektuře instrukční sady (ISA) cílového backendu. Tento isa_circuit obsahuje dva parametry.

Krok 3a. Migrace parametrizovaných obvodů

U Sampler jsou hodnoty parametrů druhým prvkem n-tice PUB. U Executor je předej jako circuit_arguments do append_circuit_item.

Sampler:

params = np.random.rand(10, circuit.num_parameters) # 10 parameter sets
pubs = (isa_circuit, params)

Executor

program = QuantumProgram(shots=1024)
program.append_circuit_item(
isa_circuit,
circuit_arguments=np.random.rand(10, circuit.num_parameters), # 10 sets
)

# CircuitItem result shape: (parameter_sets, shots, register_bits) -> (10, 1024, 2)
result_0 = result[0]["meas"]

Krok 3b. Migrace vestavěného twirlingu na explicitní anotace

Toto je nejvýznamnější změna. Sampler za tebe aplikuje twirling pomocí možností. U Executor tento záměr deklaruješ explicitně pomocí anotovaných boxů a samplexu (z Samplomatic).

Sampler (twirling pomocí možností):

sampler = Sampler(mode=backend)
sampler.options.twirling.enable_gates = True
sampler.options.twirling.enable_measure = True

Executor (twirling pomocí boxů a samplexu):

from samplomatic import build
from samplomatic.transpiler import generate_boxing_pass_manager

# 1. Group gates and measurements into annotated boxes with twirling annotations
boxes_pm = generate_boxing_pass_manager(
enable_gates=True, # gate twirling
enable_measures=True, # measurement twirling
)
boxed_circuit = boxes_pm.run(isa_circuit)

# 2. Build the (template circuit, samplex) pair.
# The template circuit's single-qubit gates are replaced by parameterized gates;
# the samplex encodes how to generate the randomized parameters at runtime.
template_circuit, samplex = build(boxed_circuit)

# 3. Append as a samplex item, specifying the number of randomizations
program = QuantumProgram(shots=1024)
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
"parameter_values": np.random.rand(10, 2), # original circuit params
},
shape=(28, 10), # 28 randomizations x 10 parameter sets
)

Protože šablonový obvod a samplex jsou sestaveny na straně klienta, můžeš je lokálně prozkoumat a vzorkovat, abys ověřil výstup, než něco odešleš na hardware.

Ověření: Vzorkuj šablonový obvod lokálně

Můžeš čerpat randomizace ze samplexu a navázat je na šablonový obvod, abys potvrdil, že samplex produkuje očekávané hodnoty parametrů. Hodnoty parametrů vrácené samplex.sample jsou přímo kompatibilní s parametry šablonového obvodu.

# Check which inputs the samplex requires (for the twirling example above,
# this is just the original circuit's parameter values).
print(samplex.inputs())

# Bind the required inputs, then draw a few randomizations locally.
inputs = samplex.inputs().bind(
parameter_values=np.random.rand(2), # one set of the original circuit's params
)
outputs = samplex.sample(inputs, num_randomizations=3)

# Assign one randomization's parameter values to the template circuit and inspect it.
bound_template = template_circuit.assign_parameters(outputs["parameter_values"][0])
bound_template.draw("mpl", idle_wires=False)

Chceš-li jít dále, můžeš ověřit, že je každá randomizace logicky ekvivalentní původnímu obvodu, například převedením obou na objekty Operator a porovnáním jejich unitárních implementací (po zohlednění korekcí outputs["measurement_flips.<register>"], které ruší twirling měření), nebo porovnáním očekávaných hodnot z lokálního spuštění StatevectorSampler nebo StatevectorEstimator. Kompletní návod najdeš v průvodci Samplomatic Vstupy a výstupy Samplex.

Krok 4. Změň, jak jsou požadovány shoty

Přesuň shoty z PUB do QuantumProgram(shots=...). V Executor se shots vztahuje na celou úlohu. Pokud potřebuješ různé počty shotů, odešli více úloh.

Sampler:

# Run — shots are passed to run()
sampler = Sampler(mode=backend)
job = sampler.run([(isa_circuit, None, 25)])

Executor:

# Build a QuantumProgram — shots are on the program
program = QuantumProgram(shots=25)
program.append_circuit_item(isa_circuit)

Krok 5. Aktualizuj možnosti dle potřeby

Executor má k dispozici méně možností než Sampler, protože volby týkající se zmírnění chyb se nyní nacházejí ve tvých anotacích a samplexu místo v možnostech.

Existuje také strukturální rozdíl v tom, kde se nastavení nacházejí.

  • U Sampler se vše, včetně voleb ovlivňujících následné zpracování výsledků, konfiguruje pomocí možností primitiva nebo v PUB.

  • U Executor se volby ovlivňující to, jak jsou výsledky úlohy formátovány a následně zpracovávány, nastavují na QuantumProgram, nikoli na ExecutorOptions.

Examples:

SamplerExecutor
shotsQuantumProgram(shots=...)
meas_typeQuantumProgram(meas_level=...)

ExecutorOptions obsahuje pouze nastavení nižší úrovně provádění a prostředí, která nemění strukturu vrácených dat. Má tři skupiny nejvyšší úrovně:

Zejména možnosti twirling a dynamical_decoupling existují v Sampler, ale ne v Executor. Místo toho jsou tyto hodnoty možností vyjádřeny prostřednictvím modelu řízeného provádění.

Example:

from qiskit_ibm_runtime import Executor, ExecutorOptions

options = ExecutorOptions(
environment={"log_level": "INFO"},
execution={"init_qubits": True},
)
# or mutate after construction:
options = ExecutorOptions()
options.environment.log_level = "INFO"
options.execution.init_qubits = True

executor = Executor(mode=backend, options=options)

Krok 6. Aktualizuj příkaz run

Vstupem úlohy Executor je program, místo PUB.

Sampler:

# Submit a job
sampler.run([(isa_circuit, parameter_values)])

Executor:

# Submit a job
executor.run(program)

Krok 7. Změň, jak přistupuješ k výsledkům

V Executor jsou výsledky pole NumPy, nikoli objekty BitArray. Použij řetězec s názvem jako index (result[0]["meas"]) a získáš zpět np.ndarray. Není třeba si pamatovat cestu k atributu .data.<register>.

Chceš-li přejít ze Sampler na Executor, změň result[i].data.<reg> (BitArray) na result[i]["<reg>"] (np.ndarray), poté přepiš následné zpracování založené na get_counts na operace NumPy.

ÚkolSamplerExecutor
Získání dat registruresult[0].data.measresult[0]["meas"]
Datový typBitArraynp.ndarray
Slovník počtůresult[0].data.meas.get_counts()Následné zpracování pole ručně
Více registrůresult[0].data.<name> na registrresult[0]["<name>"] na registr
Tvar pole CircuitItem-(parameter_sets, shots, register_bits)
Tvar pole SamplexItem-(randomizations, parameter_sets, shots, register_bits)
Zrušení twirlingu měřeníAutomatickyresult[i]["measurement_flips.<name>"] + XOR
poznámka

BitArray u Sampler nabízí pomocné funkce (get_counts, slice_bits, slice_shots, expectation_values a masky pro post-selekci). Executor vrací syrová NumPy pole, takže toto post-processing můžeš provést pomocí standardních operací NumPy.

Krok 8. Zpracuj twirlované výsledky (korekce bitového překlopení)

Když aplikuješ twirling měření prostřednictvím SamplexItem, Executor vrátí surová (twirlovaná) měření plus korekce bitového překlopení potřebné ke zrušení twirlingu. Musíš je aplikovat ručně; nic se neopravuje implicitně.

Při použití Executor zruš twirling explicitně pomocí korekcí measurement_flips.<reg> a operace XOR, jak je znázorněno v následujícím příkladu:

# SamplexItem result shape: (randomizations, parameter_sets, shots, register_bits)
result_1 = result[1]["meas"] # example: (28, 10, 1024, 2)

# Bit-flip corrections to undo measurement twirling
flips_1 = result[1]["measurement_flips.meas"] # example: (28, 10, 1, 2)

# Undo the twirling through classical XOR (broadcasts over the shots axis)
unflipped_result_1 = result_1 ^ flips_1

V Sampler neexistuje ekvivalentní krok, protože ten za tebe twirling ruší.

Kompletní příklad: Migrace základní úlohy vzorkování

Sampler

import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler

# 1. Account + backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# 2. Circuit
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.h(1)
circuit.cz(0, 1)
circuit.h(1)
circuit.measure_all()

# 3. Transpile to ISA
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)

# 4. Run — shots are passed to run()
sampler = Sampler(mode=backend)
job = sampler.run([(isa_circuit,)], shots=25)
result = job.result()

# 5. Access results: a BitArray keyed by register name
counts = result[0].data.meas.get_counts()

Executor

import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Executor
from qiskit_ibm_runtime.quantum_program import QuantumProgram

# 1. Account + backend (unchanged)
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# 2. Circuit (unchanged)
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.h(1)
circuit.cz(0, 1)
circuit.h(1)
circuit.measure_all()

# 3. Transpile to ISA (unchanged)
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)

# 4. Build a QuantumProgram — shots are on the program
program = QuantumProgram(shots=25)
program.append_circuit_item(isa_circuit)

# 5. Run
executor = Executor(mode=backend)
job = executor.run(program)
result = job.result()

# 6. Access results: a plain np.ndarray keyed by register name
# shape = (shots, register_bits)
meas = result[0]["meas"]

Další kroky