# How to create and add MPS

Hello there,

Sorry for the newbie question (and if that has been answered elsewhere but I haven't found approaching solutions) but here it is:

I want to create 2 MPS in Julia and add them. The first question is that I would like to customise the core MPS. As such, my first and last core MPS are different from the others in the indices they hold. Is there a way to do that ? I.e. do I have to create a MPS with say N sites and then customise one by one like MPS1 = CustomTensor1; MPS[2] = CustomTensor2, etc... ? Then, I am not sure how would ITensor resolve the indexing then.

The other question is how to change the link dimension ? I heard about pluss* but not sure it was for Julia.

Finally, if I solve question 1 I assume I'd be able to sum them together. However, is that sum equivalent to the operations described in that article (bottom of page 7, top page 8) ?

Thanks for your help, that is really appreciated.

Kind regards,

Roland

commented by (120 points)
Hi @MattFishman,

Just a follow-up question on the MPS/MPD discussion above. I understand how to construct the MPD/MPO from the MPS by filling the MPD tensor elements with the corresponding MPS tensor elements. But I still fail to practically understand how to get the vectors from the kernel of the MPS tensors. If I get correctly what you suggested above, getting the MPD tensors from MPS tensors can be done by
1. Left-orthonormalising the MPS
2. Compute a full decomposition (SVD or QR) from which the matrix U is what I am looking for.
However, SVD is implemented in ITensors.jl ? Or is it not the full SVD ?

Thanks for your time and help.

BW,

Roland
commented by (10.9k points)
The full SVD/QR is not currently implemented in ITensors.jl, so you will have to do something custom for your case. The Julia LinearAlgebra function nullspace would give you what you need (https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#LinearAlgebra.nullspace). Here is a small script that gets the null space/kernel of an orthogonalized MPS tensor:

using ITensors
using LinearAlgebra

function LinearAlgebra.nullspace(A::ITensor, left_inds)
Cl = combiner(left_inds)
cl = combinedind(Cl)
AC = A * Cl
n = nullspace(array(AC))
ln = Index(size(n, 2), "null")
NC = itensor(nullspace(array(AC)), cl, ln)
return NC * dag(Cl)
end

N = 4
s = siteinds("S=1/2", N)
psi = randomMPS(s, 2)
orthogonalize!(psi, N)

n = 2
A = psi[n]
left_inds = (linkind(psi, n-1), siteind(psi, n))
N = nullspace(A, left_inds)

@show N * A

The nullspace(::ITensor, ...) function simply wraps the Julia one that works on the underlying Array data of the ITensor. This is similar to how we would implement it internally (I have been meaning to add a nullspace(::ITensor, ...) function but it is a bit more complicated when there are QNs involved and I haven't had the time). Note you should check it does the correct thing for complex numbers (I didn't test it for that), and also note it won't work for QN conserving ITensors/MPS.
commented ago by (120 points)
Hi @MattFishman,

Ok thanks I get it. It works fine as my tensors are only real-valued.

Last point that puzzles me a little is when computing the nullspace of end tensors. In a simple case describe in the article, these are 2x2 matrices and if the nullspace is non-empty, I should get 2x1 vectors. However, in most cases, I get 2x0 from LinearAlgebra.nullspace. I tried using rtol=2 but the returned matrix doesn't nullify the tensor. Any idea maybe ?

The other point, I am not sure what is meant by "Then choose (d^2 −d) orthonormal vectors in the kernel of A[n]". From the above procedure, I can compute the kernel of As which are 2x2x2 tensors but when constructing G, filling the elements for the added index should be done by choosing a vector in the kernel of A (as stated above). However, is this choice arbitrary ? What if the kernel is empty ? Sorry for the slightly off question. I am still trying to understand the whole process as being quite new to it.

Thanks a lot.

Kind regards,
Roland
commented ago by (10.9k points)
The only case when there are 2x2 matrices is the first tensor at the edge of the MPS (tensor A[1] of Fig. 1 (a)), which indeed will always have a null space of size 2x0 (keep in mind because of the gauge it is already an orthogonal matrix, which always has a null space of size 0). So there will be no subspace to expand by in that case (and no index added on to the first tensor in the MPD), which is in Fig. 1(a).

For tensor A[2] to A[N-1], as you say the tensors are size 2x2x2 (dxdxd) which get reshaped into matrices of size d^2xd. Because you pick the orthogonal gauge with the gauge center at the end of the MPS (site N), the columns of this matrix are orthogonal to each other and therefore linearly independent. So the (left) nullspace is always the maximum it can be, i.e. (d^2-d) = 2 orthonormal vectors of length d^2 = 4. The left null space of that matrix cannot be empty since it is a rectangular matrix (the columns don't span the entire space).
commented ago by (120 points)
Hi @MattFishman,

Thank you for you answer, that's clear really.

I am now able to compute the nullspace and place the resulting vectors in G. However, I can't seem to fullfil orthogonality conditions provided by Eq. (8). Any ideas maybe ? I tried several options without much success tbh.

Thanks again !

Roland