Przejdź do głównej treści

Reprezentacja komputerów kwantowych dla Transpilera

Wersje pakietów

Kod na tej stronie został opracowany przy użyciu poniższych zależności. Zalecamy korzystanie z tych wersji lub nowszych.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

Aby przekształcić abstrakcyjny obwód na obwód ISA, który może działać na określonym QPU (jednostce przetwarzania kwantowego), Transpiler potrzebuje pewnych informacji o QPU. Informacje te znajdują się w dwóch miejscach: obiekcie BackendV2 (lub starszym BackendV1), do którego planujesz przesyłać zadania, oraz atrybucie Target Backendu.

  • Target zawiera wszystkie istotne ograniczenia urządzenia, takie jak jego natywne bramki bazowe, łączność Qubitów oraz informacje o pulsach lub czasach.
  • Backend domyślnie posiada Target, zawiera dodatkowe informacje — takie jak InstructionScheduleMap — i udostępnia interfejs do przesyłania zadań z obwodami kwantowymi.

Możesz również jawnie podać informacje dla Transpilera, na przykład jeśli masz konkretny przypadek użycia lub jeśli uważasz, że te informacje pomogą Transpilerowi wygenerować bardziej zoptymalizowany obwód.

Dokładność, z jaką Transpiler generuje najbardziej odpowiedni obwód dla konkretnego sprzętu, zależy od tego, ile informacji Target lub Backend ma na temat swoich ograniczeń.

uwaga

Ponieważ wiele podstawowych algorytmów transpilacji ma charakter stochastyczny, nie ma gwarancji, że zostanie znaleziony lepszy obwód.

Ta strona pokazuje kilka przykładów przekazywania informacji o QPU do Transpilera. W przykładach tych używany jest target z pozorowanego Backendu FakeSherbrooke.

Konfiguracja domyślna

Najprostszym sposobem użycia Transpilera jest podanie wszystkich informacji o QPU przez przekazanie Backend lub Target. Aby lepiej zrozumieć, jak działa Transpiler, skonstruuj obwód i poddaj go transpilacji z różnymi informacjami w następujący sposób.

Zaimportuj niezbędne biblioteki i utwórz instancję QPU: Aby przekształcić abstrakcyjny obwód na obwód ISA, który może działać na konkretnym procesorze, Transpiler potrzebuje pewnych informacji o tym procesorze. Zazwyczaj informacje te są przechowywane w Backend lub Target przekazywanych do Transpilera i żadne dodatkowe informacje nie są potrzebne. Możesz jednak również jawnie podać informacje dla Transpilera, na przykład jeśli masz konkretny przypadek użycia lub jeśli uważasz, że te informacje pomogą Transpilerowi wygenerować bardziej zoptymalizowany obwód.

Ten temat pokazuje kilka przykładów przekazywania informacji do Transpilera. W tych przykładach używany jest target z pozorowanego Backendu FakeSherbrooke.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()
target = backend.target

Przykładowy obwód używa instancji efficient_su2 z biblioteki obwodów Qiskit.

from qiskit.circuit.library import efficient_su2

qc = efficient_su2(12, entanglement="circular", reps=1)

qc.draw("mpl")

Output of the previous code cell

Ten przykład używa domyślnych ustawień do transpilacji do target Backendu, co dostarcza wszystkich informacji potrzebnych do przekształcenia obwodu na taki, który zadziała na Backendzie.

from qiskit.transpiler import generate_preset_pass_manager

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=target, seed_transpiler=12345
)
qc_t_target = pass_manager.run(qc)
qc_t_target.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

Ten przykład jest używany w późniejszych sekcjach tego tematu, aby zilustrować, że mapa sprzężeń i bramki bazowe są kluczowymi informacjami przekazywanymi do Transpilera w celu optymalnej konstrukcji obwodu. QPU zazwyczaj może wybrać domyślne ustawienia dla innych informacji, które nie są przekazywane, takich jak czas i harmonogramowanie.

Mapa sprzężeń

Mapa sprzężeń to graf pokazujący, które Qubity są połączone i tym samym mają między sobą bramki dwu-Qubitowe. Czasem ten graf jest kierunkowy, co oznacza, że bramki dwu-Qubitowe mogą działać tylko w jednym kierunku. Jednak Transpiler zawsze może odwrócić kierunek bramki, dodając dodatkowe bramki jedno-Qubitowe. Abstrakcyjny obwód kwantowy zawsze może być reprezentowany na tym grafie, nawet jeśli jego łączność jest ograniczona, przez wprowadzenie bramek SWAP do przemieszczania informacji kwantowej.

Qubity z naszych abstrakcyjnych obwodów nazywane są wirtualnymi Qubitami, a te na mapie sprzężeń to fizyczne Qubity. Transpiler zapewnia odwzorowanie między wirtualnymi a fizycznymi Qubitami. Jednym z pierwszych kroków transpilacji, etapem layout, jest wykonanie tego odwzorowania.

uwaga

Choć etap routingu jest powiązany z etapem layout — który wybiera rzeczywiste Qubity — domyślnie temat ten traktuje je jako osobne etapy dla uproszczenia. Kombinacja routingu i layoutu nazywana jest mapowaniem Qubitów. Dowiedz się więcej o tych etapach w temacie Etapy Transpilera.

Przekaż argument słów kluczowych coupling_map, aby zobaczyć jego wpływ na Transpiler:

coupling_map = target.build_coupling_map()

pass_manager = generate_preset_pass_manager(
optimization_level=0, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv0 = pass_manager.run(qc)
qc_t_cm_lv0.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

Jak pokazano powyżej, wstawiono kilka bramek SWAP (każda złożona z trzech bramek CX), co spowoduje wiele błędów na obecnych urządzeniach. Aby zobaczyć, które Qubity zostały wybrane na rzeczywistej topologii Qubitów, użyj plot_circuit_layout z wizualizacji Qiskit:

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv0, backend, view="physical")

Output of the previous code cell

Pokazuje to, że nasze wirtualne Qubity 0–11 zostały trywialnie odwzorowane na linię fizycznych Qubitów 0–11. Wróćmy do ustawień domyślnych (optimization_level=1), które używają VF2Layout jeśli wymagany jest jakikolwiek routing.

pass_manager = generate_preset_pass_manager(
optimization_level=1, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv1 = pass_manager.run(qc)
qc_t_cm_lv1.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

Teraz nie ma wstawionych bramek SWAP, a wybrane fizyczne Qubity są takie same jak podczas używania klasy target.

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv1, backend, view="physical")

Output of the previous code cell

Teraz layout jest w pierścieniu. Ponieważ ten layout respektuje łączność obwodu, nie ma bramek SWAP, co zapewnia znacznie lepszy obwód do wykonania.

Bramki bazowe

Każdy komputer kwantowy obsługuje ograniczony zestaw instrukcji zwany bramkami bazowymi. Każda bramka w obwodzie musi być przetłumaczona na elementy tego zestawu. Zestaw ten powinien składać się z bramek jedno- i dwu-Qubitowych tworzących uniwersalny zestaw bramek, co oznacza, że dowolną operację kwantową można rozłożyć na te bramki. Wykonuje to BasisTranslator, a bramki bazowe można określić jako argument słowa kluczowego w Transpilerze, aby przekazać te informacje.

basis_gates = list(target.operation_names)
print(basis_gates)
['sx', 'switch_case', 'x', 'if_else', 'measure', 'for_loop', 'delay', 'ecr', 'id', 'reset', 'rz']

Domyślne bramki jedno-Qubitowe w ibm_sherbrooke to rz, x i sx, a domyślna bramka dwu-Qubitowa to ecr (echoed cross-resonance). Bramki CX są konstruowane z bramek ecr, więc na niektórych QPU ecr jest określone jako bramka bazowa dwu-Qubitowa, a na innych domyślną jest cx. Bramka ecr jest splatającą częścią bramki cx. Oprócz bramek sterujących istnieją również instrukcje delay i pomiaru.

uwaga

QPU mają domyślne bramki bazowe, ale możesz wybrać dowolne bramki, o ile dostarczysz instrukcję lub dodasz bramki pulsowe (patrz Tworzenie przebiegów Transpilera). Domyślne bramki bazowe to te, dla których przeprowadzono kalibracje na QPU, więc nie trzeba dostarczać dodatkowych instrukcji/bramek pulsowych. Na przykład na niektórych QPU cx jest domyślną bramką dwu-Qubitową, a na innych ecr. Pełną listę możliwych natywnych bramek i operacji znajdziesz w dokumentacji.

pass_manager = generate_preset_pass_manager(
optimization_level=1,
coupling_map=coupling_map,
basis_gates=basis_gates,
seed_transpiler=12345,
)
qc_t_cm_bg = pass_manager.run(qc)
qc_t_cm_bg.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

Zwróć uwagę, że obiekty CXGate zostały rozłożone na bramki ecr i jedno-Qubitowe bramki bazowe.

Współczynniki błędów urządzenia

Klasa Target może zawierać informacje o współczynnikach błędów operacji na urządzeniu. Na przykład poniższy kod pobiera właściwości bramki echoed cross-resonance (ECR) między Qubitem 1 a 0 (należy pamiętać, że bramka ECR jest kierunkowa):

target["ecr"][(1, 0)]
InstructionProperties(duration=5.333333333333332e-07, error=0.007494257741828603)

Dane wyjściowe wyświetlają czas trwania bramki (w sekundach) oraz jej współczynnik błędu. Aby ujawnić informacje o błędach Transpilerowi, zbuduj model targetu z basis_gates i coupling_map z powyższego i wypełnij go wartościami błędów z Backendu FakeSherbrooke.

from qiskit.transpiler import Target
from qiskit.circuit.controlflow import IfElseOp, SwitchCaseOp, ForLoopOp

err_targ = Target.from_configuration(
basis_gates=basis_gates,
coupling_map=coupling_map,
num_qubits=target.num_qubits,
custom_name_mapping={
"if_else": IfElseOp,
"switch_case": SwitchCaseOp,
"for_loop": ForLoopOp,
},
)

for i, (op, qargs) in enumerate(target.instructions):
if op.name in basis_gates:
err_targ[op.name][qargs] = target.instruction_properties(i)

Przeprowadź transpilację z nowym targetem err_targ:

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=err_targ, seed_transpiler=12345
)
qc_t_cm_bg_et = pass_manager.run(qc)
qc_t_cm_bg_et.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

Ponieważ target zawiera informacje o błędach, przebieg VF2PostLayout stara się znaleźć optymalne Qubity do użycia, co skutkuje tym samym obwodem, który pierwotnie znaleziono z tymi samymi fizycznymi Qubitami.

Kolejne kroki