はやし雑記

はやしです

Blueqatで量子コンピューター入門をしてみた(基本・半加算器)


\def\bra#1{\mathinner{\left\langle{#1}\right|}}
\def\ket#1{\mathinner{\left|{#1}\right\rangle}}
\def\braket#1#2{\mathinner{\left\langle{#1}\middle|#2\right\rangle}}

はじめに

GWに時間があったので、量子コンピューターについて少し勉強した。
理解を深めるため、Blueqatを触ってみた。

Blueqatとは

量子ゲート方式の量子コンピュータ回路をシミュレートするためのPythonライブラリ

github.com

(基本的な事)量子ビットと量子ゲート

Quantum logic gate - Wikipedia

 n量子ビットの状態は、 2^{n}次元のベクトルで記述することができる。

1量子ビットの場合:

\ket{a} = c_0 \ket{0} + c_1 \ket{1} \to
  \left(
    \begin{array}{c}
      c_0 \\
      c_1
    \end{array}
  \right)


\|c_0\|^2 + \|c_1\|^2 = 1

2量子ビットの場合:

\ket{ab} = \ket{a} \otimes \ket{b} = c_{00} \ket{00} + c_{01} \ket{01} + c_{10} \ket{10} + c_{11} \ket{11} \to
  \left(\begin{array}{c}
    c_{00} \\
    c_{01} \\
    c_{10} \\
    c_{11}
  \end{array}\right)


\|c_{00}\|^2 + \|c_{01}\|^2 + \|c_{10}\|^2 + \|c_{11}\|^2 = 1

 n量子ビットに作用する量子ゲートは、 2^{n} \times 2^{n}のユニタリー行列で表される。

例: 1量子ビットに作用するNOTゲート(いわゆるビットフリップ)

X = 
  \left(\begin{array}{cc}
    0 & 1 \\
    1 & 0
  \end{array}\right)


X \ket{a} = 
  \left(\begin{array}{cc}
    0 & 1 \\
    1 & 0
  \end{array}\right)
  \left(\begin{array}{c}
      c_{0} \\
      c_{1}
  \end{array}\right)
  =
    \left(\begin{array}{c}
      c_{1} \\
      c_{0}
  \end{array}\right)

Blueqatの使い方

from blueqat import Circuit

# 量子ビット数を指定しない回路
c = Circuit()

# 2量子ビットの回路
c = Circuit(2)

# 状態ベクトルを計算
c.run()
## array([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j])

# m[:]で全量子ビットの値を計算
c.m[:].run()
## array([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j])

# 第0ビットをアダマール変換
Circuit().h[0].run()
## array([0.70710678+0.j, 0.70710678+0.j])

# 観測すると波束が収束し、[1, 0]と[0, 1]が半々の確率で得られる
Circuit().h[0].m[:].run()
## array([1.+0.j, 0.+0.j])

# 1000回計算する
Circuit().h[0].m[:].run(shots=1000)
## Counter({'1': 505, '0': 495})

# 2回アダマール変換すると元に戻る
Circuit().h[0].h[0].run()
## array([1.+0.j, 0.+0.j])

# 観測すると波束は収束するのでダメになる
Circuit().h[0].m[0].h[0].run()
## array([0.70710678+0.j, 0.70710678+0.j])


アダマール変換を \ket{0}に作用させると、 \ket{0}, \ket{1} の重ね合わせ状態が得られる。


\frac{1}{\sqrt{2}}
\left(
  \begin{array}{cc}
    1 & 1 \\
    1 & -1
  \end{array}
\right)
\left(
  \begin{array}{c}
    1 \\
    0
  \end{array}
\right)
= \frac{1}{\sqrt{2}}
\left(
  \begin{array}{c}
    1  \\
    1
  \end{array}
\right)

Blueqatで半加算器を作る

量子コンピューター的な半加算器はトフォリゲートとCNOTゲートで実現できる。
第0, 1ビットが入力で、第2ビットが桁上り出力、第3が出力の、4量子ビットの回路とすると、以下のように組めば良い。

  • 第0, 1ビットをアダマール変換(h)
  • トフォリゲート(ccx)によって第0, 1ビットが両方とも1のとき、第2ビットを反転する
  • CNOTゲート(cx)によって、第0ビットが1のとき第3ビットを反転、第1ビットが1のとき第3ビットを反転する

f:id:hayashikunsan:20190503012616p:plain


入力と出力の関係は以下の表の通り。

0 1 2 3
0 0 0 0
0 1 0 1
1 0 0 1
1 1 1 0

Blueqatで実装すると、以下のようになる。

Circuit().h[0,1].ccx[0,1,2].cx[0,3].cx[1,3]
## array([5.00000000e-01+0.00000000e+00j, 0.00000000e+00+0.00000000e+00j,
##       0.00000000e+00+0.00000000e+00j, 2.77555756e-17+2.77555756e-17j,
##       3.92523115e-17-5.88784672e-17j, 0.00000000e+00+0.00000000e+00j,
##       0.00000000e+00+0.00000000e+00j, 5.00000000e-01-3.36731597e-18j,
##       0.00000000e+00+0.00000000e+00j, 5.00000000e-01-3.36731597e-18j,
##       5.00000000e-01+5.21438353e-17j, 0.00000000e+00+0.00000000e+00j,
##       0.00000000e+00+0.00000000e+00j, 0.00000000e+00+0.00000000e+00j,
##       0.00000000e+00+0.00000000e+00j, 0.00000000e+00+0.00000000e+00j])

# 1000回計算して0,1,2,3ビットを観測
Circuit().h[0,1].ccx[0,1,2].cx[0,3].cx[1,3].m[:].run(shots=1000)
## Counter({'1001': 236, '0101': 277, '0000': 244, '1110': 243})

対応表の通りの結果が得られた。