Making a Custom DMRG Observer
The Observer system lets you define custom measurements to be performed within algorithms
such as DMRG and time evolution. For the DMRG algorithm, you can make a subclass of
the DMRGObserver
type to implement custom measurements and printing of information
from the ITensor dmrg
function.
Let's see how to make a custom DMRG Observer by way of example.
Making our CustomObserver type
First make a type that is a subclass of DMRGObserver
. We will call ours
CustomObserver
:
class CustomObserver : public DMRGObserver
{
public:
CustomObserver(MPS const& psi,
Args const& args = Args::global())
: DMRGObserver(psi)
{}
}; // class CustomObserver
Note that the parent type, DMRGObserver
, requires an MPS to be
passed to it, so we also require our CustomObserver
to take an
MPS in its constructor. This MPS is a reference to the one
being optimized by the dmrg
function.
Overloading the measure
method
The DMRGObserver::measure
method is what gets called by the dmrg
function after
each step. We can overload this method to change the information that gets
printed by the dmrg
function or to perform other custom measurements.
To overload measure
, first we need to declare it as one of CustomObserver
's methods:
class CustomObserver : public DMRGObserver
{
public:
CustomObserver(MPS const& psi,
Args const& args = Args::global())
: DMRGObserver(psi)
{}
void virtual
measure(Args const& args);
}; // class CustomObserver
Next we need to actually define this method (outside of the class):
void CustomObserver::
measure(Args const& args = Args::global())
{
// your custom measurement code goes here
}
Now we can put any code we want into measure
to measure the state being optimized
by dmrg
or report on the status of the DMRG optimization process.
Customizing the measure
method
What kind of properties are available to measure
? First of all, we can access
the MPS being optimized by DMRG by calling DMRGObserver::psi()
:
void CustomObserver::
measure(Args const& args = Args::global())
{
// Obtain a reference to psi, the MPS being optimized:
auto& psi = DMRGObserver::psi();
}
Just as usefully, we can get a lot of information from the dmrg
function
itself that gets passed as named arguments through the args
object.
Here are the different named arguments available:
void CustomObserver::
measure(Args const& args = Args::global())
{
// Obtain a reference to psi, the MPS being optimized:
auto& psi = DMRGObserver::psi();
// How many sweeps of DMRG are to be performed:
auto nsweep = args.getInt("NSweep",0);
// Which sweep of DMRG we are on:
auto sw = args.getInt("Sweep",0);
// Which half sweep of DMRG we are on:
auto ha = args.getInt("HalfSweep",0);
// Which bond DMRG is on:
auto b = args.getInt("AtBond",1);
// What is the current energy?
auto energy = args.getReal("Energy",0);
// What was the last truncation error computed?
auto truncerr = args.getReal("Truncerr",0);
// What is the current truncation error cutoff?
auto cutoff = args.getReal("Cutoff",0);
// What is the current maximum bond dimension?
auto maxdim = args.getInt("MaxDim",0);
// Should output be silenced?
auto silent = args.getBool("Silent",false);
}
You do not have to define all of these variables. The code above is just to illustrate which named arguments are available to you to use.
Calling the default DMRGObserver::measure
method
When you overload measure
, by default it "shadows" the one defined
by DMRGObserver
which will no longer get called. However, the implementation of
measure
inside of DMRGObserver
performs a number of useful measurements,
such as reporting the entanglement entropy at the center of the MPS during
each sweep.
To still run the DMRGObserver::measure
method while also having your own
custom implementation, just put the line DMRGObserver::measure(args);
somewhere inside your own measure
function.
Overloading the checkDone
method
Subclasses of DMRGObserver
can also overload a method named checkDone
which returns a bool
. If checkDone
returns true
, then the dmrg
function will exit,
returning the current energy and MPS wavefunction.
To overload checkDone
, first declare it in your CustomObserver
class:
class CustomObserver : public DMRGObserver
{
public:
CustomObserver(MPS const& psi,
Args const& args = Args::global())
: DMRGObserver(psi)
{}
void virtual
measure(Args const& args);
bool virtual
checkDone(Args const& args);
}; // class CustomObserver
Next define the checkDone
method itself (outside of the class):
bool virtual
checkDone(Args const& args = Args::global())
{
return false;
}
To customize this method, you can read in the same set of named arguments as
in the measure
function above. Let's use just one of them, the energy, to
determine when we are going to stop our dmrg
calculation:
bool virtual
checkDone(Args const& args = Args::global())
{
auto energy = args.getReal("Energy");
if(energy < -100.0) return true;
return false;
}
This is just a contrived example, with -100 being a made-up value, and in
your own application you might want to store the last reported energy inside
your CustomObserver
and check whether the latest energy differs from
the last one by some relative amount. Or you could set a checkDone
criterion
based on the truncation error, entanglement entropy, or any other quantity
you wish.
Back to Formulas
Back to Main