Příklady Executoru
Verze balíčků
Kód na této stránce byl vyvinut za použití následujících požadavků. Doporučujeme používat tyto verze nebo novější.
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
Příklady v této části ilustrují některé běžné způsoby použití primitivu Executor. Před spuštěním těchto příkladů postupuj podle pokynů v Instalace Qiskit a Rychlý start Executoru.
Než začneš
Některé z příkladů 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 znázorněno 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: Parametrizovaný obvod
Tento příklad ilustruje, jak přidávat položky obvodu s parametry a také jak přidávat položky samplex. Skládá se z těchto kroků:
- Nastavení obvodu: Vygeneruj a transpiluj cílový obvod.
- Příprava samplexu: Seskup hradla a měření do anotovaných boxů a vygeneruj pár šablony obvodu a samplexu.
- Spuštění: Přidej položku obvodu a položku samplexu do
QuantumPrograma spusť obě v jedné úloze.
Nastavení obvodu
Připrav tříqubitový stav GHZ, otoč qubity kolem osy Pauliho-Z a změř qubity ve výpočetní bázi.
from qiskit.circuit import Parameter, QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService, Executor
from qiskit_ibm_runtime.quantum_program import QuantumProgram
from qiskit.transpiler import generate_preset_pass_manager
import numpy as np
from samplomatic import build
from samplomatic.transpiler import generate_boxing_pass_manager
# Generate the circuit
circuit = QuantumCircuit(3)
circuit.h(0)
circuit.h(1)
circuit.cz(0, 1)
circuit.h(1)
circuit.h(2)
circuit.cz(1, 2)
circuit.h(2)
circuit.rz(Parameter("theta"), 0)
circuit.rz(Parameter("phi"), 1)
circuit.rz(Parameter("lam"), 2)
circuit.measure_all()
Zadej backend a transpiluj obvod tak, aby používal pouze instrukce podporované QPU (označované jako obvod architektury sady instrukcí (ISA)).
# Initialize the service and choose a backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# Transpile the circuit to ISA
preset_pass_manager = generate_preset_pass_manager(
backend=backend, optimization_level=3
)
isa_circuit = preset_pass_manager.run(circuit)
Příprava samplexu
Použij pomocnou funkci generate_boxing_pass_manager a její parametry twirling k seskupení dvouqubitových hradel a měření do boxů a k aplikaci anotací twirling.
boxing_pm = generate_boxing_pass_manager(
# Add gate twirling
enable_gates=True,
# Add measurement twirling
enable_measures=True,
)
boxed_circuit = boxing_pm.run(isa_circuit)
Použij metodu build k vygenerování šablony obvodu a samplexu.
# Build the template circuit and the samplex
template_circuit, samplex = build(boxed_circuit)
Spuštění obvodů
Executor spouští objekty QuantumProgram. Každý QuantumProgram může obsahovat několik položek. Tento příklad přidá položku obvodu a položku samplexu ke spuštění. Úplné podrobnosti najdeš v Vstupy a výstupy Executoru.
Prvním krokem je inicializace prázdného programu, přičemž se požaduje 1024 shotů pro každou konfiguraci každé položky.
# Generate a quantum program
program = QuantumProgram(shots=1024)
Připoj položku obvodu k QuantumProgram. Tato položka obvodu se skládá ze dvou částí – ISA obvodu a 10 sad jeho hodnot parametrů.
# Append the circuit and the parameter values to the program
program.append_circuit_item(
isa_circuit,
circuit_arguments=np.random.rand(10, 3), # 10 sets of parameter values
)
Připoj položku samplexu k QuantumProgram s těmito argumenty:
- Šablona obvodu a samplex vygenerovaný funkcí
build - Deset sad hodnot parametrů pro původní obvod
- Počet randomizací k provedení
# Append the template circuit and samplex as a samplex item
program.append_samplex_item(
template_circuit,
samplex=samplex,
samplex_arguments={
"parameter_values": np.random.rand(
10, 3
), # 10 sets of parameter values
},
shape=(2, 14, 10),
)
Spuštění úlohy Executoru
# initialize an Executor with default options
executor = Executor(mode=backend)
# Submit the job
job = executor.run(program)
# Retrieve the result
result = job.result()
Získej výsledek pro každý úkol.
# Access the results of the classical register of task #0, the CircuitItem
result_0 = result[0]["meas"]
# Access the results of the classical register of task #1, the SamplexItem
result_1 = result[1]["meas"]
Příklad: Provedení PEC
Tento příklad ukazuje, jak používat položku samplex k provedení probabilistického rušení chyb (PEC) pro zmírňování chyb.
Uvažuj zrcadlovou verzi obvodu s deseti qubity a dvěma jedinečnými vrstvami hradel CX. Toto jsou hlavní úkoly:
- Spusť obvod s twirlingem.
- Spusť obvod s PEC zmírňováním, jako v práci "Probabilistic error cancellation with sparse Pauli-Lindblad models on noisy quantum processors".
Postup se skládá z těchto kroků:
- Nastavení: Vygeneruj cílový obvod a seskup jeho operace do boxů.
- Učení: Nauč se šum instrukcí, které chceme zmírňovat pomocí PEC.
- Spuštění: Spusť obvod na backendu.
- Analýza: Zpracuj a analyzuj výsledky.
Pro srovnání spustíme tento zrcadlový obvod dvakrát. Jednou s aplikovaným pouze Pauliho twirlingem a jednou s aplikovaným PEC zmírňováním.
Využití pro tento příklad je přibližně 10 minut na procesoru Heron r2.
Nastavení obvodu
Zvol backend a připrav 10-qubitový obvod.
from qiskit_ibm_runtime import QiskitRuntimeService, Executor
from qiskit_ibm_runtime.quantum_program import QuantumProgram
from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.transpiler import generate_preset_pass_manager
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic import build
# Initialize the service and choose a backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
# Prepare a circuit
num_qubits = 10
num_layers = 10
qubits = list(range(num_qubits))
circuit = QuantumCircuit(num_qubits)
for layer_idx in range(num_layers):
circuit.rx(Parameter(f"theta_{layer_idx}"), qubits)
for i in range(num_qubits // 2):
circuit.cz(qubits[2 * i], qubits[2 * i + 1])
circuit.rx(Parameter(f"phi_{layer_idx}"), qubits)
for i in range(num_qubits // 2 - 1):
circuit.cz(qubits[2 * i] + 1, qubits[2 * i + 1] + 1)
circuit.draw("mpl", scale=0.35, fold=100)
Kombinuj obvod s jeho inverzí, abys vytvořil zrcadlový obvod.
mirror_circuit = circuit.compose(circuit.inverse())
mirror_circuit.measure_all()
mirror_circuit.draw("mpl", scale=0.35, fold=100)
Nastav několik hodnot parametrů:
import numpy as np
parameter_values = np.random.rand(mirror_circuit.num_parameters)
Použij pass manager k transpilaci obvodu na ISA obvod.
preset_pass_manager = generate_preset_pass_manager(
backend=backend,
optimization_level=3,
)
isa_circuit = preset_pass_manager.run(mirror_circuit)
Dále seskup hradla a měření do anotovaných boxů. Můžeš to provést ručně nebo použít funkci generate_boxing_pass_manager ze Samplomatic pro pohodlí. První obvod bude mít aplikován pouze twirling, a proto potřebuje pouze anotaci Twirl. Druhý obvod bude spuštěn s plným PEC zmírňováním a potřebuje jak anotaci Twirl, tak InjectNoise.
# Pass manager used to create twirled-annotated boxes.
boxing_pm = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
)
mirror_circuit_twirl = boxing_pm.run(isa_circuit)
# Pass manager used to create a new boxed circuit with
# both Twirl and InjectNoise annotations.
boxing_pm = generate_boxing_pass_manager(
enable_gates=True,
enable_measures=True,
inject_noise_targets="gates", # no measurement mitigation
inject_noise_strategy="uniform_modification",
)
mirror_circuit_pec = boxing_pm.run(isa_circuit)
Učení šumu
Chceš-li minimalizovat počet experimentů učení šumu, identifikuj jedinečné instrukce ve druhém obvodu (v tom s boxy anotovanými InjectNoise). Při definování jedinečnosti jsou dvě instrukce boxů stejné, pokud platí obě z následujících podmínek:
- Jejich obsah je stejný, až na jednoqubitová hradla.
- Jejich anotace
Twirlje stejná (každá jiná anotace je ignorována).
To vede ke třem jedinečným instrukcím, konkrétně lichým a sudým boxům hradel a konečnému boxu měření.
from samplomatic.utils import find_unique_box_instructions
unique_box_instructions = find_unique_box_instructions(
mirror_circuit_pec.data
)
assert len(unique_box_instructions) == 3
Inicializuj NoiseLearnerV3, zvol parametry učení nastavením jeho možností a spusť úlohu učení šumu.
from qiskit_ibm_runtime.noise_learner_v3 import NoiseLearnerV3
learner = NoiseLearnerV3(backend)
learner.options.shots_per_randomization = 128
learner.options.num_randomizations = 32
learner.options.layer_pair_depths = [0, 1, 2, 4, 16, 32]
learner_job = learner.run(unique_box_instructions)
learner_job.job_id()
learner_result = learner_job.result()
Převeď result na objekt požadovaný samplexem pomocí metody result.to_dict.
noise_maps = learner_result.to_dict(
instructions=unique_box_instructions, require_refs=False
)
Spuštění obvodů
Executor spouští objekty QuantumProgram. Každý QuantumProgram může obsahovat několik položek, které jsou k programu připojeny. Každá položka je úkol pro program k provedení.
Inicializuj prázdný program, přičemž požaduješ 1000 shotů pro každou konfiguraci každé položky.
from qiskit_ibm_runtime.quantum_program import QuantumProgram
# Initialize an empty QuantumProgram
program = QuantumProgram(shots=1000)
Dále vytvoř šablonu obvodu a samplex pro mirror_circuit_twirl a připoj je k programu. Také požaduj 900 randomizací od samplexu. To znamená, že samplex vygeneruje 900 sad parametrů a každá sada bude provedena 1000krát (počet shotů) na QPU.
Toto je první úkol programu (výsledek 0).
template_twirl, samplex_twirl = build(mirror_circuit_twirl)
program.append_samplex_item(
template_twirl,
samplex=samplex_twirl,
samplex_arguments={"parameter_values": parameter_values},
shape=(900,),
)
Podobně připoj šablonu obvodu a samplex sestavený pro mirror_circuit_pec, přičemž požaduješ 900 randomizací. Toto je druhý úkol programu (výsledek 1).
template_pec, samplex_pec = build(mirror_circuit_pec)
program.append_samplex_item(
template_pec,
samplex=samplex_pec,
samplex_arguments={
"parameter_values": parameter_values,
"pauli_lindblad_maps": noise_maps,
"noise_scales": {
ref: -1.0 for ref in noise_maps
}, # Set the scales to -1 for PEC
},
shape=(900,),
)
Importuj Executor a odešli úlohu.
from qiskit_ibm_runtime.executor import Executor
executor = Executor(backend)
executor_job = executor.run(program)
executor_job.job_id()
executor_results = executor_job.result()
executor_results
twirl_result = executor_results[0]
print(f"Twirl result keys:\n {list(twirl_result.keys())}\n")
print(f"Shape of results: {twirl_result['meas'].shape}")
pec_result = executor_results[1]
print(f"PEC result keys:\n {list(pec_result.keys())}\n")
print(f"Shape of results: {pec_result['meas'].shape}")
Twirl result keys:
['meas', 'measurement_flips.meas']
Shape of results: (900, 1000, 10)
PEC result keys:
['meas', 'measurement_flips.meas', 'pauli_signs']
Shape of results: (900, 1000, 10)
Analýza výsledků
Nakonec dodatečně zpracuj výsledky pro odhad středních hodnot jednoqubitových operátorů Pauliho-Z působících na každý z deseti aktivních qubitů (očekávaná hodnota: 1.0).
# Undo measurement twirling
twirl_result_unflipped = (
twirl_result["meas"] ^ twirl_result["measurement_flips.meas"]
)
# Calculate the expectation values of single-qubit Z operators
exp_vals = 1 - 2 * twirl_result_unflipped.mean(axis=1).mean(axis=0)
for qubit, val in enumerate(exp_vals):
print(f"Qubit {qubit} -> {np.round(val, 2)}")
Qubit 0 -> 0.77
Qubit 1 -> 0.76
Qubit 2 -> 0.66
Qubit 3 -> 0.71
Qubit 4 -> 0.69
Qubit 5 -> 0.67
Qubit 6 -> 0.62
Qubit 7 -> 0.59
Qubit 8 -> 0.62
Qubit 9 -> 0.68
# Undo measurement twirling
pec_result_unflipped = (
pec_result["meas"] ^ pec_result["measurement_flips.meas"]
)
# Calculate the signs for PEC mitigation
signs = np.prod((-1) ** pec_result["pauli_signs"], axis=-1)
signs = signs.reshape((signs.shape[0], 1))
# Calculate the expectation values of single-qubit Z operators as required by
# PEC mitigation
exp_vals = 1 - (2 * pec_result_unflipped.mean(axis=1) * signs).mean(axis=0)
for qubit, val in enumerate(exp_vals):
print(f"Qubit {qubit} -> {np.round(val, 2)}")
Qubit 0 -> 0.98
Qubit 1 -> 0.99
Qubit 2 -> 0.96
Qubit 3 -> 0.98
Qubit 4 -> 0.98
Qubit 5 -> 0.98
Qubit 6 -> 0.98
Qubit 7 -> 0.95
Qubit 8 -> 0.95
Qubit 9 -> 0.94
Další kroky
- Prostuduj přehled broadcastingu.
- Zjisti, jak používat možnosti Executoru.
- Porozumět modelu řízeného spuštění.
- Prostuduj dokumentaci Samplomatic.
- Zjisti, jak kombinovat různé techniky zmírňování chyb při používání modelu řízeného spuštění v tutoriálu Probabilistic error cancellation with shaded lightcones.