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

Початок роботи з наближеною квантовою компіляцією за допомогою тензорних мереж (AQC-Tensor)

Версії пакетів

Код на цій сторінці було розроблено з використанням наступних вимог. Рекомендуємо використовувати ці версії або новіші.

qiskit[all]~=2.3.0
qiskit-aer~=0.17
qiskit-addon-utils~=0.3.0
qiskit-addon-aqc-tensor[aer,quimb-jax]~=0.2.0; sys.platform != 'darwin'
scipy~=1.16.3

Цей посібник демонструє простий робочий приклад для початку роботи з AQC-Tensor. У цьому прикладі ти візьмеш схему Троттера, яка моделює еволюцію поперечно-польової моделі Ізінга, і використаєш метод AQC-Tensor для зменшення глибини отриманої схеми. Крім того, цей приклад вимагає пакету qiskit-addon-utils для генератора задач, qiskit-aer для моделювання тензорних мереж і scipy для оптимізації параметрів.

Для початку пригадаємо, що гамільтоніан поперечно-польової моделі Ізінга має вигляд

HIsing=i=1NJi,(i+1)ZiZi+1+hiXi\mathcal{H}_{Ising} = \sum_{i=1}^N J_{i,(i+1)}Z_iZ_{i+1} + h_i X_i

де ми будемо вважати, що діють періодичні граничні умови, які означають, що при i=10i=10 отримуємо i+1=111i+1=11\rightarrow 1, JJ — сила зв'язку між двома вузлами, а hh — сила зовнішнього магнітного поля.

Наступний фрагмент коду згенерує гамільтоніан ланцюжка Ізінга з 10 вузлів із періодичними граничними умовами.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-addon-aqc-tensor qiskit-addon-utils qiskit-aer scipy
from qiskit.transpiler import CouplingMap
from qiskit_addon_utils.problem_generators import generate_xyz_hamiltonian
from qiskit.synthesis import SuzukiTrotter
from qiskit_addon_utils.problem_generators import (
generate_time_evolution_circuit,
)
from qiskit_addon_aqc_tensor import generate_ansatz_from_circuit
from qiskit_addon_aqc_tensor.simulation import tensornetwork_from_circuit
from qiskit_addon_aqc_tensor.simulation import compute_overlap
from qiskit_addon_aqc_tensor.objective import MaximizeStateFidelity
from qiskit_aer import AerSimulator
from scipy.optimize import OptimizeResult, minimize

# Generate some coupling map to use for this example
coupling_map = CouplingMap.from_heavy_hex(3, bidirectional=False)

# Choose a 10-qubit circle on this coupling map
reduced_coupling_map = coupling_map.reduce(
[0, 13, 1, 14, 10, 16, 4, 15, 3, 9]
)

# Get a qubit operator describing the Ising field model
hamiltonian = generate_xyz_hamiltonian(
reduced_coupling_map,
coupling_constants=(0.0, 0.0, 1.0),
ext_magnetic_field=(0.4, 0.0, 0.0),
)

Розбиття часової еволюції на дві частини для класичного та квантового виконання

Загальна мета цього прикладу — моделювати часову еволюцію модельного гамільтоніана. Ми робимо це за допомогою еволюції Троттера, яка буде розбита на дві частини.

  1. Початкова частина, яку можна моделювати за допомогою матричних добутків станів (MPS). Саме вона буде «скомпільована» за допомогою AQC-Tensor.
  2. Подальша частина, яка буде виконана на квантовому залізі.

Ми оберемо еволюцію системи до часу tf=5t_f=5 і використаємо AQC-Tensor для стиснення часової еволюції до часу t=4t=4, а потім еволюціонуємо за допомогою звичайних кроків Троттера до tft_f.

Далі ми згенеруємо дві схеми: одну, яка буде стиснута за допомогою AQC-Tensor, і одну, яка буде виконана на QPU. Для першої схеми, оскільки вона буде класично моделюватись за допомогою матричних добутків станів, ми використаємо велику кількість шарів, щоб мінімізувати похибку Троттера. Тоді як друга схема, що моделює часову еволюцію від ti=4t_i=4 до tf=5t_f=5, використовуватиме значно менше шарів для мінімізації глибини.

# Generate circuit to be compressed
aqc_evolution_time = 4.0
aqc_target_num_trotter_steps = 45

aqc_target_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),
time=aqc_evolution_time,
)

# Generate circuit to execute on hardware
subsequent_evolution_time = 1.0
subsequent_num_trotter_steps = 5

subsequent_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=subsequent_num_trotter_steps),
time=subsequent_evolution_time,
)

Для порівняння ми також згенеруємо третю схему — таку, що еволюціонує до t=4t=4, але має таку саму кількість шарів, що й друга схема, яка еволюціонує від ti=4t_i=4 до tf=5t_f=5. Це схема, яку ми б виконали, якби не використовували техніку AQC-Tensor. Назвемо її схемою порівняння.

aqc_comparison_num_trotter_steps = int(
subsequent_num_trotter_steps
/ subsequent_evolution_time
* aqc_evolution_time
)
aqc_comparison_num_trotter_steps

comparison_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_comparison_num_trotter_steps),
time=aqc_evolution_time,
)

Генерація анзацу та побудова MPS-моделювання

Далі ми згенеруємо анзац, який будемо оптимізувати. Він еволюціонуватиме до того ж часу еволюції, що й наша перша схема (від ti=0t_i=0 до tf=4t_f=4), але з меншою кількістю кроків Троттера.

Після генерації схеми ми передаємо її у функцію generate_ansatz_from_circuit() AQC-Tensor, яка аналізує двокубітну зв'язність і повертає дві речі. По-перше — згенеровану схему анзацу з тією самою двокубітною зв'язністю, і по-друге — набір параметрів, які, підставлені в анзац, дають вхідну схему.

aqc_ansatz_num_trotter_steps = 5

aqc_good_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_ansatz_num_trotter_steps),
time=aqc_evolution_time,
)

aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(
aqc_good_circuit, qubits_initially_zero=True
)
aqc_ansatz.draw("mpl", fold=-1)

Output of the previous code cell

Далі ми побудуємо MPS-представлення стану, який потрібно апроксимувати за допомогою AQC. Ми також обчислимо вірність ψ1ψ22|\langle\psi_1 | \psi_2 \rangle |^2 між станом, підготовленим схемою порівняння, та схемою, яка генерує цільовий стан (з використанням більшої кількості кроків Троттера).

# Generate MPS simulator settings and obtain the MPS representation of the target state
simulator_settings = AerSimulator(
method="matrix_product_state",
matrix_product_state_max_bond_dimension=100,
)
aqc_target_mps = tensornetwork_from_circuit(
aqc_target_circuit, simulator_settings
)

# Compute the fidelity between the MPS representation of the target state and the state produced by the comparison circuit
comparison_mps = tensornetwork_from_circuit(
comparison_circuit, simulator_settings
)
comparison_fidelity = (
abs(compute_overlap(comparison_mps, aqc_target_mps)) ** 2
)
print(f"Comparison fidelity: {comparison_fidelity}")
Comparison fidelity: 0.9997111919739693

Оптимізація параметрів анзацу за допомогою MPS

Нарешті, ми оптимізуємо схему анзацу так, щоб вона генерувала цільовий стан з більшою вірністю, ніж comparison_fidelity. Функція вартості для мінімізації — MaximizeStateFidelity, і вона буде оптимізована за допомогою оптимізатора L-BFGS бібліотеки scipy.

objective = MaximizeStateFidelity(
aqc_target_mps, aqc_ansatz, simulator_settings
)

stopping_point = 1 - comparison_fidelity

def callback(intermediate_result: OptimizeResult):
print(f"Intermediate result: Fidelity {1 - intermediate_result.fun:.8}")
if intermediate_result.fun < stopping_point:
# Good enough for now
raise StopIteration

result = minimize(
objective,
aqc_initial_parameters,
method="L-BFGS-B",
jac=True,
options={"maxiter": 100},
callback=callback,
)
if (
result.status
not in (
0,
1,
99,
)
): # 0 => success; 1 => max iterations reached; 99 => early termination via StopIteration
raise RuntimeError(
f"Optimization failed: {result.message} (status={result.status})"
)

print(f"Done after {result.nit} iterations.")
aqc_final_parameters = result.x
Intermediate result: Fidelity 0.95084365
Intermediate result: Fidelity 0.98409893
Intermediate result: Fidelity 0.99142033
Intermediate result: Fidelity 0.99521405
Intermediate result: Fidelity 0.99566673
Intermediate result: Fidelity 0.99650054
Intermediate result: Fidelity 0.99683487
Intermediate result: Fidelity 0.99720426
Intermediate result: Fidelity 0.99761726
Intermediate result: Fidelity 0.99809073
Intermediate result: Fidelity 0.99838244
Intermediate result: Fidelity 0.99861841
Intermediate result: Fidelity 0.99874617
Intermediate result: Fidelity 0.99892696
Intermediate result: Fidelity 0.99908129
Intermediate result: Fidelity 0.99917737
Intermediate result: Fidelity 0.99925456
Intermediate result: Fidelity 0.99933134
Intermediate result: Fidelity 0.99947173
Intermediate result: Fidelity 0.99956469
Intermediate result: Fidelity 0.99964488
Intermediate result: Fidelity 0.99967419
Intermediate result: Fidelity 0.99968821
Intermediate result: Fidelity 0.9997448
Done after 24 iterations.

На цьому етапі ми маємо набір параметрів, які генерують цільовий стан з вищою вірністю, ніж та, яку б дала схема порівняння без використання AQC. З цими оптимальними параметрами стиснута схема тепер має меншу похибку Троттера і меншу глибину, ніж оригінальна схема.

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

final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)
final_circuit.compose(subsequent_circuit, inplace=True)
final_circuit.draw("mpl", fold=-1)

Output of the previous code cell

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