Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Comme indiqué plus en détail dans la description du type de données qubit , les calculs quantiques sont exécutés sous la forme d’effets secondaires d’opérations pris en charge en mode natif sur le processeur quantique ciblé. Il s’agit en fait des seuls effets secondaires dans Q#. Étant donné que tous les types sont immuables, aucun effet secondaire n’impacte une valeur qui est explicitement représentée dans Q#. Par conséquent, tant qu’une implémentation d’un certain appelant n’appelle pas directement ou indirectement l’une de ces opérations implémentées en mode natif, son exécution produit toujours la même sortie, en fonction de la même entrée.
Q# vous permet de fractionner explicitement ces calculs purement déterministes en fonctions . Étant donné que l’ensemble d’instructions prises en charge en mode natif n’est pas fixe et intégré au langage lui-même, mais plutôt entièrement configurable et exprimé en tant que bibliothèque Q#, le déterminisme est garanti en exigeant que les fonctions puissent appeler uniquement d’autres fonctions et ne peuvent pas appeler d’opérations. En outre, les instructions natives qui ne sont pas déterministes, c’est-à-dire parce qu’elles ont un impact sur l’état quantique, sont représentées en tant qu’opérations. Avec ces deux restrictions, les fonctions peuvent être évaluées dès que leur valeur d’entrée est connue et, en principe, ne doivent jamais être évaluées plusieurs fois pour la même entrée.
Q# distingue donc deux types de pouvant être appelées: opérations et fonctions. Tous les appelants acceptent un seul argument (potentiellement tuple-valued) comme entrée et produisent une valeur unique (tuple) comme sortie. Syntactiquement, le type d’opération est exprimé en tant que <TIn> => <TOut> is <Char>
, où <TIn>
doit être remplacé par le type d’argument, <TOut>
doit être remplacé par le type de retour, et <Char>
doit être remplacé par les caractéristiques de l’opération . Si aucune caractéristique n’a besoin d’être spécifiée, la syntaxe simplifie la <TIn> => <TOut>
. De même, les types de fonctions sont exprimés en tant que <TIn> -> <TOut>
.
En dehors de cette garantie déterminisme, il y a peu de différence entre les opérations et les fonctions. Les deux sont des valeurs de première classe qui peuvent être transmises librement ; ils peuvent être utilisés comme valeurs de retour ou arguments pour d’autres appelants, comme illustré dans l’exemple suivant :
function Pow<'T>(op : 'T => Unit, pow : Int) : 'T => Unit {
return PowImpl(op, pow, _);
}
Les deux peuvent être instanciés en fonction d’une définition paramétrable par type, par exemple, la fonction paramétrablePow
précédemment, et elles peuvent être partiellement appliquées comme fait dans l’instruction return
dans l’exemple.
Caractéristiques de l’opération
En plus des informations sur le type d’entrée et de sortie, le type d’opération contient des informations sur les caractéristiques d’une opération. Ces informations, par exemple, décrivent les fonctoraux pris en charge par l’opération. En outre, la représentation interne contient également des informations pertinentes sur l’optimisation qui sont déduites par le compilateur.
Les caractéristiques d’une opération sont un ensemble d’étiquettes prédéfinies et intégrées. Elles sont exprimées sous la forme d’une expression spéciale qui fait partie de la signature de type. L’expression se compose de l’un des ensembles prédéfinis d’étiquettes ou d’une combinaison d’expressions de caractéristiques via un opérateur binaire pris en charge.
Il existe deux ensembles prédéfinis, Adj
et Ctl
.
-
Adj
est l’ensemble qui contient une étiquette unique indiquant qu’une opération est adjoint, ce qui signifie qu’elle prend en charge le fonctorAdjoint
et que la transformation quantique appliquée peut être « annulée », c’est-à-dire qu’elle peut être inversée. -
Ctl
est l’ensemble qui contient une étiquette unique indiquant qu’une opération est contrôlable, ce qui signifie qu’elle prend en charge le fonctorControlled
et son exécution peut être conditionnée sur l’état d’autres qubits.
Les deux opérateurs pris en charge dans le cadre d’expressions de caractéristiques sont l’union définie +
et l’intersection définie *
.
Dans EBNF (extended Backus–Naur form),
predefined = "Adj" | "Ctl";
characteristics = predefined
| "(", characteristics, ")"
| characteristics ("+"|"*") characteristics;
Comme prévu, *
a une priorité plus élevée que +
et les deux sont associatifs de gauche. Le type d’une opération unitaire, par exemple, est exprimé en tant que <TIn> => <TOut> is Adj + Ctl
, où <TIn>
doit être remplacé par le type de l’argument d’opération, et <TOut>
remplacé par le type de la valeur retournée.
Remarque
L’indication des caractéristiques d’une opération de cette forme présente deux avantages majeurs ; pour une, de nouvelles étiquettes peuvent être introduites sans avoir de mots clés de langage exponentiellement pour toutes les combinaisons d’étiquettes. Plus important encore, l’utilisation d’expressions pour indiquer les caractéristiques d’une opération prend également en charge les paramétrages sur les caractéristiques d’opération à l’avenir.