Přeskočit na hlavní obsah

Implementace v Qiskitu

V teto sekci se podivame na nektere implementace v Qiskitu pro koncepty predstavene v teto lekci. Pokud si chces tyto implementace spustit sam/sama, coz vrele doporucujeme, podivej se na stranku Instalace Qiskitu v dokumentaci IBM Quantum, kde najdes podrobnosti o nastaveni Qiskitu.

Je dulezite mit na pameti, ze Qiskit je neustale vyvijen a je primarne zameren na maximalizaci vykonu kvantovych pocitacu, ktere pomoci nej ovladas a ktere se samy stale vyviji. V dusledku toho se Qiskit meni, coz muze obcas vest k zastaravani kodu. S ohledem na to vzdy pred ukazkami kodu v Qiskitu v tomto kurzu spustime nasledujici prikazy, aby bylo jasne, ktera verze Qiskitu byla pouzita. Od verze Qiskit v1.0 je to jednoduchy zpusob, jak zjistit aktualne nainstalovanu verzi Qiskitu.

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

print(__version__)
2.1.1

Pokud to spoustis v cloudovem prostredi Pythonu, muzes potrebovat nainstalovat nektere z nasledujicich balicku:

#!pip install qiskit
#!pip install jupyter
#!pip install sympy
#!pip install matplotlib
#!pip install pylatexenc

Vektory a matice v Pythonu

Qiskit pouziva programovaci jazyk Python, takze nez budeme mluvit konkretne o Qiskitu, muze byt uzitecne si velmi strucne projit vypocty s maticemi a vektory v Pythonu.

V Pythonu lze vypocty s maticemi a vektory provadet pomoci tridy array z knihovny NumPy, ktera poskytuje funkcionalitu pro mnoho numerickych a vedeckych vypoctu. Nasledujici kod nacte tuto knihovnu, definuje dva sloupcove vektory, ket0 a ket1, odpovidajici stavovym vektorum Qubit 0\vert 0\rangle a 1,\vert 1\rangle, a pote vypise jejich prumer.

import numpy as np

ket0 = np.array([[1], [0]])
ket1 = np.array([[0], [1]])

print(ket0 / 2 + ket1 / 2)
[[0.5]
[0.5]]

Pomoci array muzeme take vytvaret matice reprezentujici operace.

M1 = np.array([[1, 1], [0, 0]])
M2 = np.array([[1, 0], [0, 1]])
M = M1 / 2 + M2 / 2
print(M)
[[1.  0.5]
[0. 0.5]]

Vezmi prosim na vedomi, ze veskerý kod v dane lekci tohoto kurzu se ocekava, ze bude spousten postupne. Proto zde nemusime znovu importovat NumPy, protoze uz byl naimportovan.

Nasobeni matic, vcetne nasobeni matice vektorem jako specialniho pripadu, lze provadet pomoci funkce matmul z NumPy.

print(np.matmul(M1, ket1))
print(np.matmul(M1, M2))
print(np.matmul(M, M))
[[1]
[0]]
[[1 1]
[0 0]]
[[1. 0.75]
[0. 0.25]]

Toto formatovani vystupu neni vizualne uplne idealni. Jednim resenim pro situace, kdy potrebujes neco hezciho, je pouziti funkce array_to_latex v Qiskitu z modulu qiskit.visualization. Vsimni si, ze v nasledujicim kodu pouzivame obecnou funkci Pythonu display. Naproti tomu konkretni chovani print muze zaviset na tom, co se tiskne, jako je tomu u poli definovanych pomoci NumPy.

from qiskit.visualization import array_to_latex

display(array_to_latex(np.matmul(M1, ket1)))
display(array_to_latex(np.matmul(M1, M2)))
display(array_to_latex(np.matmul(M, M)))
[10] \begin{bmatrix} 1 \\ 0 \\ \end{bmatrix} [1100] \begin{bmatrix} 1 & 1 \\ 0 & 0 \\ \end{bmatrix} [134014] \begin{bmatrix} 1 & \frac{3}{4} \\ 0 & \frac{1}{4} \\ \end{bmatrix}

Stavy, mereni a operace

Qiskit obsahuje nekolik trid, ktere umoznuji vytvaret a manipulovat se stavy, merenimi a operacemi -- takze neni treba programovat vse potrebne pro simulaci kvantovych stavu, mereni a operaci v Pythonu od nuly. Nize jsou uvedeny nektere priklady, ktere ti pomohou zacit.

Definice a zobrazeni stavovych vektoru

Trida Statevector v Qiskitu poskytuje funkcionalitu pro definovani a manipulaci s kvantovymi stavovymi vektory. V nasledujicim kodu je naimportovana trida Statevector a definovano nekolik vektoru. (Take importujeme funkci sqrt z knihovny NumPy pro vypocet odmocniny. Tuto funkci lze alternativne volat jako np.sqrt za predpokladu, ze NumPy jiz byl naimportovan, jak tomu bylo vyse; jde pouze o jiny zpusob importu a pouziti teto konkretni funkce.)

from qiskit.quantum_info import Statevector
from numpy import sqrt

u = Statevector([1 / sqrt(2), 1 / sqrt(2)])
v = Statevector([(1 + 2.0j) / 3, -2 / 3])
w = Statevector([1 / 3, 2 / 3])

Trida Statevector obsahuje metodu draw pro zobrazeni stavovych vektoru ruznymi zpusoby, vcetne text pro cisty text, latex pro vykresleny LaTeX a latex_source pro zdrojovy kod LaTeXu, coz se muze hodit pro kopirovani do dokumentu. (Pro zobrazeni LaTeX kodu pouzij print misto display pro nejlepsi vysledky.)

display(u.draw("text"))
display(u.draw("latex"))
print(u.draw("latex_source"))
[0.70710678+0.j,0.70710678+0.j]

220+221\frac{\sqrt{2}}{2} |0\rangle+\frac{\sqrt{2}}{2} |1\rangle

\frac{\sqrt{2}}{2} |0\rangle+\frac{\sqrt{2}}{2} |1\rangle

Trida Statevector take obsahuje metodu is_valid, ktera overuje, zda je dany vektor platnym kvantovym stavovym vektorem (jinymi slovy, ze ma euklidovskou normu rovnou 1): Trida Statevector take obsahuje metodu is_valid, ktera overuje, zda je dany vektor platnym kvantovym stavovym vektorem (jinymi slovy, ze ma euklidovskou normu rovnou 1):

display(u.is_valid())
display(w.is_valid())
True
False

Simulace mereni pomoci Statevector

Dale se podivame na jeden zpusob, jak lze v Qiskitu simulovat mereni kvantovych stavu, a to pomoci metody measure z tridy Statevector. Pouzijme stejny stavovy vektor Qubit v, ktery jsme definovali drive.

display(v.draw("latex"))

(13+2i3)0231(\frac{1}{3} + \frac{2 i}{3}) |0\rangle- \frac{2}{3} |1\rangle

Spusteni metody measure simuluje mereni ve standardni bazi. Vrati vysledek tohoto mereni a novy kvantovy stavovy vektor systemu po mereni. (Zde pouzivame Pythonovou funkci print s prefixem f pro formatovany vystup s vlozenymi vyrazy.)

outcome, state = v.measure()
print(f"Measured: {outcome}\nPost-measurement state:")
display(state.draw("latex"))
Measured: 1
Post-measurement state:

1- |1\rangle

Vysledky mereni jsou pravdepodobnostni, takze tato metoda muze pri opakovanem spusteni vracet ruzne vysledky. Pro konkretni priklad vektoru v definovaneho vyse metoda measure definuje kvantovy stavovy vektor po mereni jako

(1+2i5)0\biggl(\frac{1 + 2i}{\sqrt{5}}\biggr) \vert 0\rangle

(misto 0\vert 0\rangle) nebo

1- \vert 1\rangle

(misto 1\vert 1\rangle), v zavislosti na vysledku mereni. V obou pripadech jsou alternativy k 0\vert 0\rangle a 1\vert 1\rangle ve skutecnosti ekvivalentni temto stavovym vektorum; rika se, ze jsou ekvivalentni az na globalni fazi, protoze jeden se rovna druhemu vynasobenemu komplexnim cislem na jednotkove kruznici. Tato problematika je podrobneji probrána v lekci Kvantove Circuit a prozatim ji muzete bezpecne ignorovat.

Statevector vyhodi chybu, pokud je metoda measure aplikovana na neplatny kvantovy stavovy vektor.

Statevector take disponuje metodou sample_counts, ktera umoznuje simulovat libovolny pocet mereni na systemu, pricemz pokazde zacina s novou kopii stavu. Napriklad nasledujici kod ukazuje vysledek mereni vektoru v 10001000 krat, coz (s vysokou pravdepodobnosti) vede k vysledku 00 priblizne 55 z kazych 99 pripadu (neboli asi 556556 z 10001000 pokusu) a k vysledku 11 priblizne 44 z kazych 99 pripadu (neboli asi 444444 z 10001000 pokusu). Nasledujici kod take demonstruje funkci plot_histogram z modulu qiskit.visualization pro vizualizaci vysledku.

from qiskit.visualization import plot_histogram

statistics = v.sample_counts(1000)
plot_histogram(statistics)

Output of the previous code cell

Spusteni tohoto kodu vicekrat s ruznymi pocty vzorku misto 1000,1000, ti muze pomoci vybudovat intuici pro to, jak pocet pokusu ovlivnuje pocet vyskytu jednotlivych vysledku. S vice a vice vzorky se podil vzorku pro kazdou moznost pravdepodobne priblizuje odpovidajici pravdepodobnosti. Tento jev je obecneji znam jako zakon velkych cisel v teorii pravdepodobnosti.

Provadeni operaci pomoci Operator a Statevector

Unitarni operace lze v Qiskitu definovat pomoci tridy Operator, jak ukazuje nasledujici priklad. Tato trida obsahuje metodu draw s podobnymi argumenty jako Statevector. Vezmi na vedomi, ze volba latex produkuje vysledky ekvivalentni array_from_latex.

from qiskit.quantum_info import Operator

Y = Operator([[0, -1.0j], [1.0j, 0]])
H = Operator([[1 / sqrt(2), 1 / sqrt(2)], [1 / sqrt(2), -1 / sqrt(2)]])
S = Operator([[1, 0], [0, 1.0j]])
T = Operator([[1, 0], [0, (1 + 1.0j) / sqrt(2)]])

display(T.draw("latex"))
[10022+2i2] \begin{bmatrix} 1 & 0 \\ 0 & \frac{\sqrt{2}}{2} + \frac{\sqrt{2} i}{2} \\ \end{bmatrix}

Unitarni operaci muzeme na stavovy vektor aplikovat pomoci metody evolve.

v = Statevector([1, 0])

v = v.evolve(H)
v = v.evolve(T)
v = v.evolve(H)
v = v.evolve(S)
v = v.evolve(Y)

display(v.draw("latex"))

(0.14644660940.3535533906i)0+(0.3535533906+0.8535533906i)1(0.1464466094 - 0.3535533906 i) |0\rangle+(-0.3535533906 + 0.8535533906 i) |1\rangle

Nahled na kvantove Circuit

Kvantove Circuit budou formalne predstaveny az v lekci Kvantove Circuit, coz je treti lekce v tomto kurzu, ale uz ted si muzeme vyzkouset skladani unitarnich operaci na Qubit pomoci tridy QuantumCircuit v Qiskitu. Konkretne muzeme definovat kvantovy Circuit (ktery v tomto pripade bude jednodusse sekvenci unitarnich operaci provedenych na jednom Qubit) nasledovne.

from qiskit import QuantumCircuit

circuit = QuantumCircuit(1)

circuit.h(0)
circuit.t(0)
circuit.h(0)
circuit.s(0)
circuit.y(0)

display(circuit.draw(output="mpl"))

Output of the previous code cell

Zde pouzivame metodu draw z tridy QuantumCircuit s rendererem mpl (zkratka pro Matplotlib, vizualizacni knihovnu Pythonu). Toto je jediny renderer, ktery budeme pro kvantove Circuit v tomto kurzu pouzivat, ale existuji i dalsi moznosti, vcetne textoveho a LaTeX rendereru.

Operace se aplikuji sekvencne, od leve strany diagramu smerem doprava. Sikovny zpusob, jak ziskat unitarni matici odpovidajici tomuto Circuit, je pouzit metodu from_circuit z tridy Operator.

display(Operator.from_circuit(circuit).draw("latex"))
[0.14644660940.3535533906i0.8535533906+0.3535533906i0.3535533906+0.8535533906i0.3535533906+0.1464466094i] \begin{bmatrix} 0.1464466094 - 0.3535533906 i & 0.8535533906 + 0.3535533906 i \\ -0.3535533906 + 0.8535533906 i & 0.3535533906 + 0.1464466094 i \\ \end{bmatrix}

Muzeme take inicializovat pocatecni kvantovy stavovy vektor a pak ho nechat vyvijt podle sekvence operaci popsane Circuit.

ket0 = Statevector([1, 0])
v = ket0.evolve(circuit)
display(v.draw("latex"))

(0.14644660940.3535533906i)0+(0.3535533906+0.8535533906i)1(0.1464466094 - 0.3535533906 i) |0\rangle+(-0.3535533906 + 0.8535533906 i) |1\rangle

Nasledujici kod simuluje experiment, ve kterem je stav ziskany z vyse uvedeneho Circuit meren standardnim bazovym merenim 4000 krat (pokazde s novou kopii stavu).

statistics = v.sample_counts(4000)
display(plot_histogram(statistics))

Output of the previous code cell