Übung, Teil 2: Erstellen eines Quanten-Zufallszahlengenerators

Abgeschlossen

In dieser Einheit implementieren Sie die zweite Phase des Quanten-Zufallszahlen-Generators: die Kombination mehrerer Zufallsbits, um eine größere Zufallszahl zu bilden. Diese Phase baut auf dem Zufallsbit-Generator auf, den Sie in der vorherigen Lektion bereits erstellt haben.

Kombinieren mehrerer zufälliger Bits, um eine größere Zahl zu bilden

In der vorherigen Lerneinheit haben Sie einen Zufallsbitgenerator erstellt, der ein zufälliges Bit generiert, indem ein Qubit in die Superposition gesetzt und gemessen wird.

Wenn Sie das Qubit messen, erhalten Sie mit einer Wahrscheinlichkeit von 50 % ein zufälliges Bit, entweder 0 oder 1. Der Wert dieses Bits ist wirklich zufällig. Sie können nicht wissen, welches Ergebnis Sie mit der Messung erhalten. Aber wie können Sie dieses Verhalten verwenden, um größere Zufallszahlen zu generieren?

Angenommen, Sie wiederholen den Prozess viermal und erzeugen dabei diese Folge von Binärzahlen:

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

Wenn Sie diese Bits verketten oder in eine Bitzeichenfolge kombinieren, können Sie eine größere Zahl bilden. In diesem Beispiel entspricht die Bitfolge ${0110}$ der Dezimalzahl 6.

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

Wenn Sie diesen Prozess mehrmals wiederholen, können Sie mehrere Bits zu einer beliebigen großen Zahl kombinieren.

Definieren der Logik für den Zufallszahlen-Generator

Sehen wir uns an, wie die Logik eines Zufallszahlengenerators aussehen sollte, vorausgesetzt, der zufällige Bitgenerator, der in der vorherigen Einheit erstellt wurde, ist vorhanden:

  1. Definieren Sie max als höchste Zahl, die Sie generieren möchten.
  2. Definieren Sie die Anzahl zufälliger Bits, die Sie generieren müssen, indem Sie berechnen, wie viele Bits, nBits, Sie benötigen, um ganze Zahlen bis max auszudrücken.
  3. Generieren Sie eine zufällige Bitzeichenfolge, die nBits lang ist.
  4. Wenn die Bitzeichenfolge eine Zahl größer als max darstellt, kehren Sie zu Schritt 3 zurück.
  5. Andernfalls ist der Vorgang abgeschlossen. Geben Sie die generierte Zahl als ganze Zahl zurück.

Legen Sie zum Beispiel max auf 12 fest. Das heißt, 12 ist die größte Zahl, die Sie aus dem Zufallszahlengenerator abrufen möchten.

Sie benötigen ${\lfloor ln(12) / ln(2) + 1 \rfloor}$ gleich 4 Bits, um eine Zahl zwischen 0 und 12 darzustellen. (Aus Platzgründen überspringen wir die Ableitung dieser Gleichung.)

Angenommen, Sie generieren die Bitzeichenfolge ${1101_{\ binary}}$, dann entspricht dies ${13_{\ decimal}}$. Da 13 größer als 12 ist, wiederholen Sie den Vorgang.

Als Nächstes generieren Sie die Bitzeichenfolge ${0110_{\ binary}}$, dies entspricht ${6_{\ decimal}}$. Da 6 kleiner als 12 ist, ist der Prozess abgeschlossen.

Der Zufallszahlengenerator gibt die Zahl 6 zurück.

Erstellen eines vollständigen Zufallszahlengenerators

Hier erweitern Sie die Main.qs-Datei, um größere Zufallszahlen zu erstellen.

Importieren der erforderlichen Bibliotheken

Zunächst müssen Sie die erforderlichen Namespaces aus der Q#-Standardbibliothek in das Programm importieren. Der Q#-Compiler lädt viele allgemeine Funktionen und Vorgänge automatisch. Für den vollständigen Quanten-Zufallszahlengenerator benötigen Sie jedoch einige zusätzliche Funktionen und Vorgänge aus zwei Q#-Namespaces: Microsoft.Quantum.Math und Microsoft.Quantum.Convert.

Kopieren Sie die folgenden import-Anweisungen, und fügen Sie sie am Anfang Ihrer Main.qs-Datei hinzu:

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

Umbenennen des Main-Vorgangs in GenerateRandomBit

Für den vollständigen Zufallszahlengenerator werden Sie den in der vorherigen Lektion definierten Vorgang wiederverwenden. Der Vorgangsname Main ist jedoch der Einstiegspunkt des Programms und sollte eindeutig sein. Um Verwirrung zu vermeiden, müssen Sie den Main-Vorgang in GenerateRandomBit umbenennen.

Der GenerateRandomBit-Vorgang sollte wie folgt aussehen:

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

Definieren des zufälligen Quantenzahlenvorgangs

Hier definieren Sie den GenerateRandomNumberInRange-Vorgang. Mit diesem Vorgang wird der GenerateRandomBit-Vorgang wiederholt aufgerufen, um eine Bitzeichenfolge zu erstellen.

Kopieren Sie den folgenden Code, und fügen Sie diesen vor dem GenerateRandomBit-Vorgang in Ihre Main.qs-Datei ein.

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

Sehen Sie sich den neuen Code noch einmal an.

  • Sie müssen die Anzahl der Bits berechnen, die erforderlich sind, um ganze Zahlen bis zu maxausdrücken. Die BitSizeI-Funktion aus der Microsoft.Quantum.Math-Bibliothek konvertiert eine ganze Zahl in die Anzahl der Bits, die erforderlich sind, um sie darzustellen.
  • Der GenerateRandomNumberInRange-Vorgang verwendet eine for-Schleife zum Generieren von Zufallszahlen, bis eine Zahl generiert wird, die kleiner oder gleich max ist. Die for-Schleife funktioniert genauso wie eine for-Schleife in anderen Programmiersprachen.
  • Die Variable bits ist eine veränderbare Variable. Eine änderbare Variable ist eine Variable, die während der Berechnung geändert werden kann. Verwenden Sie die set-Direktive, um den Wert einer änderbaren Variablen zu ändern.
  • Die ResultArrayAsInt-Funktion stammt aus der Microsoft.Quantum.Convert-Bibliothek. Mit dieser Funktion wird die Bitzeichenfolge in eine positive ganze Zahl konvertiert.

Hinzufügen eines Einstiegspunkts

Schließlich fügen Sie dem Programm einen Einstiegspunkt hinzu. Standardmäßig sucht der Q#-Compiler nach einem Main-Vorgang und startet die Verarbeitung dort, unabhängig davon, wo er sich befindet. Der Main-Vorgang ruft den GenerateRandomNumberInRange-Vorgang auf, um eine zufällige Zahl zwischen 0 und einer max Zahl zu generieren. In diesem Beispiel definieren Sie den Maximalwert als 100.

Kopieren Sie den folgenden Code, und fügen Sie ihn in Ihre Main.qs Datei ein:

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

Endgültiges Programm

Ihre Datei Main.qs sollte wie folgt aussehen:

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

Ausführen des Programms

Testen Sie den neuen Zufallszahlen-Generator.

  1. Bevor Sie das Programm ausführen, müssen Sie das Zielprofil auf Uneingeschränkt festlegen. Wählen Sie Ansicht>Befehlspalette aus, suchen Sie nach QIR, wählen Sie Q# aus: Legen Sie das Azure Quantum QIR-Zielprofil fest und wählen Sie dann Q#: uneingeschränkt aus.
  2. Um Ihr Programm auszuführen, wählen Sie in der Liste der Befehle über dem Vorgang Main Ausführen aus, oder drücken Sie STRG+F5. Die Ausgabe wird in der Debugkonsole angezeigt.
  3. Führen Sie das Programm erneut aus, um ein anderes Ergebnis anzuzeigen.

Hinweis

Wenn das Zielprofil nicht auf Uneingeschränkt festgelegt ist, wird beim Ausführen des Programms eine Fehlermeldung angezeigt.

Herzlichen Glückwunsch! Nun wissen Sie, wie klassische Logik mit Q# kombiniert werden kann, um einen Quanten-Zufallszahlen-Generator zu erstellen.

Zusatzübung

Ändern Sie das Programm so, dass die generierte Zufallszahl auch größer als die Mindestzahl min statt null ist.