量子コンピュータで行う論理演算(1)
先日QuantumChallengeに参加してみていくつか感じたことの一つに
「問題設定が与えられた後、それを量子回路に対応させることが難しい」
ということがあります。
現状の量子計算はアカデミア要素が強いせいもあってか参考になる記事も少なく、自分で考えるということが強く求められるフェーズのプログラミングだと感じました。
論文や有名なアルゴリズムを実装してみたという記事はいくつか見つかりましたが、どうしてそのように量子回路を組むのかまではまだ踏み込めていない印象です。
つまり、数理的な素養やもともと量子計算・量子情報処理に関わっている・いたという人はいくらか苦労した上でプログラミングできるけど、そうでない人には敷居が高いと感じました。
というわけで、自分の勉強も兼ねて量子回路を書くためのテクニック集的なものをこれから書いていこうと思います。
量子情報処理が専門でない人でこれから量子計算始めたいという人が少しでもプログラミングできるようになる助けになれば幸いと思います。
今回はQuantumChallengのweek1Aで解説がされていた、量子ゲートと論理演算との対応についていくつか解説します。
対象とする読者
- 量子プログラミングに興味を持ち始めたばかりのエンジニア
- 量子計算に興味を持ち始めたばかりの高校生・大学生 など
前提とする知識(簡単に解説はします)
- 論理演算(AND, OR, NOT)が分かること
- 基本的な量子ゲート(X, CNOT, CCNOTなど)が分かること
お断り
僕は基本Qiskitしか使わないので解説ソースもQiskitで書きます。
Q#やIonQなど他の言語・フレームワーク・ハードウェアに興味ある人には申し訳ないですが、考え方は共通していると思うのでご参考程度に、ということでお願いします。
バージョン情報
- Python 3.7.3
- Qiskit 0.23.1
目次
論理演算とは
2つないし複数の論理値(日本語で真/偽、Boolean型でいうところのTrue/False)を組み合わせて計算すること。
プログラミングでは主にif文の条件式で用いることで、処理の条件分岐を行います。
量子計算でも計算途中で条件分岐をすることが発生します。(今度紹介しますが加算器などの計算するにも根本的には条件分岐です。)
でも量子回路上にはif文は存在しないので、量子ゲートを組み合わせて実現します。
論理演算と量子ゲートの対応
古典NOTゲートとXゲート
NOTゲートというのは「○○でない」という元の「○○である」を否定することです。
通常のプログラミングだと、例えば性別フラグ・男性フラグis_man
などをBoolearn型で用意して、顧客データの集計などすることを想像してみてください。
あえてフラグの男女を反転させるとこういうケースです。
if not is_man: cnt_woman += 1 else: cnt_man += 1
古典NOTゲートは量子ゲートではXゲートが対応します。
qr = QuantumRegister(1, 'input') cr = ClassicalRegister(2) qc = QuantumCircuit(qr, cr) qc.measure(qr, cr[0]) qc.x(qr) qc.measure(qr, cr[1]) qc.reverse_bits() qc.draw(output='mpl')
この測定結果の分布は下記です。
Xゲートの性質を考えればその通りですが、入力が状態に対して出力は状態になっています。
測定結果のビットの並びは測定順と逆順で、左側がXゲート通過後で右側がXゲート通過前です。
(量子回路に書いてある測定の番号が若い順に文字列の右側から表示されます)
なお、量子ビットの状態はで初期化されているので、何らかの理由で状態を使いたい場合にもXゲートを使います。
以降の説明でもこの手法を多用します。
古典ANDゲートとCCNOT(CCX)ゲート
ANDゲートとは「AかつBである」と二つの条件の両方が満たされていることを示すものです。 例えば、性別ごとに職業を集計する時などでしょうか。
if is_man and is_sport_player: cnt_man_sport += 1 elif is_man and is_engineer: cnt_man_engineer += 1 elif is_woman and is_sport_player: cnt_woman_sport += 1 elif is_woman and is_engineer: cnt_woman_engineer += 1 (以下略)
古典ANDゲートにはCCNOT(CCX)ゲート(2つのコントールビットがともに状態であればターゲットビットの状態の0/1を反転する)が対応します。
CCNOTゲートの2つのコントロールビットを量子AND回路の入力、そしてCCNOTゲートのターゲットビットを量子AND回路の出力(論理演算した結果)に対応させます。
「AかつBである」のAは入力1の状態が1(BooleanでいうところのTrue)でBは入力2の状態が1に対応します。
qr_input = QuantumRegister(2, 'input') qr_output = QuantumRegister(1, 'output') cr = ClassicalRegister(3) qc = QuantumCircuit(qr_input, qr_output, cr) qc.ccx(qr_input[0], qr_input[1], qr_output) qc.measure(qr_input, cr[:2]) qc.measure(qr_output, cr[2]) qc.reverse_bits() qc.draw(output='mpl')
この結果は下記に示すように、ターゲットビットは0
のままです。
コントロールビットである2つの入力がともに0
だからですね。
他のパターンは以下になります。(コードと入力が10
の場合は省略します。)
最後の入力が11
の場合のみ、ターゲットビットの状態が1
になっていますね。
「入力1が1(True)でかつ入力2が1(True)」であることが示されたということです。
古典XORゲートとCNOT(CX)ゲート
XORゲートとは「AとBのどちらかが一方のみがTrueである場合」を示します。 例えば会社の部署の人数を集計する時に、兼務を除きたい場合です。
if (dept_A or dept_B) and not (dept_A and dept_B): if dept_A: cnt_only_A += 1 else: cnt_only_B += 1
古典XORゲートはCNOT(CX)ゲートを2つ組み合わせた量子回路が対応します。
qr_input = QuantumRegister(2, 'input') qr_output = QuantumRegister(1, 'output') cr = ClassicalRegister(3) qc = QuantumCircuit(qr_input, qr_output, cr) qc.cx(qr_input[0], qr_output) qc.cx(qr_input[1], qr_output) qc.measure(qr_input, cr[:2]) qc.measure(qr_output, cr[2]) qc.reverse_bits() qc.draw(output='mpl')
この状態の分布は下記で、入力どちらの状態も0なので出力も0です。
その他のパターンは以下になります。
最後の入力が11
の場合は出力が0
になっており、古典XORと同じ挙動になっていますね。
古典ORゲートとCNOT(CX)ゲート・CCNOT(CCX)ゲートの組み合わせ
ORゲートは「AとBのすくなくともどちらかTrueである場合」を示します。
XORと異なり、兼務を含めて集計する場合が相当します。
if (dept_A or dept_B): cnt_AorB += 1
古典ORゲートはCNOT(CX)ゲート2つとCCNOT(CX)ゲート1つを組み合わせた量子回路が対応します。
qr_input = QuantumRegister(2, 'input') qr_output = QuantumRegister(1, 'output') cr = ClassicalRegister(3) qc = QuantumCircuit(qr_input, qr_output, cr) qc.cx(qr_input[0], qr_output) qc.cx(qr_input[1], qr_output) qc.ccx(qr_input[0], qr_input[1], qr_output) qc.measure(qr_input, cr[:2]) qc.measure(qr_output, cr[2]) qc.reverse_bits() qc.draw(output='mpl')
量子XOR回路と異なるのは、最後にCCXゲートがあることで入力が11の場合に2つのCXゲートを通ってターゲットビットの状態が0
-> 1
-> 0
と変化した後、改めてターゲットビットを反転して1
になることです。
上記の回路の分布は下記で、やはり入力がともに0なので出力も0です。
その他のパターンは以下になります。
最後の入力が11
の場合に出力が1
になっており、古典ORと同じ挙動になっていますね。
古典NANDゲートとCCNOT(CCX)ゲート
NANDゲートとは「AかつB以外の場合」を示します。 例えば、男性のスポーツ選手以外の人数(男性でスポーツ選手以外の人数 + 女性)を集計する場合などです。(あくまで例なのでこういう集計をする状況があるかは分かりません)
if not (is_man and is_sport_player): cnt_not_man_and_sport += 1
古典NANDにはCCNOT(CCX)ゲートのターゲットビットにXゲートを組み合わせた量子回路が対応します。
qr_input = QuantumRegister(2, 'input') qr_output = QuantumRegister(1, 'output') cr = ClassicalRegister(3) qc = QuantumCircuit(qr_input, qr_output, cr) qc.x(qr_output) qc.ccx(qr_input[0], qr_input[1], qr_output) qc.measure(qr_input, cr[:2]) qc.measure(qr_output, cr[2]) qc.reverse_bits() qc.draw(output='mpl')
量子ゲートそのものはそれぞれの量子ビットの状態を操作することなので、行いたい演算の結果がその通り得られるならターゲットビットにもXゲートをかけていいのです。 (かけちゃいけないというルールもない)
この結果は下記で、入力が00
の場合は「AでなくBでもない」ので「AかつB以外の場合」に含まれておりNANDの結果はTrue
です。
実際に出力は1
になっています。
その他のパターンは以下になります。
最後の回路でNANDの特徴である、入力がともに1
の時は出力が0になっていて「AかつBの場合」は「AかつB以外の場合」にふくまれていないことが示されています。