Regarding Vidal's representation of MPS

Hi,
I was curious if there is some available routine/function which can be useful for converting a right/left orthogonal MPS in the Vidal’s notation in ITensor. To be precise, I have in mind the representation shown in https://arxiv.org/pdf/1008.3477.pdf , section 7.3.2.

I might add that I am interested in MPI parallelization in TEBD as discussed in [1912.06127] Parallel time-dependent variational principle algorithm for matrix product states. This article mentions
that parallel MPS algorithms can be realized in Vidal’s notation. (TDVP parallelisation is
discussed in PHYSICAL REVIEW B 101, 235123 (2020), which also uses Vidal notation)
It would be helpful if the you can kindly point me to codes/functions in ITensor
in case they are already available for parallel implemention of TEBD.

Best,
Sourav.

Hi, good question but no, we don’t have any specific facilities or types to represent “Vidal canonical” MPS. However it would not be too hard to make your own type that does this. All the type would need is an array of the various tensors (\Gamma_j and \Lambda_j tensors) to be stored, either all in a single array or two separate arrays for the \Gamma's and \Lambda's.

To actually obtain a “bond tensor” \Lambda_j, you just orthogonalize a standard type of MPS to site j, then use the SVD - which we definitely do have in ITensor - and then \Lambda is the “S” or singular-value matrix of the SVD. The \Gamma tensors are related to the original MPS tensors by multiplications of \Lambda^{-1} into those tensors. This is one reason the \Gamma-\Lambda form is less popular for actual applications: its use often involves inverting very small numbers which can lead to numerical stability issues.

For some code that shows how you can SVD apart a single MPS tensor (in this case to get the entanglement, but the principle is the same) you can see the following code example:
https://itensor.github.io/ITensors.jl/stable/examples/MPSandMPO.html#Computing-the-Entanglement-Entropy-of-an-MPS

Ok Thanks !

Hi,

In the previous context, I have a somewhat naive question as follows:

Suppose , I have some initial product state which I create by using:

N = 6
s = siteinds(“S=1/2”,N)
psi = randomMPS(s; linkdims=1)

Now, if I print psi, I am going to get

ITensors.MPS
[1] ((dim=2|id=197|“S=1/2,Site,n=1”), (dim=1|id=777|“Link,l=1”))
[2] ((dim=1|id=777|“Link,l=1”), (dim=2|id=706|“S=1/2,Site,n=2”), (dim=1|id=592|“Link,l=2”))
[3] ((dim=1|id=592|“Link,l=2”), (dim=2|id=898|“S=1/2,Site,n=3”), (dim=1|id=542|“Link,l=3”))
[4] ((dim=1|id=542|“Link,l=3”), (dim=2|id=255|“S=1/2,Site,n=4”), (dim=1|id=3|“Link,l=4”))
[5] ((dim=1|id=3|“Link,l=4”), (dim=2|id=595|“S=1/2,Site,n=5”), (dim=1|id=856|“Link,l=5”))
[6] ((dim=1|id=856|“Link,l=5”), (dim=2|id=622|“S=1/2,Site,n=6”))

So, for each psi[i], I have a physical index and two virtual indices (apart from at the
boundary where I only have 1 virtual index ).

Now, I can use orthogonalization function to make psi right-orthogonal, for instance. So, this tensor / MPS is like my \Gamma.
Now, since this is simple product state, so all the \Lambda_{i} would be just a 1 \times 1 matrix with element 1.

How can I save this \Lambda in the MPS form as in \Gamma, so that I have the correct links and indices. Problem is each \Lambda_{i} is sitting on a link , so I cannot distinguish the right and left virtual legs via “Link, l=x” as done for the \Gamma_{i}. Can you help me in understanding how do I go about it? The main objective is to store \Lambda in a convenient from so that later contraction etc. become more systematic within ITensor notations.

Yes, so basically you could just make two arrays, one to hold your Lambda’s and one to hold your Gammas.

Getting into the details of the indices, ITensor Index objects are distinguished not only by their tags (such as “Link,l=4”) but also by their id number (the number you see printed after “id=…”). So theoretically you could have two indices with the same tags on a Lambda and it would be ok.

A better way to go would be to actually use the tag system to further distinguish the two indices of a Lambda. So one of the indices could have tags like “Link,Left,l=5” and the other “Link,Right,l=5” for bond number 5. Then in a printout you could more easily tell which one is coming out of the left of Lambda and the right of Lambda. This would unfortunately lead to a weird situation where for a Gamma the index labeled “Right” would come out of the left of the Gamma and “Left” out of the right of a Gamma, so you could alternatively label them “A” and “B” or some other labeling that you like.

Hi,
Thanks for your reply. But I am still having one issue as follows:

I generate the \Lambda as follows (denote by M in the code)

N = 6
s = siteinds(“S=1/2”,N)
psi = randomMPS(s; linkdims=2)
M = ITensors.MPS(s)
l = Vector{Index}(undef,N)
chi, element = 1, [1.0]

for i=1:N-1
l1 , l2 = Index(chi,“Link,Left,l=(i)"), Index(chi,"Link,Right,l=(i)”)
T = reshape(element, (1,1))
M[i] = ITensor(T, l1,l2)
end

l1 = Index(chi,“Link,Left,l=$(N)”)
T = reshape(element, (1,1))
M[N] = ITensor(T,l1)

The psi created looks like

ITensors.MPS
[1] ((dim=2|id=100|“S=1/2,Site,n=1”), (dim=2|id=538|“Link,l=1”))
[2] ((dim=2|id=538|“Link,l=1”), (dim=2|id=770|“S=1/2,Site,n=2”), (dim=2|id=92|“Link,l=2”))
[3] ((dim=2|id=92|“Link,l=2”), (dim=2|id=382|“S=1/2,Site,n=3”), (dim=2|id=119|“Link,l=3”))
[4] ((dim=2|id=119|“Link,l=3”), (dim=2|id=167|“S=1/2,Site,n=4”), (dim=2|id=703|“Link,l=4”))
[5] ((dim=2|id=703|“Link,l=4”), (dim=2|id=283|“S=1/2,Site,n=5”), (dim=2|id=839|“Link,l=5”))
[6] ((dim=2|id=839|“Link,l=5”), (dim=2|id=494|“S=1/2,Site,n=6”))

And \Lambda looks like

ITensors.MPS
[1] ((dim=1|id=885|“Left,Link,l=1”), (dim=1|id=194|“Link,Right,l=1”))
[2] ((dim=1|id=729|“Left,Link,l=2”), (dim=1|id=735|“Link,Right,l=2”))
[3] ((dim=1|id=403|“Left,Link,l=3”), (dim=1|id=825|“Link,Right,l=3”))
[4] ((dim=1|id=432|“Left,Link,l=4”), (dim=1|id=369|“Link,Right,l=4”))
[5] ((dim=1|id=616|“Left,Link,l=5”), (dim=1|id=992|“Link,Right,l=5”))
[6] ((dim=1|id=307|“Left,Link,l=6”),)

Now, when I try the multiply MPS at some site (for instance site =3) with the \Lambda just to its right (i.e, \Lambda sitting on right side bond), I get

print(psi[3]*M[3])

ITensor ord=5
Dim 1: (dim=2|id=92|“Link,l=2”)
Dim 2: (dim=2|id=382|“S=1/2,Site,n=3”)
Dim 3: (dim=2|id=119|“Link,l=3”)
Dim 4: (dim=1|id=403|“Left,Link,l=3”)
Dim 5: (dim=1|id=825|“Link,Right,l=3”)
ITensors.NDTensors.Dense{Float64, Vector{Float64}}
2×2×2×1×1
[:, :, 1, 1, 1] =
0.8997157483855767 -0.3258873572108523
0.25694720924808373 -0.058385953136905755

[:, :, 2, 1, 1] =
0.01238106719578167 -0.2900960387392452
-0.46996470968106846 0.8424383560773483

clearly, I get a 5 index tensor instead of 3 and as seen the common leg is not contracted. This is
(so far as I understand) because the id numbers are different for their “common leg”. How should I modify in construction of \Lambda such that contractions and other operations can be implemented correctly?

As I think you know, you will have to do things in a way that ensures the Lambda’s share a common index with the Gamma tensors to their left and right.

The key way to do this is to obtain the Lambda’s by computing the SVD of MPS tensors (say if you are starting from a regular, right-canonical MPS then turning it step by step into a Vidal form MPS). Our svd function in ITensor returns U,S,V tensors such that the S tensor has two indices, one which correctly connects to U and the other to V. So you should be computing the Lambda as being the “S” of a certain SVD of MPS tensors. Then it will connect to U and V and the Gammas are related to U and V (not equal to them, but related through inverses of Lambda’s).

1 Like

Ok, I get it. Thanks !

1 Like