Przejdź do głównej treści

Implementacja w Qiskit

W poprzedniej lekcji zapoznałeś się po raz pierwszy z klasami Statevector i Operator w Qiskit i użyłeś ich do symulowania operacji oraz pomiarów na pojedynczych qubitach. W tej sekcji użyjemy tych klas, żeby zbadać zachowanie wielu qubitów.

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

print(__version__)
2.1.1

Zaczniemy od zaimportowania klas Statevector i Operator oraz funkcji pierwiastka kwadratowego z NumPy. Od tej pory, co do zasady, będziemy dbać o to, żeby wszystkie wymagane importy znajdowały się na początku każdej lekcji.

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

Iloczyny tensorowe

Klasa Statevector ma metodę tensor, która zwraca iloczyn tensorowy danego Statevector z innym, podanym jako argument. Argument jest interpretowany jako czynnik tensorowy po prawej stronie.

Na przykład poniżej tworzymy dwa wektory stanu reprezentujące 0\vert 0\rangle i 1,\vert 1\rangle, i używamy metody tensor, żeby utworzyć nowy wektor ψ=01.\vert \psi\rangle = \vert 0\rangle \otimes \vert 1\rangle. Zauważ, że używamy tutaj metody from_label do zdefiniowania stanów 0\vert 0\rangle i 1,\vert 1\rangle, zamiast definiować je ręcznie.

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

01 |01\rangle

Inne dozwolone etykiety to „+" i „-" dla stanów plus i minus, a także „r" i „l" (skróty od „right" i „left") dla stanów

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

Tutaj „+", „-" lub „right" i „left" pochodzą z kontekstu kwantowomechanicznego spinu, w którym składowa spinu może wskazywać w lewo lub w prawo w doświadczeniu; nie chodzi tu o skrajnie prawy lub skrajnie lewy qubit w układach wieloqubitowych. Oto przykład iloczynu tensorowego +\vert {+} \rangle i 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

Alternatywą jest użycie operatora ^ do iloczynów tensorowych, który naturalnie daje te same wyniki.

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

Klasa Operator ma również metodę tensor (a także metodę from_label), co widać w poniższych przykładach.

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}

Podobnie jak w przypadku wektorów, operator ^ jest równoważny.

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}

Złożone stany można ewoluować za pomocą złożonych operacji dokładnie tak, jak można by się spodziewać — podobnie jak widzieliśmy dla pojedynczych układów w poprzedniej lekcji. Na przykład poniższy kod oblicza stan (HI)ϕ(H\otimes I)\vert\phi\rangle dla ϕ=+i\vert\phi\rangle = \vert + \rangle \otimes \vert {-i}\rangle (który został już zdefiniowany powyżej).

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

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

Oto kod, który definiuje operację CXCX i oblicza CXψCX \vert\psi\rangle dla ψ=+0.\vert\psi\rangle = \vert + \rangle \otimes \vert 0 \rangle. Żeby było jasne, jest to operacja CXCX, w której qubit po lewej stronie jest qubit kontrolny, a qubit po prawej stronie jest qubit docelowy. Wynikiem jest stan Bella ϕ+.\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

Pomiary cząstkowe

W poprzedniej lekcji użyliśmy metody measure do symulowania pomiaru wektora stanu kwantowego. Metoda ta zwraca dwie rzeczy: symulowany wynik pomiaru oraz nowy Statevector po tym pomiarze.

Domyślnie measure mierzy wszystkie qubity w wektorze stanu. Możemy alternatywnie podać listę liczb całkowitych jako argument, co powoduje, że mierzone są tylko qubity o tych indeksach. Żeby to zademonstrować, poniższy kod tworzy stan

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

i mierzy qubit numer 0, czyli qubit skrajnie prawy. (Qiskit numeruje qubity począwszy od 0, od prawej do lewej. Wrócimy do tej konwencji numerowania w następnej lekcji.)

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