@yuichirominato 2019.01.27更新 619views

【加算】10進数同士の足し算を量子ゲートで実装。


はじめに

量子コンピュータは2進数で計算しますが読みにくい、まだ2進数で消耗してるの?と言われるのも当然です。普通に10進数をやってみます。

一般化

こちらを使って一般化します。

https://blog.mdrft.com/post/2127

また、Carry,Sum,Carry_reverseもきちんと作ります。

carryなどつくる

最初に作ってしまいます。一番上の量子ビットの番号が決まればあとのも決まります。

from blueqat import Circuit

def carry(a):
    return Circuit().ccx[a+1,a+2,a+3].cx[a+1,a+2].ccx[a,a+2,a+3]

def carry_reverse(a):
    return Circuit().ccx[a,a+2,a+3].cx[a+1,a+2].ccx[a+1,a+2,a+3]

def sum(a):
    return Circuit().cx[a+1,a+2].cx[a,a+2] 

あとは使いたいときに足し合わせるだけです。

(carry(0)+carry(3)+Circuit().cx[4,5]+sum(3)+carry_reverse(0)+sum(0)).m[:].run(shots=100)

Counter({'0000000': 100})

これは1ビットの足し算回路。こんな感じで使います。

x = carry(0)+carry(3)+Circuit().cx[4,5]+sum(3)+carry_reverse(0)+sum(0)

(Circuit().x[1,4]+x).m[:].run(shots=100)                              

Counter({'0110110': 100})

こちらは1+2=3。入力はxゲートを適用します。

2進数を10進数に直す

使いにくいので直しちゃいます。

def tobinary(A):
    return bin(A)[2:] 

tobinary(10)                                                                                    
'1010'

足し算の桁数をそろえる

桁数を取得して桁数を合わせます。

def digits(a,b): 
     aa = tobinary(a)  
     bb = tobinary(b)  
     alen = len(aa)  
     blen = len(bb)  
     maxlen = max(alen,blen) 
     if alen>blen: 
         bb = bb.zfill(alen) 
     elif blen>alen: 
         aa = aa.zfill(blen) 
  
     str = '' 
     for i in range(maxlen): 
         str += '0' + aa[maxlen-i-1] + bb[maxlen-i-1] 
     str += '0' 
     return str

digits(2,2)                                                                                     
'0000110'

桁数に合わせてXゲートを適用

def tox(a): 
     cir = Circuit(len(a)) 
     for i in range(len(a)): 
         if a[i] == "1": 
             cir += Circuit().x[i] 
     return cir

tox("101").m[:].run(shots=100)                                                                  
Counter({'101': 100})

きちんと反映されてます。これらを組み合わせて、任意の10進数を入れるとXゲートが作動してデータが量子回路に準備されます。

#5と2
tox(digits(5,2)).m[:].run(shots=100) 

Counter({'0100010100': 100})

#70と90
tox(digits(70,90)).m[:].run(shots=1) 
Counter({'0000110100010010000110': 1})

これで10進数をいれて2進数の回路が上記の一般化加算器回路の通りに並びました。

求めた2進数を10進数に戻す

出た解は2進数ですので、10進数に直します。

def todecimal(A):
    return int(str(A),2) 

todecimal(10) 
2

なおりました。次に量子回路のabcの並び順からbを順番に取り出していきます。

#0000101からbを選ぶには、
def getb(result): 
     str = result[-1] 
     digi = int((len(result)-1)/3) 
     for i in range(digi): 
         str += result[-2-i*3] 
     return todecimal(str)

一般化回路

早速adder(とreverse adder)とsumを組みあわせて先ほどの入力を処理します。まずは最初のadderを実装します。adderはビット数に合わせて調整します。

def plus(a,b): 
     qubits = len(digits(a,b)) 
     cir1 = tox(digits(a,b)) 
     digi = int((len(digits(a,b))-1)/3) 

     cir2 = Circuit(qubits)     
     for i in range(digi): 
         cir2 += carry(i*3) 

     cir3 = Circuit(qubits).cx[-3,-2] + sum((digi-1)*3) 
  
     cir4 = Circuit(qubits) 
     for i in range(digi-1): 
         cir4 += carry_reverse((digi-i-2)*3) 
         cir4 += sum((digi-i-2)*3)
  
     result = (cir1 + cir2 + cir3 + cir4).m[:].run(shots=1) 
     return getb(result.most_common()[0][0])

ついにできた!

計算してみましょう

計算してみます

plus(2,2)
4

plus(13,15)
28

plus(70,90)
160

意外と計算時間かかりますが、全てゲートで加算器ができました!やってみてください。コード全体は下記です。

from blueqat import Circuit

#ビットのキャリー回路
def carry(a):
    return Circuit().ccx[a+1,a+2,a+3].cx[a+1,a+2].ccx[a,a+2,a+3]

#ビットのキャリー回路の逆
def carry_reverse(a):
    return Circuit().ccx[a,a+2,a+3].cx[a+1,a+2].ccx[a+1,a+2,a+3]

#ビットの合計
def sum(a):
    return Circuit().cx[a+1,a+2].cx[a,a+2] 

#10進数を2進数に
def tobinary(A):
    return bin(A)[2:] 

#2つの10進数を2進数に直して、桁を揃えて加算回路の順にビットを並べ替える
def digits(a,b): 
     aa = tobinary(a)  
     bb = tobinary(b)  
     alen = len(aa)  
     blen = len(bb)  
     maxlen = max(alen,blen) 
     if alen>blen: 
         bb = bb.zfill(alen) 
     elif blen>alen: 
         aa = aa.zfill(blen) 
  
     str = '' 
     for i in range(maxlen): 
         str += '0' + aa[maxlen-i-1] + bb[maxlen-i-1] 
     str += '0' 
     return str

#ビット文字列をXゲートを使ったデータ入力回路に変換
def tox(a): 
     cir = Circuit(len(a)) 
     for i in range(len(a)): 
         if a[i] == "1": 
             cir += Circuit().x[i] 
     return cir

#2進数を10進数に
def todecimal(A):
    return int(str(A),2) 

#加算回路から加算の結果のビット列だけを抜き出して結合
def getb(result): 
     str = result[-1] 
     digi = int((len(result)-1)/3) 
     for i in range(digi): 
         str += result[-2-i*3] 
     return todecimal(str)

#全てを組み合わせて加算回路に
def plus(a,b): 
     qubits = len(digits(a,b)) 
     cir1 = tox(digits(a,b)) 
     digi = int((len(digits(a,b))-1)/3) 

     cir2 = Circuit(qubits)     
     for i in range(digi): 
         cir2 += carry(i*3) 

     cir3 = Circuit(qubits).cx[-3,-2] + sum((digi-1)*3) 
  
     cir4 = Circuit(qubits) 
     for i in range(digi-1): 
         cir4 += carry_reverse((digi-i-2)*3) 
         cir4 += sum((digi-i-2)*3)
  
     result = (cir1 + cir2 + cir3 + cir4).m[:].run(shots=1) 
     return getb(result.most_common()[0][0])

まとめ

スーパーマリオメーカーやマインクラフトが得意な人なら量子コンピュータの汎用計算でやっていけると思います。僕より先に勉強会で実装されている方がいたので励みになりました。ありがとうございます。

Recommended


Wikiへ移動