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?

Řezání Gate pro snížení šířky Circuit

V tomto notebooku projdeme kroky Qiskit patternu a využijeme circuit cutting ke snížení počtu Qubitů v Circuit. Budeme řezat Gate, abychom mohli rekonstruovat očekávanou hodnotu čtyřqubitového Circuit pomocí pouze dvouqubitových experimentů.

Postup se skládá z těchto kroků:

  • Krok 1: Namapování problému na kvantové Circuit a operátory:

    • Namapuj hamiltonián na kvantový Circuit.
  • Krok 2: Optimalizace pro cílový hardware [Používá cutting addon]:

    • Řezání Circuit a observablu.
    • Transpilace subexperimentů pro hardware.

  • Krok 3: Spuštění na cílovém hardware:

    • Spusť subexperimenty získané v Kroku 2 pomocí primitiva Sampler.
  • Krok 4: Post-processing výsledků [Používá cutting addon]:

    • Zkombinuj výsledky Kroku 3 pro rekonstrukci očekávané hodnoty sledovaného observablu.

Krok 1: Mapování​

Vytvoření Circuit k řezání​

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

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_cutting": "qiskit-addon-cutting", "qiskit_aer": "qiskit-aer", "qiskit_ibm_runtime": "qiskit-ibm-runtime"}
_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.circuit.library import efficient_su2

qc = efficient_su2(4, entanglement="linear", reps=2)
qc.assign_parameters([0.4] * len(qc.parameters), inplace=True)

qc.draw("mpl", scale=0.8)

Diagram kvantového Circuit

Definování observablu​

from qiskit.quantum_info import SparsePauliOp

observable = SparsePauliOp(["ZZII", "IZZI", "-IIZZ", "XIXI", "ZIZZ", "IXIX"])

Krok 2: Optimalizace​

Rozdělení Circuit a observablu podle zadaného rozdělení Qubitů​

Každý štítek v partition_labels odpovídá Qubitu v circuit na stejném indexu. Qubity sdílející společný štítek oddílu budou seskupeny dohromady a nelokální Gate přesahující více než jeden oddíl budou přeříznuty.

Poznámka: Argument observables funkce partition_problem je typu PauliList. Koeficienty a fáze termů observablu jsou během dekompozice problému a provádění subexperimentů ignorovány. Lze je znovu použít při rekonstrukci očekávané hodnoty.

from qiskit_addon_cutting import partition_problem

partitioned_problem = partition_problem(
circuit=qc, partition_labels="AABB", observables=observable.paulis
)
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables
bases = partitioned_problem.bases

Vizualizace rozloženého problému​

subobservables
{'A': PauliList(['II', 'ZI', 'ZZ', 'XI', 'ZZ', 'IX']),
'B': PauliList(['ZZ', 'IZ', 'II', 'XI', 'ZI', 'IX'])}
subcircuits["A"].draw("mpl", scale=0.8)

Diagram kvantového Circuit

subcircuits["B"].draw("mpl", scale=0.8)

Diagram kvantového Circuit

Výpočet sampling overhead pro zvolené řezy​

Zde řežeme dva CNOT Gate, což vede k sampling overhead 929^2.

Více informací o sampling overhead vzniklém při circuit cutting najdeš ve vysvětlujícím materiálu.

import numpy as np

print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")
Sampling overhead: 81.0

Generování subexperimentů ke spuštění na Backend​

generate_cutting_experiments přijímá argumenty circuits/observables jako slovníky mapující štítky qubitových oddílů na příslušné subcircuit/subobservables.

Pro simulaci očekávané hodnoty Circuit v plné velikosti se ze sdruženého kvazipravděpodobnostního rozdělení dekomponovaných Gate generuje mnoho subexperimentů, které jsou pak spuštěny na jednom nebo více Backend. Počet vzorků odebraných z rozdělení je řízen parametrem num_samples a pro každý jedinečný vzorek je přiřazen jeden kombinovaný koeficient. Více informací o výpočtu koeficientů najdeš ve vysvětlujícím materiálu.

from qiskit_addon_cutting import generate_cutting_experiments

subexperiments, coefficients = generate_cutting_experiments(
circuits=subcircuits, observables=subobservables, num_samples=np.inf
)

Výběr Backend​

Zde používáme falešný Backend, který způsobí, že Qiskit Runtime poběží v lokálním režimu (tj. na lokálním simulátoru).

from qiskit_ibm_runtime.fake_provider import FakeManilaV2

backend = FakeManilaV2()

Příprava subexperimentů pro Backend​

Před odesláním do Qiskit Runtime musíme transpilovat Circuit s naším Backend jako cílem.

from qiskit.transpiler import generate_preset_pass_manager

# Transpile the subexperiments to ISA circuits
pass_manager = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_subexperiments = {
label: pass_manager.run(partition_subexpts)
for label, partition_subexpts in subexperiments.items()
}

Krok 3: Spuštění​

Spuštění subexperimentů pomocí primitiva Qiskit Runtime Sampler​

from qiskit_ibm_runtime import SamplerV2, Batch

# Submit each partition's subexperiments to the Qiskit Runtime Sampler
# primitive, in a single batch so that the jobs will run back-to-back.
with Batch(backend=backend) as batch:
sampler = SamplerV2(mode=batch)
jobs = {
label: sampler.run(subsystem_subexpts, shots=2**12)
for label, subsystem_subexpts in isa_subexperiments.items()
}
/home/garrison/Qiskit/qiskit-ibm-runtime/qiskit_ibm_runtime/session.py:157: UserWarning: Session is not supported in local testing mode or when using a simulator.
warnings.warn(
# Retrieve results
results = {label: job.result() for label, job in jobs.items()}

Krok 4: Post-processing​

Rekonstrukce očekávané hodnoty​

Rekonstruuj očekávané hodnoty pro každý term observablu a zkombinuj je pro rekonstrukci očekávané hodnoty původního observablu.

from qiskit_addon_cutting import reconstruct_expectation_values

# Get expectation values for each observable term
reconstructed_expval_terms = reconstruct_expectation_values(
results,
coefficients,
subobservables,
)

# Reconstruct final expectation value
reconstructed_expval = np.dot(reconstructed_expval_terms, observable.coeffs)

Porovnání rekonstruované očekávané hodnoty s přesnou očekávanou hodnotou z původního Circuit a observablu​

from qiskit_aer.primitives import EstimatorV2

estimator = EstimatorV2()
exact_expval = estimator.run([(qc, observable)]).result()[0].data.evs
print(f"Reconstructed expectation value: {np.real(np.round(reconstructed_expval, 8))}")
print(f"Exact expectation value: {np.round(exact_expval, 8)}")
print(f"Error in estimation: {np.real(np.round(reconstructed_expval-exact_expval, 8))}")
print(
f"Relative error in estimation: {np.real(np.round((reconstructed_expval-exact_expval) / exact_expval, 8))}"
)
Reconstructed expectation value: 0.6991539
Exact expectation value: 0.56254612
Error in estimation: 0.13660778
Relative error in estimation: 0.24283836