サンプルコードを見ていく。内容は単純で、
- ランダムな $\theta$, $\phi$, $\lambda$ で初期化されたユニバーサルゲート $U3(\theta, \phi, \lambda)$ だけからなる variational form について、
- $U3(\theta, \phi, \lambda) \ket{0} = \alpha \ket{0} + \beta \ket{1}$ が $0.48642994 \ket{0} + 0.51357006 \ket{1}$ を出力するような variational form になるように COBYLA オプティマイザで最適化した時、
- $\theta$, $\phi$, $\lambda$ はどういう値になっているか?
を確認するというものである。
from qiskit.aqua.components.optimizers import COBYLA
の部分は Qiskit 0.34.2 で動いているがいつ動かなくなるかあやしいので、
from qiskit.algorithms.optimizers import COBYLA
に変更しておく。
def get_var_form(params): qr = QuantumRegister(1, name="q") cr = ClassicalRegister(1, name='c') qc = QuantumCircuit(qr, cr) qc.u3(params[0], params[1], params[2], qr[0]) qc.measure(qr, cr[0]) return qc
も怒られたので、
qc.u(params[0], params[1], params[2], qr[0])
にする。UGate については UGate — Qiskit 0.34.2 documentation が参考になる。U3Gate とはゲートの分解が少し違うが論理的には等価である。
この改造を施して上から見ていく。
>>> print(target_distr) [0.51357006 0.48642994]
ここはシードを固定しているのでこういう値になる。
分布の近さは Manhattan 距離($L^1$ 距離)で見るということなので、何かしら離散的な分布 $p = \{p_i\}$ と $q = \{q_i\}$ があるとして距離は $\mathrm{dist}(p, q) = \sum_i |p_i - q_i|$ で測られる。
objective_function
の実装としては、variational form に 10000 ショット打って観測された分布と前述の target_distr
の $L^1$ 距離をとっている。
$U3$ ゲートの変数 $\theta$, $\phi$, $\lambda$ はランダムな値で初期化されて、
COBYLA オプティマイザが最適化するパラメータとして渡されている。
maxiter
は 2 や 3 でも近い時は近い値が出てくる。500 くらいだとまぁ安定しているが、10000 にしても滅茶苦茶近い値になるわけでもなかった。optimizer.optimize
の中で全部やってくれるようなので、まるで Keras を叩いているかのような心地だが、なんとなく雰囲気は分かったような気がする。
何度か適当に実行すると
Target Distribution: [0.51357006 0.48642994] Obtained Distribution: [0.5135, 0.4865] Output Error (Manhattan Distance): 0.049940118738839134 Parameters Found: [1.60055144 0.73234824 0.5787642 ]
が出た。
>>> print(counts) {'1': 5135, '0': 4865} >>> import math >>> print(math.cos(1.60055144/2)**2) 0.4851246386492849
なので、$\theta$ は正しそう。($\phi$ と $\lambda$ は観測に関係ないので実質ランダムな値のまま)