Gestion de la mémoire quantique

Un programme commence toujours sans qubits, ce qui signifie que vous ne pouvez pas transmettre les valeurs de type Qubit en tant qu’arguments de point d’entrée. Cette restriction est intentionnelle, puisque le but de Q# est d’exprimer et de raisonner sur un programme dans son intégralité. Au lieu de cela, un programme alloue et libère des qubits ou de la mémoire quantique au fur et à mesure. À cet égard, Q# modélise l’ordinateur quantique en tant que segment de mémoire qubit.

Plutôt que de prendre en charge des instructions d’allocation et de libération distinctes pour la mémoire quantique, Q# prend en charge l’allocation de mémoire quantique sous forme d’instructions de bloc, où la mémoire est uniquement accessible dans le cadre de l’instruction de bloc. Le bloc d’instructions peut être implicitement défini lors de l’allocation de qubits pour la durée de l’étendue actuelle, comme cela est décrit plus en détail dans les sections relatives aux instructions use et borrow. Toute tentative d’accès aux qubits alloués après la fin de l’instruction entraîne une exception d’exécution.

Q# possède deux instructions, use et borrow, pour instancier des valeurs de qubits, des tableaux de qubits ou toute combinaison de ceux-ci. Vous pouvez utiliser ces instructions uniquement dans des opérations. Elles recueillent les valeurs de qubit instanciées, les lient aux variables spécifiées dans l’instruction, puis exécutent un bloc d’instructions. À la fin du bloc, les variables liées sont hors de portée et ne sont plus définies.

Q# fait la distinction entre l’allocation de qubits propres et non propres. Les qubits propres ne sont pas enchevêtrés et ne sont pas utilisés par une autre partie du calcul. Les qubits non propres sont des qubits dont l’état est inconnu et qui peuvent même être enchevêtrés avec d’autres parties de la mémoire du processeur quantique.

Instruction use

Les qubits propres sont alloués par l’instruction use.

  • L’instruction se compose du mot clé use suivi d’une liaison et d’un bloc d’instructions facultatif.
  • Si un bloc d’instructions est présent, les qubits sont uniquement disponibles dans ce bloc. Dans le cas contraire, les qubits sont disponibles jusqu’à la fin de la portée actuelle.
  • La liaison suit le même modèle que les instructions let : un symbole unique ou un tuple de symboles, suivi d’un signe égal =, et soit d’un tuple unique, soit d’un tuple correspondant d'initialiseurs.

Les initialiseurs sont disponibles pour un qubit unique, indiqué comme Qubit() , ou un tableau de qubits, Qubit[n] , où n est une expression Int. Par exemple,

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

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

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

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

Les qubits sont assurés d’être dans un état |0⟩ lors de l’allocation. Ils sont libérés à la fin de l’étendue et doivent être dans un état |0⟩ lors de la mise en production. Cette exigence n’est pas appliquée par le compilateur, car cela nécessiterait une évaluation symbolique qui s’avérerait vite excessivement coûteuse. Lors d’une exécution sur simulateurs, l’exigence peut être appliquée par le runtime. Sur les processeurs quantiques, l’exigence ne peut pas être appliquée au runtime. un qubit non mesuré peut être réinitialisé sur |0⟩ via une transformation unitaire. Dans le cas contraire, il en découle un comportement incorrect.

L’instruction use alloue les qubits à partir du segment de mémoire qubit libre du processeur quantique et les retourne au segment de mémoire au plus tard à la fin de la portée dans laquelle les qubits sont liés.

Instruction borrow

L’instruction borrow accorde l’accès aux qubits déjà alloués, mais qui ne sont pas en cours d’utilisation. Ces qubits peuvent être dans un état arbitraire et doivent être à nouveau dans le même état lorsque l’instruction borrow se termine. Certains algorithmes quantiques peuvent utiliser des qubits sans compter sur leur état exact et sans exiger qu’ils soient désenchevêtrés du reste du système. En d’autres termes, ils ont besoin temporairement de qubits supplémentaires, mais ils peuvent garantir que ces qubits reviendront exactement à leur état d’origine, quel qu’il soit.

Si des qubits sont utilisés mais restent inchangés durant les parties d’une sous-routine, ces qubits peuvent être empruntés pour être utilisés par un tel algorithme, sans qu’il soit nécessaire d’allouer de la mémoire quantique supplémentaire. Le fait d’emprunter plutôt que d’allouer permet de considérablement réduire les besoins globaux en mémoire quantique d’un algorithme, et constitue un exemple quantique d’un compromis espace-temps standard.

Une instruction borrow suit le même modèle que celui décrit précédemment pour l’instruction use, avec les mêmes initialiseurs disponibles. Par exemple,

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

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

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

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

Les qubits empruntés sont dans un état inconnu et hors de portée à la fin du bloc d’instructions. L’emprunteur s’engage à laisser les qubits dans l’état où ils se trouvaient quand ils ont été empruntés ; c’est-à-dire que leur état au début et à la fin du bloc d’instructions doit être le même.

L’instruction borrow permet de récupérer les qubits en cours d’utilisation dont la non-utilisation par le programme est garantie entre le moment où le qubit est lié et sa dernière utilisation. En l’absence de qubits suffisants à emprunter, les qubits sont alloués et renvoyés dans le segment de mémoire comme une instruction use.

Notes

Les cas d’utilisation connus des qubits non propres incluent les implémentations des portes CNOT multi-contrôlées qui nécessitent très peu de qubits, et les implémentations d’incrémenteurs. Cet article sur la factorisation avec des qubits fournit un exemple d’algorithme utilisant des qubits empruntés.