연습 2부 - 양자 난수 생성기 만들기

완료됨

이 단원에서는 양자 난수 생성기의 두 번째 단계, 즉 여러 난수 비트를 결합하여 더 큰 난수를 형성하는 단계를 구현합니다. 이 단계는 이전 단원에서 만든 난수 비트 생성기를 기반으로 진행됩니다.

여러 임의 비트를 결합하여 더 큰 숫자 형성

이전 단원에서는 큐비트를 중첩에 넣고 측정하여 임의 비트를 생성하는 임의 비트 생성기를 만들었습니다.

큐비트를 측정하면 임의 비트(0 또는 1)가 50% 확률로 표시됩니다. 이 비트의 값은 실제로 임의이며 측정 후 무엇을 얻을지 알 수 있는 방법은 없습니다. 하지만 이 동작을 사용하여 더 큰 난수를 생성하려면 어떻게 해야 하나요?

프로세스를 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을 반환합니다.

완전한 난수 생성기 만들기

여기서는 Main.qs 파일을 확장하여 더 큰 난수를 만듭니다.

필요한 라이브러리를 가져옵니다.

먼저, Q# 표준 라이브러리에서 프로그램으로 필요한 네임스페이스를 가져와야 합니다. Q# 컴파일러는 많은 일반적인 함수와 연산을 자동으로 로드하지만 완전한 양자 난수 생성기의 경우 두 개의 Q# 네임스페이스(Microsoft.Quantum.MathMicrosoft.Quantum.Convert)에서 추가 함수와 연산이 필요합니다.

다음 import 지시문을 복사하여 Main.qs 파일 맨 위에 붙여넣습니다.

import Microsoft.Quantum.Convert.*;
import Microsoft.Quantum.Math.*;

Main 작업의 이름을 GenerateRandomBit로 변경

완전한 난수 생성기를 위해서는 이전 단원에서 정의한 연산을 다시 사용하게 될 것입니다. 그러나 작업 이름 Main은 프로그램의 진입점이므로 고유해야 합니다. 혼동을 피하려면 Main 작업의 이름을 GenerateRandomBit로 바꿔야 합니다.

GenerateRandomBit 작업은 다음과 같아야 합니다.

    operation GenerateRandomBit() : Result {
        // Allocate a qubit.
        use q = Qubit();
    
        // Set the qubit into superposition of 0 and 1 using the Hadamard 
        H(q);
    
        // Measure the qubit and store the result.
    
        let result = M(q);
    
        // Reset qubit to the |0〉 state.
        Reset(q);
    
        // Return the result of the measurement.
        return result;
    }

양자 난수 연산 정의

여기에서 GenerateRandomNumberInRange 작업을 정의합니다. 이 작업은 GenerateRandomBit 작업을 반복적으로 호출하여 비트 문자열을 생성합니다.

다음 코드를 복사하여 GenerateRandomBit 작업 전에 Main.qs 파일에 붙여넣습니다.

    /// 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 함수는 정수를 이를 표현하는 데 필요한 비트 수로 변환합니다.
  • GenerateRandomNumberInRange 작업은 for 루프를 사용하여 max보다 작거나 같은 값을 생성할 때까지 난수를 생성합니다. for 루프는 다른 프로그래밍 언어의 for 루프와 정확히 동일하게 작동합니다.
  • bits 변수는 변경 가능한 변수입니다. 변경 가능한 변수는 계산 중에 변경될 수 있는 변수입니다. set 지시문을 사용하여 변경 가능한 변수의 값을 변경할 수 있습니다.
  • ResultArrayAsInt 함수는 Microsoft.Quantum.Convert 라이브러리가 제공합니다. 이 함수는 비트 문자열을 양의 정수로 변환합니다.

진입점 추가

마지막으로 프로그램에 진입점을 추가합니다. 기본적으로 Q# 컴파일러는 Main 연산을 찾아서 해당 연산이 어디에 있든 거기에서 처리를 시작합니다. Main 연산은 GenerateRandomNumberInRange 연산을 호출하여 0과 max 사이의 난수를 생성합니다. 이 예에서는 최댓값을 100으로 정의합니다.

다음 코드를 복사하여 Main.qs 파일에 붙여넣습니다.

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

최종 프로그램

Main.qs 파일은 다음과 같이 표시됩니다.

import Microsoft.Quantum.Convert.*;
import Microsoft.Quantum.Math.*;

    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 operation
        H(q);
    
        // 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.
        Reset(q);
    
        // Return the result of the measurement.
        return result;
    }

프로그램 실행

새 난수 생성기를 사용해 보겠습니다.

  1. 프로그램을 실행하기 전에 대상 프로필을 제한 없음으로 설정해야 합니다. 보기>명령 팔레트를 선택하고 QIR을 검색한 후 Q#: Azure Quantum QIR 대상 프로필을 선택한 다음 Q#: 무제한을 선택합니다.
  2. 프로그램을 실행하려면 Main 작업 위의 명령 목록에서 실행을 선택하거나 Ctrl+F5를 누릅니다. 디버그 콘솔에 출력이 표시됩니다.
  3. 다른 결과를 보려면 프로그램을 다시 실행합니다.

참고 항목

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

축하합니다! 이제 고전 논리를 Q#과 결합하여 양자 난수 생성기를 만드는 방법을 알았습니다.

보너스 연습

생성된 임의 값이 0이 아닌 최소 수 min보다 크도록 프로그램을 수정합니다.