# [Julia] Largest truncation error in DMRG output

+1 vote

Hi,

I've been using the julia version of ITensor lately, and I noticed that calling DMRG by default does not print any information regarding the maximum truncation error for each sweep, unlike the C++ version. I've searched the documentation but could not find anything related to the truncation error. Is there some way to turn this feature on? Or is it just not implemented yet?

Best,

Rafael

commented by (51.6k points)
Hi Rafael,
Currently this feature just isn't implemented in the Julia version. Is it something you would be willing to contribute? In the C++ version it's implemented through the DMRGObserver type (in its measure function) which in Julia is all in the file src/mps/observer.jl.

Alternatively, if you want to keep track of the truncation error just in your own custom code, you can make a custom observer type as detailed on this documentation page:

https://itensor.github.io/ITensors.jl/stable/Observer.html

Miles
commented by (200 points)
Hi Miles,

Thanks for the reply. I will take a look into DMRGObserver and custom observers to see if I can implement it in a convenient way.

Best,

Rafael
commented by (51.6k points)
Great. Thanks for being open to trying that. If you find you get stuck or have questions along the way, please just post a reply here and I will see it, or email me.

Basically the pattern is that you should either alter DMRGObserver (and then send us a pull request to merge your changes) or make your own new observer, which could be modeled on DMRGObserver, that stores like a "max_trunc_err" variable inside it. Then before each sweep you would reset this to zero, and each time you get a report of the truncation error inside the measure! function (it is passed as one of the keyword arguments), you would call
max_trunc_err = max(max_trunc_err, truncerr)
to update max_trunc_err. At the end of the sweep you'd print out this value and again reset it to zero.

Miles
commented by (200 points)
Hi Miles,

I have tried following your directions but for some reason I am still unable to get the largest truncation error. I have created a new observer containing a max_trunc_err variable, and overloaded the measure! and checkdone! functions so that measure! does max_trunc_err = max(max_trunc_err, truncerr), and checkdone! prints the max_trunc_err and then resets its value to 0. From what I understand, it seems like the checkdone! function is only called at the end of a sweep, while the measure! function is called every step of every sweep, so I thought it should work. However, I always get a value of 0 for the largest truncation error. Here is a minimum working example:

using ITensors

mutable struct DemoObserver <: AbstractObserver
max_trunc_err::Float64
end

function ITensors.measure!(obs::DemoObserver;kwargs...)
truncerr = truncerror(kwargs[:spec])
max_trunc_err=max(obs.max_trunc_err,truncerr)
end

function ITensors.checkdone!(obs::DemoObserver;kwargs...)
println("Largest truncation error = ",obs.max_trunc_err)
obs.max_trunc_err=0.0
return false
end

let
N = 10
max_trunc_err = 0.0

s = siteinds("S=1/2",N)

a = AutoMPO()
for n=1:N-1
a += "Sz",n,"Sz",n+1
a += 0.5,"S+",n,"S-",n+1
a += 0.5,"S-",n,"S+",n+1
end
H = MPO(a,s)
psi0 = randomMPS(s,4)

sweeps = Sweeps(5)
maxdim!(sweeps,10)

obs = DemoObserver(max_trunc_err)

println("Starting DMRG")
energy, psi = dmrg(H,psi0,sweeps; observer=obs, outputlevel=1)

return
end

Do you know what I am doing wrong? Did I misunderstand how/where each of these functions are called?

Best,

Rafael
commented by (51.6k points)
Thanks for working on this. I think I see what the issue is. On the following line inside of measure!:

max_trunc_err=max(obs.max_trunc_err,truncerr)

the variable max_trunc_err here is being created as a new local variable inside that function. It is not having the effect of updating the max_trunc_err inside of the obs object but just has the same name as that variable.

I think if you just change the line to:

obs.max_trunc_err=max(obs.max_trunc_err,truncerr)

then it should work the way you expect.
commented by (51.6k points)
By the way that's clever to put the printout into the checkdone! function. I had not thought of using it that way. Normally what I would have done is to get the info about what bond and half-sweep one is on from the keyword args to the measure! function. Then if the bond is 1 and the half-sweep number is 2, it means we are at the end of a sweep. But using checkdone! is much simpler and a totally good way to do it.
commented by (200 points)
Thanks, it is working as intended!

Now I would like to implement something that works like this inside the observer.jl file, so that I don't have to overload the measure! and checkdone! functions every time I want to check the truncation error. Do you think it would be better to change the DMRGObserver struct or to just add this new custom observer to the file?
commented by (51.6k points)
Hi Rafael,
So I hope this isn't frustrating news but, prompted by your question, I finally added the reporting of the max truncation error to our DMRG code today. (It's in a pending pull request that I will merge.)

However, I still hope the code you wrote can be useful to you if you want to customize the output even more. You wouldn't really have to overload the measure! and checkdone! functions every time because you can just put this code into a file (demoobserver.jl, say) and then put include("demoobserver.jl") into your main code. Then the only thing you have to do is just construct and pass your observer to the dmrg function if you want to use it. So it shouldn't be too much harder than if it was built into ITensor.

Of course if you do have a change for the provided observers you'd like to make, we welcome that and would be happy to accept a PR from you, and best to run the change by us first to see if it's along the lines of the designs we want.

Thanks,
Miles
commented by (200 points)
No problem at all, thanks for helping me out and quickly addressing the issue!
commented by (51.6k points)
Great. Looking forward to chatting more in the future -

Miles