average_data関数を使う。
Qiskitでは任意オブザーバブルの期待値計算をする関数は与えられていません。
Z基底で測ったときの0,1の比率しか得られません。
すごく困ります。
しかしaverage_data(counts, observable)を”うまく”使うことで
Qiskitで任意オブザーバブルの期待値を計算できます。
ただし、average_data関数のhelpをよく見る必要があります。
average_data(counts, observable)
Compute the mean value of an diagonal observable.
Takes in a diagonal observable in dictionary, list or matrix format and then
calculates the sum_i value(i) P(i) where value(i) is the value of the
observable for state i.
Args:
counts (dict): a dict of outcomes from an experiment
observable (dict or matrix or list): The observable to be averaged over.
As an example, ZZ on qubits can be given as:
* dict: {"00": 1, "11": 1, "01": -1, "10": -1}
* matrix: [[1, 0, 0, 0], [0, -1, 0, 0, ], [0, 0, -1, 0], [0, 0, 0, 1]]
* matrix diagonal (list): [1, -1, -1, 1]
Returns:
Double: Average of the observable
また、以下のQAも参考になります。
https://quantumcomputing.stackexchange.com/questions/6940/how-to-calculate-an-expected-value-of-some-operator-acting-on-qubits
まず、average_dataで計算されるのは、基本的にはZ基底で対角化されたオブザーバブルを前提とした期待値です。
単純に、measureの結果として"0"が出れば固有値$\lambda_{0}$とし、"1"が出れば固有値$\lambda_{1}$としてカウントされ、最後にその平均が計算されます。
複数量子ビットの場合も同様です。(0,1の組み合わせが$2^{N}$通りであるので、固有値も$2^{N}$個指定します)
出力 = 固有値×その固有値の確率 の和 です。
average_dataの引数として任意の行列を入れることが出来ますが、実際には対角行列でなくては
意味がありません。(対角要素が自動的に固有値と解釈され、それ以外は無視されます。)
このような単純な計算で期待値が得られるためには、
オブザーバブルがZ基底で対角化されるようなものでなければなりません。
では、Z基底で対角化されないオブザーバブル、例えば$X$を計算するにはどうしたらいいでしょう?
答えは先のQAサイトにあるとおりなのですが、measureの前に、オブザーバブルを対角化するような基底に変換する演算子$U$を入れてやればよいです。
これは、オブザーバブルに対して(古典コンピューターなり手計算で)対角化をすることで求めましょう。。
つまり $X=U^{\dagger} \Lambda U$ を満たす$U$を見つければよいです。
すると$X$を対角化する基底での測定になっているので、対応する固有値(を、対角行列$\Lambda$として)をaverage_dataに教えてやればOKです。
例をやってみます。
https://qiita.com/YuichiroMinato/items/784afba41df7e5f2dbe5
によると、$X=HZH$らしいので、$X$は$H$による座標変換で対角化出来ます。固有値は(Zの対角要素を拾うと)1と-1です。
measureの前に$U=H$を入れてやって、測定します。0か1が得られます。0が得られた確率を$p$,1が得られた確率を$1-p$とすると、求める$X$の期待値は
$ \langle X \rangle = 1p + (-1)(1-p)$ となるはずです。
よって、U=Hを事前に入れた上で、 average_data(counts, $\Lambda=Z$) で出来るはずです。
このあたりも参考になります。
VQE/QAOAの期待値測定の部分を学ぶ
やってみる
やっていきましょう。
まず、当たり前ですがZの固有状態を生成して、それをaverage_data(counts,Z)で取ってみます。
# 必要なモジュールのインポート
from qiskit import IBMQ, QuantumCircuit, ClassicalRegister, QuantumRegister
from qiskit import execute, Aer
from qiskit.qasm import pi
from qiskit.tools.visualization import plot_histogram, circuit_drawer
import numpy as np
from qiskit.aqua.operators import WeightedPauliOperator
circuit = QuantumCircuit(1)
circuit.id(0)
circuit.measure_all()
from qiskit.quantum_info.analysis import average_data
backend = Aer.get_backend('qasm_simulator')
results = execute(circuit, backend, shots=1024).result()
counts = results.get_counts()
print(counts)
I_mat = np.array([[1, 0], [0, 1]])
Z_mat = np.array([[1, 0], [0, -1]])
X_mat = np.array([[0, 1], [1, 0]])
obs = Z_mat
expectation = average_data(counts, obs)
print(expectation)
もちろん、"0"のみが観測され、その期待値は 1 * (1024/1024) + (-1)*(0/1024) = 1 となります。
次に、$X$の固有状態$| + \rangle$ を生成して、$X$の期待値をaverage_dataで計算しようとしてみます。
期待値は1のはずですが・・・?
circuit = QuantumCircuit(1)
circuit.h(0)
circuit.measure_all()
obs = X_mat
ということで、正しく計算されません。
average_dataは、0*(478/1024)+0*(546/1024)という計算をしたと思われます。
X_mat = np.array([[0, 1], [1, 0]]) だからです。(対角成分以外は無視されている)
正しく使うには、measureの前に$U=H$を入れます。
そして、average_dataの引数としては$\Lambda=Z$を指定します。
すると、
とうまくいきます。
average_dataは、1*(1024/1024)+(-1)*(0/1024)という計算をしたと思われます。
結論
- Qiskitで任意オブザーバブルの期待値計算するには、対角化した上でaverage_data
- 関数の使い方に注意。