Přeskočit na hlavní obsah

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.4.0
qiskit-ibm-runtime~=0.46.1
samplomatic~=0.18.0
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime samplomatic

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 snímků.

poznámka

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

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 instrukční sady architektury (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ího úkolu (CircuitItem) v programu. Obsahuje jeden klíč, meas, což je název klasického registru ve vstupním Circuit. Hodnota tohoto klíče se mapuje na np.ndarray tvaru (sady parametrů, snímky, bity registru), 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)

Výsledek SamplexItem

Druhá položka obsahuje výsledky spuštění druhého úkolu (SamplexItem) v programu. Tato položka obsahuje více klíčů. Klíč meas, což je název klasického registru vstupního Circuit, se mapuje na pole výsledků tohoto registru. Toto pole má tvar (randomizace, sady parametrů, snímky, klasické bity), tedy (28, 10, 1024, 3) v tomto příkladu. Výstup navíc obsahuje klíč measurement_flips.meas, což jsou korekce překlopení bitů pro zrušení twirling měření pro registr meas. Tvar tohoto výstupu bude (28, 10, 1, 3) pro náš příklad, protože k provedení překlopení bitů je potřeba pouze jeden snímek.

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

Další kroky

Doporučení