Vai al contenuto principale

Implementazione con Qiskit

Nella lezione precedente abbiamo dato una prima occhiata alle classi Statevector e Operator di Qiskit, e le abbiamo usate per simulare operazioni e misurazioni su singoli qubit. In questa sezione useremo queste classi per esplorare il comportamento di più qubit.

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit
from qiskit import __version__

print(__version__)
2.1.1

Inizieremo importando le classi Statevector e Operator, oltre alla funzione radice quadrata di NumPy. D'ora in avanti, in linea generale, ci occuperemo di tutti gli import necessari all'inizio di ogni lezione.

from qiskit.quantum_info import Statevector, Operator
from numpy import sqrt

Prodotti tensoriali

La classe Statevector dispone di un metodo tensor, che restituisce il prodotto tensoriale di quello Statevector con un altro, fornito come argomento. L'argomento viene interpretato come il fattore tensoriale a destra.

Ad esempio, qui sotto creiamo due vettori di stato che rappresentano 0\vert 0\rangle e 1,\vert 1\rangle, e usiamo il metodo tensor per creare un nuovo vettore, ψ=01.\vert \psi\rangle = \vert 0\rangle \otimes \vert 1\rangle. Nota che qui stiamo usando il metodo from_label per definire gli stati 0\vert 0\rangle e 1,\vert 1\rangle, anziché definirli manualmente.

zero = Statevector.from_label("0")
one = Statevector.from_label("1")
psi = zero.tensor(one)
display(psi.draw("latex"))

01 |01\rangle

Le altre etichette ammesse includono "+" e "-" per gli stati più e meno, nonché "r" e "l" (abbreviazioni di "right" e "left") per gli stati

+i=120+i21ei=120i21.\vert {+i} \rangle = \frac{1}{\sqrt{2}} \vert 0 \rangle + \frac{i}{\sqrt{2}} \vert 1 \rangle \qquad\text{e}\qquad \vert {-i} \rangle = \frac{1}{\sqrt{2}} \vert 0 \rangle - \frac{i}{\sqrt{2}} \vert 1 \rangle.

Qui "+" , "-" oppure "right" e "left" derivano dal contesto dello spin in meccanica quantistica, in cui una componente dello spin può puntare a sinistra o a destra in un esperimento; non si riferiscono al qubit più a destra o più a sinistra in sistemi a più qubit. Ecco un esempio del prodotto tensoriale di +\vert {+} \rangle e i.\vert {-i} \rangle.

plus = Statevector.from_label("+")
minus_i = Statevector.from_label("l")
phi = plus.tensor(minus_i)
display(phi.draw("latex"))

1200i201+1210i211\frac{1}{2} |00\rangle- \frac{i}{2} |01\rangle+\frac{1}{2} |10\rangle- \frac{i}{2} |11\rangle

In alternativa, si può usare l'operazione ^ per i prodotti tensoriali, che naturalmente produce gli stessi risultati.

display((plus ^ minus_i).draw("latex"))

1200i201+1210i211\frac{1}{2} |00\rangle- \frac{i}{2} |01\rangle+\frac{1}{2} |10\rangle- \frac{i}{2} |11\rangle

Anche la classe Operator dispone di un metodo tensor (e di un metodo from_label), come vediamo negli esempi seguenti.

H = Operator.from_label("H")
Id = Operator.from_label("I")
X = Operator.from_label("X")
display(H.tensor(Id).draw("latex"))
display(H.tensor(Id).tensor(X).draw("latex"))
[220220022022220220022022] \begin{bmatrix} \frac{\sqrt{2}}{2} & 0 & \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & \frac{\sqrt{2}}{2} \\ \frac{\sqrt{2}}{2} & 0 & - \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & - \frac{\sqrt{2}}{2} \\ \end{bmatrix} [02200022002200022000000220002200220002200220002200220002200000022000220022000220] \begin{bmatrix} 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 \\ \end{bmatrix}

Anche in questo caso, come per i vettori, l'operazione ^ è equivalente.

display((H ^ Id ^ X).draw("latex"))
[02200022002200022000000220002200220002200220002200220002200000022000220022000220] \begin{bmatrix} 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 \\ \end{bmatrix}

Gli stati composti possono essere evoluti tramite operazioni composte nel modo che ci aspettiamo — proprio come abbiamo visto per i sistemi singoli nella lezione precedente. Ad esempio, il codice seguente calcola lo stato (HI)ϕ(H\otimes I)\vert\phi\rangle per ϕ=+i\vert\phi\rangle = \vert + \rangle \otimes \vert {-i}\rangle (già definito sopra).

display(phi.evolve(H ^ Id).draw("latex"))

22002i201\frac{\sqrt{2}}{2} |00\rangle- \frac{\sqrt{2} i}{2} |01\rangle

Ecco del codice che definisce un'operazione CXCX e calcola CXψCX \vert\psi\rangle per ψ=+0.\vert\psi\rangle = \vert + \rangle \otimes \vert 0 \rangle. Per essere precisi, si tratta di un'operazione CXCX in cui il qubit a sinistra è il controllo e il qubit a destra è il bersaglio. Il risultato è lo stato di Bell ϕ+.\vert\phi^{+}\rangle.

CX = Operator([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]])
psi = plus.tensor(zero)
display(psi.evolve(CX).draw("latex"))

2200+2211\frac{\sqrt{2}}{2} |00\rangle+\frac{\sqrt{2}}{2} |11\rangle

Misurazioni parziali

Nella lezione precedente abbiamo usato il metodo measure per simulare la misurazione di un vettore di stato quantistico. Questo metodo restituisce due elementi: il risultato simulato della misurazione e il nuovo Statevector dato tale risultato.

Per impostazione predefinita, measure misura tutti i qubit nel vettore di stato. In alternativa, possiamo fornire come argomento una lista di interi, che fa sì che vengano misurati solo i qubit con quegli indici. Per dimostrarlo, il codice seguente crea lo stato

w=001+010+1003\vert w\rangle = \frac{\vert 001\rangle + \vert 010\rangle + \vert 100\rangle}{\sqrt{3}}

e misura il qubit numero 0, ovvero il qubit più a destra. (Qiskit numera i qubit partendo da 0, da destra a sinistra. Torneremo su questa convenzione di numerazione nella prossima lezione.)

w = Statevector([0, 1, 1, 0, 1, 0, 0, 0] / sqrt(3))
display(w.draw("latex"))

result, state = w.measure([0])
print(f"Measured: {result}\nState after measurement:")
display(state.draw("latex"))

result, state = w.measure([0, 1])
print(f"Measured: {result}\nState after measurement:")
display(state.draw("latex"))

33001+33010+33100\frac{\sqrt{3}}{3} |001\rangle+\frac{\sqrt{3}}{3} |010\rangle+\frac{\sqrt{3}}{3} |100\rangle

Measured: 0
State after measurement:

22010+22100\frac{\sqrt{2}}{2} |010\rangle+\frac{\sqrt{2}}{2} |100\rangle

Measured: 00
State after measurement:

100 |100\rangle