Sari la conținutul principal

Clasa Operator

Versiuni de pachete

Codul de pe această pagină a fost dezvoltat folosind cerințele de mai jos. Recomandăm utilizarea acestor versiuni sau a unora mai noi.

qiskit[all]~=2.3.0

Această pagină arată cum să folosești clasa Operator. Pentru o prezentare generală a reprezentărilor de operatori în Qiskit, inclusiv clasa Operator și altele, consultă Prezentare generală a claselor de operatori.

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit
import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import CXGate, RXGate, XGate
from qiskit.quantum_info import Operator, Pauli, process_fidelity

Conversia claselor în Operatori

Mai multe alte clase din Qiskit pot fi convertite direct într-un obiect Operator folosind metoda de inițializare a operatorului. De exemplu:

  • Obiecte Pauli
  • Obiecte Gate și Instruction
  • Obiecte QuantumCircuit

Reține că ultimul punct înseamnă că poți folosi clasa Operator ca simulator unitar pentru a calcula matricea unitară finală a unui Circuit cuantic, fără a fi nevoie să apelezi un Backend simulator. Dacă Circuit-ul conține operații nesuportate, se ridică o excepție. Operațiile nesuportate sunt: measure, reset, operații condiționale sau un Gate care nu are o definiție de matrice sau o descompunere în Gate-uri cu definiții de matrice.

# Create an Operator from a Pauli object

pauliXX = Pauli("XX")
Operator(pauliXX)
Operator([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
[0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],
[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]],
input_dims=(2, 2), output_dims=(2, 2))
# Create an Operator for a Gate object
Operator(CXGate())
Operator([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
[0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]],
input_dims=(2, 2), output_dims=(2, 2))
# Create an operator from a parameterized Gate object
Operator(RXGate(np.pi / 2))
Operator([[0.70710678+0.j        , 0.        -0.70710678j],
[0. -0.70710678j, 0.70710678+0.j ]],
input_dims=(2,), output_dims=(2,))
# Create an operator from a QuantumCircuit object
circ = QuantumCircuit(10)
circ.h(0)
for j in range(1, 10):
circ.cx(j - 1, j)

# Convert circuit to an operator by implicit unitary simulation
Operator(circ)
Operator([[ 0.70710678+0.j,  0.70710678+0.j,  0.        +0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0.70710678+0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j],
...,
[ 0. +0.j, 0. +0.j, 0. +0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0.70710678+0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j],
[ 0.70710678+0.j, -0.70710678+0.j, 0. +0.j, ...,
0. +0.j, 0. +0.j, 0. +0.j]],
input_dims=(2, 2, 2, 2, 2, 2, 2, 2, 2, 2), output_dims=(2, 2, 2, 2, 2, 2, 2, 2, 2, 2))

Utilizarea Operatorilor în Circuit-uri

Operator-ii unitari pot fi inserați direct într-un QuantumCircuit folosind metoda QuantumCircuit.append. Aceasta convertește Operator-ul într-un obiect UnitaryGate, care este adăugat în Circuit.

Dacă operatorul nu este unitar, se ridică o excepție. Acest lucru poate fi verificat folosind funcția Operator.is_unitary(), care returnează True dacă operatorul este unitar și False în caz contrar.

# Create an operator
XX = Operator(Pauli("XX"))

# Add to a circuit
circ = QuantumCircuit(2, 2)
circ.append(XX, [0, 1])
circ.measure([0, 1], [0, 1])
circ.draw("mpl")

Output of the previous code cell

Reține că în exemplul de mai sus operatorul este inițializat dintr-un obiect Pauli. Totuși, obiectul Pauli poate fi inserat direct în Circuit și va fi convertit într-o secvență de Gate-uri Pauli cu un singur Qubit:

# Add to a circuit
circ2 = QuantumCircuit(2, 2)
circ2.append(Pauli("XX"), [0, 1])
circ2.measure([0, 1], [0, 1])
circ2.draw()
┌────────────┐┌─┐   
q_0: ┤0 ├┤M├───
│ Pauli(XX) │└╥┘┌─┐
q_1: ┤1 ├─╫─┤M├
└────────────┘ ║ └╥┘
c: 2/═══════════════╩══╩═
0 1

Combine Operators

Operatorii pot fi combinați folosind mai multe metode.

Produs tensorial

Doi operatori AA și BB pot fi combinați într-un operator produs tensorial ABA\otimes B folosind funcția Operator.tensor. Rețineți că, dacă atât AA cât și BB sunt operatori pe un singur Qubit, atunci A.tensor(B) = ABA\otimes B va avea subsistemele indexate ca matricea BB pe subsistemul 0, și matricea AA pe subsistemul 1.

A = Operator(Pauli("X"))
B = Operator(Pauli("Z"))
A.tensor(B)
Operator([[ 0.+0.j,  0.+0.j,  1.+0.j,  0.+0.j],
[ 0.+0.j, -0.+0.j, 0.+0.j, -1.+0.j],
[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[ 0.+0.j, -1.+0.j, 0.+0.j, -0.+0.j]],
input_dims=(2, 2), output_dims=(2, 2))

Expansiune tensorială

O operație strâns înrudită este Operator.expand, care acționează ca un produs tensorial, dar în ordine inversă. Astfel, pentru doi operatori AA și BB ai A.expand(B) = BAB\otimes A, unde subsistemele sunt indexate ca matricea AA pe subsistemul 0, și matricea BB pe subsistemul 1.

A = Operator(Pauli("X"))
B = Operator(Pauli("Z"))
A.expand(B)
Operator([[ 0.+0.j,  1.+0.j,  0.+0.j,  0.+0.j],
[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[ 0.+0.j, 0.+0.j, -0.+0.j, -1.+0.j],
[ 0.+0.j, 0.+0.j, -1.+0.j, -0.+0.j]],
input_dims=(2, 2), output_dims=(2, 2))

Compoziție

Poți, de asemenea, să compui doi operatori AA și BB pentru a implementa înmulțirea matriceală folosind metoda Operator.compose. A.compose(B) returnează operatorul cu matricea B.AB.A:

A = Operator(Pauli("X"))
B = Operator(Pauli("Z"))
A.compose(B)
Operator([[ 0.+0.j,  1.+0.j],
[-1.+0.j, 0.+0.j]],
input_dims=(2,), output_dims=(2,))

Poți, de asemenea, să compui în ordine inversă, aplicând BB în fața lui AA folosind argumentul front al metodei compose: A.compose(B, front=True) = A.BA.B:

A = Operator(Pauli("X"))
B = Operator(Pauli("Z"))
A.compose(B, front=True)
Operator([[ 0.+0.j, -1.+0.j],
[ 1.+0.j, 0.+0.j]],
input_dims=(2,), output_dims=(2,))

Compoziție pe subsisteme

Rețineți că compoziția anterioară necesită ca dimensiunea totală de ieșire a primului operator AA să fie egală cu dimensiunea totală de intrare a operatorului compus BB (și similar, dimensiunea de ieșire a lui BB trebuie să fie egală cu dimensiunea de intrare a lui AA când se compune cu front=True).

Poți, de asemenea, să compui un operator mai mic cu o selecție de subsisteme ale unui operator mai mare folosind argumentul qargs al metodei compose, cu sau fără front=True. În acest caz, dimensiunile relevante de intrare și ieșire ale subsistemelor compuse trebuie să corespundă. Rețineți că operatorul mai mic trebuie să fie întotdeauna argumentul metodei compose.

De exemplu, pentru a compune o Gate pe doi qubiți cu un operator pe trei qubiți:

# Compose XZ with a 3-qubit identity operator
op = Operator(np.eye(2**3))
XZ = Operator(Pauli("XZ"))
op.compose(XZ, qargs=[0, 2])
Operator([[ 0.+0.j,  0.+0.j,  0.+0.j,  0.+0.j,  1.+0.j,  0.+0.j,  0.+0.j,
0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, -1.+0.j, 0.+0.j,
0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j,
0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,
-1.+0.j],
[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,
0.+0.j],
[ 0.+0.j, -1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,
0.+0.j],
[ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,
0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, -1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,
0.+0.j]],
input_dims=(2, 2, 2), output_dims=(2, 2, 2))
# Compose YX in front of the previous operator
op = Operator(np.eye(2**3))
YX = Operator(Pauli("YX"))
op.compose(YX, qargs=[0, 2], front=True)
Operator([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j, 0.+0.j],
[0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]],
input_dims=(2, 2, 2), output_dims=(2, 2, 2))

Combinații liniare

Operatorii pot fi, de asemenea, combinați folosind operatori liniari standard pentru adunare, scădere și înmulțire cu scalari numere complexe.

XX = Operator(Pauli("XX"))
YY = Operator(Pauli("YY"))
ZZ = Operator(Pauli("ZZ"))

op = 0.5 * (XX + YY - 3 * ZZ)
op
Operator([[-1.5+0.j,  0. +0.j,  0. +0.j,  0. +0.j],
[ 0. +0.j, 1.5+0.j, 1. +0.j, 0. +0.j],
[ 0. +0.j, 1. +0.j, 1.5+0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j, -1.5+0.j]],
input_dims=(2, 2), output_dims=(2, 2))

Un aspect important este că, în timp ce tensor, expand și compose păstrează unitaritatea operatorilor unitari, combinațiile liniare nu o fac; prin urmare, adunarea a doi operatori unitari va produce, în general, un operator ne-unitar:

op.is_unitary()
False

Conversie implicită la Operators

Rețineți că pentru toate metodele de mai jos, dacă al doilea obiect nu este deja un obiect Operator, acesta este convertit implicit într-unul de către metodă. Aceasta înseamnă că matricele pot fi transmise direct fără a fi convertite explicit într-un Operator mai întâi. Dacă conversia nu este posibilă, este generată o excepție.

# Compose with a matrix passed as a list
Operator(np.eye(2)).compose([[0, 1], [1, 0]])
Operator([[0.+0.j, 1.+0.j],
[1.+0.j, 0.+0.j]],
input_dims=(2,), output_dims=(2,))

Compară Operators

Operatorii implementează o metodă de egalitate care poate fi folosită pentru a verifica dacă doi operatori sunt aproximativ egali.

Operator(Pauli("X")) == Operator(XGate())
True

Rețineți că aceasta verifică dacă fiecare element al matricei operatorilor este aproximativ egal; doi operatori unitari care diferă printr-o fază globală nu sunt considerați egali:

Operator(XGate()) == np.exp(1j * 0.5) * Operator(XGate())
False

Fidelitate de proces

Poți, de asemenea, să compari operatorii folosind funcția process_fidelity din modulul Quantum Information. Aceasta este o cantitate din teoria informației care măsoară cât de apropiați sunt doi canale cuantice unul de celălalt, iar în cazul operatorilor unitari nu depinde de faza globală.

# Two operators which differ only by phase
op_a = Operator(XGate())
op_b = np.exp(1j * 0.5) * Operator(XGate())

# Compute process fidelity
F = process_fidelity(op_a, op_b)
print("Process fidelity =", F)
Process fidelity = 1.0

Rețineți că fidelitatea de proces este în general o măsură valabilă a apropierii doar dacă operatorii de intrare sunt unitari (sau CP în cazul canalelor cuantice), și este generată o excepție dacă intrările nu sunt CP.

Pași următori

Recomandări