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

# 任意オブザーバブルの期待値を計算する
Qiskitで任意オブザーバブルの期待値を計算する方法は、以前の記事で記載しています。
ただし、色々と制約もあります。

- [average_dataを使う方法](https://qiita.com/notori48/items/0bdeba72b8010e800cc8)　→　$Z$基底で対角化されることを前提としている。（一般には別途座標変換が必要で、面倒）
- [Statevectorとexpectation_valueを使う方法](https://qiita.com/notori48/items/396d7148482e005ba507) →　状態ベクトルが必要。（実機では状態ベクトルは通常得られない）

今回は、色々調べてみて　「実機で使えて、かつコーディングが楽なもの」を探してみます。
使うのはqiskit.aqua です。

[2021/10/15]
qiskit.aquaが廃止になり別ライブラリに分岐していますので注意してください。
https://qiskit.org/documentation/aqua_tutorials/Qiskit%20Algorithms%20Migration%20Guide.html#QuantumInstance
import先が変わっています。

# qiskit.aquaによるオブザーバブルの期待値計算

QAサイトに答えがありました。が、一部typoがあるので修正したものを記載します。
https://quantumcomputing.stackexchange.com/questions/12080/evaluating-expectation-values-of-operators-in-qiskit

処理としては、おそらくaverage_dataを使う方法と同じです。
ただし座標変換が自動化されていますので、自分で書かなくていいです！

```python
pip install qiskit pylatexenc
#必要なモジュールのインポート
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 X, Y, Z, I
from qiskit.aqua.operators.state_fns import CircuitStateFn
op =  (-1.0523732 * I^I) + (0.39793742 * I^Z) + (-0.3979374 * Z^I) \
    + (-0.0112801 * Z^Z) + (0.18093119 * X^X)

# define the state you w.r.t. which you want the expectation value
# 期待値を計算する対象の状態ベクトルを作る。（＝量子回路出力）
circuit = QuantumCircuit(2)
circuit.x(0) 
circuit.x(1)
circuit.draw('mpl')
psi = CircuitStateFn(circuit) #量子回路出力の状態ベクトルを取得

```

ちょっと注意したいのが、量子計算は本来古典的に実行ができない規模の計算をするためのものです。
なので、CircuitStateFn(circuit)で状態ベクトルが取れることを前提にすべきなのか疑問です。
まぁ、それをいってしまうとシミュレーターで計算すること自体もそうなのですが。

続けます。

```python

from qiskit import Aer
from qiskit.aqua import QuantumInstance
from qiskit.aqua.operators import PauliExpectation, CircuitSampler, StateFn

# define your backend or quantum instance (where you can add settings)
backend = Aer.get_backend('qasm_simulator') #シミュレーターだが、実機でもOK
q_instance = QuantumInstance(backend, shots=1024) #測定手続きを定義

# define the state to sample
measurable_expression = StateFn(op, is_measurement=True).compose(psi) #オブザーバブルと状態ベクトルから、測定から期待値計算できるように準備する？

# convert to expectation value
expectation = PauliExpectation().convert(measurable_expression)  #パウリ積の線形和にする？

# get state sampler (you can also pass the backend directly)
sampler = CircuitSampler(q_instance).convert(expectation)  #実行結果から期待値を計算する（ここで座標変換を入れてから測定している？）

# evaluate
print('Sampled:', sampler.eval().real)  

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/a13c3826-b853-429d-86ea-2c0a34192da3.png)

実行のたびに値は変わります。
上記は実機でも実行できるはずです！
→実機(ibmqx2)で動くこと確認しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/d0197b2f-f7f1-59ee-d383-c1fa149012fa.png)


また、サンプリングではなく状態ベクトルベース？の期待値も計算できるそうです。
実行を何度やっても実行結果は同じです。


```python

from qiskit.aqua.operators.expectations import AerPauliExpectation, MatrixExpectation

# snapshot based expectation
expectation = AerPauliExpectation().convert(measurable_expression)
sampler = CircuitSampler(backend).convert(expectation)  
print('Snapshot:', sampler.eval().real) 

# Matrix based expectation
expectation = MatrixExpectation().convert(measurable_expression)
sampler = CircuitSampler(backend).convert(expectation)  
print('Matrix:', sampler.eval().real) 

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/07943be2-54a7-e071-586b-46109a03ebf6.png)

試していないですが、こっちはbackendとして実機を指定するとバグるかもしれません？
実機は確率的に動くわけですから、実行結果が毎回同じということはないはずです。

→　確かに、エラーで止められました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/b3a0e425-cb05-d761-3f9f-4a26ab4a0767.png)

このあたり、中で何が起こっているかわかっていないので、もっと勉強します。

# 結論
- 状態ベクトル（シミュレーターでしか得られない）だけでなく、
測定結果から任意オブザーバブルの期待値を計算する方法がわかった。

- 期待値測定の方法だけでもいろいろ種類があります。大事なのは、どんな状況で使えば正しい答えを得られるのかということです。現状、それを知るには内部をある程度勉強する必要があると思います。
例えば average_data 関数は対角化していなくても動いてしまいますが、正しい結果となりません。