Tutorial: Implementieren eines Quanten-Zufallszahlengenerators in Q#

Hinweis

Microsoft Quantum Development Kit (classic QDK) wird nach dem 30. Juni 2024 nicht mehr unterstützt. Wenn Sie ein vorhandener QDK-Entwickler sind, empfehlen wir Ihnen, auf das neue Azure Quantum Development Kit (Modern QDK) umzusteigen, um die Entwicklung von Quantenlösungen fortzusetzen. Weitere Informationen finden Sie unter Migrieren ihres Q# Codes zum modernen QDK.

Hier erfahren Sie, wie Sie ein einfaches Quantenprogramm in Q# schreiben, das sich die Quantenmechanik zunutze macht, um eine Zufallszahl zu generieren.

In diesem Lernprogramm lernen Sie Folgendes:

  • Erstellen Sie ein Q# Programm.
  • Überprüfen Sie die Standard Komponenten eines Q# Programms.
  • Definieren Sie die Logik eines Problems.
  • Kombinieren Sie klassische Und Quantenvorgänge, um ein Problem zu lösen.
  • Arbeiten mit Qubits und Superposition, um einen Quanten-Zufallszahlen-Generator zu erstellen

Tipp

Wenn Sie Ihren Weg zum Quantencomputing beschleunigen möchten, lesen Sie Code mit Azure Quantum, ein einzigartiges Feature der Azure Quantum-Website. Hier können Sie integrierte Q# Beispiele oder Ihre eigenen Q# Programme ausführen, neuen Q# Code aus Ihren Eingabeaufforderungen generieren, Ihren Code in VS Code für das Web mit einem Klick öffnen und ausführen und Copilot Fragen zum Quantencomputing stellen.

Voraussetzungen

Definieren des Problems

Klassische Computer erzeugen keine Zufallszahlen, sondern Pseudozufallszahlen. Ein Pseudozufallszahlen-Generator generiert eine deterministische Sequenz von Zahlen auf Grundlage eines Ausgangswerts, der als Seed bezeichnet wird. Um sich Zufallswerten besser anzunähern, ist dieser Ausgangswert oft die aktuelle Zeit der CPU-Uhr.

Quantencomputer hingegen können echte Zufallszahlen generieren. Dies liegt daran, dass die Messung eines Qubits in der Superposition ein probabilistischer Prozess ist. Das Ergebnis der Messung ist zufällig, und es gibt keine Möglichkeit, das Ergebnis vorherzusagen. Dies ist das Grundprinzip von Quanten-Zufallszahlengeneratoren.

Ein Qubit ist eine Einheit von Quanteninformationen, die sich in einer Superposition befindet. Bei der Messung kann sich ein Qubit entweder im Zustand 0 oder im Zustand 1 befinden. Vor der Messung stellt der Qubitzustand jedoch die Wahrscheinlichkeit dar, mit der bei einer Messung entweder 0 oder 1 gelesen wird.

Sie beginnen mit einem Qubit in einem Basiszustand, z. B. 0. Der erste Schritt des Zufallszahlengenerators besteht darin, einen Hadamard-Vorgang zu verwenden, um das Qubit in eine gleiche Superposition zu versetzen. Die Messung dieses Zustands ergibt eine Null oder eins mit einer Wahrscheinlichkeit von 50 % jedes Ergebnisses, ein wirklich zufälliges Bit.

Es gibt keine Möglichkeit, zu wissen, was Sie nach der Messung des Qubits in der Superposition erhalten, und das Ergebnis ist ein anderer Wert, wenn der Code aufgerufen wird. 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. Nun können Sie Ihren Vorgesetzten diese Zahl als sicheres Kennwort zur Verfügung stellen, da Sie sicher sein können, dass kein Hacker im gesamten All die Ergebnisse der Sequenz von Messungen ermitteln könnte.

Definieren der Logik für den Zufallszahlen-Generator

Im Folgenden wird beschrieben, wie die Logik eines Zufallszahlengenerators aussehen sollte, sofern wir über einen Zufallsbitgenerator verfügen:

  1. Definieren Sie max als höchste Zahl, die Sie generieren möchten.
  2. Definieren Sie die Anzahl der Zufallsbits, die Sie generieren müssen. Dazu berechnen Sie, wie viele Bits (nBits) erforderlich sind, um ganze Zahlen bis zu 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, dass 12 die größte Zahl ist, die Sie als sicheres Kennwort verwenden 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 wird hier auf die Ableitung dieser Gleichung verzichtet.)

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 Quantenzufallszahlengenerator gibt die Zahl 6 als Kennwort zurück. Legen Sie in der Praxis eine größere Zahl als den Höchstwert fest, da niedrigere Zahlen einfach zu knacken sind, indem einfach alle möglichen Kennwörter ausprobiert werden. Um das Erraten oder Knacken des Kennworts weiter zu erschweren, könnten Sie den ASCII-Code verwenden, um Binärdaten in Text zu konvertieren und ein Kennwort mithilfe von Zahlen, Symbolen und einer Mischung aus Groß- und Kleinbuchstaben zu generieren.

Schreiben eines Zufälligen Bitgenerators

Der erste Schritt besteht darin, einen Q# Vorgang zu schreiben, der ein zufälliges Bit generiert. Dieser Vorgang ist einer der Bausteine des Zufallszahlengenerators.

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

Sehen Sie sich den neuen Code an.

  • Sie definieren den GenerateRandomBit-Vorgang. Dieser benötigt keine Eingabe und erzeugt einen Wert vom Typ Result. Der Typ Result stellt das Ergebnis einer Messung dar und kann einen von zwei möglichen Werten haben: Zero oder One.
  • Sie ordnen ein einzelnes Qubit mit dem use Schlüsselwort (keyword) zu. Bei der Zuordnung befindet sich ein Qubit immer im Zustand Zero.
  • Sie verwenden den H -Vorgang, um das Qubit in einer gleichen Superposition zu platzieren.
  • Sie verwenden den M Vorgang, um das Qubit zu messen, und geben den gemessenen Wert zurück (Zero oder One).
  • Sie verwenden den Reset Vorgang, um das Qubit auf den Zustand '|0'' zurückzusetzen.

Wenn das Qubit mithilfe der H-Operation in Superposition versetzt und mithilfe der M-Operation gemessen wird, führt jeder Codeaufruf zu einem anderen Ergebniswert.

Visualisieren des Q# Codes mit der Bloch-Kugel

Bei der Bloch-Kugel steht der Nordpol für den klassischen Wert 0 und der Südpol für den klassischen Wert 1. Jede Überlagerung kann durch einen Punkt auf der Kugel dargestellt werden (per Pfeil). Je näher sich das Ende des Pfeils an einem der Pole befindet, desto höher ist die Wahrscheinlichkeit, dass das Qubit bei einer Messung auf den klassischen Wert zurückfällt, der dem Pol zugeordnet ist. Bei dem durch den Pfeil dargestellten Qubit-Zustand in der folgenden Abbildung ist es beispielsweise wahrscheinlicher, dass sich bei einer Messung der Wert 0 ergibt:

Ein Diagramm, das einen Qubitzustand mit einer hohen Wahrscheinlichkeit zeigt, dass 0 (null) gemessen wird.

Diese Darstellung kann zur Visualisierung der Aktivitäten des Codes verwendet werden:

  1. Beginnen Sie mit einem im Zustand 0 initialisierten Qubit, und wenden Sie eine H-Operation an, um eine gleichmäßige Superposition zu erreichen, bei der die Wahrscheinlichkeit für 0 und 1 jeweils gleich hoch ist.

    Ein Diagramm, das die Vorbereitung eines Qubits in Superposition zeigt, indem das Hadamard-Gate angewendet wird.
  2. Messen Sie anschließend das Qubit, und speichern Sie die Ausgabe:

    Ein Diagramm, das die Messung eines Qubits und das Speichern der Ausgabe zeigt.

Da das Ergebnis der Messung zufällig und die Wahrscheinlichkeit der Messung von 0 oder 1 identisch ist, haben Sie ein vollkommen zufälliges Bit erhalten. Sie können diesen Vorgang mehrmals aufrufen, um ganze Zahlen zu erstellen. Wenn Sie den Vorgang beispielsweise dreimal aufrufen, um drei zufällige Bits zu erhalten, können Sie zufällige 3-Bit-Zahlen erstellen (also eine Zufallszahl zwischen 0 und 7).

Schreiben eines vollständigen Zufallszahlengenerators

  1. Zuerst müssen Sie dem Programm die erforderlichen Q# Namespaces hinzufügen. Für den vollständigen Zufallszahlengenerator müssen Sie drei Q# Namespaces einschließen: Microsoft.Quantum.Math, Microsoft.Quantum.Intrinsicund Microsoft.Quantum.Convert.

    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Math;
    
  2. Als Nächstes definieren Sie den GenerateRandomNumberInRange Vorgang. Mit diesem Vorgang wird der GenerateRandomBit-Vorgang wiederholt aufgerufen, um eine Bitzeichenfolge zu erstellen.

        /// 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 zum Ausdrücken ganzer Zahlen bis zu maxerforderlich sind. Die BitSizeI Funktion aus dem Microsoft.Quantum.Math Namespace konvertiert eine ganze Zahl in die Anzahl der Bits, die für ihre Darstellung erforderlich sind.
    • Der SampleRandomNumberInRange-Vorgang verwendet eine for-Schleife zum Generieren von Zufallszahlen, bis eine Zahl generiert wird, die kleiner oder gleich max ist. Die for Schleife funktioniert genau wie eine for Schleife in anderen Programmiersprachen.
    • Die Variable bits ist eine veränderliche 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 dem Microsoft.Quantum.Convert Namespace. Mit dieser Funktion wird die Bitzeichenfolge in eine positive ganze Zahl konvertiert.
  3. Abschließend fügen Sie einen Einstiegspunkt hinzu. In diesem Beispiel ist der Main Vorgang der Einstiegspunkt des Programms. Der Vorgang wird aufgerufen GenerateRandomNumberInRange , um eine Zufallszahl zwischen 0 und 100 zu generieren.

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

    Mit der let-Direktive werden Variablen deklariert, die während der Berechnung nicht geändert werden. Hier definieren wir den Maximalwert als 100.

  4. Der vollständige Code für den Zufallszahlengenerator lautet wie folgt:

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

Ausführen des Programms für den Zufallszahlengenerator

Sie können das Programm in Copilot in Azure Quantum und in Visual Studio Code als eigenständige Q# Anwendung oder mit einem Python-Hostprogramm ausführen.

Sie können Ihren Q# Code mit copilot in Azure Quantum kostenlos testen . Sie benötigen lediglich ein Microsoft-E-Mail-Konto (MSA). Weitere Informationen zum Copilot in Azure Quantum finden Sie unter Erkunden von Azure Quantum.

  1. Öffnen Sie copilot in Azure Quantum in Ihrem Browser.

  2. Kopieren Sie den folgenden Code, und fügen Sie ihn in den Code-Editor ein.

    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. Wählen Sie die Anzahl der auszuführenden Aufnahmen aus, und klicken Sie auf Ausführen.

  4. Die Ergebnisse werden im Histogramm und in den Feldern Ergebnisse angezeigt.

  5. Klicken Sie auf Code erklären , um Copilot aufzufordern, Ihnen den Code zu erklären.

Tipp

Über Copilot in Azure Quantum können Sie Ihr Programm in VS Code für das Web öffnen, indem Sie in der rechten Ecke des Code-Editors auf die Schaltfläche VS Code-Logo klicken.

Hinweis

Dieser Codeausschnitt wird derzeit auf keiner verfügbaren Azure Quantum-Hardware targetsausgeführt, da die aufrufbare ResultArrayAsInt eine QPU mit vollständigem Berechnungsprofil erfordert.

Nächste Schritte

Sehen Sie sich weitere Q#-Tutorials an:

  • Die Quantenverschränkung zeigt, wie ein Q# Programm geschrieben wird, das Qubits bearbeitet und misst und die Auswirkungen von Überlagerung und Verschränkung veranschaulicht.
  • Der Suchalgorithmus von Grover zeigt, wie ein Q# Programm geschrieben wird, das den Suchalgorithmus von Grover verwendet.
  • Quantum Fourier Transforms untersucht, wie ein Q# Programm geschrieben wird, das direkt auf bestimmte Qubits anspricht.
  • Die Quantum Katas sind selbstgesteuerte Tutorials und Programmierübungen, die darauf abzielen, die Elemente des Quantencomputings und Q# der Programmierung gleichzeitig zu vermitteln.