Das Benutzerhandbuch zur Quantenprogrammiersprache Q#

Die Quantenprogrammiersprache Q# ist Teil des Quantum Development Kit von Microsoft, das umfassende IDE-Unterstützung und Tools für die Programmvisualisierung und -analyse bietet. Mit Q# und dem Quantum Development Kit (QDK) können Sie Quantenprogramme schreiben und mithilfe von Azure Quantum auf echter Quantenhardware ausführen.

Weitere Informationen finden Sie unter Einrichten einer lokalen Entwicklungsumgebung für Azure Quantum sowie unter Übermitteln von Q#-Aufträgen an Azure Quantum.

Das Q#-Benutzerhandbuch enthält:

  • Möglichkeiten zum Ausführen eines Q#-Programms: Ein Q#-Programm kann als eigenständige Anwendung oder mit einem zusätzlichen Hostprogramm ausgeführt werden, das in Python oder einer .NET-Sprache geschrieben wurde.

  • Testen und Debuggen von Q#-Programmen: Wie bei der herkömmlichen Programmierung muss unbedingt überprüft werden können, ob sich Quantenprogramme wie vorgesehen verhalten, und es muss möglich sein, fehlerhaftes Verhalten zu diagnostizieren. Das Quantum Development Kit ermöglicht das Testen und Debuggen von Quantenprogrammen.

  • Das Handbuch zur Sprache Q#: Q# ist eine eigenständige Sprache, die ein hohes Maß an Abstraktion bietet. Es gibt kein Konzept eines Quantenzustands oder einer Schaltung. Q# implementiert stattdessen Programme in Form von Anweisungen und Ausdrücken, ähnlich wie klassische Programmiersprachen. Das Handbuch zur Sprache Q# enthält eine vollständige Spezifikation und Dokumentation der Quantenprogrammiersprache Q#.

  • Dokumentation zu Quantensimulatoren: Bei Quantensimulatoren handelt es sich um Softwareprogramme, die auf klassischen Computern ausgeführt werden und als Zielcomputer für ein Q#-Programm fungieren. Sie ermöglichen das Ausführen und Testen von Quantenprogrammen auf klassischen Computern.

  • Die Q#-Bibliotheksdokumentation: Das Quantum Development Kit bietet zusätzliche fachgebietsspezifische Funktionen in Form von NuGet-Paketen, die Ihren Q#-Projekten hinzugefügt werden können. Die Dokumentation umfasst Vorgänge, Funktionen, benutzerdefinierte Typen, Beispiele und Konzepte der Q#-Standardbibliothek sowie der Quantenchemiebibliothek, der Bibliothek für quantenbasiertes maschinelles Lernen und der numerischen Quantenbibliothek.

Was enthält ein Q#-Programm?

Hier erfahren Sie, welche allgemeinen Komponenten ein Q#-Programm umfasst. Sehen Sie sich das folgende Q#-Programm an:

namespace HelloQuantum {

    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;


    @EntryPoint()
    operation SayHelloQ() : Unit {
        Message("Hello quantum world!");
    }
}

EntryPoint teilt dem Q#-Compiler mit, wo mit der Ausführung des Programms begonnen werden soll. Das Programm gibt die folgende Meldung aus:

    Hello quantum world!

Namespaces

Jede Q#-Datei beginnt in der Regel mit einem Namespace. Hier sehen Sie ein Beispiel:

namespace HelloQuantum {
    // Your code goes here.
}

Namespaces helfen bei der Strukturierung zusammengehöriger Funktionen. Sie werden wichtig, wenn Sie Q#-Bibliotheken in Ihren Programmen verwenden und eigene Bibliotheken schreiben.

Bibliotheken

In Q# werden ausgiebig Bibliotheken genutzt. Eine Bibliothek ist ein Paket, das Funktionen und Vorgänge enthält, die Sie in Quantenprogrammen verwenden können.

Beispielsweise unterstützt Sie die Bibliothek Microsoft.Quantum.Chemistry bei der Durchführung von Quantenberechnungen aus der Chemie. Es gibt mehrere Standardbibliotheken, die alle Arten von grundlegenden Vorgängen abdecken.

Wenn Sie eine Funktion oder einen Vorgang aus einer Bibliothek abrufen, geben Sie den Namespace der Bibliothek an. Im folgenden Beispiel wird die Message-Funktion aus der Bibliothek Microsoft.Quantum.Intrinsic aufgerufen, um in der Konsole eine Meldung auszugeben:

namespace HelloQuantum {

    @EntryPoint()
    operation SayHelloQ() : Unit {
        Microsoft.Quantum.Intrinsic.Message("Hello quantum world!");
    }
}

Normalerweise verwenden Sie die open-Direktive, um den Code kompakter und leichter lesbar zu machen.

Dieses Beispiel funktioniert genauso wie das vorherige, allerdings wird die open-Direktive verwendet, um den Namespace Microsoft.Quantum.Intrinsic in das Programm einzubinden:

namespace HelloQuantum {

    open Microsoft.Quantum.Intrinsic;

    @EntryPoint()
    operation SayHelloQ() : Unit {
        Message("Hello quantum world!");
    }
}

Hier geben Sie einfach Message an, und der Compiler erkennt den entsprechenden Namespace.

Die Q#-Dokumentation enthält eine umfassende Referenzdokumentation für alle integrierten Bibliotheken. Weitere Informationen finden Sie unter Q#-Bibliotheken.

Typen

Q# bietet zahlreiche integrierte Typen, mit denen Sie bereits vertraut sind (etwa Int, Double, Bool und String), sowie spezifische Typen für Quantencomputing. Der Typ Result stellt beispielsweise das Ergebnis einer Qubit-Messung dar und kann einen von zwei möglichen Werten aufweisen: One oder Zero. Q# bietet auch Typen, die Bereiche, Arrays und Tupel definieren. Sie können sogar eigene benutzerdefinierte Typen definieren.

Insgesamt ist das Q#-Typsystem ziemlich minimalistisch, in dem Sinne, dass es kein explizites Konzept von Klassen oder Schnittstellen gibt, wie es von klassischen Sprachen wie C# oder Java verwendet werden kann.

Zuordnen von Qubits

In Q# werden Qubits mithilfe des Schlüsselworts use zugeordnet. Sie können ein oder mehrere Qubits gleichzeitig zuordnen.

Im Folgenden finden Sie ein Beispiel für die Zuordnung eines Qubit:

// Allocate a qubit.
use q = Qubit();

// Do something with q here.

Standardmäßig beginnt jedes Qubit, das Sie mit dem Schlüsselwort use zuordnen, im Zustand null.

Quantenvorgänge

Nach der Zuordnung kann ein Qubit an Operationen und Funktionen übergeben werden, die auch als aufrufbare Aufrufe bezeichnet werden. Gewissermaßen ist dies alles, was ein Q#-Programm mit einem Qubit ausführen kann. Vorgänge sind die Grundbausteine eines Q#-Programms. Ein Vorgang Q# ist eine Quantenunterroutine. Das heißt, es handelt sich um eine aufrufbare Routine, die Quantenvorgänge enthält, mit denen der Zustand des Qubit-Registers geändert wird.

Um einen Q#-Vorgang zu definieren, geben Sie einen Namen für den Vorgang und dessen Ein- und Ausgabe an. Im Folgenden finden Sie ein einfaches Beispiel:

operation SayHelloQ() : Unit {
    Message("Hello quantum world!");
}

Der Name des Vorgangs lautet hierbei SayHelloQ. Er akzeptiert null Argumente als Eingabe und gibt den Typ Unit zurück. Dies bedeutet, dass der Vorgang keine Informationen zurückgibt.

Die Q#-Bibliotheken enthalten auch Vorgänge, die Sie in Ihren Programmen verwenden können – etwa den Hadamard- oder H-Vorgang. Bei einem Qubit auf Z-Basis versetzt der H-Vorgang das Qubit in eine ausgeglichene Superposition. Wenn sich das Qubit in Superposition befindet, ist die Wahrscheinlichkeit jeweils 50 Prozent, dass eine Messung null oder eins ergibt.

Alle direkten Aktionen für den Zustand eines Qubits werden durch systeminterne aufrufbare Komponenten, z. B. X und H, definiert, d. h. aufrufbare Komponenten, deren Implementierungen nicht in Q# sondern vom Zielcomputer definiert werden. Was diese Operationen tatsächlich ausführen, hängt von dem Zielcomputer ab, auf dem das jeweilige Q#-Programm ausgeführt wird. Weitere Informationen finden Sie unter Q#Programmimplementierung.

Wenn Sie das Programm beispielsweise auf unserem Simulator für den vollständigen Zustand ausführen, führt dieser die entsprechenden mathematischen Operationen für das simulierte Quantensystem aus. Wenn es sich mit einem Blick vorwärts in die Zukunft bei dem Zielcomputer jedoch um einen echten Quantencomputer handelt, wird dieser durch den internen Aufruf solcher Vorgänge Q#angewiesen, die entsprechenden tatsächlichen Vorgänge für die tatsächliche Quantum-Hardware auszuführen. Auf einem Quantencomputer mit abgefangenen Quantendaten werden die Quantenvorgänge beispielsweise durch genau getimte Pulse realisiert.

Ein Q#-Programm kombiniert diese Vorgänge gemäß der Definition durch den Zielcomputer zu allgemeineren Vorgängen für die Quantenberechnung. Auf diese Weise erleichtert Q# das Ausdrücken der Logik, die Quantenalgorithmen und hybriden quantenklassischen Algorithmen zugrunde liegt, und ist gleichzeitig allgemein in Bezug auf die Struktur eines Zielcomputers oder Simulators.

Messen von Qubits

Es gibt viele Arten von Quantenmessungen. Bei Q# liegt der Fokus allerdings auf projektiven Messungen für einzelne Qubits (auch Pauli-Messungen genannt). Bei der Messung in einer bestimmten Basis (etwa in der Berechnungsbasis $\ket{0},\ket{1}$) wird der Qubit-Zustand auf den gemessenen Basiszustand projiziert und damit die Superposition zwischen den beiden zerstört.

In Q# wird für Pauli-Messungen der Measure-Vorgang angewendet. Er führt eine gemeinsame Messung eines oder mehrerer Qubits in den angegebenen Pauli-Basen durch. Der Measure-Vorgang gibt einen Result-Typ zurück.

Hinweis

Wenn das Basisarray und das Qubitarray unterschiedliche Längen aufweisen, ist der Measure-Vorgang nicht erfolgreich.

Zur Implementierung einer Messung in der Berechnungsbasis $\ket{0},\ket{1}$ kann auch der M-Vorgang verwendet werden. Er führt eine Messung eines einzelnen Qubits in der Pauli-Z-Basis durch. Somit entspricht der M-Vorgang der Anwendung von Measure([PauliZ], [qubit]).

Ein einfaches Beispiel ist das folgende Programm, das ein Qubit im Zustand $\ket{0}$ zuordnet, dann die Hadamard-Transformation H auf es anwendet und das Ergebnis in der PauliZ-Basis berechnet.

@EntryPoint()
operation MeasureOneQubit() : Result {
    // Allocate a qubit, by default it is in zero state      
    use q = Qubit();  
    // We apply a Hadamard operation H to the state
    // It now has a 50% chance of being measured 0 or 1  
    H(q);      
    // Now we measure the qubit in Z-basis.
    let result = M(qubit);
    // We reset the qubit before releasing it.
    if result == One { X(qubit); }
    // Finally, we return the result of the measurement.
    return result;
    
}

Für Messungen, die über eine einzelne gemeinsame Messung hinausgehen, enthält der Namespace Microsoft.Quantum.Measurement spezifischere Vorgänge. Der MultiM-Vorgang verwendet beispielsweise ein Array von Qubits und gibt ein Array von Messergebnissen in der Berechnungsbasis zurück.

Nächste Schritte