I'm failing to generalize the example in the sample code Measure a correlator from an MPS wavefunction to assign the entries across the lattice in the C++ version. When applying to say, the Kitaev wire model, I can create the MPS and calculate one correlation, but when I try to generalize to measuring it across the lattice and assigning that to a 1-d array, I get an error Wrong number of IndexVals passed to elt/eltC. (expected 0, got 4)
, with that error having been expected 2 at some version for debugging. Additionally, when I attempt to do this, I get the following before that error message:
inds () =
(dim=2|id=943|"n=2,Site,Fermion") <Out>
1: 1 QN({"Pf"}, 0, -2})
2: 1 QN({"Pf"}, 1, -2})
(dim=2|id=173|"n=2,Site,Fermion") <In>
1: 1 QN({"Pf"}, 0, -2})
2: 1 QN({"Pf"}, 1, -2})
(dim=2|id=173|"n=2,Site,Fermion") <Out>
1: 1 QN({"Pf"}, 0, -2})
2: 1 QN({"Pf"}, 1, -2})
(dim=2|id=943|"n=2,Site,Fermion") <In>
1: 1 QN({"Pf"}, 0, -2})
2: 1 QN({"Pf"}, 1, -2})
Which clearly has something to do with the QN Objects, but I'm not sure exactly what. It doesn't help that I haven't used C/C++ in a long time, so having most everything listed as auto
for the datatype is somewhat dissatisfying. I attempted to use typeid
to determine what I should be using for datatypes in these examples, but that failed fantastically. My guess is that there is an issue when I attempt to put the left and right index linking in multiple times? Then the operators that I stick into elt
are defined properly?
I've attached two basic codes, a "Good" single correlation calculation, and a "Bad" multiple-site calculation. To keep things simple, I haven't tried to optimize the bad example, which will come after I get something to work. You'll also notice that I assign the correlation for site jj=3
to element 3 of the 1D array but L=20 here so it's not something I'm worried about. Though it is so embarrassing when my Fortran slips out in public.
Here is the "Good" implementation that runs, computes the ground state energy, and spits out a single correlation:
`
#include "itensor/all.h"
using namespace itensor;
int main()
{
int L = 20;
auto psites = Fermion(L,{"ConserveNf",false});
auto mu = 0.1;
auto t = 1.0 ;
auto Delta = 1.0;
// Create the operators for building the Hamiltonian
auto ampo = AutoMPO(psites);
for( auto ii:range1(L-1))
{
ampo += mu, "N", ii;
// ampo += mu, "N"-0.5, ii;
ampo += -t, "Cdag", ii, "C", ii+1;
ampo += -t, "Cdag", ii+1, "C", ii;
ampo += Delta, "Cdag", ii, "Cdag", ii+1;
ampo += Delta, "C", ii+1, "C", ii;
}
// Add the final site's chemical potential term
ampo += mu,"N",L;
// Generate the Hamiltonian
auto H = toMPO(ampo);
auto state = InitState(psites);
// Set the initial state to be a product state
// such that it is within the symmetry sector
// OLD for Fermion Hopping: auto state = InitState(psites,"Emp");
for(int is = 1; is <= L; ++is)
{
state.set(is, is%2==1 ? "1" : "0");
}
auto psi0 = randomMPS(state);
for( auto ii : range1(L) ) if( ii%2==0 ) state.set(ii,"Occ");
// Set the number of DMRG sweeps
auto sweeps = Sweeps(5);
// Set the maximum bond dimension per sweep
// Setting it low initially allows the computation to be much faster
sweeps.maxdim() = 10,20,100,100,200;
// Set the cutoff for the bond dimension
sweeps.cutoff() = 1E-10;
// Run the DMRG
auto [energy,psi] = dmrg(H,psi0,sweeps,"Silent");
// Calculate the energy and state
println("Ground state energy is ", energy) ;
auto ii = 1;
auto jj = 3;
auto Adag_ii = op(psites,"Adag",ii);
auto A_jj = op(psites,"A",jj);
// 'gauge' the MPS to site i
// any 'position' between i and j, inclusive, would work here
psi.position(ii);
auto psidag = dag(psi);
psidag.prime();
// index linking ii to ii-1:
auto lii_1 = leftLinkIndex(psi,ii);
auto Cij = prime(psi(ii),lii_1)*Adag_ii*psidag(ii);
for(int kk = ii+1; kk < jj; ++kk)
{
Cij *= psi(kk);
Cij *= op(psites,"F",kk); // J-W string - need to add the "F" argument in between
Cij *= psidag(kk);
}
// index linking jj to jj+1
auto ljj = rightLinkIndex(psi,jj);
Cij *= prime(psi(jj),ljj);
Cij *= A_jj;
Cij *= psidag(jj);
float GFjjresult = elt(Cij); // use eltC if expecting complex
std::cout << GFjjresult << ' ';
return 0;
}
`
And here is the "Bad" implementation where everything goes to heck:
`
#include "itensor/all.h"
using namespace itensor;
int main()
{
int L = 20;
auto psites = Fermion(L,{"ConserveNf",false});
auto mu = 0.1;
auto t = 1.0 ;
auto Delta = 1.0;
// Create the operators for building the Hamiltonian
auto ampo = AutoMPO(psites);
for( auto ii:range1(L-1))
{
ampo += mu, "N", ii;
// ampo += mu, "N"-0.5, ii;
ampo += -t, "Cdag", ii, "C", ii+1;
ampo += -t, "Cdag", ii+1, "C", ii;
//
ampo += Delta, "Cdag", ii, "Cdag", ii+1;
ampo += Delta, "C", ii+1, "C", ii;
}
// Add the final site's chemical potential term
ampo += mu,"N",L;
// Generate the Hamiltonian
auto H = toMPO(ampo);
auto state = InitState(psites);
// Set the initial state to be a product state
// such that it is within the symmetry sector
// OLD for Fermion Hopping: auto state = InitState(psites,"Emp");
for(int is = 1; is <= L; ++is)
{
state.set(is, is%2==1 ? "1" : "0");
}
auto psi0 = randomMPS(state);
for( auto ii : range1(L) ) if( ii%2==0 ) state.set(ii,"Occ");
// Set the number of DMRG sweeps
auto sweeps = Sweeps(5);
// Set the maximum bond dimension per sweep
// Setting it low initially allows the computation to be much faster
sweeps.maxdim() = 10,20,100,100,200;
// Set the cutoff for the bond dimension
sweeps.cutoff() = 1E-10;
// Run the DMRG
auto [energy,psi] = dmrg(H,psi0,sweeps,"Silent");
// Calculate the energy and state
println("Ground state energy is ", energy) ;
auto ii = 1;
Real GF1jj[L];
auto jj = 3;
auto Adag_ii = op(psites,"Adag",ii);
auto A_jj = op(psites,"A",jj);
// 'gauge' the MPS to site i
// any 'position' between i and j, inclusive, would work here
psi.position(ii);
auto psidag = dag(psi);
psidag.prime();
// index linking ii to ii-1:
for(int jj=ii+1; jj < L; ++jj)
{
auto lii_1 = leftLinkIndex(psi,ii);
auto Cij = prime(psi(ii),lii_1)*Adag_ii*psidag(ii);
for(int kk = ii+1; kk < jj; ++kk)
{
Cij *= psi(kk);
Cij *= op(psites,"F",kk); // J-W string - need to add the "F" argument in between
Cij *= psidag(kk);
}
// index linking jj to jj+1
auto ljj = rightLinkIndex(psi,jj);
Cij *= prime(psi(jj),ljj);
Cij *= A_jj;
Cij *= psidag(jj);
Real GFjjresult = elt(Cij); // use eltC if expecting complex
GF1jj[jj] = GFjjresult;
}
std::cout << GF1jj[3] << ' ';
return 0;
}
`