1
/
5

量子コンピューターの言語「Q#」を試す・2


1.準備

Azureを利用するまでの準備については、前回解説していますので、そちらを参照ください。
あくまでAzureを利用するための準備はできている前提となります。

新しいノートブックを作成します。その際、カーネルには「IQ#」を選択します。
IQ#のカーネルは、前回のようにPythonを記述するのではなく、Q#のコードを記述していくことになります。

2.量子ビットの状態を設定する

IQ#でノートブックを作成すると、下記のような一文が自動的に生成されます。
これはサブスク認証などの事前準備を行ってくれるマジックコードで、実際の処理内容にはかかわりません。

%azure.connect "/subscriptions/\<subscription ID>/\<resource group>/providers/Microsoft.Quantum/Workspaces/\<workspace>" \<location>

まずは量子ビットの状態を設定するSetQubitState関数を作成します。
この関数はResult型のdesiredと、Qubit型のtargetの2つの引数をもとにQubit型のtarget変数の量子ビットの状態を古典的な状態に設定します。古典的な状態とはいわゆるbit値であり、0か1で表される状態です。
つまり、前回検証した重ね合わせの状態を含みませんので、0か1のどちらかが100%の確率で表されることになります。


SetQubitState関数にはMXの2つのオペレーションを利用しています。

  • M操作:引数として渡された量子ビットを測定し、いずれかの状態(0か1か)を返却する。
  • X操作:量子ビットを測定した際に返却される状態を反転させます。(0は1に、1は0に)

これらの関数を利用し、target変数を測定し、desired変数で渡した値と同一であればそのままとしますが、異なる場合にはX関数を用いて状態を反転させ、量子ビットを望む状態に固定します。

operation SetQubitState(desired : Result, target : Qubit) : Unit {
    if desired != M(target) {
        X(target);
    }
}


3.量子ビットの状態をテストする

作成したSetQubitState関数をテストするための、TestBellState関数を作成します。
useで2つの量子ビット(q1, q2)を初期化します。
テストは次の手順で行います。

  1. q1は引数で指定した値を初期値として設定できるようにし、q2は固定で0を初期値とします。
  2. q1q2の順番にM関数を用い、ビットの状態を測定、その結果を格納します。
  3. 測定結果が1となった回数をカウントしていきます。
  4. 最後にq1、q2の測定結果のカウントを出力します。
operation TestBellState(count : Int, initial : Result) : (Int, Int, Int, Int) {
    mutable numOnesQ1 = 0;
    mutable numOnesQ2 = 0;

    // allocate the qubits
    use (q1, q2) = (Qubit(), Qubit());
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);
        
        // measure each qubit
        let resultQ1 = M(q1);
        let resultQ2 = M(q2);

        // Count the number of 'Ones':
        if resultQ1 == One {
            set numOnesQ1 += 1;
        }
        if resultQ2 == One {
            set numOnesQ2 += 1;
        }
    }

    // reset the qubits
    SetQubitState(Zero, q1);
    SetQubitState(Zero, q2);
    

    // Return number of |0> states, number of |1> states
    Message("q1:Zero, One  q2:Zero, One");
    return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

}


では、まずは上記の関数が本当に動いてくれるのか、マジックコマンドのsimulateを使い実行します。
このマジックコマンドはQ#のコードをシミュレーションして、実行結果を返してくれるコマンドです。
1000回実行し、q1の量子ビットは1を設定しています。

%simulate TestBellState count=1000 initial=1
==================
q1:Zero, One  q2:Zero, One
(0, 1000, 1000, 0)

当然結果は、q1は0の測定結果はなく、1だけが1000回カウントされており、q2の結果はその逆になります。
では、q1の初期値を0にした場合はどうなるでしょうか。

%simulate TestBellState count=1000 initial=0
==================
q1:Zero, One q2:Zero, One
(1000, 0, 1000, 0)

当然ですが、q1に0が設定されたことで、q1とq2の結果が全く同じになりました。
ここで重要なことはq1の設定を変更しても、q1の結果を変える事はできたが、q2の結果は変化しなかったです。

4.量子ビットを重ね合わせ状態にする

コードに手を加え、量子ビットの状態を変化させます。
やり方は簡単で、以下のコードを追加するだけです。

H(q1);

この1行を、SetQubitState関数で量子ビットに値を与えた後に、記述します。
H関数は引数で指定した量子ビットを「重ね合わせ」の状態にします。
これで量子ビットq1は0が50%、1が50%の状態となりました。

operation TestBellState(count : Int, initial : Result) : (Int, Int, Int, Int) {
    mutable numOnesQ1 = 0;
    mutable numOnesQ2 = 0;

    // allocate the qubits
    use (q1, q2) = (Qubit(), Qubit());
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);

        H(q1);
        
        // measure each qubit
        let resultQ1 = M(q1);
        let resultQ2 = M(q2);
----------------------------------snip----------------------------------

しかし、本当にそうなっているでしょうか?
テストしてみます。

%simulate TestBellState count=1000 initial=1
==================
q1:Zero, One  q2:Zero, One
(505, 495, 1000, 0)

どうやら、量子ビットq1は想定通り、重ね合わせの状態になっているようです。
ちなみに0と1の確率が50%ずつと書きましたが、正確に50%にはなりませんので、上記の結果のように1000回程度の試行では約50%という結果になります。

5.量子ビットをもつれさせる

最後に量子ビットをもつれさせます。
そのためにはCNOT(Controlled-NOT)関数で、制御ビット(q1)と標的ビット(q2)を指定します。

CNOT(q1, q2);

量子ビットの重ね合わせを行ったH関数の下に記載します。

operation TestBellState(count : Int, initial : Result) : (Int, Int, Int, Int) {
    mutable numOnesQ1 = 0;
    mutable numOnesQ2 = 0;

    // allocate the qubits
    use (q1, q2) = (Qubit(), Qubit());
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);

        H(q1);
        CNOT(q1, q2);
        
        // measure each qubit
        let resultQ1 = M(q1);
        let resultQ2 = M(q2);
----------------------------------snip----------------------------------

これでどうなるのでしょうか?
量子ビットのもつれ(エンタングルメント)というのは、かみ砕いた表現をすると、ある1つの量子の状態を観測した際、他の異なる量子の観測結果にも影響を与えてしまう状態です。
厳密な表現ではないのですが、ある2つの量子があった時、その量子がいずれの状態であるかは最初分かりません。しかし、片方の量子の状態が確定した場合、もう片方の量子の状態が瞬時に確定する、この性質を量子のもつれ、と言います。

この性質が注目される理由の1つは片方の量子の観測から、もう片方の量子の状態が確定するまでの時間は瞬時であると考えられていること、もう1つがこの性質は遠く離れていたとしても距離に関わらず機能する、と考えられていることです。
そして、つまり距離に関わらず瞬時に量子Aから量子Bに情報が伝達される、とも言いかえることができます。
一種の情報のテレポーテーションであり、これがいわゆる量子テレポーテーションと呼ばれるものです。

しかし、現実に情報伝達手段としてこの性質が利用できるかは疑問視されており、その理由として挙げられるのが、量子Aから量子Bへ情報を伝達したい場合に「量子Aを観測した」という情報をもう片方の量子Bを持つ誰かへ伝える手段は古典的な方法に頼らざるを得ないためです。
時間を示し合わせて量子A/Bを観測しても、それが自分自身の観測によって確定したのか、あるいは量子Aを観測した結果状態が確定しているのかを量子Bの側からだけでは判別できません。つまり、結局、電話やメール等の古典的な手段で量子Aの側は、量子Bの側へ、量子Aを観測したよ、という情報を伝えなければいけないのです。これでは、残念ながら今とさほど変わりませんね。
なんとも、残念な話ではありますが、今後の発展によってブレイクスルーが生まれれば、光よりも早い通信手段を得ることが可能になる、という点は科学の発展において重要なファクターの1つです。

それでは、仮想ではありますが、実際に量子もつれを観測してみます。
これまで通り、1000回の実行します。
実行結果を見る前に、これまでの結果では量子ビットq2は全く変化しなかったことを思い出してください。

%simulate TestBellState count=1000 initial=1
==================
q1:Zero, One  q2:Zero, One
(488, 512, 488, 512)

なんと、量子ビットq1と量子ビットq2の結果が完全に同じになりました。
これは量子ビットq1の観測によって、量子ビットq2の状態に影響を与えたことにより、量子ビットq1と同じ結果になったのです。

6.次のステップ

量子ビットの「重ね合わせ」と「もつれ」の代表的な状態を試すことができました。
次はそうした基本的な操作を組み合わせたプログラムを作成するチュートリアルプログラムに挑戦したいと思います。

それでは、ここまでお読みいただき、ありがとうございました!

エス・エー・エス株式会社からお誘い
この話題に共感したら、メンバーと話してみませんか?
エス・エー・エス株式会社では一緒に働く仲間を募集しています
11 いいね!
11 いいね!

同じタグの記事

今週のランキング

須川 正隆さんにいいねを伝えよう
須川 正隆さんや会社があなたに興味を持つかも