注釈
このページは 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行列を考えてみましょう。
後に \(\mu\) を設定することもできますし、その値もスイープすることもできます。 SEA は、モデルパウリ (量子ビット) ハミルトニアンを使って、シミュレーション・レジスターと以下の式のプローブ量子ビット q0
の両方を含む、より大きな 「共鳴」 ハミルトニアンを構築することによって動作します。
ここで、角周波数 \(\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]:

ここで、パラメーターを修正し、複数のポイント 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>

[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 Software | Version |
---|---|
qiskit-terra | 0.20.0 |
qiskit-aer | 0.10.3 |
qiskit-ignis | 0.7.0 |
qiskit-ibmq-provider | 0.18.3 |
qiskit | 0.35.0 |
System information | |
Python version | 3.9.10 |
Python compiler | Clang 11.1.0 |
Python build | main, Feb 1 2022 21:27:48 |
OS | Darwin |
CPUs | 2 |
Memory (Gb) | 16.0 |
Mon Apr 11 16:17:45 2022 EDT |