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.
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
AerSamplervqiskit-aerpro 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 vqiskit-ibm-runtimev0.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 (pro
SamplerV2ji poskytuje).
- 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
-
Koncepční mapování
Následující tabulka ukazuje, jak se koncepty Sampler mapují na Executor.
| Koncept | Sampler | Executor |
|---|---|---|
| Import | from qiskit_ibm_runtime import SamplerV2 | from qiskit_ibm_runtime import Executor |
| Vstup | Seznam PUBů (n-tice) | QuantumProgram objektů QuantumProgramItem |
| Obvod a parametry | n-tice (circuit, params, shots) | program.append_circuit_item(circuit, circuit_arguments=...) |
| Twirling | TwirlingOptions | Explicitně pomocí anotovaných boxů a samplexu (append_samplex_item) |
| Volání spuštění | sampler.run([pub, ...]) | executor.run(program) |
| Typ výsledku | PrimitiveResult objektů SamplerPubResult | QuantumProgramResult (iterovatelný) |
| Přístup k datům | result[0].data.<register> (BitArray) | result[0]["<register>"] (np.ndarray) |
| Správa šumu | Vestavěné možnosti | Musí být sestaveno ručně (anotace, samplex, NoiseLearnerV3) |
Přehled kroků migrace
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]
- Doporučuje se
qiskit-ibm-runtimev0.48.0, protože přidává možnostmeas_level = "both"a skupinu twirlingulocal_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 naExecutorOptions.
Examples:
| Sampler | Executor |
|---|---|
shots | QuantumProgram(shots=...) |
meas_type | QuantumProgram(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ě:
-
environment(EnvironmentOptions) -
execution(ExecutionOptions): Obsahuje méně možností než u Sampler. Například neexistuje žádná možnostmeas_typepro Executor.
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.
| Úkol | Sampler | Executor |
|---|---|---|
| Získání dat registru | result[0].data.meas | result[0]["meas"] |
| Datový typ | BitArray | np.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 registr | result[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í | Automaticky | result[i]["measurement_flips.<name>"] + XOR |
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"]