Expressions classiques
qiskit.circuit.classical
Ce module contient une représentation exploratoire des opérations en temps réel sur les valeurs classiques pendant l'exécution du circuit.
À l'heure actuelle, seules les expressions simples portant sur des bits et des registres et donnant lieu à une valeur booléenne sont prises en charge; celles-ci ne peuvent être utilisées que dans les conditions des opérateurs QuantumCircuit.if_test() (IfElseOp) et QuantumCircuit.while_loop() (WhileLoopOp), ainsi que dans l'argument de l'opérateur QuantumCircuit.switch() (SwitchCaseOp).
Il s'agit d'un module exploratoire, et bien que nous nous engagions à respecter la politique de dépréciation standard de Qiskit, sachez que la portée du module sera délibérément limitée au départ, et que les premières versions pourraient ne pas évoluer proprement vers la version finale. Il est possible que certains éléments de ce module soient remplacés (sous réserve de dépréciation) au lieu d'être améliorés sous une nouvelle forme.
Le système de types et l'arbre d'expressions seront étendus au fil du temps, et il est possible que les types autorisés de certaines opérations doivent changer entre les versions de Qiskit au fur et à mesure que les capacités de traitement classiques se développent.
Expressions
qiskit.circuit.classical.expr
Les composants nécessaires à la construction des expressions sont tous exportés de l'espace de noms expr dans l'espace de noms qiskit.circuit.classicalvous pouvez donc choisir d'utiliser l'accès qualifié (par exemple expr.Value) ou d'importer directement les noms dont vous avez besoin et de les appeler sans le préfixe.
Il existe deux façons de construire des expressions. Les classes qui forment la représentation du système d'expression ont des constructeurs qui n'effectuent aucune vérification de type; c'est à l'appelant de s'assurer qu'il construit des objets valides. Pour une interface plus conviviale de la construction directe, il existe des fonctions d'aide associées à la plupart des classes qui effectuent la validation et l'inférence de type. Ils sont décrits ci-dessous, dans la section Construction.
Représentation
Le système d'expression est basé sur une représentation arborescente. Tous les nœuds de l'arbre sont des instances finales (non héritables) de la classe de base abstraite :
Expr
class qiskit.circuit.classical.expr.Expr
Bases : object
Classe de base de tous les nœuds de l'arbre d'expression. Le cas de base ne doit jamais être instancié directement.
Elle ne doit pas être sous-classée par les utilisateurs; les sous-classes forment les données internes de la représentation des expressions et il n'est pas judicieux d'en ajouter en dehors du code de la bibliothèque Qiskit.
Toutes les sous-classes doivent définir leur type attribut dans leur __init__constructeur et ne doivent pas appeler le constructeur du parent.
Ces objets sont mutables et ne doivent pas être réutilisés à un autre endroit sans copie.
Toutes les instances Expr définissent un attribut booléen const , qui indique si l'expression peut être évaluée au moment de la compilation. La plupart des classes d'expressions le déduisent lors de la construction en se basant sur la constance de leurs opérandes.
La base des variables dynamiques est la variable Varqui peut être soit une variable temps réel arbitrairement typée, soit une enveloppe autour d'une variable de type Clbit ou ClassicalRegister.
Var
class qiskit.circuit.classical.expr.Var(var, type, *, name=None)
Bases : Expr
Une variable classique.
Ces variables se présentent sous deux formes : une variable de type nouveau qui possède son emplacement de stockage et un nom associé, et une variable de type ancien qui englobe une variable de type Clbit ou ClassicalRegister qui appartient à un circuit contenant. En général, la construction de variables destinées à être utilisées dans des programmes doit utiliser Var.new() ou QuantumCircuit.add_var().
Les variables sont immuables une fois créées; elles peuvent donc servir de clés dans un dictionnaire.
name
Nom de la variable. Cette variable doit exister si l'attribut backing var est de type UUIDnew-style, c'est-à-dire s'il s'agit d'une variable de style nouveau, et doit être None de type old-style s'il s'agit d'une variable de style ancien.
new
classmethod new(name, ty)
Générer une nouvelle variable nommée qui possède son propre stockage de sauvegarde.
var
Une référence au stockage de données de sauvegarde de Var l'instance. ClassicalRegisterLorsqu'on transfère des ClassicalRegister instances de Clbit type ancien vers un Var, il s'agit précisément du Clbit ou du. Si la variable est une variable classique de nouveau type (c'est-à-dire une variable disposant de sa propre mémoire, distincte de l'ancienne Clbit/ClassicalRegister modèle), ce champ contiendra un UUID identifiant unique permettant de l'identifier.
De même, les littéraux utilisés dans les expressions (tels que les entiers) doivent être élevés au rang de nœuds Value avec les types associés. A Value est toujours considérée comme une expression constante.
Valeur
Les variables d'étirement à utiliser dans les expressions de durée sont représentées par le nœud Stretch nœud.
Étirement
class qiskit.circuit.classical.expr.Stretch(var, name)
Bases : Expr
Une variable extensible.
En général, la construction de variables extensibles destinées à être utilisées dans des programmes devrait utiliser Stretch.new() ou QuantumCircuit.add_stretch()
name
Le nom de la variable d'étirement.
new
classmethod new(name)
Générer une nouvelle variable d'étirement nommée.
var
A UUID pour identifier de manière unique ce tronçon.
Les opérations traditionnellement associées aux opérateurs pré, post ou infixes dans la programmation sont représentées par les opérateurs Unary et Binary selon le cas. Chacun d'entre eux prend un code de type d'opération, qui est exposé sous forme d'énumérations à l'intérieur de chaque classe en tant que Unary.Op et Binary.Op respectivement.
Unaire
class qiskit.circuit.classical.expr.Unary(op, operand, type)
Bases : Expr
Une expression unaire.
Paramètres
- op - Le code d'opération décrivant l'opération en cours.
- operand - L'opérande de l'opération.
- type - Le type résolu du résultat.
Op
class Op(*values)
Bases : Enum
Enumération des opcodes pour les opérations unaires.
La négation bit à bit BIT_NOT prend un bit unique ou un entier non signé de largeur connue et renvoie une valeur du même type.
La négation logique LOGIC_NOT prend une entrée qui est implicitement transformée en booléen et renvoie un booléen.
La négation arithmétique NEGATE prend en entrée une valeur de type float ou duration et renvoie une valeur du même type.
Binaire
class qiskit.circuit.classical.expr.Binary(op, left, right, type)
Bases : Expr
Une expression binaire.
Paramètres
- op - Le code d'opération décrivant l'opération en cours.
- left - L'opérande de gauche.
- right - L'opérande de droite.
- type - Le type résolu du résultat.
Op
class Op(*values)
Bases : Enum
Enumération des opcodes pour les opérations binaires.
Les opérations bit à bit BIT_AND, BIT_OR et BIT_XOR s'appliquent à deux opérandes de même type, qui doivent être un bit unique ou un entier non signé de largeur fixe. Le type résultant est le même que les deux types d'entrée.
Les opérations logiques LOGIC_AND et LOGIC_OR contraignent d'abord implicitement leurs arguments à être des booléens, puis appliquent l'opération logique. Le type résultant est toujours booléen.
Les relations mathématiques binaires EQUAL, NOT_EQUAL, LESS, LESS_EQUAL, GREATER et GREATER_EQUAL prennent des entiers non signés (avec une conversion implicite pour qu'ils aient la même largeur) et renvoient un booléen.
Les opérations de décalage de bits SHIFT_LEFT et SHIFT_RIGHT peuvent prendre des types de conteneurs de type bit (par exemple, des entiers non signés) comme opérande de gauche, et n'importe quel type d'entier comme opérande de droite. Dans tous les cas, la largeur du bit de sortie est la même que celle de l'entrée, et les zéros remplissent les espaces "exposés".
Les opérateurs arithmétiques ADD binaires, SUB, MUL, et DIV peuvent être appliqués à deux nombres à virgule flottante ou à deux entiers non signés, qui doivent être mis à la même largeur lors de leur création à l'aide d'un transtypage. Les DIV opérateurs ADD, SUB, et peuvent être appliqués à deux durées pour donner une autre durée, ou un nombre à virgule flottante dans le cas de DIV. L'opérateur MUL peut également être appliqué à une durée et à un type numérique, ce qui donne une autre durée. Enfin, DIV l'opérateur peut être utilisé pour diviser une durée par un nombre, ce qui donne une durée.
Les types de type bit (entiers non signés) peuvent être indexés par des types entiers, représentés par Index. Le résultat est un seul bit. L'expression résultante a un emplacement mémoire associé (et peut donc être utilisée comme valeur l pour Storeetc.) si la cible est également une valeur l.
Indice
class qiskit.circuit.classical.expr.Index(target, index, type)
Bases : Expr
Une expression d'indexation.
Paramètres
- target - L'objet à indexer.
- index - L'expression qui effectue l'indexation.
- type - Le type résolu du résultat.
Lors de la construction d'expressions, il faut s'assurer que les types sont valides pour l'opération. Les tentatives de construction d'expressions avec des types non valides entraîneront l'apparition d'une erreur régulière Python TypeError.
Dans ce système, les expressions sont définies de manière à n'agir que sur certains ensembles de types. Toutefois, les valeurs peuvent être moulées dans un super-type approprié afin de satisfaire aux exigences de typage. Dans ce cas, un nœud de l'arbre d'expression est utilisé pour représenter la promotion. Dans tous les cas où les opérations indiquent qu'elles "moulent implicitement" ou "contraignent" leurs arguments, l'arbre d'expression doit comporter ce nœud représentant la conversion.
cast
class qiskit.circuit.classical.expr.Cast(operand, type, implicit=False)
Bases : Expr
Une conversion d'un type à un autre, impliquée par l'utilisation d'une expression dans un contexte différent.
Construction
La construction directe de la représentation de l'arbre est fastidieuse et il est facile de faire une erreur de typage. Dans de nombreux cas, une grande partie du typage peut être déduite, les valeurs scalaires peuvent être automatiquement promues en instances, et toutes les promotions nécessaires peuvent être résolues en instances appropriées Value instances, et toutes les promotions nécessaires peuvent être résolues en nœuds Cast appropriés.
Les fonctions et méthodes décrites dans cette section constituent une manière plus conviviale de construire l'arbre d'expression, tout en restant proche de la représentation interne. Toutes ces fonctions transforment automatiquement les valeurs scalaires valides de Python en valeurs correspondantes de Var ou Value correspondants, et résoudront toute conversion implicite nécessaire en votre nom. Si vous souhaitez utiliser directement une valeur scalaire en tant que nœud Expr vous pouvez le faire manuellement lift() manuellement.
lift
qiskit.circuit.classical.expr.lift(value, /, type=None)
Soulevez le site Python value jusqu'à ce qu'il atteigne le niveau Value ou Var.
Si un type explicite est donné, le typage dans la sortie le reflétera.
Exemples
Transformer des objets de circuits simples en Var instances :
>>> from qiskit.circuit import Clbit, ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.lift(Clbit())
Var(<clbit>, Bool())
>>> expr.lift(ClassicalRegister(3, "c"))
Var(ClassicalRegister(3, "c"), Uint(3))Le type de la valeur renvoyée peut être modifié si la valeur fournie peut être interprétée sans perte comme étant du type spécifié (utilisez cast() pour effectuer l'ensemble complet des opérations de conversion, y compris celles entraînant une perte) :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr, types
>>> expr.lift(ClassicalRegister(3, "c"), types.Uint(5))
Var(ClassicalRegister(3, "c"), Uint(5))
>>> expr.lift(5, types.Uint(4))
Value(5, Uint(4))Paramètres
Type de retour
En règle générale, vous devez créer des instances Var en utilisant la méthode QuantumCircuit.add_var() pour les déclarer dans un contexte de circuit, car une méthode QuantumCircuit n'acceptera pas un Expr qui contient des variables qui ne sont pas déjà déclarées en son sein, car il doit savoir comment allouer la mémoire et comment la variable sera initialisée. Toutefois, si vous souhaitez le faire manuellement, vous devez utiliser l'appel de bas niveau Var.new() pour générer en toute sécurité une variable nommée à utiliser.
Vous pouvez spécifier manuellement les casts dans les cas où le cast est autorisé sous forme explicite, mais peut être avec perte (comme le cast d'une précision plus élevée Uint vers un autre de moindre précision).
cast
qiskit.circuit.classical.expr.cast(operand, type, /)
Créer un cast explicite de la valeur donnée vers le type donné.
Exemples
Ajout d'un nœud de conversion explicite qui convertit explicitement un type de précision supérieure en un type de précision inférieure :
>>> from qiskit.circuit.classical import expr, types
>>> value = expr.value(5, types.Uint(32))
>>> expr.cast(value, types.Uint(8))
Cast(Value(5, types.Uint(32)), types.Uint(8), implicit=False)Paramètres
Type de retour
Il existe des fonctions d'aide à la construction pour chacune des opérations unaires.
bit_not
qiskit.circuit.classical.expr.bit_not(operand, /)
Crée un nœud d'expression bitwise "not" à partir de la valeur donnée, en résolvant toute conversion implicite et en élevant la valeur dans un nœud "not" si nécessaire Value si nécessaire.
Exemples
Négation bit à bit de a ClassicalRegister:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.bit_not(ClassicalRegister(3, "c"))
Unary(Unary.Op.BIT_NOT, Var(ClassicalRegister(3, 'c'), Uint(3)), Uint(3))Paramètres
operand (Any)
Type de retour
logic_not
qiskit.circuit.classical.expr.logic_not(operand, /)
Crée un nœud d'expression logique "not" à partir de la valeur donnée, en résolvant toute conversion implicite et en élevant la valeur dans un nœud "not" si nécessaire Value si nécessaire.
Exemples
Négation logique de a ClassicalRegister:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.logic_not(ClassicalRegister(3, "c"))
Unary(Unary.Op.LOGIC_NOT, Cast(Var(ClassicalRegister(3, 'c'), Uint(3)), Bool(), implicit=True), Bool())Paramètres
operand (Any)
Type de retour
negate
qiskit.circuit.classical.expr.negate(operand, /)
Négation d'un nœud d'expression à partir de la valeur fournie, en effectuant les conversions implicites nécessaires et en transformant la valeur en un Value nœud si nécessaire.
Exemples
Négation d'un nombre à virgule flottante :
>>> from qiskit.circuit.classical import expr
>>> expr.negate(5.0)
Unary(Unary.Op.NEGATE, Value(5.0, Float()), Float())Négation d'une durée :
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.negate(Duration.dt(1000))
Unary(Unary.Op.NEGATE, Value(Duration.dt(1000), Duration()), Duration())Paramètres
operand (Any)
Type de retour
De même, des fonctions d'aide sont définies pour les opérations binaires et les relations.
bit_and
qiskit.circuit.classical.expr.bit_and(left, right, /)
Crée un nœud d'expression binaire "et" à partir de la valeur donnée, en résolvant toute conversion implicite et en élevant les valeurs dans des nœuds "et" si nécessaire Value si nécessaire.
Exemples
La combinaison "et" d'un registre classique et d'un entier littéral :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.bit_and(ClassicalRegister(3, "c"), 0b111)
Binary(Binary.Op.BIT_AND, Var(ClassicalRegister(3, 'c'), Uint(3)), Value(7, Uint(3)), Uint(3))Paramètres
Type de retour
bit_or
qiskit.circuit.classical.expr.bit_or(left, right, /)
Crée un nœud d'expression binaire "ou" à partir de la valeur donnée, en résolvant toute conversion implicite et en élevant les valeurs dans des nœuds "ou" si nécessaire Value si nécessaire.
Exemples
Ou binaire d'un registre classique et d'un littéral d'entier :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.bit_or(ClassicalRegister(3, "c"), 0b101)
Binary(Binary.Op.BIT_OR, Var(ClassicalRegister(3, 'c'), Uint(3)), Value(5, Uint(3)), Uint(3))Paramètres
Type de retour
bit_xor
qiskit.circuit.classical.expr.bit_xor(left, right, /)
Crée un nœud d'expression binaire "exclusif ou" à partir de la valeur donnée, en résolvant toute conversion implicite et en élevant les valeurs en nœuds Value si nécessaire.
Exemples
Ou exclusif bit à bit d'un registre classique et d'un entier littéral :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.bit_xor(ClassicalRegister(3, "c"), 0b101)
Binary(Binary.Op.BIT_XOR, Var(ClassicalRegister(3, 'c'), Uint(3)), Value(5, Uint(3)), Uint(3))Paramètres
Type de retour
logic_and
qiskit.circuit.classical.expr.logic_and(left, right, /)
Crée un nœud d'expression logique "et" à partir de la valeur donnée, en résolvant toute conversion implicite et en élevant les valeurs dans des nœuds "et" si nécessaire Value si nécessaire.
Exemples
Le "et" logique de deux bits classiques :
>>> from qiskit.circuit import Clbit
>>> from qiskit.circuit.classical import expr
>>> expr.logic_and(Clbit(), Clbit())
Binary(Binary.Op.LOGIC_AND, Var(<clbit 0>, Bool()), Var(<clbit 1>, Bool()), Bool())Paramètres
Type de retour
logic_or
qiskit.circuit.classical.expr.logic_or(left, right, /)
Crée un nœud d'expression logique "ou" à partir de la valeur donnée, en résolvant toute conversion implicite et en élevant les valeurs en nœuds "ou" si nécessaire Value si nécessaire.
Exemples
Ou logique de deux bits classiques
>>> from qiskit.circuit import Clbit
>>> from qiskit.circuit.classical import expr
>>> expr.logic_or(Clbit(), Clbit())
Binary(Binary.Op.LOGIC_OR, Var(<clbit 0>, Bool()), Var(<clbit 1>, Bool()), Bool())Paramètres
Type de retour
equal
qiskit.circuit.classical.expr.equal(left, right, /)
Crée un nœud d'expression "égal" à partir de la valeur donnée, en résolvant toute conversion implicite et en transformant les valeurs en nœuds Value si nécessaire.
Exemples
Égalité entre un registre classique et un nombre entier :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.equal(ClassicalRegister(3, "c"), 7)
Binary(Binary.Op.EQUAL, Var(ClassicalRegister(3, "c"), Uint(3)), Value(7, Uint(3)), Uint(3))Paramètres
Type de retour
not_equal
qiskit.circuit.classical.expr.not_equal(left, right, /)
Crée un nœud d'expression "pas égal" à partir de la valeur donnée, en résolvant toute conversion implicite et en transformant les valeurs en nœuds Value si nécessaire.
Exemples
Inégalité entre un registre classique et un nombre entier :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.not_equal(ClassicalRegister(3, "c"), 7)
Binary(Binary.Op.NOT_EQUAL, Var(ClassicalRegister(3, "c"), Uint(3)), Value(7, Uint(3)), Uint(3))Paramètres
Type de retour
less
qiskit.circuit.classical.expr.less(left, right, /)
Crée un nœud d'expression "moins que" à partir de la valeur donnée, en résolvant toute conversion implicite et en élevant les valeurs en nœuds Value si nécessaire.
Exemples
Demande si un registre classique est inférieur à un entier :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.less(ClassicalRegister(3, "c"), 5)
Binary(Binary.Op.LESS, Var(ClassicalRegister(3, "c"), Uint(3)), Value(5, Uint(3)), Uint(3))Paramètres
Type de retour
less_equal
qiskit.circuit.classical.expr.less_equal(left, right, /)
Crée un nœud d'expression "inférieur ou égal à" à partir de la valeur donnée, en résolvant toute conversion implicite et en élevant les valeurs dans les nœuds Value si nécessaire.
Exemples
Demande si un registre classique est inférieur ou égal à un autre :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.less_equal(ClassicalRegister(3, "a"), ClassicalRegister(3, "b"))
Binary(Binary.Op.LESS_EQUAL, Var(ClassicalRegister(3, "a"), Uint(3)), Var(ClassicalRegister(3, "b"), Uint(3)), Uint(3))Paramètres
Type de retour
greater
qiskit.circuit.classical.expr.greater(left, right, /)
Crée un nœud d'expression "plus grand que" à partir de la valeur donnée, en résolvant toute conversion implicite et en élevant les valeurs dans les nœuds Value si nécessaire.
Exemples
Demande si un registre classique est supérieur à un entier :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.greater(ClassicalRegister(3, "c"), 5)
Binary(Binary.Op.GREATER, Var(ClassicalRegister(3, "c"), Uint(3)), Value(5, Uint(3)), Uint(3))Paramètres
Type de retour
greater_equal
qiskit.circuit.classical.expr.greater_equal(left, right, /)
Crée un nœud d'expression "supérieur ou égal à" à partir de la valeur donnée, en résolvant toute conversion implicite et en élevant les valeurs dans les nœuds Value si nécessaire.
Exemples
Demande si un registre classique est supérieur ou égal à un autre :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.greater_equal(ClassicalRegister(3, "a"), ClassicalRegister(3, "b"))
Binary(Binary.Op.GREATER_EQUAL, Var(ClassicalRegister(3, "a"), Uint(3)), Var(ClassicalRegister(3, "b"), Uint(3)), Uint(3))Paramètres
Type de retour
shift_left
qiskit.circuit.classical.expr.shift_left(left, right, /, type=None)
Créer un nœud d'expression "bitshift left" à partir des deux valeurs données, en résolvant toute conversion implicite et en élevant les valeurs en nœuds Value si nécessaire.
Si type est donné, l'opérande left lui sera imposé (si possible).
Exemples
Déplacer la valeur d'une variable autonome vers la gauche d'un certain montant :
>>> from qiskit.circuit.classical import expr, types
>>> a = expr.Var.new("a", types.Uint(8))
>>> expr.shift_left(a, 4)
Binary(Binary.Op.SHIFT_LEFT, Var(<UUID>, Uint(8), name='a'), Value(4, Uint(3)), Uint(8))Décale un littéral entier d'une valeur variable, en imposant le type du littéral :
>>> expr.shift_left(3, a, types.Uint(16))
Binary(Binary.Op.SHIFT_LEFT, Value(3, Uint(16)), Var(<UUID>, Uint(8), name='a'), Uint(16))Paramètres
Type de retour
shift_right
qiskit.circuit.classical.expr.shift_right(left, right, /, type=None)
Crée un nœud d'expression "bitshift right" à partir des valeurs données, en résolvant toute conversion implicite et en élevant les valeurs en nœuds Value si nécessaire.
Si type est donné, l'opérande left lui sera imposé (si possible).
Exemples
Décaler la valeur d'un registre classique vers la droite d'un certain montant :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.shift_right(ClassicalRegister(8, "a"), 4)
Binary(Binary.Op.SHIFT_RIGHT, Var(ClassicalRegister(8, "a"), Uint(8)), Value(4, Uint(3)), Uint(8))Paramètres
Type de retour
add
qiskit.circuit.classical.expr.add(left, right, /)
Crée un nœud d'expression d'addition à partir des valeurs données, en résolvant toute conversion implicite et en transformant les valeurs en nœuds Value si nécessaire.
Exemples
Addition de deux nombres à virgule flottante :
>>> from qiskit.circuit.classical import expr
>>> expr.add(5.0, 2.0)
Binary(Binary.Op.ADD, Value(5.0, Float()), Value(2.0, Float()), Float())Ajout de deux durées :
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.add(Duration.dt(1000), Duration.dt(1000))
Binary(Binary.Op.ADD, Value(Duration.dt(1000), Duration()), Value(Duration.dt(1000), Duration()), Duration())Paramètres
Type de retour
sub
qiskit.circuit.classical.expr.sub(left, right, /)
Crée un nœud d'expression de soustraction à partir des valeurs données, en résolvant toute conversion implicite et en transformant les valeurs en nœuds Value si nécessaire.
Exemples
Soustraction de deux nombres à virgule flottante :
>>> from qiskit.circuit.classical import expr
>>> expr.sub(5.0, 2.0)
Binary(Binary.Op.SUB, Value(5.0, Float()), Value(2.0, Float()), Float())Soustraction de deux durées :
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.add(Duration.dt(1000), Duration.dt(1000))
Binary(Binary.Op.SUB, Value(Duration.dt(1000), Duration()), Value(Duration.dt(1000), Duration()), Duration())Paramètres
Type de retour
mul
qiskit.circuit.classical.expr.mul(left, right)
Crée un nœud d'expression de multiplication à partir des valeurs données, en résolvant toute conversion implicite et en transformant les valeurs en nœuds Value si nécessaire.
Cette fonction peut être utilisée pour multiplier des opérandes numériques du même type, ou pour multiplier un opérande de durée par un opérande numérique.
Exemples
Multiplication de deux nombres à virgule flottante :
>>> from qiskit.circuit.classical import expr
>>> expr.mul(5.0, 2.0)
Binary(Binary.Op.MUL, Value(5.0, Float()), Value(2.0, Float()), Float())Multiplication d'une durée par un flottant :
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.mul(Duration.dt(1000), 0.5)
Binary(Binary.Op.MUL, Value(Duration.dt(1000), Duration()), Value(0.5, Float()), Duration())Paramètres
Type de retour
div
qiskit.circuit.classical.expr.div(left, right)
Crée un nœud d'expression de division à partir des valeurs données, en résolvant toute conversion implicite et en transformant les valeurs en nœuds Value si nécessaire.
Cette fonction peut être utilisée pour diviser des opérandes numériques du même type, pour diviser un opérande par un opérande numérique ou pour diviser deux opérandes numériques Duration par un opérande numérique, ou pour diviser deux opérandes Duration ce qui donne une expression de type Float.
Exemples
Division de deux nombres à virgule flottante :
>>> from qiskit.circuit.classical import expr
>>> expr.div(5.0, 2.0)
Binary(Binary.Op.DIV, Value(5.0, Float()), Value(2.0, Float()), Float())Division de deux durées :
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.div(Duration.dt(10000), Duration.dt(1000))
Binary(Binary.Op.DIV, Value(Duration.dt(10000), Duration()), Value(Duration.dt(1000), Duration()), Float())Division d'une durée par un flotteur :
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.div(Duration.dt(10000), 12.0)
Binary(Binary.Op.DIV, Value(Duration.dt(10000), Duration()), Value(12.0, types.Float()), Duration())Paramètres
Type de retour
Vous pouvez indexer des nombres entiers non signés et des nombres binaires en utilisant un autre nombre entier non signé de n'importe quelle largeur. Cela inclut les opérations de stockage, si la cible de l'index est accessible en écriture.
index
qiskit.circuit.classical.expr.index(target, index, /)
Indexer le site target avec l'entier donné index, en élevant les valeurs en nœuds si nécessaire Value si nécessaire.
Elle peut être utilisée comme cible d'un Storesi l'adresse target est elle-même une valeur l.
Exemples
Indexation d'un registre classique avec un littéral :
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.index(ClassicalRegister(8, "a"), 3)
Index(Var(ClassicalRegister(8, "a"), Uint(8)), Value(3, Uint(2)), Bool())Paramètres
Type de retour
La méthode traditionnelle de Qiskit pour spécifier des conditions d'égalité à utiliser dans les conditionnelles est d'utiliser un double-tuple de a Clbit ou ClassicalRegister et d'un entier. Il s'agit d'une condition d'égalité exacte et il n'y a aucune possibilité de spécifier d'autres relations. La fonction d'aide lift_legacy_condition() convertit cet ancien format en la nouvelle syntaxe d'expression.
lift_legacy_condition
qiskit.circuit.classical.expr.lift_legacy_condition(condition, /)
Transformer une ancienne condition d'égalité de deux tuple en une condition de nouveau style Expr.
Paramètres
condition (tuple[qiskit.circuit.Clbit |qiskit.circuit.ClassicalRegister, int])
Type de retour
Travailler avec l'arbre d'expression
Un consommateur typique de l'arbre d'expression souhaite parcourir l'arbre de manière récursive, potentiellement avec état, en agissant sur chaque nœud différemment en fonction de son type. Il s'agit naturellement d'un problème de double répartition; la logique de "ce qui doit être fait" est vraisemblablement étatique et les utilisateurs devraient être libres de définir leurs propres opérations, alors que chaque nœud définit "ce sur quoi on agit". Nous permettons cette double distribution en fournissant une classe de visiteurs de base pour l'arbre d'expression.
ExprVisitor
class qiskit.circuit.classical.expr.ExprVisitor
Bases : Generic[_T_co]
Classe de base pour les visiteurs de l'arbre Expr l'arbre. Les sous-classes doivent surcharger les méthodes visit_* qu'elles sont en mesure de gérer et doivent être organisées de manière à ce que les méthodes inexistantes ne soient jamais appelées.
visit_binary
visit_cast
visit_generic
visit_index
visit_stretch
visit_unary
visit_value
visit_var
Les consommateurs de l'arbre d'expression doivent sous-classer le visiteur et surcharger les méthodes visit_* qu'ils souhaitent utiliser. Toute méthode non surchargée appellera visit_generic()qui, si elle n'est pas surchargée, lèvera un RuntimeError pour s'assurer que vous savez si de nouveaux nœuds ont été ajoutés à l'arbre d'expression que vous n'êtes pas encore en train de traiter.
Pour la commodité des visiteurs simples qui n'ont besoin que d'inspecter les variables d'une expression et non la structure générale, la méthode de l'itérateur iter_vars() est fournie.
iter_vars
qiskit.circuit.classical.expr.iter_vars(node)
Obtenir un itérateur sur les Var référencés à n'importe quel niveau dans le fichier Expr.
Exemples
Imprimez le nom de chaque ClassicalRegister rencontré :
from qiskit.circuit import ClassicalRegister
from qiskit.circuit.classical import expr
cr1 = ClassicalRegister(3, "a")
cr2 = ClassicalRegister(3, "b")
for node in expr.iter_vars(expr.bit_and(expr.bit_not(cr1), cr2)):
if isinstance(node.var, ClassicalRegister):
print(node.var.name)Paramètres
node (Expr)
Type de retour
Pour itérer sur toutes les variables, y compris les variables extensibles, la méthode iterator iter_identifiers() est fournie.
iter_identifiers
qiskit.circuit.classical.expr.iter_identifiers(node)
Obtenir un itérateur sur les éléments Var et Stretch référencés à n'importe quel niveau dans l'élément Expr.
Exemples
Imprimez le nom de chaque ClassicalRegister rencontré :
from qiskit.circuit import ClassicalRegister
from qiskit.circuit.classical import expr
cr1 = ClassicalRegister(3, "a")
cr2 = ClassicalRegister(3, "b")
for node in expr.iter_vars(expr.bit_and(expr.bit_not(cr1), cr2)):
if isinstance(node.var, ClassicalRegister):
print(node.var.name)Obtenir un itérateur sur les nœuds de l'expression Var de l'expression.
Paramètres
node (Expr)
Type de retour
Deux expressions peuvent être comparées pour une égalité structurelle directe en utilisant l'opérateur intégré Python == . En général, cependant, on peut vouloir comparer deux expressions de manière un peu plus sémantique, en permettant que les nœuds qu'elles contiennent soient liés à des descriptions différentes de l'emplacement de la mémoire entre deux circuits différents Var à l'intérieur de ces expressions soient liés à des descriptions différentes de l'emplacement de la mémoire entre deux circuits différents. Dans ce cas, on peut utiliser structurally_equivalent() avec deux fonctions "clés" appropriées pour effectuer la comparaison.
structurally_equivalent
qiskit.circuit.classical.expr.structurally_equivalent(left, right, left_var_key=None, right_var_key=None)
Ces deux expressions ont-elles exactement la même structure arborescente, jusqu'à une fonction clé pour les Var ?
En d'autres termes, ces deux expressions sont-elles exactement les mêmes arbres, si ce n'est que nous comparons les champs en appelant la fonction appropriée sur eux, et en comparant la sortie pour l'égalité Var.var en appelant la fonction *_var_key appropriée et en comparant les résultats pour vérifier l'égalité. Cette fonction n'autorise aucune "équivalence" sémantique telle que l'affirmation que a == b est équivalent à b == a; l'ordre d'évaluation des opérandes pourrait, en général, rendre une telle affirmation fausse (considérons les fonctions hypothétiques de extern qui accèdent à l'état global).
Les fonctions clés ne sont soumises à aucune exigence, si ce n'est que leurs résultats doivent être assortis de méthodes générales __eq__ . Si une fonction clé renvoie None, la variable sera utilisée mot pour mot.
Paramètres
- left (Expr) – l'un des
Exprnœuds. - right (Expr) – l'autre
Exprnœud. - left_var_key (Callable[[Any], Any] | None) – un appel dont la sortie doit être utilisée lors de la comparaison des
Var.varattributs. Si cet argument estNoneou si sa sortie estNonepour une variable donnée dansleft, la variable sera utilisée mot pour mot. - right_var_key (Callable[[Any], Any] | None) – identique à
left_var_key, mais utilisé pour les variables deright.
Type de retour
Exemples
Comparaison de deux expressions pour l'équivalence structurelle, sans remappage des variables. Elles sont différentes parce que les différentes instances se comparent différemment Clbit comparent différemment :
>>> from qiskit.circuit import Clbit
>>> from qiskit.circuit.classical import expr
>>> left_bits = [Clbit(), Clbit()]
>>> right_bits = [Clbit(), Clbit()]
>>> left = expr.logic_and(expr.logic_not(left_bits[0]), left_bits[1])
>>> right = expr.logic_and(expr.logic_not(right_bits[0]), right_bits[1])
>>> expr.structurally_equivalent(left, right)
FalseComparaison des deux mêmes expressions, mais cette fois en utilisant des fonctions de correspondance qui associent les bits à de simples indices :
>>> left_key = {var: i for i, var in enumerate(left_bits)}.get
>>> right_key = {var: i for i, var in enumerate(right_bits)}.get
>>> expr.structurally_equivalent(left, right, left_key, right_key)
TrueCertaines expressions ont des emplacements de mémoire associés, d'autres peuvent être purement temporaires. Vous pouvez utiliser is_lvalue() pour déterminer si une expression est associée à un emplacement mémoire.
is_lvalue
qiskit.circuit.classical.expr.is_lvalue(node, /)
Retourne si cette expression peut être utilisée dans des positions de valeur l, c'est-à-dire si elle a un emplacement bien défini dans la mémoire, par exemple un emplacement qui pourrait être accessible en écriture.
Le fait qu'il s'agisse d'une valeur de type l est une condition nécessaire mais non suffisante pour que cet emplacement soit accessible en écriture; il est possible qu'un objet plus grand contenant cet emplacement mémoire n'autorise pas l'écriture depuis la portée qui tente d'y écrire. Il s'agirait toutefois d'une propriété d'accès du programme hôte, et non d'une propriété inhérente au système d'expression.
Une expression constante n'est jamais une valeur l.
Exemples
Les valeurs littérales ne sont jamais des valeurs l; aucun emplacement mémoire n'est associé (par exemple) à la constante 1:
>>> from qiskit.circuit.classical import expr
>>> expr.is_lvalue(expr.lift(2))
FalseVar sont toujours des valeurs l, car ils ont toujours un emplacement mémoire associé :
>>> from qiskit.circuit.classical import types
>>> from qiskit.circuit import Clbit
>>> expr.is_lvalue(expr.Var.new("a", types.Bool()))
True
>>> expr.is_lvalue(expr.lift(Clbit()))
TrueActuellement, il n'existe pas d'opérations unaires ou binaires sur les variables qui puissent produire une expression de valeur l, mais il est probable qu'à l'avenir, une sorte d'opération d'"indexation" sera ajoutée, qui pourrait produire des valeurs l :
>>> a = expr.Var.new("a", types.Uint(8))
>>> b = expr.Var.new("b", types.Uint(8))
>>> expr.is_lvalue(a) and expr.is_lvalue(b)
True
>>> expr.is_lvalue(expr.bit_and(a, b))
FalseParamètres
node (Expr)
Type de retour
saisie
qiskit.circuit.classical.types
Représentation
Le système de type de l'arbre d'expression est exposé à travers ce module. Ceci est intrinsèquement lié au système d'expression du module expr car la plupart des expressions ne peuvent être comprises que dans le contexte des types sur lesquels elles agissent.
Tous les types héritent d'une classe de base abstraite :
Type
class qiskit.circuit.classical.types.Type
Bases : object
Classe de base de tous les nœuds de l'arbre des types. Le cas de base ne doit jamais être instancié directement.
Elle ne doit pas être sous-classée par les utilisateurs; les sous-classes forment les données internes de la représentation des expressions et il n'est pas judicieux d'en ajouter en dehors du code de la bibliothèque Qiskit.
Les types doivent être considérés comme des objets immuables et ne doivent pas être modifiés. Il est permis de réutiliser un Type provenant d'un autre objet sans le copier, et c'est généralement la meilleure approche en termes de performances. Type sont conçus pour être de petites quantités de données, et il est préférable de pointer vers la même instance de données lorsque c'est possible plutôt que d'allouer une nouvelle version de la même chose. Dans la mesure du possible, les constructeurs de la classe renvoient des instances singleton pour faciliter cette opération.
Le type Bool représente Clbit et les littéraux True et False, le type Uint représente ClassicalRegister et Python les entiers, le type Float représente Python flottants, et le type Duration représente une durée à utiliser dans les opérations de circuit tenant compte du temps.
Bool
class qiskit.circuit.classical.types.Bool
Bases : Type
Le type booléen. Celui-ci a exactement deux valeurs : True et False.
Uint
class qiskit.circuit.classical.types.Uint(width)
Bases : Type
Un entier non signé d'une largeur de bit fixe.
Flottant
class qiskit.circuit.classical.types.Float
Bases : Type
Un nombre à virgule flottante à double précision IEEE-754.
À l'avenir, il pourra également être utilisé pour représenter d'autres valeurs flottantes de largeur fixe.
Durée
Travailler avec les types
Certaines fonctions supplémentaires de ces types sont documentées dans les sections suivantes. Les utilisateurs qui construisent des expressions à l'aide de l' interface de construction orientée vers l'utilisateur ne devraient pas avoir besoin de les utiliser.
Ordre partiel des types
Le système de types est doté d'un ordre partiel, où est interprété comme " est un sous-type strict de ". Notez que l'ordre partiel est un sous-ensemble du graphe orienté qui décrit les opérations de distribution explicites autorisées entre les types. L'ordre partiel définit quand un type peut être interprété directement sans perte comme un autre.
L'interface de bas niveau permettant d'interroger la relation de sous-typage est la fonction order() fonction.
order
qiskit.circuit.classical.types.order(left, right, /)
Obtenir la relation d'ordre entre les deux types sous la forme d'une énumération.
Exemples
Comparez deux Uint types de largeur différente :
>>> from qiskit.circuit.classical import types
>>> types.order(types.Uint(8), types.Uint(16))
Ordering.LESSComparez deux types qui n'ont pas d'ordre entre eux :
>>> types.order(types.Uint(8), types.Bool())
Ordering.NONEParamètres
Type de retour
La valeur de retour est une énumération Ordering qui décrit, le cas échéant, la relation de sous-typage existant entre les deux types.
Ordre
class qiskit.circuit.classical.types.Ordering(*values)
Bases : Enum
Enumération des relations possibles entre deux types. Les types n'ont qu'un ordre partiel, il est donc possible que deux types n'aient aucune relation de sous-typage.
Il convient de noter que la relation sous-/supériorité n'est pas la même que la possibilité de faire passer explicitement un type d'un type à l'autre.
Certaines méthodes d'aide sont ensuite définies en fonction de cette primitive de bas niveau order() de bas niveau :
is_subtype
qiskit.circuit.classical.types.is_subtype(left, right, /, strict=False)
La relation est-elle valable? S'il n'y a pas de relation d'ordre entre les deux types, cette méthode renvoie False. Si strict, l'égalité est également interdite.
Exemples
Vérifier si un type est une sous-classe d'un autre :
>>> from qiskit.circuit.classical import types
>>> types.is_subtype(types.Uint(8), types.Uint(16))
TrueVérifier si un type est une sous-classe stricte d'un autre :
>>> types.is_subtype(types.Bool(), types.Bool())
True
>>> types.is_subtype(types.Bool(), types.Bool(), strict=True)
FalseParamètres
Type de retour
is_supertype
qiskit.circuit.classical.types.is_supertype(left, right, /, strict=False)
La relation est-elle valable? S'il n'y a pas de relation d'ordre entre les deux types, cette méthode renvoie False. Si strict, l'égalité est également interdite.
Exemples
Vérifier si un type est une superclasse d'un autre :
>>> from qiskit.circuit.classical import types
>>> types.is_supertype(types.Uint(8), types.Uint(16))
FalseVérifier si un type est une superclasse stricte d'un autre :
>>> types.is_supertype(types.Bool(), types.Bool())
True
>>> types.is_supertype(types.Bool(), types.Bool(), strict=True)
FalseParamètres
Type de retour
greater
qiskit.circuit.classical.types.greater(left, right, /)
Obtenir le plus grand des deux types, en supposant qu'il existe une relation d'ordre entre eux. Techniquement, il s'agit d'une version légèrement restreinte du concept de "rencontre" des deux types en ce sens que la valeur de retour doit être l'une des entrées. En pratique, dans le système de types, il n'existe pas de concept de type "somme", de sorte que la "rencontre" existe si et seulement s'il existe un ordre entre les deux types, et qu'elle est égale au plus grand des deux types.
Retours
Le plus grand des deux types.
Augmentations
TypeError - s'il n'y a pas de relation d'ordre entre les deux types.
Paramètres
Type de retour
Exemples
Trouver le plus grand de deux Uint types :
>>> from qiskit.circuit.classical import types
>>> types.greater(types.Uint(8), types.Uint(16))
types.Uint(16)Conversion entre types
Il est fréquent de devoir convertir des valeurs d'un type en valeurs d'un autre type. Les règles de distribution sont intégrées dans le module types module. Vous pouvez interroger les types de moulage à l'aide de cast_kind():
cast_kind
qiskit.circuit.classical.types.cast_kind(from_, to_, /)
Déterminez le type de moulage nécessaire pour passer du type gauche au type droit.
Exemples
>>> from qiskit.circuit.classical import types
>>> types.cast_kind(types.Bool(), types.Bool())
<CastKind.EQUAL: 1>
>>> types.cast_kind(types.Uint(8), types.Bool())
<CastKind.IMPLICIT: 2>
>>> types.cast_kind(types.Bool(), types.Uint(8))
<CastKind.LOSSLESS: 3>
>>> types.cast_kind(types.Uint(16), types.Uint(8))
<CastKind.DANGEROUS: 4>Paramètres
Type de retour
Les valeurs de retour de cette fonction sont une énumération expliquant les types de conversion autorisés du type de gauche vers le type de droite.
Notez que les casts entre Float et Uint sont considérés comme dangereux dans les deux sens et doivent être effectués explicitement.