Quantum-Arbeitsspeicherverwaltung

Ein Programm beginnt immer ohne Qubits. Das bedeutet, dass Werte vom Typ Qubit nicht als Einstiegspunktargumente übergeben werden können. Diese Einschränkung ist beabsichtigt, da es ein Ziel von Q# ist, ein Programm in seiner Gesamtheit auszudrücken und zu erklären. Stattdessen ordnet ein Programm Qubits (oder Quantenspeicher) während der Ausführung zu bzw. gibt ihn wieder frei. In diesem Zusammenhang modelliert Q# den Quantencomputer als einen Qubit-Heap.

Anstatt separate Zuweisungs- und Freigabeanweisungen für den Quantenspeicher zu unterstützen, unterstützt Q# die Quantenspeicherbelegung in Form von Blockanweisungen, wobei auf den Arbeitsspeicher nur innerhalb des Bereichs dieser Blockanweisung zugegriffen werden kann. Der Anweisungsblock kann implizit definiert werden, wenn Qubits für die Dauer des aktuellen Bereichs zugeordnet werden. Dies wird in den Abschnitten zu den Anweisungen use und borrow ausführlicher beschrieben. Wenn versucht wird, nach Abschluss der Anweisung auf die zugeordneten Qubits zuzugreifen, tritt eine Laufzeitausnahme auf.

Q# verfügt über zwei Anweisungen (use und borrow), um Qubit-Werte, Arrays von Qubits oder eine beliebige Kombination zu initiieren. Diese Anweisungen können nur innerhalb von Vorgängen verwendet werden. Sie erfassen die instanziierten Qubit-Werte, binden sie an die in der Anweisung festgelegten Variablen und führen dann einen Block von Anweisungen aus. Am Ende des Blocks gehen die gebundenen Variablen aus dem Geltungsbereich und sind nicht mehr definiert.

In Q# wird zwischen der Zuordnung von bereinigten und schmutzigen Qubits unterschieden. Bereinigte Qubits sind nicht verschränkt und werden von keinem anderen Teil der Berechnung verwendet. Schmutzige Qubits sind Qubits, deren Zustand unbekannt ist und die sogar mit anderen Teilen des Speichers des Quantenprozessors verschränkt sein können.

use-Anweisung

Bereinigte Qubits werden von der use-Anweisung zugeordnet.

  • Die Anweisung besteht aus dem Schlüsselwort use gefolgt von einer Bindung und einem optionalen Anweisungsblock.
  • Wenn ein Anweisungsblock vorhanden ist, sind die Qubits nur innerhalb dieses Blocks verfügbar. Andernfalls sind die Qubits bis zum Ende des aktuellen Geltungsbereichs verfügbar.
  • Die Bindung folgt dem gleichen Muster wie let-Anweisungen: Entweder ein einzelnes Symbol oder ein Tupel von Symbolen, gefolgt von einem Gleichheitszeichen =und entweder einem einzelnen Tupel oder einem übereinstimmenden Tupel von Initialisierer.

Initialisierer sind entweder für ein einzelnes Qubit verfügbar, das als Qubit() angegeben ist, oder für ein Array von Qubits, Qubit[n], wobei n ein Int Ausdruck ist. Beispiel:

use qubit = Qubit();
// ...

use (aux, register) = (Qubit(), Qubit[5]);
// ...

use qubit = Qubit() {
    // ...
}

use (aux, register) = (Qubit(), Qubit[5]) {
    // ...
}

Die Qubits befinden sich bei der Belegung garantiert in einem |0⟩ Zustand. Sie werden am Ende des Bereichs freigegeben und müssen sich bei der Veröffentlichung im Zustand |0⟩ befinden. Diese Anforderung wird nicht vom Compiler erzwungen, da dies eine symbolische Auswertung erfordern würde, die schnell zu teuer wird. Bei der Ausführung in Simulatoren kann die Anforderung während der Laufzeit erzwungen werden. Bei Quantenprozessoren kann die Anforderung nicht während der Laufzeit erzwungen werden. Ein nicht gemessenes Qubit kann durch eine unitäre Transformation auf |0⟩ zurückgesetzt werden. Andernfalls führt dies zu einem falschen Verhalten.

Die use-Anweisung ordnet die Qubits dem freien Qubit-Heap des Quantenprozessors zu und gibt sie spätestens am Ende des Geltungsbereichs, in dem die Qubits gebunden sind, an den Heap zurück.

borrow-Anweisung

Die borrow-Anweisung gewährt Zugriff auf Qubits, die bereits zugewiesen sind, aber aktuell nicht verwendet werden. Diese Qubits können sich in einem beliebigen Zustand befinden und müssen am Ende der borrow-Anweisung wieder den gleichen Zustand aufweisen. Einige Quantenalgorithmen sind bei der Verwendung von Qubits nicht auf deren genauen Zustand angewiesen und setzen nicht voraus, dass deren Verschränkung mit dem restlichen System aufgehoben wird. Das bedeutet, dass sie vorübergehend zusätzliche Qubits benötigen. Sie können jedoch sicherstellen, dass diese Qubits wieder exakt in ihren ursprünglichen Zustand zurückversetzt werden – unabhängig davon, welcher Zustand das war.

Wenn Qubits verwendet werden, aber während Teilen eines Unterprogramms nicht berührt werden, können diese Qubits für die Verwendung durch einen solchen Algorithmus ausgeliehen werden, anstatt zusätzlichen Quantenspeicher zuzuordnen. Ausleihen statt Zuordnen kann den gesamten Quantenspeicherbedarf eines Algorithmus erheblich reduzieren und ist ein Quantenbeispiel für einen typischen Raum-Zeit-Kompromiss.

Eine borrow-Anweisung folgt dem gleichen Muster wie weiter oben für die use-Anweisung beschrieben, und es stehen die gleichen Initialisierer zur Verfügung. Beispiel:

borrow qubit = Qubit();
// ...

borrow (aux, register) = (Qubit(), Qubit[5]);
// ...

borrow qubit = Qubit() {
    // ...
}

borrow (aux, register) = (Qubit(), Qubit[5]) {
    // ...
}

Die ausgeliehenen Qubits befinden sich in einem unbekannten Zustand und gehen am Ende des Anweisungsblocks aus dem Geltungsbereich. Der Ausleiher verpflichtet sich, die Qubits in dem Zustand zu belassen, in dem sie ausgeliehen wurden. Mit anderen Worten: Ihr Zustand zu Beginn und am Ende des Anweisungsblocks muss identisch sein.

Die borrow-Anweisung ruft verwendete Qubits ab, die von dem Zeitpunkt, an dem das Qubit gebunden ist, bis zur letzten Verwendung dieses Qubits garantiert nicht vom Programm verwendet werden. Wenn nicht genügend Qubits zum Ausleihen zur Verfügung stehen, werden die Qubits wie bei einer use-Anweisung vom Heap zugeordnet und wieder an diesen zurückgegeben.

Hinweis

Zu den bekannten Anwendungsfällen von schmutzigen Qubits gehören Implementierungen von multigesteuerten CNOT-Gattern, die sehr wenige Qubits benötigen, sowie Implementierungen von Inkrementierern. Die Arbeit zur Faktorisierung mit Qubits enthält ein Beispiel für einen Algorithmus mit geliehenen Qubits.