# SVD swapping index arrow in TEBD algorithm with conserved quantum numbers

Hello,
I am implementing the TEBD algorithm in Vidal's gauge (G. Vidal, PRL 98 2007) in presence of conserved quantum numbers and I get some error regarding the indices’ arrows.
I report here a minimal example code that reproduces the issue:

auto sites = SpinHalf(N,{"ConserveQNs=",true});
auto init = InitState(sites);
for(auto n : range1(N))
{
init.set(n, n%2 == 1 ? "Up" : "Dn");
}
auto psi = MPS(init);
std::vector<ITensor> lambda(N-1);
for(int i=1; i<= N-1; i++)
{
auto u= commonIndex(psi(i),psi(i+1));
lambda.at(i-1) = ITensor(dag(u), prime(u));
lambda.at(i-1).set(dag(u)(1), prime(u)(1), 1.);
}
for(int b= 1; b<N; b++){
ITensor A = psi(b);
ITensor B = psi(b+1);
Print(lambda.at(b-1));
A = noPrime(lambda.at(b-1)*A);
auto AA = A*B;
auto u= commonInds(A,AA);
auto [U,S,V] = svd(AA,u,{"Truncation=", false});
lambda.at(b-1) = S;
psi.ref(b) = U;
psi.ref(b+1) = V;
}


Here, I initialize the system in a product state and define the lambda matrices in the second loop. After this procedure, the indices' arrows of the lambdas have the correct direction in and out.
Then, to avoid priming/unpriming indices in the lambdas, I perform the svd in the third loop, that should just change the indices from (i,i') to (i,j). Nevertheless, I observe that after contraction with the state at a local site psi(i) and SVD the direction of one of the arrows changes from in to out, thus making the contraction with the following site impossible. Furthermore, here the lambda acquires a fictitious bond dimension d=2 and its norm becomes larger by a factor sqrt(2). Please notice that the code does not show the actual TEBD, but just the minimal working patch that reproduces the issue.
Even though it might be possible to fix this issue, at least for what concerns the wrong arrows, by manually change the direction of the troublesome index, I feel like there must be something I am missing and an easier solution.
As this seems to involve the svd routine, I hope you could give some insightful answer to this issue.

Pietro

+1 vote

Hi Pietro,

I think using ITensor's MPS class is not necessary here, and makes it a bit confusing to keep track of the indices. Here is a minimal example of the step you are trying to reproduce from the paper, just in terms of ITensors:

// Site indices
auto s = SpinHalf(2,{"ConserveQNs=",true});
auto sA = s(1);
auto sB = s(2);

auto lA = Index(QN(), 1, "lA");
auto lB = Index(QN(), 1, "lB");

// Gamma tensors
auto GammaA = randomITensor(QN(), dag(prime(lB)), sA, dag(lA));
auto GammaB = randomITensor(QN(), dag(prime(lA)), sB, dag(lB));

// Lambda tensors
auto lambdaA = randomITensor(QN(), lA, prime(lA));
auto lambdaB = randomITensor(QN(), lB, prime(lB));

// Fig. 3 (ii)
auto theta = lambdaB * GammaA * lambdaA * GammaB * lambdaB;

PrintData(inds(theta));

// Fig. 3 (iii)
auto [X, lambdaA_tilde, Y] = svd(theta, {lB, sA}, {"LeftTags = ", "lA_new", "RightTags = ", "lA_new_p"});

PrintData(inds(X));
PrintData(inds(lambdaA_tilde));
PrintData(inds(Y));


You can see there should be no Index mismatch, and if you are a bit careful with the indices you should be able to follow along with the next steps of the algorithm in the paper.

Cheers,
Matt