다음을 통해 공유


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

이 자습서에서는 큐비트를 조작하고 측정하며 중첩 및 얽힘의 효과를 보여 주는 프로그램을 작성 Q# 합니다. 특정 양자 상태에서 두 개의 큐비트를 준비하고, 큐비트 Q# 에서 작동하여 상태를 변경하는 방법을 알아보고, 중첩 및 얽힘의 효과를 보여 줍니다. 큐비트 상태, 작업 및 측정값을 소개하는 프로그램을 하나씩 빌드 Q# 합니다.

시작하기 전에 이해해야 할 몇 가지 주요 개념은 다음과 같습니다.

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

이 자습서에서는 다음 작업을 수행하는 방법을 알아봅니다.

  • 큐비트를 원하는 상태로 초기화하는 작업을 만듭니 Q# 다.
  • 큐비트를 중첩에 넣습니다.
  • 큐비트 쌍을 얽습니다.
  • 큐비트를 측정하고 결과를 관찰합니다.

양자 컴퓨팅 과정을 가속화하려면 Azure Quantum 웹 사이트의 고유한 기능인 Azure Quantum을 사용하여 코드를 확인하세요. 여기서는 기본 제공 Q# 샘플 또는 사용자 고유 Q# 의 프로그램을 실행하고, 프롬프트에서 새 Q# 코드를 생성하고, 한 번의 클릭으로 웹용 VS Code에서 코드를 열고 실행하고, Copilot에게 양자 컴퓨팅에 대한 질문을 할 수 있습니다.

필수 조건

Azure Quantum용 Copilot에서 코드 샘플을 실행하려면 다음이 필요합니다.

  • Microsoft(MSA) 전자 메일 계정입니다.

Copilot에 대한 자세한 내용은 Azure Quantum 탐색을 참조 하세요.

알려진 상태로 큐비트 초기화

첫 번째 단계는 큐비트를 알려진 상태로 초기화하는 Q# 연산을 정의하는 것입니다. 이 연산은 큐비트를 클래식 상태로 설정하기 위해 호출할 수 있습니다. 즉, 측정 시 100%의 시간을 반환 Zero 하거나 시간의 100%를 반환 One 합니다. 큐비트를 측정하면 값 Q#Result또는 값만 가질 수 있는 형식Zero이 반환됩니다One.

Azure Quantum용 Copilot를 열고 다음 코드를 코드 편집기 창에 복사합니다. 아직 실행 선택하지 마세요. 자습서의 뒷부분에서 코드를 실행합니다.

import Microsoft.Quantum.Intrinsic.*;
import Microsoft.Quantum.Canon.*;

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

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

SetQubitState 연산:

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

종 상태를 테스트하는 테스트 작업 작성

이제 SetQubitState 연산의 효과를 보여 주기 위해 이름이 Main인 다른 연산을 만듭니다. 이 작업은 두 개의 큐비트를 할당하고 첫 SetQubitState 번째 큐비트를 알려진 상태로 설정한 다음 큐비트를 측정하여 결과를 확인합니다.

다음 코드를 작업 아래의 코드 편집기 창에 복사합니다 SetQubitState .

operation Main() : (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 {
            numOnesQ1 += 1;
        }
        if resultQ2 == One {
            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로 초기화하고 각 큐비트를 1,000번 측정합니다.

Main 연산:

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

Azure Quantum에 대한 Copilot에서 코드 실행

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

코드를 독립 실행형 프로그램으로 실행하려면 Copilot의 Q# 컴파일러가 프로그램을 시작할 위치를 알고 있어야 합니다. 네임스페이스를 지정하지 않으므로 컴파일러는 기본 진입점을 작업으로 Main 인식합니다. 자세한 내용은 프로젝트 및 암시적 네임스페이스를 참조 하세요.

Q# 이제 이 시점까지의 프로그램은 다음과 같이 표시됩니다.

import Microsoft.Quantum.Intrinsic.*;
import Microsoft.Quantum.Canon.*;

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

operation Main() : (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 {
            numOnesQ1 += 1;
        }
        if resultQ2 == One {
            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 );

}

전체 코드 샘플을 복사하여 Azure Quantum 코드 창의 Copilot에 붙여넣고, 샷 수에 대한 슬라이더를 "1"로 설정하고, 실행을 선택합니다. 결과는 히스토그램 및 결과 필드에 표시됩니다.

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

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

값을 initialZero 변경하고 프로그램을 다시 실행하는 경우 첫 번째 큐비트가 매번 반환 Zero 되는지 확인해야 합니다.

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

Ctrl-Z>다시 실행하기 전에 코드에 테스트 변경 내용을 적용할 때마다 파일을 저장합니다.

큐비트를 중첩에 넣기

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

큐비트를 중첩에 배치하기 위해 Q#에서는 H 또는 Hadamard 연산을 제공합니다. X 큐비트를 0에서 프로시저로 큐비트 초기화 작업을 회수합니다. 이 작업은 큐비트를 H 동일한 확률 또는 Zero같음 상태로 대칭 이동합니다. 측정할 때 중첩의 큐비트는 대략 동일한 수의 ZeroOne 결과를 반환해야 합니다.

초기 값을 Main 다시 설정하여 작업의 줄을 One 삽입하여 작업의 코드를 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 vary
Q1 - Ones: 477
Q2 - Zeros: 1000
Q2 - Ones: 0

프로그램을 실행할 때마다 첫 번째 큐비트의 결과는 약간 다르지만 50% One 와 50%에 Zero가까우며 두 번째 큐비트의 결과는 항상 유지됩니다 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에서 슬라이더를 이동하고 샷 수를 늘리면 중첩 결과가 샷 분포에 따라 약간 달라지는 방식을 확인할 수 있습니다.

두 큐비트 얽기

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

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

프로그램에서 CNOT 연산 바로 다음에 H 연산을 추가합니다. 전체 프로그램은 다음과 같습니다.

import Microsoft.Quantum.Intrinsic.*;
import Microsoft.Quantum.Canon.*;

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

operation Main() : (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 {
            numOnesQ1 += 1;
        }
        if resultQ2 == One {
            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의 ZeroOne 확률은 여전히 있음) 두 번째 큐비트의 측정 결과는 프로그램을 실행하는 횟수에 관계없이 항상 첫 번째 큐비트의 측정값과 동일합니다. CNOT 연산은 두 큐비트를 얽어서 두 큐비트 중 한 큐비트에서 발생하는 모든 것이 다른 큐비트에서 발생하도록 했습니다.

필수 조건

로컬 개발 환경에서 코드 샘플을 개발하고 실행하려면 다음을 수행합니다.

새 Q# 파일 만들기

  1. Visual Studio Code를 열고 파일>새 텍스트 파일을 선택하여 새 파일을 만듭니다.
  2. 파일을 CreateBellStates.qs로 저장합니다. 이 파일에는 프로그램에 대한 코드가 Q# 포함됩니다.

알려진 상태로 큐비트 초기화

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

다음 코드를 열고 CreateBellStates.qs 복사합니다.

import Microsoft.Quantum.Intrinsic.*;
import Microsoft.Quantum.Canon.*;

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

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

SetQubitState 연산:

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

종 상태를 테스트하는 테스트 작업 작성

이제 SetQubitState 연산의 효과를 보여 주기 위해 이름이 Main인 다른 연산을 만듭니다. 이 작업은 두 개의 큐비트를 할당하고, SetQubitState 첫 번째 큐비트를 알려진 상태로 설정한 다음, 큐비트를 측정하여 결과를 확인합니다.

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

operation Main() : (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 {
            numOnesQ1 += 1;
        }
        if resultQ2 == One {
            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번 측정합니다.

Main 연산:

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

코드 실행

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

코드를 독립 실행형 프로그램으로 실행하려면 컴파일러가 Q# 프로그램을 시작할 위치를 알고 있어야 합니다. 네임스페이스를 지정하지 않으므로 컴파일러는 기본 진입점을 작업으로 Main 인식합니다. 자세한 내용은 프로젝트 및 암시적 네임스페이스를 참조 하세요.

  1. CreateBellStates.qs 이제 이 시점까지의 파일은 다음과 같습니다.

    import Microsoft.Quantum.Intrinsic.*;
    import Microsoft.Quantum.Canon.*;
    
    operation SetQubitState(desired : Result, target : Qubit) : Unit {
        if desired != M(target) {
            X(target);
        }
    }
    
    operation Main() : (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 {
                numOnesQ1 += 1;
            }
            if resultQ2 == One {
                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. 프로그램을 실행하기 전에 대상 프로필이 무제한으로 설정되어 있는지 확인합니다. 보기 - 명령 팔레트를 선택하고>

    참고 항목

    대상 프로필이 무제한으로 설정되지 않은 경우 프로그램을 실행할 때 오류가 발생합니다.

  3. 프로그램을 실행하려면 오른쪽 위에 있는 재생 아이콘 드롭다운에서 파일 실행을 선택하고, 작업 앞의 명령 목록에서 실행을Q#하거나, Ctrl+F5 누릅니 Main 다. 프로그램은 기본 시뮬레이터에서 작업을 실행 Main 합니다.

  4. 출력이 디버그 콘솔에 표시됩니다.

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

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

  5. 값을 initialZero 변경하고 프로그램을 다시 실행하는 경우 첫 번째 큐비트가 매번 반환 Zero 되는지 확인해야 합니다.

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

Ctrl-Z>다시 실행하기 전에 코드에 테스트 변경 내용을 적용할 때마다 파일을 저장합니다.

큐비트를 중첩에 넣기

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

큐비트를 중첩에 배치하기 위해 Q#에서는 H 또는 Hadamard 연산을 제공합니다. X 큐비트를 이전에 알려진 상태회수합니다. 이 연산은 큐비트를 Zero 같은 확률 One 또는 H같은 상태로 대칭 이동합니다. 측정할 때 중첩의 큐비트는 대략 동일한 수의 ZeroOne 결과를 반환해야 합니다.

  1. Main 연산을 포함하도록 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. 프로그램을 실행할 때마다 첫 번째 큐비트의 결과는 약간 다르지만 50% One 와 50%에 Zero가까우며 두 번째 큐비트의 결과는 항상 유지됩니다 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
    

두 큐비트 얽기

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

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

  1. 프로그램에서 CNOT 연산 바로 다음에 H 연산을 추가합니다. 전체 프로그램은 다음과 같습니다.

    import Microsoft.Quantum.Intrinsic.*;
    import Microsoft.Quantum.Canon.*;
    
        operation SetQubitState(desired : Result, target : Qubit) : Unit {
            if desired != M(target) {
                X(target);
            }
        }
    
    operation Main() : (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 {
                numOnesQ1 += 1;
            }
            if resultQ2 == One {
                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
    Result: "(502, 498, 502, 498)"
    

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

빈도 히스토그램 그리기

양자 프로그램을 여러 번 실행하여 얻은 결과의 분포를 시각화해 보겠습니다. 빈도 히스토그램은 이러한 결과의 확률 분포를 시각화하는 데 도움이 됩니다.

  1. 보기 - 명령 팔레트>하거나 Ctrl+Shift+P를 누르고 : 파일을 표시Q#"을 입력합니다. 앞의 명령 목록에서 히스토그램을 선택할 수도 있습니다Main. 히스토그램 창을 열려 Q# 면 이 옵션을 선택합니다.

  2. 프로그램을 실행하는 여러 (예: 100개의 샷)을 입력하고 Enter 키를 누릅니 . 히스토그램 창에 히스토그램이 Q# 표시됩니다.

  3. 히스토그램의 각 막대는 가능한 결과에 해당하며, 높이가 결과가 관찰되는 횟수를 나타냅니다. 이 경우 50개의 고유한 결과가 있습니다. 각 결과에 대해 첫 번째 큐비트와 두 번째 큐비트의 측정 결과는 항상 동일합니다.

    Visual Studio Code의 Q# 히스토그램 창을 스크린샷으로 표시합니다.

    마우스 스크롤 휠 또는 트랙 패드 제스처를 사용하여 히스토그램을 확대/축소할 수 있습니다. 확대하면 스크롤하는 동안 Alt 키를 눌러 차트를 이동하면 됩니다.

  4. 막대를 선택하여 해당 결과의 백분율표시합니다.

  5. 왼쪽 위 설정 아이콘 을 선택하여 옵션을 표시합니다. 상위 10개 결과, 상위 25개 결과 또는 모든 결과를 표시할 수 있습니다. 결과를 높음에서 낮음 또는 낮음에서 높음으로 정렬할 수도 있습니다.

    Q# 설정을 표시하는 방법을 보여 주는 Visual Studio Code의 히스토그램 창을 스크린샷으로 표시합니다.

다른 Q# 자습서 살펴보기:

  • Grover의 검색 알고리즘 은 Grover의 검색 알고리즘을 Q# 사용하는 프로그램을 작성하는 방법을 보여줍니다.
  • Quantum Fourier Transform 은 특정 큐비트를 Q# 직접 해결하는 프로그램을 작성하는 방법을 살펴봅니다.
  • Quantum Katas는 양자 컴퓨팅 및 프로그래밍 요소를 동시에 교육하기 위한 자가 진행 자습서 및 Q# 프로그래밍 연습입니다.