By putting the correct definitions of the creation and annihilation operators, the model seems to converge towards the ground state energy. We can compare the variational state (red curve) with the ED results (black lines).
Could you perhaps explain what type of errors you are getting?
the hamiltonian is hermitean, despite the mistake in labeling the functions, the energy should be exactly the same, we just need to swap the names of the functions !
Thanks for the prompt response and sorry for causing confusion. I thought the wrong hopping term is already crucial so I didn't explain more. I should be more specific:
I actually changed the setting in the original file to 1d hubbard chain model (L=2, D=1, t=2, U=0.01, n_fermion=(1,1)), and find VMC results has an overall minus sign compared to exact results
E_0
.
I think the reason is the wrong hopping term in orignal file, which reads
, I think there should be a overall minus sign compared to the correct hopping term and this explains the sign problem in VMC and exact values.
After I swap the name, the results becomes reasonable:
Strangely, for D=2, 2d hubbard model
H_{\rm wrong}
will still gives the right answer and I don't know why. Maybe due to the particle-hole symmetry for half filling system? Or my setting could be wrong?
Below are the modified file, I only changed the value of L, D, t, U and n_fermion.
importnetketasnkimportnumpyasnpimportmatplotlib.pyplotaspltimportjsonfromnetketimportexperimentalasnkxL=2# take a 2x2 latticeD=1t=2# tunneling/hoppingU=0.01# coulomb# create the graph our fermions can hop ong=nk.graph.Hypercube(length=L,n_dim=D,pbc=True)n_sites=g.n_nodes# create a hilbert space with 2 up and 2 down spinshi=nkx.hilbert.SpinOrbitalFermions(n_sites,s=1/2,n_fermions=(1,1))# create an operator representing fermi hubbard interactions# -t (i^ j + h.c.) + U (i^ i j^ j)# we will create a helper function to abbreviate the creation, destruction and number operators# each operator has a site and spin projection (sz) in order to find the right position in the hilbert space samplesdefc(site,sz):returnnkx.operator.fermion.create(hi,site,sz=sz)defcdag(site,sz):returnnkx.operator.fermion.destroy(hi,site,sz=sz)defnc(site,sz):returnnkx.operator.fermion.number(hi,site,sz=sz)up=+1/2down=-1/2ham=0.0forszin(up,down):foru,ving.edges():ham+=-t*cdag(u,sz)*c(v,sz)-t*cdag(v,sz)*c(u,sz)foruing.nodes():ham+=U*nc(u,up)*nc(u,down)ed_energies=np.linalg.eigvalsh(ham.to_dense())print("Hamiltonian =",ham.operator_string())# metropolis exchange moves fermions around according to a graph# the physical graph has LxL vertices, but the computational basis defined by the# hilbert space contains (2s+1)*L*L occupation numbers# by taking a disjoint copy of the lattice, we can# move the fermions around independently for both spins# and therefore conserve the number of fermions with up and down spin# g.n_nodes == L*L --> disj_graph == 2*L*Ldisj_graph=nk.graph.disjoint_union(g,g)sa=nk.sampler.MetropolisExchange(hi,graph=disj_graph,n_chains=16)# since the hilbert basis is a set of occupation numbers, we can take a general RBM# we take complex parameters, since it learns sign structures more easily, and for even fermion number, the wave function might be complexma=nk.models.RBM(alpha=1,param_dtype=complex,use_visible_bias=False)vs=nk.vqs.MCState(sa,ma,n_discard_per_chain=100,n_samples=512)# we will use sgd with Stochastic Reconfigurationopt=nk.optimizer.Sgd(learning_rate=0.01)sr=nk.optimizer.SR(diag_shift=0.1)gs=nk.driver.VMC(ham,opt,variational_state=vs,preconditioner=sr)# now run the optimization# first step will take longer in order to compileexp_name="fermions_test"gs.run(500,out=exp_name)############## plot #################withopen(f"{exp_name}.log","r")asf:data=json.load(f)x=data["Energy"]["iters"]y=data["Energy"]["Mean"]["real"]# plot the energy levelsplt.axhline(ed_energies[0],color="red",label="E0")foreined_energies[1:]:plt.axhline(e,color="black")plt.plot(x,y,color="blue",label="VMC")plt.xlabel("step")plt.ylabel("E")plt.legend()plt.show()
The naming issue was not affecting the number operator, that was defined separately and in the correct way, so since the hopping is invariant under renaming of c and cdagger, there was no actual problem with the energy... On the other hand I'm not sure I understand the context of the minus sign issue you mention
yes you are actually right, it was my oversight. Thank you for catching this issue, indeed this is still in the Experimental branch of netket because it is not fully tested, so if you find other inconsistencies please tell us.