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

Утиліти Qiskit addon

Package versions

The code on this page was developed using the following requirements. We recommend using these versions or newer.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
qiskit-addon-utils~=0.3.0
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-addon-utils qiskit-ibm-runtime

Пакет утиліт Qiskit addon — це набір функцій для підтримки робочих процесів, що включають один або кілька аддонів Qiskit. Наприклад, цей пакет містить функції для створення гамільтоніанів, генерації схем часової еволюції Троттера, а також для розрізання й об'єднання квантових схем.

Встановлення

Є два способи встановити утиліти Qiskit addon: через PyPI або зібравши зі вихідного коду. Рекомендується встановлювати ці пакети у віртуальному середовищі, щоб уникнути конфліктів залежностей.

Встановлення через PyPI

Найпростіший спосіб встановити пакет утиліт Qiskit addon — через PyPI.

pip install 'qiskit-addon-utils'

Встановлення зі вихідного коду

Натисни тут, щоб дізнатися, як встановити цей пакет вручну.

Якщо ти хочеш зробити внесок у цей пакет або встановити його вручну, спочатку склонуй репозиторій:

git clone git@github.com:Qiskit/qiskit-addon-utils.git

і встанови пакет через pip. Якщо плануєш запускати туторіали з репозиторію пакета, також встанови залежності для ноутбуків. Якщо плануєш розробляти в репозиторії — встанови залежності dev.

pip install tox jupyterlab -e '.[notebook-dependencies,dev]'

Починаємо роботу з утилітами

Пакет qiskit-addon-utils містить кілька модулів: для генерації задач при симуляції квантових систем, розфарбовування графів для ефективнішого розміщення вентилів у квантовій схемі, а також розрізання схем, що може допомогти з оберненим розповсюдженням операторів. Наступні розділи описують кожен модуль. Корисну інформацію також можна знайти в документації API пакета.

Генерація задач

Вміст модуля qiskit_addon_utils.problem_generators включає:

  • Функцію generate_xyz_hamiltonian(), яка генерує представлення SparsePauliOp XYZ-моделі Ізінга з урахуванням топології зв'язності:

H=(j,k)E(JxXjXk+JyYjYk+JzZjZk)+jV(hxXj+hyYj+hzZj)H = \sum_{(j,k)\in E} \left(J_x X_jX_k + J_yY_jY_k + J_zZ_jZ_k\right) + \sum_{j\in V} \left(h_x X_j + h_y Y_j + h_z Z_j\right)

  • Функцію generate_time_evolution_circuit(), яка будує схему, що моделює часову еволюцію заданого оператора.
  • Три об'єкти PauliOrderStrategy для перебору різних упорядкувань рядків Паулі. Це особливо корисно разом із розфарбовуванням графів і може використовуватися як аргументи в обох функціях — generate_xyz_hamiltonian() і generate_time_evolution_circuit().

Розфарбовування графів

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

Для прикладу: функція auto_color_edges() генерує розфарбовування ребер для наївної схеми, що виконує CZGate вздовж кожного з'єднання кубітів. Наведений нижче фрагмент коду використовує карту зв'язності бекенду FakeSherbrooke, будує цю наївну схему, а потім застосовує функцію auto_color_edges() для створення еквівалентної, але ефективнішої схеми.

from qiskit_ibm_runtime.fake_provider import FakeSherbrooke
from qiskit import QuantumCircuit
from qiskit_addon_utils.coloring import auto_color_edges
from qiskit_addon_utils.slicing import combine_slices, slice_by_depth
from collections import defaultdict

backend = FakeSherbrooke()
coupling_map = backend.coupling_map

# Create naive circuit
circuit = QuantumCircuit(backend.num_qubits)
for edge in coupling_map.graph.edge_list():
circuit.cz(edge[0], edge[1])

# Color the edges of the coupling map
coloring = auto_color_edges(coupling_map)
circuit_with_coloring = QuantumCircuit(backend.num_qubits)

# Make a reverse coloring dict in order to make the circuit
color_to_edge = defaultdict(list)
for edge, color in coloring.items():
color_to_edge[color].append(edge)

# Place edges in order of color
for edges in color_to_edge.values():
for edge in edges:
circuit_with_coloring.cz(edge[0], edge[1])

print(f"The circuit without using edge coloring has depth: {circuit.depth()}")
print(
f"The circuit using edge coloring has depth: {circuit_with_coloring.depth()}"
)
The circuit without using edge coloring has depth: 37
The circuit using edge coloring has depth: 3

Розрізання

Нарешті, модуль qiskit-addon-utils.slicing містить функції та проходи транспілятора для роботи зі "зрізами" схеми — часовими розбиттями QuantumCircuit, що охоплюють усі кубіти. Ці зрізи переважно використовуються для оберненого розповсюдження операторів. Схему можна розрізати чотирма основними способами: за типом вентиля, глибиною, розфарбовуванням або інструкціями Barrier. Ці функції повертають список об'єктів QuantumCircuit. Розрізані схеми можна знову об'єднати за допомогою функції combine_slices(). Більше інформації — в API reference модуля.

Нижче наведено кілька прикладів того, як створювати зрізи для такої схеми:

import numpy as np
from qiskit import QuantumCircuit

num_qubits = 9
qc = QuantumCircuit(num_qubits)
qc.ry(np.pi / 4, range(num_qubits))
qubits_1 = [i for i in range(num_qubits) if i % 2 == 0]
qubits_2 = [i for i in range(num_qubits) if i % 2 == 1]
qc.cx(qubits_1[:-1], qubits_2)
qc.cx(qubits_2, qubits_1[1:])
qc.cx(qubits_1[-1], qubits_1[0])
qc.rx(np.pi / 4, range(num_qubits))
qc.rz(np.pi / 4, range(num_qubits))
qc.draw("mpl", scale=0.6)

Output of the previous code cell

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

# Slice circuit into partitions of depth 1
slices = slice_by_depth(qc, 1)

# Recombine slices in order to visualize the partitions together
combined_slices = combine_slices(slices, include_barriers=True)
combined_slices.draw("mpl", scale=0.6)

Output of the previous code cell

У випадках, коли виконуються схеми Троттера для моделювання динаміки квантової системи, може бути вигідно розрізати за типом вентиля.

from qiskit_addon_utils.slicing import slice_by_gate_types

slices = slice_by_gate_types(qc)

# Recombine slices in order to visualize the partitions together
combined_slices = combine_slices(slices, include_barriers=True)
combined_slices.draw("mpl", scale=0.6)

Output of the previous code cell

Якщо твій робочий процес розроблений з урахуванням фізичної топології зв'язності QPU, на якому він виконуватиметься, можна створювати зрізи на основі розфарбовування ребер. Фрагмент коду нижче призначає трьохколірне розфарбовування ребрам схеми і розрізає схему відповідно до цього розфарбовування. (Примітка: це стосується лише нелокальних вентилів. Однокубітні вентилі розрізаються за типом вентиля).

from qiskit_addon_utils.slicing import slice_by_coloring

# Assign a color to each set of connected qubits
coloring = {}
for i in range(num_qubits - 1):
coloring[(i, i + 1)] = i % 3
coloring[(num_qubits - 1, 0)] = 2

# Create a circuit with operations added in order of color
qc = QuantumCircuit(num_qubits)
qc.ry(np.pi / 4, range(num_qubits))
edges = [
edge for color in range(3) for edge in coloring if coloring[edge] == color
]
for edge in edges:
qc.cx(edge[0], edge[1])
qc.rx(np.pi / 4, range(num_qubits))
qc.rz(np.pi / 4, range(num_qubits))

# Create slices by edge color
slices = slice_by_coloring(qc, coloring=coloring)

# Recombine slices in order to visualize the partitions together
combined_slices = combine_slices(slices, include_barriers=True)
combined_slices.draw("mpl", scale=0.6)

Output of the previous code cell

Якщо у тебе є власна стратегія розрізання, можна розмістити бар'єри в схемі для позначення місць розрізання й використати функцію slice_by_barriers.

qc = QuantumCircuit(num_qubits)
qc.ry(np.pi / 4, range(num_qubits))
qc.barrier()
qubits_1 = [i for i in range(num_qubits) if i % 2 == 0]
qubits_2 = [i for i in range(num_qubits) if i % 2 == 1]
qc.cx(qubits_1[:-1], qubits_2)
qc.cx(qubits_2, qubits_1[1:])
qc.cx(qubits_1[-1], qubits_1[0])
qc.barrier()
qc.rx(np.pi / 4, range(num_qubits))
qc.rz(np.pi / 4, range(num_qubits))
qc.draw("mpl", scale=0.6)

Output of the previous code cell

Після встановлення бар'єрів можна розглядати кожен зріз окремо.

from qiskit_addon_utils.slicing import slice_by_barriers

slices = slice_by_barriers(qc)
slices[0].draw("mpl", scale=0.6)

Output of the previous code cell

slices[1].draw("mpl", scale=0.6)

Output of the previous code cell

slices[2].draw("mpl", scale=0.6)

Output of the previous code cell

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

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