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

Твій перший квантовий експеримент

Вступ

У наступному відео Олівія Лейнс проведе тебе крізь матеріал цього уроку. Або ж ти можеш відкрити відео на YouTube для цього уроку в окремому вікні.

До цього моменту ти вже запустив свою першу квантову схему і вивчив основи квантових обчислень: як представляються квантові стани, як вентилі діють на ці стани, і як квантові явища — суперпозиція та заплутаність — беруть участь у цьому. Тепер час застосувати все це на практиці та вирішити першу задачу на квантовому комп'ютері.

Більш широкий ландшафт задач, придатних для квантових обчислень, ми дослідимо в наступному уроці. Зараз ми зосередимось на задачі з галузі симуляції природи: використання квантового комп'ютера як більш чистого та керованого замінника природної квантової системи. Насправді, це і було першим застосуванням, яке Річард Фейнман передбачив для квантових комп'ютерів у 1980-х роках. Як він влучно висловився: "Природа не є класичною, дідько його візьми, і якщо ти хочеш створити симуляцію природи, то краще зроби її квантово-механічною..."

У цьому уроці ми дотримаємось цього принципу, щоб змоделювати взаємодію між двома спінами, які можна уявити як крихітні магніти. Залежно від знаку їхньої взаємодії, вони можуть прагнути вирівнятися й вказувати в одному напрямку, або антивирівнятися й вказувати у протилежних напрямках. Ми зосередимось на останньому випадку, оскільки він часто призводить до більш цікавої — і більш складної — поведінки. Після того як ми зрозуміємо цю невелику двокубітну систему, ми покажемо, як ті самі ідеї масштабуються, дозволяючи квантовим комп'ютерам скористатися своїм експоненційним масштабуванням при симуляції великих спінових систем.

Два взаємодіючі магніти

Для цієї задачі ми використаємо два кубіти — по одному для кожного спіну в нашій моделі. Кожен спін може вказувати вгору (стан кубіта 0|0\rangle), вниз (стан кубіта 1|1\rangle) або перебувати в суперпозиції двох станів.

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

Тепер припустимо, що в нашій системі також є магнітне поле, що вказує зліва направо. Оскільки це поле вказує впоперек до звичайного напрямку спінів вгору-вниз, воно називається поперечним полем. Це поле може перевертати спіни, що призводить до того, що конфігурація з найнижчою енергією є певною суперпозицією розміщень спінів вгору і вниз, а не якимось одним визначеним шаблоном спінів.

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

H=JZ1Z0+hx(X1+X0)H = J Z_1 Z_0 + h_x (X_1 + X_0)

де JJ — коефіцієнт, що контролює силу взаємодії між спінами, а hxh_x — коефіцієнт сили зовнішнього магнітного поля. Z1Z0Z_1 Z_0 заохочує або штрафує спіни залежно від того, чи вони вирівняні або антивирівняні, а X0X_0 і X1X_1 представляють ефект перевертання спінів магнітним полем.

У фізиці системи прагнуть перейти до стану з найнижчою можливою енергією, який називається основним станом. Знаходження цього стану з найнижчою енергією є поширеною задачею, але вона вимагає методів оптимізації, що виходять за межі цього уроку.

Натомість ми поставимо простіше запитання: якщо ми підготуємо спіни в певному стані, яка енергія цього стану?

Щоб відповісти на це, ми:

  1. Підготуємо спіни в стані за нашим вибором
  2. Виміряємо енергію цього стану за допомогою наведеного вище гамільтоніана

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

Реалізація в Qiskit

Перш ніж перейти до написання коду, нам потрібно трохи підготуватись. Коли ми запускаємо квантову схему, ми завжди завершуємо вимірюванням кубітів. Але є два різних види запитань, які ми можемо поставити про результат цього вимірювання: іноді ми просто хочемо знати, в якому стані знаходиться кубіт. В інших випадках ми хочемо знати, задано квантовий стан, яке значення фізичної величини, наприклад енергії?

У Qiskit ці два типи запитань обробляються двома різними інструментами, які називаються примітивами.

Sampler відповідає на перший тип запитання. Він запускає схему багато разів і повідомляє нам, як часто ми вимірюємо кожен можливий результат, наприклад 00, 01, 10 або 11. Результат — це гістограма, що показує ймовірність кожного результату вимірювання.

Estimator відповідає на другий тип запитання. Замість гістограми він об'єднує багато вимірювань за лаштунками, щоб обчислити одне число, наприклад енергію стану відповідно до гамільтоніана, який ми надаємо.

Щоб допомогти тобі зрозуміти, коли і чому ми використовували б кожен із цих інструментів, ми пройдемось через два повних робочих процеси (які називаються "шаблонами Qiskit"), застосованих до тієї самої двокубітної системи.

Робочий процес шаблонів Qiskit

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

  1. Відобрази задачу на модель, яку можна представити квантовими схемами
  2. Оптимізуй схему для запуску на конкретному бекенді
  3. Виконай оптимізовану схему на вибраному бекенді
  4. Виконай постобробку необроблених даних вимірювань

Експеримент 1: використай Sampler для вимірювання стану

Відображення

Загалом, крок відображення — це місце, де ми з'ясовуємо, як представити реальну задачу в термінах кубітів, операторів і вимірювань. У багатьох застосуваннях це найскладніша та найбільш трудомістка частина робочого процесу — навіть прості запитання, наприклад "що представляє кожен кубіт?", не завжди мають однозначних відповідей.

Однак у цьому експерименті відображення навмисно просте. Кожен фізичний ступінь свободи відображається безпосередньо на один кубіт. Завдяки цій відповідності один-до-одного крок відображення зводиться до вибору квантового стану, який ми хочемо підготувати, та написання схеми, яка підготовлює і вимірює цей стан.

Тут ми підготуємо заплутаний стан Белла, подібний до того, який ми зробили в самому першому уроці цього курсу:

Ψ=12(1001)\vert\Psi\rangle = \frac{1}{\sqrt{2}}(\vert 10\rangle - \vert 01\rangle)
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# Import Qiskit primitives
from qiskit import QuantumCircuit

# Make state
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.x(1)
qc.z(0)

# Measure state
qc.measure_all()

# Draw circuit
qc.draw("mpl")

Output of the previous code cell

Оптимізація

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

Під час оптимізації:

  1. Ми обираємо бекенд — або справжній квантовий комп'ютер, або симулятор.
  2. Ми призначаємо кубіти нашої схеми фізичним кубітам на пристрої.
  3. Ми переписуємо схему, використовуючи лише ті вентилі, які квантовий комп'ютер може фактично виконати.
  4. За бажанням впроваджуємо техніки пом'якшення та придушення помилок, щоб зменшити вплив шуму.

У Qiskit це обробляється автоматично транспілятором. Після вибору бекенду транспілятор виконує всю роботу, щоб підготувати твою схему до виконання, тому тобі не потрібно вручну налаштовувати вентилі або призначення кубітів. Транспілятор також пропонує різні рівні оптимізації, які можуть допомогти зменшити помилки за необхідності. Оптимізація виконується поетапно, які називаються "проходами". Тому ця оптимізація буде оброблятись за допомогою pass_manager у наведеному нижче коді. Щоб дізнатись більше про помилки та пом'якшення помилок, дивись курс Олівії Лейнс Quantum Computing in Practice.

# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService

## Load the Qiskit Runtime service
# QiskitRuntimeService.save_account(
# channel="ibm_quantum_platform",
# token="YOUR_TOKEN_HERE",
# overwrite=True,
# set_as_default=True,
# )
# service = QiskitRuntimeService(channel="ibm_quantum_platform")

# Or load saved credentials
service = QiskitRuntimeService()

# Use the least busy backend, or uncomment the loading of a specific backend like "ibm_brisbane".
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)
# backend = service.backend("ibm_brisbane")
print(backend.name)
ibm_fez
# Transpile the circuit and optimize for running on the quantum computer selected
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)

qc_isa.draw("mpl")

Output of the previous code cell

Виконання

Тепер ми готові до виконання! Ми завантажимо Sampler, а потім надішлемо завдання до бекенду.

# Load the Runtime primitive and session
from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(mode=backend)

Або якщо ти використовуєш симулятор, можеш розкоментувати та запустити цю клітинку замість цього:

## Load the backend sampler
# from qiskit.primitives import BackendSamplerV2

## Load the Aer simulator and generate a noise model based on the currently-selected backend.
# from qiskit_aer import AerSimulator
# from qiskit_aer.noise import NoiseModel

# noise_model = NoiseModel.from_backend(backend)

## Define a simulator using Aer, and use it in Sampler.
# backend_sim = AerSimulator(noise_model=noise_model)
# sampler_sim = BackendSamplerV2(backend=backend_sim)

## Alternatively, load a fake backend with generic properties and define a simulator.
## backend_gen = GenericBackendV2(num_qubits=18)
## sampler_gen = BackendSamplerV2(backend=backend_gen)
job = sampler.run([qc_isa], shots=100)
# job = sampler_sim.run([qc_isa]) # uncomment if you want to run on a simulator
res = job.result()
counts = res[0].data.meas.get_counts()

Постобробка

from qiskit.visualization import plot_histogram

print("counts = ", counts)
plot_histogram(counts)
counts =  {'10': 49, '01': 50, '11': 1}

Output of the previous code cell

Ми бачимо, що більшість лічильників припадає або на 01, або на 10, тобто коли один кубіт вимірювався як 0, інший був 1, і навпаки. Це відповідає стану Белла Ψ\vert \Psi^- \rangle, який ми підготували.

Експеримент 2: використай Estimator для вимірювання енергії

Тепер, коли ми побачили, як вибирати квантовий стан, давай використаємо Estimator для обчислення енергії нашого стану Белла Ψ=12(0110)\vert \Psi^- \rangle = \frac{1}{\sqrt{2}}(\vert 01 \rangle - \vert 10 \rangle).

Відображення

Нагадаємо, що енергія системи визначається взаємодією між спінами (JJ) і зовнішнім магнітним полем (hxh_x), як це описано гамільтоніаном:

H=JZ1Z0+hx(X1+X0)H = J Z_1 Z_0 + h_x (X_1 + X_0)

Кожен доданок гамільтоніана повідомляє нам, як певна комбінація спінів вносить внесок в енергію. У Qiskit ми можемо представити ці доданки як оператори Паулі, які є просто позначеннями простих дій на кубіти:

  • Z1Z0Z_1 Z_0 діє з ZZ на обох кубітах.
  • X0X_0 діє з XX на кубіт 0.
  • X1X_1 діє з XX на кубіт 1.

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

# Import Qiskit primitives
from qiskit.quantum_info import SparsePauliOp

# Parameters
J = 1.0 # antiferromagnetic coupling (J<0)
hx = -0.5 # transverse field strength

# 1. Define the Hamiltonian H = J Z1 Z2 + hx (X1 + X2)
obs = SparsePauliOp.from_list([("ZZ", J), ("XI", hx), ("IX", hx)])

# Make state
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.x(1)
qc.z(0)
<qiskit.circuit.instructionset.InstructionSet at 0x1387ed630>

Зауважимо, що ми опустили рядок qc.measure_all() у нашому коді. Це тому, що з Estimator нам не потрібно вказувати, де вимірювати в схемі. Ми просто скажемо йому, які спостережувані ми хочемо оцінити, а Qiskit подбає про вимірювання за лаштунками.

Оптимізація

Крок оптимізації відбувається, як і раніше, з тією різницею, що наші спостережувані також записуються у спосіб, який квантовий комп'ютер може зрозуміти.

# Transpile the circuit and optimize for running on the quantum computer selected
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)

qc_isa.draw("mpl")

Output of the previous code cell

Виконання

На кроці виконання ми завантажимо Estimator, а потім надішлемо схему разом зі списком спостережуваних, які ми хочемо оцінити, до квантового комп'ютера.

# Load the Runtime primitive and session
from qiskit_ibm_runtime import EstimatorV2 as Estimator

estimator = Estimator(mode=backend)
# Load the backend sampler

# noise_model = NoiseModel.from_backend(backend)

# Use Aer simulator in Estimator
# estimator_sim = BackendEstimatorV2(backend=backend_sim)

# Alternatively, load a fake backend with generic properties and define a simulator.
# backend_gen = GenericBackendV2(num_qubits=18)
# estimator_gen = BackendEstimatorV2(backend=backend_gen)
pubs = [(qc_isa, obs_isa)]
job = estimator.run([[qc_isa, obs_isa]])
res = job.result()

# Uncomment lines below to run the job on the Aer simulator with noise model from real backend
# job = estimator_sim.run([[qc_isa,obs_isa]])
# res=job.result()

Постобробка

Нарешті, на кроці постобробки ми просто виводимо енергію, обчислену за лаштунками за допомогою Estimator.

print(res[0].data.evs)
-0.9934112021453058

Це енергія нашого стану!

Висновок

У цьому уроці ми навчились підготовляти простий двокубітний квантовий стан, що представляє два взаємодіючі спіни. Ми побачили, як використовувати Sampler для спостереження розподілу результатів вимірювань і як використовувати Estimator для обчислення енергії стану відповідно до гамільтоніана. По ходу ми побачили, як гамільтоніан кодує взаємодії між спінами та ефекти зовнішнього поля, і як різні стани можуть мати різну енергію.

Розширення до багатьох спінів

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

Природним розширенням цього експерименту було б збільшення кількості кубітів для представлення більшої кількості спінів і зміна способу підготовки спінів, щоб спробувати знайти стан із найнижчою енергією. Цей підхід є суттю варіаційних методів, про які ти можеш дізнатись у курсі Variational Quantum Algorithms.

Існують також інші квантові підходи до вивчення енергій основного стану, що виходять за рамки варіаційних методів. Ці методи тут не розглядаються, але вводяться у курсі Quantum Diagonalization Algorithms, якщо тебе цікавить дізнатись більше.

Навчальна мета

Повернись до початку Експерименту 2 і спробуй його знову з іншим станом суперпозиції. Чи можеш ти знайти стан із ще нижчою енергією, ніж та, яку ми використовували?

This translation based on the English version of 7 трав. 2026 р.