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.3.0
qiskit-ibm-runtime~=0.43.1
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 Circuit.
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 losowej unitarnej, po której następuje bramka SWAP.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
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")
Użyjemy atrapowego Backend FakeSherbrooke w naszych przykładach. 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 robi różnicę.
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 Circuit ma tylko dwie bramki ECR, ale jest przybliżonym Circuit. Aby zrozumieć, czym różni się jego działanie od dokładnego Circuit, możemy obliczyć wierność między operatorem unitarnym, który implementuje ten Circuit, a dokładnym unitarnym. Przed wykonaniem obliczeń najpierw redukujemy transpilowany Circuit, który zawiera 127 Qubitów, do Circuit zawierającego tylko aktywne Qubity, których jest 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.