Cytnx icon indicating copy to clipboard operation
Cytnx copied to clipboard

Tensor decomposition: ED

Open pcchen opened this issue 1 year ago • 1 comments

There are several related issues about various tensor decompositions. I will create several issues, but I will write some general guidelines here.

Proposed guideline: If we provide a tensor decomposition T -> A B C, where T, A, B, C are UniTensors, then we should design the bonds and labels of A, B, C, such that one can directly compare T and cyntax.Contract([A,B,C]) without any relabelling or combing bonds.

Specific issues related to ED

Consider first the non-symmetric UniTensor.

  • Returned V is always rank-2, i.e., all incoming bonds are combined, all outgoing bonds are combined.
  • Original labels are not used.

As a result,

  • Even for rank-2 UniTensor, one has to perform manual relabelling to perform Contract([V, E, Vdag]) and compare to T.
  • For higher-rank UniTensor, Contract([V, E, Vdag]) will result in a rank-2 tensor and cannot be compared to T.

How to get eigenvectors

  • For rank-2 UniTensor, returned V is rank-2, and one can use V[:, i] to get the i-th eigenvector.
  • For higher rank UniTensor, if you want the i-th eigenvector in the original basis, you have to reshape V[:, i] by your self.
  • For symmetric UniTensor, since slicing is not available, I don't know how to easily obtain i-th eivenvector even for rank-2 UniTensor.

How to check is is a square matrix (I propose we have some more strict rule here)

  • For rank-2 UniTensor this is trivial.
  • For higher rank UniTensor
    • Do we just check the combined dimension?
    • Or we need to require that number of in-bond = number of out-bond, and the sequence and dimension matches? Meaning the in and out are the same linear space and use the same basis.

Following two code examples will run in current release, but I think maybe we should not allow this, because the in and out space are permuated somehow.

import cytnx
bond1 = cytnx.Bond(cytnx.BD_IN, [cytnx.Qs(1)>>2, cytnx.Qs(-1)>>2],[cytnx.Symmetry.U1()])
bond3 = cytnx.Bond(cytnx.BD_OUT, [cytnx.Qs(-1)>>2, cytnx.Qs(1)>>2], [cytnx.Symmetry.U1()])
uTsym = cytnx.UniTensor([bond1, bond3]).relabels(["a","b"]).set_name("uTsym")
uTsym.print_diagram()
cytnx.random.uniform_(uTsym, low=-1., high=1.)
print(uTsym)
eigvals, V = cytnx.linalg.Eigh(uTsym)
print(eigvals)
print(V)
import cytnx
bond1 = cytnx.Bond(cytnx.BD_IN, [cytnx.Qs(1)>>1, cytnx.Qs(-1)>>1],[cytnx.Symmetry.U1()])
bond2 = cytnx.Bond(cytnx.BD_IN, [cytnx.Qs(-1)>>1, cytnx.Qs(1)>>1],[cytnx.Symmetry.U1()])
bond3 = cytnx.Bond(cytnx.BD_OUT, [cytnx.Qs(-1)>>1, cytnx.Qs(1)>>1], [cytnx.Symmetry.U1()])
bond4 = cytnx.Bond(cytnx.BD_OUT, [cytnx.Qs(1)>>1, cytnx.Qs(-1)>>1], [cytnx.Symmetry.U1()])
uTsym = cytnx.UniTensor([bond1, bond2, bond3, bond4]).relabels(["a","b","c","d"]).set_name("uTsym")
uTsym.print_diagram()
cytnx.random.uniform_(uTsym, low=-1., high=1.)
print(uTsym)
eigvals, V = cytnx.linalg.Eigh(uTsym)
V.print_diagram()
print(eigvals)
# print(V)

For symmetric UniTensor, the output are sorted by block structure. It is hence difficult to see globally which is the i-th eivenvalue. (and also difficult to get eigenvector)

pcchen avatar Apr 29 '24 06:04 pcchen

Also, I think Lanczos will return higher-rank UniTensor. And when you define the LinOp, I think you basically need to match the in and out vector space.

pcchen avatar Apr 29 '24 06:04 pcchen