Espressioni classiche
qiskit.circuit.classical
Questo modulo contiene una rappresentazione esplorativa delle operazioni in tempo reale sui valori classici durante l'esecuzione del circuito.
Attualmente sono supportate solo espressioni semplici su bit e registri che restituiscono un valore booleano; tali espressioni sono valide esclusivamente nelle condizioni di QuantumCircuit.if_test() (IfElseOp) e QuantumCircuit.while_loop() (WhileLoopOp), nonché nell'argomento di QuantumCircuit.switch() (SwitchCaseOp).
Si tratta di un modulo esplorativo e, sebbene ci impegneremo a rispettare la politica di deprezzamento standard di Qiskit, vi preghiamo di tenere presente che il modulo sarà deliberatamente limitato all'inizio e le prime versioni potrebbero non evolvere in modo pulito nella versione finale. È possibile che vari componenti di questo modulo vengano sostituiti (soggetti a deprecazioni) invece di essere migliorati in una nuova forma.
Il sistema di tipi e l'albero delle espressioni saranno ampliati nel tempo ed è possibile che i tipi consentiti di alcune operazioni debbano cambiare da una versione all'altra di Qiskit, man mano che si sviluppano le capacità di elaborazione classiche.
Espressioni
qiskit.circuit.classical.expr
I componenti necessari per costruire le espressioni sono tutti esportati dallo spazio dei nomi expr all'interno di qiskit.circuit.classicalquindi si può scegliere se utilizzare l'accesso qualificato (per esempio expr.Value) o importare direttamente i nomi necessari e chiamarli senza prefisso.
Esistono due percorsi per la costruzione delle espressioni. Le classi che formano la rappresentazione del sistema di espressioni hanno costruttori che eseguono un controllo di tipo nullo; spetta al chiamante assicurarsi che stiano costruendo oggetti validi. Per un'interfaccia più semplice alla costruzione diretta, ci sono funzioni di aiuto associate alla maggior parte delle classi che eseguono la validazione e l'inferenza dei tipi. Questi sono descritti di seguito, nella sezione Costruzione.
Rappresentazione
Il sistema di espressione si basa sulla rappresentazione ad albero. Tutti i nodi dell'albero sono istanze finali (non ereditabili) della classe base astratta:
Espr
class qiskit.circuit.classical.expr.Expr
Basi: object
Classe base di tutti i nodi dell'albero delle espressioni. Il caso base non deve mai essere istanziato direttamente.
Non deve essere sottoclassato dagli utenti; le sottoclassi costituiscono i dati interni della rappresentazione delle espressioni e non ha senso aggiungerne altre al di fuori del codice della libreria Qiskit.
Tutte le sottoclassi sono tenute a impostare il proprio type attributo nel proprio __init__codice e non devono richiamare l'inizializzatore della classe padre.
Questi oggetti sono mutabili e non devono essere riutilizzati in una posizione diversa senza una copia.
Tutte le istanze Expr definiscono un attributo booleano const , che indica se l'espressione può essere valutata in tempo di compilazione. La maggior parte delle classi di espressioni lo deduce durante la costruzione, in base alla costanza dei loro operandi.
La base per le variabili dinamiche è la variabile Varche può essere sia una variabile in tempo reale digitata arbitrariamente, sia un wrapper attorno a una variabile Clbit o ClassicalRegister.
Var
class qiskit.circuit.classical.expr.Var(var, type, *, name=None)
Basi: Expr
Una variabile classica.
Queste variabili assumono due forme: una variabile di nuovo stile che possiede la sua posizione di memorizzazione e ha un nome associato; e una variabile di vecchio stile che avvolge un elemento Clbit o ClassicalRegister che è posseduta da un circuito contenente. In generale, la costruzione di variabili per l'uso nei programmi dovrebbe usare Var.new() o QuantumCircuit.add_var().
Le variabili sono immutabili una volta create, quindi possono essere utilizzate come chiavi dei dizionari.
name
Il nome della variabile. Questo deve essere presente se l'attributo backing var è un UUID, ovvero se si tratta di una variabile di nuovo stile, e deve essere None se si tratta di una variabile di vecchio stile.
new
classmethod new(name, ty)
Genera una nuova variabile con nome che possiede il proprio archivio di backup.
var
Un riferimento all'archivio dati di supporto dell'istanza Var . ClassicalRegisterQuando si trasferiscono istanze di ClassicalRegister vecchio Clbit tipo in un Var, questo è esattamente il Clbit o il. ClbitSe la variabile è una variabile classica di nuovo tipo (ovvero una variabile che dispone di una propria area di memoria separata da quella delClassicalRegister vecchio modello), questo campo conterrà un UUID identificatore univoco che la contraddistingue.
Allo stesso modo, i letterali usati nelle espressioni (come gli interi) devono essere sollevati a Value con tipi associati. A Value è sempre considerata un'espressione costante.
Valore
Le variabili stretch da usare nelle espressioni di durata sono rappresentate dal nodo Stretch nodo.
Tendi
class qiskit.circuit.classical.expr.Stretch(var, name)
Basi: Expr
Una variabile di tipo stretch.
In generale, la costruzione di variabili di tipo stretch da usare nei programmi dovrebbe usare Stretch.new() o QuantumCircuit.add_stretch()
name
Il nome della variabile stretch.
new
classmethod new(name)
Genera una nuova variabile stretch con nome.
var
A UUID per identificare in modo univoco questo tratto.
Le operazioni tradizionalmente associate agli operatori pre-, post- o infix nella programmazione sono rappresentate dagli operatori Unary e Binary a seconda dei casi. Ognuno di essi prende un codice del tipo di operazione, esposto come enumerazione all'interno di ogni classe come Unary.Op e Binary.Op rispettivamente.
Unario
class qiskit.circuit.classical.expr.Unary(op, operand, type)
Basi: Expr
Un'espressione unaria.
Parametri
- op - L'opcode che descrive l'operazione in corso.
- operando - L'operando dell'operazione.
- tipo - Il tipo risolto del risultato.
Operatore
class Op(*values)
Basi: Enum
Enumerazione degli opcode per le operazioni unarie.
La negazione bitwise BIT_NOT prende un singolo bit o un intero senza segno di ampiezza nota e restituisce un valore dello stesso tipo.
La negazione logica LOGIC_NOT accetta un input implicitamente forzato a un booleano e restituisce un booleano.
La negazione aritmetica NEGATE accetta come input un valore di tipo float o duration e restituisce un valore dello stesso tipo.
Binario
class qiskit.circuit.classical.expr.Binary(op, left, right, type)
Basi: Expr
Un'espressione binaria.
Parametri
- op - L'opcode che descrive l'operazione in corso.
- left - L'operando di sinistra.
- right - L'operando di destra.
- tipo - Il tipo risolto del risultato.
Operatore
class Op(*values)
Basi: Enum
Enumerazione degli opcode per le operazioni binarie.
Le operazioni bitwise BIT_AND, BIT_OR e BIT_XOR si applicano a due operandi dello stesso tipo, che devono essere un singolo bit o un intero senza segno di larghezza fissa. Il tipo risultante è lo stesso dei due tipi di ingresso.
Le operazioni logiche LOGIC_AND e LOGIC_OR prima coercizzano implicitamente i loro argomenti in booleani e poi applicano l'operazione logica. Il tipo risultante è sempre booleano.
Le relazioni matematiche binarie EQUAL, NOT_EQUAL, LESS, LESS_EQUAL, GREATER e GREATER_EQUAL prendono numeri interi senza segno (con un cast implicito per renderli della stessa larghezza) e restituiscono un booleano.
Le operazioni di bitshift SHIFT_LEFT e SHIFT_RIGHT possono accettare tipi di contenitori simili ai bit (ad esempio, numeri interi senza segno) come operando di sinistra e qualsiasi tipo di intero come operando di destra. In tutti i casi, la larghezza del bit di uscita è uguale a quella dell'ingresso e gli zeri riempiono gli spazi "esposti".
Gli operatori aritmetici ADD binari, SUB, MUL, e DIV possono essere applicati a due numeri in virgola mobile o a due interi senza segno, che devono essere convertiti in modo da avere la stessa lunghezza durante la creazione tramite un cast. Gli DIV operatori ADD, SUB, e possono essere applicati a due durate, restituendo un'altra durata o un numero in virgola mobile nel caso di DIV. L'operatore MUL può essere applicato anche a una durata e a un tipo numerico, restituendo un'altra durata. Infine, DIV l'operatore può essere utilizzato per dividere una durata per un valore numerico, ottenendo una durata.
I tipi di bit (interi senza segno) possono essere indicizzati da tipi di interi, rappresentati da Index. Il risultato è un singolo bit. L'espressione risultante ha una posizione di memoria associata (e quindi può essere usata come valore l per i file Store, ecc.) se anche l'obiettivo è un valore l.
Indice
class qiskit.circuit.classical.expr.Index(target, index, type)
Basi: Expr
Un'espressione di indicizzazione.
Parametri
- target - L'oggetto da indicizzare.
- index - L'espressione che esegue l'indicizzazione.
- tipo - Il tipo risolto del risultato.
Quando si costruiscono le espressioni, bisogna assicurarsi che i tipi siano validi per l'operazione. I tentativi di costruire espressioni con tipi non validi solleveranno un regolare Python TypeError.
Le espressioni di questo sistema sono definite per agire solo su determinati insiemi di tipi. Tuttavia, per soddisfare i requisiti di tipizzazione, i valori possono essere lanciati verso un supertipo adatto. In questi casi, un nodo dell'albero delle espressioni viene utilizzato per rappresentare la promozione. In tutti i casi in cui le operazioni segnalano di "lanciare implicitamente" o "costringere" i loro argomenti, l'albero delle espressioni deve avere questo nodo che rappresenta la conversione.
Cast
class qiskit.circuit.classical.expr.Cast(operand, type, implicit=False)
Basi: Expr
Un cast da un tipo a un altro, implicito nell'uso di un'espressione in un contesto diverso.
Costruzioni
La costruzione diretta della rappresentazione ad albero è prolissa ed è facile sbagliare la digitazione. In molti casi, gran parte della tipizzazione può essere dedotta, i valori scalari possono essere promossi automaticamente a Value istanze e le promozioni necessarie possono essere risolte in nodi adeguati Cast nodi adatti.
Le funzioni e i metodi descritti in questa sezione rappresentano un modo più semplice per costruire l'albero delle espressioni, pur rimanendo vicini alla rappresentazione interna. Tutte queste funzioni sollevano automaticamente i valori scalari validi di Python nei corrispondenti valori di Var o Value e risolveranno qualsiasi cast implicito richiesto per conto dell'utente. Se si vuole usare direttamente un valore scalare come nodo Expr nodo, si può usare manualmente lift() manualmente.
lift
qiskit.circuit.classical.expr.lift(value, /, type=None)
Solleva il dato Python value a un Value o Var.
Se viene fornito un type esplicito, la digitazione nell'output rifletterà questo dato.
Esempi
Sollevare semplici oggetti di circuito per renderli Var istanze:
>>> 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))È possibile specificare il tipo del valore restituito, se il valore fornito può essere interpretato senza perdita di informazioni come quel tipo (utilizzare cast() per eseguire una serie completa di operazioni di conversione, comprese quelle con perdita di informazioni):
>>> 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))Parametri
Tipo di restituzione
In genere si dovrebbero creare istanze che possiedono memoria Var utilizzando il metodo QuantumCircuit.add_var() per dichiararle in un contesto circuitale, poiché il metodo QuantumCircuit non accetterà un oggetto Expr che contenga variabili non ancora dichiarate, poiché deve sapere come allocare la memoria e come inizializzare la variabile. Tuttavia, se si desidera farlo manualmente, è necessario utilizzare la chiamata di basso livello Var.new() per generare in modo sicuro una variabile con nome da utilizzare.
È possibile specificare manualmente i cast nei casi in cui il cast è consentito in forma esplicita, ma può essere soggetto a perdite (ad esempio il cast di una precisione superiore Uint a una di precisione inferiore).
cast
qiskit.circuit.classical.expr.cast(operand, type, /)
Crea un cast esplicito dal valore dato al tipo dato.
Esempi
Aggiungere un nodo di cast esplicito che esegue il cast esplicito di un tipo di precisione superiore a uno di precisione inferiore:
>>> 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)Parametri
Tipo di restituzione
Esistono funzioni costruttrici ausiliarie per ciascuna delle operazioni unarie.
bit_not
qiskit.circuit.classical.expr.bit_not(operand, /)
Crea un nodo di espressione bitwise 'not' dal valore dato, risolvendo qualsiasi cast implicito e sollevando il valore in un nodo Value se necessario.
Esempi
Negazione bitwise di 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))Parametri
operand (Any)
Tipo di restituzione
logic_not
qiskit.circuit.classical.expr.logic_not(operand, /)
Crea un nodo di espressione logica 'not' dal valore dato, risolvendo qualsiasi cast implicito e sollevando il valore in un nodo Value se necessario.
Esempi
Negazione logica di 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())Parametri
operand (Any)
Tipo di restituzione
negate
qiskit.circuit.classical.expr.negate(operand, /)
Negare un nodo di espressione a partire dal valore specificato, risolvendo eventuali conversioni implicite e trasformando il valore in un Value nodo, se necessario.
Esempi
Negazione di un numero in virgola mobile:
>>> from qiskit.circuit.classical import expr
>>> expr.negate(5.0)
Unary(Unary.Op.NEGATE, Value(5.0, Float()), Float())Negazione di una durata:
>>> 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())Parametri
operand (Any)
Tipo di restituzione
Allo stesso modo, per le operazioni binarie e le relazioni sono state definite delle funzioni di aiuto.
bit_and
qiskit.circuit.classical.expr.bit_and(left, right, /)
Crea un nodo di espressione bitwise 'e' dal valore dato, risolvendo qualsiasi cast implicito e sollevando i valori nei nodi Value se necessario.
Esempi
Bitwise 'and' di un registro classico e di un letterale intero:
>>> 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))Parametri
Tipo di restituzione
bit_or
qiskit.circuit.classical.expr.bit_or(left, right, /)
Crea un nodo di espressione bitwise 'o' dal valore dato, risolvendo qualsiasi cast implicito e sollevando i valori in nodi Value se necessario.
Esempi
Bitwise 'or' di un registro classico e di un letterale intero:
>>> 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))Parametri
Tipo di restituzione
bit_xor
qiskit.circuit.classical.expr.bit_xor(left, right, /)
Crea un nodo di espressione bitwise 'exclusive or' a partire dal valore dato, risolvendo qualsiasi cast implicito e sollevando i valori nei nodi Value se necessario.
Esempi
Bitwise 'exclusive or' di un registro classico e di un letterale intero:
>>> 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))Parametri
Tipo di restituzione
logic_and
qiskit.circuit.classical.expr.logic_and(left, right, /)
Crea un nodo di espressione logica 'e' a partire dal valore dato, risolvendo qualsiasi cast implicito e sollevando i valori nei nodi Value se necessario.
Esempi
Logica "e" di due bit classici:
>>> 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())Parametri
Tipo di restituzione
logic_or
qiskit.circuit.classical.expr.logic_or(left, right, /)
Crea un nodo di espressione logica 'o' a partire dal valore dato, risolvendo qualsiasi cast implicito e sollevando i valori nei nodi Value se necessario.
Esempi
Logica 'o' di due bit classici
>>> 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())Parametri
Tipo di restituzione
equal
qiskit.circuit.classical.expr.equal(left, right, /)
Crea un nodo di espressione 'uguale' dal valore dato, risolvendo qualsiasi cast implicito e sollevando i valori in nodi Value se necessario.
Esempi
Uguaglianza tra un registro classico e un intero:
>>> 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))Parametri
Tipo di restituzione
not_equal
qiskit.circuit.classical.expr.not_equal(left, right, /)
Crea un nodo di espressione "non uguale" dal valore dato, risolvendo qualsiasi cast implicito e sollevando i valori nei nodi Value se necessario.
Esempi
Disuguaglianza tra un registro classico e un intero:
>>> 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))Parametri
Tipo di restituzione
less
qiskit.circuit.classical.expr.less(left, right, /)
Crea un nodo di espressione "meno di" dal valore dato, risolvendo qualsiasi cast implicito e sollevando i valori nei nodi Value se necessario.
Esempi
Chiede se un registro classico è inferiore a un intero:
>>> 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))Parametri
Tipo di restituzione
less_equal
qiskit.circuit.classical.expr.less_equal(left, right, /)
Crea un nodo di espressione "minore o uguale a" a partire dal valore dato, risolvendo qualsiasi cast implicito e sollevando i valori nei nodi Value se necessario.
Esempi
Interrogare se un registro classico è minore o uguale a un altro:
>>> 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))Parametri
Tipo di restituzione
greater
qiskit.circuit.classical.expr.greater(left, right, /)
Crea un nodo di espressione "maggiore di" dal valore dato, risolvendo qualsiasi cast implicito e sollevando i valori nei nodi Value se necessario.
Esempi
Chiede se un registro classico è maggiore di un intero:
>>> 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))Parametri
Tipo di restituzione
greater_equal
qiskit.circuit.classical.expr.greater_equal(left, right, /)
Crea un nodo di espressione "maggiore o uguale a" a partire dal valore dato, risolvendo qualsiasi cast implicito e sollevando i valori nei nodi Value se necessario.
Esempi
Interrogare se un registro classico è maggiore o uguale a un altro:
>>> 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))Parametri
Tipo di restituzione
shift_left
qiskit.circuit.classical.expr.shift_left(left, right, /, type=None)
Crea un nodo di espressione 'bitshift left' dai due valori dati, risolvendo qualsiasi cast implicito e sollevando i valori in nodi Value se necessario.
Se viene dato type , l'operando left verrà coercizzato ad esso (se possibile).
Esempi
Sposta il valore di una variabile indipendente a sinistra di una certa quantità:
>>> 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))Sposta un letterale intero di una quantità variabile, coercendo il tipo del letterale:
>>> 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))Parametri
Tipo di restituzione
shift_right
qiskit.circuit.classical.expr.shift_right(left, right, /, type=None)
Crea un nodo di espressione 'bitshift right' dai valori dati, risolvendo qualsiasi cast implicito e sollevando i valori nei nodi Value se necessario.
Se viene dato type , l'operando left verrà coercizzato ad esso (se possibile).
Esempi
Sposta il valore di un registro classico a destra di una certa quantità:
>>> 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))Parametri
Tipo di restituzione
add
qiskit.circuit.classical.expr.add(left, right, /)
Crea un nodo di espressione di addizione a partire dai valori dati, risolvendo qualsiasi cast implicito e sollevando i valori in nodi di tipo Value se necessario.
Esempi
Addizione di due numeri in virgola mobile:
>>> 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())Aggiunta di due durate:
>>> 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())Parametri
Tipo di restituzione
sub
qiskit.circuit.classical.expr.sub(left, right, /)
Crea un nodo di espressione di sottrazione dai valori dati, risolvendo qualsiasi cast implicito e sollevando i valori in nodi di tipo Value se necessario.
Esempi
Sottrazione di due numeri in virgola mobile:
>>> 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())Sottrazione di due durate:
>>> 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())Parametri
Tipo di restituzione
mul
qiskit.circuit.classical.expr.mul(left, right)
Crea un nodo espressione di moltiplicazione a partire dai valori dati, risolvendo qualsiasi cast implicito e sollevando i valori in nodi Value se necessario.
Può essere utilizzato per moltiplicare operandi numerici dello stesso tipo o per moltiplicare un operando di durata per un operando numerico.
Esempi
Moltiplicazione di due numeri in virgola mobile:
>>> 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())Moltiplicazione di una durata per un valore fluttuante:
>>> 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())Parametri
Tipo di restituzione
div
qiskit.circuit.classical.expr.div(left, right)
Crea un nodo di espressione di divisione dai valori dati, risolvendo qualsiasi cast implicito e sollevando i valori in nodi di tipo Value se necessario.
Può essere utilizzato per dividere operandi numerici dello stesso tipo, per dividere un operando per un operando numerico o per dividere due operandi numerici Duration per un operando numerico, oppure per dividere due operandi Duration che producono un'espressione di tipo Float.
Esempi
Divisione di due numeri in virgola mobile:
>>> 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())Divisione di due durate:
>>> 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())Divisione di una durata per un galleggiante:
>>> 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())Parametri
Tipo di restituzione
È possibile indicizzare gli interi senza segno e i bit simili utilizzando un altro intero senza segno di qualsiasi larghezza. Questo include le operazioni di memorizzazione, se la destinazione dell'indice è scrivibile.
index
qiskit.circuit.classical.expr.index(target, index, /)
Indicizza il sito target con il dato intero index, sollevando i valori in Value se necessario.
Questo può essere usato come bersaglio di un elemento Store, se target è a sua volta un valore l.
Esempi
Indicizza un registro classico con un letterale:
>>> 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())Parametri
Tipo di restituzione
Il metodo tradizionale di Qiskit per specificare le condizioni di uguaglianza da utilizzare nei condizionali è quello di utilizzare una doppia tupla di a Clbit o ClassicalRegister e un intero. Questa rappresenta una condizione di uguaglianza esatta e non c'è modo di specificare altre relazioni. La funzione helper lift_legacy_condition() converte questo formato legacy nella nuova sintassi delle espressioni.
lift_legacy_condition
qiskit.circuit.classical.expr.lift_legacy_condition(condition, /)
Sollevare una condizione di uguaglianza a due tuple in un nuovo stile Expr.
Parametri
condition (tuple[qiskit.circuit.Clbit |qiskit.circuit.ClassicalRegister, int])
Tipo di restituzione
Lavorare con l'albero delle espressioni
Un tipico utente dell'albero delle espressioni vuole percorrere ricorsivamente l'albero, potenzialmente in modo statico, agendo su ogni nodo in modo diverso a seconda del suo tipo. Si tratta naturalmente di un problema di doppio dispacciamento: la logica di "ciò che deve essere fatto" è probabilmente statica e gli utenti dovrebbero essere liberi di definire le proprie operazioni, ma ogni nodo definisce "ciò su cui si agisce". Per consentire questo doppio dispatch, forniamo una classe visitatore di base per l'albero delle espressioni.
ExprVisitor
class qiskit.circuit.classical.expr.ExprVisitor
Basi: Generic[_T_co]
Classe base per i visitatori dell'albero Expr albero. Le sottoclassi devono sovrascrivere i metodi di visit_* che sono in grado di gestire e devono essere organizzate in modo che i metodi inesistenti non vengano mai richiamati.
visit_binary
visit_cast
visit_generic
visit_index
visit_stretch
visit_unary
visit_value
visit_var
Gli utenti dell'albero delle espressioni devono sottoclasse il visitatore e sovrascrivere i metodi di visit_* che desiderano gestire. Qualsiasi metodo non sovrascritto chiamerà visit_generic()che, a meno che non venga sovrascritto, solleverà un RuntimeError per assicurarsi che si sappia se sono stati aggiunti nuovi nodi all'albero delle espressioni che non sono ancora stati gestiti.
Per la comodità dei semplici visitatori che devono ispezionare solo le variabili di un'espressione e non la struttura generale, viene fornito il metodo iteratore iter_vars() viene fornito.
iter_vars
qiskit.circuit.classical.expr.iter_vars(node)
Ottiene un iteratore sui Var a cui si fa riferimento a qualsiasi livello nel file Expr.
Esempi
Stampare il nome di ogni ClassicalRegister incontrato:
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)Parametri
node (Expr)
Tipo di restituzione
Per eseguire un iteratore su tutte le variabili, comprese quelle di tipo stretch, è disponibile il metodo iteratore iter_identifiers() viene fornito.
iter_identifiers
qiskit.circuit.classical.expr.iter_identifiers(node)
Ottiene un iteratore sugli elementi Var e Stretch a cui si fa riferimento a qualsiasi livello nel file Expr.
Esempi
Stampare il nome di ogni ClassicalRegister incontrato:
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)Ottiene un iteratore sui soli nodi Var dell'espressione.
Parametri
node (Expr)
Tipo di restituzione
Due espressioni possono essere confrontate per un'uguaglianza strutturale diretta utilizzando l'operatore incorporato Python == . In generale, però, si potrebbe voler confrontare due espressioni in modo leggermente più semantico, ammettendo che i Var nodi al loro interno siano legati a descrizioni diverse della posizione della memoria tra due circuiti diversi. In questo caso, si può utilizzare structurally_equivalent() con due opportune funzioni "chiave" per effettuare il confronto.
structurally_equivalent
qiskit.circuit.classical.expr.structurally_equivalent(left, right, left_var_key=None, right_var_key=None)
Queste due espressioni hanno esattamente la stessa struttura ad albero, fino a qualche funzione chiave per gli oggetti? Var oggetti?
In altre parole, queste due espressioni sono esattamente gli stessi alberi, tranne che per il fatto che confrontiamo i campi Var.var chiamando la funzione *_var_key appropriata su di essi e confrontando l'output per verificare l'uguaglianza. Questa funzione non consente alcuna "equivalenza" semantica, come ad esempio affermare che a == b è equivalente a b == a; l'ordine di valutazione degli operandi potrebbe, in generale, rendere falsa una tale affermazione (si pensi a ipotetiche funzioni di extern che accedono allo stato globale).
Non ci sono requisiti sulle funzioni chiave, tranne che le loro uscite devono avere metodi generali __eq__ . Se una funzione chiave restituisce None, la variabile verrà utilizzata alla lettera.
Parametri
- left (Expr) – uno dei
Exprnodi. - right (Expr) – l'altro
Exprnodo. - left_var_key (Callable[[Any], Any] | None) – un callable il cui output deve essere usato quando si confrontano gli
Var.varattributi. Se questo argomento èNoneo il suo output èNoneper una determinata variabile inleft, la variabile verrà utilizzata alla lettera. - right_var_key (Callable[[Any], Any] | None) – come
left_var_key, ma utilizzato sulle variabili diright.
Tipo di restituzione
Esempi
Confronto di due espressioni per l'equivalenza strutturale, senza rimappatura delle variabili. Questi sono diversi perché le diverse Clbit istanze si confrontano in modo diverso:
>>> 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)
FalseConfronto tra le stesse due espressioni, ma questa volta utilizzando funzioni di mappatura che associano i bit a semplici indici:
>>> 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)
TrueAlcune espressioni hanno posizioni di memoria associate, mentre altre possono essere puramente temporanee. È possibile utilizzare is_lvalue() per determinare se un'espressione ha una posizione di memoria associata.
is_lvalue
qiskit.circuit.classical.expr.is_lvalue(node, /)
Restituisce se questa espressione può essere usata in posizioni di valore l, cioè se ha una posizione ben definita in memoria, ad esempio una che potrebbe essere scrivibile.
Il fatto che si tratti di un valore di tipo l è una condizione necessaria ma non sufficiente affinché questa posizione di memoria sia scrivibile; è possibile che un oggetto più grande contenente tale posizione di memoria non consenta la scrittura da parte dell'ambito che tenta di scriverci. Si tratterebbe tuttavia di una proprietà di accesso del programma contenitore e non di una proprietà intrinseca del sistema di espressione.
Un'espressione costante non è mai un valore l.
Esempi
I valori letterali non sono mai valori l; non esiste una locazione di memoria associata (ad esempio) alla costante 1:
>>> from qiskit.circuit.classical import expr
>>> expr.is_lvalue(expr.lift(2))
FalseVar i nodi sono sempre valori l, perché hanno sempre una posizione di memoria associata:
>>> 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()))
TrueAttualmente non esistono operazioni unarie o binarie sulle variabili in grado di produrre un'espressione a l, ma è probabile che in futuro venga aggiunta una sorta di operazione di "indicizzazione", che potrebbe produrre valori a 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))
FalseParametri
node (Expr)
Tipo di restituzione
Immissione
qiskit.circuit.classical.types
Rappresentazione
Il sistema di tipi dell'albero delle espressioni è esposto attraverso questo modulo. Questo è intrinsecamente legato al sistema di espressioni del modulo expr poiché la maggior parte delle espressioni possono essere comprese solo nel contesto dei tipi su cui agiscono.
Tutti i tipi ereditano da una classe base astratta:
Tipo
class qiskit.circuit.classical.types.Type
Basi: object
Classe base di tutti i nodi dell'albero dei tipi. Il caso base non deve mai essere istanziato direttamente.
Non deve essere sottoclassato dagli utenti; le sottoclassi costituiscono i dati interni della rappresentazione delle espressioni e non ha senso aggiungerne altre al di fuori del codice della libreria Qiskit.
I tipi devono essere considerati oggetti immutabili e non devono essere mutati. È consentito riutilizzare un oggetto Type che si prende da un altro oggetto senza copiarlo e in genere questo è l'approccio migliore per le prestazioni. Type gli oggetti sono progettati per essere piccole quantità di dati ed è meglio puntare alla stessa istanza dei dati, se possibile, piuttosto che allocare in heap una nuova versione della stessa cosa. Ove possibile, i costruttori della classe restituiranno istanze singleton per agevolare questa operazione.
Il Bool rappresenta il tipo Clbit e i letterali True e False, il tipo Uint rappresenta ClassicalRegister e Python interi, il tipo Float rappresenta Python i float e il tipo Duration tipo rappresenta una durata da utilizzare nelle operazioni circuitali di temporizzazione.
Bool
class qiskit.circuit.classical.types.Bool
Basi: Type
Il tipo booleano. Questo ha esattamente due valori: True e False.
Uint
class qiskit.circuit.classical.types.Uint(width)
Basi: Type
Un intero senza segno di larghezza fissa di bit.
A virgola mobile
class qiskit.circuit.classical.types.Float
Basi: Type
Un numero in virgola mobile a doppia precisione IEEE-754.
In futuro, potrà essere utilizzato anche per rappresentare altri float a larghezza fissa.
Durata
Lavorare con i tipi
Nelle sezioni successive sono documentate alcune funzioni aggiuntive su questi tipi. Si prevede che questi vengano utilizzati solo nelle manipolazioni dell'albero delle espressioni; gli utenti che costruiscono le espressioni utilizzando l' interfaccia di costruzione rivolta all'utente non dovrebbero aver bisogno di usarli.
Ordinamento parziale dei tipi
Il sistema di tipi è dotato di un ordinamento parziale, dove è interpretato come " è un sottotipo stretto di ". Si noti che l'ordinamento parziale è un sottoinsieme del grafo diretto che descrive le operazioni di fusione esplicita consentite tra i tipi. L'ordinamento parziale definisce quando un tipo può essere interpretato direttamente e senza perdite come un altro.
L'interfaccia di basso livello per interrogare la relazione di sottotipizzazione è la funzione order() funzione.
order
qiskit.circuit.classical.types.order(left, right, /)
Ottiene la relazione di ordinamento tra i due tipi come valore di enumerazione.
Esempi
Confrontare due Uint tipi di larghezza diversa:
>>> from qiskit.circuit.classical import types
>>> types.order(types.Uint(8), types.Uint(16))
Ordering.LESSConfrontare due tipi che non hanno un ordine tra loro:
>>> types.order(types.Uint(8), types.Bool())
Ordering.NONEParametri
Tipo di restituzione
Il valore di ritorno è un'enumerazione Ordering che descrive l'eventuale relazione di sottotipizzazione tra i due tipi.
Ordinamento
class qiskit.circuit.classical.types.Ordering(*values)
Basi: Enum
Enumerazione che elenca le possibili relazioni tra due tipi. I tipi hanno solo un ordinamento parziale, quindi è possibile che due tipi non abbiano alcuna relazione di sottotipizzazione.
Si noti che la relazione di sotto-sopravvivenza non coincide con la possibilità di lanciare esplicitamente un tipo da uno all'altro.
Alcuni metodi di aiuto sono poi definiti in termini di questa primitiva di basso livello order() primitivo:
is_subtype
qiskit.circuit.classical.types.is_subtype(left, right, /, strict=False)
La relazione è valida? Se non esiste una relazione d'ordine tra i due tipi, viene restituito False. Se strict, allora anche l'uguaglianza è proibita.
Esempi
Controlla se un tipo è una sottoclasse di un altro:
>>> from qiskit.circuit.classical import types
>>> types.is_subtype(types.Uint(8), types.Uint(16))
TrueControlla se un tipo è una sottoclasse stretta di un altro:
>>> types.is_subtype(types.Bool(), types.Bool())
True
>>> types.is_subtype(types.Bool(), types.Bool(), strict=True)
FalseParametri
Tipo di restituzione
is_supertype
qiskit.circuit.classical.types.is_supertype(left, right, /, strict=False)
La relazione è valida? Se non esiste una relazione d'ordine tra i due tipi, viene restituito False. Se strict, allora anche l'uguaglianza è proibita.
Esempi
Controlla se un tipo è una superclasse di un altro:
>>> from qiskit.circuit.classical import types
>>> types.is_supertype(types.Uint(8), types.Uint(16))
FalseControlla se un tipo è una superclasse stretta di un altro:
>>> types.is_supertype(types.Bool(), types.Bool())
True
>>> types.is_supertype(types.Bool(), types.Bool(), strict=True)
FalseParametri
Tipo di restituzione
greater
qiskit.circuit.classical.types.greater(left, right, /)
Ottiene il maggiore dei due tipi, supponendo che esista una relazione d'ordine tra di essi. Tecnicamente, si tratta di una versione leggermente ristretta del concetto di "incontro" dei due tipi, in quanto il valore di ritorno deve essere uno degli ingressi. In pratica, nel sistema dei tipi non esiste il concetto di tipo "somma", quindi l'"incontro" esiste se e solo se esiste un ordinamento tra i due tipi ed è uguale al maggiore dei due tipi.
Risultati
Il maggiore dei due tipi.
Aumenti
TypeError - se non esiste una relazione d'ordine tra i due tipi.
Parametri
Tipo di restituzione
Esempi
Trovare il maggiore tra due Uint tipi:
>>> from qiskit.circuit.classical import types
>>> types.greater(types.Uint(8), types.Uint(16))
types.Uint(16)Conversione tra tipi
È frequente la necessità di lanciare valori di un tipo in un altro tipo. Le regole di fusione per questo sono incorporate nel modulo types del modulo. È possibile interrogare i tipi di fusione utilizzando cast_kind():
cast_kind
qiskit.circuit.classical.types.cast_kind(from_, to_, /)
Determinare il tipo di cast necessario per passare dal tipo sinistro al tipo destro.
Esempi
>>> 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>Parametri
Tipo di restituzione
I valori di ritorno di questa funzione sono un'enumerazione che spiega i tipi di cast consentiti dal tipo sinistro al tipo destro.
Si noti che i cast tra Float e Uint sono considerati pericolosi in entrambe le direzioni e devono essere fatti esplicitamente.