# Tracking entanglement entropy convergence

**URL:** <https://itensor.discourse.group/t/tracking-entanglement-entropy-convergence/837>\
**Category:** ITensor Julia Questions\
**Tags:** julia, dmrg\
**Created:** [May 4, 2023, 5:23am UTC](https://itensor.discourse.group/t/tracking-entanglement-entropy-convergence/837 "2023-05-04T05:23:56Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![eibarragp](https://avatars.discourse-cdn.com/v4/letter/e/b5e925/32.png) [@eibarragp](https://itensor.discourse.group/u/eibarragp)\
**Post date:** [May 4, 2023, 5:23am UTC](https://itensor.discourse.group/t/tracking-entanglement-entropy-convergence/837/1 "2023-05-04T05:23:57Z")

</div>

Hi,

I am new to using ITensor (and Julia) and I noticed that the C++ version was outputting the vN entropy at the center bond as well as the energy, etc… after each sweep. On the other hand, the Julia version does not, and I’d like to do that. I’ve followed the advice I found in the documentation to define the vN entropy (see below)

```auto
using ITensors
function entropy_von_neumann(psi::MPS, b::Int)
    s = siteinds(psi)  
    orthogonalize!(psi, b)
    _,S = svd(psi[b], (linkind(psi, b-1), s[b]))
    SvN = 0.0
    for n in 1:dim(S, 1)
      p = S[n,n]^2
      SvN -= p * log(p)
    end
    return SvN
end

```

This works well after I finish the calculation, but I would like to output this after every sweep. From what I understood an observer is needed for that.

If I understood correctly a new `ITensor.op` operator that calls the `entropy_von_neumann` function needs to be defined and then be called under `DMRGObserver`, followed by calling such observer in the `dmg` arguments with `outputlevel =1`.

Does anyone know how to do this?

```auto
    function op!(Op::ITensor,::OpName"vN_entrop",::SiteType"MySiteType",s::Index)
        Op[s'=>1,s=>3] = entropy_von_neumann(psi,b)
    end
    
    vN_observer = DMRGObserver(["vN_entrop"],sites,energy_tol=1E-7)
    energy, psi = dmrg(H, psi0; nsweeps, maxdim, cutoff, noise, observer=vN_observer,outputlevel=1)

```

But I get the following error:

```auto
Overload of "op" or "op!" functions not found for operator name "vN_entrop" and Index tags: ("Electron,Site,n=9",)

```

And is also not very clear to me what should be the values going here `Op[s'=>1,s=>3]`.

For context, I am trying to solve a small 3x3 OBC plain-vanilla Fermi Hubbard model in the square lattice.

Thanks!

---

<div class="post-metadata">

**Author:** ![miles](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/miles/32/6_2.png) [@miles](https://itensor.discourse.group/u/miles)\
**Post date:** [May 4, 2023, 7:30pm UTC](https://itensor.discourse.group/t/tracking-entanglement-entropy-convergence/837/2 "2023-05-04T19:30:56Z")

</div>

Thanks for the question. It’s great that you already tried a way of doing it, but there’s no need to involve the ITensors.op function. (The ITensors.op family of functions is for defining custom operators, such as S^z or S^+ for a spin degree of freedom, so it’s not the thing to use to measure entanglement of a state.)

Here’s a working solution you can use, where I’ve made a custom observer type and overloaded its `measure!` function to print out the entanglement across the current bond of DMRG:

```julia
mutable struct EntanglementObserver <: AbstractObserver
end

function ITensors.measure!(o::EntanglementObserver; bond, sweep, half_sweep, psi, projected_operator, kwargs...)
  U,S,V = svd(psi[bond], uniqueinds(psi[bond],psi[bond+1]))
  SvN = 0.0
  for n=1:dim(S, 1)
    p = S[n,n]^2
    SvN -= p * log(p)
  end
  println(" Entanglement across bond $bond = $SvN")
end

```

You can pass this observer to a `dmrg` calculation like this:

```auto
observer = EntanglementObserver()
energy, psi = dmrg(H,psi0; nsweeps, maxdim, cutoff, observer, outputlevel=2)

```

Hope that helps – please let me know if you have a follow-up question about using this.

---

<div class="post-metadata">

**Author:** ![miles](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/miles/32/6_2.png) [@miles](https://itensor.discourse.group/u/miles)\
**Post date:** [May 6, 2023, 3:46pm UTC](https://itensor.discourse.group/t/tracking-entanglement-entropy-convergence/837/3 "2023-05-06T15:46:08Z")

</div>

I’ve also now posted this example in the ITensor documentation:  
[https://itensor.github.io/ITensors.jl/dev/examples/DMRG.html#Printing-the-Entanglement-Entropy-at-Each-Step](https://itensor.github.io/ITensors.jl/dev/examples/DMRG.html#Printing-the-Entanglement-Entropy-at-Each-Step)

---

<div class="post-metadata">

**Author:** ![mathew0036](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/mathew0036/32/214_2.png) [@mathew0036](https://itensor.discourse.group/u/mathew0036)\
**Post date:** [May 6, 2023, 7:29pm UTC](https://itensor.discourse.group/t/tracking-entanglement-entropy-convergence/837/4 "2023-05-06T19:29:38Z")

</div>

Thanks for the additional documentation!  
Just a small follow up question on this, is it possible to have more than one kind of observer in the same dmrg calculation? For example, an energy observer as well as one for the entanglement entropy or any other operator averages? I understand how the energy observer can help terminate the dmrg calculation quicker, but if I wanted an additional observer (along with the energy observer) that checked the average of some local operator and then terminates the dmrg if some condition isn’t satisfied, is such a set up possible?

---

<div class="post-metadata">

**Author:** ![eibarragp](https://avatars.discourse-cdn.com/v4/letter/e/b5e925/32.png) [@eibarragp](https://itensor.discourse.group/u/eibarragp)\
**Post date:** [May 8, 2023, 1:49pm UTC](https://itensor.discourse.group/t/tracking-entanglement-entropy-convergence/837/5 "2023-05-08T13:49:57Z")

</div>

Hi Miles,

Thanks for the response. I tried running the example as is now in the documentation and I get the following error:

```auto
Sweep 1, half 1, bond (1,2) energy=-1.9510957542541163
  Truncated using cutoff=1.0E-08 maxdim=10 mindim=1
  Trunc. err=0.00E+00, bond dimension 2
ERROR: UndefKeywordError: keyword argument projected_operator not assigned

```

Do you have any suggestion for this?

Thanks!

---

<div class="post-metadata">

**Author:** ![miles](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/miles/32/6_2.png) [@miles](https://itensor.discourse.group/u/miles)\
**Post date:** [May 8, 2023, 2:16pm UTC](https://itensor.discourse.group/t/tracking-entanglement-entropy-convergence/837/6 "2023-05-08T14:16:34Z")

</div>

For that issue, you can just remove the keyword argument `projected_operator` from your `measure!` function definition. Or you can upgrade ITensors.jl to the latest version (that keyword argument was only added more recently).

---

<div class="post-metadata">

**Author:** ![miles](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/miles/32/6_2.png) [@miles](https://itensor.discourse.group/u/miles)\
**Post date:** [May 8, 2023, 2:30pm UTC](https://itensor.discourse.group/t/tracking-entanglement-entropy-convergence/837/7 "2023-05-08T14:30:03Z")

</div>

It’s a good question about multiple observers. Unfortunately we don’t support that yet. We will support that (actually an even better system) in an upcoming redesign of our DMRG code, but it’s not available yet in the ITensors.jl package.

For now, a good alternative is just to continue to customize your observer. So in the example above, you could make the `measure!` function of the observer do more things, and you can put data fields if needed into the definition of the observer type itself to store information and so on. Also you can define the `checkdone!` method to stop a DMRG calculation early. There are more details and examples on this documentation page:  
[https://itensor.github.io/ITensors.jl/dev/Observer.html](https://itensor.github.io/ITensors.jl/dev/Observer.html)

---

<div class="post-metadata">

**Author:** ![eibarragp](https://avatars.discourse-cdn.com/v4/letter/e/b5e925/32.png) [@eibarragp](https://itensor.discourse.group/u/eibarragp)\
**Post date:** [May 8, 2023, 5:16pm UTC](https://itensor.discourse.group/t/tracking-entanglement-entropy-convergence/837/8 "2023-05-08T17:16:58Z")

</div>

Thanks Miles! 🙂

Cheers,  
Eduardo

---

<div class="post-metadata">

**Author:** ![ryanlevy](https://yyz2.discourse-cdn.com/free1/user_avatar/itensor.discourse.group/ryanlevy/32/150_2.png) [@ryanlevy](https://itensor.discourse.group/u/ryanlevy)\
**Post date:** [May 9, 2023, 2:06pm UTC](https://itensor.discourse.group/t/tracking-entanglement-entropy-convergence/837/9 "2023-05-09T14:06:42Z")

</div>

Hi Miles,  
I’m not sure this code works for both sweeps. For `half_sweep==1` this produces 0 each time (because the orthogonality center is in `bond+1` already) and for `half_sweep==2` you get a reasonable number

I suggest the following change (if I understand the bond correctly)

```julia
center,second = (half_sweep == 1) ? (bond+1,bond) : (bond,bond+1) 
U,S,V = svd(psi[center], uniqueinds(psi[center],psi[second]))
 

```
