# Singular values are not sorted with conserved parity?

Hi Miles,

I thought the singular values are sorted from the largest to the smallest after "svd". But it seems they are not if we conserve the parity. It is easy to sort by ourselves, but I'm not sure if you missed it for ConserveParity=true. Thanks.

#include "itensor/all.h"
using namespace itensor;

int
main()
{
int N = 8;

auto sites = SpinHalf(N,{"ConserveSz=",false, "ConserveParity",true});

auto ampo = AutoMPO(sites);
for(int j = 1; j < N; ++j)
{
ampo += 0.5,"S+",j,"S-",j+1;
ampo += 0.5,"S-",j,"S+",j+1;
ampo +=     "Sz",j,"Sz",j+1;
}
auto H = toMPO(ampo);

auto sweeps = Sweeps(20); //number of sweeps is 5
sweeps.maxdim() = 10,20,100,100,200;
sweeps.cutoff() = 1E-10;

auto state0 = InitState(sites);
for(int is = 1; is <= N; ++is)
{
state0.set(is,is%2==1 ? "Up" : "Dn");
//state0.set(is,"Dn");
}

auto psi0 = randomMPS(state0);

auto [energy,psi] = dmrg(H,psi0,sweeps,{"Quiet",true,"EnergyErrgoal=",1e-6,"EntropyErrgoal=",1e-5});

println("Ground State Energy = ",energy);

auto b = 4;

//"Gauge" the MPS to site b
psi.position(b);

//SVD this wavefunction to get the spectrum
//of density-matrix eigenvalues
auto s = siteIndex(psi,b);
auto [U,S,V] = svd(psi(b),{l,s});
auto u = commonIndex(U,S);

//Apply von Neumann formula
//to the squares of the singular values
Real SvN = 0.;
for(auto n : range1(dim(u)))
{
auto Sn = elt(S,n,n);
auto p = sqr(Sn);
if(n<=4) println(n, " ", p);
if(p > 1E-14) SvN += -p*log(p);
}
printfln("Across bond b=%d, SvN = %.10f",b,SvN);

return 0;
}


Jin

Hi Jin,
Thanks for the question. However, when I run the sample code you posted, I get the following output at the end:

Ground State Energy = -3.37493
1 0.893389
2 0.035519
3 1.64686e-05
4 4.13928e-06
Across bond b=4, SvN = 0.4569757731

which is indeed sorted. Are you seeing a very different output and can you post which singular values you are seeing?

Best,
Miles

commented by (1.2k points)
Hi Miles, thanks for the reply. During the sweep, the output shows that

vN Entropy at center bond b=4 = 0.456975773109
Eigs at center bond b=4: 0.8934 0.0355 0.0355 0.0355
Largest link dim during sweep 4/20 was 16
Largest truncation error: 9.15589e-17
Energy after sweep 4/20 is -3.374932598688
Sweep 4/20 CPU time = 0.0292s (Wall time = 0.0312s)

The first 4 biggest singular values should be 0.8934 0.0355 0.0355 0.0355. The last two are placed somewhere else.
+1 vote

Hi Jin,
Ok now I've figured it out. This will be the official answer (I had missed a detail about the code in my other answer).

The answer is that, no, the diagonal entries in the S tensor are in general not sorted. They are sorted within each block, but not across blocks. This is chosen so that U and V can retain a block-sparse structure when conserving quantum numbers.

So one way to get a sorted list of all of the singular values is to loop over them all first, put them into a std::vector, then call std::sort on that vector.

Another way is to call the older interface for the SVD that takes U,S, and V as (reference) arguments:
http://itensor.org/docs.cgi?vers=cppv3&page=classes/decomp
This older interface returns a Spectrum object which can be used to access a sorted list of all of the density matrix eigenvalues (squares of singular values).

Best regards,
Miles

P.S. just for extra info, the behavior of the code in the presence of quantum numbers is not specifically programmed for each kind of quantum number, such as parity or otherwise. It is written in a very generic way, so would likely either work for parity and all other types of quantum numbers or fail for parity as well as all other quantum numbers.

commented by (1.2k points)
I see, thanks for the detail explanations.