자습서: Q#으로 양자 얽힘 살펴보기

이 자습서에서는 큐비트를 조작 및 측정하고 중첩과 얽힘의 효과를 시연하는 Q# 프로그램을 작성하는 방법을 보여 줍니다.

  • 클래식 비트는 0 또는 1 같은 단일 이진 값을 보유하는 반면, 큐비트 상태는 두 양자 상태 0과 1의 중첩에 있을 수 있습니다. 가능한 각 양자 상태에는 연결된 확률 진폭이 있습니다.
  • 큐비트를 측정하는 행위는 특정 확률로 0 또는 1의 이진 결과를 생성하고 큐비트의 상태를 중첩에서 변경합니다.
  • 여러 큐비트는 서로 독립적으로 설명할 수 없도록, 얽히게 할 수 있습니다. 즉, 얽힌 쌍의 한 큐비트에 어떤 일이 발생하든 다른 큐비트에도 발생합니다.

이 자습서에서는 특정 양자 상태에 있는 두 큐비트를 준비하고, Q#에서 두 큐비트의 상태를 변경하는 작업을 수행하며, 중첩 및 얽힘의 효과를 알아봅니다. 큐비트 상태, 연산 및 측정을 소개하는 Q# 프로그램을 하나씩 작성하게 됩니다.

필수 구성 요소

이 자습서를 완료하려면 다음이 필요합니다.

이 자습서에서는 다음 방법에 대해 알아봅니다.

  • 큐비트를 측정하고 원하는 상태로 초기화하는 Q# 연산을 만듭니다.
  • 큐비트를 만들고 프로그램을 테스트합니다.
  • 큐비트를 중첩에 넣습니다.
  • 큐비트 쌍을 얽습니다.

작업 영역에 새 Notebook 만들기

  1. Azure Portal에 로그인하고 이전 단계에서 만든 작업 영역을 선택합니다.
  2. 왼쪽 블레이드에서 Notebooks를 선택합니다.
  3. 내 Notebooks를 클릭하고 새로 추가를 클릭합니다.
  4. 커널 형식에서 IQ#를 선택합니다.
  5. 파일 이름(예: Entanglement.ipynb)을 입력하고 파일 만들기를 클릭합니다.

새 Notebook이 열리면 구독 및 작업 영역 정보를 기반으로 첫 번째 셀에 대한 코드가 자동으로 만들어집니다.

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

참고

%azure.connect는 Jupyter Notebook에서 작업을 간소화하는 데 도움이 되는 명령 집합인 IQ# Magic 명령입니다.

이 셀을 실행하는 경우 구독에 대해 인증하고 사용 가능한 공급자 및 대상 목록을 표시해야 합니다.

측정을 사용하여 큐비트 초기화

첫 번째 단계는 큐비트를 알려진 상태로 초기화하는 Q# 연산을 정의하는 것입니다. 큐비트를 클래식 상태로 설정하려면 이를 호출합니다. 즉, 시간의 Zero 100%를 반환하거나 시간의 One 100%를 반환합니다. ZeroOne은 큐비트 측정에서 가능한 두 가지 결과를 나타내는 Q# 값입니다.

+ 코드를 클릭하여 새 셀을 추가하고 다음 코드를 추가합니다.

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

참고

이 코드의 연산에서 사용되는 Microsoft.Quantum.IntrinsicMicrosoft.Quantum.Canon 네임스페이스는 Azure Quantum Notebook의 모든 셀에서 자동으로 열립니다.

이 코드 예제는 큐비트 상태를 변환하는 두 가지 연산인 MX를 소개합니다.

SetQubitState 연산:

  1. 두 개의 매개 변수를 사용합니다. 하나는 필요한 상태가 큐비트(0 또는 1)임을 나타내는 desired라는 Result 형식이고 다른 하나는 Qubit 형식입니다.
  2. 큐비트(Zero 또는 One)의 상태를 측정하고 결과를 desired에 지정된 값과 비교하는 측정 연산 M을 수행합니다.
  3. 측정값이 비교된 값과 일치하지 않는 경우 X 연산을 실행합니다. 이 연산은 측정이 ZeroOne을 반환할 확률이 역전되도록 큐비트의 상태를 플리핑합니다. 이러한 방식으로 SetQubitState는 항상 대상 큐비트를 원하는 상태로 설정합니다.

측정 테스트

이제 SetQubitState 연산의 효과를 보여 주기 위해 이름이 TestBellState인 다른 연산을 만듭니다.

새 셀을 또 하나 추가하고 다음 코드를 추가합니다.

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

}

TestBellState 연산:

  1. 두 매개 변수를 사용합니다. 하나는 측정을 실행할 횟수인 count이고 다른 하나는 큐비트를 초기화할 필요한 상태인 initial입니다.
  2. use 문을 호출하여 두 큐비트를 초기화합니다.
  3. count 반복을 반복합니다. 각 루프에 대해
    1. SetQubitState를 호출하여 첫 번째 큐비트에 지정된 initial 값을 설정합니다.
    2. SetQubitState를 다시 호출하여 두 번째 큐비트를 Zero 상태로 설정합니다.
    3. M 연산을 사용하여 각 큐비트를 측정합니다.
    4. One을 반환하는 각 큐비트의 측정 수를 저장합니다.
  4. 루프가 완료되면 SetQubitState를 다시 호출하여 큐비를 알려진 상태(Zero)로 다시 설정합니다. 그러면 다른 사용자가 큐비트를 알려진 상태에서 할당할 수 있습니다. 이는 use 문에 필요합니다.
  5. 마지막으로, 결과를 반환하기 전에 Message 함수를 사용하여 콘솔에 메시지를 표시합니다.

코드 테스트

중첩 및 얽힘 프로시저로 이동하기 전에 이 지점까지 코드를 테스트하여 큐비트의 초기화 및 측정을 확인합니다.

TestBellState 연산을 실행하려면 %simulate 매직 명령을 사용하여 Azure Quantum 전체 상태 시뮬레이터를 호출합니다. countinitial 인수를 지정해야 향 합니다(예: count=1000initial=1). 그러면 첫 번째 큐비트를 One로 초기화하고 각 큐비트를 1,000번 측정합니다. 다음 명령을 사용하여 새 셀을 추가하고 모두 실행을 클릭합니다.

%simulate TestBellState count=1000 initial=1

그러면 다음과 같이 출력됩니다.

q1:Zero, One  q2:Zero, One
(0, 1000, 1000, 0)

큐비트는 아직 조작되지 않았기 때문에 초기 값을 유지했습니다. 첫 번째 큐비트는 매번 One을 반환하고 두 번째 큐비트는 Zero을 반환합니다.

셀을 initial=0으로 다시 실행하면 첫 번째 큐비트도 매번 Zero를 반환하는 것을 알 수 있습니다.

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

큐비트를 중첩에 넣기

현재 프로그램의 큐비트는 모두 클래식 상태입니다. 즉, 1 또는 0입니다. 프로그램에서 큐비트를 알려진 상태로 초기화하고 조작할 프로세스를 추가하지 않았기 때문에 이를 알 수 있습니다. 큐비트를 얽기 전에 첫 번째 큐비트를 중첩 상태로 전환합니다. 이 상태에서는 큐비트의 측정이 50%의 시간에서 Zero를 반환하고 50%의 시간에서 One을 반환합니다. 개념적으로 큐비트는 ZeroOne 사이에서 모든 상태의 선형 조합으로 간주될 수 있습니다.

큐비트를 중첩에 배치하기 위해 Q#에서는 H 또는 Hadamard 연산을 제공합니다. 큐비트를 0에서 1로(또는 그 반대로) 플립한 이전의 측정값을 사용한 큐비트 초기화 프로시저에서의 X 연산을 다시 떠올려 보겠습니다. H 연산은 0 또는 1의 동일한 확률 상태로 큐비트를 중간으로 대칭 이동합니다. 측정할 때 중첩의 큐비트는 대략 동일한 수의 ZeroOne 결과를 반환해야 합니다.

TestBellState를 사용한 이전 셀에서 for 루프 내부에 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); 

%simulate 명령에서 큐비트를 다시 1로 초기화하고 모두 실행을 클릭하면 중첩 상태의 첫 번째 큐비트의 결과를 볼 수 있습니다.

%simulate TestBellState count=1000 initial=1
q1:Zero, One  q2:Zero, One
(523, 477, 1000, 0)      // results will vary

프로그램을 실행할 때마다 첫 번째 큐비트의 결과는 약간씩 달라지지만 50% One과 50% Zero에 가깝고 두 번째 큐비트의 결과는 항상 Zero를 유지합니다.

Q1:Zero/One  Q2:Zero/One
(510, 490, 1000, 0)

첫 번째 큐비트를 Zero로 초기화하면 유사한 결과를 반환합니다.

%simulate TestBellState count=1000 initial=0
Q1:Zero/One  Q2:Zero/One
(504, 496, 1000, 0)

두 큐비트 얽기

앞에서 설명한 것처럼 얽힌 큐비트는 서로 독립적으로 설명할 수 없도록 연결됩니다. 즉, 얽힌 쌍의 한 큐비트에 어떤 연산이 발생하든 다른 큐비트에도 발생합니다. 이렇게 하면 다른 큐비트의 상태를 측정하여 측정하지 않고 한 큐비트의 결과 상태를 알 수 있습니다. 이 예제에서는 두 큐비트를 사용하지만 셋 이상의 큐비트를 얽을 수도 있습니다.

얽힘을 사용하도록 설정하기 위해 Q#에서는 CNOTControled-NOT을 나타내는 연산을 제공합니다. 두 큐비트에 대해 이 연산을 실행하면 그 결과로 첫 번째 큐비트가 One인 경우 두 번째 큐비트가 대칭 이동됩니다.

H 연산 직후의 for 루프에 CNOT 연산을 추가합니다. 이제 TestBellState 연산이 다음과 같이 표시됩니다.

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);                   // added CNOT operation
        
        // 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 );

}

모두 실행을 클릭하여 업데이트된 연산을 실행하면 다음이 출력됩니다.

Q1:Zero/One  Q2:Zero/One
(502, 498, 502, 498)      // actual results will vary

첫 번째 큐비트에 대한 통계는 변경되지 않았지만(측정 후 Zero 또는 One의 50/50 확률) 두 번째 큐비트의 측정 결과는 큐비트가 무엇으로 초기화되든 항상 첫 번째 큐비트의 측정값과 동일합니다. CNOT 연산은 두 큐비트를 얽어서 두 큐비트 중 한 큐비트에서 발생하는 모든 것이 다른 큐비트에서 발생하도록 했습니다.

필수 조건

이 자습서에서는 다음 방법에 대해 알아봅니다.

  • 큐비트를 측정하고 원하는 상태로 초기화하는 Q# 연산을 만듭니다.
  • 큐비트를 만들고 프로그램을 테스트합니다.
  • 큐비트를 중첩에 넣습니다.
  • 큐비트 쌍을 얽습니다.

측정을 사용하여 큐비트 초기화

첫 번째 단계는 큐비트를 알려진 상태로 초기화하는 Q# 연산을 정의하는 것입니다. 이를 호출하여 큐비트를 클래식 상태로 설정할 수 있습니다. 즉, 시간의 Zero 100%를 반환하거나 시간의 One 100%를 반환합니다. ZeroOne은 큐비트 측정에서 가능한 두 가지 결과를 나타내는 Q# 값입니다.

프로젝트에서 Program.qs의 내용을 다음 코드로 바꿉니다.

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

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

이 코드 예제는 큐비트 상태를 변환하는 두 가지 연산인 MX를 소개합니다.

SetQubitState 연산:

  1. 두 개의 매개 변수를 사용합니다. 하나는 필요한 상태가 큐비트(0 또는 1)임을 나타내는 desired라는 Result 형식이고 다른 하나는 Qubit 형식입니다.
  2. 큐비트(Zero 또는 One)의 상태를 측정하고 결과를 desired에 지정된 값과 비교하는 측정 연산 M을 수행합니다.
  3. 측정값이 비교된 값과 일치하지 않는 경우 X 연산을 실행합니다. 이 연산은 측정이 ZeroOne을 반환할 확률이 역전되도록 큐비트의 상태를 플리핑합니다. 이러한 방식으로 SetQubitState는 항상 대상 큐비트를 원하는 상태로 설정합니다.

측정 테스트

이제 SetQubitState 연산의 효과를 보여 주기 위해 이름이 TestBellState인 다른 연산을 만듭니다.

Program.qs 파일에서 SetQubitState 연산 이후에 다음 연산을 추가합니다.

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

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

    // Return times we saw |0>, times we saw |1>
    Message("q1:Zero, One  q2:Zero, One");
    return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

}

TestBellState 연산:

  1. 두 매개 변수를 사용합니다. 하나는 측정을 실행할 횟수인 count이고 다른 하나는 큐비트를 초기화할 필요한 상태인 initial입니다.
  2. use 문을 호출하여 두 큐비트를 초기화합니다.
  3. count 반복을 반복합니다. 각 루프에 대해
    1. SetQubitState를 호출하여 첫 번째 큐비트에 지정된 initial 값을 설정합니다.
    2. SetQubitState를 다시 호출하여 두 번째 큐비트를 Zero 상태로 설정합니다.
    3. M 연산을 사용하여 각 큐비트를 측정합니다.
    4. One을 반환하는 각 큐비트의 측정 수를 저장합니다.
  4. 루프가 완료되면 SetQubitState를 다시 호출하여 큐비를 알려진 상태(Zero)로 다시 설정합니다. 그러면 다른 사용자가 큐비트를 알려진 상태에서 할당할 수 있습니다. 이는 use 문에 필요합니다.
  5. 마지막으로, 결과를 반환하기 전에 Message 함수를 사용하여 콘솔에 메시지를 출력합니다.

명령 프롬프트에서 코드를 실행합니다.

중첩 및 얽힘 프로시저로 이동하기 전에 이 시점까지 코드를 테스트하여 큐비트의 초기화 및 측정을 확인합니다.

코드를 독립 실행형 프로그램으로 실행하려면 Q# 컴파일러가 dotnet run 명령을 실행할 때 프로그램을 시작할 위치를 알아야 합니다. 이를 위해 Q# 파일에서 실행하려는 연산의 바로 앞에 @EntryPoint()를 추가합니다. 이 경우에는 TestBellState 연산입니다.

참고

@EntryPoint()는 독립 실행형 Q# 프로그램에만 필요합니다. Jupyter Notebook에서 Q# 프로그램을 실행하거나 Python 또는 .NET 호스트 파일에서 Q# 프로그램을 호출하는 경우에는 필요하지 않으며, 포함되면 오류가 발생합니다.

이제 program.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(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' we saw:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Return times we saw |0>, times we saw |1>
        Message("q1:Zero, One  q2:Zero, One");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

프로그램을 실행하려면 명령 프롬프트에서 countinitial 인수를 지정해야 합니다. 예를 들어 --count 1000--initial One은 첫 번째 큐비트를 One으로 초기화하고 각 큐비트를 1000번 측정합니다. 다음 명령을 실행합니다.

dotnet run --count 1000 --initial One

그러면 다음과 같이 출력됩니다.

Q1:Zero/One  Q2:Zero/One
(0, 1000, 1000, 0)

큐비트는 아직 조작되지 않았기 때문에 초기 값을 유지했습니다. 첫 번째 큐비트는 매번 One을 반환하고 두 번째 큐비트는 Zero를 반환합니다.

셀을 --initial Zero로 다시 실행하면 첫 번째 큐비트도 매번 Zero를 반환하는 것을 알 수 있습니다.

dotnet run --count 1000 --initial Zero
Q1:Zero/One  Q2:Zero/One
(1000, 0, 1000, 0)

큐비트를 중첩에 넣기

현재 프로그램의 큐비트는 모두 클래식 상태입니다. 즉, 1 또는 0입니다. 프로그램에서 큐비트를 알려진 상태로 초기화하고 조작할 프로세스를 추가하지 않았기 때문에 이를 알 수 있습니다. 큐비트를 얽기 전에 첫 번째 큐비트를 중첩 상태로 전환합니다. 여기서 큐비트의 측정값은 Zero(시간의 50%) 및 One(시간의 50%)을 반환합니다. 개념적으로 큐비트는 ZeroOne의 중간으로 생각할 수 있습니다.

큐비트를 중첩에 배치하기 위해 Q#에서는 H 또는 Hadamard 연산을 제공합니다. 큐비트를 0에서 1로(또는 그 반대로) 플립한 이전의 측정값을 사용한 큐비트 초기화 프로시저에서의 X 연산을 다시 떠올려 보겠습니다. H 연산은 0 또는 1의 동일한 확률 상태로 큐비트를 중간으로 대칭 이동합니다. 측정할 때 중첩의 큐비트는 대략 동일한 수의 ZeroOne 결과를 반환해야 합니다.

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

이제 프로그램을 실행할 때 중첩에서 첫 번째 큐비트의 결과를 볼 수 있습니다.

dotnet run --count 1000 --initial One
Q1:Zero/One  Q2:Zero/One
(523, 477, 1000, 0)      // results will vary

프로그램을 실행할 때마다 첫 번째 큐비트의 결과는 약간 다르지만 50% One 및 50% Zero에 가까우며 두 번째 큐비트의 결과는 항상 Zero로 유지됩니다.

dotnet run --count 1000 --initial One
Q1:Zero/One  Q2:Zero/One
(510, 490, 1000, 0)

첫 번째 큐비트를 Zero로 초기화하면 유사한 결과를 반환합니다.

dotnet run --count 1000 --initial Zero
Q1:Zero/One  Q2:Zero/One
(504, 496, 1000, 0)

두 큐비트 얽기

앞에서 설명한 것처럼 얽힌 큐비트는 서로 독립적으로 설명할 수 없도록 연결됩니다. 즉, 하나의 큐비트에 어떤 연산이 일어나든 얽힌 큐비트에도 발생합니다. 이렇게 하면 다른 큐비트의 상태를 측정하여 측정하지 않고 한 큐비트의 결과 상태를 알 수 있습니다. 이 예제에서는 두 큐비트를 사용하지만 셋 이상의 큐비트를 얽을 수도 있습니다.

얽힘을 사용하도록 설정하기 위해 Q#에서는 CNOTControled-NOT을 나타내는 연산을 제공합니다. 두 큐비트에 대해 이 연산을 실행하면 그 결과로 첫 번째 큐비트가 One인 경우 두 번째 큐비트가 대칭 이동됩니다.

프로그램에서 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(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);      // Add the CNOT operation after the H operation

            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' we saw:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Return times we saw |0>, times we saw |1>
        Message("q1:Zero, One  q2:Zero, One");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

이제 프로그램을 실행합니다.

dotnet run --count 1000 --initial One
Q1:Zero/One  Q2:Zero/One
(502, 498, 502, 498)

첫 번째 큐비트에 대한 통계는 변경되지 않았지만(측정 후 Zero 또는 One의 확률 50/50) 두 번째 큐비트의 측정 결과는 항상 첫 번째 큐비트의 측정과 동일합니다. CNOT 연산은 두 큐비트를 얽어서 둘 중 하나에서 발생하는 모든 것이 다른 큐비트에서도 발생하도록 했습니다.

다음 단계

다른 양자 알고리즘 및 기술을 계속 탐색합니다.

  • Grover의 검색 알고리즘 구현 자습서에서는 Grover의 검색 알고리즘을 사용하여 그래프 색 지정 문제를 해결하는 Q# 프로그램을 작성하는 방법을 보여 줍니다.
  • Q#으로 큐비트 수준 프로그램 작성 및 시뮬레이션에서는 직접 특정 큐비트의 주소를 지정하는 Q# 프로그램 작성 방법을 살펴봅니다.
  • Quantum Kata는 양자 컴퓨팅과 Q# 프로그래밍의 요소를 동시에 가르치기 위한 Jupyter Notebook 기반의 자기 주도적 자습서 및 프로그래밍 연습입니다.