Tutorial: Erkunden der Quantenverschränkung mit Q#

In diesem Tutorial erfahren Sie, wie Sie ein Q#-Programm schreiben, mit dem Qubits bearbeitet und gemessen werden können. Darüber hinaus werden die Auswirkungen von Superposition und Verschränkung veranschaulicht. Sie bereiten zwei Qubits in einem bestimmten Quantenzustand vor, lernen, wie Sie mit Q# Qubits arbeiten, um ihren Zustand zu ändern, und zeigen die Auswirkungen von Superposition und Verschränkung. Sie erstellen Ihr Q# Programm schrittweise, um Qubitzustände, Vorgänge und Messungen einzuführen.

Hinweis

Das Microsoft Quantum Development Kit (Classic QDK) wird nach dem 30. Juni 2024 nicht mehr unterstützt. Wenn Sie bereits 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.

Im Folgenden finden Sie einige wichtige Konzepte, die Sie verstehen sollten, bevor Sie beginnen:

  • Klassische Bits enthalten einen einzelnen binären Wert (0 oder 1). Der Zustand eines Qubits kann dagegen eine Superposition von zwei Quantenzuständen sein (also 0 und 1). Jeder mögliche Quantenzustand besitzt eine zugeordnete Wahrscheinlichkeitsamplitude.
  • Die Messung eines Qubits erzeugt ein binäres Ergebnis mit einer bestimmten Wahrscheinlichkeit und ändert den Zustand des Qubits aus der Superposition heraus.
  • Mehrere Qubits können so verschränkt werden, dass sie nicht unabhängig voneinander beschrieben werden können. Das bedeutet Folgendes: Was auch immer mit einem Qubit in einem verschränkten Paar geschieht, geschieht auch mit dem anderen Qubit.

In diesem Tutorial lernen Sie Folgendes:

  • Erstellen Sie Q# Vorgänge, um ein Qubit in einen gewünschten Zustand zu initialisieren.
  • Setzen eines Qubits in Superposition
  • Verschränken eines Qubit-Paars
  • Messen Sie ein Qubit, und beobachten Sie die Ergebnisse.

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

Zum Ausführen des Codebeispiels im Copilot für Azure Quantum benötigen Sie Folgendes:

  • Ein Microsoft-E-Mail-Konto (MSA).

Weitere Informationen zum Copilot finden Sie unter Erkunden von Azure Quantum.

Initialisieren eines Qubits in einen bekannten Zustand

Der erste Schritt besteht darin, einen Q#-Vorgang zu definieren, der ein Qubit in einem bekannten Zustand initialisiert. Dies kann aufgerufen werden, um ein Qubit auf einen klassischen Zustand festzulegen, d. h., wenn es gemessen wird, gibt Zero es entweder 100 % der Zeit zurück oder gibt 100 % der Zeit zurück One . Das Messen eines Qubits gibt einen Q# Typ Resultzurück, der nur den Wert oder Zero haben Onekann.

Öffnen Sie copilot for Azure Quantum , und kopieren Sie den folgenden Code in das Code-Editor-Fenster. Klicken Sie noch nicht auf Ausführen . Sie führen den Code später im Tutorial aus.

   namespace Bell {
       open Microsoft.Quantum.Intrinsic;
       open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }
   }

Im Codebeispiel werden die beiden Standardvorgänge M und X eingeführt, die den Zustand eines Qubits transformieren.

Der SetQubitState-Vorgang:

  1. Verwendet zwei Parameter: einen Typ Resultmit dem Namen desired, der den gewünschten Zustand für das Qubit in (Zero oder One) darstellt, und einen Typ Qubit.
  2. Führt einen Messvorgang M aus, der den Zustand des Qubits misst (Zero oder One) und das Ergebnis mit dem in desired angegebenen Wert vergleicht.
  3. Wenn die Messung nicht mit dem verglichenen Wert übereinstimmt, führt sie einen Vorgang X aus, der den Zustand des Qubits so umdreht, dass die Wahrscheinlichkeiten einer Zero und One zurückgebenden Messung umgekehrt werden. Auf diese Weise versetzt SetQubitState das Zielqubit immer in den gewünschten Zustand.

Schreiben eines Testvorgangs zum Testen des Bell-Zustands

Erstellen Sie als Nächstes einen weiteren Vorgang mit dem Namen TestBellState, um die Auswirkungen des SetQubitState-Vorgangs zu veranschaulichen. Dieser Vorgang ordnet zwei Qubits zu, ruft SetQubitState auf, um das erste Qubit auf einen bekannten Zustand festzulegen, und misst dann die Qubits, um die Ergebnisse anzuzeigen.

Kopieren Sie den folgenden Code in das Code-Editor-Fenster unterhalb des Vorgangs SetQubitState .

operation TestBellState() : (Int, Int, Int, Int) {
    mutable numOnesQ1 = 0;
    mutable numOnesQ2 = 0;
    let count = 1000;
    let initial = One;

    // allocate the qubits
    use (q1, q2) = (Qubit(), Qubit());   
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);
        
        // measure each qubit
        let resultQ1 = M(q1);            
        let resultQ2 = M(q2);           

        // Count the number of 'Ones' returned:
        if resultQ1 == One {
            set numOnesQ1 += 1;
        }
        if resultQ2 == One {
            set numOnesQ2 += 1;
        }
    }

    // reset the qubits
    SetQubitState(Zero, q1);             
    SetQubitState(Zero, q2);
    

    // Display the times that |0> is returned, and times that |1> is returned
    Message($"Q1 - Zeros: {count - numOnesQ1}");
    Message($"Q1 - Ones: {numOnesQ1}");
    Message($"Q2 - Zeros: {count - numOnesQ2}");
    Message($"Q2 - Ones: {numOnesQ2}");
    return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

}

Im Code sind die count Variablen und initial auf 1000 und One festgelegt. So wird das erste Qubit auf One initialisiert und jedes Qubit 1000-mal gemessen.

Beim TestBellState-Vorgang geschieht Folgendes:

  1. Legt Variablen für den Indikator und den anfänglichen Qubitzustand fest.
  2. Ruft die use-Anweisung auf, um zwei Qubits zu initialisieren.
  3. Führt Schleifendurchläufe für count Iterationen aus. Für jede Schleife wird
    1. SetQubitState aufgerufen, um einen angegebenen initial-Wert für das erste Qubit festzulegen.
    2. SetQubitState erneut aufgerufen, um das zweite Qubit in einen Zero-Zustand zu setzen.
    3. der M-Vorgang verwendet, um jedes Qubit zu messen.
    4. die Anzahl der Messungen für jedes Qubit gespeichert, das One zurückgibt.
  4. Nach dem Schleifendurchlauf wird SetQubitState erneut aufgerufen, um die Qubits in einen bekannten Zustand (Zero) zurückzusetzen, damit andere Benutzer die Qubits in einem bekannten Zustand zuordnen können. Dies ist aufgrund der use-Anweisung erforderlich.
  5. Schließlich wird die Message -Funktion verwendet, um Ergebnisse in den Copilot-Ausgabefenstern zu drucken, bevor die Ergebnisse zurückgegeben werden.

Ausführen des Codes im Copilot für Azure Quantum

Bevor Sie mit den Prozeduren für Superposition und Verschränkung fortgefahren werden, können Sie den Code bis zu diesem Punkt testen, um die Initialisierung und Messung der Qubits zu sehen.

Um den Code als eigenständiges Programm auszuführen, muss der Q# Compiler im Copilot wissen , wo das Programm gestartet werden soll. Dies erfolgt in der Q# Datei, indem sie direkt @EntryPoint() vor dem Vorgang, den Sie zuerst ausführen möchten, hinzufügen. In diesem Fall ist z. B. der TestBellState Vorgang.

Hinweis

@EntryPoint() ist nur für eigenständige Q#-Programme erforderlich. Wenn Sie ein Q# Programm in Jupyter Notebooks ausführen oder ein Q# Programm aus einer Python-Hostdatei aufrufen, ist dies nicht erforderlich und löst einen Fehler aus, wenn sie enthalten ist.

Fügen Sie unmittelbar vor dem @EntryPoint()TestBellState Vorgang hinzu, und Ihr Q# Programm bis zu diesem Punkt sollte nun wie folgt aussehen:

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

    operation SetQubitState(desired : Result, target : Qubit) : Unit {
        if desired != M(target) {
            X(target);
        }
    }

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = One;

        // allocate the qubits
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
            
            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

Kopieren Sie das vollständige Codebeispiel, und fügen Sie es in das Codefenster Copilot for Azure Quantum ein, legen Sie die Folie für die Anzahl der Aufnahmen auf "1" fest, und klicken Sie auf Ausführen. Die Ergebnisse werden im Histogramm und in den Feldern Ergebnisse angezeigt.

Q1 - Zeros: 0
Q1 - Ones: 1000
Q2 - Zeros: 1000
Q2 - Ones: 0

Da die Qubits noch nicht bearbeitet wurden, haben sie ihre Anfangswerte beibehalten: Das erste Qubit gibt jedes Mal One zurück, und das zweite Qubit gibt Zero zurück.

Wenn Sie den Wert von initial in Zero ändern und das Programm erneut ausführen, sollten Sie beachten, dass auch das erste Qubit jedes Mal zurückgegeben wird Zero .

Q1 - Zeros: 1000
Q1 - Ones: 0
Q2 - Zeros: 1000
Q2 - Ones: 0

Setzen eines Qubits in Superposition

Derzeit befinden sich die Qubits im Programm alle in einem klassischen Zustand, d. h., sie sind entweder 1 oder 0. Sie wissen dies, da das Programm die Qubits in einem bekannten Zustand initialisiert und Sie keine Prozesse hinzugefügt haben, um sie zu bearbeiten. Bevor Sie die Qubits verschränken, versetzen Sie das erste Qubit in einen Superpositionszustand, wobei eine Messung des Qubits ~50% der Zeit und One ~50% der Zeit zurückgibt Zero . Konzeptionell kann man sich das Qubit mit der gleichen Wahrscheinlichkeit für die Messung von entweder Zero oder Oneansehen.

Um ein Qubit in die Superposition zu versetzen, stellt Q# den H-Vorgang (Hadamard) bereit. Rufen Sie den X Vorgang aus der Prozedur Initialisieren eines Qubits auf eine zuvor bekannte Zustandsprozedur zurück , die ein Qubit von 0 auf 1 (oder umgekehrt) umgedreht hat. Der H Vorgang kippt das Qubit auf halbem Weg in einen Zustand gleicher Wahrscheinlichkeiten von Zero oder One. Bei der Messung sollte ein Qubit in Superposition ungefähr die gleiche Anzahl von Zero- und One-Ergebnissen zurückgeben.

Ändern Sie den Code im TestBellState Vorgang, indem Sie den Anfangswert auf One zurücksetzen und eine Zeile für den H Vorgang einfügen:

for test in 1..count {
    use (q1, q2) = (Qubit(), Qubit());   
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);
        
        H(q1);                // Add the H operation after initialization and before measurement

        // measure each qubit
        let resultQ1 = M(q1);            
        let resultQ2 = M(q2); 
        ...

Wenn Sie nun das Programm ausführen, können Sie die Ergebnisse des ersten Qubits in der Superposition sehen.

Q1 - Zeros: 523            // results will vary
Q1 - Ones: 477
Q2 - Zeros: 1000
Q2 - Ones: 0

Jedes Mal, wenn Sie das Programm ausführen, variieren die Ergebnisse für das erste Qubit geringfügig, liegen jedoch nahe bei 50 % One und 50 % Zero, während die Ergebnisse für das zweite Qubit die ganze Zeit Zero bleiben.

Q1 - Zeros: 510           
Q1 - Ones: 490
Q2 - Zeros: 1000
Q2 - Ones: 0

Das Initialisieren des ersten Qubits auf Zero gibt ähnliche Ergebnisse zurück.

Q1 - Zeros: 504           
Q1 - Ones: 496
Q2 - Zeros: 1000
Q2 - Ones: 0

Hinweis

Indem Sie den Schieberegler im Copilot für Azure Quantum bewegen und die Anzahl der Aufnahmen erhöhen, können Sie sehen, wie sich die Superpositionsergebnisse geringfügig über die Verteilung der Aufnahmen unterscheiden.

Verschränken zweier Qubits

Wie bereits erwähnt, sind verschränkte Qubits so verbunden, dass sie nicht unabhängig voneinander beschrieben werden können. Das bedeutet Folgendes: Jeder Vorgang, der für ein Qubit ausgeführt wird, wird auch für das verschränkte Qubit ausgeführt. Dies ermöglicht es Ihnen, den resultierenden Zustand eines Qubits ohne Messung zu ermitteln, indem Sie nur den Zustand des anderen Qubits messen. (In diesem Beispiel werden zwei Qubits verwendet. Es ist jedoch auch möglich, drei oder mehr Qubits zu verschränken.)

Um die Verschränkung zu ermöglichen, wird von Q# der CNOT-Vorgang bereitgestellt, der für Controlled-NOT steht. Das Ergebnis des Ausführens dieses Vorgangs für zwei Qubits ist, dass das zweite Qubit umgekehrt wird, wenn das erste Qubit One ist.

Fügen Sie den CNOT-Vorgang Ihrem Programm unmittelbar nach dem H-Vorgang hinzu. Ihr vollständiges Programm sollte wie folgt aussehen:

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = Zero;

        // allocate the qubits
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
        
            H(q1);            
            CNOT(q1, q2);      // Add the CNOT operation after the H operation

            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

Wenn Sie nun das Programm ausführen, sollte folgendes angezeigt werden:

Q1 - Zeros: 502           // results will vary
Q1 - Ones: 498
Q2 - Zeros: 502
Q2 - Ones: 498

Beachten Sie, dass sich die Statistiken für das erste Qubit nicht geändert haben (es gibt immer noch eine ~50/50-Wahrscheinlichkeit eines Zero oder eines One nach der Messung), aber die Messergebnisse für das zweite Qubit sind immer identisch mit der Messung des ersten Qubits, unabhängig davon, wie oft Sie das Programm ausführen. Der CNOT-Vorgang hat die zwei Qubits verschränkt, sodass was immer mit dem einen von ihnen geschieht, auch mit dem anderen geschieht.

Voraussetzungen

So entwickeln und führen Sie das Codebeispiel in Ihrer lokalen Entwicklungsumgebung aus:

Erstellen einer neuen Q# Datei

  1. Öffnen Sie Visual Studio Code, und wählen Sie Datei > Neue Textdatei aus, um eine neue Datei zu erstellen.
  2. Speichern Sie die Datei unter dem Namen CreateBellStates.qs. Diese Datei enthält den Q# Code für Ihr Programm.

Initialisieren eines Qubits in einen bekannten Zustand

Der erste Schritt besteht darin, einen Q#-Vorgang zu definieren, der ein Qubit in einem bekannten Zustand initialisiert. Dieser Vorgang kann aufgerufen werden, um ein Qubit auf einen klassischen Zustand festzulegen. Das bedeutet, dass entweder immer Zero oder immer One zurückgegeben wird. Zero und One sind Q#-Werte, die die beiden einzigen möglichen Ergebnisse der Messung eines Qubits darstellen.

Öffnen Sie CreateBellStates.qs den folgenden Code, und kopieren Sie diesen:

   namespace Bell {
       open Microsoft.Quantum.Intrinsic;
       open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }
   }

Im Codebeispiel werden die beiden Standardvorgänge M und X eingeführt, die den Zustand eines Qubits transformieren.

Der SetQubitState-Vorgang:

  1. Verwendet zwei Parameter: einen Typ Resultmit dem Namen desired, der den gewünschten Zustand für das Qubit in (Zero oder One) darstellt, und einen Typ Qubit.
  2. Führt einen Messvorgang M aus, der den Zustand des Qubits misst (Zero oder One) und das Ergebnis mit dem in desired angegebenen Wert vergleicht.
  3. Wenn die Messung nicht mit dem verglichenen Wert übereinstimmt, führt sie einen Vorgang X aus, der den Zustand des Qubits so umdreht, dass die Wahrscheinlichkeiten einer Zero und One zurückgebenden Messung umgekehrt werden. Auf diese Weise versetzt SetQubitState das Zielqubit immer in den gewünschten Zustand.

Schreiben eines Testvorgangs zum Testen des Bell-Zustands

Erstellen Sie als Nächstes einen weiteren Vorgang mit dem Namen TestBellState, um die Auswirkungen des SetQubitState-Vorgangs zu veranschaulichen. Dieser Vorgang ordnet zwei Qubits zu, ruft SetQubitState auf, um das erste Qubit auf einen bekannten Zustand festzulegen, und misst dann die Qubits, um die Ergebnisse anzuzeigen.

Fügen Sie der Datei CreateBellStates.qs nach dem Vorgang SetQubitState den folgenden Vorgang hinzu:

operation TestBellState() : (Int, Int, Int, Int) {
    mutable numOnesQ1 = 0;
    mutable numOnesQ2 = 0;
    let count = 1000;
    let initial = One;

    // allocate the qubits
    use (q1, q2) = (Qubit(), Qubit());   
    for test in 1..count {
        SetQubitState(initial, q1);
        SetQubitState(Zero, q2);
        
        // measure each qubit
        let resultQ1 = M(q1);            
        let resultQ2 = M(q2);           

        // Count the number of 'Ones' returned:
        if resultQ1 == One {
            set numOnesQ1 += 1;
        }
        if resultQ2 == One {
            set numOnesQ2 += 1;
        }
    }

    // reset the qubits
    SetQubitState(Zero, q1);             
    SetQubitState(Zero, q2);
    

    // Display the times that |0> is returned, and times that |1> is returned
    Message($"Q1 - Zeros: {count - numOnesQ1}");
    Message($"Q1 - Ones: {numOnesQ1}");
    Message($"Q2 - Zeros: {count - numOnesQ2}");
    Message($"Q2 - Ones: {numOnesQ2}");
    return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

}

Im Code sind die count Variablen und initial auf 1000 und One festgelegt. So wird das erste Qubit auf One initialisiert und jedes Qubit 1000-mal gemessen.

Beim TestBellState-Vorgang geschieht Folgendes:

  1. Verwendet zwei Parameter: count, die Anzahl der Ausführungen einer Messung, und initial, den gewünschten Zustand zum Initialisieren des Qubits.
  2. Ruft die use-Anweisung auf, um zwei Qubits zu initialisieren.
  3. Führt Schleifendurchläufe für count Iterationen aus. Für jede Schleife wird
    1. SetQubitState aufgerufen, um einen angegebenen initial-Wert für das erste Qubit festzulegen.
    2. SetQubitState erneut aufgerufen, um das zweite Qubit in einen Zero-Zustand zu setzen.
    3. der M-Vorgang verwendet, um jedes Qubit zu messen.
    4. die Anzahl der Messungen für jedes Qubit gespeichert, das One zurückgibt.
  4. Nach dem Schleifendurchlauf wird SetQubitState erneut aufgerufen, um die Qubits in einen bekannten Zustand (Zero) zurückzusetzen, damit andere Benutzer die Qubits in einem bekannten Zustand zuordnen können. Dies ist aufgrund der use-Anweisung erforderlich.
  5. Schließlich wird die Message-Funktion verwendet, um eine Meldung in der Konsole auszugeben, bevor die Ergebnisse zurückgegeben werden.

Ausführen des Codes

Bevor Sie mit den Prozeduren für Superposition und Verschränkung fortfahren, testen Sie den Code bis zu diesem Punkt, um die Initialisierung und Messung der Qubits zu sehen.

Dies erfolgt in der Q# Datei, indem sie direkt vor dem auszuführenden Vorgang eine @EntryPoint() hinzufügen. In diesem Fall ist z. B. der TestBellState Vorgang.

Hinweis

@EntryPoint() ist nur für eigenständige Q#-Programme erforderlich. Wenn Sie ein Q# Programm in Jupyter Notebooks ausführen oder ein Q# Programm aus einer Python-Hostdatei aufrufen, ist dies nicht erforderlich und löst einen Fehler aus, wenn sie enthalten ist.

Die Datei CreateBellStates.qs sollte jetzt wie folgt aussehen:

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = One;

        // allocate the qubits
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
            
            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

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 SieQ# : Festlegen des Azure Quantum QIR-Zielprofils und dann : uneingeschränkt ausQ#.

Wählen Sie zum Ausführen des Programms in der Dropdownliste des Wiedergabesymbols oben rechts die Option Datei ausführen Q# aus, oder drücken Sie STRG+F5. Das Programm führt den Vorgang oder die Funktion aus, die mit dem @EntryPoint() -Attribut im Standardsimulator gekennzeichnet ist.

Hinweis

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

Ihre Ausgabe wird in der Debugkonsole angezeigt.

Q1 - Zeros: 0
Q1 - Ones: 1000
Q2 - Zeros: 1000
Q2 - Ones: 0

Da die Qubits noch nicht bearbeitet wurden, haben sie ihre Anfangswerte beibehalten: Das erste Qubit gibt jedes Mal One zurück, und das zweite Qubit gibt Zero zurück.

Wenn Sie den Wert von initial in Zero ändern und das Programm erneut ausführen, sollten Sie beachten, dass auch das erste Qubit jedes Mal zurückgegeben wird Zero .

Q1 - Zeros: 1000
Q1 - Ones: 0
Q2 - Zeros: 1000
Q2 - Ones: 0

Tipp

Denken Sie daran, ihre Datei jedes Mal zu speichern, wenn Sie eine Änderung am Code einführen, bevor Sie sie erneut ausführen.

Setzen eines Qubits in Superposition

Derzeit befinden sich die Qubits im Programm alle in einem klassischen Zustand, d. h., sie sind entweder 1 oder 0. Sie wissen dies, da das Programm die Qubits in einem bekannten Zustand initialisiert und Sie keine Prozesse hinzugefügt haben, um sie zu bearbeiten. Bevor Sie die Qubits verschränken, versetzen Sie das erste Qubit in einen Superpositionszustand, wobei eine Messung des Qubits in 50 Prozent der Fälle Zero und 50 Prozent der Fälle One zurückgibt. Konzeptuell können Sie sich das Qubit als Kombination von Zero und One vorstellen.

Um ein Qubit in die Superposition zu versetzen, stellt Q# den H-Vorgang (Hadamard) bereit. Rufen Sie den X Vorgang aus der Prozedur Initialisieren eines Qubits in eine bekannte Zustandsprozedur zurück, die ein Qubit von Zero zu One (oder umgekehrt) gekippt hat. Der H Vorgang kippt das Qubit auf halbem Weg in einen Zustand mit gleicher Wahrscheinlichkeit von Zero oder One. Bei der Messung sollte ein Qubit in Superposition ungefähr die gleiche Anzahl von Zero- und One-Ergebnissen zurückgeben.

Ändern Sie den Code im TestBellState-Vorgang so, dass er den H-Vorgang einschließt:

    for test in 1..count {
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
            
            H(q1);                // Add the H operation after initialization and before measurement

            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2); 
            ...

Wenn Sie nun das Programm ausführen, sehen Sie die Ergebnisse des ersten Qubits in Superposition:

Q1 - Zeros: 523            // results will vary
Q1 - Ones: 477
Q2 - Zeros: 1000
Q2 - Ones: 0

Bei jeder Ausführung des Programms variieren die Ergebnisse für das erste Qubit geringfügig, liegen aber meist in 50 Prozent der Fälle bei One und in 50 Prozent der Fälle bei Zero, während die Ergebnisse für das zweite Qubit immer Zero lauten.

Q1 - Zeros: 510           
Q1 - Ones: 490
Q2 - Zeros: 1000
Q2 - Ones: 0

Beim Initialisieren des ersten Qubits mit Zero werden ähnliche Ergebnisse zurückgegeben.

Q1 - Zeros: 504           
Q1 - Ones: 496
Q2 - Zeros: 1000
Q2 - Ones: 0

Verschränken zweier Qubits

Wie bereits erwähnt, sind verschränkte Qubits so verbunden, dass sie nicht unabhängig voneinander beschrieben werden können. Das bedeutet Folgendes: Jeder Vorgang, der für ein Qubit ausgeführt wird, wird auch für das verschränkte Qubit ausgeführt. Dies ermöglicht es Ihnen, den resultierenden Zustand eines Qubits ohne Messung zu ermitteln, indem Sie nur den Zustand des anderen Qubits messen. (In diesem Beispiel werden zwei Qubits verwendet. Es ist jedoch auch möglich, drei oder mehr Qubits zu verschränken.)

Um die Verschränkung zu ermöglichen, wird von Q# der CNOT-Vorgang bereitgestellt, der für Controlled-NOT steht. Das Ergebnis des Ausführens dieses Vorgangs für zwei Qubits ist, dass das zweite Qubit umgekehrt wird, wenn das erste Qubit One ist.

Fügen Sie den CNOT-Vorgang Ihrem Programm unmittelbar nach dem H-Vorgang hinzu. Ihr vollständiges Programm sollte wie folgt aussehen:

namespace Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

       operation SetQubitState(desired : Result, target : Qubit) : Unit {
           if desired != M(target) {
               X(target);
           }
       }

    @EntryPoint()
    operation TestBellState() : (Int, Int, Int, Int) {
        mutable numOnesQ1 = 0;
        mutable numOnesQ2 = 0;
        let count = 1000;
        let initial = One;

        // allocate the qubits
        use (q1, q2) = (Qubit(), Qubit());   
        for test in 1..count {
            SetQubitState(initial, q1);
            SetQubitState(Zero, q2);
        
            H(q1);            
            CNOT(q1, q2);      // Add the CNOT operation after the H operation

            // measure each qubit
            let resultQ1 = M(q1);            
            let resultQ2 = M(q2);           
    
            // Count the number of 'Ones' returned:
            if resultQ1 == One {
                set numOnesQ1 += 1;
            }
            if resultQ2 == One {
                set numOnesQ2 += 1;
            }
        }
    
        // reset the qubits
        SetQubitState(Zero, q1);             
        SetQubitState(Zero, q2);
        
    
        // Display the times that |0> is returned, and times that |1> is returned
        Message($"Q1 - Zeros: {count - numOnesQ1}");
        Message($"Q1 - Ones: {numOnesQ1}");
        Message($"Q2 - Zeros: {count - numOnesQ2}");
        Message($"Q2 - Ones: {numOnesQ2}");
        return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 );

    }
}

Q1 - Zeros: 502           
Q1 - Ones: 498       // results will vary
Q2 - Zeros: 502
Q2 - Ones: 498

Die Statistiken für das erste Qubit haben sich nicht geändert (eine Wahrscheinlichkeit von 50/50 für Zero oder One nach der Messung). Die Messergebnisse für das zweite Qubit sind jedoch immer identisch mit der Messung des ersten Qubits. Der CNOT-Vorgang hat die zwei Qubits verschränkt, sodass jeder Vorgang, der für eins von Ihnen ausgeführt wird, auch für das andere ausgeführt wird.

Zeichnen des Häufigkeitshistogramms

Wir visualisieren die Verteilung der Ergebnisse, die durch die mehrfache Ausführung des Quantenprogramms erzielt wurden. Das Häufigkeitshistogramm hilft dabei, die Wahrscheinlichkeitsverteilung dieser Ergebnisse zu visualisieren.

  1. Wählen Sie Ansicht –> Befehlspalette aus, oder drücken Sie STRG+UMSCHALT+P, und geben Sie "Histogramm" ein, wodurch die Q#Option angezeigt werden soll: Datei ausführen und Histogramm anzeigen . Wählen Sie diese Option aus, um das Q# Histogrammfenster zu öffnen.

  2. Geben Sie eine Reihe von Aufnahmen ein, um das Programm auszuführen, z. B. 100 Aufnahmen, und drücken Sie die EINGABETASTE. Das Histogramm wird im Q# Histogrammfenster angezeigt.

  3. Jeder Balken im Histogramm entspricht einem möglichen Ergebnis, und seine Höhe stellt die Anzahl der Beobachteten des Ergebnisses dar. In diesem Fall gibt es 50 verschiedene eindeutige Ergebnisse. Beachten Sie, dass für jedes Ergebnis die Messergebnisse für das erste und das zweite Qubit immer gleich sind.

    Screenshot des Q# Histogrammfensters in Visual Studio Code.

    Tipp

    Sie können das Histogramm mithilfe des Mauslaufrads oder einer Trackpadgeste zoomen. Wenn sie vergrößert ist, können Sie das Diagramm schwenken, indem Sie während des Bildlaufs "ALT" drücken.

  4. Klicken Sie auf eine Leiste, um den Prozentsatz dieses Ergebnisses anzuzeigen.

  5. Klicken Sie auf das Symbol mit den Einstellungen oben links, um Optionen anzuzeigen. Sie können die besten 10 Ergebnisse, die ersten 25 Ergebnisse oder alle Ergebnisse anzeigen. Sie können die Ergebnisse auch von "hoch" nach "niedrig" oder "niedrig" nach "hoch" sortieren.

    Screenshot des Q# Histogrammfensters in Visual Studio Code, das zeigt, wie Einstellungen angezeigt werden.

Nächste Schritte

Sehen Sie sich weitere Q#-Tutorials an:

  • Der Quanten-Zufallszahlengenerator zeigt, wie ein Q# Programm geschrieben wird, das zufällige Zahlen aus Qubits in der Superposition generiert.
  • Der Suchalgorithmus von Grover zeigt, wie ein Q# Programm geschrieben wird, das den Grover-Suchalgorithmus verwendet.
  • Quantum Fourier Transform untersucht, wie ein Q# Programm geschrieben wird, das bestimmte Qubits direkt adressiert.
  • Die Quanten-Katas sind Selbstlernprogramme und Programmierübungen, die darauf abzielen, die Elemente des Quantencomputings und Q# der Programmierung gleichzeitig zu unterrichten.