Some questions about the svd_theta

 Posts: 26
 Joined: 08 Jan 2019, 03:03
Some questions about the svd_theta
Hi everyone,
I want to write a little program to calculate the correlation length with a given "theta" (which is located in the center of the chain), so I need to do svd to theta and get the right matrice B. But there is a problem, I get the theta by using function "get_theta" for MPS object, and extract the data by using "to_ndarray", and run "np.linalg.svd(matrice)". but this gives the order by sorting the singular value, which is different from "svd_theta" in tenpy. I donot know how to spilt the physical leg out in my case and how to calculate the transfer matrix. Would anyone help me with this, or tell me how to reconstruct the matrice into a block form?
Thanks,
Qicheng
I want to write a little program to calculate the correlation length with a given "theta" (which is located in the center of the chain), so I need to do svd to theta and get the right matrice B. But there is a problem, I get the theta by using function "get_theta" for MPS object, and extract the data by using "to_ndarray", and run "np.linalg.svd(matrice)". but this gives the order by sorting the singular value, which is different from "svd_theta" in tenpy. I donot know how to spilt the physical leg out in my case and how to calculate the transfer matrix. Would anyone help me with this, or tell me how to reconstruct the matrice into a block form?
Thanks,
Qicheng
Re: Some questions about the svd_theta
Hi Qicheng,
how exactly do you want to extract the correlation length from the B?
For a finite system, this is a somewhat illdefined question, because you have no (guaranteed) periodicity. You might want to look at the correlation functions directly and fit an exponential to that.
For an infinite system, you can write down the transfermatrix and take the (second) largest eigenvalue, see e.g. the beginning of chapter 4 in our notes arXiv:1805.00055. This is exactly what the function correlation_length does.
That being said, you should probably do the svd directly with tenpy's tenpy.linalg.np_conserved.svd instead of using
how exactly do you want to extract the correlation length from the B?
For a finite system, this is a somewhat illdefined question, because you have no (guaranteed) periodicity. You might want to look at the correlation functions directly and fit an exponential to that.
For an infinite system, you can write down the transfermatrix and take the (second) largest eigenvalue, see e.g. the beginning of chapter 4 in our notes arXiv:1805.00055. This is exactly what the function correlation_length does.
That being said, you should probably do the svd directly with tenpy's tenpy.linalg.np_conserved.svd instead of using
to_ndarray
and numpy's svd. Moreover, you can also just use the MPS get_B method to get the B with the expected 3 legs 'vL', 'p', 'vR'.
 Posts: 26
 Joined: 08 Jan 2019, 03:03
Re: Some questions about the svd_theta
Johannes,
Thanks for your reply, I know that the transfer matrix method is only welldefined in a case with translational invariance, and for the contracting of the transfer matrix we need right matrice B or left matrice A.
My question is about the implementation of the charge conservation in the calculation. For example, as said in the note, when we combine the physical leg (p) with the left leg (vL) or the right leg (vR), we map the indices for "vL" and "p" into something like "2*vL+p", so that the charge rule preserved. In this case, the inverse mapping (split combined leg) can be written simply.
In tenpy, theta with combined legs can be obtained by the following code:
this is also can be done with:
If we have a theta in the matrix form (legs combined), we can split physical legs from theta by using the inverse mapping:
start from a theta with combined legs
split it
But there is a question is: how to do svd for theta can preserve the block structure? If simply run "U, S, Vh = np.linalg.svd(theta)" (where theta is the wavefunction in matrix from, i.e. it's obtained by
), it will return the right matrice B (which is just Vh) but sorted by the the singular values. Also due to this reason, we cannot split combined leg back into "vR" and "p" by using the inverse mapping mentioned above. In this case, I donot know how to calculate the transfer matrix since I cannot do the tensor product of right matrice B and trace out the physical leg.
In the note, it said that we can do svd in each charge sector, I'm not sure how to do. For example, for a matrix form theta, it seems we need to do the inverse mapping first (split combined leg) to get a rank3 tensor with shape (chi, 4, chi) and do svd in each charege sector "theta[:, 0, :]", "theta[:, 1, :]", "theta[:, 2, :]", and "theta[:, 3, :]", i.e. do svd in sector (2, 0, 0, 2) respectively? Like in the follwing:
There will be another question: we have two zero charge sector since (1) + (+1) = (+1) + (1) = 0, how to deal with this?
In fact, I think somehow we can calculate the transfer matrix without using any knowledge of the charge conservation, i.e. with only a given matrix form theta (just the data of theta, extracted by using ".to_ndarray()"), we can obtain the transfer matrix. But I really donot know how to do this.
Thanks,
Qicheng
Thanks for your reply, I know that the transfer matrix method is only welldefined in a case with translational invariance, and for the contracting of the transfer matrix we need right matrice B or left matrice A.
My question is about the implementation of the charge conservation in the calculation. For example, as said in the note, when we combine the physical leg (p) with the left leg (vL) or the right leg (vR), we map the indices for "vL" and "p" into something like "2*vL+p", so that the charge rule preserved. In this case, the inverse mapping (split combined leg) can be written simply.
In tenpy, theta with combined legs can be obtained by the following code:
Code: Select all
theta = psi.get_theta(0)
theta = theta.combine_legs([('vL', 'p0'), ('p1', 'vR')], qconj=[+1, 1])
theta = theta.to_ndarray()
Code: Select all
theta = psi.get_theta(0).to_ndarray()
combined_theta = np.zeros((2*chi, 2*chi))
for i in range(chi):
for j in range(2):
for k in range(chi):
for l in range(2):
combined_theta[2*i+j, 2*k+l] = theta[i, j, l, k]
start from a theta with combined legs
Code: Select all
theta = psi.get_theta(0)
theta = theta.combine_legs([('vL', 'p0'), ('p1', 'vR')], qconj=[+1, 1])
theta = theta.to_ndarray()
Code: Select all
split_theta = np.zeros((chi, 2, 2, chi))
for i in range(chi):
for j in range(2):
for k in range(chi):
for l in range(2):
split_theta[i, j, l, k] = theta[2*i+j, 2*k+l]
But there is a question is: how to do svd for theta can preserve the block structure? If simply run "U, S, Vh = np.linalg.svd(theta)" (where theta is the wavefunction in matrix from, i.e. it's obtained by
Code: Select all
theta = psi.get_theta(0)
theta = theta.combine_legs([('vL', 'p0'), ('p1', 'vR')], qconj=[+1, 1])
theta = theta.to_ndarray()
In the note, it said that we can do svd in each charge sector, I'm not sure how to do. For example, for a matrix form theta, it seems we need to do the inverse mapping first (split combined leg) to get a rank3 tensor with shape (chi, 4, chi) and do svd in each charege sector "theta[:, 0, :]", "theta[:, 1, :]", "theta[:, 2, :]", and "theta[:, 3, :]", i.e. do svd in sector (2, 0, 0, 2) respectively? Like in the follwing:
Code: Select all
theta = psi.get_theta(0)
theta = theta.combine_legs([('vL', 'p0'), ('p1', 'vR')], qconj=[+1, 1])
theta = theta.to_ndarray()
split_theta = np.zeros((chi, 4, chi))
for i in range(chi):
for j in range(2):
for k in range(chi):
for l in range(2):
split_theta[i, 2*j+l, k] = theta[2*i+j, 2*k+l]
In fact, I think somehow we can calculate the transfer matrix without using any knowledge of the charge conservation, i.e. with only a given matrix form theta (just the data of theta, extracted by using ".to_ndarray()"), we can obtain the transfer matrix. But I really donot know how to do this.
Thanks,
Qicheng

 Posts: 26
 Joined: 08 Jan 2019, 03:03
Re: Some questions about the svd_theta
There's another thing related, and I donnot understand how to deal with it.
For example, consider a spinhalf chain with conserved Sz, we can write down the 3 subblocks with Sz "2, 0, 2", In this case, we can do svd for each charge sector.
But in the case of, for example, TFI chain where the Sz is not conserved, the "2, 0, 2" are coupled, and we cannot do svd for each charge sector. In this case, how to do svd for the twosite wavefunction theta to get A and B?
For example, consider a spinhalf chain with conserved Sz, we can write down the 3 subblocks with Sz "2, 0, 2", In this case, we can do svd for each charge sector.
But in the case of, for example, TFI chain where the Sz is not conserved, the "2, 0, 2" are coupled, and we cannot do svd for each charge sector. In this case, how to do svd for the twosite wavefunction theta to get A and B?
Re: Some questions about the svd_theta
The conversion
For example, there is a tenpy.linalg.np_conserved.svd function direction in tenpy, which is aware of the charge block structure and does the svd for each block individually. Thus, this svd implementation (which at some point calls numpy's svd for the blocks) does not sort by singular values completely, but only within each block. Hence you should do something like
Take a look at
to_ndarray
discards information (namely: which index corresponds to which charges? what are the charge blocks we have?). Thus it cannot be reverted (at least not after subsequent tensordot/svd/...) and should be avoided at all. Instead you should use the functions provided by tenpy.linalg.np_conserved directly.For example, there is a tenpy.linalg.np_conserved.svd function direction in tenpy, which is aware of the charge block structure and does the svd for each block individually. Thus, this svd implementation (which at some point calls numpy's svd for the blocks) does not sort by singular values completely, but only within each block. Hence you should do something like
Code: Select all
import tenpy.linalg.np_conserved as npc
theta = psi.get_theta(0, i=2) # legs 'vL', 'p0', 'p1', 'vR'
theta = theta.combine_legs([('vL', 'p0'), ('p1', 'vR')], qconj=[+1, 1]) # labels '(vL.p0)', '(p1.vR)'
U, S, Vh = npc.svd(theta, inner_labels=['vR', 'vL']) # U has labels '(vL.p0)', 'vR'; V has labels 'vL', '(p1.vR)'
A0 = U.split_legs(['(vL.p0)']) # A has labels 'vL', 'p0', 'vR' and is leftcanonical
B1 = Vh.split_legs(['(p1.vR)']) # B has labels 'vL', 'p1', 'vR' and is rightcanonical
A0.ireplace_labels('p0', 'p')
B1.ireplace_labels('p1', 'p')
examples/a_np_conserved.py
for more details.If the hamiltonian doesn't preserve the total Sz, your MPS (ground state) also doesn't, and hence you don't run into that problem. In case of the TFI chain written as \(H = Sx.Sx + g Sz\), you can at most preserve the Sz parity, which has only two independent charge sectors. The svd can then be done in each sector individually.QichengTang wrote: ↑01 Jul 2019, 04:16But in the case of, for example, TFI chain where the Sz is not conserved, the "2, 0, 2" are coupled, and we cannot do svd for each charge sector. In this case, how to do svd for the twosite wavefunction theta to get A and B?

 Posts: 26
 Joined: 08 Jan 2019, 03:03
Re: Some questions about the svd_theta
Thank you, Johannes, now I'm clear with the svd process, but here appears another question.
As in the note said, the process of combination of two legs is something like mapping the indices for "vL" and "p" into something like "2*vL+p", so you can split out the physical leg by using a inverse mapping.
The question is, how to split out the physical leg after svd, i.e. how tenpy.linalg.np_conserved.split_legs works in the case of svd? It seems like, the mapping of indices we made in the process of leg combination) will be destroyed by svd, although the onetoone correspondence of indices exists, we donot know how to write down the inverse mapping to split out the physical leg.
In the total Sz conserved case, the different total Sz sectors are individual, so the block structure preserved after we do svd. Since the 2 degrees of freedom of the physical leg are "up" and "down" and we know exactly the total Sz of each block, we can split out the physical leg.
But in the case of TFI chain, when we do svd, there's no more concept of total Sz sectors, and I donot know how to split out the physical leg in this kind of cases.
As in the note said, the process of combination of two legs is something like mapping the indices for "vL" and "p" into something like "2*vL+p", so you can split out the physical leg by using a inverse mapping.
The question is, how to split out the physical leg after svd, i.e. how tenpy.linalg.np_conserved.split_legs works in the case of svd? It seems like, the mapping of indices we made in the process of leg combination) will be destroyed by svd, although the onetoone correspondence of indices exists, we donot know how to write down the inverse mapping to split out the physical leg.
In the total Sz conserved case, the different total Sz sectors are individual, so the block structure preserved after we do svd. Since the 2 degrees of freedom of the physical leg are "up" and "down" and we know exactly the total Sz of each block, we can split out the physical leg.
But in the case of TFI chain, when we do svd, there's no more concept of total Sz sectors, and I donot know how to split out the physical leg in this kind of cases.
Re: Some questions about the svd_theta
You can only split legs that were combined previously. In TeNPy, you can see that those legs store the charge data as tenpy.linalg.charges.LegPipe instead of tenpy.linalg.charges.LegCharge. Those pipes have the additional data needed to split the legs.
The matrices generated by SVD, say
Hence, if e.g. the
The matrices generated by SVD, say
A_ij = U_ik S_k V_kl
, keep the very same LegCharge/LegPipe instances for the outer legs i, l
, only the inner leg k
gets a new LegCharge instance.Hence, if e.g. the
i
was a pipe combining the left and physical indices of the B tensor, the U will also have the Pipe for index i
, such that it can be split off again.
 Posts: 26
 Joined: 08 Jan 2019, 03:03
Re: Some questions about the svd_theta
It's clear now, thanks for your help!Johannes wrote: ↑02 Jul 2019, 13:42You can only split legs that were combined previously. In TeNPy, you can see that those legs store the charge data as tenpy.linalg.charges.LegPipe instead of tenpy.linalg.charges.LegCharge. Those pipes have the additional data needed to split the legs.
The matrices generated by SVD, sayA_ij = U_ik S_k V_kl
, keep the very same LegCharge/LegPipe instances for the outer legsi, l
, only the inner legk
gets a new LegCharge instance.
Hence, if e.g. thei
was a pipe combining the left and physical indices of the B tensor, the U will also have the Pipe for indexi
, such that it can be split off again.