Ustawianie poziomu optymalizacji Transpilera
Wersje pakietów
Kod na tej stronie został opracowany przy użyciu poniższych wymagań. Zalecamy używanie tych wersji lub nowszych.
qiskit[all]~=2.6.1
qiskit-ibm-runtime~=0.50.0
Prawdziwe urządzenia kwantowe są podatne na szum i błędy bramek, dlatego optymalizacja Circuit w celu zmniejszenia ich głębokości i liczby bramek może znacząco poprawić wyniki uzyskiwane z wykonania tych obwód.
Funkcja generate_preset_pass_manager ma jeden wymagany argument pozycyjny, optimization_level, który kontroluje, ile wysiłku Transpiler wkłada w optymalizację Circuit. Ten argument może być liczbą całkowitą przyjmującą jedną z wartości 0, 1, 2 lub 3.
Wyższe poziomy optymalizacji generują bardziej zoptymalizowane Circuit kosztem dłuższego czasu kompilacji.
Poniższa tabela wyjaśnia optymalizacje przeprowadzane przy każdym ustawieniu.
| Poziom optymalizacji | Opis |
|---|---|
| 0 | Brak optymalizacji: zazwyczaj używany do charakteryzacji sprzętu
|
| 1 | Lekka optymalizacja:
|
| 2 | Średnia optymalizacja:
|
| 3 | Wysoka optymalizacja:
|
Poziom optymalizacji w działaniu
Ponieważ bramki dwuqubitowe są zazwyczaj najważniejszym źródłem błędów, możemy w przybliżeniu określić ilościowo „efektywność sprzętową" transpilacji, licząc liczbę bramek dwuqubitowych w wynikowym Circuit. Tutaj wypróbujemy różne poziomy optymalizacji na wejściowym Circuit składającym się z losowego operatora unitarnego, po którym następuje bramka SWAP.
# 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"}
_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 import QuantumCircuit
from qiskit.circuit.library import UnitaryGate
from qiskit.quantum_info import Operator, random_unitary
UU = random_unitary(4, seed=12345)
rand_U = UnitaryGate(UU)
qc = QuantumCircuit(2)
qc.append(rand_U, range(2))
qc.swap(0, 1)
qc.draw("mpl", style="iqp")
Backend FakeSherbrooke z qiskit_ibm_runtime jest używany w tych przykładach, ale możesz go wypróbować na dowolnym prawdziwym lub symulowanym Backendzie kompatybilnym z Qiskit. Twoje wyniki mogą być inne.
Najpierw transpilujmy przy użyciu poziomu optymalizacji 0.
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke
backend = FakeSherbrooke()
pass_manager = generate_preset_pass_manager(
optimization_level=0, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)
Transpilowany Circuit ma sześć dwuqubitowych bramek ECR.
Powtórzmy dla poziomu optymalizacji 1:
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke
backend = FakeSherbrooke()
pass_manager = generate_preset_pass_manager(
optimization_level=1, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)
Transpilowany Circuit nadal ma sześć bramek ECR, ale liczba jednoqubitowych bramek się zmniejszyła.
Powtórzmy dla poziomu optymalizacji 2:
pass_manager = generate_preset_pass_manager(
optimization_level=2, backend=backend, seed_transpiler=12345
)
qc_t2_exact = pass_manager.run(qc)
qc_t2_exact.draw("mpl", idle_wires=False)
To daje te same wyniki co poziom optymalizacji 1. Pamiętaj, że zwiększenie poziomu optymalizacji nie zawsze coś zmienia.
Powtórzmy ponownie z poziomem optymalizacji 3:
pass_manager = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=12345
)
qc_t3_exact = pass_manager.run(qc)
qc_t3_exact.draw("mpl", idle_wires=False)
Teraz są tylko trzy bramki ECR. Osiągamy ten wynik, ponieważ na poziomie optymalizacji 3 Qiskit próbuje powtórnie syntetyzować dwuqubitowe bloki bramek, a każda dwuqubitowa bramka może być zaimplementowana przy użyciu co najwyżej trzech bramek ECR. Możemy uzyskać jeszcze mniej bramek ECR, jeśli ustawimy approximation_degree na wartość mniejszą niż 1, pozwalając Transpilerowi na przybliżenia, które mogą wprowadzić pewien błąd w dekompozycji bramki (patrz Często używane parametry transpilacji):
pass_manager = generate_preset_pass_manager(
optimization_level=3,
approximation_degree=0.99,
backend=backend,
seed_transpiler=12345,
)
qc_t3_approx = pass_manager.run(qc)
qc_t3_approx.draw("mpl", idle_wires=False)
Ten obwód ma tylko dwie bramki ECR, ale jest obwodem przybliżonym. Aby zrozumieć, czym różni się jego działanie od dokładnego obwodu, możemy obliczyć wierność między operatorem unitarnym, który implementuje ten obwód, a dokładnym operatorem unitarnym. Przed wykonaniem obliczeń najpierw redukujemy transpilowany obwód, który zawiera 127 kubitów, do obwodu zawierającego tylko aktywne kubity, których są dwa.
import numpy as np
def trace_to_fidelity_2q(trace: float) -> float:
return (4.0 + trace * trace.conjugate()) / 20.0
# Reduce circuits down to 2 qubits so they are easy to simulate
qc_t3_exact_small = QuantumCircuit.from_instructions(qc_t3_exact)
qc_t3_approx_small = QuantumCircuit.from_instructions(qc_t3_approx)
# Compute the fidelity
exact_fid = trace_to_fidelity_2q(
np.trace(np.dot(Operator(qc_t3_exact_small).adjoint().data, UU))
)
approx_fid = trace_to_fidelity_2q(
np.trace(np.dot(Operator(qc_t3_approx_small).adjoint().data, UU))
)
print(
f"Synthesis fidelity\nExact: {exact_fid:.3f}\nApproximate: {approx_fid:.3f}"
)
Synthesis fidelity
Exact: 1.000+0.000j
Approximate: 0.992+0.000j
Zmiana poziomu optymalizacji może również wpływać na inne aspekty Circuit, nie tylko na liczbę bramek ECR. Przykłady tego, jak ustawienie poziomu optymalizacji zmienia układ, znajdziesz w sekcji Reprezentowanie komputerów kwantowych.
Kolejne kroki
- Aby dowiedzieć się więcej o funkcji
generate_preset_passmanager, zacznij od tematu Domyślne ustawienia transpilacji i opcje konfiguracji. - Kontynuuj naukę o transpilacji z tematem Etapy Transpilera.
- Wypróbuj przewodnik Porównaj ustawienia Transpilera.
- Wypróbuj samouczek Buduj kody repetycyjne.
- Zobacz dokumentację API Transpile.