Přeskočit na hlavní obsah
Tento projekt je v betě. Našel jsi chybu? Otevřít issue na GitHubu. Máš otázku nebo nápad? Zeptej se v Discussions — rádi si poslechneme tvou zpětnou vazbu!
Jaká je kvalita překladu na této stránce?

Vstupy a výstupy Executor

Verze balíčků

Kód na této stránce byl vyvinut s použitím následujících požadavků. Doporučujeme používat tyto nebo novější verze.

qiskit[all]~=2.6.1
qiskit-ibm-runtime~=0.50.0
samplomatic~=0.21.0

Primitiv Executor je součástí modelu řízeného spouštění, který poskytuje větší flexibilitu při přizpůsobování pracovního postupu zmírňování chyb.

Vstupy a výstupy primitivu Executor se výrazně liší od vstupů a výstupů primitivů Sampler a Estimator. Například místo přijímání seznamu PUBů jako vstupu přijímá Executor QuantumProgram, který obsahuje seznam objektů QuantumProgramItem. Tyto kontejnerové třídy ti dávají větší flexibilitu než PUB, což je jednoduchá datová struktura n-tice.

Výstup Executor je QuantumProgramResult, který je iterovatelný a obsahuje jeden prvek pro každý vstupní QuantumProgramItem.

Vstupy: Kvantové programy​

Jak bylo uvedeno dříve, vstupem do primitivu Executor je QuantumProgram, což je iterovatelná kolekce objektů QuantumProgramItem. Tyto objekty mohou být dvou typů:

  • CircuitItem, který obvykle uchovává Circuit a jeho hodnoty parametrů (pokud existují).
  • SamplexItem, který obvykle uchovává následující:
    • Šablonový Circuit
    • Objekt samplex, který se používá ke generování randomizovaných sad parametrů za běhu (například pro provádění twirling nebo vkládání šumu)
    • Argumenty pro samplex, které mohou zahrnovat hodnoty parametrů pro původní Circuit

Každá z těchto položek představuje jiný úkol, který má Executor provést.

Než začneš​

Některé příklady kódu na této stránce používají samplex, který je součástí balíčku Samplomatic. Proto před spuštěním těchto bloků kódu musíš nainstalovat Samplomatic, jak je uvedeno v následujícím bloku kódu. Více informací najdeš v dokumentaci Samplomatic.

pip install samplomatic

# For visualization support, include the visualization dependencies.
# pip install samplomatic[vis]

Příklad: Vytvoření QuantumProgram se dvěma různými úkoly​

Nejprve inicializuj svůj kvantový program, poté k němu přidej položky programu pomocí append_circuit_item nebo append_samplex_item (pokud je přítomen samplex), jak je uvedeno v následujících příkladech.

Následující buňka inicializuje QuantumProgram a specifikuje, že má pro každou konfiguraci každé položky v programu spustit 1024 shotů (opakování).

poznámka

Na rozdíl od Sampler přijímá QuantumProgram pouze jednu hodnotu počtu shotů. Pokud chceš jinou hodnotu počtu shotů, potřebuješ samostatný QuantumProgram, což by byla samostatná úloha.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_ibm_runtime": "qiskit-ibm-runtime", "samplomatic": "samplomatic"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.quantum_program import QuantumProgram
from qiskit_ibm_runtime import Executor, QiskitRuntimeService
from qiskit.circuit import Parameter, QuantumCircuit
import numpy as np
from samplomatic import build
from samplomatic.transpiler import generate_boxing_pass_manager

# Initialize an empty program
program = QuantumProgram(shots=1024)

# Initialize and transpile a 3-qubit quantum circuit with 2 parameters.
circuit = QuantumCircuit(3)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.rz(Parameter("theta"), 0)
circuit.rz(Parameter("phi"), 1)

# `measure_all` adds a 3-bit classical register named "meas"
circuit.measure_all()

# Choose the least busy backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Generate a preset pass manager
# This will be used to convert the abstract circuit to an
# equivalent Instruction Set Architecture (ISA) circuit.
preset_pass_manager = generate_preset_pass_manager(
backend=backend, optimization_level=0
)

# Transpile the circuit
isa_circuit = preset_pass_manager.run(circuit)

Přidání CircuitItem​

Dále přidej cílový Circuit, který byl transpilován podle architektury instrukční sady (ISA) backendu, do QuantumProgram. Protože tento Circuit má dva parametry, musíme také poskytnout hodnoty parametrů (10 sad v tomto příkladu). Spuštění tohoto CircuitItem je první úkol, který program provede.

# Append the transpiled circuit and an array
# containing 10 sets of parameter values to the program
program.append_circuit_item(
isa_circuit,
circuit_arguments=np.random.rand(
10, 2
), # 10 sets of parameter values and 2 parameters
)

Přidání SamplexItem​

Položky Circuit jsou spouštěny bez jakékoli randomizace. Naopak položky samplex ti umožňují specifikovat, jak randomizovat jejich obsah. Následující buňka používá funkci generate_boxing_pass_manager() pro seskupení Gate a měření Circuit do boxů a přidání anotace twirling ke každému boxu. Poté generuje pár šablonového Circuit a samplex pomocí funkce build().

Spuštění tohoto SamplexItem je druhý úkol, který program provede.

Podrobnosti o samplex a jeho argumentech najdeš v dokumentaci API Samplomatic. Informace o používání funkce generate_boxing_pass_manager() najdeš v průvodci Transpileru Samplomatic.

# Transpile the circuit, additionally grouping gates and measurements into annotated boxes
preset_pass_manager = generate_preset_pass_manager(
backend=backend, optimization_level=0
)

# Use the boxing pass manager to group gates
# and measurements into boxes and add
# a`Twirl` annotation.
preset_pass_manager.post_scheduling = generate_boxing_pass_manager(
# Add gate twirling
enable_gates=True,
# Add measurement twirling
enable_measures=True,
)
boxed_circuit = preset_pass_manager.run(circuit)

# Build the template circuit and the samplex. The template circuit has parametric gates
# without fixed values and the samplex randomly generates the parameter
# values on the server side at runtime to perform twirling.
template_circuit, samplex = build(boxed_circuit)

# Determine what arguments are required by the samplex.
# Input the arguments in samplex_arguments.
print(samplex.inputs())
TensorInterface(<
- 'parameter_values' <float64[2]>: Input parameter values to use during sampling.
>)
# Append the template circuit and samplex as a samplex item
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
# the arguments required by the samplex.sample method
"parameter_values": np.random.rand(10, 2),
},
shape=(28, 10), # 28 randomizations and 10 sets of parameter values
)
# Initialize an Executor with the default options
executor = Executor(mode=backend)

# Submit the job
job = executor.run(program)

# Retrieve the result
result = job.result()

Výstupy​

Výstup Executor je QuantumProgramResult, který je iterovatelný. Obsahuje jeden záznam na vstupní QuantumProgramItem ve stejném pořadí jako vstupní položky. Každá z těchto výstupních položek je slovník, kde klíče jsou řetězce odpovídající názvům klasických registrů ve vstupních obvodech (mimo jiné), takže si už nemusíš pamatovat tyto názvy jako u výstupu Sampler. Hodnoty slovníku jsou typu np.ndarray.

Výsledek předchozího příkladu obsahuje tyto položky:

Výsledek CircuitItem​

První položka obsahuje výsledky spuštění první úlohy (CircuitItem) v programu. Obsahuje jeden klíč, meas, což je název klasického registru ve vstupním obvodu. Hodnota tohoto klíče je mapována na np.ndarray o tvaru (parameter sets, shots, register bits), což je (10, 1024, 3) pro výše uvedený příklad.

Následující kód ilustruje, jak k těmto informacím přistupovat:

# Access the results of the classical register of task #0, a CircuitItem
result_0 = result[0]["meas"]
print(f"Result shape: {result_0.shape}")
Result shape: (10, 1024, 3)

Nejpravější osa result_0 probíhá přes klasické bity v pořadí little-endian. Index 0 tedy obsahuje výsledek klasického bitu 0, tedy nejméně významného bitu.

Výsledek SamplexItem​

Druhá položka obsahuje výsledky spuštění druhé úlohy (SamplexItem) v programu. Tato položka obsahuje více klíčů. Klíč meas, což je název klasického registru vstupního obvodu, je mapován na pole výsledků tohoto registru. Toto pole má tvar (randomizations, parameter sets, shots, classical bits), tedy (28, 10, 1024, 3) v tomto příkladu.

Kromě toho výstup obsahuje klíč measurement_flips.meas, což jsou korekce bitových převrácení, které vrací zpět twirling měření pro registr meas. Tento výstupní tvar bude pro náš příklad (28, 10, 1, 3), protože k provedení bitového převrácení je zapotřebí pouze jeden shot.

Všimni si, že nejpravější osa result_1 probíhá přes klasické bity v pořadí little-endian.

# Access the results of the classical register of task #1
result_1 = result[1]["meas"]
print(f"Result shape: {result_1.shape}")

# Access the bit-flip corrections
flips_1 = result[1]["measurement_flips.meas"]
print(f"Bit-flip corrections shape: {flips_1.shape}")

# Undo the bit flips via classical XOR
unflipped_result_1 = result_1 ^ flips_1
Result shape: (28, 10, 1024, 3)
Bit-flip corrections shape: (28, 10, 1, 3)

Zobrazení execution spans​

Jediné volání Executor.run() odešle jedinou úlohu. Na straně serveru však služba nemusí nutně spouštět všechny konfigurace kvantového programu najednou. Místo toho seskupí svázané obvody položek programu do částí (chunks) a na QPU spouští vždy jednu část. Nemusíš program dělit ani odesílat další úlohy; dělení probíhá automaticky v rámci jediné úlohy. Atribut metadata výsledku obsahuje informace o časování těchto částí v result.metadata.chunk_timing. Tyto časové značky jsou skutečné časy zahájení a ukončení každé části na QPU. Pomocí těchto informací můžeš zjistit, kdy byla konkrétní data na QPU nasbírána, pochopit, jak Executor práci rozdělil, nebo diagnostikovat problémy s výkonem.

chunk_timing je seznam, který obsahuje jeden ChunkSpan na každou provedenou část. Každý ChunkSpan má tyto atributy:

  • start a stop: Časové značky UTC, kdy část začala a skončila provádění na QPU.

  • parts: Seznam objektů ChunkPart, které popisují, které položky programu do části přispěly. Každý ChunkPart obsahuje následující:

    • idx_item: Index položky programu v pořadí, v jakém byly položky přidány do QuantumProgram.

    • size: Počet konfigurací (prvků tvaru položky) z dané položky, které byly provedeny v této části. Například SamplexItem v předchozím příkladu má tvar (28, 10), takže má celkem 280 konfigurací.

Následující kód vypíše dobu trvání každé části a obsah každé části pro dříve odeslanou úlohu:

for idx, span in enumerate(result.metadata.chunk_timing):
duration = (span.stop - span.start).total_seconds()
print(f"Chunk {idx}: {span.start} to {span.stop} ({duration:.3f} s)")
for part in span.parts:
print(f" Item {part.idx_item}: {part.size} configurations")
Chunk 0: 2026-11-06 01:47:46.009718+00:00 to 2026-11-06 01:49:05.577720+00:00 (79.568 s)
Item 0: 10 configurations
Item 1: 280 configurations

Vlastnost QuantumProgramResult.timing obaluje stejný seznam do objektu ChunkTiming, který navíc uvádí globální informace o souboru částí:

timing = result.timing

print("Number of chunks:", len(timing))
print(" Start of the first chunk:", timing.start)
print(" End of the last chunk:", timing.stop)
print(" Total duration (s):", timing.duration)
Number of chunks: 1
Start of the first chunk: 2026-11-06 01:47:46.009718+00:00
End of the last chunk: 2026-11-06 01:49:05.577720+00:00
Total duration (s): 79.568002

Vizualizace execution spans​

Pomocí funkce draw_chunk_timings vizualizuj časování částí v interaktivním sloupcovém grafu. Osa x je čas a každá část je vykreslena jako vodorovný úsek, který zahrnuje její čas zahájení a ukončení. Osa y ukazuje kumulativní počet dokončených konfigurací (nebo procento celkové zátěže, pokud nastavíš normalize_y=True). Najetím na úsek zobrazíš časové značky, dobu trvání a části dané části.

Funkce vrací obrázek plotly, který můžeš zobrazit přímo, uložit do souboru, nebo obojí. Přijímá buď seznam chunk_timing, nebo objekt ChunkTiming. Můžeš jich předat několik, například z různých úloh, a vykreslit je do stejného grafu. Nastavením common_start=True je zarovnáš na společný čas zahájení pro porovnání.

Vyžadován Plotly

draw_chunk_timings vyžaduje plotly. Můžeš ho nainstalovat příkazem pip install plotly.

Mezery mezi částmi

Vizualizace může ukazovat mezery mezi prováděním částí. Všechny úlohy odeslané na skutečné QPU procházejí klasickým předzpracováním, například převodem na pulzy, které lze odeslat do hardwaru. Protože toto předzpracování může probíhat paralelně, služba vyřazuje z fronty a spouští více úloh současně. QPU však dokáže zpracovávat jen jednu jednotku práce najednou. Pokud proto úloha generuje více částí, mohou se její části prolínat s částmi úloh jiných uživatelů a každá část může muset čekat, až na ni přijde řada na QPU. Proto mohou mezi částmi vznikat mezery.

from qiskit_ibm_runtime.visualization import draw_chunk_timings

fig = draw_chunk_timings(result.timing, names="Executor job")

# Alternatively, call the `draw()` method of the ChunkTiming object
# fig = result.timing.draw()

# Uncomment the following line to display the figure
# fig.show(renderer="notebook")

# Save to a file
# fig.write_html("chunk_timings.html")

Další kroky​

Doporučení