Japanese
言語
English
Japanese
Spanish

注釈

このページは docs/tutorials/sea_with_sampler.ipynb から生成されました。

Samplerを用いた分光固有値ソルバーアルゴリズム

このチュートリアルでは、分光学的固有値ソルバーアルゴリズム (SEA, arXiv:2202.12910) の簡単な例を実行して、柔軟な回路を Sampler primitive に送信する機能を示します。 SEAは、モデルハミルトニアンの量子シミュレーションに使用され、「プローブ」補助量子ビットをシミュレーションレジスターと相互作用させることによって機能します。 プローブ量子ビットのエネルギーが掃引され、シミュレーションハミルトニアンの固有値が、分光法の実験ツールと同様に、応答のピークまたはディップとして観察されます。 各点 (エネルギー) は異なる量子回路であるため、この手法は必要な回路の数に関して高価です。 Sampler は、必要な Parameter を渡して1つの回路だけを送信する柔軟性を備えています。

ローカル開発環境のセットアップ

このチュートリアルでは、Qiskit Runtime Service インスタンスが必要です。まだ実行していない場合は、これらの手順 に従ってセットアップします。

[1]:
# load necessary Runtime libraries
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Session

backend = "ibmq_qasm_simulator"  # use the simulator

シンプルなハミルトニアン・モデル

量子ビット上で動作する パウリX行列を考えてみましょう。

\[H_{\rm Pauli}/\hbar = \mu X\]

後に \(\mu\) を設定することもできますし、その値もスイープすることもできます。 SEA は、モデルパウリ (量子ビット) ハミルトニアンを使って、シミュレーション・レジスターと以下の式のプローブ量子ビット q0 の両方を含む、より大きな 「共鳴」 ハミルトニアンを構築することによって動作します。

\[H_{\rm res} / \hbar = -\frac{1}{2} \omega IZ + c XX + H_{\rm Pauli}/\hbar \otimes I\]

ここで、角周波数 \(\omega\) は、プローブ量子ビットのエネルギーに対応し、 \(c\) は、プローブ・量子ビットと、シミュレーション・レジスター ( この場合は q1 ) 内の量子ビット間の結合です。 \(I\), \(X\), および \(Z\) はパウリのスピン行列に対応し、それらの順序は動作する量子ビットを反映しています ( この表記はリトル・エンディアンです ) 。以下のコードでは、 \(\hbar \equiv 1\) に設定します。

Qiskit Opflowのツールを使用して SEA 回路を構成することができます。

[2]:
from qiskit.circuit import Parameter
from qiskit.opflow import I, X, Z

mu = Parameter("$\\mu$")
ham_pauli = mu * X
[3]:
cc = Parameter("$c$")
ww = Parameter("$\\omega$")

ham_res = -(1 / 2) * ww * (I ^ Z) + cc * (X ^ X) + (ham_pauli ^ I)

共鳴ハミルトニアンを時間発展させます。

[4]:
tt = Parameter("$t$")
U_ham = (tt * ham_res).exp_i()

時間発展演算子 \(U_{\rm ham}\) から、スズキ - トロッター展開を用いて、シミュレーションの離散時間ステップを実装した量子回路に変換します。 時間が短くなるほど(トロッターステップが多いほど)、量子回路をより正確にすることができますが、深さが長くなり、ノイズの多い量子ハードウェア上での実行時にエラーが発生する可能性があります。 次に、この回路を IBM バックエンドの基底ゲートに transpile (変換)し、プローブ・量子ビット q0 のみを測定します。

[5]:
from qiskit import transpile
from qiskit.circuit import ClassicalRegister
from qiskit.opflow import PauliTrotterEvolution, Suzuki
import numpy as np

num_trot_steps = 5
total_time = 10
cr = ClassicalRegister(1, "c")

spec_op = PauliTrotterEvolution(
    trotter_mode=Suzuki(order=2, reps=num_trot_steps)
).convert(U_ham)
spec_circ = spec_op.to_circuit()
spec_circ_t = transpile(spec_circ, basis_gates=["sx", "rz", "cx"])
spec_circ_t.add_register(cr)
spec_circ_t.measure(0, cr[0])
[5]:
<qiskit.circuit.instructionset.InstructionSet at 0x1273c9a00>
[6]:
spec_circ_t.draw("mpl")
[6]:
../_images/tutorials_sea_with_sampler_10_0.png

ここで、パラメーターを修正し、複数のポイント num_pts を使用して頻度をスイープするようにします。 モデルのハミルトニアン \(H_{\rm Pauli}\) の固有値は \(\pm \mu\) であるため、これらの数値を含む範囲を選択する必要があります。

Parameter キーと値は分離して、List 内の List に変換する必要があることに注意してください。 キーは、各回路内の Parameter を示します。 この場合、回路は1つしかないため、キーの List 内には1つの List が含まれます。 Parameter 値については、ww の値ごとに List があります。

[7]:
# fixed Parameters
fixed_params = {cc: 0.3, mu: 0.7, tt: total_time}
# Parameter value for single circuit
param_keys = list(spec_circ_t.parameters)

# run through all the ww values to create a List of Lists of Parameter value
num_pts = 101
wvals = np.linspace(-2, 2, num_pts)
param_vals = []
for wval in wvals:
    all_params = {**fixed_params, **{ww: wval}}
    param_vals.append([all_params[key] for key in param_keys])

sampler を呼び出す際には、実行したい回路を指す circuits のリストと、各回路のパラメーター値を指定します。

[8]:
with Session(backend=backend):
    sampler = Sampler()
    job = sampler.run(
        circuits=[spec_circ_t] * num_pts, parameter_values=param_vals, shots=1e5
    )
    result = job.result()

準確率を \(\langle Z \rangle\) に変換することにより、 \(Z\) の期待値を構築します。

[9]:
Zexps = []
for dist in result.quasi_dists:
    if 1 in dist:
        Zexps.append(1 - 2 * dist[1])
    else:
        Zexps.append(1)

簡単なチェックとして、Qiskit Opflowで正確な期待値を計算します。

[10]:
from qiskit.opflow import PauliExpectation, Zero

param_bind = {cc: 0.3, mu: 0.7, tt: total_time}

init_state = Zero ^ 2
obsv = I ^ Z
Zexp_exact = (U_ham @ init_state).adjoint() @ obsv @ (U_ham @ init_state)

diag_meas_op = PauliExpectation().convert(Zexp_exact)
Zexact_values = []
for w_set in wvals:
    param_bind[ww] = w_set
    Zexact_values.append(np.real(diag_meas_op.bind_parameters(param_bind).eval()))

そして、すべてをプロットすることにより、ピーク時のエネルギーが \(\pm \mu\) になることが示されます。

[11]:
import matplotlib.pyplot as plt

plt.style.use("dark_background")

fig, ax = plt.subplots(dpi=100)
ax.plot([-param_bind[mu], -param_bind[mu]], [0, 1], ls="--", color="purple")
ax.plot([param_bind[mu], param_bind[mu]], [0, 1], ls="--", color="purple")
ax.plot(wvals, Zexact_values, label="Exact")
ax.plot(wvals, Zexps, label=f"{backend}")
ax.set_xlabel(r"$\omega$ (arb)")
ax.set_ylabel(r"$\langle Z \rangle$ Expectation")
ax.legend()
[11]:
<matplotlib.legend.Legend at 0x12c286cd0>
../_images/tutorials_sea_with_sampler_20_1.png
[12]:
import qiskit_ibm_runtime

qiskit_ibm_runtime.version.get_version_info()
[12]:
'0.7.0'
[13]:
from qiskit.tools.jupyter import *

%qiskit_version_table

Version Information

Qiskit SoftwareVersion
qiskit-terra0.20.0
qiskit-aer0.10.3
qiskit-ignis0.7.0
qiskit-ibmq-provider0.18.3
qiskit0.35.0
System information
Python version3.9.10
Python compilerClang 11.1.0
Python buildmain, Feb 1 2022 21:27:48
OSDarwin
CPUs2
Memory (Gb)16.0
Mon Apr 11 16:17:45 2022 EDT