Qiskitで任意オブザーバブルの期待値計算をする方法

# 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 = 1*p + (-1)*(1-p)$ となるはずです。
よって、U=Hを事前に入れた上で、　average_data(counts, $\Lambda=Z$) で出来るはずです。

このあたりも参考になります。
[VQE/QAOAの期待値測定の部分を学ぶ](https://qiita.com/gyu-don/items/efbd66c691981d7185c5)

# やってみる
やっていきましょう。
まず、当たり前ですがZの固有状態を生成して、それをaverage_data(counts,Z)で取ってみます。

```python
#必要なモジュールのインポート
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)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/f9b0de78-42fc-dfdb-738f-ce5eb4bf866f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/6599a322-21b8-a94d-79d0-2df85af1f66d.png)

もちろん、"0"のみが観測され、その期待値は 1 * (1024/1024) + (-1)*(0/1024) = 1 となります。

次に、$X$の固有状態$| + \rangle$ を生成して、$X$の期待値をaverage_dataで計算しようとしてみます。
期待値は1のはずですが・・・？

```python
circuit = QuantumCircuit(1) 
circuit.h(0)
circuit.measure_all()
obs = X_mat
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/61604d88-7188-1c03-9444-b5081f17d0c1.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/62b72e94-ec4e-7797-14e8-6aacc4a85a74.png)

ということで、正しく計算されません。
average_dataは、0*(478/1024)+0*(546/1024)という計算をしたと思われます。
X_mat = np.array([[0, 1], [1, 0]])　だからです。（対角成分以外は無視されている）

正しく使うには、measureの前に$U=H$を入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/1a36802e-5f29-d202-5dbd-8d4a5a1592aa.png)
そして、average_dataの引数としては$\Lambda=Z$を指定します。
すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/7cad4fdc-7892-9423-4f66-1ba630568096.png)

とうまくいきます。
average_dataは、1*(1024/1024)+(-1)*(0/1024)という計算をしたと思われます。

# 結論
- Qiskitで任意オブザーバブルの期待値計算するには、対角化した上でaverage_data
- 関数の使い方に注意。