<jupyter_start><jupyter_text>たし算量子コンピュータには従来のコンピュータと同じ計算もできるという特徴があります。たし算の回路を確認します。  今回学ぶこと1. 量子ゲートを使って二進数のたし算を実装2. 量子の重ね合わせを使って1つの回路で複数のたし算  BlueqatのインストールpipからBlueqatをインストールします。<jupyter_code>!pip install blueqat<jupyter_output>Requirement already satisfied: blueqat in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (0.3.13)
Requirement already satisfied: numpy~=1.12 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from blueqat) (1.18.3)
Requirement already satisfied: scipy>=1.1.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from blueqat) (1.1.0)
[33mWARNING: You are using pip version 20.0.2; however, version 20.1 is available.
You should consider upgrading via the '/home/ec2-user/anaconda3/envs/python3/bin/python -m pip install --upgrade pip' command.[0m<jupyter_text>二進数のたし算たし算は桁上がりを実行するccxゲートと、位の足し合わせを実行するcxゲートを使います。今回はa+b=cdという二進数のたし算の量子回路を行います。今回はaとbの値によって4種類のたし算を実装します。それぞれのたし算は、0+0 = 00 => 0000  0+1 = 01 => 0101  1+0 = 01 => 1001  1+1 = 10 => 1110  となります。4量子ビットのビット列で表現し、前半の2量子ビットが入力値aとbで、後半の2量子ビットが出力値cとdです。aとbを入力する回路と、実際にたし合わせを実現する回路を別に作り、何度か使い回します。1のようなデータの入力はXゲートを使って0を反転させて実装します。 たし算の回路部分はこのようになります。*はコントロールビットです。```a ---*---*------- ab ---*---|---*--- b0 ---X---|---|--- c0 -------X---X--- d```aとbにXゲートを使ってデータを入れると、ccx回路で桁上がり、cx回路で位のたし合わせを行います。<jupyter_code>#ツールの読み込み
from blueqat import Circuit

#たし算部分を実現します。
adder = Circuit().ccx[0,1,2].cx[0,3].cx[1,3]
#0+0
(Circuit() + adder).m[:].run(shots=100)
#0+1
(Circuit().x[1] + adder).m[:].run(shots=100)
#1+0
(Circuit().x[0] + adder).m[:].run(shots=100)
#1+1
(Circuit().x[0,1] + adder).m[:].run(shots=100)<jupyter_output><empty_output><jupyter_text>このように、たし算が実装できました。  重ね合わせを利用したたし算ここで、Xゲートでデータを一つ一つ入れる代わりに、Hゲートを使ってたし算をしてみます。<jupyter_code>#Xゲートの代わりにHゲートを入力に使う
(Circuit().h[0,1] + adder).m[:].run(shots=100)<jupyter_output><empty_output><jupyter_text>アダマールゲートを利用すると4つのたし算が大体1/4ずつ答えとして出てきました。このように汎用たし算回路を作ると、重ね合わせ状態を利用した計算を実行できます。  もつれを利用したたし算次にHゲートの代わりにa+b=1となるたし算を量子のもつれを使って行ってみます。<jupyter_code>#01と10のもつれを作る
(Circuit().h[0].cx[0,1].x[0] + adder).m[:].run(shots=100)<jupyter_output><empty_output><jupyter_text>このように、入力値が01と10がもつれているので、この2つのたし算が約1/2ずつ出てきます。 --------  解説：回路の作成（１桁目）まずは上の1桁目から作成します。1桁目を見ると、0, 0, 0, 1 の順になっています。表で表すと以下になります。|X|Y|X+Yの2桁目||:-:|:-:|:-:||0|0|0||0|1|0||1|0|0||1|1|1|これを見ると CCXゲートと同じことがわかります。(CCXは入力の頭2つのビットが1ならば3番目のビットを反転させる)このことから入力が 11 の場合は以下の回路を考えることができます。上から2ビットを入力、残りの1ビットを出力だと考えると上の回路から 1 が出力されるのがわかります。  解説：回路の作成（２桁目）次にもう一つのくらいを作成します。2桁目を見ると、0, 1, 1, 0 の順になっています。表で表すと以下になります。|X|Y|X+Yの1桁目||:-:|:-:|:-:||0|0|0||0|1|1||1|0|1||1|1|0|これを見ると CXゲートと同じことがわかります。(左辺がCXの入力で右辺が出力の2番目のビット)このことから入力が 10 の場合は以下の回路を考えることができます。上から2ビットを入力、残りの1ビットを出力だと考えると上の回路から 1 が出力されるのがわかります。  解説：回路の作成（全体）最後に上の二つの回路をまとめます。入力を 00 としてまとめた回路を以下に示します。上2ビットを入力、残りの2ビットが出力です。始めの CCX は1桁目の部分で残りの 2つの CX は2桁目の部分です。  解説：重ね合わせ回路の実装量子の重ね合わせを用いると4パターンを一気に操作することができます。式としては以下の物を考えます。見てわかる通り右辺に入力の4パターンが出てきました。この性質を用いて実装します。回路は以下のようになります。今まで Xゲートを施していた部分を Hゲートにして 4パターンを作っています。  (応用) 一般の足し算一般の10進数同士で足し算を実装します。  $a, b$ の和を考えることとします。$a, b$ は $a = a_n ... a_0$, $b = b_n ... b_0$ と2進数で表示できます。  (ここで n は数が大きい方の位を基準とします。)回路は以下のようになります。$c_i$ を carry ビットと言って繰り上がった数を表します。  足し算回路は carry と呼ばれる繰り上がりの部分と sum の合計の部分にわかれています。まずはこの2つの部分を考察します。  繰り上がり回路は以下のようになります。回路を上から $c_i, a_i, b_i, c_{i+1}$ とすると $c_{i+1}$ に繰り上がりの部分が現れます。  合計各位の和を考えます。回路は以下のようになります。回路を上から $c_i, a_i, b_i$ とすると $b_i$ に3つの数の和の繰り上がりを除いた部分が現れます。  実装足し算回路を実装します。流れは以下のようになります。  1. carry 回路で各位の繰り上がりを求める。  2. CXゲートで最後のcarryの部分を元に戻す。  3. sum 回路で $b_n$ に各位の和を出力する。  4. carry の逆回路でその位の値を元に戻す。  5. sum 回路で $b_i$ に各位の和を出力する。  6. 4,5の繰り返し。以上の流れから $a+b$ は $b_{n+1} ... b_0$ の部分に出力されることが分かります。足し算回路を実装するために下準備をします。  まずは carry とその逆回路, sum 回路を作ります。<jupyter_code>from blueqat import Circuit

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

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

def sum(i):
    return Circuit().cx[i+1,i+2].cx[i,i+2]<jupyter_output><empty_output><jupyter_text>10進数を2進数にする関数も作っておきます。<jupyter_code>def tobinary(A):
    return bin(A)[2:]

tobinary(10)<jupyter_output><empty_output><jupyter_text>数を回路にマッピングする関数を作ります。<jupyter_code>def digits(a,b): 
     # 2進数に変換
     aa = tobinary(a)  
     bb = tobinary(b)  
     alen = len(aa)  
     blen = len(bb)  

     # nを決めて大きい方にビット数を合わせる
     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)<jupyter_output><empty_output><jupyter_text>回路の初期状態は全て0なので、マッピングした値に合うようにXゲートを施す必要があります。  この関数を作ります。<jupyter_code>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)<jupyter_output><empty_output><jupyter_text>最後に出力の部分を考えます。  まずは出力は2進数なので10進数に変換する関数を考えます。<jupyter_code>def todecimal(A):
    return int(str(A),2) 

todecimal(1001)<jupyter_output><empty_output><jupyter_text>回路では $a_i, b_i, c_i$ が混ざった値が出力されるのでその中で $b_i$ のみ取り出します。<jupyter_code>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)

getb("0000110")<jupyter_output><empty_output><jupyter_text>一般化回路以上で全ての準備が整ったので足し算回路を作ります。<jupyter_code>def plus(a,b): 
     # 2進数表示のマッピング
     qubits = len(digits(a,b)) 
     cir1 = toX(digits(a,b)) 
     digi = int((len(digits(a,b))-1)/3) 

     # 前半のcarry回路
     cir2 = Circuit(qubits)     
     for i in range(digi): 
         cir2 += carry(i*3) 

     # 最後の桁の処理
     cir3 = Circuit(qubits).cx[-3,-2] + sum((digi-1)*3) 

     # carryの逆回路とsum回路でbiに和を出力
     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])<jupyter_output><empty_output><jupyter_text>実際に計算してみます。<jupyter_code>plus(2,2)
plus(13,15)
plus(70,90)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1610305958132045, 'fraction_numerical': 0.052012882447665054, 'mean_word_length': 5.403092783505155, 'pattern_counts': {'":': 1, '<': 48, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '106672', 'license': 'Apache-2.0', 'n_tokens_mistral': 4254, 'n_tokens_neox': 3878, 'n_words': 340, 'path': 'tutorial-ja/100_adder_ja.ipynb', 'repo_name': 'tmdoi/Blueqat-tutorials', 'size': '6210'}