doping makes maxlinkdim get stuck at 1

Dear there,
I’m playing with the simple 2-leg Hubbard model. I attach my short code below. And I got a problem that is when I run the half filling case (I have 16x2 sites, so 32 particles in total), there’s no problem, but when I trying case like 1 electron per two sites (16 particles total), all my sweeps show maxlinkdim=1, even though I’ve set both max and min dim to be 256:
setmaxdim!(sweeps_tem,256) , setmindim!(sweeps_tem,256)
I’ve also attached this error results. Could you help to see what I’m doing wrong with this standard Hubbard model?
Thank you so much!!

flux(psi0) = QN(("Nf",16,-1),("Sz",0))
sweeps_tem = Sweeps
1 cutoff=1.0E-16, maxdim=512, mindim=512, noise=0.0E+00
2 cutoff=1.0E-16, maxdim=512, mindim=512, noise=0.0E+00
3 cutoff=1.0E-16, maxdim=512, mindim=512, noise=0.0E+00
4 cutoff=1.0E-16, maxdim=512, mindim=512, noise=0.0E+00
5 cutoff=1.0E-16, maxdim=512, mindim=512, noise=0.0E+00
6 cutoff=1.0E-16, maxdim=512, mindim=512, noise=0.0E+00

After sweep 1 energy=0.0  maxlinkdim=1 maxerr=0.00E+00 time=19.378
After sweep 2 energy=0.0  maxlinkdim=1 maxerr=0.00E+00 time=0.017
After sweep 3 energy=0.0  maxlinkdim=1 maxerr=0.00E+00 time=0.026
After sweep 4 energy=0.0  maxlinkdim=1 maxerr=0.00E+00 time=0.017
After sweep 5 energy=0.0  maxlinkdim=1 maxerr=0.00E+00 time=0.025
After sweep 6 energy=0.0  maxlinkdim=1 maxerr=0.00E+00 time=0.016
using ITensors
using HDF5
	let
	  N = 16
      Npart = 16
	  t = 1.0
      U = 1.0 
      
      sites = Vector{Index}(undef,2N)
      for j=1:2N
      sites[j] = siteind("Electron";addtags="n=$j",conserve_qns=true)  
      end

	  ampo = OpSum()
	  # x direction:
	  for n in 0:1
	    for i in n+1:2:(n+1+2*(N-2))
            ampo += -t, "Cdagup", i,     "Cup", i + 2
            ampo += -t, "Cdagup", i + 2, "Cup", i
            ampo += -t, "Cdagdn", i,     "Cdn", i + 2
            ampo += -t, "Cdagdn", i + 2, "Cdn", i
        end
      end
      
	  # y direction:
	  for i in 1:2:31
            ampo += -t, "Cdagup", i,       "Cup", i + 1
            ampo += -t, "Cdagup", i + 1,   "Cup", i
            ampo += -t, "Cdagdn", i,       "Cdn", i + 1
            ampo += -t, "Cdagdn", i + 1,   "Cdn", i
      end
      
      # Hubbard U interaction
      for i in 1:2N
        ampo += U, "Nup", i, "Ndn", i
      end

	  H = MPO(ampo, sites)
	   
	  state = ["Emp" for n in 1:2N]
	  p = Npart
	  count=1

      # Half filling case (no problem)
      for i in 1:2N
	    state[i]= (isodd(count) ? "Up" : "Dn")
	    count += 1
	  end

     # 1 electrons per two sites  (get stuck at maxlinkdim=1)
      for i in 1:4:31
	    println("$i")
	    state[i]= (isodd(count) ? "Up" : "Dn")
	    count += 1
	  end
	  for i in 2:4:32
	    println("$i")
	    state[i]= (isodd(count) ? "Up" : "Dn")
	    count += 1
	  end
	  

      psi0 = productMPS(sites, state)
	  @show flux(psi0)


 
	  # Start DMRG calculation:   
	   
	  sweeps_tem= Sweeps(10)      
	  bond=256
 	  setmaxdim!(sweeps_tem,bond)  
 	  setmindim!(sweeps_tem,bond)
 	  @show sweeps_tem     

      energy, psi_tem = dmrg(H, psi0, sweeps_tem; eigsolve_tol=1e-6)

	end

So very subtle thing - essentially the eigensolver is getting stuck on your zero energy initial state. I suggest two ways around this:

  • Change the initial state
    • e.g. on the 2:4:32 loop change the state to "Dn":"Up"
    • In general explore different initial states (randomMPS etc)
    • Also since you’re using U=1 I would suggest checking out ITensorGaussianMPS
  • Add noise via setnoise! which will kick it out of this local minimum
1 cutoff=1.0E-16, maxdim=256, mindim=256, noise=1.0E-04
2 cutoff=1.0E-16, maxdim=256, mindim=256, noise=1.0E-08
3 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
4 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
5 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
6 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
7 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
8 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
9 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
10 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00

After sweep 1 energy=-31.760666337294182  maxlinkdim=256 maxerr=4.20E-06 time=5.672
After sweep 2 energy=-33.69509755771345  maxlinkdim=256 maxerr=2.11E-06 time=10.813
After sweep 3 energy=-33.904212229406134  maxlinkdim=256 maxerr=1.62E-06 time=8.891
After sweep 4 energy=-33.91973697981166  maxlinkdim=256 maxerr=8.51E-07 time=8.446
After sweep 5 energy=-33.921146348939324  maxlinkdim=256 maxerr=7.85E-07 time=8.158
After sweep 6 energy=-33.92125464390863  maxlinkdim=256 maxerr=6.98E-07 time=8.374
After sweep 7 energy=-33.921257483852635  maxlinkdim=256 maxerr=5.34E-07 time=8.459
After sweep 8 energy=-33.92125757700647  maxlinkdim=256 maxerr=5.31E-07 time=8.329
After sweep 9 energy=-33.92125757815557  maxlinkdim=256 maxerr=5.31E-07 time=8.557
After sweep 10 energy=-33.92125757774615  maxlinkdim=256 maxerr=5.31E-07 time=8.775

See this page for more: DMRG FAQs · ITensors.jl

2 Likes

Thank you so much for your reply! I just tried changing state to "Dn":"Up" in 2:4:32 loop and it immediately solves my problem. But I’m a little confused about why this initial state doesn’t get the simulation stuck but the previous one does. I thought the difference is just starting both raws with Up spin or starting 1 raw with Up and the other with Dn. Why “Up+Dn” setting would cause stuck problem?

And another quick question, after I change to "Dn":"Up" in 2:4:32, the results are as below. I just wonder why in the first sweep my maxlinkdim=16? (I’ve used setmindim!(sweeps,256), so I thought it’ll all start with 256. I’ve also tried your setnoise! method, in that way I do have all sweeps with dim=256 as you show) I do this because I want to avoid starting simulation with very small bonddim, but it seems I can’t avoid it in some situation?

Thank you so much!

1 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
2 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
3 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
4 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
5 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
6 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
7 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
8 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
9 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00
10 cutoff=1.0E-16, maxdim=256, mindim=256, noise=0.0E+00

After sweep 1 energy=-32.99985778491951  maxlinkdim=16 maxerr=0.00E+00 time=24.372
After sweep 2 energy=-33.915259892864206  maxlinkdim=256 maxerr=0.00E+00 time=3.677
After sweep 3 energy=-33.92108446775214  maxlinkdim=256 maxerr=2.83E-07 time=11.960
After sweep 4 energy=-33.92125115571354  maxlinkdim=256 maxerr=6.49E-07 time=11.506
After sweep 5 energy=-33.921257296065775  maxlinkdim=256 maxerr=5.44E-07 time=10.977
After sweep 6 energy=-33.92125750804987  maxlinkdim=256 maxerr=5.27E-07 time=10.100
After sweep 7 energy=-33.921257541294985  maxlinkdim=256 maxerr=5.27E-07 time=9.572
After sweep 8 energy=-33.9212575712304  maxlinkdim=256 maxerr=5.28E-07 time=9.922
After sweep 9 energy=-33.921257571701645  maxlinkdim=256 maxerr=5.28E-07 time=10.680
After sweep 10 energy=-33.92125757153307  maxlinkdim=256 maxerr=5.28E-07 time=10.307

I’m not sure about the answer to your first question about initial state – maybe Ryan has a good guess or intuition there, but about the second question: it’s actually a very good thing to have a DMRG calculation initially start with a smaller bond/link dimension as long as it doesn’t stay stuck at that small dimension forever.

A really good strategy to converge DMRG results more reliably and in a shorter total time is to do many sweeps (e.g. 10 or 20 sweeps) at a lower bond dimension, like \chi=20, say, then gradually raise the bond dimension at the end to the final value needed for the most accuracy, so like doing two or four sweeps at the very end at \chi=256.

1 Like

Oh I see! Thank you for letting me this strategy!
But just curious, for this setmindim! function itself, if I want to control the bonddim in each sweep exactly, like I want it start exactly from dim=20 for 5 sweeps, can I do this by setting both maxdim and mindim to be 20? Or even I do this, the simulation will still start with other bonddim that’s lower than what I’ve set for mindim?
Thank you!

re: the initial state, if you look on the first site you have two up spins next to each other (then two down etc). The hop from site 1<->2 is disallowed, I think that is what trips up the eigensolver in this low rank environment (just a hunch though). By switching up->down, site 1 and 2 etc can hop ‘freely’.

1 Like

If you set the cutoff to be really small, like 1E-16, then it will almost certainly make DMRG saturate to the maxdim that you set. So that is a good way to do it. Then toward the end of your calculation it can be a good idea to raise the cutoff somewhat, to 1E-12 for very high accuracy, or 1E-8 for high accuracy, or 1E-6 for good accuracy, which can automatically detect if you can get away with a lower bond dimension and save you computing time.

1 Like

Got it! Thank you so much!

Oh I see! I didn’t notice this!
And just a double check, you mentioned because my U=1, I can try the GaussianMPS, I just start reading that, it says it creates a MPS of a free fermion (Gaussian) state, so is it because my interaction U is very small, so I could try starting with a free fermion state?

Yes exactly, the free fermion state (U=0) is generally a good starting guess when U is small

1 Like

Your interaction doesn’t have to be small for a Gaussian starting state to help you, though it’s a very good question or concern. More practially, the Gaussian state will already do a good job of minimizing the hopping part of the Hamiltonian so that all DMRG has to do is make small corrections to include the effect of the interacting part. Perhaps for very large U a different starting state could be better but Gaussian is always reasonable to try.

1 Like

Thank you!

I see! Thank you!