Ćwiczenie— część 2 — tworzenie kwantowego generatora liczb losowych

Ukończone

W tej lekcji zaimplementujesz drugą część kwantowego generatora liczb losowych. Połączysz wiele losowych bitów, aby utworzyć większą liczbę losową. Ta część opiera się na generatorze bitów losowych, który został już utworzony w poprzedniej lekcji.

Łączenie wielu losowych bitów w celu utworzenia większej liczby

W poprzedniej lekcji utworzono generator bitów losowych, który umieszcza kubit w stanie superpozycji, a następnie mierzy kubit w celu wygenerowania losowej wartości bitowej 0 lub 1, z których każdy ma 50% prawdopodobieństwa. Wartość tego bitu jest naprawdę losowa, nie ma możliwości z wyprzedzeniem wiedzieć, jaki będzie wynik pomiaru. Ale jak można użyć tego zachowania, aby wygenerować większe liczby losowe?

Jeśli powtarzasz proces cztery razy, możesz wygenerować tę sekwencję cyfr binarnych:

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

Jeśli połączysz te bity w ciąg bitowy, możesz utworzyć większą liczbę. W tym przykładzie sekwencja bitowa ${0110}$ w zapisie binarnym jest równoważna liczbie 6 w systemie dziesiętnym.

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

Aby wygenerować dowolnie dużą liczbę losową, po prostu powtórz ten proces wiele razy. Następnie połącz wszystkie bity w liczbę binarną i przekonwertuj liczbę binarną na liczbę dziesiętną.

Definiowanie logiki generatora liczb losowych

Przed napisaniem kodu w języku Q# przedstawimy logikę generowania liczby losowej:

  1. Zdefiniuj max jako maksymalną liczbę dziesiętną, którą chcesz wygenerować.
  2. Określ liczbę losowych bitów, nBits, które są wymagane do wygenerowania max.
  3. Wygeneruj losowy ciąg bitowy o długości nBits.
  4. Jeśli ciąg bitowy reprezentuje liczbę większą niż max, wróć do poprzedniego kroku.
  5. W przeciwnym razie proces zostanie zakończony. Zwraca wygenerowaną liczbę jako liczbę dziesiętną.

Na przykład zdefiniujmy max wartość 12. Oznacza to, że 12 jest największą liczbą, którą powinien wygenerować generator liczb losowych.

Użyj następującego równania, aby określić liczbę bitów wymaganą do reprezentowania liczby 12 w pliku binarnym:

$${\lfloor ln(12) / ln(2) + 1 \rfloor}$$

Zgodnie z tym równaniem potrzebne są 4 bity do reprezentowania liczby z zakresu od 0 do 12.

Załóżmy na przykład, że generujesz losowy bit cztery razy i pobierasz ciąg bitowy ${1101_{\ binary}}$. Ta wartość w systemie binarnym jest równa 13 w systemie dziesiętnym. Ponieważ 13 jest większe niż 12, należy powtórzyć proces.

Następnie wygenerujesz ciąg bitowy ${0110_{\ binary}}$, który jest równy ${6_{\ decimal}}$. Ponieważ 6 jest mniejsze niż 12, proces jest zakończony.

Kwantowy generator liczb losowych zwraca liczbę 6.

Tworzenie pełnego generatora liczb losowych w języku Q#

W tym miejscu rozszerzysz Main.qs plik z poprzedniej lekcji, aby skompilować generator liczb losowych.

Importowanie wymaganych bibliotek

Najpierw zaimportuj przestrzenie nazw z standardowej biblioteki języka Q#, która zawiera funkcje i operacje potrzebne do zapisania programu. Kompilator języka Q# ładuje wiele typowych funkcji i operacji automatycznie. Jednak w przypadku kwantowego generatora liczb losowych potrzebne są pewne dodatkowe funkcje i operacje z dwóch przestrzeni nazw języka Q#: Microsoft.Quantum.Math i Microsoft.Quantum.Convert.

Skopiuj i wklej następujące import dyrektywy na początku Main.qs pliku:

import Std.Convert.*;
import Std.Math.*;

Uwaga

Można używać Std zamiast Microsoft.Quantum do importowania funkcji i operacji z biblioteki standardowej.

Zmień nazwę operacji na MainGenerateRandomBit

Program generatora liczb losowych używa Main operacji, którą napisałeś w poprzedniej jednostce, aby wygenerować losowy bit. Main Zmień nazwę operacji na GenerateRandomBit tak, aby ta operacja ma bardziej opisową nazwę i nie jest punktem wejścia do programu.

Skopiuj i wklej następujący kod do Main.qspliku :

import Std.Convert.*;
import Std.Math.*;

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

Definiowanie operacji generatora liczb losowych

Utwórz nową operację o nazwie GenerateRandomNumberInRange. Ta operacja wielokrotnie wywołuje operację GenerateRandomBit, aby utworzyć ciąg bitów.

Skopiuj następujący kod i umieść go bezpośrednio przed operacją GenerateRandomBit w Main.qs pliku:

/// 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's within the requested range.
    // Generate it again if it's outside the range.
    return sample > max ? GenerateRandomNumberInRange(max) | sample;
}

Oto omówienie kodu w pliku GenerateRandomNumberInRange:

  • Wywołaj funkcję BitSizeI z biblioteki Std.Math, aby obliczyć liczbę bitów potrzebnych do reprezentowania liczby całkowitej przechowywanej w max.
  • for Użyj pętli, aby wygenerować liczbę losowych bitów równych nBits. Wywołaj operację GenerateRandomBit , aby wygenerować losowe bity.
  • Wewnątrz pętli, użyj instrukcji set, aby zaktualizować zmienną bits każdym nowym losowym bitem. Zmienna bits jest zmienną modyfikowalnym, co oznacza, że wartość bits może ulec zmianie podczas obliczeń.
  • Wywołaj funkcję ResultArrayAsInt z biblioteki Std.Convert, aby przekonwertować tablicę bitów w bits na dodatnią liczbę całkowitą przechowywaną w sample.
  • W instrukcji return sprawdź, czy wartość sample jest większa niż max. Jeśli sample wartość jest większa niż max, wywołaj GenerateRandomNumberInRange ponownie i rozpocznij od nowa. W przeciwnym razie zwróć losową liczbę przechowywaną w sample.

Dodawanie punktu wejścia

Na koniec dodaj operację punktu wejścia do kodu, aby kompilator mógł uruchomić program. Domyślnie kompilator języka Q# szuka Main operacji i używa Main jej jako punktu wejścia, niezależnie od tego, gdzie Main znajduje się w pliku. W tym miejscu operacja ustawia wartość parametru max i wywołuje operację GenerateRandomNumberInRange w celu wygenerowania losowej liczby z zakresu od 0 do max.

Na przykład aby wygenerować losową liczbę z zakresu od 0 do 100, skopiuj następujący kod do Main.qs pliku:

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

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

Końcowy program

Oto kompletny kod języka Q# dla programu w pliku Main.qs:

import Std.Convert.*;
import Std.Math.*;

operation Main() : Int {
    let max = 100;
    Message($"Generating 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's within the requested range.
    // Generate it again if it's 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;
}

Uruchamianie programu

Wypróbuj nowy kwantowy generator liczb losowych!

Aby uruchomić program, wybierz opcję Uruchom z listy poleceń powyżej operacji Main. Lub naciśnij Ctrl + F5. Twój wynik jest wyświetlany w konsoli debugowania. Uruchom program wiele razy i zwróć uwagę, jak zmienia się wynik.

Gratulacje! Utworzono prawdziwie losowy generator liczb kwantowych w języku Q#.

Ćwiczenie dodatkowe

Spróbuj zmodyfikować program, aby wymagać również wygenerowanej liczby losowej większej niż minimalna liczba dodatnia, minzamiast zera.