Hi Miles,
For sure the things that have if( nc_ == 2) else if (nc_ == 1) etc in them need to be extended, but I'm confused at the level of overhauling needed in the localmpo code. For instance,if I'm just inputting an MPO and a NumCenter argument, then I think this is the primary snippet of code to focus on for calling localMPO (line 275 of
https://github.com/ITensor/ITensor/blob/v3/itensor/mps/localmpo.h)
inline LocalMPO::
LocalMPO(const MPO& H,
const Args& args)
: Op_(&H),
PH_(H.length()+2),
LHlim_(0),
RHlim_(H.length()+1),
nc_(2),
Psi_(0)
{
if(args.defined("NumCenter"))
numCenter(args.getInt("NumCenter"));
}
Do RHlim and PH_ need to depend on the NumCenter argument? What I'm imagining is that we add fictitious sites past the actual physical system and set the bonds to those sites as 0 and so the +1 or +2 in the arguments of RHlim_ and PH_ account for the extra sites in the usual 2-site DMRG?
If I adapt something like
if(nc_ == 2)
lop_.update(Op_->A(b), Op_->A(b+1), L(), R());
else if(nc_ == 1)
lop_.update(Op_->A(b), L(), R());
else if(nc_ == 0)
lop_.update(L(),R());
to add an additional operator as M1 (middle 1)
if(nc_ == 3)
lop_.update(Op_->A(b), Op_->A(b+1), Op_->A(b+2), L(), M1(), R());
else if(nc_ == 2)
lop_.update(Op_->A(b), Op_->A(b+1), L(), R());
else if(nc_ == 1)
lop_.update(Op_->A(b), L(), R());
else if(nc_ == 0)
lop_.update(L(),R());
end
then I get an error that M1 is undefined, which makes sense since L and R are defined in statements like
ITensor const&
L() const { return PH_[LHlim_]; }
// Replace left edge tensor at current bond
void
L(ITensor const& nL) { PH_[LHlim_] = nL; }
// Replace left edge tensor bordering site j
// (so that nL includes sites < j)
void
L(int j, ITensor const& nL);
But for M1, would something like this work
ITensor const&
M1() const { return PH_[LHlim_ + 1]; }
// Replace left edge tensor at current bond
void
M1(ITensor const& nM1) { PH_[LHlim_+1] = nM1; }
// Replace left edge tensor bordering site j
// (so that nM1 includes sites < j)
void
M1(int j, ITensor const& nM1);
?
PH_ is some vector of ITensors, but I'm not really sure what nL/nR/nM1 really means in this code. They're defined as ITensor objects (object used loosely here - I'm not sure if it's exactly a CC+ object in the jargon) and a constant, so I suppose it shouldn't be changed mid-call to L, R, or M1. Searching the localmpo.h file linked to above, I don't see any calls to L() or R() that don't use empty parentheses for me to try to figure it out.
I attempted (admittedly, not very hard) to look up tutorials on classes in C++, and they define things like a rectangle or other cute but not very useful classes that always take the same inputs.
As an aside, I'm not sure that this is the best path to my goal.
My main purpose of this is to find more accurate MPS approximations of a pair of nearly degenerate states.
My *hope* is that enlarging the number of sites that the DMRG optimizes over would help improve the ability to distinguish between the two nearly degenerate states. Using a randomMPS fails (and a random initial ansatz performs worse on exact diagonalization code in Fortran compared to other initial ansatz that may as well be random with respect to the ground state), and adding noise doesn't seem to help (I've tried variants of maximum number of bonds, noise size, etc).
- I haven't attempted using pinning fields at the opposite ends of the lattice to get the state close, then rerunning without the pinning fields to optimize.
- Another thing I haven't tried is taking a MPS, and (somehow) splitting it into two to try to find better approximations to the states then rerunning the DMRG using those as the starting states.
Jared