Langkau ke kandungan utama

Mengurangkan ralat Trotter bagi dinamik Hamiltonian dengan formula berbilang produk

Dalam notebook ni, korang akan belajar cara guna Formula Berbilang Produk (MPF) untuk mencapai ralat Trotter yang lebih rendah pada observable kita berbanding ralat yang ditanggung oleh Circuit Trotter paling dalam yang sebenarnya akan kita jalankan. Korang akan buat ni dengan melalui langkah-langkah corak Qiskit:

  • Langkah 1: Petakan ke masalah kuantum
    • Mulakan Hamiltonian masalah kita
    • Guna MPF untuk menjana Circuit evolusi masa yang di-Trotterkan
  • Langkah 2: Optimumkan masalah
  • Langkah 3: Jalankan eksperimen
  • Langkah 4: Bina semula keputusan
    • Kira nilai jangkaan MPF

Langkah 1: Petakan ke masalah kuantum​

1a: Menyediakan Hamiltonian kita​

Kita guna model Ising pada garisan 10 tapak:

H^Ising=βˆ‘i=19Ji,(i+1)ZiZ(i+1)+βˆ‘i=110hiXi ,\hat{\mathcal{H}}_{\text{Ising}} = \sum_{i=1}^{9} J_{i,(i+1)} Z_i Z_{(i+1)} + \sum_{i=1}^{10} h_i X_i \, ,

di mana JJ adalah kekuatan gandingan antara dua tapak dan hh adalah medan magnet luaran. Pakej qiskit_addon_utils menyediakan fungsi-fungsi boleh guna semula untuk pelbagai tujuan.

Modul qiskit_addon_utils.problem_generators nya menyediakan fungsi untuk menjana Hamiltonian seperti Heisenberg pada graf sambungan yang diberikan. Graf ini boleh jadi sama ada rustworkx.PyGraph atau CouplingMap yang memudahkan penggunaannya dalam aliran kerja berpusat-Qiskit.

Dalam bahagian berikut, kita cipta garisan mudah 10 Qubit menggunakan kaedah CouplingMap.from_line.

# Added by doQumentation β€” required packages for this notebook
!pip install -q numpy qiskit qiskit-addon-mpf qiskit-addon-utils rustworkx scipy
from qiskit.transpiler import CouplingMap

# Generate some coupling map to use for this example
coupling_map = CouplingMap.from_line(10, bidirectional=False)
from rustworkx.visualization import graphviz_draw

graphviz_draw(coupling_map.graph, method="circo")

Code output

Seterusnya, kita jana SparsePauliOp pada sambungan yang diberikan dengan pemalar yang dikehendaki.

from qiskit_addon_utils.problem_generators import generate_xyz_hamiltonian

# Get a qubit operator describing the Ising field model
hamiltonian = generate_xyz_hamiltonian(
coupling_map,
coupling_constants=(0.0, 0.0, 1.0),
ext_magnetic_field=(0.4, 0.0, 0.0),
)
print(hamiltonian)
SparsePauliOp(['IIIIIIIZZI', 'IIIIIZZIII', 'IIIZZIIIII', 'IZZIIIIIII', 'IIIIIIIIZZ', 'IIIIIIZZII', 'IIIIZZIIII', 'IIZZIIIIII', 'ZZIIIIIIII', 'IIIIIIIIIX', 'IIIIIIIIXI', 'IIIIIIIXII', 'IIIIIIXIII', 'IIIIIXIIII', 'IIIIXIIIII', 'IIIXIIIIII', 'IIXIIIIIII', 'IXIIIIIIII', 'XIIIIIIIII'],
coeffs=[1. +0.j, 1. +0.j, 1. +0.j, 1. +0.j, 1. +0.j, 1. +0.j, 1. +0.j, 1. +0.j,
1. +0.j, 0.4+0.j, 0.4+0.j, 0.4+0.j, 0.4+0.j, 0.4+0.j, 0.4+0.j, 0.4+0.j,
0.4+0.j, 0.4+0.j, 0.4+0.j])

Observable yang akan kita ukur adalah jumlah magnetisasi yang boleh kita bina dengan mudah seperti yang ditunjukkan di bawah:

from qiskit.quantum_info import SparsePauliOp

L = coupling_map.size()
observable = SparsePauliOp.from_sparse_list([("Z", [i], 1 / L / 2) for i in range(L)], num_qubits=L)
print(observable)
SparsePauliOp(['IIIIIIIIIZ', 'IIIIIIIIZI', 'IIIIIIIZII', 'IIIIIIZIII', 'IIIIIZIIII', 'IIIIZIIIII', 'IIIZIIIIII', 'IIZIIIIIII', 'IZIIIIIIII', 'ZIIIIIIIII'],
coeffs=[0.05+0.j, 0.05+0.j, 0.05+0.j, 0.05+0.j, 0.05+0.j, 0.05+0.j, 0.05+0.j,
0.05+0.j, 0.05+0.j, 0.05+0.j])

1b: Formula Berbilang Produk​

MPF mengurangkan ralat Trotter bagi dinamik Hamiltonian melalui gabungan berwajaran beberapa pelaksanaan Circuit.

Untuk lebih jelas, kita takrifkan MPF sebagai:

ΞΌ(t)=βˆ‘jxjρjkj(tkj)+someΒ remainingΒ TrotterΒ error ,\mu(t) = \sum_{j} x_j \rho^{k_j}_{j}\left(\frac{t}{k_j}\right) + \text{some remaining Trotter error} \, ,

di mana xjx_j adalah pekali pemberat kita, ρjkj\rho^{k_j}_j adalah matriks ketumpatan yang sepadan dengan keadaan tulen yang diperoleh dengan mengevolusi keadaan awal menggunakan formula produk, SkjS^{k_j}, melibatkan kjk_j langkah Trotter, dan jj mengindeks bilangan formula produk yang membentuk MPF.

Perkara utama di sini ialah ralat Trotter yang tinggal adalah lebih kecil daripada ralat Trotter yang akan diperoleh dengan hanya menggunakan nilai kjk_j terbesar!

Korang boleh lihat kegunaan MPF dari dua perspektif:

  1. Untuk bajet langkah Trotter yang tetap yang boleh korang jalankan, korang boleh dapatkan keputusan dengan ralat Trotter yang lebih kecil secara keseluruhan.
  2. Untuk bilangan langkah Trotter yang menghasilkan Circuit dalam, korang boleh guna MPF untuk mencari beberapa Circuit kedalaman lebih pendek untuk dijalankan yang menghasilkan ralat Trotter yang serupa.

Pengenalan kepada MPF statik​

MPF Statik adalah yang mana nilai xjx_j TIDAK bergantung pada masa evolusi, tt.

Menentukan pekali MPF statik untuk set nilai kjk_j yang diberikan adalah bersamaan dengan menyelesaikan sistem persamaan linear: Ax=bAx=b, di mana xx adalah pekali yang kita minati, AA adalah matriks yang bergantung pada kjk_j dan jenis PF yang kita guna (SS), dan bb adalah vektor kekangan. Untuk ringkas, kita tidak akan masuk lebih detail di sini dan sebaliknya merujuk korang ke dokumentasi LSE.

Kita boleh cari penyelesaian untuk xx secara analitik sebagai x=Aβˆ’1bx = A^{-1}b, lihat contohnya Carrera Vazquez et al., 2023 atau Zhuk et al., 2023. Namun, penyelesaian tepat ini boleh jadi "tidak terkondisi" menghasilkan L1-norm yang sangat besar untuk pekali kita, xx, yang boleh membawa kepada prestasi MPF yang buruk. Sebaliknya, seseorang juga boleh mendapatkan penyelesaian anggaran yang meminimumkan L1-norm of xx dalam usaha mengoptimumkan tingkah laku MPF.

Dalam bahagian berikut, korang akan belajar cara buat semua ini.

Memilih kjk_j​

Pilihan kjk_j adalah bergantung pada pengguna akhir. Pada dasarnya, sebarang nilai boleh dipilih tetapi ada kjk_j yang akan membawa kepada amplifikasi hingar yang lebih besar pada peranti sebenar berbanding pilihan lain. Oleh itu, adalah penting untuk cuba mencari nilai kjk_j yang "baik".

Di sini, kita akan pilih nilai tetap untuk kjk_j. Nilai terkecil didorong oleh masa evolusi sasaran t=8.0t=8.0 yang biasanya memberitahu kita untuk memenuhi t/kmin<1t/k_{\text{min}} \lt 1 tetapi secara empirikal kita tahu bahawa menetapkannya sama dengan 11 biasanya berfungsi juga. Jika korang ingin tahu lebih lanjut tentang ini dan cara memilih nilai kjk_j yang lain, rujuk panduan masing-masing: Cara memilih langkah Trotter untuk MPF.

time = 8.0
trotter_steps = (8, 12, 19)

Menyediakan LSE​

Sekarang yang kita dah pilih kjk_j, kita mesti terlebih dahulu bina LSE, Ax=bAx=b seperti yang dijelaskan di atas. Matriks AA bukan sahaja bergantung pada kjk_j tetapi juga pilihan formula produk (PF) kita -- khususnya perintahnya. Selain itu, seseorang boleh mengambil kira sama ada PF adalah simetri atau tidak (lihat Carrera Vazquez et al., 2023), dengan menetapkan symmetric=True. Namun, ini tidak diperlukan seperti yang ditunjukkan oleh Zhuk et al., 2023.

Di sini, kita akan guna formula Suzuki-Trotter perintah kedua yang menghasilkan order=2 dan kita akan tetapkan symmetric=True.

from qiskit_addon_mpf.static import setup_static_lse

lse = setup_static_lse(trotter_steps, order=2, symmetric=True)
print(lse)
LSE(A=array([[1.00000000e+00, 1.00000000e+00, 1.00000000e+00],
[1.56250000e-02, 6.94444444e-03, 2.77008310e-03],
[2.44140625e-04, 4.82253086e-05, 7.67336039e-06]]), b=array([1., 0., 0.]))

Menyelesaikan untuk xx secara analitik​

Seperti yang disebutkan sebelum ini, kita boleh cari xx secara analitik:

import numpy as np

coeffs_analytical = lse.solve()
print(coeffs_analytical)
[ 0.17239057 -1.19447005  2.02207947]

Mengoptimumkan untuk xx menggunakan model tepat​

Sebagai alternatif kepada mengira x=Aβˆ’1bx=A^{-1}b, korang juga boleh guna setup_exact_problem untuk membina contoh cvxpy.Problem yang menggunakan LSE sebagai kekangan dan penyelesaian optimalnya akan menghasilkan xx.

Dalam bahagian seterusnya, akan jelas kenapa antara muka ini wujud.

from qiskit_addon_mpf.costs import setup_exact_problem

model_exact, coeffs_exact = setup_exact_problem(lse)
model_exact.solve()
print(coeffs_exact.value)
[ 0.17239057 -1.19447005  2.02207947]

Sebagai petunjuk sama ada MPF yang dibina dengan pekali ini akan menghasilkan keputusan yang baik, kita boleh guna L1-norm (lihat juga Carrera Vazquez et al., 2023).

print(np.linalg.norm(coeffs_exact.value, ord=1))
3.3889400921655914

Mengoptimumkan untuk xx menggunakan model anggaran​

Mungkin berlaku bahawa norma L1 untuk set nilai kjk_j yang dipilih dianggap terlalu tinggi. Jika itu berlaku dan korang tidak boleh pilih set nilai kjk_j yang berbeza, korang boleh guna penyelesaian anggaran untuk LSE sebagai ganti penyelesaian tepat.

Untuk buat begitu, cuma guna setup_sum_of_squares_problem untuk membina contoh cvxpy.Problem yang berbeza yang mengehadkan L1-norm kepada ambang yang dipilih sambil meminimumkan perbezaan AxAx dan bb.

from qiskit_addon_mpf.costs import setup_sum_of_squares_problem

model_approx, coeffs_approx = setup_sum_of_squares_problem(lse, max_l1_norm=3.0)
model_approx.solve()
print(coeffs_approx.value)
print(np.linalg.norm(coeffs_approx.value, ord=1))
[-0.40454257  0.57553173  0.8290123 ]
1.8090865903790838

Perhatikan, korang ada kebebasan penuh tentang cara menyelesaikan masalah pengoptimuman ini, bermakna korang boleh tukar penyelesai pengoptimuman, ambang penumpuannya, dan sebagainya. Tengok panduan masing-masing tentang Cara guna model anggaran.

1c: Menyediakan Circuit Trotter​

Pada ketika ini, kita dah jumpa pekali pengembangan kita, xx, dan yang tinggal ialah menjana Circuit kuantum yang di-Trotterkan. Sekali lagi, modul qiskit_addon_utils.problem_generators datang menyelamatkan untuk buat benda tu:

from qiskit.synthesis import SuzukiTrotter
from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit

circuits = []
for k in trotter_steps:
circ = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(order=2, reps=k),
time=time,
)
circuits.append(circ)
circuits[0].draw("mpl", fold=-1)

Quantum circuit diagram

circuits[1].draw("mpl", fold=-1)

Quantum circuit diagram

circuits[2].draw("mpl", fold=-1)

Quantum circuit diagram

Langkah 2: Optimumkan masalah​

Biasanya, ini adalah langkah dalam corak di mana korang mengoptimumkan Circuit untuk pelaksanaan pada perkakasan. Di sini, oleh sebab kita hanya guna simulator tanpa hingar, kita cuma transpile Circuit kita untuk GenericBackendV2.

from qiskit.providers.fake_provider import GenericBackendV2
from qiskit.transpiler import generate_preset_pass_manager

backend = GenericBackendV2(num_qubits=10)
transpiler = generate_preset_pass_manager(optimization_level=2, backend=backend)

transpiled_circuits = [transpiler.run(circ) for circ in circuits]

Langkah 3: Jalankan eksperimen kuantum​

Seperti yang dijelaskan pada awal tadi, kita akan langkau langkah pengoptimuman 2 kerana kita cuma akan mengira nilai jangkaan observable sasaran kita menggunakan simulator bebas-hingar, iaitu StatevectorEstimator.

from qiskit.primitives import StatevectorEstimator

estimator = StatevectorEstimator()
job = estimator.run([(circ, observable) for circ in transpiled_circuits])
result = job.result()

Langkah 4: Bina semula keputusan​

Pertama, kita ekstrak nilai jangkaan individu yang diperoleh untuk setiap Circuit Trotter:

evs = [res.data.evs for res in result]
print(evs)
[array(0.23799162), array(0.35754312), array(0.38649906)]

Seterusnya, kita gabungkan semula nilai-nilai itu dengan pekali MPF kita untuk menghasilkan nilai jangkaan keseluruhan MPF. Di bawah, kita buat begitu untuk setiap cara berbeza yang kita gunakan untuk mengira xx.

print("Analytical    solution:", evs @ coeffs_analytical)
print("Exact model solution:", evs @ coeffs_exact.value)
print("Approx. model solution:", evs @ coeffs_approx.value)
Analytical    solution: 0.3954847855980006
Exact model solution: 0.39548478559800204
Approx. model solution: 0.42991214253489807

Akhirnya, untuk masalah kecil ini kita boleh kira nilai rujukan tepat menggunakan scipy.linalg.expm seperti berikut:

from scipy.linalg import expm

exp_H = expm(-1j * time * hamiltonian.to_matrix())

initial_state = np.zeros(exp_H.shape[0])
initial_state[0] = 1.0

time_evolved_state = exp_H @ initial_state

exact_obs = time_evolved_state.conj() @ observable.to_matrix() @ time_evolved_state
print(exact_obs.real)
0.40060242487899755

Kita boleh nampak dengan jelas bahawa MPF telah mengurangkan ralat Trotter berbanding yang diperoleh dengan PF individu paling dalam dengan kj=19k_j=19. Namun, kita juga nampak bahawa model anggaran tidak sempurna kerana ia sebenarnya menghasilkan nilai jangkaan yang lebih buruk daripada penyelesaian tepat. Ini menunjukkan kepentingan menggunakan kriteria penumpuan yang ketat pada model anggaran seperti yang akan korang pelajari dalam panduan Cara guna model anggaran.