# Automatic differentiation with density matrix in yao

**URL:** <https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467>\
**Category:** Quantum\
**Tags:** question, differentiation, yao\
**Created:** [June 11, 2024, 9:57am UTC](https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467 "2024-06-11T09:57:31Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![stone44](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stone44/32/208488_2.png) [@stone44](https://discourse.julialang.org/u/stone44)\
**Post date:** [June 11, 2024, 9:57am UTC](https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467/1 "2024-06-11T09:57:31Z")

</div>

Hey there,  
i am currently implementing a quantum variational algorithm, where my goal is to minimize a cost function, where i use a gradient based optimzer. Since i have no analytically closed form of my gradient, i am currently stuck.

I know one can use automatic differentiation when one has a pure state by  
simply using the function expect’( op::AbstractBlock, reg).

Now my question: Is there a similar function for mixed states, where i have a density matrix, so i could simply use expect’(op::AbstractBlock, density\_matrix)?

If that’s not the case: Do you have any idea how i could get the gradient of an expectation value in a simple fashion when my system is described by a density matrix in yao?

My expectation value of an Operator O is Tr[U+ O U rho] where the + stands for the hermitian conjugate and rho is the density matrix. The unitary time evolution operator U depends on a set of variational parameters. The gradient is calculated in respect to those parameters.

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [June 11, 2024, 10:41am UTC](https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467/2 "2024-06-11T10:41:26Z")

</div>

I think that’s a question for the developers of Yao.jl, ping @Roger-luo and @1115

---

<div class="post-metadata">

**Author:** ![stone44](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stone44/32/208488_2.png) [@stone44](https://discourse.julialang.org/u/stone44)\
**Post date:** [June 13, 2024, 1:10pm UTC](https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467/3 "2024-06-13T13:10:02Z")

</div>

Thanks a lot for your reply, I’m not entirely sure, what you mean by pinging them.

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [June 13, 2024, 1:46pm UTC](https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467/4 "2024-06-13T13:46:15Z")

</div>

I just did by tagging them on this post 😉 if they don’t answer here, perhaps opening a GitHub issue would be more efficient

---

<div class="post-metadata">

**Author:** ![stone44](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stone44/32/208488_2.png) [@stone44](https://discourse.julialang.org/u/stone44)\
**Post date:** [June 13, 2024, 1:48pm UTC](https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467/5 "2024-06-13T13:48:55Z")

</div>

Oh 😂 😅, appreciate your help!

---

<div class="post-metadata">

**Author:** ![1115](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/1115/32/4465_2.png) [@1115](https://discourse.julialang.org/u/1115)\
**Post date:** [June 13, 2024, 2:28pm UTC](https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467/6 "2024-06-13T14:28:52Z")

</div>

I think this feature is not available yet in Yao. Yao has a naive AD engine that only supports differentiating reversible gates, however density matrices simulation is usually not reversible and requires checkpointing.

Currently, I am focusing more on simulating quantum circuits by contracting tensor networks. The contraction is backended by `OMEinsum`, which has good support to automatic differentiation.

I am happy to help convert your simulation to tensor networks for better automatic differentiation if you could provide a minimum working example.

Reference:

> **[Tensor network backend · Documentation | Yao](https://docs.yaoquantum.org/dev/man/yao2einsum.html)**
>
> Documentation for Documentation | Yao.

---

<div class="post-metadata">

**Author:** ![stone44](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stone44/32/208488_2.png) [@stone44](https://discourse.julialang.org/u/stone44)\
**Post date:** [June 18, 2024, 12:48pm UTC](https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467/7 "2024-06-18T12:48:53Z")

</div>

Thanks a lot for your answer and the offer. I really appreciate it. I will need to talk to my supervisor if that’s what we want.

One further question regarding automatic differentation, this time with a pure state.  
Again there i am trying to get the gradient of my loss function in respect to my parameters.

Here a minimal working example:

```julia
using Yao 

N = 2 #number of qubits
T = 0.1 #time step
Ψ = ArrayReg(complex([1.,0.,0.,0.])) #initial state 

hamiltonian(x1,x2,x3) = x1*put(N, 1=>Z)*put(N, 2=>Z) + x2*put(N, 1=>X) + x3*put(N, 2=>X)

observable = put(N, 1=>Z)*put(N, 2=>Z)

C = expect(observable, Ψ => time_evolve(hamiltonian(1.,2.,3.), T)) #cost function 

```

So what i want here is the gradient ∇ = (dC/dx1 , dC/dx2, dC/dx3)

Im trying to get it by simply using

```julia
_ , ∇ = expect'(observable, Ψ => time_evolve(hamiltonian(1.,2.,3.), T))

```

but there is only one value saved in ∇. I assume its the derivative in respect to time.  
How to i obtain the gradient of the loss function in respect to these parameters?

---

<div class="post-metadata">

**Author:** ![1115](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/1115/32/4465_2.png) [@1115](https://discourse.julialang.org/u/1115)\
**Post date:** [June 19, 2024, 2:04am UTC](https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467/8 "2024-06-19T02:04:42Z")

</div>

Again, the AD over Hamiltonian parameters is not supported yet in Yao yet. Differentiating Hamiltonian parameters is tricky, which you could find some useful information in the note by @stevengj :  
[https://www.semanticscholar.org/paper/Notes-on-Adjoint-Methods-for-18.335-Johnson/75c033c779d9b357af2dab11f438fcc7b689e310](https://www.semanticscholar.org/paper/Notes-on-Adjoint-Methods-for-18.335-Johnson/75c033c779d9b357af2dab11f438fcc7b689e310)

In your tasks, if errors are acceptable, a straight-forward approach is to trotterize the Hamiltonian and differentiate over the parameters with the built-in AD engine.

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [June 19, 2024, 12:28pm UTC](https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467/9 "2024-06-19T12:28:41Z")

</div>

I can’t speak to Yao specifically, but fundamentally, there’s nothing different about open quantum systems vs. closed quantum systems. In closed quantum systems, you have `|Ψ̇⟩ = H |Ψ⟩`, in open quantum systems you have `ρ̇ = L ρ`. In both cases, Ψ/ρ are just vectors (vectorized density matrices: just write the columns of the density matrix underneath each other), and H/L are operators (super-operators, but again: if you’ve vectorized ρ, L is just a matrix). The only difference is that H has real eigenvalues (Hermitian) and L does not (or, only if there is no dissipation). Small detail: most textbooks put an extra imaginary-i in the Liouville equation, but I find it much more useful to have the exact same form of the Schrödinger and Liouville equation. I would point you to the [docstring of `liouvillian` in QuantumControl.lj](https://juliaquantumcontrol.github.io/QuantumControl.jl/stable/api/quantum_propagators/#QuantumPropagators.Generators.liouvillian).

As for how to convert the standard Lindblad equation into the matrix L, see [Appendix B.2 in arXiv 1312.0111v2](https://arxiv.org/abs/1312.0111v2).

So if you have an analytic way to calculate the gradient for the closed case, you should also be able to calculate the gradient for the open case as well. Beyond that, I would also argue that auto-differentiating through a Hamiltonian/Liouvillian, respectively through a time propagation/circuit evaluation is a bad idea. I’ve proposed using [“semi-automatic differentiation”](https://quantum-journal.org/papers/q-2022-12-07-871/) which effectively avoids all of the AD overhead (assuming you can differentiate analytically the “standard” overlap functionals). I’ve implemented in this concept for pulse-level control. Yao operates on the higher circuit level, of course. I think the same idea applies in this context; but nobody has implemented semi-AD in Yao, I would assume. Still, you might find the paper instructive and be able to code something up yourself relatively easily.

---

<div class="post-metadata">

**Author:** ![stone44](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stone44/32/208488_2.png) [@stone44](https://discourse.julialang.org/u/stone44)\
**Post date:** [June 21, 2024, 12:21pm UTC](https://discourse.julialang.org/t/automatic-differentiation-with-density-matrix-in-yao/115467/10 "2024-06-21T12:21:47Z")

</div>

Great, thanks for the hint. Trotterization and then using the AD-engine works fine. Since my gates share parameters, i needed to sum up the output of expect’.  
Thanks for your help, appreciate your work a lot!
