プログラムを書き初めてあまり経っておらず量子コンピュータの知識もなかったのですが、Q#で何か書きたいと思い量子ビットについて少し勉強して、量子ビットを用いて1+1の計算を実行できるようにしました。
※完全に理解しているわけではないので表現などが間違っているかもしれません。
#基礎知識
量子計算基礎.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ゲート
$x=0$のときは$y$に変化はなく、$x=1$のときは$y$が反転します。例えば、$x=1$,$y=1$のとき$y$は反転するので$|0\rangle$に、$x=0$,$y=1$のとき$y$に変化はないので$|1\rangle$になります。
#論理回路から量子回路へ
まず、量子回路ではなく論理回路で1+1を行うときの図を見ます。この回路では$A=1$、$B=1$のときに1+1の計算結果が出力されます。
- 真理値表
A | B | S | C |
---|---|---|---|
0 | 0 | 0 | 0 |
1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 |
1 | 1 | 0 | 1 |
これは半加算器と呼ばれるもので、繰り上りを考慮しない2進数1桁の加算ができます。Aに1を、Bに1を入れると、Sに0が、Cに1が出力されます。つまり2進数で10という値(Cが2桁目でSが1桁目)が得られるという事なので、10進数に直すと2となります。
これを、量子回路に変換したものが下の図です。この図は、$a=|1\rangle$、$b=|1\rangle$の時の結果を表しています。
ここで使われているのは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に、0がCCNOTゲートを通った後の値がCにあたります。なので、この二つの部分をMゲート(量子ビットの観測を行う)に通し1か0かを判別すれば、計算が可能になります。この回路で1+1を行うには、$a=|1\rangle$、$b=|1\rangle$にすればいいです。
#コード
まずは.qs
ファイルの方から。
Q#ではmutable
で可変変数を、let
で不変定数を定義します。mutable
で定義した変数にはset
を使って数値を代入します。
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に代入、2桁目にあたる。
if(c== One){
set result = result + 2; //桁上がりがあり、2桁目が1ということなので10進数では2
}
CNOT(qubits[0],qubits[1]); //a,bをCNOTゲートに通す
let s = M(qubits[1]); //bの観測値をsに代入、1桁目にあたる
if (s == One){
set result = result + 1; //一桁目が1ということなので10進数では1
}
Set(Zero,qubits[0]);
Set(Zero,qubits[1]);
Set(Zero,qubits[2]);
}
return (result);
}
}
Set
で必要な量子ビットを作成します。観測した量子ビットが必要としている値ではなかったときに、Xゲートを通して反転させて必要な値を得ています。
Hadd
が今回の目的である1+1を行う部分です。Hadd
の引数は二つで、ここの値が両方One
($|1>と考えていい$)のときに、1+1の計算結果が出ます。ほかにも、0+0、1+0,0+1ができます。中身を見ていきます。まずSet
で必要な量子ビットを用意します。それを上で説明した量子回路の図通りにCCNOTゲート、CNOTゲートに通していきます。CCNOT( )、CNOT( )は引数の最後が図の$\oplus$がある列になっているようです。にゲートに通した後の量子ビットの値をMゲートに通して観測値をlet
で宣言したc
,s
に代入します。その値を見てresult
に数値を代入します。
1+1が行われるときs
はZero
、c
はOne
となるはずです。
では次は.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; //1+1を実行
var answer = res;
System.Console.WriteLine($"answer:{answer,-4}"); //結果を表示
}
System.Console.WriteLine("Press any key to continue...");
System.Console.ReadKey();
}
}
}