import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
Let's run some tests and see what the dynamics of the defect density looks like.
run defects.py
First, start and stay in the ferromagnetic phase.
numt=1000
g=np.linspace(0,0,numt)
N=10
T=1
D,f=defectstime(g,N,T,numt)
t=np.linspace(0,T,numt)
l1=plt.plot(t,D,label='$D$')
l2=plt.plot(t,f,label='$f$')
plt.axis([0,1,-.5,1.5])
plt.legend(prop={'size':16},loc='best')
<matplotlib.legend.Legend at 0x97ac350>
The defect density is indeed zero; similarly the system always stays in the instantaenous ground state, since the Hamiltonian is constant.
Now let's try constant fields in the paramagnetic phase, for which g>gc=1.
g=np.linspace(2,2,1000)
D,f=defectstime(g,N,T,numt)
l1=plt.plot(t,D,label='$D$')
l2=plt.plot(t,f,label='$f$')
plt.axis([0,1,-.5,1.5])
plt.legend(prop={'size':16},loc='best')
<matplotlib.legend.Legend at 0x995fc10>
The defect density stays at a constant value, which is determined by the strength of g. Higher and higher values of g, taking the system deeper into the paramagnetic phase, should cause the defect density to saturate at 0.5 (although it doesn't really make sense to talk about topological defects in the paramagnetic phase, as the symmetry is not broken; maybe kink density is better).
gstr=np.array([2,5,10,30,60])
for k in gstr:
g=np.linspace(k,k,numt)
D,f=defectstime(g,N,T,numt)
plt.plot(t,D,label='$g={0}$'.format(k))
plt.legend(prop={'size':16},loc='best')
<matplotlib.legend.Legend at 0x9b33110>
Looks good.
Now, we will use the linear quench. Let's fix the chain size at N=10 and see if we can access different regimes for the dynamics by changing the rate at which we quench.
The quench occurs from time t=0 to time t=T, from g=2 to g=0. So g(t)=2−2Tt. This means that the quench time is τQ=T/2.
From Dziarmaga: using Landau-Zener one can show that if τQ<τadQ, then the quench becomes nonadiabatic, where τadQ=ℏN22π3J≈0.016N2. So by varying T on either side of this threshhold, we should observe adiabatic behavior, where the final defect density is close to 0 and the fidelity remains high (indicating that the system remains close to its instantaneous ground state), and nonadiabatic (diabatic?) behavior, where the defect density does something else, and the fidelity drops. This nonadiabatic regime is what we are interested in, since we want to control the defect density.
N=10
g=np.linspace(2,0,numt)
Ttimes=np.array([50,20,10,5,3.2,1,0.1])
t=np.linspace(0,1,numt)
for k in Ttimes:
D,f=defectstime(g,N,k,numt)
plt.figure(1)
plt.plot(t,D,label=r'$\tau_Q={0}$'.format(k/2.))
plt.figure(2)
plt.plot(t,f,label=r'$\tau_Q={0}$'.format(k/2.))
plt.figure(1)
plt.legend(prop={'size':10},loc='best')
plt.title('$N=10$',fontsize=26)
plt.xlabel(r'$t/2\tau_Q$',fontsize=22)
plt.ylabel('$D$',fontsize=22)
plt.figure(2)
plt.legend(prop={'size':10},loc='best')
plt.xlabel(r'$t/2\tau_Q$',fontsize=22)
plt.ylabel('$f$',fontsize=22)
<matplotlib.text.Text at 0xa7c6a70>
For the largest quench times, τQ=25,10 or T=50,20, D decreases all the way to 0 in the ferromagnetic phase. Correspondingly, the fidelities for these two quench times are very close to 1.0 at all times, except for a slight dip for the τQ=10 curve when g is close to its critical value.
Clearly, as the quench time is reduced, the dynamics becomes less adiabatic. The fidelities for smaller τQ never recover once the critical point is passed at 2t/τQ=0.5, and D(T) starts to rise. Once τQ<τadQ, markedly different behavior appears, in that f(T) becomes much lower and D(T) becomes much higher. Indeed, for τQ=0.05, the defect density appears to be constant, indicating that the system is "frozen out", and that it cannot respond to a change in the magnetic field. This means that we probably would not be able to control the system on such a short time scale either, but we can still try.
Of course, the above plots are for N=10. Different sizes will yield different behaviors of D and f for these values of τQ, but if the quench times are scaled according to τQ∼N2, then the same behavior should be observed. Let's check this. Double N, and quadruple all the quench times above.
N=20
g=np.linspace(2,0,numt)
Ttimes=4*np.array([50,20,10,5,3.2,1,0.1])
t=np.linspace(0,1,numt)
for k in Ttimes:
D,f=defectstime(g,N,k,numt)
plt.figure(1)
plt.plot(t,D,label=r'$\tau_Q={0}$'.format(k/2.))
plt.figure(2)
plt.plot(t,f,label=r'$\tau_Q={0}$'.format(k/2.))
plt.figure(1)
plt.legend(prop={'size':10},loc='best')
plt.title('$N=20$',fontsize=26)
plt.xlabel(r'$t/2\tau_Q$',fontsize=22)
plt.ylabel('$D$',fontsize=22)
plt.figure(2)
plt.legend(prop={'size':10},loc='best')
plt.xlabel(r'$t/2\tau_Q$',fontsize=22)
plt.ylabel('$f$',fontsize=22)
<matplotlib.text.Text at 0x9faf290>
The agreement is not perfect, but somewhat close. Perhaps this is because although the analysis in deriving τQ makes sense for finite N, it also assumes that N is large. Anyway, this suggests that larger systems are more responsive to changes in g and therefore more amenable to being controlled over a greater variety of time scales. We will try to simulate as large systems as possible, since the computational expense of the numerics scales linearly with N (but also linearly with T, which we may also increase as the system size gets bigger).
If we want to increase the number of defects at the final time, we can try quenching from a higher initial value of g, so that the system starts deeper in the paramagnetic phase. We still have to fix g(T)=0 ( g<−1 again belongs to the paramagnetic phase), so if we do this we will have to adjust T or τQ accordingly. Let's check to see how starting at a higher value of g(0) affects the defect density. We will fix N=10 and T=1, so that the dynamics is nonadiabatic.
gi=np.array([2,3,5,10,20])
N=10
T=1
t=np.linspace(0,T,numt)
for k in gi:
g=np.linspace(k,0,numt)
D,f=defectstime(g,N,T,numt)
plt.figure(1)
plt.plot(t,D,label=r'$g(0)={0}$'.format(k))
plt.figure(2)
plt.plot(t,f,label=r'$g(0)={0}$'.format(k))
plt.figure(1)
plt.legend(prop={'size':10},loc='best')
plt.xlabel(r'$t$',fontsize=22)
plt.ylabel('$D$',fontsize=22)
plt.figure(2)
plt.legend(prop={'size':10},loc='best')
plt.xlabel(r'$t$',fontsize=22)
plt.ylabel('$f$',fontsize=22)
<matplotlib.text.Text at 0xb981750>
We see that the defect density gets higher, and that the fidelities change at later and later times; this is because the critical point is being crossed later. We could try changing the pulses we optimize in this way later, but this change may be identical to just making τQ shorter.
Now we will check that the code reproduces the KZ scaling, which together with Landau-Zener states that the density of defects should scale with the quench time as D=12π√ℏ2JτQ (Zurek and Dziarmaga). In numerical simulations, the exponent of τQ was found to decrease with N, down to 0.58 for N=100. We will use smaller N for now, so if we obtain an exponent higher than 0.5 we should not be surprised. We will fix N=50, g(0)=5 (to match them), and g(T)=0. Zurek et al. plot the defect density against the dimensionless quench rate τ0/τQ, where τ0=ℏ/2J. For us, then, τ0=1/2 and τQ=T/5, so τ0/τQ=5/2T. We will calculate D(T) for τ0/τQ=0.01, 0.1, 0.2, 0.3, and 0.4. To compare with the following figure from Zurek et al.:
from IPython.core.display import Image
Image(filename='ZurekFig1.png')
from scipy.io import loadmat,savemat
density=np.zeros([5])
d=loadmat('defects_N50_gi5_T250.mat')
density[0]=d['d']
d=loadmat('defects_N50_gi5_T25.mat')
density[1]=d['d']
d=loadmat('defects_N50_gi5_T12.5.mat')
density[2]=d['d']
d=loadmat('defects_N50_gi5_T8.33.mat')
density[3]=d['d']
d=loadmat('defects_N50_gi5_T6.25.mat')
density[4]=d['d']
rate=np.array([.01,.1,.2,.3,.4])
plt.plot(rate,density,'-o')
plt.xlabel(r'$\tau_0/\tau_Q$',fontsize=20)
plt.ylabel('$D$',fontsize=20)
<matplotlib.text.Text at 0xb778fd0>
from scipy import optimize
def sqrtfunc(x,a,b):
return a*(x**b)
popt,pcov = optimize.curve_fit(sqrtfunc,rate,density)
print popt
[ 0.18935153 0.5899717 ]
With these few points, we can reproduce Zurek et al.'s results. Our fited exponent is 0.59, and our coefficient is 0.19, both of which are in excellent agreement with their results of 0.58 and 0.16 using larger N and more points.
Now, let's see what D-MORPH can do by looking at a (partially) optimized pulse. For this test simulation we set N=20, T=1, and used an an initial control a linear quench such that g(0)=2 and g(T)=0. The optimization lasts until s, the DMORPH parameter, reaches a pre-specified value; we chose smax=1 for now. First, we will examine the initial and final control fields g(t):
dict=loadmat('g_N20_T1_s1.0.mat')
g=dict['g'].transpose()
g0=g[:,0]
g1=g[:,-1]
t=np.linspace(0,1,1000)
plt.plot(t,g0,label='$g(0,t)$')
plt.plot(t,g1,label='$g(s_{max},t)$')
plt.xlabel('$t$',fontsize=20)
plt.ylabel('$g$',fontsize=20)
plt.legend(prop={'size':14},loc='best')
<matplotlib.legend.Legend at 0xc3f5d10>
Now we will examine the resulting defect densities and fidelities as functions of time.
D0,f0=defectstime(g0,20,1,1000)
D1,f1=defectstime(g1,20,1,1000)
plt.figure(1)
plt.plot(t,D0,label='$D(0,t)$')
plt.plot(t,D1,label='$D(s_{max},t)$')
plt.xlabel('$t$',fontsize=20)
plt.ylabel('$D$',fontsize=20)
plt.legend(prop={'size':14},loc='best')
plt.figure(2)
plt.plot(t,f0,label='$f(0,t)$')
plt.plot(t,f1,label='$f(s_{max},t)$')
plt.xlabel('$t$',fontsize=20)
plt.ylabel('$f$',fontsize=20)
plt.legend(prop={'size':14},loc='best')
<matplotlib.legend.Legend at 0xc629ab0>
We have managed to lower the final defect density by a little. Letting DMORPH run longer should produce a better result.