Привет! Сегодня, в первый день нового учебного года мы будем решать интересную задачку про Винтика и Шпунтика, которую не так давно запостил vvvphoenix. Да решать не на бумажке, не на калькуляторе, и даже не на питоне, а на новейшем облачном фотонном квантовом компьютере!
Задача
В оригинальном посте все началось с олимпиадной задачки для 7-8 классов:
Незнайка записывает 10-значное десятичное число, оставляя пропуск вместо одной из цифр. Он предлагает Винтику заполнить пропуск любой цифрой, а затем показать полученное 10-значное число Шпунтику. Как могут Винтик и Шпунтик договориться, чтобы Шпунтик угадал, на каком именно месте стоял пропуск?
Если вы не видели задачу раньше, подумайте немного над ее решением, оно не очень сложное.
Ключ к решению — чексумма: Винтик заполняет пропуск такой цифрой, чтобы чексумма 10-значного числа совпадала с номером пропущенного разряда.
Чексумму можно выбрать любую, например, посчитать сумму всех цифр и взять ее последнюю цифру. Скажем, если Незнайка загадал 12345_7890, то Винтик заполняет его цифрой 7. Шпунтик считает сумму всех цифр: 1+2+3+4+5+7+7+8+9 = 46. Последняя цифра суммы — 6, значит пропуск стоял в шестом разряде.
Очевидно, что Винтик и Шпунтик могут договориться и использовать любую чексумму — а значит, у задачи есть больше одного решения. И тут vvvphoenix задается по-настоящему интересным вопросом: а сколько же всего существует решений? Иными словами, сколько существует взаимооднозначных соответствий между 10^10 строками с пропуском, которые придумывает Незнайка, и 10^10 десятизначными числами, которые записывает Винтик?
Вообще 10^10 — это немножко дофига. К счастью, смысл задачи не меняется для N-значных чисел в N-значной системе счисления: например, для N=2 Незнайка придумывает двухначное число, в котором один из разрядов — 0 или 1, а на месте второго стоит пропуск. Теперь Винтику и Шпунтику нужно найти отображение множества {0..., 1..., ...0, ...1} на {00, 01, 10, 11}. Нюанс в том, что не все варианты доступны: "0_" не может соответствовать "11", потому что первые разряды не совпадают. Давайте нарисуем возможные варианты в виде таблицы, где 1 — разрешенные соответствия, а 0 — запрещенные:
Несложно заметить, что у этой задачи ровно два решения:
Для N=3 таблица вырастает до N^N x N^N = 27x27 и выглядит так:
Картинка из телеграма автора задачи
Таблицы — это здорово: глядя на них, легко заметить что ответ на задачу — это количество способов расставить небьющих друг друга ладей на разрешенные клетки. Любой математик, услышав про ладей, сразу же даст абсолютно точный, но совершенно бесполезный ответ: количество расстановок равно перманенту матрицы с картинки выше. К этому же ответу можно прийти и через теорию графов.
Перманент — это буквально задачка про ладей, заплывших в мир матриц. Считается он так: берем набор небьющих друг друга ладей, перемножаем числа под ними, повторяем для всех возможных наборов ладей, и, наконец, суммируем все получившиеся произведения. Этим перманент очень похож на детерминант, в котором все минусы заменены на плюсы:
На этом сходства заканчиваются. В отличие от детерминанта, вычисление перманента имеет экспоненциальную сложность, и быстрого алгоритма для него не существует. Возвращаясь к задаче про Винтика и Шпунтика, для случая N=2 (матрица 4х4) перманент считается на бумажке и равен 2, расчеты для N=3 (матрица 27х27) на питоне занимают около часа и дают 10 752, а дальше вычисления становятся неприлично долгими. Случай N=10 так и вообще остается в области фантастики.
А еще у перманента не очень много практических применений, поэтому я не удивлюсь, если вы услышали о нем впервые. Мне он тоже попался на глаза совсем недавно. И совсем по другой причине.
Boson sampling
Задача о бозонном сэмплинге появилась почти пятнадцать лет назад, но прогремела заметно позже. Именно на ее разновидностях сначала Google, а потом и группа профессора Пэна в Китае продемонстрировали превосходство квантового компьютера над классическим. Бозонный сэмплинг — задача довольно синтетическая: для нее не существует эффективных классических алгоритмов, при этом она идеально подходит для реализации на квантовых компьютерах. А теперь пристегните ремни, потому что звучит она еще более необычно:
У нас есть n волноводов для света (например, оптических волокон). Некоторые из волноводов попарно пересекаются на сплиттерах: на каждом сплиттере свет из каждого волновода делится на две части, половина остается в том же волноводе, половина уходит в другой. Расположение сплиттеров известно. Мы выбираем m из n волноводов и запускаем на вход каждого из них ровно по одному фотону. Какова вероятность того, что на выходе каждого из этих m волноводов все еще останется по одному фотону?
Волноводы на фотонном чипе. Credit: PhotonQ
Вопрос из зала: эээ… и это все еще имеет отношение к квантовому превосходству?
И еще какое! Секрет в том, что одиночные фотоны — это квантовые объекты: проходя через сплиттер, фотон не выбирает один выход, а остается в обоих, прямо как полуживой-полумертвый кот сами-знаете кого. А еще фотоны интерферируют между собой, добавляя щепотку квантовой запутанности в эту и без того запутанную задачу.
Вопрос из зала: Так мы же знаем расположение сплиттеров? Вычисление должно быть элементарным, разве нет?
Давайте разбираться. Вот, например, мы послали на первые два волновода по фотону и хотим увидеть на выходе один фотон во втором волноводе, а один — в третьем. Какова вероятность такого события?
Ну понятно, тут два (на самом деле 2!) варианта: либо первый фотон пойдет во второй волновод, а второй — в третий, либо наоборот. Можно записать это как произведение вероятностей, сумма которых подозрительно напоминает перманент матрицы 2х2:
А если фотонов три? Тогда у нас 3! = 6 вариантов:
и идеальное совпадение с перманентом матрицы 3х3. Именно этот перманент и делает бозонный сэмплинг экспоненциально сложным для классических алгоритмов.
Linear optics quantum computing
Разумеется, необычная формулировка задачи про бозонный сэмплинг появилась не на пустом месте. Все железо в ней — фотонный чип с волноводами и сплиттерами, источники одиночных фотонов и их детекторы — это части одной большой парадигмы квантовых вычислений на линейной оптике. Удивительно, но такого простого (да нифига) набора оптики с лихвой хватает и для реализации основных квантовых гейтов, и для гораздо более интересных приемов.
Впрочем, в 2019 году Google демонстрировала квантовое превосходство на сверхпроводниковых кубитах. На тот момент это была единственная масштабируемая платформа для квантовых компьютеров. Зато уже через год научная группа Цзянвей Пэна в Китае запустила бозонный сэмплинг на фотонном компьютере, да каком — вместо фотонного чипа там была настоящая стеклянная оптика, занимавшая целый стол!
Фотонный компьютер Jiuzhang собственной персоной. Credit: University of Science and Technology of China
Вскоре после этого фотонные квантовые компьютеры уверенно ворвались на рынок. Сейчас в мире даже есть два сервера облачных фотонных вычислений, и если канадская Xanadu ориентирована только на корпоративных клиентов, то французская Quandela дает всем желающим возможность бесплатно прикоснуться к фотонным вычислениям. Черт, вы только представьте: 2010-й год, Ааронсон и Архипов — авторы идеи бозонного сэмплинга — выглядят буквально как персонаж мема:
а сегодня кто угодно может запустить их идею в несколько строчек на питоне. Ну что, попробуем и мы?
Дорога в облака
После регистрации на cloud.quandela.com мы попадаем на главную страницу, которая встречает нас статусом доступных платформ. Среди них несколько симуляторов и квантовый процессор (QPU) под названием Altair:
Сердце Altair — это универсальный программируемый фотонный чип (universal interferometer). Специальный источник (SPS) генерирует поток одиночных фотонов, который разводится демультиплексором на заданные входы в чипе. На выходе чипа стоят сверхпроводящие однофотонные детекторы (SNSPD), которые измеряют распределение фотонов после прохождения чипа.
Отсюда. Картинке больше года, с тех пор чип немного вырос.
В 20-модовый чип Altair (это значит, что в нем 20 волноводов) можно запустить до 10 фотонов. Это очень условно соответствует 10+ кубитам; условно — потому что фотонные компьютеры кодируют информацию более эффективно, и 10 кубитов — это оценка снизу. На странице QPU можно найти полную схему чипа, она выглядит примерно так:
и содержит несколько сотен сплиттеров и фазовращателей. Сплиттеры фиксированы, программируется чип именно фазовращателями, которые меняют фазу проходящего через них света, влияя на интерференцию фотонов в разных модах.
Теперь давайте разберемся с тем, как все это запустить.
Квантовый Hello, world!
Для работы с облаком нужно сгенерировать токен и установить фреймворк под названием Perceval (pip install perceval-quandela
). В Perceval нас интересует несколько сущностей.
Processor
Первым делом мы инициализируем квантовый процессор или его симулятор. Если нас интересует процессор в облаке, то мы инициализируем класс RemoteProcessor
именем процессора с Quandela Cloud и токеном:
import perceval as pcvl
proc = pcvl.RemoteProcessor("qpu:altair", token) # QPU Altair
proc = pcvl.RemoteProcessor("sim:altair", token) # симулятор Altair на GPU
Если же мы не хотим в облако, то можно запустить симулятор на локальной машине, указав архитектуру процессора:
proc = pcvl.Processor("CliffordClifford2017")
На симуляторе можно запускать любое число задач, а для работы на настоящем QPU понадобятся кредиты. Юзеру дается 200 бесплатных кредитов каждый месяц.
Circuit
Следующим шагом мы создаем схему, которую хотим запрограммировать в фотонный чип. Она инициализируется количеством мод, которые мы хотим использовать:
c = pcvl.Circuit(2)
pcvl.pdisplay(c)
Последняя строчка рисует схему: сейчас в ней два волновода, которые идут от входа к выходу без каких-либо пересечений:
Давайте добавим в схему два сплиттера с фазовращателем — это называется интерферометр Маха-Цендера:
phase = 0.5*np.pi
c.add(0, pcvl.BS())
c.add(0, pcvl.PS(phi=phase))
c.add(0, pcvl.BS())
pcvl.pdisplay(c)
Осталось записать эту схему в чип:
proc.set_circuit(c)
Source
Теперь мы должны прописать входы чипа, на которые мы подаем одиночные фотоны. Это делается при помощи класса BasicState
. Мы подадим один фотон в первую моду, а вторую оставим пустой:
input_state = pcvl.BasicState([1,0])
proc.with_input(input_state)
Sampler
Остается запустить вычисления, а потом повторить их несколько тысяч раз. Зачем? Все потому, что любые квантовые вычисления на любых платформах — вероятностые: после открывании коробки любой кот окажется либо живым, либо мертвым. Каким он был до открывания — квантовым, немножко квантовым, обычным дворовым — черт его знает. Чтобы узнать это, придется приготовить кота:
открыть коробку, записать результат, а потом повторить эксперимент еще пару тысяч раз. Если в половине случаев кот остался живым, то наш рецепт готовил идеального полуживого-полумертвого кота Шредингера. Если живыми остались 90% котов, то и кот из рецепта был скорее жив, чем мертв. Именно так и никак иначе мы и набираем итоговую статистику. В любых квантовых вычислениях мы измеряем вероятность тех или иных исходов, запуская один и тот же алгоритм много раз и считая количество результатов. Собственно, это и называется сэмплингом.
А так как квантовое измерение — процесс, подобный подбрасыванию монетки, то он подвержен дробовому шуму. Из-за него квантовые алгоритмы в принципе не могут дать нам точный результат. Цель квантовых вычислений — это дать быструю эффективную оценку, а не точность в несколько знаков после запятой. Поэтому отклонение от точного результата в десятки процентов, а то и несколько раз — это совершенно нормально.
Для запуска сэмплинга в Perceval используется класс Sampler
, который инициализируется процессором с прописанной схемой и максимальным количеством шотов (shots):
sampler = Sampler(proc, max_shots_per_call=1000)
Здесь max_shots_per_call
— это количество повторений, в которых на выходе чипа был задетектирован хотя бы один фотон. Дело в том, что реальный чип — он большой и сложный, и какой-то процент фотонов в нем теряется, поэтому в ряде попыток до детекторов не долетит ничего. Чтобы получить 1000 шотов, компьютер сделает больше, чем 1000 повторений. Впрочем, наш локальный симулятор работает без потерь.
Нам осталось поставить задачу в очередь задач:
job = sampler.sample_count.execute_async()
и время от времени проверять ее статус:
print(f"Job status = {job.status()}")
Job status = SUCCESS
Results
Когда задача будет готова, мы можем забрать ее результаты:
results = job.get_results()
Для этого нужно скопитьвать ее ID из списка задач на облаке:
и обратиться к ней таким образом:
proc = pcvl.RemoteProcessor(proc_name, token)
job_id = 'e2692e28-9ccd-4f9d-b2fe-8c64ded10d66'
job = proc.resume_job(job_id)
results = job.get_results()
Результат квантового вычисления показывает, сколько раз алгоритм дал ту или иную комбинацию фотонов (outcomes) на выхоже из чипа. В нашем случае он выглядит так:
outcomes = results['results']
print(outcomes)
{
|0,1>: 497
|1,0>: 503
}
Симулятор произвел 1000 шотов, в 503 из них фотон оказался в первой моде, в 497 — во второй. Почти идеальное соотношение 50:50. А что будет, если мы поменяем фазу интерферометра Маха-Цендера?
phase = 0*np.pi
{
|0,1>: 1000
}
phase = 1*np.pi
{
|1,0>: 1000
}
Ого, поведение интерферометра меняется в зависимости от приложенной фазы! В принципе, это именно то, чего мы от него ожидаем: интерферометр Маха-Цендера часто используется именно для перераспределения света между двумя выводами. (Если присмотреться к схеме чипа Altair, то можно заметить, что он буквально набит такими интерферометрами.) Это не квантовый эффект, а классическая интерференция, но для Hello, world! нам её хватит.
Теперь повторим те же вычисления не на симуляторе, а на QPU. При этом с вашего счета в Quandela Cloud списываются кредиты: один кредит соответствует миллиону шотов. Нам хватит всего тысячи шотов:
phase = 0*np.pi
{
|0,1>: 930
|1,0>: 70
}
phase = 0.5*np.pi
{
|0,1>: 480
|1,0>: 520
}
phase = 1*np.pi
{
|0,1>: 141
|1,0>: 859
}
Не так идеально, но работает! Ничего удивительного: оптика QPU сложная, поэтому к выходу из чипа набегает какая-то ошибка — впрочем, она не сильно мешает реальным квантовым вычисленям.
Матрицы
Вместо того, чтобы набирать схему из сплиттеров и фазовращателей, можно пойти другим путем. По большому счету чип с N модами — это матрица размера NxN, которая превращает входной вектор длины N в выходной вектор такой же длины:
Компоненты входного вектора — это количество фотонов, которое мы запускаем в каждую из мод, ну а выходной вектор показывает среднее число фотонов на выходе из чипа. А теперь самое прекрасное: оказывается, что любую унитарную матрицу можно записать в чип за полиномиальное время. Алгоритм для этого подбирает такие значения фазовращателей, при которых пропускание чипа хорошо аппроксимирует заданную матрицу. А вы же помните, что прохождение через чип тесно связано с перманентом?
Квантовый перманент
Чуть раньше мы узнали, что вероятность получить определенное распределение фотонов на выходе пропорциональна перманенту некой матрицы. Давайте начнем с самого простого случая: две моды, мы запускаем по фотону в каждую и хотим узнать, как часто мы увидим такое же распределение — по фотону в каждой моде — на выходе из чипа. Не вдаваясь в детали, посчитать вероятность такого исхода невероятно просто: она равна
где U — это матрица, описывающая чип. А значит, перманент матрицы U можно вычислить как
Здесь N_shots — общее число шотов, а N_events — количество интересующих нас событий на выходе, где в каждой моде оказалось по фотону.
На удивление простая формула, не так ли? Давайте проверим её на каком-нибудь примере. Возьмем, например, вот такую матрицу:
перманент которой несложно посчитать: 0.6 + (-0.4) = 0.2. А теперь попробуем вычислить его на симуляторе. В Perceval матрица записывается в фотонный чип вот таким образом:
U = np.array([
[np.sqrt(0.6), np.sqrt(0.4)],
[-np.sqrt(0.4), np.sqrt(0.6)],
])
unitary_component = comp.Unitary(pcvl.Matrix(U))
pcvl.pdisplay(unitary_component)
и отображается не как набор сплиттеров-фазовращателей, а как один большой блок:
Посылаем по фотону в каждую моду и запускаем вычисления:
input_state = pcvl.BasicState([1,1])
shots = 10_000
proc = pcvl.Processor("CliffordClifford2017")
proc.set_circuit(unitary_component)
proc.with_input(input_state)
proc.min_detected_photons_filter(1)
sampler = Sampler(proc, max_shots_per_call=shots)
remote_job = sampler.sample_count
remote_job.execute_async()
и смотрим на результаты:
results = remote_job.get_results()
outcomes = results['results']
print(outcomes)
{
|2,0>: 4759
|0,2>: 4829
|1,1>: 412
}
412 событий из 10 000 шотов соответствуют перманенту:
perm = np.sqrt(412/10_000)
print(f'Calculated permanent: {perm:.2f}')
Calculated permanent: 0.20
Идеальное совпадение с ожидаемым результатом!
Унитарность
С матрицами связан один нюанс. Матрица U должна быть унитарной, другую физически не получится прописать в чип. Но это не проблема: если мы хотим посчитать перманент произвольной матрицы A размером N x N, то мы всегда можем дополнить ее до унитарной матрицы U размером 2N x 2N:
Матрица U переводит входной вектор длины 2N в выходной вектор такой же длины, но подматрица А видит только первую половину входного вектора, переводя ее в первую половину выходного. А значит, чтобы посчитать перманент А, мы можем подать по одиночному фотону только в первые N мод и выбрать события с таким же распределением фотонов на выходе.
хорошо описан в этой работе:
Если в двух словах, то мы:
- генерируем матрицу A_s, нормируя A на ее спектральную норму s
- составляем матрицу U с подматрицей A_s как в уравнении (6)
- после вычисления перманента A_s не забываем скорректировать его на спектральную норму:
где n — число строк (или столбцов) матрицы.
import numpy as np
from numpy import linalg
from scipy.linalg import sqrtm
def prepare_unitary(A):
n = len(A)
_, D, _ = linalg.svd(A)
s = np.max(D)
As = A/s
Q = sqrtm(np.identity(n) - np.dot(As, As.conj().T))
R = sqrtm(np.identity(n) - np.dot(As.conj().T, As))
Ubmat = np.bmat([
[As, Q],
[R, -As.conj().T]
])
Ubmat = Ubmat.real
return np.copy(Ubmat), s
Заметьте, что кроме матрицы U функция возвращает ещё и спектральную норму s, на которое нужно будет отнормировать результат (n — это размер матрицы A):
В задаче про Винтика и Шпунтика для N=2 мы считаем перманент матрицы 4х4, которую мы впишем в унитарную матрицу размером 8x8 и легко запишем в чип Altair. К сожалению, уже для N=3 нам потребуется матрица 54х54 — это заметно больше нынешних возможностей. Ну что ж, не все сразу, начнем с простого.
Считаем!
Задаем матрицу из задачки про Винтика и Шпутника для N=2:
A = np.array([
[1, 0, 1, 0],
[0, 1, 0, 1],
[1, 1, 0, 0],
[0, 0, 1, 1],
])
Дополняем ее до унитарной матрицы U и готовимся послать по одиночному фотону в первые четыре моды:
import perceval.components as comp
U, s = prepare_unitary(A)
print(f'Spectral norm = {s}')
unitary_component = comp.Unitary(pcvl.Matrix(U))
input_state = pcvl.BasicState([1,1,1,1,0,0,0,0])
Spectral norm = 2.0
Локальный симулятор
Для начала запускаем вычисления на нашем компьютере:
proc = pcvl.Processor("CliffordClifford2017")
proc.set_circuit(unitary_component)
proc.with_input(input_state)
proc.min_detected_photons_filter(1)
shots = 10_000
sampler = Sampler(proc, max_shots_per_call=shots)
sampler.default_job_name = 'Permanent'
remote_job = sampler.sample_count
remote_job.execute_async()
и получаем результат:
results = remote_job.get_results()
outcomes = results['results']
print(outcomes)
{
|0,0,0,0,1,0,1,2>: 66
|0,0,0,2,1,1,0,0>: 249
|0,0,0,0,0,2,2,0>: 63
|0,0,0,0,0,1,2,1>: 80
...
|1,0,0,0,0,0,3,0>: 1
}
Нас интересует только события, когда выходное состояние совпало с входным. Переменная outcomes
— это объект класса BSCount
, который наследует от dict
, поэтому к нему можно обратиться просто как
events = outcomes[input_state]
print(f'Detected events: {events}')
Detected events: 153
Восстанавливаем перманент по формуле выше, не забывая про нормировку на спектральную норму s:
n = 4 # размер матрицы
perm = (s**n) * np.sqrt(events/shots)
print(f'Calculated permanent: {perm:.2f}')
1.98
Вау, идеальное совпадение с ожидаемой двойкой!
Симулятор Altair
Теперь запустим то же самое на облачном симуляторе, предварительно увеличив число шотов до 100 миллионов:
shots = 100_000_000
proc = pcvl.RemoteProcessor('sim:altair', token)
После окончания посмотрим, сколько же совпадений мы увидели:
events = outcomes[input_state]
print(f'Detected events: {events}')
Detected events: 83
Всего 83 из 100 миллионов?! Минуту назад мы видели в два раза больше совпадений на 10 тысяч шотов, что произошло?
Секрет в том, что QPU очень большой и сложный, и фотону легко в нем потеряться. Суммарное пропускание (transmittance) QPU Altair составляет всего несколько процентов. По дефолту симулятор запускает расчет именно пропусканием в 6 % — то есть только 6 % фотонов оказываются задетектированы на выходе из чипа. Но это же симулятор, поэтому пропускание можно выставить обратно на 100 %:
proc = pcvl.RemoteProcessor('sim:altair', token)
proc.set_parameters({
"transmittance": 1.00,
})
и запустить вычисления еще раз:
events = outcomes[input_state]
print(f'Detected events: {events}')
n = 4 # размер матрицы
perm = (s**n) * np.sqrt(events/shots)
print(f'Calculated permanent: {perm:.2f}')
Detected events: 1444826
Calculated permanent: 1.98
Совсем другое дело! Но что же делать с симуляцией рельного QPU, у которого пропускание t гораздо ниже? В принципе, эти потери несложно учесть:
- Один фотон, запущенный в QPU, будет задетектирован с вероятностью t, а потерян — с веротяностью 1-t.
- Для двух фотонов вероятность задетектировать оба равна t^2, а вероятность потерять оба — (1-t)^2.
- И так далее. Для четырех картинка выглядит как-то так:
Когда мы вычисляем перманент, мы делим число интересующих нас событий |1,1,1,1,0,0,0,0>
на число всех событий. Из-за потерь события |1,1,1,1,0,0,0,0>
приходят в t^4 раз реже, а шоты надо скорректировать на 1 — (1-t)^4 чтобы не забыть случаи со всеми нулями на выходе. В итоге получаем красивую формулу:
И немедленно подставляем в нее наш результат с 83 событиями из 100 000 000 и t = 6 %:
events = outcomes[input_state]
print(f'Detected events: {events}')
n = 4 # размер матрицы
t = 0.06 # пропускание
perm = (s**n) * np.sqrt(events/shots * (1-(1-t)**n)/t**n)
print(f'Calculated permanent: {perm:.2f}')
Detected samples: 83
Calculated permanent: 1.90
Бинго! Вот таким нехитрым способом можно учесть неидеальность квантового процессора.
QPU Altair
Осталось запустить то же самое на настоящем QPU. Его пропускание еще меньше, поэтому увеличим число шотов до 1 миллиарда:
shots = 1_000_000_000
proc = pcvl.RemoteProcessor('qpu:altair', token)
и заберем результаты:
events = outcomes[input_state]
print(f'Detected events: {events}')
Detected events: 69
Пропускание в тот день составило 2.3 %, поэтому после коррекции я получил
n = 4 # размер матрицы
t = 0.023 # пропускание
perm = (s**n) * np.sqrt(events/shots * (1-(1-t)**n)/t**n)
print(f'Calculated permanent: {perm:.2f}')
Calculated permanent: 2.22
И вновь перманент равен двум, как мы и ожидали. Напомню, что мы не ждем высокой точности от квантовых вычислений, ошибка всего в 10 % — это более, чем замечательно.
Ну что же, принимайте поздравления, мы решили задачу про Винтика и Шпунтика на квантовом компьютере!
Вместо заключения
Вы удивитесь, но перманент оказывается крепким орешком даже для квантовых компьютеров. Хоть каждый шот и вычисляется со скоростью света, количество шотов, необходимых для вычислений, быстро растет с размерностью задачи. Похоже, что задачи из класса #P, к которым относится и вычисление перманента, так и останутся экспоненциально сложными и для классических, и для квантовых алгоритмов — хотя последние и показывают на них приличное ускорение.
А теперь хорошие новости: фотонные квантовые компьютеры способны далеко не только на бозонный сэмплинг. Фотонные платформы принципиально отличаются от привычных сверхпроводниковых чипов IBM или Google и позволяет нативно реализовывать новые интересные алгоритмы. При этом на фотонные чипы на удивление хорошо портируются примитивы сверхпроводниковых платформ, поэтому на них можно будет успешно запускать и знаменитые алгоритмы Шора или Гровера. Разумеется, десятифотонного компьютера от Quandela пока еще недостаточно для факторизации простых чисел; впрочем, он уже успешно используется в простых юз-кейсах и учебных программах. Плюс ко всему все нынешние фотонные платформы показывают уверенный рост и на удивление хорошие перспективы для масштабирования. Так что все самое интересное только начинается.
Автор: qbertych