Qiskitには量子プログラム開発の高速化やデベロッパーエクスペリエンスを向上させるために、Qiskit Runtimeというツールを提供しています。
IBM Quantum ChallengeでQiskit Runtimeがトピックに取り上げられたこともあり、この記事ではQiskit Runtimeの初歩を紹介します。
Qiskit Runtimeとは
Qiskit Runtimeとは量子プログラム開発をよりシンプルに、そしてプログラムをより高速に実行するためのサービスです。
計算をより高速に
Qiskit Runtimeでは従来の方法よりも量子計算を高速化することが出来ます。
従来は命令を1回ずつハードウェアに送信していたため、繰り返し計算が必要なアルゴリズムではどんなに量子コンピュータを使って計算自体を高速化しても、結果を取得するまでの全体の時間は速くないことが起きえます。
- リクエストを量子コンピュータ側にデータを送信する時間
- 量子コンピュータ側でジョブがキューに格納されてから実行されるまでの順番待ち
例えばLiHのような小規模な分子シミュレーションでさえも、繰り返し計算数は数百万回必要とされていて、演算ごとのオーバーヘッドはボトルネックとなります。
Qiskit Runtimeでは量子回路の情報を含んだアルゴリズム全体を受け取ることで、開発者と量子コンピュータ間の長い通信の往復を解消し、アルゴリズムの高速な実行を可能としています。
Qiskit Runtimeにより量子化学アルゴリズムで120倍の高速化を実現したとの報告も上がっています。
アルゴリズム構築をより簡単に
また、Qiskit Runtimeでは「Qiskit Primitives(プリミティブ)」を提供しており、開発者はアルゴリズム開発をより簡単に行う事ができます。
プリミティブとは元々複雑なモノを構成する基本要素という意味を持ち、Qiskit Primitivesでは量子計算の主要処理を部品化して提供しています。こうすることでハードウェアの細かい特性を気にせずにアルゴリズムの開発に集中することが出来ます。
Qiskit Primitivesは現在2つの機能を提供しています。
- Sampler
量子回路の出力をサンプリングして確率分布を推定します。量子回路を設計する際に各データ点の確率分布を効率的に評価する場合に利用します。 - Estimator
関心のある演算子の期待値を計算します。演算子の期待値は多くの量子アルゴリズムで使われている量で、問題に対する最終的な解にのみ興味がある場合に有用です。
IBM Quantum Challengeから実装方法を学ぶ
Qiskit Runtimeの概要を理解したところで早速Qiskit Runtimeのプリミティブを使って実装してみましょう。
題材としてIBM Quantum Challenge2022 Fallのexcersise1のパラメータ化された量子回路を用いたデモを取り上げます。
IBM Quantum Challengeは手を動かしながらQiskit Runtimeを学ぶ事ができる教材として最適なのでぜひ一度取り組んでみてください。
サンプル量子回路の構築
Qiskit Runtimeを使うことで特にパラメータ化された量子回路の扱いが簡単になります。サンプル回路を構築していきましょう。
theta = Parameter('theta')
qc = QuantumCircuit(2,1)
qc.x(1)
qc.h(0)
qc.cp(theta,0,1)
qc.h(0)
qc.measure(0,0)
qc.draw("mpl")
この回路から出力される量子状態の理論値を計算すると以下のようになります。
|\psi\rangle=(\cos(\frac{\lambda}{2})|01\rangle-i\sin(\frac{\lambda}{2})|11\rangle)
パラメータの準備
Qiskit Runtimeを使って異なる位相パラメータをバインドして、全ての回路を実行させます。ここでは0から$2\pi$までを50等分して各点をパラメータの値とします。
phases = np.linspace(0, 2*np.pi, 50)
# Phases need to be expressed as list of lists in order to work
individual_phases = [[ph] for ph in phases]
Sampler
それではSmplerプリミティブを使って異なる位相パラメータをバインドした量子回路の出力の確率分布を求めていきます。
はじめにQiskit Runtimeで量子回路を実行するためには以下のステップが必要です。
実行結果から測定した1番目の量子ビットの状態が1である確率分布を取り出し、位相パラメータごとにプロットします。
出力される量子状態の理論値は上のようになるので、期待値は$\sin^2(\frac{\lambda}{2})$と計算できます。
# The probablity of being in the 1 state for each of these values
prob_values = [dist.get(1, 0) for dist in result.quasi_dists]
plt.plot(phases, prob_values, 'o', label='simulator')
plt.plot(phases, np.sin(phases/2,)**2, label='theory')
plt.xlabel('Phase')
plt.ylabel('Probability')
plt.legend();
黄色の実線は理論値で青の点が測定結果です。使用しているバックグラウンドのランダム性により理論値からばらつきがありますが、確率分布が理論値とほぼ一致していることが確認できました。
Estimator
EstimatorもSamplerとほぼ同様に実行可能です。ただし、Estimatorに用いる量子回路は測定の無い回路である必要がある点に注意が必要です。
ここでは先程の量子回路を使って演算子$ZZ$の期待値を求めてみましょう。
# 先ほどの回路から測定を取り除く
qc_no_meas = qc.remove_final_measurements(inplace=False)
# define target operator
ZZ = SparsePauliOp.from_list([("ZZ", 1)])
# 3steps
backend = service.backends(simulator=True)[0]
options = Options(simulator={"seed_simulator": 42})
with Session(service=service, backend=backend):
estimator = Estimator(options=options)
job = estimator.run(circuits=[qc_no_meas]*len(phases), parameter_values=individual_phases, observables=[ZZ]*len(phases))
実行結果から期待値を取り出し、位相パラメータごとにプロットします。理論値は上の計算結果から$2\sin^2(\frac{\lambda}{2}) -1$であることがわかります。
\begin{aligned} \langle ZZ\rangle &= \langle\psi| ZZ |\psi\rangle \\ &= |\langle00|\psi\rangle|^2 - |\langle01|\psi\rangle|^2 - |\langle10|\psi\rangle|^2 + |\langle11|\psi\rangle|^2 \\ &= -\cos^2(\frac{\lambda}{2}) + \sin^2(\frac{\lambda}{2}) \\ &= 2\sin^2(\frac{\lambda}{2}) -1 \end{aligned}
param_results = job.result()
exp_values = param_results.values
plt.plot(phases, exp_values, 'o', label='real')
plt.plot(phases, 2*np.sin(phases/2,)**2-1, label='theory')
plt.xlabel('Phase')
plt.ylabel('Expectation')
plt.legend();
こちらも理論値とほぼ一致する結果が得られました。
まとめ
この記事ではQiskit Runtimeの概要と実装方法について、IBM Quantum Challengeを題材に紹介しました。
今回は紹介できませんでしたが、Qiskit Runtimeを利用するとエラー緩和の機構を簡単に組み込む事ができる点が非常に大きなメリットです。
Quantum Challengeの後半ではエラー緩和に関するトピックが取り上げられているので別の記事で紹介していきます。
コメント