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

Пом'якшення помилок за допомогою функції IBM Circuit

Примітка

Функції Qiskit Functions є експериментальною можливістю, доступною лише для користувачів планів IBM Quantum® Premium, Flex та On-Prem (через API IBM Quantum Platform). Вони мають статус попереднього випуску та можуть змінюватися.

Приблизний час виконання: 26 хвилин на процесорі Eagle (ПРИМІТКА: Це лише оцінка. Ваш час виконання може відрізнятися.) У цьому посібнику розглядається приклад побудови та запуску робочого процесу з використанням функції IBM Circuit. Ця функція приймає на вхід Primitive Unified Blocs (PUB) і повертає очікувані значення з пом'якшенням помилок. Вона забезпечує автоматизований та налаштований конвеєр для оптимізації схем і виконання на квантовому обладнанні, щоб дослідники могли зосередитися на розробці алгоритмів та застосувань.

Відвідайте документацію для ознайомлення зі вступом до Qiskit Functions та дізнайтеся, як розпочати роботу з функцією IBM Circuit.

Передумови

У цьому посібнику розглядається загальна апаратно-ефективна тротеризована схема часової еволюції для двовимірної моделі Ізінга з поперечним полем, а також обчислюється глобальна намагніченість. Така схема корисна в різних прикладних галузях, таких як фізика конденсованих середовищ, хімія та машинне навчання. Для отримання додаткової інформації про структуру цієї моделі зверніться до Nature 618, 500–505 (2023).

Функція IBM Circuit поєднує можливості сервісу транспіляції Qiskit та Qiskit Runtime Estimator, надаючи спрощений інтерфейс для запуску схем. Функція виконує транспіляцію, придушення помилок, пом'якшення помилок та виконання схем в рамках єдиного керованого сервісу, щоб ми могли зосередитися на відображенні задачі на схеми, а не на побудові кожного кроку шаблону самостійно.

Вимоги

Перед початком роботи з цим посібником переконайся, що у тебе встановлено наступне:

  • Qiskit SDK v1.2 або новіший (pip install qiskit)
  • Qiskit Runtime v0.28 або новіший (pip install qiskit-ibm-runtime)
  • Клієнт IBM Qiskit Functions Catalog v0.0.0 або новіший (pip install qiskit-ibm-catalog)
  • Qiskit Aer v0.15.0 або новіший (pip install qiskit-aer)

Налаштування

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-catalog qiskit-ibm-runtime rustworkx
import rustworkx
from collections import defaultdict
from numpy import pi, mean

from qiskit_ibm_runtime import QiskitRuntimeService

from qiskit_ibm_catalog import QiskitFunctionsCatalog

from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.quantum_info import SparsePauliOp

Крок 1: Відображення класичних вхідних даних на квантову задачу

  • Вхід: Параметри для створення квантової схеми
  • Вихід: Абстрактна схема та спостережувані величини

Побудова схеми

Схема, яку ми створимо, є апаратно-ефективною тротеризованою схемою часової еволюції для двовимірної моделі Ізінга з поперечним полем. Ми починаємо з вибору бекенду. Властивості цього бекенду (а саме його карта зв'язків) будуть використані для визначення квантової задачі та забезпечення її апаратної ефективності.

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)

Далі ми отримуємо карту зв'язків з бекенду.

coupling_graph = backend.coupling_map.graph.to_undirected(multigraph=False)
layer_couplings = defaultdict(list)

Ми маємо бути уважними при проєктуванні шарів нашої схеми. Ми зробимо це шляхом розфарбовування ребер карти зв'язків (тобто групування неперетинних ребер) і використаємо це розфарбовування для більш ефективного розміщення вентилів у схемі. Це призведе до меншої глибини схеми з шарами вентилів, які можуть виконуватися одночасно на обладнанні.

edge_coloring = rustworkx.graph_bipartite_edge_color(coupling_graph)

for edge_idx, color in edge_coloring.items():
layer_couplings[color].append(
coupling_graph.get_edge_endpoints_by_index(edge_idx)
)
layer_couplings = [
sorted(layer_couplings[i]) for i in sorted(layer_couplings.keys())
]

Далі ми напишемо просту допоміжну функцію, яка реалізує апаратно-ефективну тротеризовану схему часової еволюції для двовимірної моделі Ізінга з поперечним полем, використовуючи отримане вище розфарбовування ребер.

def construct_trotter_circuit(
num_qubits: int,
num_trotter_steps: int,
layer_couplings: list,
barrier: bool = True,
) -> QuantumCircuit:
theta, phi = Parameter("theta"), Parameter("phi")
circuit = QuantumCircuit(num_qubits)

for _ in range(num_trotter_steps):
circuit.rx(theta, range(num_qubits))
for layer in layer_couplings:
for edge in layer:
if edge[0] < num_qubits and edge[1] < num_qubits:
circuit.rzz(phi, edge[0], edge[1])
if barrier:
circuit.barrier()

return circuit

Ми виберемо кількість кубітів та кроків Троттера, а потім побудуємо схему.

num_qubits = 100
num_trotter_steps = 2

circuit = construct_trotter_circuit(
num_qubits, num_trotter_steps, layer_couplings
)
circuit.draw("mpl", fold=-1)

Результат виконання попередньої комірки коду

Для оцінки якості виконання нам потрібно порівняти результат з ідеальним. Обрана схема виходить за межі можливостей класичного моделювання методом повного перебору. Тому ми фіксуємо параметри всіх вентилів Rx у схемі на 00, а всіх вентилів Rzz на π\pi. Це робить схему кліфордовою, що дозволяє виконати ідеальне моделювання та отримати ідеальний результат для порівняння. У цьому випадку ми знаємо, що результат буде 1.0.

parameters = [0, pi]

Побудова спостережуваної величини

Спочатку обчислимо глобальну намагніченість вздовж z^\hat{z} для NN-кубітної задачі: Mz=i=1NZi/NM_z = \sum_{i=1}^N \langle Z_i \rangle / N. Для цього потрібно спочатку обчислити намагніченість окремого вузла Zi\langle Z_i \rangle для кожного кубіта ii, що визначено в наступному коді.

observables = []
for i in range(num_qubits):
obs = "I" * (i) + "Z" + "I" * (num_qubits - i - 1)
observables.append(SparsePauliOp(obs))

print(observables[0])
SparsePauliOp(['ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],
coeffs=[1.+0.j])

Кроки 2 та 3: Оптимізація задачі для виконання на квантовому обладнанні та запуск за допомогою функції IBM Circuit

  • Вхід: Абстрактна схема та спостережувані величини
  • Вихід: Очікувані значення з пом'якшенням помилок

Тепер ми можемо передати абстрактну схему та спостережувані величини функції IBM Circuit. Вона виконає транспіляцію та запуск на квантовому обладнанні за нас і поверне очікувані значення з пом'якшенням помилок. Спочатку ми завантажимо функцію з каталогу IBM Qiskit Functions.

catalog = QiskitFunctionsCatalog(
token="<YOUR_API_KEY>"
) # Use the 44-character API_KEY you created and saved from the IBM Quantum Platform Home dashboard
function = catalog.load("ibm/circuit-function")

Функція IBM Circuit приймає pubs, backend_name, а також додаткові вхідні параметри для налаштування транспіляції, пом'якшення помилок тощо. Ми створюємо pub з абстрактної схеми, спостережуваних величин та параметрів схеми. Назва бекенду повинна бути вказана як рядок.

pubs = [(circuit, observables, parameters)]
backend_name = backend.name

Ми також можемо налаштувати options для транспіляції, придушення помилок та пом'якшення помилок. Якщо ми не бажаємо вказувати їх, будуть використані налаштування за замовчуванням. Функція IBM Circuit постачається з часто використовуваними параметрами: optimization_level, який контролює ступінь оптимізації схеми, та mitigation_level, який визначає ступінь придушення та пом'якшення помилок. Зверніть увагу, що mitigation_level функції IBM Circuit відрізняється від resilience_level, що використовується в Qiskit Runtime Estimator. Для детального опису цих часто використовуваних параметрів, а також інших розширених параметрів, відвідайте документацію функції IBM Circuit.

У цьому посібнику ми встановимо default_precision, optimization_level: 3 та mitigation_level: 3, що увімкне твірлінг вентилів та екстраполяцію нульового шуму (ZNE) через імовірнісне підсилення помилок (PEA) поверх налаштувань рівня 1 за замовчуванням.

options = {
"default_precision": 0.011,
"optimization_level": 3,
"mitigation_level": 3,
}

З визначеними вхідними даними ми надсилаємо завдання функції IBM Circuit для оптимізації та виконання.

job = function.run(backend_name=backend_name, pubs=pubs, options=options)

Крок 4: Постобробка та повернення результату в бажаному класичному форматі

  • Вхід: Результати від функції IBM Circuit
  • Вихід: Глобальна намагніченість

Обчислення глобальної намагніченості

Результат виконання функції має такий самий формат, як і Estimator.

result = job.result()[0]

Ми отримуємо очікувані значення з пом'якшенням та без пом'якшення помилок з цього результату. Ці очікувані значення представляють намагніченість окремого вузла вздовж напрямку z^\hat{z}. Ми усереднюємо їх для отримання глобальної намагніченості та порівнюємо з ідеальним значенням 1.0 для даного екземпляра задачі.

mitigated_expvals = result.data.evs
magnetization_mitigated = mean(mitigated_expvals)

print("mitigated:", magnetization_mitigated)

unmitigated_expvals = [
result.data.evs_extrapolated[i][0][1] for i in range(num_qubits)
]
magnetization_unmitigated = mean(unmitigated_expvals)

print("unmitigated:", magnetization_unmitigated)
mitigated: 0.9749883476088692
unmitigated: 0.7832977198447583

Опитування щодо посібника

Будь ласка, пройди це коротке опитування, щоб надати відгук про цей посібник. Твої думки допоможуть нам покращити наш контент та досвід користувачів.

Посилання на опитування