量子コンピュータには高速性と汎用性があります。現在の量子コンピュータは少ない量子ビットを活用するために、汎用性は後回しにして高速性の検討をしています。しかし将来的なことを考えて汎用性も考えてみます。
まずは最新のBlueqatを使って足し算をやってみたいと思います。今回は工夫をして、|a,b> => |a,a+b>というように量子ビットを節約して加算を行なってみます。作る回路はまずは1ビットでやってみます。
0+0=0,1+0=1,0+1=1,1+1=2
を実装してみます。
入力a,入力b,入力c=0,出力a,出力a+b,出力桁上がりcとして、この順番で、
000000
010010
100110
110101
となればokです。回路は、コントロールゲート*の記号でターゲットゲートがXとなってcxとccx(トフォリ)を表現して
a --*--*-- a
b --*--X-- a+b
c --X----- c
Blueqatコードとしては、ccxとcxをつかい、
from blueqat import Circuit
a = Circuit().ccx[0,1,2].cx[0,1].m[:] #足し算回路
#000の入力
(Circuit() + a).run(shots=100)
Counter({'000': 100}) #出力も000
#100の入力
(Circuit().x[0] + a).run(shots=100)
Counter({'110': 100}) #出力は110
#010の入力
(Circuit().x[1] + a).run(shots=100)
Counter({'010': 100}) #出力は010
#110の入力
(Circuit().x[0,1] + a).run(shots=100)
Counter({'101': 100}) #出力は101
できました。これが、上から、
0+0=0
1+0=1
0+1=1
1+1=2
となりました。
大きくしてみます。1995年の有名な論文がありますので参考にします。
Quantum Networks for Elementary Arithmetic Operations
V. Vedral, A. Barenco, A. Ekert
(Submitted on 16 Nov 1995)
https://arxiv.org/abs/quant-ph/9511018
これが一般化された加算器です。図中のCarryとSumはこうなります。
a+bを実現しますが、$a_0*2^0+a_1*2^1+a_2*2^2,…+b_0*2^0+b_1*2^1+b_2*2^2,… = $のようにビットを使って計算をします。ビット数節約のために、bの値が上書きされて、a+bとなって出てきます。
a+bを考えますが、aもbも1量子ビットの場合の一般化は、4量子ビットを使って下記のようになります。*はコントロールビットを表します。a0とb0に数字を入れると、b0が上書きされて、|c0,a0,b0,b1> ==> |c0,a0,a0+b0,b1>となってでてきます。b2は桁上がりです。
c0 --?--------*--------*-- c0
a0 --?--*--*--|--*--*--|-- a0
b0 --?--*--X--*--X--X--X-- a0+b0
b1 --?--X-----X----------- b1
コードで書くと、
from blueqat import Circuit
a = Circuit().ccx[1,2,3].cx[1,2].ccx[0,2,3].cx[1,2].cx[1,2].cx[0,2].m[:]
(Circuit() + a).run(shots=100)
Counter({'0000': 100})
最初の?に何も入れないで実行すると、0000 -> 0000となります。これはあってます。0+0=0
(Circuit().x[1] + a).run(shots=100)
Counter({'0110': 100})
これもあってます、0100 -> 0110となって答えが01となっています。
(Circuit().x[2] + a).run(shots=100)
Counter({'0010': 100})
これもあっています。0010 -> 0010となり、0+1 = 01となります。
(Circuit().x[1,2] + a).run(shots=100)
Counter({'0101': 100})
これもあっています。0110 -> 0101となり、1+1 = 10となり、桁上がりに成功しています。
次に2量子ビット使ってみます。今度は7量子ビット使います。
c0 --?------*-------------*-------*- c0
a0 --?--*-*-|-------------|-*-*-*-|- a0
b0 --?--*-X-*-------------*-X-*-X-X- a0+b0
c1 --?--X---X-----*-----*-X---X----- c1
a1 --?--------*-*-|-*-*-|----------- a1
b1 --?--------*-X-*-X-X-X----------- a1+b1
b2 --?--------X---X----------------- b2
コードは、
a = Circuit().ccx[1,2,3].cx[1,2].ccx[0,2,3].ccx[4,5,6].cx[4,5].ccx[3,5,6].cx[4,5].cx[4,5].cx[3,5].ccx[0,2,3].cx[1,2].ccx[1,2,3].cx[1,2].cx[0,2].m[:]
(Circuit()+a).run(shots=100)
Counter({'0000000': 100})
00+00=000
次に、例えば、3+3 = ?をすると、
(Circuit().x[1,2,4,5]+a).run(shots=100)
Counter({'0100111': 100})
11+11 = 110これにより3+3=6
これは全加算器が一般化されているので、どんどん上に拡張していくことで大きな数を実装することができます。
ちなみに回路を逆に組むことで減算ができます。
いまの2ビット回路を組んで、4-2をしてみます。これは先ほどの回路を逆にするだけです。
コードは、
a = Circuit().cx[0,2].cx[1,2].ccx[1,2,3].cx[1,2].ccx[0,2,3].cx[3,5].cx[4,5].cx[4,5].ccx[3,5,6].cx[4,5].ccx[4,5,6].ccx[0,2,3].cx[1,2].ccx[1,2,3].m[:]
(Circuit().x[4,5,6]+a).run(shots=100)
Counter({'0000101': 100})
こうなりました。a1=1となり、4-2=2となりました。b2の桁上がりは逆算できないようでしたのでこれは自分で0にしないといけないかもしれません。
まずHゲートを使ってみます。足し算が重ね合わせを使うので答えがどれが出るかわかりません。
a = Circuit().ccx[1,2,3].cx[1,2].ccx[0,2,3].ccx[4,5,6].cx[4,5].ccx[3,5,6].cx[4,5].cx[4,5].cx[3,5].ccx[0,2,3].cx[1,2].ccx[1,2,3].cx[1,2].cx[0,2].m[:]
(Circuit().h[1,2,4,5]+a).run(shots=100)
Counter({'0100101': 8,
'0100111': 6,
'0000101': 7,
'0010110': 7,
'0110010': 10,
'0010000': 8,
'0000000': 6,
'0000010': 5,
'0000110': 6,
'0010010': 7,
'0110101': 8,
'0100001': 5,
'0100010': 5,
'0110110': 7,
'0110000': 3,
'0010101': 2})
このように重ね合わせを使ってたくさんの足し算をすることができました。答えは100回計算してばらつきを見ました。
簡単に加算をみてみました。これを使ってモジュロ演算もできます。次回はモジュロ演算も見てみたいと思います。また、2進数表示のままだったので、次回は10進数に直してみやすくしておきます。以上です。
Tweetinfo@mdrft.com