Руководство по Лаборатории

Лаборатория даёт вам Python со всеми квантовыми библиотеками прямо в браузере, симуляторы всех видов, двойники настоящих чипов, само настоящее железо и арендованные машины для счёта, который никуда больше не помещается. Это руководство рассказывает, какие задачи здесь решаются и как именно: с кодом, с ценами и с указанием, в каком блокноте что разобрано.

Вход и первые шаги

Войдите на странице входа тем же мессенджером, которым пользуетесь в курсе: откроется чат с ботом, нажмите там «Старт» и вернитесь на страницу. Через полминуты у вас открыта среда с блокнотами. Ставить на свой компьютер ничего не нужно, среда целиком живёт в браузере и говорит по-русски.

Первым делом откройте блокнот 00-start: он за десять минут проводит по среде и показывает главный вызов, с которого начинается любая работа:

import qqlab

lab = qqlab.connect()      # адрес и ключ уже в окружении, аргументы не нужны
lab.backends()             # весь парк: симуляторы, двойники, железо, машины в аренду

Объект lab это единая точка входа. Через него уходят прогоны на симуляторы и железо, через него же доступны классические решатели, фотоника, отжиг и арендованные машины. Полный список вызовов с примерами собран в блокноте 12-sdk-reference.

Как устроено рабочее место

Ваш дом это каталог со своими файлами: блокноты, данные, результаты. Он переживает выход, перезапуск среды и обновления; ночами с него снимается резервная копия. Примеры при первом входе копируются к вам домой, это уже ваши файлы: правьте их как угодно, оригиналы не пострадают, а новые примеры досыпаются при обновлениях, не трогая ваших правок.

Недостающие пакеты ставятся обычным способом прямо из блокнота:

%pip install networkx

Три вещи, которые полезно знать заранее:

Карта примеров

Шестнадцать блокнотов лежат в каталоге examples и устроены как подробные разборы: каждый шаг объяснён до того, как случится. Ходить по ним подряд не обязательно, выбирайте по задаче.

БлокнотО чём
00-startпутеводитель по среде и первый прогон
01-hello-bellпервая запутанная пара и чтение результатов
02-backends-tourэкскурсия по парку: чем симулятор отличается от двойника и железа
03-vqe-vs-dmrgвариационный расчёт против классического эталона на одной задаче
04-photonics-homфотоника: эффект Хонга, Оу и Манделя своими руками
05-qubo-annealingпостановка задачи оптимизации и отжиг
06-photonics-serverфотонные схемы на серверных движках
07-anneal-serverотжиг на серверных решателях с бюджетом
08-noise-and-stateмодели шума и что они делают с состоянием
09-workshop-layoutсквозная задача: расстановка оборудования в цехе от постановки до ответа
10-chip-twinпаспорт настоящего чипа и сборка его двойника
11-maintenance-scheduleвторая сквозная задача: график ремонтов при ограниченных бригадах
12-sdk-referenceсправочник по всем вызовам с примерами
13-heavy-machineодна арендованная машина: когда нужна и сколько стоит
14-heavy-batchпачка работ на арендованных машинах: все виды, отмена, счёт
15-heavy-sessionсессия: машина держится, вариационный цикл идёт шагами

Схемы и симуляторы

Схемы пишутся на привычном Qiskit, среда его уже знает. Небольшую схему считает идеальный симулятор:

from qiskit import QuantumCircuit

qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])

result = lab.simulate(qc, shots=2000)
result.counts                      # {'00': 1004, '11': 996}

Идеальный ответ полезен как ориентир, но настоящие устройства шумят. Модель шума подключается тем же вызовом, и по разнице с идеальным ответом видно, что именно шум делает с вашей схемой:

noisy = lab.simulate(qc, shots=2000, noise={"error_1q": 0.002, "error_2q": 0.02})

Как шум устроен внутри и как читать его следы в результатах, разобрано в блокноте 08-noise-and-state. Что делать, когда кубитов становится больше, чем помещается в среде, рассказано в разделе про арендованные машины.

Двойники чипов и настоящее железо

Список всего, на чём можно считать, живой и запрашивается одной строкой:

for b in lab.backends():
    print(b.address, b.kind, b.num_qubits, "кубит",
          "платно" if b.paid else "бесплатно")

Каждая точка исполнения бывает одного из трёх видов. Симулятор считает идеально. Двойник это эмулятор конкретного настоящего чипа, собранный из его топологии и свежей калибровки: он отвечает на вопрос «что получится именно на этом устройстве», не тратя очередь и деньги. Железо это сам чип: прогон встаёт в очередь производителя, а результат забирается по готовности.

Прогон на выбранной точке выглядит одинаково для всех трёх видов:

result = lab.run(qc, "iqm/emerald::emulator", shots=1000)

Двойника можно собрать и своими руками из паспорта устройства. Паспорт это топология, времена когерентности, ошибки гейтов и считывания, всё с последней калибровки:

props = lab.properties("iqm/emerald")
twin = props.twin()        # обычный симулятор Qiskit с шумом именно этого чипа

Разбор паспорта и сборка двойника показаны в блокноте 10-chip-twin, а экскурсия по всему парку в 02-backends-tour. Прогоны на настоящем железе платные, цена видна в профиле после каждого прогона.

Фотоника

Фотонные вычисления устроены иначе, чем гейтовые: состояние живёт в модах света, а схема собирается из светоделителей и фазовых пластин. В среде стоят профильные библиотеки, а у lab есть фотонное крыло:

ph = lab.photonic

hom = ph.hom(shots=2000)           # эффект Хонга, Оу и Манделя
hom.probabilities                  # два фотона выходят вместе, а не порознь

bs = ph.beamsplitter(0, 1, theta=0.785)
res = ph.sample(modes=2, photons=[1, 1], elements=[bs], shots=1000)

Для задач побольше есть выборка по графу: она лежит в основе задачи о плотном подграфе и разобрана вместе с ней. Начните с 04-photonics-hom, где эффект собирается руками, затем 06-photonics-server про серверные движки и выбор платформы через ph.platforms().

Оптимизация и отжиг

Большой класс практических задач сводится к выбору наилучшей комбинации из конечного числа вариантов: что куда поставить, кого когда назначить, что включить в набор. Такие задачи записываются матрицей QUBO и решаются отжигом:

an = lab.anneal

Q = an.build("max_cut", edges=[(0, 1), (1, 2), (2, 0), (2, 3)])
answer = an.solve(Q["Q"], method="sa", budget=2000)
answer.chosen                      # какие вершины попали в разрез

Сборщик an.build знает типовые постановки и избавляет от ручного вывода матрицы, а решать можно и своим QUBO. Как записать в ту же форму житейскую задачу целиком, со штрафами и проверкой кодирования, показывают два сквозных разбора: 09-workshop-layout про расстановку оборудования в цехе и 11-maintenance-schedule про график ремонтов, где появляются ограничения-неравенства. Основы в 05-qubo-annealing, серверные решатели с бюджетом в 07-anneal-server.

Классические эталоны

Ответ квантового способа ничего не значит, пока его не с чем сравнить. Поэтому рядом с симуляторами стоят классические решатели, и сравнение делается в том же блокноте, без переключения инструментов:

cl = lab.classical

exact = cl.tfim_ground(n_sites=16, h=1.0, method="exact")   # точная диагонализация
dmrg  = cl.tfim_ground(n_sites=64, h=1.0, method="dmrg")    # тензорная сеть
dmrg["energy"]

Образец рабочего процесса: посчитать вариационным алгоритмом, посчитать эталоном, честь по чести положить оба ответа рядом и сделать вывод. Так построен блокнот 03-vqe-vs-dmrg, и так же устроены оба сквозных разбора: в задаче про цех квантовый ответ сверяется с точным переборщиком, и по этой сверке видно, где выигрыш настоящий, а где показалось.

Квантовая химия

В среде стоит полный химический стек: интегралы считает химический пакет, из них строится гамильтониан молекулы, дальше он переводится в кубиты и решается вариационно. Всё от начала до конца, без подставленных чисел:

from openfermion.chem import MolecularData
from openfermion.transforms import get_fermion_operator, jordan_wigner
from openfermionpyscf import run_pyscf

geometry = [("H", (0, 0, 0)), ("H", (0, 0, 0.74))]
molecule = run_pyscf(MolecularData(geometry, "sto-3g", multiplicity=1),
                     run_scf=True, run_fci=True)

molecule.hf_energy       # грубое приближение, с которого начинают
molecule.fci_energy      # точное значение, эталон

qubit_op = jordan_wigner(get_fermion_operator(molecule.get_molecular_hamiltonian()))

Одна точка на четырёх кубитах считается в среде за секунды. Целая кривая диссоциации, где расстояние между атомами пробегает десятки значений, уходит одной командой на арендованные машины, об этом ниже. Вариационный расчёт против эталона разобран в 03-vqe-vs-dmrg.

Коррекция ошибок

Логический кубит собирается из многих физических, и главный вопрос здесь звучит так: начиная с какого уровня физического шума избыточность начинает помогать, а не вредить. Чтобы это увидеть, нужны миллионы запусков, и в среде для этого стоят профильные инструменты:

import stim

circuit = stim.Circuit.generated(
    "surface_code:rotated_memory_z",
    distance=3, rounds=3, after_clifford_depolarization=0.01)
sampler = circuit.compile_detector_sampler()
shots = sampler.sample(10_000)

Декодирование берёт на себя pymatching. Десятки тысяч запусков среда считает сама; миллионы, нужные для порога кода, отправляются на арендованные машины работой qec_shots, пример есть в 14-heavy-batch.

Машины в аренду

Рано или поздно задача перестаёт помещаться: вектор состояния на тридцати кубитах требует шестнадцать гигабайт, кривая из десятков точек считается часами, порогу кода нужны миллионы запусков. Для этого есть арендованные машины: под вашу работу поднимаются машины нужного размера, считают её по частям сразу на нескольких, отдают результат и гасятся. Вы платите за время машин по факту, и короткая работа стоит один токен, потому что столько времени и занимает.

Пачка работ

Форма у всей тяжёлой работы одна: она режется на независимые единицы. Виды работ такие:

РаботаЧто считаетЕдиница
circuit_runодну большую схему, до 31 кубитався схема целиком
qaoa_scanсетку параметров QAOAточка сетки
noise_trajectoriesтраектории схемы под шумомтраектория
sa_restartsрестарты отжига на одной задачерестарт
gbs_samplesвыборки бозонного сэмплерапачка выборок
qec_shotsзапуски кода коррекции с декодированиемпачка запусков
dmrg_groundосновное состояние цепочки вдоль сетки поляточка сетки
molecule_curveэнергию молекулы вдоль межатомного расстоянияточка кривой

Вызов одинаковый для всех, меняются имя и параметры. Вот кривая диссоциации водорода на двадцати четырёх расстояниях:

job = lab.heavy("molecule_curve", units=24,
                params={"molecule": "H2", "r_from": 0.35, "r_to": 2.5, "vqe": True})

job["points"]        # по каждой точке: приближение, эталон и вариационный ответ
job["cost_tokens"]   # сколько списано со счёта, в токенах

Такой прогон занимает пару минут на двух машинах и обходится примерно в пять токенов. Не хочется ждать в блокноте: поставьте работу с wait=False, заберите позже через lab.scan_result(job_id), а передумали, так lab.cancel(job_id) погасит машины и выставит счёт только за потраченное время. Все виды работ с примерами собраны в 14-heavy-batch.

Одна большая схема

Схема, которой не хватает памяти среды, отправляется целиком: под неё подбирается машина с нужной памятью по числу кубитов в самой схеме.

result = lab.simulate_heavy(qc, shots=4096)

Сессия для вариационных циклов

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

with lab.heavy_session(n_qubits=26) as s:
    for params in optimizer:
        counts = s.iterate(circuit_for(params))["counts"]

Время идёт, пока сессия открыта, поэтому её надо закрывать; менеджер контекста делает это сам, а забытая сессия закрывается по простою через четверть часа. Разбор в 15-heavy-session.

Очередь: работа принимается всегда

Если свободных машин нет, постановка не падает: работа встаёт в живую очередь и стартует сама, когда место освободится. В её статусе видно место в очереди, занятость ядер и верхнюю границу ожидания; стояние бесплатно, деньги списываются только со старта машин. Передумали: lab.cancel снимает работу из очереди без единого токена.

Где всё это видно, не заглядывая в код: значок в шапке среды рядом с вашим аватаром. Красный «считается» горит, пока идёт платный счёт, жёлтый «в очереди» висит, пока работа ждёт машин, а если значка нет, ничего не тратится. Подробности в профиле: блок «Сейчас в работе» стоит первым, у каждой работы там виден её номер для lab.scan_result и lab.cancel.

Машины прерываемые, поэтому дешёвые: облако вправе отнять их посреди счёта. Недосчитанная часть пересдаётся сама, за отнятое вы не платите, снаружи это выглядит как «работа идёт дольше обычного».

Арендованные машины видны в общем списке как heavy-par вместе с ценой часа машины и перечнем работ: lab.backends() покажет и это. Отказ случается до денег: работа, которая заведомо не поместится в память или для которой не хватает средств, отклоняется сразу, а не после получаса оплаченного счёта.

Деньги и профиль

Бесплатно всё, из чего состоит повседневная работа: среда, симуляторы, модели шума, двойники чипов, классические решатели, фотоника, отжиг и все примеры. Платных вещей две: прогон на настоящем квантовом железе и счёт на арендованных машинах.

Деньги списываются со счёта по факту: за арендованные машины по времени их жизни от подъёма до гашения, за железо по прейскуранту производителя. Подписки нет, минимального чека нет. Цена каждого прогона видна в профиле сразу после его завершения, строкой с тем, что считалось, сколько времени заняло и во что обошлось. Работа, потерянная по вине площадки, не оплачивается: за отозванную машину часть пересчитывается, а несостоявшийся прогон возвращает залог.

Профиль открывается из среды: меню «Файл → Панель управления Hub», кнопка «Открыть профиль». Там баланс, история прогонов с ценами, движение средств и пополнение.

Какую дорогу выбрать

ЗадачаИнструментГде разобрано
Проверить идею на маленькой схемеlab.simulate01, 08
Узнать, что получится на конкретном чипедвойник: lab.properties(...).twin()10
Запустить на настоящем железеlab.run на бэкенд вида hardware02
Оптимизационная задача из жизниQUBO и отжиг: lab.anneal05, 09, 11
Сравнить квантовый ответ с классикойlab.classical03, 09
Фотонные схемы и выборкиlab.photonic04, 06
Молекула: энергия и кривая связихимический стек, затем molecule_curve03, 14
Порог кода коррекцииstim в среде, затем qec_shots14
Схема больше 25 кубитовlab.simulate_heavy13
Сетка параметров, траектории, рестартыlab.heavy14
Вариационный цикл на большой схемеlab.heavy_session15

Если что-то пошло не так

Лаборатория это часть проекта Учи Кванты!. Руководство обновляется вместе с самой Лабораторией.