Виконання динамічних схем
Версії пакетів
Код на цій сторінці було розроблено з використанням таких вимог. Рекомендуємо використовувати ці або новіші версії.
qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1
Динамічні схеми — це потужні інструменти, за допомогою яких можна вимірювати кубіти в середині виконання квантової схеми, а потім виконувати класичні логічні операції в рамках схеми, базуючись на результатах цих вимірювань у середині схеми. Цей процес також відомий як класичне зворотне подавання. Хоча це ще ранні дні розуміння того, як найкраще скористатися динамічними схемами, квантова дослідницька спільнота вже визначила ряд варіантів використання, таких як:
- Ефективна підготовка квантових станів, наприклад стан GHZ, W-стан (для отримання додаткової інформації про W-стан дивись також "State preparation by shallow circuits using feed forward") та широкий клас матричних продуктових станів
- Ефективне дальнє заплутування між кубітами на одному чіпі з використанням неглибоких схем
- Ефективна вибірка схем, схожих на IQP
Однак ці покращення, принесені динамічними схемами, пов'язані з компромісами. Вимірювання в середині схеми та класичні операції зазвичай мають більший час виконання, ніж двокубітні вентилі, і це збільшення часу може нівелювати переваги зменшеної глибини схеми. Тому скорочення тривалості вимірювання в середині схеми є пріоритетним напрямом вдосконалення у міру того, як IBM Quantum® випускає нову версію динамічних схем. Інші обмеження при використанні динамічних схем дивись у таблиці сумісності функцій Estimator або Sampler.
Специфікація OpenQASM 3 визначає ряд структур потоку керування, але Qiskit Runtime наразі підтримує лише умовне твердження if. У Qiskit SDK це відповідає методу if_test на QuantumCircuit. Цей метод повертає контекстний менеджер і зазвичай використовується у твердженні with. Цей посібник описує, як використовувати це умовне твердження.
Приклади коду в цьому посібнику використовують стандартну інструкцію вимірювання для вимірювань у середині схеми. Однак рекомендується замість цього використовувати інструкцію MidCircuitMeasure, якщо backend її підтримує. Дивись розділ Вимірювання в середині схеми для деталей.
Пошук backends, що підтримують динамічні схеми
Щоб знайти всі backends, до яких має доступ твій акаунт та які підтримують динамічні схеми, запусти код, подібний до такого. Цей приклад передбачає, що ти зберіг свої облікові дані для входу. Також можна явно вказати облікові дані при ініціалізації сервісного акаунта Qiskit Runtime. Це дозволить переглядати backends, доступні для конкретного екземпляра або типу плану, наприклад.
- Backends, доступні для акаунту, залежать від екземпляра, вказаного в облікових даних.
- Нова версія динамічних схем тепер доступна всім користувачам на всіх backends. Дивись оголошення для отримання додаткової інформації.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# This cell is hidden from users. It hides all those "...instance was not set..." warnings.
import warnings
warnings.filterwarnings("ignore", message=".*Instance was not set*")
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
dc_backends = service.backends(dynamic_circuits=True)
print(dc_backends)
[<IBMBackend('ibm_pittsburgh')>, <IBMBackend('ibm_kingston')>, <IBMBackend('ibm_marrakesh')>, <IBMBackend('ibm_fez')>, <IBMBackend('ibm_boston')>]
Вимірювання в середині схеми
До qiskit-ibm-runtime v0.43.0 measure була єдиною інструкцією вимірювання в Qiskit. Однак вимірювання в середині схеми мають різні вимоги до налаштування порівняно з кінцевими вимірюваннями (вимірюваннями, що відбуваються в кінці схеми). Наприклад, при налаштуванні вимірювання в середині схеми потрібно враховувати тривалість інструкції, оскільки довші інструкції спричиняють більш зашумлені схеми. Не потрібно враховувати тривалість інструкції для кінцевих вимірювань, оскільки після кінцевих вимірювань інструкцій немає.
Інструкція MidCircuitMeasure відображається на інструкцію measure_2, що повідомляється в supported_instructions backend. Однак measure_2 підтримується не на всіх backends. Використовуй service.backends(filters=lambda b: "measure_2" in b.supported_instructions) для пошуку backends, що підтримують її. Нові вимірювання можуть бути додані в майбутньому, але це не гарантовано.
Метод MidCircuitMeasure
У qiskit-ibm-runtime v0.43.0 була введена інструкція MidCircuitMeasure. Як випливає з назви, це нова інструкція вимірювання, оптимізована для вимірювань у середині схеми на IBM® QPU. Хоча можна використовувати QuantumCircuit.measure для вимірювання в середині схеми, через свою конструкцію MidCircuitMeasure зазвичай є кращим вибором. Наприклад, вона додає менше накладних витрат до схеми, ніж при використанні QuantumCircuit.measure.
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime.circuit import MidCircuitMeasure
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)
circ = QuantumCircuit(2, 2)
circ.x(0)
circ.append(MidCircuitMeasure(), [0], [0])
# circ.measure([0], [0])
# circ.measure_all()
print(circ.draw(cregbundle=False))
┌───┐┌────────────┐
q_0: ┤ X ├┤0 ├
└───┘│ │
q_1: ─────┤ Measure_2 ├
│ │
c_0: ═════╡0 ╞
└────────────┘
c_1: ═══════════════════
- Для використання вимірювань повинен бути принаймні один класичний регістр.
- Примітив Sampler вимагає вимірювань схеми. Можна додати вимірювання схеми з примітивом Estimator, але вони ігноруються.
Store
З qiskit-ibm-runtime версії 0.47.0 або пізнішої ти можеш використовувати інструкцію store для збереження результату класичного виразу, якщо цей вираз буде використовуватися неодноразово. Операції автоматично паралелізуються, що робить твій код значно ефективнішим під час виконання.
Для отримання додаткової інформації дивись посібник Класичне зворотне подавання та потік керування.
Коли ти використовуєш store для збереження значення в класичний регістр на реальному backend, це значення зберігається лише в пам'яті під час виконання і не копіюється та не повертається в результаті завдання.
Наприклад, у наступному коді temp має те саме значення, що й creg під час виконання, і if_test працює як очікується. Але після завершення завдання BitArray temp, повернений у результаті завдання, не містить значення creg. Тобто job.result()[0].data.temp дорівнює 0.
creg = ClassicalRegister(3, "c")
temp = ClassicalRegister(3, "temp")
...
qc.store(temp, creg)
with circuit.if_test((temp, 0b001)):
...
Повний приклад
Наступний код створює та запускає динамічну схему на апаратному забезпеченні IBM®.
from qiskit_ibm_runtime import SamplerV2, QiskitRuntimeService
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.transpiler import generate_preset_pass_manager
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)
# Create a dynamic circuit
qubits = QuantumRegister(1)
clbits = ClassicalRegister(1)
qc = QuantumCircuit(qubits, clbits)
(q0,) = qubits
(c0,) = clbits
qc.h(q0)
qc.measure(q0, c0)
with qc.if_test((c0, 1)):
qc.x(q0)
qc.measure(q0, c0)
# Convert to an ISA circuit for the given backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)
# Generate samplers for backend targets
sampler = SamplerV2(backend)
# Submit jobs
sampler_job = sampler.run([isa_circuit])
result = sampler_job.result()
print(
f">>> {' Job ID:':<10} {sampler_job.job_id()} ({sampler_job.status()})"
)
>>> Job ID: d88cakp789is7391vq0g (DONE)
Обмеження Qiskit Runtime
Враховуй такі обмеження при запуску динамічних схем у Qiskit Runtime.
-
Через обмежену фізичну пам'ять керуючої електроніки також є обмеження на кількість тверджень
ifта розмір їхніх операндів. Це обмеження є функцією кількості мовлень та кількості трансльованих бітів у завданні (не у схемі).При обробці умови
ifдані вимірювань потрібно передати до керуючої логіки для здійснення цієї оцінки. Мовлення — це передача унікальних класичних даних, а трансльовані біти — це кількість класичних бітів, що передаються. Розглянемо таке:c0 = ClassicalRegister(3)c1 = ClassicalRegister(5)...with circuit.if_test((c0, 1)) ...with circuit.if_test((c0, 3)) ...with circuit.if_test((c1[2], 1)) ...У попередньому прикладі коду перші два об'єкти
if_testнаc0вважаються одним мовленням, оскільки вмістc0не змінився і тому не потребує повторного мовлення.if_testнаc1є другим мовленням. Перше транслює всі три біти вc0, а друге транслює лише один біт, що в сумі складає чотири трансльованих біти.Наразі, якщо ти транслюєш 60 бітів щоразу, завдання може мати приблизно 300 мовлень. Якщо транслювати лише один біт щоразу, то завдання може мати 2400 мовлень.
-
Операнд, що використовується у твердженні
if_test, має бути 32 або менше бітів. Таким чином, якщо ти порівнюєш весьClassicalRegister, розмір цьогоClassicalRegisterмає бути 32 або менше бітів. Однак якщо порівнюєш лише один біт зClassicalRegister, то цейClassicalRegisterможе бути будь-якого розміру (оскільки операнд — лише один біт).Наприклад, блок коду "Недійсно" не працює, оскільки
crмає більше 32 бітів. Однак можна використовувати класичний регістр ширший за 32 біти, якщо тестується лише один біт, як показано в блоці коду "Дійсно".- Недійсно
- Дійсно
cr = ClassicalRegister(50)qr = QuantumRegister(50)circuit = QuantumCircuit(qr, cr)...circ.measure(qr, cr)with circ.if_test((cr, 15)):...cr = ClassicalRegister(50)qr = QuantumRegister(50)circuit = QuantumCircuit(qr, cr)...circ.measure(qr, cr)with circ.if_test((cr[5], 1)):... -
Вкладені умовні вирази не дозволені. Наприклад, наступний блок коду не працюватиме, оскільки в ньому є
if_testвсередині іншогоif_test:- Недійсно
- Дійсно
c1 = ClassicalRegister(1, "c1")c2 = ClassicalRegister(2, "c2")...with circ.if_test((c1, 1)):with circ.if_test(c2, 1)):...cr = ClassicalRegister(2)...with circuit.if_test((cr, 0b11)):... -
Наявність
resetабо вимірювань всередині умовних виразів не підтримується. -
Арифметичні операції не підтримуються.
-
Дивись таблицю функцій OpenQASM 3 для визначення того, які функції OpenQASM 3 підтримуються на Qiskit та Qiskit Runtime.
-
Коли OpenQASM 3 (замість
QuantumCircuit) використовується як вхідний формат для передачі схем до примітивів Qiskit Runtime, підтримуються лише інструкції, що можуть бути завантажені в Qiskit. Класичні операції, наприклад, не підтримуються, оскільки не можуть бути завантажені в Qiskit. Дивись Імпорт програми OpenQASM 3 у Qiskit для отримання додаткової інформації. -
Інструкції
for,whileтаswitchне підтримуються.
Використання динамічних схем з Estimator
Оскільки Estimator не підтримує динамічні схеми, можна використовувати Sampler та будувати власні схеми вимірювань замість цього.
Щоб відтворити поведінку Estimator, виконай такий процес:
- Групуй терміни всіх спостережуваних у розбиття. Це можна зробити за допомогою
PauliListAPI, наприклад.приміткаМожна використовувати атрибут примітива
BitArrayдля обчислення очікуваних значень наданих спостережуваних. - Виконуй одну схему зміни базису на розбиття (яка зміна базису потрібна для кожного розбиття). Дивись модуль
measurement_basesутиліти доповнення для вимірювань Measurement bases для отримання додаткової інформації. Дивись документацію пакету утилітних доповнень Qiskit. - Додавай результати для кожного розбиття разом.
Обмеження
Переглядай будь-яку таблицю сумісності функцій, щоб зрозуміти обмеження при використанні динамічних схем. Зверни увагу, що сумісність функцій не залежить від примітива.
Наступні кроки
- Дізнайся, як реалізувати точне динамічне роз'єднання за допомогою stretch.
- Переглянь посібник класичного зворотного подавання та потоку керування.
- Використовуй візуалізацію часового розкладу схеми для налагодження та оптимізації динамічних схем.
- Не всі функції сумісні з динамічними схемами. Перевір розділ сумісності функцій для Sampler або Executor для деталей.