연습 2부 - 양자 난수 생성기 만들기
이 단원에서는 양자 난수 생성기의 두 번째 단계, 즉 여러 난수 비트를 결합하여 더 큰 난수를 형성하는 단계를 구현합니다. 이 단계는 이전 단원에서 만든 난수 비트 생성기를 기반으로 진행됩니다.
여러 임의 비트를 결합하여 더 큰 숫자 형성
이전 단원에서는 큐비트를 중첩에 넣고 측정하여 임의 비트를 생성하는 임의 비트 생성기를 만들었습니다.
큐비트를 측정하면 임의 비트(0 또는 1)가 50% 확률로 표시됩니다. 이 비트의 값은 실제로 임의이며 측정 후 무엇을 얻을지 알 수 있는 방법은 없습니다. 하지만 이 동작을 사용하여 더 큰 난수를 생성하려면 어떻게 해야 하나요?
프로세스를 4번 반복하여 다음과 같은 이진수 시퀀스를 생성한다고 가정하겠습니다.
$${0, 1, 1, 0}$$
이러한 비트를 비트 문자열로 연결하거나 결합하면 더 큰 숫자를 형성할 수 있습니다. 이 예제에서 비트 시퀀스 ${0110}$는 10진수 6과 같습니다.
$${0110_{\ binary} \equiv 6_{\ decimal}}$$
이 프로세스를 여러 번 반복하면 여러 비트를 결합하여 큰 숫자를 구성할 수 있습니다.
난수 생성기 논리 정의
이전 장치에서 빌드된 임의 비트 생성기를 제공하는 경우 난수 생성기의 논리가 무엇인지 간략히 살펴보겠습니다.
max
를 생성하려는 최대 수로 정의합니다.- 최대
max
까지의 정수를 표현하는 데 필요한 비트 수(nBits
)를 계산하여 생성해야 하는 임의 비트 수를 정의합니다. - 길이가
nBits
인 임의 비트 문자열을 생성합니다. - 비트 문자열이
max
보다 큰 숫자를 나타내는 경우 3단계로 돌아갑니다. - 그렇지 않으면 프로세스가 완료된 것입니다. 생성된 숫자를 정수로 반환합니다.
예를 들어 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.Math
및 Microsoft.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;
}
프로그램 실행
새 난수 생성기를 사용해 보겠습니다.
- 프로그램을 실행하기 전에 대상 프로필을 제한 없음으로 설정해야 합니다. 보기>명령 팔레트를 선택하고 QIR을 검색한 후 Q#: Azure Quantum QIR 대상 프로필을 선택한 다음 Q#: 무제한을 선택합니다.
- 프로그램을 실행하려면
Main
작업 위의 명령 목록에서 실행을 선택하거나 Ctrl+F5를 누릅니다. 디버그 콘솔에 출력이 표시됩니다. - 다른 결과를 보려면 프로그램을 다시 실행합니다.
참고 항목
대상 프로필이 제한 없음으로 설정되지 않은 경우 프로그램을 실행할 때 오류가 발생합니다.
축하합니다! 이제 고전 논리를 Q#과 결합하여 양자 난수 생성기를 만드는 방법을 알았습니다.
보너스 연습
생성된 임의 값이 0이 아닌 최소 수 min
보다 크도록 프로그램을 수정합니다.