Перейти до основного вмісту

Встановлення рівня оптимізації транспілятора

Версії пакетів

Код на цій сторінці розроблено з використанням наведених нижче залежностей. Рекомендуємо використовувати ці або новіші версії.

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

Реальні квантові пристрої схильні до шумів і помилок вентилів, тому оптимізація схем для зменшення їхньої глибини та кількості вентилів може суттєво покращити результати виконання цих схем. Функція generate_preset_pass_manager має один обов'язковий позиційний аргумент — optimization_level, який визначає, скільки зусиль транспілятор витрачає на оптимізацію схем. Цей аргумент може бути цілим числом з множини: 0, 1, 2 або 3. Вищі рівні оптимізації генерують більш оптимізовані схеми ціною збільшення часу компіляції. У наведеній нижче таблиці пояснюються оптимізації, що виконуються при кожному налаштуванні.

Рівень оптимізаціїОпис
0

Без оптимізації: зазвичай використовується для характеризації апаратного забезпечення

  • Базовий переклад
  • Розміщення/Маршрутизація: TrivialLayout, де вибираються ті самі номери фізичних кубітів, що й віртуальних, та вставляються SWAP-вентилі для забезпечення роботи (з використанням SabreSwap)
1

Легка оптимізація:

  • Розміщення/Маршрутизація: спочатку виконується спроба розміщення з TrivialLayout. Якщо потрібні додаткові SWAP, знаходиться розміщення з мінімальною кількістю SWAP за допомогою SabreSwap, а потім VF2LayoutPostLayout намагається вибрати найкращі кубіти у графі.
  • InverseCancellation
  • Оптимізація однокубітних вентилів
2

Середня оптимізація:

  • Розміщення/Маршрутизація: рівень оптимізації 1 (без trivial) + евристична оптимізація з більшою глибиною пошуку та кількістю спроб функції оптимізації. Оскільки TrivialLayout не використовується, немає спроби використати однакові номери фізичних і віртуальних кубітів.
  • CommutativeCancellation
3

Висока оптимізація:

  • Рівень оптимізації 2 + подальша евристична оптимізація розміщення/маршрутизації з більшими зусиллями/кількістю спроб
  • Ресинтез двокубітних блоків за допомогою KAK-розкладання Картана.
  • Проходи, що порушують унітарність:
    • OptimizeSwapBeforeMeasure: переміщує вимірювання для уникнення SWAP
    • RemoveDiagonalGatesBeforeMeasure: видаляє вентилі перед вимірюваннями, що не впливають на результати вимірювань

Рівень оптимізації в дії

Оскільки двокубітні вентилі зазвичай є найзначнішим джерелом помилок, ми можемо приблизно оцінити «апаратну ефективність» транспіляції, підрахувавши кількість двокубітних вентилів у результуючій схемі. Тут ми спробуємо різні рівні оптимізації на вхідній схемі, що складається з випадкового унітарного оператора, за яким слідує 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")

Вивід попередньої комірки коду

Ми будемо використовувати симульований бекенд FakeSherbrooke в наших прикладах. Спочатку виконаємо транспіляцію з рівнем оптимізації 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)

Вивід попередньої комірки коду

Транспільована схема містить шість двокубітних вентилів ECR.

Повторимо для рівня оптимізації 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)

Вивід попередньої комірки коду

Транспільована схема все ще містить шість вентилів ECR, але кількість однокубітних вентилів зменшилася.

Повторимо для рівня оптимізації 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)

Вивід попередньої комірки коду

Це дає ті самі результати, що й рівень оптимізації 1. Зверни увагу, що підвищення рівня оптимізації не завжди має ефект.

Повторимо ще раз, з рівнем оптимізації 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)

Вивід попередньої комірки коду

Тепер є лише три вентилі ECR. Ми отримуємо цей результат тому, що на рівні оптимізації 3 Qiskit намагається повторно синтезувати двокубітні блоки вентилів, і будь-який двокубітний вентиль можна реалізувати не більш ніж трьома вентилями ECR. Ми можемо отримати ще менше вентилів ECR, якщо встановимо approximation_degree менше 1, дозволяючи транспілятору робити наближення, що можуть вносити певну похибку в розкладання вентилів (дивись Поширено використовувані параметри транспіляції):

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)

Вивід попередньої комірки коду

Ця схема містить лише два вентилі ECR, але є наближеною. Щоб зрозуміти, наскільки її дія відрізняється від точної схеми, ми можемо обчислити точність між унітарним оператором, що реалізує ця схема, та точним унітарним. Перед обчисленням ми спочатку зводимо транспільовану схему, яка містить 127 кубітів, до схеми лише з активними кубітами — їх двоє.

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

Зміна рівня оптимізації може вплинути й на інші аспекти схеми, не лише на кількість вентилів ECR. Приклади того, як налаштування рівня оптимізації змінює розміщення, дивись у розділі Представлення квантових комп'ютерів.

Наступні кроки

Рекомендації