Related to time dependent spin spin correlations.

Hi,
I am using Itensor C++ codes.
I want to calculate spin spin correlations at different time for AFM XXZ spin-half Heisenbrg chain using open boundary condition.
e.g. <gs|S2^z(0)S2^z(t)|gs> . let length of chain N=10 .
steps that I followed are:

tstep=0.05

  1. using DMRG calculations |gs>, Ground state and E0 ground state energy calculated.
    2.operator S2^z operated on |gs> and new state |psi1> obtained.
    3.using trotter gates time evolution of |psi1> calculated and got |psi1(t)>.
    4…operator S2^z operated on |psi1(t)> and new state |psi2(t)> obtained.
  2. and finally exp(iE0ttotal)*innerC(gs,psi2(t)) calculated.

output:
E0 = -10.7364

ttotal abs(result) imag(result) real(result)
0 0.25 0 0.25
0.5 0.420919 -0.0996948 0.408942
1 0.340459 -0.0501472 0.336746
1.5 0.337924 -0.0115168 0.337727
2 0.36277 0.026344 0.361812
2.5 0.420865 0.00602888 0.420821
3 0.412091 -0.0467875 0.409427
3.5 0.388381 -0.0429918 0.385994
4 0.397469 -0.04531 0.394878
4.5 0.395097 -0.0618982 0.390218

My question is, since at each site there is spin-half, then why spin spin correlations showing result greater than 0.25? It should be less than or equal to 0.25.

When you apply the operator S2^z on |gs> and obtain |psi1> , you can find <psi1|psi1>=0.25. If you normalize the |psi1>( I think you not), you will find the exp(i E0 0)*innerC(gs,Sz,ps1(t=0)) is not equal to 0.25 .
While using trotter gates time evolution of |psi1> calculated and got |psi1(t)>. ITensors would normalize the |psi1(t)>. These processes introduce the correlation is correct when t=0, otherwise time correlation is wrong. Please check the codes.

Hi,
Are you saying I should normalize |psi1> and not |psi1(t)>?

Generally our time evolution codes don’t normalize the state for you unless you request that they do. However it’s a common pattern in many of our code examples that you normalize the state after each time step. Whether you do so in this case is merely a choice you can make or not, and there is not a right or wrong way to do it as long as you keep track of the overall normalization factors correctly.

Most likely if you are getting an incorrect result for this correlator of this size, then there just a bug or mistake in your code somewhere.

One potential issue that I notice in your question is that I believe you have the signs of the time evolution reversed, because it should be that S^z(t) = e^{i H t} S^z e^{-i H t} so that acting on the ground state on the right gives a factor e^{i E_0 t} where E_0 is the ground state energy and your time evolution should be using e^{i H t} as the evolution operator. Either that, or you could compute \langle\psi_0|S^z(t) S^z(0)|\psi_0\rangle if you want the signs to be the more ‘typical’ ones.

1 Like

Two choices: 1) Do not normalize both of them If you can, you can get the correct results. However, during the evolution, you can find <psi1(t)|psi1(t)> will decrease due to cutoff. 2) I can normalize both of them, the correlation you get now exp(i E0 ttotal)*innerC(gs,psi2(t) should multiply a constant (1/2) .

Hi everyone,

Thanks you trying out our new forum, glad to see it is already getting some use. Could you please format your code and equations? We have a guide for doing that here: Welcome to ITensor Discourse. It will make it easier for us and others to understand and answer your questions!

Thanks,
Matt

1 Like

I would suggest an even easier and safer procedure is just to numerically compute the norm of the state |\psi_1\rangle using inner(psi1,psi1) and saving the result to use later on in the calculation. It might equal 1/2 but it would be even easier to just compute it numerically.

That’s right! Thanks!

1 Like

Hi,
Whether I normalize state psi1 or not, still answer is getting above 0.25 for nonzero ttotal. Here I am sharing my Itensor C++ code. I am using Itensor version 2.0.

{
int N=10;

auto sites = SpinHalf(N,{"ConserveQNs=",false});

auto ampo = AutoMPO(sites);
for(int j = 1; j < N; ++j)
    {
    ampo += 0.5,"S+",j,"S-",j+1;
    ampo += 0.5,"S-",j,"S+",j+1;
    ampo += 4.5,"Sz",j,"Sz",j+1;
    }
auto H = toMPO(ampo);


auto psi_i = randomMPS(sites);

auto sweeps = Sweeps(6);
sweeps.maxdim() = 20,50,100;
sweeps.cutoff() = 1E-10;
sweeps.niter() = 2;
sweeps.noise() = 1E-7,1E-8,1E-9;
println(sweeps);


auto [E0,psi0] = dmrg(H,psi_i,sweeps);

PrintDat(E0);

Real tstep=0.05;
Real ttotal=0.0;
Real cutoff=1E-10;


auto gates = vector<BondGate>();

auto hterm = AutoMPO(sites);
//Make the Heisenberg Hamiltonian
for(int b = 1; b < N; ++b)
    {
   auto  hterm = 0.5*op(sites,"S+",b)*op(sites,"S-",b+1);
    hterm += 0.5*op(sites,"S-",b)*op(sites,"S+",b+1);
    hterm += 4.5*op(sites,"Sz",b)*op(sites,"Sz",b+1);

    auto g = BondGate(sites,b,b+1,BondGate::tReal,tstep/2.,hterm);
    gates.push_back(g);
    }

for(int b = N-1; b >= 1; --b)
    {
    auto  hterm = 0.5*op(sites,"S+",b)*op(sites,"S-",b+1);
    hterm += 0.5*op(sites,"S-",b)*op(sites,"S+",b+1);
    hterm += 4.5*op(sites,"Sz",b)*op(sites,"Sz",b+1);

    auto g = BondGate(sites,b,b+1,BondGate::tReal,tstep/2.,hterm);
    gates.push_back(g);
    }


auto psi=psi0;
psi.position(2);

auto newpsi= op(sites,"Sz",2)*psi(2);
newpsi.noPrime();
psi.set(2,newpsi);

auto psi1=psi;
for(int k=1;k<=10;++k)
{

gateTEvol(gates,ttotal,tstep,psi1,{"Cutoff=",cutoff,"Verbose=",true});

auto newpsi2 =  op(sites,"Sz",2)*psi1(2);
newpsi2.noPrime();
psi1.set(2,newpsi2);

auto result=exp(Cplx_i*E0*ttotal)*innerC(psi0,psi1);
psi1=psi;
Print(result);

ttotal=ttotal+0.5;
}
PrintDat(E0);
return 0;
}

Hi Vrushali,
I looked at your code (I also edited your post to format the code by putting ``` before and after). There are a number of issues in your code, so before discussing the correlator I wanted to point some of those out.

  • one issue is that after you time evolve psi1 and act S^z on it, you then reset it back to psi which is the state at time t=0. (The line I mean is psi1=psi;.) So your state is evolving forward from time t=0 over and over.
  • relatedly (and here I can understand because we didn’t do a good job documenting the gateTEvol function, though now I’ve updated the documentation on it) the usage of gateTEvol is incorrect in your code. The second argument, ttotal is the amount of time you want it to evolve your state. Here you should not evolve it starting from t=0 by larger and larger amounts, which is highly inefficient. Instead for this kind of application you should just evolve by one tstep at a time. In short you should use gateTEvol here like this:
    gateTEvol(gates,tstep,tstep,psi1,{"Cutoff=",cutoff,"Verbose=",true});
    
  • now the other issue with your code, and I believe this issue will address your question about not getting values below 0.25 is that you aren’t accounting for the norm of the state, even though it was mentioned above. Here a good debugging technique is to print things out. So when I do Print(norm(psi)); after S^z is applied, I see that the norm of the state is |\Psi| = 0.5, or in other words sqrt(inner(psi,psi))=\sqrt{\langle\Psi|\Psi\rangle}=0.5. Secondly, after time evolving the state, I observe that the norm is reset to 1.0, so it means gateTEvol normalizes the state afterward. Therefore an extra factor of 0.5 is discarded by gateTEvol and must be accounted for.
    A good way to do this is to save the norm in a separate variable before you start the time evolution and then include it again in your result.
    The upshot of all this is that in your case, you need to divide your result by 2 afterward when computing it. Then you’ll see that you always get values <0.25 as you expect.

Please note that by printing out the norm of each wavefunction in various places in your code, you could have seen what was happening to the norm after each step.

However, I do understand that gateTEvol wasn’t previously documented very well & we have updated the page on that. So your question was definitely helpful to remind us to update that documentation!

Best regards,
Miles

Hi,
Is it like , If I want answer for ttotal=10, then I have to set ttotal=10 and time evolution will start from 0 to 10 by tstep. I don’t need to set ttotal=0.

Could you please say more about what you are asking? Is your question about the gateTEvol function and how to use it?

Hi,
My question is about gateTEvol function. Suppose I want to calculate answer after ttotal=1,2,3,4,…so on. and interested how correlation is changing with time?
Then how do I use gateTEvol ?

It’s a good question. The gateTEvol function takes these arguments:

gateTEvol(Iterable const& gatelist, Real ttotal, Real tstep, MPS & psi, Observer& obs, Args args)

The last two, the Observer and Args, have default values so you aren’t required to pass them.

The ttotal and tstep arguments work like this: the gateTEvol function assumes that the gates in gatelist will advance the MPS psi by an amount tstep of time. So all that the ttotal argument does is to say that the function should apply the gates a number n = ttotal/tstep times before returning.

So if you want to calculate properties of psi outside of gateTEvol at times 1,2,3,4 and say you want to use a time step of 0.1, then you would call:

for(int step = 1; step <= Nstep; step += 1) {
    gateTEvol(gates,1.0,0.1,psi);
    // do measurements of psi
}

Each call to gateTEvol above will apply the gates 10 times to psi because 1.0/0.1 = 10.

Please let me know if that’s helpful & answers your question.

I’d encourage you to check out the code for gateTEvol itself, which you can find here:

Hi,
What about psi after first iteration? I mean after ttotal=1 iteration, before ttotal=2 can I reset psi to original as it was before ttotal=1 and then calculate psi from initial psi to psi at ttotal=2 . Or will it continue after ttotal=1 to ttotal=2 by tstep without resetting psi?.

You could reset psi to the original, but I would not recommend performing time evolution that way. A much better way to do it is to leave psi at its current value, so that it will be the wavefunction at time t=1 that is, \text{psi} = |\psi(t=1)\rangle.

Then, on the next loop when you input psi into gateTEvol, it will be evolved from time t=1 to t=2. This is a much more efficient way to do it, because you only have to do the work of evolving by a single unit of time at each step of the loop, rather than an increasingly large amount of time for every step.

(Maybe this is what you were asking in the second half of your question? Yes if you do not reset psi then gateTEvol will evolve it from time t=1 to t=2 on the next step of the loop if you set ttotal=1.0.)

Miles

Hi,
Now I got it. Thanks a lot for a such a helpful discussion.

Vrushali.

1 Like

Glad I was able to answer your questions! :+1: