Přeskočit na hlavní obsah

Kvantové algoritmy: Odhad fáze

poznámka

Kento Ueda (15. května 2024)

Tento notebook představuje základní pojmy a implementaci kvantové Fourierovy transformace (QFT) a kvantového odhadu fáze (QPE).

Stáhni si pdf původní přednášky. Pamatuj, že některé úryvky kódu mohou být zastaralé, protože jde o statické obrázky.

Přibližný čas QPU potřebný pro tento experiment je 7 sekund.

1. Úvod

Kvantová Fourierova transformace (QFT)

Kvantová Fourierova transformace je kvantovým protějškem klasické diskrétní Fourierovy transformace. Jde o lineární transformaci aplikovanou na kvantové stavy, která zobrazuje výpočetní báze do jejich reprezentací ve Fourierově bázi. QFT hraje klíčovou roli v mnoha kvantových algoritmech a poskytuje efektivní metodu pro získávání informací o periodicitě z kvantových stavů. QFT lze implementovat pomocí O(N2)O(N^2) operací s kvantovými hradly, jako jsou Hadamardova hradla a Control-Phase hradla pro NN Qubitů, což umožňuje exponenciální zrychlení oproti klasické Fourierově transformaci.

  • Aplikace: Tvoří základ kvantových algoritmů, jako je Shorův algoritmus pro faktorizaci velkých celých čísel a diskrétní logaritmus.

Kvantový odhad fáze (QPE)

Kvantový odhad fáze je kvantový algoritmus používaný k odhadu fáze spojené s vlastním vektorem unitárního operátoru. Tento algoritmus vytváří most mezi abstraktními matematickými vlastnostmi kvantových stavů a jejich výpočetními aplikacemi.

  • Aplikace: Umožňuje řešit úlohy, jako je hledání vlastních čísel unitárních matic a simulace kvantových systémů.

QFT a QPE společně tvoří zásadní páteř mnoha kvantových algoritmů řešících problémy, které jsou pro klasické počítače neproveditelné. Na konci tohoto notebooku získáš představu o tom, jak jsou tyto techniky implementovány.

2. Základy kvantové Fourierovy transformace (QFT)

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram, plot_bloch_multivector
from qiskit.quantum_info import Statevector
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler

from numpy import pi

Analogicky s diskrétní Fourierovou transformací QFT působí na kvantový stav X=j=0N1xjj\vert X\rangle = \sum_{j=0}^{N-1} x_j \vert j \rangle pro NN Qubitů a zobrazuje ho na kvantový stav Y=k=0N1ykk\vert Y\rangle = \sum_{k=0}^{N-1} y_k \vert k \rangle.

QFTN:j1Nk=0N1ωNjkkQFT_{N}: \vert j \rangle \mapsto \frac{1}{\sqrt{N}}\sum_{k=0}^{N-1}\omega_N^{jk} \vert k \rangle

kde ωNjk=e2πijkN\omega_N^{jk} = e^{2\pi i \frac{jk}{N}}.

Nebo reprezentace pomocí unitární matice:

UQFT=1Nj=0N1k=0N1ωNjkkjU_{QFT} = \frac{1}{\sqrt{N}} \sum_{j=0}^{N-1} \sum_{k=0}^{N-1} \omega_N^{jk} \vert k \rangle \langle j \vert

2.1. Intuice

Kvantová Fourierova transformace (QFT) převádí mezi dvěma bázemi: výpočetní (Z) bází a Fourierovou bází. Co však Fourierova báze v tomto kontextu znamená? Nejspíš si vybavíš, že Fourierova transformace F(ω)F(\omega) funkce f(x)f(x) popisuje konvoluci f(x)f(x) se sinusoidální funkcí o frekvenci ω\omega. Laicky řečeno: Fourierova transformace je funkce, která popisuje, kolik z každé frekvence ω\omega bychom potřebovali, abychom sestavili funkci f(x)f(x) ze sinových (nebo kosinových) funkcí. Abys lépe pochopil, co v tomto kontextu QFT znamená, podívej se na níže uvedené sekvenční obrázky, které ukazují číslo zakódované binárně pomocí čtyř Qubitů:

Ve výpočetní bázi ukládáme čísla binárně pomocí stavů 0|0\rangle a 1|1\rangle.

Všimni si frekvence, s jakou se jednotlivé Qubity mění; nejlevější Qubit se překlápí při každém zvýšení čísla, další při každých 2 zvýšeních, třetí při každých 4 zvýšeních a tak dále.

Pokud na tyto stavy aplikujeme kvantovou Fourierovu transformaci, zobrazíme

State in Computational BasisQFTState in Fourier Basis|\text{State in Computational Basis}\rangle \quad \xrightarrow[]{\text{QFT}} \quad |\text{State in Fourier Basis}\rangle QFTx=x~\text{QFT}|x\rangle = |\widetilde{x}\rangle

(Stavy ve Fourierově bázi často označujeme pomocí vlnovky (~)).

Ve Fourierově bázi ukládáme čísla pomocí různých rotací kolem osy Z:

IFRAME

Úhel, o který se každý Qubit kolem osy Z otočí, určuje číslo, které chceme uložit. Ve stavu 0~|\widetilde{0}\rangle jsou všechny Qubity ve stavu +|{+}\rangle. Jak je vidět ve výše uvedeném příkladu, k zakódování stavu 5~|\widetilde{5}\rangle na 4 Qubitech jsme nejlevější Qubit otočili o 52n=516\tfrac{5}{2^n} = \tfrac{5}{16} celé otáčky (516×2π\tfrac{5}{16}\times 2\pi radiánů). Další Qubit je otočen o dvojnásobek (1016×2π\tfrac{10}{16}\times 2\pi radiánů, tedy 10/1610/16 celé otáčky), tento úhel se pak zdvojnásobuje pro další Qubit a tak dále.

Opět si všimni frekvence, s jakou se jednotlivé Qubity mění. Nejlevější Qubit (qubit 0) má v tomto případě nejnižší frekvenci a ten nejpravější nejvyšší.

2.2 Příklad: 1qubitová QFT

Uvažujme případ N=21=2N = 2^1 = 2.

Unitární matici lze zapsat:

UQFT=12j=01k=01ω2jkkj=12(ω2000+ω2001+ω2010+ω2111)=12(00+01+1011)=H\begin{aligned} U_{QFT} & = \frac{1}{\sqrt{2}} \sum_{j=0}^{1} \sum_{k=0}^{1} \omega_2^{jk} \vert k \rangle \langle j \vert \\ & = \frac{1}{\sqrt{2}} (\omega_2^{0} \vert 0 \rangle \langle 0 \vert + \omega_2^{0} \vert 0 \rangle \langle 1 \vert + \omega_2^{0} \vert 1 \rangle \langle 0 \vert + \omega_2^{1} \vert 1 \rangle \langle 1 \vert) \\ & = \frac{1}{\sqrt{2}} (\vert 0 \rangle \langle 0 \vert + \vert 0 \rangle \langle 1 \vert + \vert 1 \rangle \langle 0 \vert - \vert 1 \rangle \langle 1 \vert) \\ & = H \end{aligned}

Tato operace je výsledkem aplikace Hadamardova Gate (HH).

2.3 Reprezentace QFT jako součinu

Zobecněme transformaci pro N=2nN = 2^n, QFTNQFT_{N} působící na stav x=x1xn\vert x \rangle = \vert x_1\ldots x_n \rangle.

QFTNx=1Ny=0N1ωNxyy=1Ny=0N1e2πixy/2ny protozˇeωNxy=e2πixyNaN=2n=1Ny=0N1e2πi(k=1nyk/2k)xy1ynprˇepsaˊno do zlomkoveˊ binaˊrnıˊ notacey=y1yn,y/2n=k=1nyk/2k=1Ny=0N1k=1ne2πixyk/2ky1ynpo rozepsaˊnıˊ exponenciaˊly soucˇtu na soucˇin exponenciaˊl,=1Nk=1n(0+e2πix/2k1)po prˇerovnaˊnıˊ sum a soucˇinu˚ a rozepsaˊnıˊy=0N1=y1=01y2=01yn=01=1N(0+e2πi2x1)(0+e2πi22x1)(0+e2πi2n1x1)(0+e2πi2nx1)\begin{aligned} QFT_N\vert x \rangle & = \frac{1}{\sqrt{N}} \sum_{y=0}^{N-1}\omega_N^{xy} \vert y \rangle \\ & = \frac{1}{\sqrt{N}} \sum_{y=0}^{N-1} e^{2 \pi i xy / 2^n} \vert y \rangle ~\text{protože}\: \omega_N^{xy} = e^{2\pi i \frac{xy}{N}} \:\text{a}\: N = 2^n \\ & = \frac{1}{\sqrt{N}} \sum_{y=0}^{N-1} e^{2 \pi i \left(\sum_{k=1}^n y_k/2^k\right) x} \vert y_1 \ldots y_n \rangle \:\text{přepsáno do zlomkové binární notace}\: y = y_1\ldots y_n, y/2^n = \sum_{k=1}^n y_k/2^k \\ & = \frac{1}{\sqrt{N}} \sum_{y=0}^{N-1} \prod_{k=1}^n e^{2 \pi i x y_k/2^k } \vert y_1 \ldots y_n \rangle \:\text{po rozepsání exponenciály součtu na součin exponenciál,} \\ & = \frac{1}{\sqrt{N}} \bigotimes_{k=1}^n \left(\vert0\rangle + e^{2 \pi i x /2^k } \vert1\rangle \right) \:\text{po přerovnání sum a součinů a rozepsání} \sum_{y=0}^{N-1} = \sum_{y_1=0}^{1}\sum_{y_2=0}^{1}\ldots\sum_{y_n=0}^{1} \\ & = \frac{1}{\sqrt{N}} \left(\vert0\rangle + e^{\frac{2\pi i}{2}x} \vert1\rangle\right) \otimes \left(\vert0\rangle + e^{\frac{2\pi i}{2^2}x} \vert1\rangle\right) \otimes \ldots \otimes \left(\vert0\rangle + e^{\frac{2\pi i}{2^{n-1}}x} \vert1\rangle\right) \otimes \left(\vert0\rangle + e^{\frac{2\pi i}{2^n}x} \vert1\rangle\right) \end{aligned}

2.4 Příklad: Konstrukce obvodu pro 3qubitovou QFT

Z výše uvedeného popisu nemusí být zřejmé, jak sestrojit QFT Circuit. Prozatím si jen všimni, že očekáváme, že tři Qubits budou mít fáze, které se vyvíjejí různými „rychlostmi“. Přesné pochopení, jak se to promítá do Circuit, je ponecháno jako cvičení pro čtenáře. V přednáškovém pdf najdeš řadu diagramů a příkladů. Mezi další zdroje patří tato lekce z kurzu Fundamentals of quantum algorithms.

QFT budeme demonstrovat pouze pomocí simulátorů, a tak nebudeme používat framework Qiskit patterns, dokud nepřejdeme ke kvantovému odhadu fáze.

# Prepare for 3 qubits circuit
qr = QuantumRegister(3)
cr = ClassicalRegister(3)
qc = QuantumCircuit(qr, cr)
qc.h(2)
qc.cp(pi / 2, 1, 2) # Controlled-phase gate from qubit 1 to qubit 2
qc.cp(pi / 4, 0, 2) # Controlled-phase gate from qubit 0 to qubit 2
qc.draw(output="mpl")

Výstup předchozí buňky kódu

qc.h(1)
qc.cp(pi / 2, 0, 1) # Controlled-phase gate from qubit 0 to qubit 1

qc.draw(output="mpl")

Výstup předchozí buňky kódu

qc.h(0)

qc.draw(output="mpl")

Výstup předchozí buňky kódu

qc.swap(0, 2)

qc.draw(output="mpl")

Výstup předchozí buňky kódu

Jako příklad zkusíme aplikovat QFT na 5|5\rangle.

Nejprve potvrdíme binární zápis celého čísla 5 a vytvoříme Circuit kódující stav 5:

bin(5)
'0b101'
qc = QuantumCircuit(3)

qc.x(0)
qc.x(2)
qc.draw(output="mpl")

Výstup předchozí buňky kódu

Kvantové stavy zkontrolujeme pomocí simulátoru Aer:

statevector = Statevector(qc)
plot_bloch_multivector(statevector)

Výstup předchozí buňky kódu

Nakonec přidáme QFT a podíváme se na výsledný stav našich Qubits:

qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)

qc.h(1)
qc.cp(pi / 2, 0, 1)

qc.h(0)

qc.swap(0, 2)

qc.draw(output="mpl")

Výstup předchozí buňky kódu

statevector = Statevector(qc)
plot_bloch_multivector(statevector)

Výstup předchozí buňky kódu

Vidíme, že naše funkce QFT zafungovala správně. Qubit 0 byl otočen o 58\tfrac{5}{8} plné otáčky, qubit 1 o 108\tfrac{10}{8} plné otáčky (což odpovídá 14\tfrac{1}{4} plné otáčky) a qubit 2 o 208\tfrac{20}{8} plné otáčky (což odpovídá 12\tfrac{1}{2} plné otáčky).

2.5 Cvičení: QFT

(1) Implementuj QFT pro 4 qubity.

##your code goes here##

(2) Aplikuj QFT na 14|14\rangle, simuluj a vykresli stavový vektor pomocí Blochovy sféry.

##your code goes here##

Řešení cvičení: QFT

(1)

qr = QuantumRegister(4)
cr = ClassicalRegister(4)
qc = QuantumCircuit(qr, cr)

qc.h(3)
qc.cp(pi / 2, 2, 3)
qc.cp(pi / 4, 1, 3)
qc.cp(pi / 8, 0, 3)

qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)

qc.h(1)
qc.cp(pi / 2, 0, 1)

qc.h(0)

qc.swap(0, 3)
qc.swap(1, 2)

qc.draw(output="mpl")

Output of the previous code cell

(2)

bin(14)
'0b1110'
qc = QuantumCircuit(4)

qc.x(1)
qc.x(2)
qc.x(3)
qc.draw("mpl")

Output of the previous code cell

qc.h(3)
qc.cp(pi / 2, 2, 3)
qc.cp(pi / 4, 1, 3)
qc.cp(pi / 8, 0, 3)

qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)

qc.h(1)
qc.cp(pi / 2, 0, 1)
qc.h(0)

qc.swap(0, 3)
qc.swap(1, 2)

qc.draw(output="mpl")

Output of the previous code cell

statevector = Statevector(qc)
plot_bloch_multivector(statevector)

Output of the previous code cell

3. Základy odhadu kvantové fáze (QPE)

Pro danou unitární operaci UU QPE odhaduje θ\theta v Uψ=e2πiθψU\vert\psi \rangle =e^{\boldsymbol{2\pi i} \theta }|\psi \rangle, protože UU je unitární, všechny jeho vlastní hodnoty mají normu 1.

3.1 Postup

1. Nastavení

ψ\vert\psi\rangle se nachází v jedné sadě qubitových registrů. Další sada nn qubitů tvoří čítací registr, do kterého uložíme hodnotu 2nθ2^n\theta:

ψ0=0nψ|\psi_0\rangle = \lvert 0 \rangle^{\otimes n} \lvert \psi \rangle

2. Superpozice

Aplikuj nn-bitovou operaci Hadamardova Gate HnH^{\otimes n} na čítací registr:

ψ1=12n2(0+1)nψ|\psi_1\rangle = {\frac {1}{2^{\frac {n}{2}}}}\left(|0\rangle +|1\rangle \right)^{\otimes n} \lvert \psi \rangle

3. Řízené unitární operace

Potřebujeme zavést řízené unitární CUCU, které aplikuje unitární operátor UU na cílový registr pouze tehdy, pokud příslušný řídicí bit je 1|1\rangle. Protože UU je unitární operátor s vlastním vektorem ψ|\psi\rangle takovým, že Uψ=e2πiθψU|\psi \rangle =e^{\boldsymbol{2\pi i} \theta }|\psi \rangle, platí:

U2jψ=U2j1Uψ=U2j1e2πiθψ==e2πi2jθψU^{2^{j}}|\psi \rangle =U^{2^{j}-1}U|\psi \rangle =U^{2^{j}-1}e^{2\pi i\theta }|\psi \rangle =\cdots =e^{2\pi i2^{j}\theta }|\psi \rangle

3.2 Příklad: T-gate QPE

Použijme T-gate jako příklad QPE a odhadněme jeho fázi θ\theta.

T1=(100eiπ4)(01)=eiπ41T|1\rangle = \begin{pmatrix} 1 & 0\\ 0 & e^\frac{i\pi}{4}\\ \end{pmatrix} \begin{pmatrix} 0\\ 1\\ \end{pmatrix} = e^\frac{i\pi}{4}|1\rangle

Očekáváme, že najdeme:

θ=18\theta = \frac{1}{8}

kde

T1=e2iπθ1T|1\rangle = e^{2i\pi\theta}|1\rangle

Inicializujeme ψ=1\vert\psi\rangle = \vert1\rangle vlastního vektoru T-gate aplikací Gate XX:

qpe = QuantumCircuit(4, 3)
qpe.x(3)
qpe.draw(output="mpl")

Output of the previous code cell

Dále aplikujeme Hadamardovy Gate na čítací Qubit:

for qubit in range(3):
qpe.h(qubit)
qpe.draw(output="mpl")

Output of the previous code cell

Provedeme řízené unitární operace:

repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(pi / 4, counting_qubit, 3) # This is C-U
repetitions *= 2
qpe.draw(output="mpl")

Output of the previous code cell

Aplikujeme inverzní kvantovou Fourierovu transformaci pro převod stavu čítacího registru a poté změříme čítací registr:

from qiskit.circuit.library import QFT
# Apply inverse QFT
qpe.append(QFT(3, inverse=True), [0, 1, 2])
qpe.draw(output="mpl")

Output of the previous code cell

for n in range(3):
qpe.measure(n, n)
qpe.draw(output="mpl")

Output of the previous code cell

Můžeme simulovat pomocí simulátoru Aer:

aer_sim = AerSimulator()
shots = 2048

pm = generate_preset_pass_manager(backend=aer_sim, optimization_level=1)
t_qpe = pm.run(qpe)

sampler = Sampler(mode=aer_sim)
job = sampler.run([t_qpe], shots=shots)
result = job.result()
answer = result[0].data.c.get_counts()

plot_histogram(answer)

Output of the previous code cell

Vidíme, že s jistotou dostaneme jeden výsledek (001), který se převede na desetinné číslo: 1. Nyní potřebujeme náš výsledek (1) vydělit 2n2^n, abychom dostali θ\theta:

θ=123=18\theta = \frac{1}{2^3} = \frac{1}{8}

Shorův algoritmus nám umožňuje faktorizovat číslo tím, že sestavíme Circuit s neznámým θ\theta a získáme θ\theta.

3.3 Cvičení

Odhadni θ=1/3\theta = 1/3 pomocí 3 qubitů pro počítání a jednoho qubitu pro vlastní vektor.

P1=eiλ1P|1\rangle = e^{i\lambda}|1\rangle. Protože chceme implementovat U1=e2πi131U|1\rangle = e^{2\pi i \tfrac{1}{3}}|1\rangle, musíme nastavit λ=2π3\lambda = \tfrac{2 \pi}{3}.

##your code goes here##

Řešení cvičení: θ=1/3\theta = 1/3

# Create and set up circuit
qpe = QuantumCircuit(4, 3)

# Apply H-Gates to counting qubits:
for qubit in range(3):
qpe.h(qubit)

# Prepare our eigenstate |psi>:
qpe.x(3)

# Do the controlled-U operations:
angle = 2 * pi / 3
repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(angle, counting_qubit, 3)
repetitions *= 2

# Do the inverse QFT:
qpe.append(QFT(3, inverse=True), [0, 1, 2])

for n in range(3):
qpe.measure(n, n)

qpe.draw(output="mpl")

Output of the previous code cell

aer_sim = AerSimulator()
shots = 4096

pm = generate_preset_pass_manager(backend=aer_sim, optimization_level=1)
t_qpe = pm.run(qpe)

sampler = Sampler(mode=aer_sim)
job = sampler.run([t_qpe], shots=shots)
result = job.result()
answer = result[0].data.c.get_counts()

plot_histogram(answer)

Output of the previous code cell

4. Spuštění pomocí primitivy Qiskit Runtime Sampler

Provedeme QPE na skutečném kvantovém zařízení a budeme postupovat podle 4 kroků Qiskit patterns.

  1. Namapuj problém do kvantově nativního formátu
  2. Optimalizuj obvody
  3. Spusť cílový Circuit
  4. Post-procesuj výsledky
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Sampler
# Loading your IBM Quantum® account(s)

service = QiskitRuntimeService()

4.1 Krok 1: Namapuj problém na kvantové obvody a operátory

qpe = QuantumCircuit(4, 3)
qpe.x(3)
for qubit in range(3):
qpe.h(qubit)
repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(pi / 4, counting_qubit, 3) # This is C-U
repetitions *= 2
qpe.append(QFT(3, inverse=True), [0, 1, 2])
for n in range(3):
qpe.measure(n, n)
qpe.draw(output="mpl")

Výstup předchozí buňky s kódem

backend = service.least_busy(simulator=False, operational=True, min_num_qubits=4)

print(backend)
<IBMBackend('ibm_strasbourg')>

4.2 Krok 2: Optimalizace pro cílový hardware

# Transpile the circuit into basis gates executable on the hardware
pm = generate_preset_pass_manager(backend=backend, optimization_level=2)
qc_compiled = pm.run(qpe)

qc_compiled.draw("mpl", idle_wires=False)

Výstup předchozí buňky s kódem

4.3 Krok 3: Spuštění na cílovém hardware

real_sampler = Sampler(mode=backend)
job = real_sampler.run([qc_compiled], shots=1024)
job_id = job.job_id()
print("job id:", job_id)
job id: d13p4zb5z6q00087ag00
job = service.job(job_id)  # Input your job-id between the quotations
job.status()
'DONE'
result_real = job.result()
print(result_real)
PrimitiveResult([SamplerPubResult(data=DataBin(c=BitArray(<shape=(), num_shots=1024, num_bits=3>)), metadata={'circuit_metadata': {}})], metadata={'execution': {'execution_spans': ExecutionSpans([DoubleSliceSpan(<start='2025-06-09 22:39:00', stop='2025-06-09 22:39:00', size=1024>)])}, 'version': 2})

4.4 Krok 4: Post-procesování výsledků

from qiskit.visualization import plot_histogram

plot_histogram(result_real[0].data.c.get_counts())

Výstup předchozí buňky s kódem

# See the version of Qiskit
import qiskit

qiskit.__version__
'2.0.2'