자습서: Q#에서 양자 난수 생성기 구현

참고

Microsoft Quantum Development Kit (클래식 QDK)는 2024년 6월 30일 이후에 더 이상 지원되지 않습니다. 기존 QDK 개발자인 경우 새로운 Azure Quantum Development Kit (최신 QDK) 로 전환하여 양자 솔루션을 계속 개발하는 것이 좋습니다. 자세한 내용은 최신 QDK로 코드 마이그레이션을 참조하세요Q#.

양자 역학의 특성을 활용하여 난수를 생성하는 기본 양자 프로그램을 Q#으로 작성하는 방법을 알아봅니다.

이 자습서에서는 다음을 수행합니다.

  • Q# 프로그램을 Create.
  • 프로그램의 기본 구성 요소를 검토합니다Q#.
  • 문제의 논리를 정의합니다.
  • 클래식 및 양자 연산을 결합하여 문제를 해결합니다.
  • 큐빗 및 중첩을 사용하여 양자 난수 생성기를 빌드합니다.

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

사전 요구 사항

문제 정의

일반 컴퓨터에서는 난수가 아니라 의사 난수를 생성합니다. 의사 난수 생성기는 시드라고 하는 일부 초기값을 기준으로 결정적 숫자 시퀀스를 생성합니다. 임의 값을 보다 정확하게 근사하기 위해 이 시드는 CPU 클록의 현재 시간인 경우가 많습니다.

반면 양자 컴퓨터는 실제로 난수를 생성할 수 있습니다. 중첩에서 큐비트의 측정이 확률적 프로세스이기 때문입니다. 측정 결과는 임의이며 결과를 예측할 방법이 없습니다. 양자 난수 생성기의 기본 원칙입니다.

큐비트는 중첩에 있을 수 있는 양자 정보의 단위입니다. 측정할 때 큐비트는 0 상태 또는 1 상태일 수 있습니다. 하지만 측정 전 큐비트 상태는 측정값이 0 또는 1일 수 있는 확률을 나타냅니다.

먼저 기저 상태(예: 0)의 큐비트로 시작합니다. 난수 생성기의 첫 번째 단계는 Hadamard 연산을 사용하여 큐비트를 동일한 중첩에 배치하는 것입니다. 이 상태를 측정하면 각 결과의 확률이 50%인 0 또는 1이 실제로 임의 비트가 됩니다.

중첩에서 큐비트를 측정한 후에 무엇을 얻을지 알 수 있는 방법은 없으며, 결과는 코드가 호출될 때마다 다른 값입니다. 그러나 이 동작을 사용하여 더 큰 난수를 생성하려면 어떻게 해야 할까요?

프로세스를 4번 반복하여 다음과 같은 이진수 시퀀스를 생성한다고 가정하겠습니다.

$${0, 1, 1, 0}$$

이러한 비트를 비트 문자열로 연결하거나 결합하면 더 큰 숫자를 형성할 수 있습니다. 이 예제에서 비트 시퀀스 ${0110}$는 10진수 6과 같습니다.

$${0110_{\ binary} \equiv 6_{\ decimal}}$$

이 프로세스를 여러 번 반복하면 여러 비트를 결합하여 큰 숫자를 구성할 수 있습니다. 이제 우주 해커가 측정 시퀀스의 결과를 알 수 없다는 것이 확실하므로 해당 숫자를 보안 암호로 제공할 수 있습니다.

난수 생성기 논리 정의

임의 비트 생성기가 있는 경우 난수 생성기의 논리를 간략하게 설명해 보겠습니다.

  1. max를 생성하려는 최대 수로 정의합니다.
  2. 생성해야 하는 임의 비트의 수를 정의합니다. 이를 위해 최대 정수 max를 표현하는 데 필요한 비트 수 nBits를 계산합니다.
  3. 길이가 nBits인 임의 비트 문자열을 생성합니다.
  4. 비트 문자열이 max보다 큰 숫자를 나타내는 경우 3단계로 돌아갑니다.
  5. 그렇지 않으면 프로세스가 완료된 것입니다. 생성된 숫자를 정수로 반환합니다.

예를 들어 max를 12로 설정하겠습니다. 여기서 12는 보안 암호로 사용하려는 가장 큰 숫자입니다.

0에서 12 사이의 숫자를 나타내려면 ${\lfloor ln(12) / ln(2) + 1 \rfloor}$, 즉 4비트가 필요합니다. (간결한 설명을 위해 이 수식을 유도하는 방법은 생략합니다.)

${13_{\ decimal}}$에 해당하는 비트 문자열 ${1101_{\ binary}}$를 생성한다고 가정하겠습니다. 13은 12보다 크므로 프로세스를 반복합니다.

다음으로 ${6_{\ decimal}}$에 해당하는 비트 문자열 ${0110_{\ binary}}$를 생성합니다. 6은 12보다 작으므로 프로세스는 완료된 것입니다.

양자 난수 생성기는 숫자 6을 암호로 반환합니다. 적은 수의 값은 가능한 모든 암호를 시도하여 쉽게 해독할 수 있기 때문에 실제로는 더 큰 숫자를 최댓값으로 설정합니다. 실제로 암호 추측 또는 해독을 어렵게 하기 위해 ASCII 코드를 사용하여 이진을 텍스트로 변환하고 숫자, 기호, 대/소문자를 사용하여 암호를 생성할 수 있습니다.

임의 비트 생성기 작성

첫 번째 단계는 임의 Q# 비트를 생성하는 작업을 작성하는 것입니다. 이 작업은 난수 생성기의 구성 요소 중 하나가 됩니다.

operation GenerateRandomBit() : Result {
    // Allocate a qubit.
    use q = Qubit();

    // Set the qubit into superposition of 0 and 1 using the Hadamard 
    H(q);

    // At this point the qubit `q` has 50% chance of being measured in the
    // |0〉 state and 50% chance of being measured in the |1〉 state.
    // Measure the qubit value using the `M` operation, and store the
    // measurement value in the `result` variable.
    let result = M(q);

    // Reset qubit to the |0〉 state.
    // Qubits must be in the |0〉 state by the time they are released.
    Reset(q);

    // Return the result of the measurement.
    return result;
}

이제 새 코드를 살펴보겠습니다.

  • 입력 없이 Result 형식의 값을 생성하는 GenerateRandomBit 연산을 정의합니다. Result 형식은 측정 결과를 나타내며 두 가지 가능한 값은 Zero 또는 One입니다.
  • 키워드(keyword) 사용하여 단일 큐비트를 할당합니다 use . 할당되는 경우 큐비트는 항상 Zero 상태입니다.
  • 연산을 H 사용하여 큐비트를 동일한 중첩에 배치합니다.
  • 연산을 M 사용하여 큐비트를 측정하고 측정된 값(Zero 또는 One)을 반환합니다.
  • 작업을 사용하여 Reset 큐비트를 |0( ) 상태로 다시 설정합니다.

H 연산을 사용하여 큐비트를 중첩 상태로 전환하고 M 연산으로 측정하면 코드가 호출될 때마다 다른 결과 값이 반환됩니다.

Bloch Q# 구를 사용하여 코드 시각화

Bloch 구의 북극은 클래식 0 값을 나타내고, 남극은 클래식 1 값을 나타냅니다. 모든 중첩은 구의 점으로 표현할 수 있습니다(화살표로 표시). 화살표의 끝부분이 극에 가까울수록 측정 시 큐비트가 해당 극에 할당된 클래식 값으로 축소될 확률이 높아집니다. 예를 들어 다음 그림에서 빨간색 화살표로 표현되는 큐비트 상태는 측정될 경우 0 값을 제공할 확률이 높습니다.

0을 측정할 확률이 높은 큐비트 상태를 보여 주는 다이어그램

이 표현을 사용하여 코드가 하는 일을 시각화할 수 있습니다.

  1. 먼저 0 상태에서 초기화된 큐비트로 시작하고, H 연산을 적용하여 01의 확률이 동일한 동등 중첩을 만듭니다.

    hadamard 게이트를 적용하여 중첩에서 큐비트의 준비를 보여 주는 다이어그램
  2. 그런 다음, 큐비트를 측정하고 출력을 저장합니다.

    큐비트의 측정 및 출력 저장을 보여 주는 다이어그램

측정 결과는 임의이고 01을 측정할 확률은 동일하므로 완전히 임의 비트를 얻었습니다. 이 연산을 여러 번 호출하여 정수를 만들 수 있습니다. 예를 들어 이 연산을 세 번 호출하여 세 개의 임의 비트를 얻으면 임의의 3비트 숫자(즉, 0~7 사이의 임의 숫자)를 빌드할 수 있습니다.

전체 난수 생성기 작성

  1. 먼저 필요한 Q# 네임스페이스를 프로그램에 추가해야 합니다. 전체 난수 생성기의 경우 세 개의 네임스페이스Microsoft.Quantum.Math, , Microsoft.Quantum.IntrinsicMicrosoft.Quantum.Convert를 포함 Q# 해야 합니다.

    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;
    
  2. 다음으로 작업을 정의합니다 GenerateRandomNumberInRange . 이 작업은 GenerateRandomBit 작업을 반복적으로 호출하여 비트 문자열을 생성합니다.

        /// Generates a random number between 0 and `max`.
        operation GenerateRandomNumberInRange(max : Int) : Int {
            // Determine the number of bits needed to represent `max` and store it
            // in the `nBits` variable. Then generate `nBits` random bits which will
            // represent the generated random number.
            mutable bits = [];
            let nBits = BitSizeI(max);
            for idxBit in 1..nBits {
                set bits += [GenerateRandomBit()];
            }
            let sample = ResultArrayAsInt(bits);
    
            // Return random number if it is within the requested range.
            // Generate it again if it is outside the range.
            return sample > max ? GenerateRandomNumberInRange(max) | sample;
        }
    
    

    잠시 새 코드를 검토해 보겠습니다.

    • 최대 정수를 표현하는 데 필요한 비트 수를 계산해야 합니다 max. 네임스페이 Microsoft.Quantum.Math 스의 함수는 BitSizeI 정수를 나타내는 데 필요한 비트 수로 변환합니다.
    • SampleRandomNumberInRange 작업은 for 루프를 사용하여 max보다 작거나 같은 값을 생성할 때까지 난수를 생성합니다. 루프는 for 다른 프로그래밍 언어의 for 루프와 정확히 동일하게 작동합니다.
    • 변수 bits 는 변경 가능한 변수입니다. 변경 가능한 변수는 계산 중에 변경될 수 있는 변수입니다. set 지시문을 사용하여 변경 가능한 변수의 값을 변경할 수 있습니다.
    • 함수는 ResultArrayAsInt 네임스페이스에서 Microsoft.Quantum.Convert 제공됩니다. 이 함수는 비트 문자열을 양의 정수로 변환합니다.
  3. 마지막으로 진입점을 추가합니다. 이 예제에서 Main 작업은 프로그램의 진입점입니다. 작업을 호출 GenerateRandomNumberInRange 하여 0에서 100 사이의 난수를 생성합니다.

        @EntryPoint()
        operation Main() : Int {
            let max = 100;
            Message($"Sampling a random number between 0 and {max}: ");
    
            // Generate random number in the 0..max range.
            return GenerateRandomNumberInRange(max);
        }
    

    let 지시문은 계산 도중 변경되지 않는 변수를 선언합니다. 여기서는 최대값을 100으로 정의합니다.

  4. 난수 생성기에 대한 전체 코드는 다음과 같습니다.

namespace QuantumRandomNumberGenerator {
    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;

    @EntryPoint()
    operation Main() : Int {
        let max = 100;
        Message($"Sampling a random number between 0 and {max}: ");

        // Generate random number in the 0..max range.
        return GenerateRandomNumberInRange(max);
    }

    /// Generates a random number between 0 and `max`.
    operation GenerateRandomNumberInRange(max : Int) : Int {
        // Determine the number of bits needed to represent `max` and store it
        // in the `nBits` variable. Then generate `nBits` random bits which will
        // represent the generated random number.
        mutable bits = [];
        let nBits = BitSizeI(max);
        for idxBit in 1..nBits {
            set bits += [GenerateRandomBit()];
        }
        let sample = ResultArrayAsInt(bits);

        // Return random number if it is within the requested range.
        // Generate it again if it is outside the range.
        return sample > max ? GenerateRandomNumberInRange(max) | sample;
    }

    operation GenerateRandomBit() : Result {
        // Allocate a qubit.
        use q = Qubit();

        // Set the qubit into superposition of 0 and 1 using the Hadamard 
        H(q);

        // At this point the qubit `q` has 50% chance of being measured in the
        // |0〉 state and 50% chance of being measured in the |1〉 state.
        // Measure the qubit value using the `M` operation, and store the
        // measurement value in the `result` variable.
        let result = M(q);

        // Reset qubit to the |0〉 state.
        // Qubits must be in the |0〉 state by the time they are released.
        Reset(q);

        // Return the result of the measurement.
        return result;
    }
}

난수 생성기 프로그램 실행

Azure Quantum의 Copilot 및 독립 실행형 Q# 애플리케이션으로 Visual Studio Code 또는 Python 호스트 프로그램을 사용하여 프로그램을 실행할 수 있습니다.

Azure Quantum의 Copilot를 무료로 사용하여 코드를 테스트 Q# 할 수 있습니다. MSA(Microsoft) 전자 메일 계정만 있으면 됩니다. Azure Quantum의 Copilot에 대한 자세한 내용은 Azure Quantum 탐색을 참조하세요.

  1. 브라우저에서 Azure Quantum에서 Copilot 를 엽니다.

  2. 다음 코드를 복사하여 코드 편집기에 붙여넣습니다.

    namespace Tutorial {
        open Microsoft.Quantum.Convert;
        open Microsoft.Quantum.Intrinsic;
        open Microsoft.Quantum.Math;
    
        @EntryPoint()
        operation Main() : Int {
            let max = 100;
            Message($"Sampling a random number between 0 and {max}: ");
    
            // Generate random number in the 0..max range.
            return GenerateRandomNumberInRange(max);
        }
    
        /// # Summary
        /// Generates a random number between 0 and `max`.
        operation GenerateRandomNumberInRange(max : Int) : Int {
            // Determine the number of bits needed to represent `max` and store it
            // in the `nBits` variable. Then generate `nBits` random bits which will
            // represent the generated random number.
            mutable bits = [];
            let nBits = BitSizeI(max);
            for idxBit in 1..nBits {
                set bits += [GenerateRandomBit()];
            }
            let sample = ResultArrayAsInt(bits);
    
            // Return random number if it is within the requested range.
            // Generate it again if it is outside the range.
            return sample > max ? GenerateRandomNumberInRange(max) | sample;
        }
    
        /// # Summary
        /// Generates a random bit.
        operation GenerateRandomBit() : Result {
            // Allocate a qubit.
            use q = Qubit();
    
            // Set the qubit into superposition of 0 and 1 using the Hadamard 
            // operation `H`.
            H(q);
    
            // At this point the qubit `q` has 50% chance of being measured in the
            // |0〉 state and 50% chance of being measured in the |1〉 state.
            // Measure the qubit value using the `M` operation, and store the
            // measurement value in the `result` variable.
            let result = M(q);
    
            // Reset qubit to the |0〉 state.
            // Qubits must be in the |0〉 state by the time they are released.
            Reset(q);
    
            // Return the result of the measurement.
            return result;
    
            // Note that Qubit `q` is automatically released at the end of the block.
        }
    }
    
  3. 실행할 샷 수를 선택하고 실행을 클릭합니다.

  4. 결과는 히스토그램 및 결과 필드에 표시됩니다.

  5. 코드 설명을 클릭하여 Copilot에게 코드를 설명하라는 메시지를 표시합니다.

Azure Quantum의 Copilot에서 코드 편집기의 오른쪽 모서리에 있는 VS Code 로고 단추를 클릭하여 웹용 VS Code에서 프로그램을 열 수 있습니다.

참고

호출 가능 ResultArrayAsInt 에는 전체 계산 프로필이 있는 QPU가 필요하므로 이 코드 조각은 현재 사용 가능한 Azure Quantum 하드웨어 targets에서 실행되지 않습니다.

다음 단계

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

  • 양자 얽힘 은 큐비트를 조작 및 측정하고 중첩 및 얽힘의 효과를 보여 주는 프로그램을 작성하는 Q# 방법을 보여 줍니다.
  • Grover의 검색 알고리즘 은 Grover의 검색 알고리즘을 Q# 사용하는 프로그램을 작성하는 방법을 보여줍니다.
  • Quantum 푸리에 변환은 특정 큐비트를 직접 해결하는 프로그램을 작성하는 Q# 방법을 살펴봅니다.
  • Quantum Katas는 양자 컴퓨팅 및 프로그래밍 요소를 동시에 교육하기 위한 자기 주도적인 자습서 및 Q# 프로그래밍 연습입니다.