Przejdź do głównej treści
Ten projekt jest w wersji beta. Znalazłeś błąd? Otwórz zgłoszenie na GitHub. Masz pytanie lub pomysł? Zapytaj w Discussions — chętnie poznamy Twoją opinię!
Jak oceniasz jakość tłumaczenia tej strony?

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 optymalizacjiOpis
0

Brak optymalizacji: zazwyczaj używany do charakteryzacji sprzętu

  • Podstawowa translacja
  • Układ/Routing: TrivialLayout, gdzie wybiera te same numery fizycznych Qubitów co wirtualne i wstawia SWAP, aby to działało (przy użyciu SabreSwap)
1

Lekka optymalizacja:

  • Układ/Routing: Najpierw próbowany jest układ z TrivialLayout. Jeśli wymagane są dodatkowe SWAP, układ z minimalną liczbą SWAP jest znajdowany za pomocą SabreSwap, następnie używany jest VF2LayoutPostLayout, aby spróbować wybrać najlepsze Qubity w grafie.
  • InverseCancellation
  • Optymalizacja bramek 1Q
2

Średnia optymalizacja:

  • Układ/Routing: Poziom optymalizacji 1 (bez trivial) + heurystyczna optymalizacja z większą głębokością przeszukiwania i próbami funkcji optymalizacji. Ponieważ TrivialLayout nie jest używany, nie ma próby użycia tych samych numerów fizycznych i wirtualnych Qubitów.
  • CommutativeCancellation
3

Wysoka optymalizacja:

  • Poziom optymalizacji 2 + heurystyczna optymalizacja układu/routingu z większym wysiłkiem/próbami
  • Resynteza bloków dwuqubitowych przy użyciu dekompozycji KAK Cartana.
  • Przebiegi łamiące unitarność:
    • OptimizeSwapBeforeMeasure: Przesuwa pomiary, aby unikać SWAP
    • RemoveDiagonalGatesBeforeMeasure: Usuwa bramki przed pomiarami, które nie wpływałyby na pomiary

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

Wynik poprzedniej komórki kodu

uwaga

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)

Wynik poprzedniej komórki kodu

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)

Wynik poprzedniej komórki kodu

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)

Wynik poprzedniej komórki kodu

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)

Wynik poprzedniej komórki kodu

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)

Wynik poprzedniej komórki kodu

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​

Zalecenia