Основы Cirq

Стереотипные программисты обычно не любят мышь, поэтому и для программирования квантовых компьютеров есть не только drag-n-drop интерфейс построения схем, но и специализированные языки программирования (Quipper, Silq, Q# и т.д.), и библиотеки для языков программирования общего назначения (Qiskit, PennyLane, Strawberry Fields).

В нашем курсе мы будем пользоваться библиотекой Cirq от Google для языка программирования Python.

Установка и запуск

Библиотека требует Python версии 3.7 и выше. Установите его для своей ОС: Linux, Mac OS X, Windows.

Желательно использовать виртуальное окружение, чтобы не засорять глобальный набор пакетов.

Установите cirq при помощи pip:

python -m pip install cirq

Проверить, что всё работает, можно при помощи следующей команды:

python -c 'import cirq_google; print(cirq_google.Sycamore)'

Первая программа

Для описания схем нужны кубиты и гейты, которые выполняют над кубитами операции.

import cirq

# Создаём кубит с именем q
qubit = cirq.NamedQubit('q')

# Схема применяет гейт Адамара и измеряет результат в m
circuit = cirq.Circuit(cirq.H(qubit), cirq.measure(qubit, key='m'))
print("Circuit:")
print(circuit)

# Эмулируем работу схемы несколько раз
simulator = cirq.Simulator()
result = simulator.run(circuit, repetitions=20)
print("Results:")
print(result)

Запуск и моделирование

Библиотека «заточена» под работу на реальных квантовых устройствах, поэтому результаты запуска будут возвращать те значения, которые выдал бы идеальный квантовый компьютер (работающий без шумов и ошибок). Функции, в названии которых есть run, обычно имеют именно такое поведение. В этом случае легко тестировать программы, используя классический компьютер, а затем запуская для работы уже на квантовом компьютере (доступном, например, в облаке).

Также доступна и моделирование работы компьютера, которое вычисляет вектор состояния. В названии функций для моделирования обычно есть слово simulate.

Запуск схемы вы уже видели в прошлом разделе, поэтому посмотрим на код для моделирования создания состояния Белла \(1/\sqrt{2} * (|00\rangle + |11\rangle)\):

import cirq

bell_circuit = cirq.Circuit()
q0, q1 = cirq.LineQubit.range(2)
bell_circuit.append(cirq.H(q0))
bell_circuit.append(cirq.CNOT(q0, q1))

print('Circuit:')
print(bell_circuit)

# Initialize Simulator
s = cirq.Simulator()

print('Simulate the circuit:')
results = s.simulate(bell_circuit)
print(results)

Кубиты и гейты, устройства и моменты

Кубиты

# Для отдельных кубитов можно задать имена. Это полезно, если ваш алгоритм
# абстрактный или не оптимизирован под конкретную реализацию квантового
# компьютера (где могут быть ограничения на кубиты, к которым применяются
# операции)

q0 = cirq.NamedQubit('source')
q1 = cirq.NamedQubit('target')

print(q0,q1)

# Можно создать кубиты в цепочке, задав для каждого номер или интервал
q3 = cirq.LineQubit(3)

# здесь создаются кубиты LineQubit(0), LineQubit(1), LineQubit(2)
q0, q1, q2 = cirq.LineQubit.range(3)

# Можно создать кубиты в сетке, по отдельности
q4_5 = cirq.GridQubit(4, 5)

# или все сразу. Код создаёт 16 кубитов от (0,0) до (3,3)
qubits = cirq.GridQubit.square(4)

Устройства

В библиотеке есть определения имеющихся квантовых устройств, например, компьютера Sycamore от Google. Линии на схеме задают пары кубитов, между которыми возможны двухкубитовые операции.

import cirq_google
print(cirq_google.Sycamore)

Гейты

Для большинства «стандартных» гейтов в библиотеке есть соответствующие объекты, например, cirq.H для гейта Адамара. Гейт, применённый к каким-либо кубитам, в cirq называется операцией (например, cirq.H(q0) — это гейт Адамара, применённый к кубиту q0).

Схемы задаются при помощи класса Circuit, к которому можно добавлять гейты, используя метод append:

circuit = cirq.Circuit()
qubits = cirq.LineQubit.range(3)
circuit.append(cirq.H(qubits[0]))
circuit.append(cirq.H(qubits[1]))
circuit.append(cirq.H(qubits[2]))
print(circuit)

В append можно передавать операции по отдельности или итерируемые объекты с операциями:

circuit2 = cirq.Circuit()
ops = [cirq.H(q) for q in cirq.LineQubit.range(3)]
circuit2.append(ops)
print(circuit2)

Моменты

Схемы состоят из моментов Moment — наборов операций, которые можно выполнять параллельно. Обычно cirq пытается использовать самый ранний момент для применения операции.

При этом если кубит уже использовался в более ранней операции, то в схеме создаётся новый момент.

print(cirq.Circuit(cirq.SWAP(q, q + 1) for q in cirq.LineQubit.range(3)))