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, ∣ψ⟩=∣0⟩⊗∣1⟩.\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⟩=12∣0⟩+i2∣1⟩e∣−i⟩=12∣0⟩−i2∣1⟩.\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"))

12∣00⟩−i2∣01⟩+12∣10⟩−i2∣11⟩\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"))

12∣00⟩−i2∣01⟩+12∣10⟩−i2∣11⟩\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"))
[220220022022220−2200220−22] \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} [0220002200220002200000022000220022000220022000−220022000−2200000022000−220022000−220] \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"))
[0220002200220002200000022000220022000220022000−220022000−2200000022000−220022000−220] \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 (H⊗I)∣ϕ⟩(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"))

22∣00⟩−2i2∣01⟩\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"))

22∣00⟩+22∣11⟩\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⟩+∣100⟩3\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"))

33∣001⟩+33∣010⟩+33∣100⟩\frac{\sqrt{3}}{3} |001\rangle+\frac{\sqrt{3}}{3} |010\rangle+\frac{\sqrt{3}}{3} |100\rangle

Measured: 0
State after measurement:

22∣010⟩+22∣100⟩\frac{\sqrt{2}}{2} |010\rangle+\frac{\sqrt{2}}{2} |100\rangle

Measured: 00
State after measurement:

∣100⟩ |100\rangle