Q#で１＋１を行う


プログラムを書き初めてあまり経っておらず量子コンピュータの知識もなかったのですが、Q#で何か書きたいと思い量子ビットについて少し勉強して、量子ビットを用いて１＋１の計算を実行できるようにしました。

※完全に理解しているわけではないので表現などが間違っているかもしれません。

#基礎知識
[量子計算基礎.pdf](http://www.quest.is.uec.ac.jp/q-school/2010/archive/量子計算基礎.pdf)
このPDFファイルには量子回路の基礎知識がのっています。知識がない人でも分かりやすいと思います。これを見て論理ゲートについて勉強しました。
また、この後の説明を理解するには論理回路の知識が必要です。

#量子ビット
量子ビットは$α|0\rangle+β|1\rangle$で表されます。これはこの量子ビットを観測したとき$|\alpha|^2$の確立で0に、$|\beta|^2$の確立で1になるという事を表しています。量子ビットの値が必ず1になるときは$|1\rangle$、0になるときは$|0\rangle$と書きます。今回はこの$|1\rangle$と$|0\rangle$しか用いず、量子ビットの特徴である重ね合わせになっている状態ついては考えません。

#量子ゲート
量子ゲートとは古典コンピューターにおけるAND,OR,NOTのようなもので、量子計算を行うときに使います。
今回はMゲート、Xゲート、CNOTゲートについてのみ簡単に説明します。詳しい仕組みや他のゲートは上記のPDFファイルにのっています。

- **Mゲート**

量子ビットを観測するゲートです。これを通さないと量子ビットの値は見れません。

- **Xゲート**

Xゲートは量子ビットを反転させることができます。例えば$|0\rangle$が入力されれば出力される値は$|1\rangle$に、$|1\rangle$が入力されれば$|0\rangle$が出力されます。論理回路でいうNOTのような役割です。

- **CNOTゲート**
![cnot.png](https://qiita-image-store.s3.amazonaws.com/0/245110/f9090dbc-5e8d-814c-b8dd-bee47fa5b667.png)
$x=0$のときは$y$に変化はなく、$x=1$のときは$y$が反転します。例えば、$x=1$,$y=1$のとき$y$は反転するので$|0\rangle$に、$x=0$,$y=1$のとき$y$に変化はないので$|1\rangle$になります。


#論理回路から量子回路へ
まず、量子回路ではなく論理回路で１＋１を行うときの図を見ます。この回路では$A=1$、$B=1$のときに１＋１の計算結果が出力されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/245110/0b58c997-3bf5-dd41-5749-2d7f7bbba72a.png)

- 真理値表

|A | B | S | C | 
|:--|--:|:-:|:-:|
| 0 | 0 | 0 | 0 |
| 1 | 0 | 1 | 0 |
| 0 | 1 | 1 | 0 |
| 1 | 1 | 0 | 1 |


これは半加算器と呼ばれるもので、繰り上りを考慮しない2進数1桁の加算ができます。Aに１を、Bに１を入れると、Sに０が、Cに１が出力されます。つまり２進数で10という値(Cが2桁目でSが1桁目)が得られるという事なので、１０進数に直すと２となります。

これを、量子回路に変換したものが下の図です。この図は、$a=|1\rangle$、$b=|1\rangle$の時の結果を表しています。
![kairo3.png](https://qiita-image-store.s3.amazonaws.com/0/245110/86afa20d-ae9b-775b-9f23-0601f112948d.png)


ここで使われているのはCNOTゲートとCCNOTゲートです。
上の論理回路と比較して説明します。まず最初にa,bと一番下の常に$|0\rangle$となる部分をCCNOTゲートでつなげている部分が論理回路のAND回路の部分にあたります。aとbの値が両方$|1\rangle$の時にだけ下の$|0\rangle$が$|1\rangle$になります。a,bの側に変化はありません。そしてその次、a,bをCNOTゲートに通している部分が、論理回路のXOR回路の部分にあたります。ここでは、bはaとbの値が同じときは$|0\rangle$になり、違うときは$|1\rangle$になります。aの側は、どちらの場合も変化はありません。この回路のbがCNOTゲートを通った後のbの値が論理回路の図のSに、０がCCNOTゲートを通った後の値がCにあたります。なので、この二つの部分をMゲート（量子ビットの観測を行う）に通し１か０かを判別すれば、計算が可能になります。この回路で１＋１を行うには、$a=|1\rangle$、$b=|1\rangle$にすればいいです。
#コード
まずは`.qs`ファイルの方から。
Q#では`mutable`で可変変数を、`let`で不変定数を定義します。`mutable`で定義した変数には`set`を使って数値を代入します。

```cs:harfadd.qs
namespace Quantum.harfadd
{
    open Microsoft.Quantum.Primitive;
    open Microsoft.Quantum.Canon;

    operation Set (desired: Result, q1: Qubit) : ()
    {
        body
        {
            let current = M(q1); // M(q1):q1キュービットの観測値を返す
            if (desired != current)
            {
                X(q1); // Xゲートによりq1キュービットを反転する
            
			}
        }
    }

	operation Hadd(q1 : Result, q2 : Result) : (Int)
	{
		body{
			mutable result = 0;    //結果をここに入れる
			using(qubits = Qubit[3])
			{
				Set(q1, qubits[0]);   //上の量子回路のaにあたる
				Set(q2, qubits[1]);   //bにあたる
				Set(Zero, qubits[2]); //0にあたる
				CCNOT(qubits[0],qubits[1],qubits[2]);  //a,b,0をCCNOTゲートに通す
				let c = M(qubits[2]);   //0がCCNOTゲートを通った後の観測値をcに代入、２桁目にあたる。
				if(c== One){
					set result = result + 2; //桁上がりがあり、２桁目が１ということなので１０進数では２
				}
				CNOT(qubits[0],qubits[1]);  //a,bをCNOTゲートに通す
				let s = M(qubits[1]);    //bの観測値をsに代入、１桁目にあたる
				if (s == One){
					set result = result + 1;  //一桁目が１ということなので１０進数では１
				}
				Set(Zero,qubits[0]);
				Set(Zero,qubits[1]);
				Set(Zero,qubits[2]);
			}
			return (result);
		}
	}

```
`Set`で必要な量子ビットを作成します。観測した量子ビットが必要としている値ではなかったときに、Xゲートを通して反転させて必要な値を得ています。
`Hadd`が今回の目的である１＋１を行う部分です。`Hadd`の引数は二つで、ここの値が両方`One`($|1>と考えていい$)のときに、１＋１の計算結果が出ます。ほかにも、０＋０、１＋０，０＋１ができます。中身を見ていきます。まず`Set`で必要な量子ビットを用意します。それを上で説明した量子回路の図通りにCCNOTゲート、CNOTゲートに通していきます。CCNOT( )、CNOT( )は引数の最後が図の$\oplus$がある列になっているようです。にゲートに通した後の量子ビットの値をMゲートに通して観測値を`let`で宣言した`c`,`s`に代入します。その値を見て`result`に数値を代入します。
１＋１が行われるとき`s`は`Zero`、`c`は`One`となるはずです。

では次は`.cs`ファイルの方のコードです。

```Driver.cs
using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Simulators;

 namespace Quantum.harfadd
{
    class Driver
    {
        static void Main(string[] args)
        {
            using (var sim = new QuantumSimulator())
            {
                var zero = Result.Zero;  //|0>
                var one = Result.One;    //|1>
                var res = Hadd.Run(sim, one, one).Result; //１＋１を実行
                var answer = res;
                System.Console.WriteLine($"answer:{answer,-4}");    //結果を表示
            }
            System.Console.WriteLine("Press any key to continue...");
            System.Console.ReadKey();
        }
    }
}
```
#実行結果
![kekka.png](https://qiita-image-store.s3.amazonaws.com/0/245110/3d99b957-ce76-999c-109e-476f4ebbfdb7.png)
１＋１＝２となるので成功しています。
#参考
- [新プログラミング言語「Q#」で量子テレポーテーション ](http://ut25252.hatenablog.com/entry/2017/12/15/222821)
- [量子コンピュータで１＋１を計算する](https://qiita.com/kjtnk/items/8385052a50e3154d1022)