Kanały kwantowe, inaczej opracje kwantowe, to najbardziej podstawowa forma zapisu dla transformacji stanu kwantowego bez wnikania w wewnętrzną naturę procesu. Najprościej mówiąc kanał kwantowy to operacja
$\rho\rightarrow \rho'=E(\rho)$
Opis taki ma szereg zastosowań. Może obrazować ewolucję kwantową, dekoherencję, operacje kwantowe związane z kwantowymi bramkami logicznymi.
Tutaj ograniczymy się do przypadku, gdy $\rho'$ jest stanem, to znaczy zakładamy, że kanał kwantowy ma reprezentację Kraussa:
$E(\rho)=\sum_i K_i \rho K_i^\dagger$
ograniczenie to oznacza, że nie rozważamy problemów niemarkowowskich (zależnych od czasu) oraz pomiarów kwantowych.
Operatory $K_i$ spełniać muszą warunek:
$\sum_i K_i^\dagger K_i\le\mathbf{I}$
Uwaga warunek $\sum_i K_i^\dagger K_i=\mathbf{I}$ gwarantuje, że $E(\rho)$ jest stanem
Dla zilustriowania uzyteczności formalizmu Kraussa rozważmy ewolucję unitarną układu $A$ i jego "otoczenia" $B$:
$\rho^{AB}=U^{AB} \rho^A\otimes |i_B\rangle\langle i_B| U^{AB\dagger}$
obliczając ślad częściowy:
$\rho_A'=\mbox{Tr}_B \rho^{AB} =\sum_n \langle e_n^B|U^{AB}|i^B\rangle \rho^A \langle i^B |U^{AB\dagger} |e_n^B\rangle$
wprowadzając $K_n =\langle e_n^B|U^{AB}|i^B\rangle$
otrzymujemy
$E(\rho^A)=\sum_n K_n\rho^A k_n^\dagger$
Zauważmy, że
$\sum_n K_n^\dagger K_n=\mathbf{I}$
Dalej zbudujemy implementację numeryczną najbardziej typowych kanałów kwantowych. Ograniczamy się do kanałów kwantowych określonych na stanach qubitów:
from qutip import *
from pylab import *
%pylab inline
Populating the interactive namespace from numpy and matplotlib
WARNING: pylab import has clobbered these variables: ['power', 'linalg', 'draw_if_interactive', 'random', 'save', 'load', 'info', 'fft'] `%pylab --no-import-all` prevents importing * from pylab and numpy
Wprowadźmy uproszczone oznaczenia dla wektorów bazy:
up=basis(2,0)
dn=basis(2,1)
oraz macierzy bazowych
rpp=up*up.dag()
rpm=up*dn.dag()
rmp=rpm.trans()
rmm=dn*dn.dag()
następnie zdefiniujemy funkcję depol() opisującą kanał depolaryzacujmy:
$E(\rho)=\sum_{n=0}^4 K_n \rho K_n$,
gdzie $K_0=\sqrt{1-p}\mathbf{I}$ zaś $K_i=\sqrt{p/3}\sigma_i$, $i=x,y,x$
def depol(rho,p):
K0=sqrt(1.0-p)*qeye(2)
K1=sqrt(p/3.0)*sigmax()
K2=sqrt(p/3.0)*sigmay()
K3=sqrt(p/3.0)*sigmaz()
x=K0*rho*K0.dag()+K1*rho*K1.dag()+K2*rho*K2.dag()+K3*rho*K3.dag()
return x
Możemy sprawdzić dla wybranych $p$ warunek zachowania śladu: $\sum_n K_n^\dagger K_n=\mathbf{I}$:
p=0.8
K0=sqrt(1.0-p)*qeye(2)
K1=sqrt(p/3.0)*sigmax()
K2=sqrt(p/3.0)*sigmay()
K3=sqrt(p/3.0)*sigmaz()
K0*K0.dag()+K1*K1.dag()+K2*K2.dag()+K3*K3.dag()
Kolejnym użytecznym kanałem jest kanał tłumienia fazy (phase damping channel).
$K_0=|1\rangle\langle 1| +\sqrt{1-p}|0\rangle\langle 0|$, $K_1=\sqrt{p} |1\rangle\langle 0|$
działanie takiego kanału opisuje funkcja damp():
def damp(rho,p):
K0=rpp+sqrt(1.0-p)*rmm
K1=sqrt(p)*rpm
x=K0*rho*K0.dag()+K1*rho*K1.dag()
return x
Ostanim z rozważanych typów kanałów jest kanał odwrócenia fazu (phase flip channel) opisany funkcją flip():
def flip(rho,p):
K0=sqrt(p)*sigmaz()
K1=sqrt(1.0-p)*qeye(2)
x=K0*rho*K0.dag()+K1*rho*K1.dag()
return x
Teraz jesteśmy gotowi do przygotowania wizualizacji wybranej charakterystyki kanału. Założymy na wejściu stan czysty:
psi=(up+dn).unit()
i jego macierz gęstości:
rho=ket2dm(psi)
W następnym kroku zdefiniujemy listy z wartościami $p$ oraz wynikami:
plist=linspace(0,1.0,10.0)
slist=zeros(len(plist))
Niech intersującą charakterystyką stanu wyjściowego będzie entropia von Neumanna:
for i1 in range(len(plist)):
p=plist[i1]
rho1=depol(rho,p)
slist[i1]=entropy_vn(rho1)
Uzyskany wynik możemy wykreślić:
plot(plist,slist,'-',label='', linewidth=4)
xlabel('p',fontsize=20)
ylabel('SvN',fontsize=20)
show()
Teraz rozważmy problem bardziej złożony. Załóżmy, że w parze qubitów przygotowanych w stanie Bella:
BB0=(tensor(rpp,rmm)+tensor(rpm,rmp)+tensor(rmp,rpm)+tensor(rmm,rpp))/2.0
jeden z qubitów podlega kanałowi depolaryzacyjnemu z $p=0.4$. Spóbujmy określić wpływ tego kanału na wartość splątania stanu pary qubitów. Rozpocznujmy od obliczenia działania depolaryzacji na stany bazowe:
p=0.4
rpp1=depol(rpp,p)
rpm1=depol(rpm,p)
rmp1=depol(rmp,p)
rmm1=depol(rmm,p)
następnie przekształćmy stan Bella:
BB0_E=(tensor(rpp1,rmm)+tensor(rpm1,rmp)+tensor(rmp1,rpm)+tensor(rmm1,rpp))/2.0
i ostatecznie obliczmy jego splątanie wykorzystując funkcję concurrence():
concurrence(BB0_E)
0.20000000000000012