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

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

注意

Microsoft Quantum Development Kit (クラシック QDK) は、2024 年 6 月 30 日以降サポートされなくなります。 既存の QDK 開発者の場合は、量子ソリューションの開発を続けるには、新しい Azure Quantum Development Kit (Modern QDK) に移行することをお勧めします。 詳細については、「コードをモダン QDK に移行する」を参照してくださいQ#

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

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

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

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

ヒント

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

前提条件

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

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

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

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

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

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

   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 つのパラメーターを受け取ります。 という名前の型 Result。これは、 (Zero または One) 内の量子ビットの目的の状態を表し、 型Qubitです。desired
  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 変数はそれぞれ と に1000One設定されます。 これにより、最初の量子ビットが 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 でコードを実行する

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

コードをスタンドアロン プログラムとして実行するには、 Q# Copilot のコンパイラがプログラムを開始する 場所 を知る必要があります。 これは、最初に実行する Q# 操作の直前に を @EntryPoint() 追加することで、ファイルで行われます。 たとえば、この場合は 操作です 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" に設定し、[ 実行] をクリックします。 結果はヒストグラムと [結果 ] フィールドに表示されます。

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

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

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

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

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

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

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

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

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

注意

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

最初の量子ビットの統計は変更されていないことに注意してください (測定後に約 50/50 回の確率が残ります)。ただし、2 番目のZeroOne量子ビットの測定結果は、プログラムの実行回数に関係なく、常に最初の量子ビットの測定と同じです。 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 つのパラメーターを受け取ります。 という名前の型 Result。これは、 (Zero または One) 内の量子ビットの目的の状態を表し、 型Qubitです。desired
  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 変数はそれぞれ と に1000One設定されます。 これにより、最初の量子ビットが 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 関数を使用してコンソールにメッセージを出力します。

コードの実行

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

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

Note

@EntryPoint() はスタンドアロン Q# プログラムにのみ必要です。 Jupyter Notebooks でプログラムを Q# 実行するとき、または Python ホスト ファイルからプログラムを 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);
           }
       }

    @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 );

    }
}

プログラムを実行する前に、ターゲット プロファイルを [無制限] に設定する必要があります。 [表示 ] -> [コマンド パレット] を選択し、[QIR] を検索し、[: Azure Quantum QIR ターゲット プロファイルを設定する] を選択Q#し、[: unrestricted] を選択Q#します。

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

注意

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

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

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

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

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

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

ヒント

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

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

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

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

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); 
            ...

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

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

このプログラムを実行するたびに、最初の量子ビットの結果は多少変動しても、ほぼ 50% の One と 50% の Zero になるのに対して、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

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 = 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. [表示 ] -> [コマンド パレット] を選択するか、Ctrl + Shift + P キーを押し、「ヒストグラム」と入力します。これにより、[ファイルの実行とヒストグラムの表示]Q# オプションが表示されます。 ヒストグラム ウィンドウを開くには、このオプションを Q# 選択します。

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

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

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

    ヒント

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

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

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

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

次のステップ

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