2.1 初めての量子Hello World
環境が準備できたので、今度は自分でプロジェクトを作成して、Writing a Quantum Programを参考に、量子コンピューティングにおけるHello Worldである「量子もつれ状態」を作ってみたいと思います。今回は触れませんが、量子もつれ状態を利用して、量子テレポーテーションなど量子コンピュータ特有のタスクが実行できます。
その前に、ここからの操作で登場する量子力学の概念を、簡単におさらいしておきましょう(太字のところは後の操作で出てきます)。
量子コンピューティングでは、同時に0と1の状態(重ね合わせ状態)を持つ「量子ビット(Qubit)」で計算を行います。2個以上のQubitに対し、重ね合わせを利用して作成された特殊な相関状態を「量子もつれ(エンタングルメント)」と呼びます。量子もつれ状態と呼ばれるものはたくさんありますが、とくに量子コンピューティングで用いられる状態が「Bell states(ベル状態)」と呼ばれるものです。
重ね合わせ状態を含む各Qubitの状態は、MRIなどの核磁気の説明で利用される3次元の単位球内の座標(X,Y,Z)で表現することができます。Qubitの3次元ベクトルの方向を操作するのが「量子ゲート」であり、X軸またはZ軸を180度回転させる「回転ゲート」、Z軸とX軸の間の軸を中心に180度回転させる「アダマールゲート」、2つのゲートで条件分岐する「制御NOTゲート(CNOTゲート)」などがあります。
量子ゲート方式の量子コンピューティングは、Qubitの状態を観測し、量子ゲートを通すことによってQubitの状態をコントロールする技術です。そしてQ#は、Qubitを操作・測定し、観測結果を得るための言語です。
量子の重ね合わせ状態や量子ゲートについてはIBMのサイトで図解されているので、詳しく理解したい方はこちらをお読みください。
2.2 プロジェクトの作成
右のソリューションエクスプローラーから一番上のソリューションを右クリックし、Add > New Projectをクリックします。追加するプロジェクトの選択が出てきますので、Q# Applicationを選択し、プロジェクトの名前を指定します。ここでは、Bellという名称のプロジェクトを作成しました。
プロジェクトには、C#言語で記述された「Driver.cs」と、Q#言語で記述された「Operation.qs」が追加されています。Driver.csは、QuantumSimulatorでOperation.qsを操作、表示するエントリポイントが記述されたコードであり、本体はOperation.qsです。
わかりやすいように、Operation.qsを右クリックして、Renameを選択し、Bell.qsに名前の変更をしましょう。
2.3 まずは1個の量子をセットしてみましょう
作成されたBell.qsを編集をしましょう。Q#では、このoperationとBodyの中にコードを記述します。operationは、今までのオブジェクト指向言語におけるstaticメソッドと同じようなものです。
以下は、Qubitその1(q1)が期待した状態(desired)ではない場合、Qubit状態を反転させる初期化コードです。M()operationによって、Qubit1個の現在の量子ビット状態を測定し、currentに結果を格納します。次のifで、q1がdesiredではない場合は、回転ゲートによってQubitのX軸を反転しています。
namespace Quantum.Bell
{
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
operation Set (desired: Result, q1: Qubit) : ()
{
body
{
let current = M(q1); // 1個のQubitの量子ビット測定
if (desired != current)
{
// 回転ゲートによってQubitのX軸を反転
X(q1);
}
}
}
}
2.4 2個の量子で重ね合わせ状態を作りましょう
次に2つのQubitで量子もつれの状態をつくり、測定を行います。namespace Quantum.Bellにあるoperation Setの次のオペレーションとして、以下のコードを追記しましょう。
ここでは、まず、usingで2つのQubitを使うことを宣言し、引数で渡されたcountの数だけループを行い測定を行います。ループの中では、1つのQubitを「0」に初期化(Qubit0)、もう1つのQubitは引数から投入される初期値で初期化します(Qubit1)。
その後、Qubit0はアダマールゲートによって、0と1の状態を取る確率が等しい量子ビットを生成します。この状態が重ね合わせ状態です。この重ね合わせ状態のQubit0とQubit1を制御NOT演算します。最後に、指定された試行回数(ループ)が終わったら、結果をTupleで返却しています。
operation BellTest (count : Int, initial: Result) : (Int,Int,Int)
{
body
{
mutable numOnes = 0;
mutable agree = 0;
using (qubits = Qubit[2])
{
for (test in 1..count)
{
// 量子ビットを1つは0に初期化、もう1つは引数から投入される初期値
Set (initial, qubits[0]);
Set (Zero, qubits[1]);
// アダマールゲートで重ね合わせ状態へ
H(qubits[0]);
// 制御NOTゲートで2つの量子ビットをNOT演算
CNOT(qubits[0],qubits[1]);
// NOT演算後のqubits[0]を測定
let res = M(qubits[0]);
// 2つの量子ビットの測定結果がマッチしたらagreeをカウントアップ
if (M(qubits[1]) == res)
{
set agree = agree + 1;
}
// 何回1を観測できたかをカウントしている
{
set numOnes = numOnes + 1;
}
}
// リセット
Set(Zero, qubits[0]);
Set(Zero, qubits[1]);
}
// NumZero|0>とNumOne|1>をそれぞれ何回測定できたかを返却する
return (count-numOnes, numOnes, agree);
}
}
2.5 実行してみましょう
ここまで出来たら、ドライバから呼び出します。C#側のシミュレーター(Driver.cs)のインスタンスを作成し、初期化した後にループカウントを1000回、Result.Zeroを初期値にした場合とResult.Oneを初期値にした場合のそれぞれでループします。
using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Simulators;
namespace Quantum.Bell
{
class Driver
{
static void Main(string[] args)
{
using (var sim = new QuantumSimulator())
{
// Try initial values
Result[] initials = new Result[] { Result.Zero, Result.One };
foreach (Result initial in initials)
{
var res = BellTest.Run(sim, 1000, initial).Result;
var (numZeros, numOnes, agree) = res;
System.Console.WriteLine(
$"Init:{initial,-4} 0s={numZeros,-4} 1s={numOnes,-4} agree={agree,-4}");
}
}
System.Console.WriteLine("Press any key to continue...");
System.Console.ReadKey();
}
}
}
さて、どのような結果が得られたでしょうか?片方の量子ビットQubit0は0と1の中間の状態にあり、それをNOT演算したわけですから、結果は、統計的にみて半分は0で半分は1を得ることになります。
まとめ
今回は、量子コンピュータの測定器をコントロールするQ#の操作について簡単に説明してきました。他にもoperation以外のセクションや定義などがありますが、これらのQ#文法についてはQ# language referenceを参考にしてください。
今までのノイマン型コンピュータと異なるアーキティクチャと考えを持つ量子コンピューティングは、これから発展するであろう技術です。ぜひ、この記事を参考に、新しい量子コンピュータの世界を体験してください。