チュートリアル:Q# を使用して量子のもつれを調査する

このチュートリアルでは、量子ビットを操作および測定し、重ね合わせとエンタングルメントの効果を示す Q# プログラムを記述します。 特定の量子状態で 2 つの量子ビットを準備し、 Q# で量子ビットを操作して状態を変更する方法を学習し、重ね合わせとエンタングルメントの効果を示します。 量子ビットの状態、演算、測定を導入するために、 Q# プログラムを 1 つずつ構築します。

開始する前に理解しておく必要がある主要な概念を次に示します。

  • 従来のビットが 1 つのバイナリ値 (0 または 1) を保持するのに対して、量子ビットの状態は、2 つの量子状態 (0 と 1) の重ね合わせになることができます。 可能性のある量子状態にはそれぞれ、関連付けられている確率振幅があります。
  • 量子ビットを測定すると、一定の確率で二項結果が生成され、量子ビットの状態が重ね合わせから変化します。
  • 複数の量子ビットは、互いに独立して記述できないように絡み合うことができます。 つまり、もつれたペアの 1 つの量子ビットに対して行われたことはすべて、もう一方の量子ビットに対しても行われます。

このチュートリアルで学習する内容は次のとおりです。

  • 量子ビットを目的の状態に初期化する Q# 操作を作成します。
  • 量子ビットを重ね合わせ状態にする。
  • 量子ビットのペアをもつれさせる。
  • 量子ビットを測定し、結果を観察します。

ヒント

量子コンピューティングの取り組みを加速させる場合は、Azure Quantum Web サイトのユニークな機能である Azure Quantum を使用した Codeをご覧ください。 ここでは、組み込みの Q# サンプルまたは独自の Q# プログラムを実行し、プロンプトから新しい Q# コードを生成し、 VS Code for the Web でコードを開いて実行し ワンクリックで Copilot に量子コンピューティングに関する質問を行うことができます。

前提条件

Copilot for Azure Quantum でコード サンプルを実行するには、次のものが必要です。

  • Microsoft (MSA) メール アカウント。

Copilot の詳細については、「 Explore Azure Quantum」を参照してください。

量子ビットを既知の状態に初期化する

最初の手順では、量子ビットを既知の状態に初期化する Q# 演算を定義します。 これは、量子ビットを古典的な状態に設定するために呼び出すことができます。つまり、測定すると、100% の時間 Zero 返すか、100% の時間 One 返します。 量子ビットを測定すると、 Q# 型の Resultが返されます。 Zero または Oneの値のみを持つことができます。

Azure Quantum 用の Copilot を開き 次のコードをコード エディター ウィンドウにコピーします。 まだ Run をクリックしないでください。このチュートリアルの後半でコードを実行します。

   namespace Bell {
       open Microsoft.Quantum.Intrinsic;
       open Microsoft.Quantum.Canon;

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

このコード例では、量子ビットの状態を変換する 2 つの標準演算である MX が紹介されています。

SetQubitState 操作は次のとおりです。

  1. 2 つのパラメーターを受け取ります。desiredという名前の型Result。量子ビットの状態 (ZeroまたはOne) を表し、型Qubit
  2. 測定操作 (M) を実行します。この操作では、量子ビットの状態 (Zero または One) を測定し、その結果を desired で指定された値と比較します。
  3. 測定値が比較値と一致しない場合は、X 演算が実行されます。この操作では、量子ビットの状態が反転され、測定で ZeroOne が返される確率が逆になります。 これにより、SetQubitState は常にターゲットの量子ビットを目的の状態にします。

Bell 状態をテストするテスト操作を記述する

次に、SetQubitState 演算の効果を示すために、TestBellState という名前の別の演算を作成します。 この操作では、2 つの量子ビットを割り当て、 SetQubitState を呼び出して最初の量子ビットを既知の状態に設定し、その量子ビットを測定して結果を確認します。

次のコードを、 SetQubitState 操作の下にあるコード エディター ウィンドウにコピーします。

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

    // 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' returned:
        if resultQ1 == One {
            set numOnesQ1 += 1;
        }
        if resultQ2 == One {
            set numOnesQ2 += 1;
        }
    }

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

    // Display the times that |0> is returned, and times that |1> is returned
    Message($"Q1 - Zeros: {count - numOnesQ1}");
    Message($"Q1 - Ones: {numOnesQ1}");
    Message($"Q2 - Zeros: {count - numOnesQ2}");
    Message($"Q2 - Ones: {numOnesQ2}");
    return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

}

このコードでは、 count 変数と initial 変数がそれぞれ 1000 に設定され、 One されます。 これにより、最初の量子ビットが One に初期化され、各量子ビットが 1000 回測定されます。

TestBellState 演算では、次の処理を行います。

  1. カウンターの変数と初期量子ビットの状態を設定します。
  2. use ステートメントを呼び出して、2 つの量子ビットを初期化します。
  3. count の回数分、ループ処理を実行します。 各ループでは、次の操作が実行されます
    1. SetQubitState を呼び出して、指定された initial 値を最初の量子ビットに設定します。
    2. SetQubitState を再度呼び出して、2 番目の量子ビットを Zero 状態に設定します。
    3. M 演算を使用して各量子ビットを測定します。
    4. One を返す各量子ビットの測定値の数を格納します。
  4. ループが完了したら、SetQubitState を再度呼び出して量子ビットを既知の状態 (Zero) にリセットし、他のユーザーが既知の状態で量子ビットを割り当てられるようにします。 この操作は、use ステートメントに必須です。
  5. 最後に、結果を返す前に、 Message 関数を使用して結果を Copilot 出力ウィンドウに出力します。

Copilot for Azure Quantum でコードを実行する

重ね合わせとエンタングルメントの手順に進む前に、ここまでのコードをテストして、量子ビットの初期化と測定を確認できます。

スタンドアロン プログラムとしてコードを実行するには、Copilot の Q# コンパイラが の場所 プログラムを開始する必要があります。 これは、最初に実行する操作の直前に@EntryPoint()を追加することによって、Q# ファイルで行われます。 たとえば、この場合は TestBellState 操作です。

Note

@EntryPoint() はスタンドアロン Q# プログラムにのみ必要です。 Jupyter Notebooks で Q# プログラムを実行するとき、または Python ホスト ファイルから Q# プログラムを呼び出すときは、必須ではなく、含まれている場合はエラーがスローされます。

TestBellState操作の直前に@EntryPoint()を追加すると、ここまでのQ# プログラムは次のようになります。

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

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

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = One;

        // 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' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

完全なコード サンプルをコピーして Copilot for Azure Quantum コード ウィンドウに貼り付け、ショット数のスライドを "1" に設定し、 Run をクリックします。 結果はヒストグラムと Results フィールドに表示されます。

Q1 - Zeros: 0
Q1 - Ones: 1000
Q2 - Zeros: 1000
Q2 - Ones: 0

量子ビットはまだ操作されていないので、初期値が保持されています。最初の量子ビットは毎回 One を返し、2 番目の量子ビットは Zero を返します。

initialの値をZeroに変更し、プログラムをもう一度実行すると、最初の量子ビットも毎回Zero返されることを確認する必要があります。

Q1 - Zeros: 1000
Q1 - Ones: 0
Q2 - Zeros: 1000
Q2 - Ones: 0

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

現在、プログラム内の量子ビットはすべて "クラシック" 状態になっています。つまり、1 または 0 です。 これは、このプログラムではこれらの量子ビットを既知の状態に初期化し、それらを操作するプロセスをまだ追加していないためであることがわかっています。 量子ビットをエンタングする前に、最初の量子ビットを 重ね合わせ状態に配置します。ここで量子ビットの測定値は約 50% の時間 Zero 返され、 One 約 50% の時間が返されます。 概念的には、量子ビットは、 Zero または Oneを測定する確率が等しいと考えることができます。

量子ビットを重ね合わせ状態にするために、Q# によって H (つまり Hadamard) 演算が提供されます。 からのX演算を思い出します。前の手順で量子ビットを既知の状態に初期化します。このプロシージャでは、量子ビットが 0 から 1 (またはその逆) に反転されました。H操作では、量子ビットhalfwayZeroまたはOneの確率が等しい状態に反転されます。 測定されると、重ね合わせ状態にある量子ビットは、ほぼ等しい数の ZeroOne の結果を返すはずです。

初期値をOneにリセットし、H操作の行を挿入して、TestBellState操作のコードを変更します。

for test in 1..count {
    use (q1, q2) = (Qubit(), Qubit());   
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);
        
        H(q1);                // Add the H operation after initialization and before measurement

        // measure each qubit
        let resultQ1 = M(q1);            
        let resultQ2 = M(q2); 
        ...

プログラムを実行すると、重ね合わせの最初の量子ビットの結果を確認できます。

Q1 - Zeros: 523            // results will vary
Q1 - Ones: 477
Q2 - Zeros: 1000
Q2 - Ones: 0

プログラムを実行するたび、最初の量子ビットの結果は、わずかな違いはあるものの、OneZero がそれぞれ 50% に近い結果になります。一方、2 番目の量子ビットの結果は常に Zero のままになります。

Q1 - Zeros: 510           
Q1 - Ones: 490
Q2 - Zeros: 1000
Q2 - Ones: 0

最初の量子ビットを Zero に初期化すると、同様の結果が返されます。

Q1 - Zeros: 504           
Q1 - Ones: 496
Q2 - Zeros: 1000
Q2 - Ones: 0

Note

Azure Quantum の Copilot でスライダーを移動し、ショットの数を増やすことで、重ね合わせの結果がショットの分布とわずかに異なることがわかります。

2 つの量子ビットをもつれさせる

前に説明したように、もつれた量子ビットは、互いに独立には記述できないように接続されます。 つまり、1 つの量子ビットに対して行われた操作はすべて、もつれた量子ビットに対しても行われます。 これにより、1 つの量子ビットの最終的な状態は、もう一方の量子ビットの状態を測定するだけで、測定しなくても知ることができます。 (この例では 2 つの量子ビットを使用しますが、3 つ以上の量子ビットをもつれさせることもできます)。

もつれを有効にするために、Q# によって CNOT 演算 (これは "制御された NOT" を表します) が提供されます。 2 つの量子ビットに対してこの操作を実行した結果、最初の量子ビットが One である場合には 2 番目の量子ビットが反転されます。

プログラムの H 演算の直後に CNOT 演算を追加します。 プログラム全体は次のようになっているものと思われます。

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

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

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = Zero;

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

            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

プログラムを実行すると、次のような内容が表示されます。

Q1 - Zeros: 502           // results will vary
Q1 - Ones: 498
Q2 - Zeros: 502
Q2 - Ones: 498

最初の量子ビットの統計情報は変更されていないことに注意してください (測定後、 Zero または One が発生する可能性はまだ約 50/50 です)。ただし、2 番目の量子ビットの測定結果は です プログラムを実行する回数に関係なく、最初の量子ビットの測定と同じです。 CNOT 操作によって 2 つの量子ビットがエンタングル状態になり、片方に何かが起きると、もう片方にも同じことが起こるようになっています。

前提条件

ローカル開発環境でコード サンプルを開発して実行するには、

新しい Q# ファイルを作成する

  1. Visual Studio Code を開き、[ファイル] > [新しいテキスト ファイル] を選んで新しいファイルを作成します。
  2. このファイルを CreateBellStates.qs として保存します。 このファイルには、プログラムの Q# コードが含まれます。

量子ビットを既知の状態に初期化する

最初の手順では、量子ビットを既知の状態に初期化する Q# 演算を定義します。 これを呼び出すと、量子ビットを古典的な状態に設定できます。つまり、100% の時間 Zero を返すか、または 100% の時間 One を返すかのどちらかになります。 ZeroOne は、量子ビットの測定の 2 つしかない考えられる結果を表す Q# 値です。

CreateBellStates.qsを開き、次のコードをコピーします。

   namespace Bell {
       open Microsoft.Quantum.Intrinsic;
       open Microsoft.Quantum.Canon;

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

このコード例では、量子ビットの状態を変換する 2 つの標準演算である MX が紹介されています。

SetQubitState 操作は次のとおりです。

  1. 2 つのパラメーターを受け取ります。desiredという名前の型Result。量子ビットの状態 (ZeroまたはOne) を表し、型Qubit
  2. 測定操作 (M) を実行します。この操作では、量子ビットの状態 (Zero または One) を測定し、その結果を desired で指定された値と比較します。
  3. 測定値が比較値と一致しない場合は、X 演算が実行されます。この操作では、量子ビットの状態が反転され、測定で ZeroOne が返される確率が逆になります。 これにより、SetQubitState は常にターゲットの量子ビットを目的の状態にします。

Bell 状態をテストするテスト操作を記述する

次に、SetQubitState 演算の効果を示すために、TestBellState という名前の別の演算を作成します。 この操作では、2 つの量子ビットを割り当て、 SetQubitState を呼び出して最初の量子ビットを既知の状態に設定し、その量子ビットを測定して結果を確認します。

CreateBellStates.qs ファイルの SetQubitState 演算の後に次の演算を追加します。

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

    // 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' returned:
        if resultQ1 == One {
            set numOnesQ1 += 1;
        }
        if resultQ2 == One {
            set numOnesQ2 += 1;
        }
    }

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

    // Display the times that |0> is returned, and times that |1> is returned
    Message($"Q1 - Zeros: {count - numOnesQ1}");
    Message($"Q1 - Ones: {numOnesQ1}");
    Message($"Q2 - Zeros: {count - numOnesQ2}");
    Message($"Q2 - Ones: {numOnesQ2}");
    return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

}

このコードでは、 count 変数と initial 変数がそれぞれ 1000 に設定され、 One されます。 これにより、最初の量子ビットが One に初期化され、各量子ビットが 1000 回測定されます。

TestBellState 演算では、次の処理を行います。

  1. 2 つのパラメーターを受け取ります。count (測定を実行する回数) と、initial (量子ビットを初期化するための望ましい状態) です。
  2. use ステートメントを呼び出して、2 つの量子ビットを初期化します。
  3. count の回数分、ループ処理を実行します。 各ループでは、次の操作が実行されます
    1. SetQubitState を呼び出して、指定された initial 値を最初の量子ビットに設定します。
    2. SetQubitState を再度呼び出して、2 番目の量子ビットを Zero 状態に設定します。
    3. M 演算を使用して各量子ビットを測定します。
    4. One を返す各量子ビットの測定値の数を格納します。
  4. ループが完了したら、SetQubitState を再度呼び出して量子ビットを既知の状態 (Zero) にリセットし、他のユーザーが既知の状態で量子ビットを割り当てられるようにします。 この操作は、use ステートメントに必須です。
  5. 最後に、結果を返す前に、Message 関数を使用してコンソールにメッセージを出力します。

コードの実行

重ね合わせともつれの手順に進む前に、この時点までのコードをテストして、これらの量子ビットの初期化と測定を確認します。

これは、実行する操作の直前に@EntryPoint()を追加することによって、Q# ファイルで行われます。 たとえば、この場合は TestBellState 操作です。

Note

@EntryPoint() はスタンドアロン Q# プログラムにのみ必要です。 Jupyter Notebooks で Q# プログラムを実行するとき、または Python ホスト ファイルから Q# プログラムを呼び出すときは、必須ではなく、含まれている場合はエラーがスローされます。

  1. CreateBellStates.qs ファイルは次のようになります。

    namespace Bell {
        open Microsoft.Quantum.Intrinsic;
        open Microsoft.Quantum.Canon;
    
           operation SetQubitState(desired : Result, target : Qubit) : Unit {
               if desired != M(target) {
                   X(target);
               }
           }
    
        @EntryPoint()
        operation TestBellState() : (Int, Int, Int, Int) {
            mutable numOnesQ1 = 0;
            mutable numOnesQ2 = 0;
            let count = 1000;
            let initial = One;
    
            // 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' returned:
                if resultQ1 == One {
                    set numOnesQ1 += 1;
                }
                if resultQ2 == One {
                    set numOnesQ2 += 1;
                }
            }
    
            // reset the qubits
            SetQubitState(Zero, q1);             
            SetQubitState(Zero, q2);
    
    
            // Display the times that |0> is returned, and times that |1> is returned
            Message($"Q1 - Zeros: {count - numOnesQ1}");
            Message($"Q1 - Ones: {numOnesQ1}");
            Message($"Q2 - Zeros: {count - numOnesQ2}");
            Message($"Q2 - Ones: {numOnesQ2}");
            return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
    
        }
    }
    
  2. プログラムを実行する前に、ターゲット プロファイルを "無制限" に設定する必要があります。 View -> コマンド パレットを選択し、QIR を検索し、Q#: Azure Quantum QIR ターゲット プロファイルを設定を選択してから、Q#: 無制限を選択します。

    Note

    ターゲット プロファイルが Unrestricted に設定されていない場合は、プログラムの実行時にエラーが発生します。

  3. プログラムを実行するには、右上の再生アイコン ドロップダウンから Run Q# ファイルを選択@EntryPoint()の下のコマンドの一覧から Run をクリックするか、Ctrl + F5 キーを押。 プログラムは、既定のシミュレーターで @EntryPoint() 属性でマークされた操作または関数を実行します。

  4. 出力がデバッグ コンソールに表示されます。

    Q1 - Zeros: 0
    Q1 - Ones: 1000
    Q2 - Zeros: 1000
    Q2 - Ones: 0
    

    量子ビットはまだ操作されていないので、初期値が保持されています。最初の量子ビットは毎回 One を返し、2 番目の量子ビットは Zero を返します。

  5. initialの値をZeroに変更し、プログラムをもう一度実行すると、最初の量子ビットも毎回Zero返されることを確認する必要があります。

    Q1 - Zeros: 1000
    Q1 - Ones: 0
    Q2 - Zeros: 1000
    Q2 - Ones: 0
    

ヒント

コードを再度実行する前に、コードに変更を導入するたびにファイルを保存することを思い出してください。

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

現在、プログラム内の量子ビットはすべて "クラシック" 状態になっています。つまり、1 または 0 です。 これは、このプログラムではこれらの量子ビットを既知の状態に初期化し、それらを操作するプロセスをまだ追加していないためであることがわかっています。 量子ビットをエンタングルする前に、最初の量子ビットを "重ね合わせ" 状態にします。これにより、量子ビットの測定で Zero が返される確率が 50%、One が返される確率が 50% になります。 概念上、量子ビットは ZeroOne の中間にあると考えることができます。

量子ビットを重ね合わせ状態にするために、Q# によって H (つまり Hadamard) 演算が提供されます。 からのX操作を思い出します前の手順で量子ビットを既知の状態に初期化します。これにより、量子ビットがZeroからOne (またはその逆) に反転されます。H操作では、量子ビットhalfwayZeroまたはOneの等しい確率の状態に反転されます。 測定されると、重ね合わせ状態にある量子ビットは、ほぼ等しい数の ZeroOne の結果を返すはずです。

  1. TestBellState 演算のコードを変更して、H 演算を含めるようにします。

        for test in 1..count {
            use (q1, q2) = (Qubit(), Qubit());   
            for test in 1..count {
                SetQubitState(initial, q1);
                SetQubitState(Zero, q2);
    
                H(q1);                // Add the H operation after initialization and before measurement
    
                // measure each qubit
                let resultQ1 = M(q1);            
                let resultQ2 = M(q2); 
                ...
    
  2. これで、プログラムを実行すると、重ね合わせの状態にある最初の量子ビットの結果を確認できます。

    Q1 - Zeros: 523            // results will vary
    Q1 - Ones: 477
    Q2 - Zeros: 1000
    Q2 - Ones: 0
    
  3. プログラムを実行するたび、最初の量子ビットの結果は、わずかな違いはあるものの、OneZero がそれぞれ 50% に近い結果になります。一方、2 番目の量子ビットの結果は常に Zero のままになります。

    Q1 - Zeros: 510           
    Q1 - Ones: 490
    Q2 - Zeros: 1000
    Q2 - Ones: 0
    
  4. 最初の量子ビットを Zero に初期化すると、同様の結果が返されます。

    Q1 - Zeros: 504           
    Q1 - Ones: 496
    Q2 - Zeros: 1000
    Q2 - Ones: 0
    

2 つの量子ビットをもつれさせる

前に説明したように、もつれた量子ビットは、互いに独立には記述できないように接続されます。 つまり、1 つの量子ビットに対して行われた操作はすべて、もつれた量子ビットに対しても行われます。 これにより、1 つの量子ビットの最終的な状態は、もう一方の量子ビットの状態を測定するだけで、測定しなくても知ることができます。 (この例では 2 つの量子ビットを使用しますが、3 つ以上の量子ビットをもつれさせることもできます)。

もつれを有効にするために、Q# によって CNOT 演算 (これは "制御された NOT" を表します) が提供されます。 2 つの量子ビットに対してこの操作を実行した結果、最初の量子ビットが One である場合には 2 番目の量子ビットが反転されます。

  1. プログラムの H 演算の直後に CNOT 演算を追加します。 プログラム全体は次のようになっているものと思われます。

    namespace Bell {
        open Microsoft.Quantum.Intrinsic;
        open Microsoft.Quantum.Canon;
    
           operation SetQubitState(desired : Result, target : Qubit) : Unit {
               if desired != M(target) {
                   X(target);
               }
           }
    
        @EntryPoint()
        operation TestBellState() : (Int, Int, Int, Int) {
            mutable numOnesQ1 = 0;
            mutable numOnesQ2 = 0;
            let count = 1000;
            let initial = One;
    
            // allocate the qubits
            use (q1, q2) = (Qubit(), Qubit());   
            for test in 1..count {
                SetQubitState(initial, q1);
                SetQubitState(Zero, q2);
    
                H(q1);            
                CNOT(q1, q2);      // Add the CNOT operation after the H operation
    
                // measure each qubit
                let resultQ1 = M(q1);            
                let resultQ2 = M(q2);           
    
                // Count the number of 'Ones' returned:
                if resultQ1 == One {
                    set numOnesQ1 += 1;
                }
                if resultQ2 == One {
                    set numOnesQ2 += 1;
                }
            }
    
            // reset the qubits
            SetQubitState(Zero, q1);             
            SetQubitState(Zero, q2);
    
    
            // Display the times that |0> is returned, and times that |1> is returned
            Message($"Q1 - Zeros: {count - numOnesQ1}");
            Message($"Q1 - Ones: {numOnesQ1}");
            Message($"Q2 - Zeros: {count - numOnesQ2}");
            Message($"Q2 - Ones: {numOnesQ2}");
            return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );
    
        }
    }
    
    
    Q1 - Zeros: 502           
    Q1 - Ones: 498       // results will vary
    Q2 - Zeros: 502
    Q2 - Ones: 498
    

最初の量子ビットの統計は変化していません (測定後の Zero または One の確率は 50/50) が、2 番目の量子ビットの測定結果は、常に最初の量子ビットの測定と同じになります。 CNOT 操作によって 2 つの量子ビットがエンタングル状態になり、片方に何かが起きると、もう片方にも同じことが起こるようになっています。

頻度ヒストグラムをプロットする

量子プログラムを複数回実行して得られた結果の分布を視覚化してみましょう。 頻度ヒストグラムは、これらの結果の確率分布を視覚化するのに役立ちます。

  1. View -> コマンド パレットを選択するか、Ctrl + Shift + P キーを押し、「ヒストグラム」と入力します。Q#:ファイルの実行とヒストグラムの表示オプションが表示されます。 @EntryPoint()の下のコマンドの一覧から Histogram をクリックすることもできます。 このオプションを選択すると、 Q# ヒストグラム ウィンドウが開きます。

  2. ショットの数を入力し100 ショットなどのプログラムを実行し、Enter キーを押します。 ヒストグラムが Q# ヒストグラム ウィンドウに表示されます。

  3. ヒストグラムの各バーは、考えられる結果に対応し、その高さは結果が観察される回数を表します。 この場合、50 種類の異なる一意の結果があります。 結果ごとに、1 番目と 2 番目の量子ビットの測定結果は常に同じであることに注意してください。

    Visual Studio Code の [ Q# ヒストグラム] ウィンドウのスクリーンショット。

    ヒント

    マウス スクロール ホイールまたはトラックパッド ジェスチャを使用して、ヒストグラムをズームできます。 拡大すると、スクロール中に 'Alt' キーを押してグラフをパンできます。

  4. バーをクリックすると、その結果の 時間 が表示されます。

  5. 左上の 設定アイコン をクリックしてオプションを表示します。 上位 10 件の結果、上位 25 件の結果、またはすべての結果を表示できます。 また、結果を高から低、低から高に並べ替えることもできます。

    Visual Studio Code の [ Q# ヒストグラム] ウィンドウのスクリーンショット。設定を表示する方法が示されています。

Q# のその他のチュートリアルを確認します。

  • グローバーの検索アルゴリズム グローバーの検索アルゴリズムを使用する Q# プログラムを記述する方法を示します。
  • 量子フーリエ変換 では、特定の量子ビットに直接対処する Q# プログラムを記述する方法について説明します。
  • Quantum Katasは、量子コンピューティングとQ#プログラミングの要素を同時に教えることを目的とした、自習型のチュートリアルとプログラミング演習です。