量子ビットによる条件分岐は並行世界への入り口か？

こんにちは｜こんばんは。カエルの姿で活動しています @kyamaz です。
~~昨年の [Advent Calender 2017](https://qiita.com/advent-calendar/2017/quantum) 以来、エントリを書くことがありませんでしたが、今年もこのイベントに参加します。[その１](https://qiita.com/advent-calendar/2018/quantum)でも記事を書く予定ですが、その２のリレーが早々に途切れてしまうのも悲しいので、急きょ読み物的なネタ記事を書いてみました。~~
すみません。参加を取り下げて、普通の記事として公開に変更します。

---
このエントリには「えっ？本当なの？」という所もあり、専門家から批判される恐れのある表現が一部含まれております。**“娯楽的に”** ご覧頂けると幸いです。[^10]

本記事の対象は、次のような方を想定しております。

|・量子コンピューターや量子プログラミングに興味がある方<br/>・基礎的なプログラミングの知識がある方<br/>・数式に極度のアレルギーのない方<br/>・量子コンピューターの仕組みや計算方法をなんとなくご存知の方|
|---|

---
では、はじめましょう。宜しくお願いします。

昨今、量子コンピューターに対する注目が集まっています。
そこで、ITエンジニアであれば「量子コンピューターをいち早く動かしたい」「プログラムを書いて量子計算と言われる計算をしていみたい」という欲求が湧いてくるのではないでしょうか。

少し調べれば、様々なライブラリがオープンソースで提供されおり、Python であれば、pip コマンドでそれらのライブラリをインストールして、すぐに利用できるようになります。そのチュートリアルや、最近充実してきた良質なブログ記事のエントリを頼りに、手元にあるPC上で動作する量子シミュレータ環境を使い、量子ビットに対してユニタリ演算子を作用させて測定するという、量子計算[^1]を試すことができます。さらに、無料アカウントを取得して、クラウド環境上にある量子コンピューターを動かすこともできます。

さて早速、本題です。
このように、量子計算においては、量子計算のライブラリが充実してきているように見えますが、**果たして、これらのライブラリは量子計算に適した記述形式を提供できているでしょうか？**

本稿では「量子ビットによる条件分岐」を考察することにより、量子計算におけるプログラミング言語の記述形式と、その動作について考えてみたいと思います。

# 量子ビットによる条件分岐
量子コンピューターに興味のある皆さんであれば、「量子ビットでは 0 と 1 が重ね合わされた状態を保持できる」というような話しを聞いたことがあると思います。量子ビットがもつ情報とは、確率的な 0 か 1 の情報であり、「測定する」[^2]とその内部の確率[^3]に応じて、0 か 1 のどちらかの情報に決定される（収束する）ような情報です。

ここで、この量子ビットの情報をもとに、条件式である `if` 文で判定して、プログラムの処理を分岐することを考えてみましょう。

例題として、次のような処理を考えます。

---
【例題】

* ２つの量子ビット $q_0, q_1$ を準備します。
* $q_0, q_1$ の状態を適当に操作します。（本稿ではこの操作には着目しません）
* $q_0$ の状態に応じて、次のように条件分岐します。  
  1. $q_0$ が $\lvert1\rangle$であれば、$q_1$ を反転します。（$q_1$にX演算子を施します）
  2. $q_0$ が $\lvert0\rangle$であれば、$q_1$ には何もしません。

---

この例題にある最後の条件分岐の部分を考えます。ソースコードで表現すると次のような記述になりそうです。

```python:【記述例１】量子ビットによる条件分岐（？）
if ( q0 == 1 ):
  q1 = X(q1) 
```

では、この`if ( q0 == 1 ) `について考えてみましょう。私たちはこの記述を見ると、この式がこの行で評価されて、`q0` の値が「 1 である」か「 1 でない」かの、二者択一ではあるものの、ここで “断定的な評価” ができると考えます。

この処理のイメージを量子計算に当てはめてみましょう。どうやら、私たちは「量子ビット `q0` を測定して、1 であるかどうかを見ている」ことを想定しているようです。つまり、`q0`を測定した値の 0 または 1 を古典ビットに置きます。その古典ビットを通して、通常私たちが良く知っている条件判定をしていることを意味しているようです。これを、擬似QASMで書くと次のような処理になりそうです。

```python:【コンパイル例１】条件分岐の処理は古典的？
qubit q0, q1;
bit c0;
# qubit の初期化や演算（操作）
# :
# :
c0 <- measure(q0);   # if文の評価のために、測定して値を確定する必要がありそう
if(c0 == 1) x(q1);   # 条件判定は QPU 上ではなく、CPU 上で行われるのでは？
```

脱線しますが、QPU と CPU を連携させてこの処理をどのようにハードウェアとして実装するかというのも、よく考えてみると、興味深い話題ではあります。ただ、ここでは量子プログラミング言語としての「記述形式」にだけ注目していきましょう。
【記述例１】のような、私たちにとって自然に思える条件式でも、量子プログラムでは確率的な情報を扱っているという量子計算の特性が色濃く関係しているようです。

この記述では、期せずして、測定という動作を伴ってしまいました。
そこで、例題を忠実に動作させるべく、量子計算っぽいプログラムの条件分岐の記述を改めて考えてみます。

量子状態をそのままに、測定もしないで、`if`文が書けるとします。単純なif文ではないので、ここで考える仮想的な量子プログラミング言語では、この記述形式を`qif`としましょう。例えば、（ブラケットも自然に記述できると仮定して、）次のような記述ができるとします。

```python:【記述例２】量子ビットによる条件分岐（仮想的な言語による）
qif ( q0 == |1> ):
  q1 = X(q1) 
```

さて、量子計算に当てはめてみると、この記述が表わす処理はどのような動作になるでしょうか。
`qif` のカッコの中の式の評価では、測定を行わないという約束を設けました。ですから、この行では確定的な評価ができません。つまり、ここでの $q_0$ の状態は、一般的に$\lvert0\rangle$ の複素確率が $ \alpha $ で、$\lvert1\rangle$の複素確率が $ \beta $ の重ね合わせ状態（ $ \alpha \lvert0\rangle + \beta \lvert1\rangle$ ）になっているとします。この`qif`文では、この量子状態のままで評価されなければなりません。

実は、この条件分岐に都合がよいユニタリ演算子があります。それは「制御ユニタリ演算子」と呼ばれる演算子です。

# 制御ユニタリ演算子

「制御ユニタリ演算子」とは、制御のための「制御ビット」とその制御ビットの状態に応じて、ユニタリ演算子 $U$ が作用する「被制御ビット」の２量子ビットに対するオペレータです。
仮に、制御ビットを $q_c$ として、被制御ビットを $q_a$ とし、$q_a$ の状態を $\lvert\psi\rangle$ とします。$q_c$ が $\lvert1\rangle$のときには $q_a$ には $U$ が作用して $U\lvert\psi\rangle$ となり、$q_c$ が $\lvert0\rangle$のときには $q_a$  には何も作業しないで $\lvert\psi\rangle$ のままになります。この制御ユニタリ演算子をテンソル積表記と行列で書くと、

$\begin{equation}
\left.\begin{aligned}
\lvert0\rangle\langle0\rvert \otimes \mathbb{1}+\lvert1\rangle\langle1\rvert \otimes U = \left( \begin{matrix}
\begin{matrix}
1 & 0 \\cr
0 & 1
\end{matrix}
& \begin{matrix}
0 & 0 \\cr
0 & 0
\end{matrix} \\cr
\begin{matrix}
0 & 0 \\cr
0 & 0
\end{matrix} & \Large{U} \\cr
\end{matrix} \right)
\end{aligned} \right.
\end{equation}$

のようになります。量子ゲート図では次のような量子回路です。

<img width="460" alt="controlledU.png" src="https://qiita-image-store.s3.amazonaws.com/0/136950/2fe2f65c-9473-cf32-e445-8e07a8654bb0.png">

この「制御ユニタリ演算子」で、量子計算で最もよく用いられるのは「制御NOT演算子（CNOT）」です。CNOTは、次の行列で表現されるオペレータです。

$\begin{equation}
\left.\begin{aligned}
CNOT = \left( \begin{matrix}
1 & 0 & 0 & 0 \\cr
0 & 1 & 0 & 0 \\cr
0 & 0 & 0 & 1 \\cr
0 & 0 & 1 & 0 \\cr
\end{matrix} \right)
\end{aligned} \right.
\end{equation}$

どのような制御ユニタリ演算子も、このCNOT演算子と、１量子ビットに作用するユニタリ演算子を組み合わせると、等価的に書きなおすことができます。そこで、CNOT演算子は量子計算の基本的な演算子の一つとされています。

いま私たちは、量子状態をそのままに、測定もしないで条件分岐する記述`qif`を考えていました。条件分岐のための判定には、制御ユニタリ演算子の制御ビットを使うと上手くいきそうです。そして条件を満たしたときの処理が、被制御ビットに対しての演算にうまくマッピングできれば、`qif`文は制御ユニタリ演算子そのものであると言えます。
偶然にも[^4]【記述例２】の例は、単にCNOT演算子を作用した量子計算にほかならないことがわかります。擬似QASMで書いてみると、次のように、とても簡単な処理にコンパイルされることになります。

```python:【コンパイル例２】量子的な条件分岐
qubit q0, q1;
# qubit の初期化や演算（操作）
# :
# :
cnot(q0, q1);   # 条件判定は QPU 上だけで行われる
```

ここで考察したように、量子計算ならではの処理を行おうとしたときには、従来のプログラミング言語にはない記述を使って、量子計算を記述することも必要になりそうです。すなわち、今までのプログラミング言語の枠組みだけでは、ネイティブな量子プログラムを記述するには、不十分なのかもしれません。ここに例を挙げた`qif`文のような新たな枠組みをもった「量子プログラミング言語」を考える必要がありそうです。[^11]

# 並行世界への入り口なのかもしれません

ここまでは「量子ビットによる条件分岐」を考えて、量子プログラミングの記述にまつわるお話しをしてきました。次に、この「量子ビットによる条件分岐のその後」について少し考えてみましょう。プログラムの記述を再掲します。下記の処理（★）で何が起きているかを軽く考察してみたいと思います。

```python:【記述例２（再掲）】量子ビットによる条件分岐（仮想的な言語による）
qif ( q0 == |1> ):
  q1 = X(q1) 
# :
# qif のあとの、ここの処理（★）を考える
```

`qif` 文では「条件が成り立ったとして処理が進む状態」と「条件が成り立たないで処理が進む状態」が確率的に処理されていきます。つまり、qif のあとの処理（★）では、プログラム自体が２つに分かれて進んでいて、その２つのプログラムが重なり合った状態と考えることはできないでしょうか。qif のあとは、まるで並行世界になり、計算が進んでいるかのように見えてきます。すなわち、これが「量子コンピューターは並列計算ができる」といわれている理由の一つかもしれません。

このようなファンタジーが量子計算で起きていると想像してみましょう。すると、枝分かれした条件分岐の数だけ、並行世界で計算された計算結果が得られ、量子コンピューターの並列処理の恩恵は絶大なパワーとなりそうです。
しかしながら、私たちはこの並行世界を体感することは、結局できないようです。qif のあとの処理（★）のどこかのタイミングで、その量子計算の様子を「測定」という行為を通じて、私たちはその状態を覗かなければなりません。覗かなければ、計算結果を得られないのが量子計算というものです。
そして、この「測定する」ときに、並行世界として処理が進んでいた量子プログラムは、そのプログラムが通ってきた全ての条件分岐の状態が、まるで遅延評価されたかのように決定されて、あたかも１つのプログラムが進行していたかのように状態が収束します。つまり、測定されなかったあらゆる可能性は、消え失せてしまうのです。

さて最後に、このような量子コンピューターでの量子計算は、果たして速いのでしょうか？果たして役に立つのでしょうか？

答えは「速くて役に立つ計算がある」のだそうです。ただ、それを理解するには、もう少し深く量子計算について知らなければならないようです。
この先に踏み込んでいろいろ勉強しているうちに、年を越してしまいそうです。本稿はこのあたりで話は終えたいと思います。

# （Postscript）ネタばらし／必ずお読みください
本稿の上記の表現には、<font color="red">決定的な誤りがあります。</font>それは、CNOT演算子があたかも並行計算に起因しているかのように述べられていることです。実は、並行計算の本質は、重ね合わせ状態にあります。その重ね合わせ状態をつくっていたのは、例題で「本稿ではこの操作には着目しません」と述べていた $q_0, q_1$ の状態を適当に操作したところで、その過程で、出来上がった状態に起因するものです。つまり、`qif`文の前に重ね合わせ状態になっており、CNOT演算は関係ありません。ただ、ここで「量子状態のまま条件判定する」という動作を考えたことにより、それ以前の重ね合わせ状態がクローズアップされたに過ぎないのです。

それでは、CNOT演算子に起因する本質は何でしょうか。それは「エンタングルメント（量子もつれ）」と呼ばれる概念が、この操作で出来上がることです。誤解を恐れずに表現すると、この演算のあと、２つの量子ビットが互いに影響し合って、切っても切れない関係になっています。これが、量子もつれです。

この「重ね合わせ」と「量子もつれ」は、量子計算には重要な概念です。その本質を正しく理解して、本稿にあるような<font color="red">**誤り(？)**も見分けられる</font>ようになりたいですね。


（●）（●）
/""　＿＿""＼ @kyamazは、オープンソース・コミュニティを通じて、皆さんと共にこういった知識を深めていければよいなぁ、と考えております。
ご興味がある方は、ぜひ一緒に知識を高めていきましょう。[^12]


[^1]: 量子計算については[去年のエントリ](https://qiita.com/kyamaz/items/4cc746cd94c1415be728)も参考にして頂けると嬉しいです。
[^2]: 計算基底での射影測定。例えば、Z基底での射影測定は、ブロッホ球の$\lvert0\rangle,\lvert1\rangle$軸への射影になります。
[^3]: 複素数で表される「複素確率」でその２乗が確率となります。
[^4]: 偶然ではなく、CNOTの演算を想定して、例題としてとりあげました。
[^10]: 本稿では、現在ある量子計算のためのライブラリの解説ではありません。仮想的な量子プログラミングでの表現の話しをします。あくまでフィクションですので、動作する環境等もありません。
[^11]: このような課題を解決するために、オープンソース・コミュニティ「OpenQLプロジェクト」[^12]を立ち上げ、そのコミュニティで議論しながら「量子プログラミング言語」や「量子コンパイラ」を開発していこうという活動をしております。
[^12]: OpenQLプロジェクトは、量子コンピューターを扱うための様々なライブラリを開発するためのオープンソースプロジェクトです。量子情報、量子コンピューターに興味がある人たちが集うコミュニティを運営しております。詳しくは[connpassのサイト](https://openql.connpass.com/)をご覧ください。