量子シミュレーション
Yukio Kawashima(2024年5月30日)
元の講義の PDF をダウンロード できます。コードスニペットは静的画像であるため、一部が非推奨になっている場合があります。
この実験を実行するおおよその QPU 時間は 7 秒です。
(このノートブックは、Qiskit Algorithms の現在は非推奨となったチュートリアルノートブックをもとにしています。)
1. はじめに
実時間発展の手 法として、トロッタリゼーション(Trotterization)は、あるタイムスライスにおけるシステムの時間発展を近似するように選ばれた量子ゲートを繰り返し適用することで構成されます。シュレーディンガー方程式から、時刻 に状態 にあるシステムの時間発展は次の形で表されます:
ここで はシステムを支配する時間非依存なハミルトニアンです。 と書けるハミルトニアンを考えます。 は 個の Qubit に作用するパウリ項のテンソル積を表します。これらのパウリ項は互いに交換する場合もあれば、しない場合もあります。 における状態が与えられたとき、量子コンピュータを用いて、後の時刻における状態 をどのように求めればよいでしょうか?演算子の指数関数はテイラー展開を通じて理解できます:
のような非常に基本的な指数関数は、コンパクトな量子ゲートのセットを用いて量子コンピュータ上で簡単に実装できます。ほとんどの興味深いハミルトニアンは単一の項だけではなく、多数の項を持ちます。 の場合に何が起こるか見てみましょう:
と が交換する場合、次のよく知られた式が成り立ちます(数値や変数 , でも同様です):
しかし、演算子が交換しない場合、テイラー展開の項を並べ替えてこのように簡略化することはできません。そのため、複雑なハミルトニ アンを量子ゲートで表現することは難しい課題となります。
一つの解決策は、時間 を非常に小さく取ることで、テイラー展開の一次項が支配的になるようにすることです。その仮定のもとで:
もちろん、より長い時間だけ状態を発展させる必要がある場合もあります。それには、このような小さな時間ステップを多数繰り返すことで実現します。このプロセスをトロッタリゼーションと呼びます:
ここで は選択 するタイムスライス(発展ステップ)です。その結果、 回適用するゲートが作成されます。タイムステップが小さいほど近似精度は高まりますが、同時に Circuit が深くなり、実際には誤差の蓄積が増大します(近代の量子デバイスでは無視できない問題です)。
今回は、 および サイトの線形格子上のイジングモデルの時間発展を調べます。これらの格子は、最近接のスピン どうしのみが相互作用するスピン配列から成ります。各スピンは と の二方向を取り得、それぞれ磁化 と に対応します。
ここで は相互作用エネルギーを、 は外部磁場の大きさ(上式では x 方向ですが、後で変更します)を表します。パウリ行列を用いてこの式を書き直し、外部磁場が横方向に対して角度 をなすとすると、
このハミルトニアンは外部磁場の効果を容易に研究できる点で有用です。計算基底では、系は以下のようにエンコードされます:
| 量子状態 | スピン表現 |
|---|---|
それでは、このような量子系の時間発展を調べていきます。特に、磁化などのシステムの特定の物理量の時間発展を可視化します。
1.1 必要条件
このチュートリアルを開始する前に、以下のパッケージがインストールされていることを確認してください:
- Qiskit SDK v1.2 以降 (
pip install qiskit) - Qiskit Runtime v0.30 以降 (
pip install qiskit-ibm-runtime) - Numpy v1.24.1 以降 < 2 (
pip install numpy)
1.2 ライブラリのインポート
MatrixExponential や QDrift など有用なライブラリも含まれていますが、このノートブックでは使用しません。時間があればぜひ試してみてください!
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-ibm-runtime
# Check the version of Qiskit
import qiskit
qiskit.__version__
'2.0.2'
# Import the qiskit library
import numpy as np
import matplotlib.pylab as plt
import warnings
from qiskit import QuantumCircuit
from qiskit.circuit.library import PauliEvolutionGate
from qiskit.primitives import StatevectorEstimator
from qiskit.quantum_info import Statevector, SparsePauliOp
from qiskit.synthesis import (
SuzukiTrotter,
LieTrotter,
)
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2
warnings.filterwarnings("ignore")
2. 問題のマッピング
2.1 横磁場イジングハミルトニアンの定義
ここでは 1 次元横磁場イジングモデルを考えます。
まず、システムパラメータ 、、、 を受け取り、ハミルトニアンを SparsePauliOp として返す関数を作成します。SparsePauliOp は、重み付きパウリ項を用いた演算子のスパース表現です。
def get_hamiltonian(nqubits, J, h, alpha):
# List of Hamiltonian terms as 3-tuples containing
# (1) the Pauli string,
# (2) the qubit indices corresponding to the Pauli string,
# (3) the coefficient.
ZZ_tuples = [("ZZ", [i, i + 1], -J) for i in range(0, nqubits - 1)]
Z_tuples = [("Z", [i], -h * np.sin(alpha)) for i in range(0, nqubits)]
X_tuples = [("X", [i], -h * np.cos(alpha)) for i in range(0, nqubits)]
# We create the Hamiltonian as a SparsePauliOp, via the method
# `from_sparse_list`, and multiply by the interaction term.
hamiltonian = SparsePauliOp.from_sparse_list(
[*ZZ_tuples, *Z_tuples, *X_tuples], num_qubits=nqubits
)
return hamiltonian.simplify()
ハミルトニアンの定義
ここでは例として、サイズ 、、、 のシステムを考えます。
n_qubits = 6
hamiltonian = get_hamiltonian(nqubits=n_qubits, J=0.2, h=1.2, alpha=np.pi / 8.0)
hamiltonian
SparsePauliOp(['IIIIZZ', 'IIIZZI', 'IIZZII', 'IZZIII', 'ZZIIII', 'IIIIIZ', 'IIIIZI', 'IIIZII', 'IIZIII', 'IZIIII', 'ZIIIII', 'IIIIIX', 'IIIIXI', 'IIIXII', 'IIXIII', 'IXIIII', 'XIIIII'],
coeffs=[-0.2 +0.j, -0.2 +0.j, -0.2 +0.j, -0.2 +0.j,
-0.2 +0.j, -0.45922012+0.j, -0.45922012+0.j, -0.45922012+0.j,
-0.45922012+0.j, -0.45922012+0.j, -0.45922012+0.j, -1.10865544+0.j,
-1.10865544+0.j, -1.10865544+0.j, -1.10865544+0.j, -1.10865544+0.j,
-1.10865544+0.j])
2.2 時間発展シミュレーションのパラメータ設定
ここでは、3 種類のトロッタリゼーション手法を考えます:
- Lie–Trotter(一次)
- 二次 Suzuki–Trotter
- 四次 Suzuki–Trotter
後の二つは演習と付録で使用します。
num_timesteps = 60
evolution_time = 30.0
dt = evolution_time / num_timesteps
product_formula_lt = LieTrotter()
product_formula_st2 = SuzukiTrotter(order=2)
product_formula_st4 = SuzukiTrotter(order=4)
2.3 量子 Circuit の準備 1(初期状態)
初期状態を作成します。ここでは のスピン配置から始めます。
initial_circuit = QuantumCircuit(n_qubits)
initial_circuit.prepare_state("001100")
# Change reps and see the difference when you decompose the circuit
initial_circuit.decompose(reps=1).draw("mpl")
2.4 量子 Circuit の準備 2(時間発展の単一 Circuit)
ここでは Lie–Trotter を用いて、単一タイムステップの Circuit を構築します。
Lie 積公式(一次)は LieTrotter クラスで実装されています。一次公式は、はじめに述べた近似から成り、和の行列指数関数を行列指数関数の積で近似します:
前述のとおり、非常に深い Circuit は誤差の蓄積を招き、現代の量子コンピュータにとって問題となります。2 Qubit ゲートは 1 Qubit ゲートよりもエラー率が高いため、特に注目すべき指標は 2 Qubit Circuit の深さです。実際に重要なのはトランスパイル後の 2 Qubit Circuit の深さです(量子コンピュータが実際に実行するのはそのCircuitだからです)。しかし、今はシミュレータを使う段階でも、この Circuit の演算数を数える習慣をつけておきましょう。
single_step_evolution_gates_lt = PauliEvolutionGate(
hamiltonian, dt, synthesis=product_formula_lt
)
single_step_evolution_lt = QuantumCircuit(n_qubits)
single_step_evolution_lt.append(
single_step_evolution_gates_lt, single_step_evolution_lt.qubits
)
print(
f"""
Trotter step with Lie-Trotter
-----------------------------
Depth: {single_step_evolution_lt.decompose(reps=3).depth()}
Gate count: {len(single_step_evolution_lt.decompose(reps=3))}
Nonlocal gate count: {single_step_evolution_lt.decompose(reps=3).num_nonlocal_gates()}
Gate breakdown: {", ".join([f"{k.upper()}: {v}" for k, v in single_step_evolution_lt.decompose(reps=3).count_ops().items()])}
"""
)
single_step_evolution_lt.decompose(reps=3).draw("mpl", fold=-1)
Trotter step with Lie-Trotter
-----------------------------
Depth: 17
Gate count: 27
Nonlocal gate count: 10
Gate breakdown: U3: 12, CX: 10, U1: 5
2.5 測定する演算子の設定
磁化演算子 と 平均スピン相関演算子 を定義します。
magnetization = (
SparsePauliOp.from_sparse_list(
[("Z", [i], 1.0) for i in range(0, n_qubits)], num_qubits=n_qubits
)
/ n_qubits
)
correlation = SparsePauliOp.from_sparse_list(
[("ZZ", [i, i + 1], 1.0) for i in range(0, n_qubits - 1)], num_qubits=n_qubits
) / (n_qubits - 1)
print("magnetization : ", magnetization)
print("correlation : ", correlation)
magnetization : SparsePauliOp(['IIIIIZ', 'IIIIZI', 'IIIZII', 'IIZIII', 'IZIIII', 'ZIIIII'],
coeffs=[0.16666667+0.j, 0.16666667+0.j, 0.16666667+0.j, 0.16666667+0.j,
0.16666667+0.j, 0.16666667+0.j])
correlation : SparsePauliOp(['IIIIZZ', 'IIIZZI', 'IIZZII', 'IZZIII', 'ZZIIII'],
coeffs=[0.2+0.j, 0.2+0.j, 0.2+0.j, 0.2+0.j, 0.2+0.j])
2.6 時間発展シミュレーションの実行
エネルギー(ハミルトニアンの期待値)、磁化(磁化演算子の期待値)、平均スピン相関(平均スピン相関演算子の期待値)を観測します。Qiskit の StatevectorEstimator(EstimatorV2)プリミティブは、オブザーバブルの期待値