# Taking Complex Autodiff Seriously in ChainRules

**URL:** <https://discourse.julialang.org/t/taking-complex-autodiff-seriously-in-chainrules/39317>\
**Category:** Specific Domains\
**Tags:** numerics, chainrulescore, complex-numbers\
**Created:** [May 12, 2020, 1:52am UTC](https://discourse.julialang.org/t/taking-complex-autodiff-seriously-in-chainrules/39317 "2020-05-12T01:52:35Z")\
**Posts on this page:** 1\
**Showing post:** 49

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 20, 2020, 6:32pm UTC](https://discourse.julialang.org/t/taking-complex-autodiff-seriously-in-chainrules/39317/49 "2020-05-20T18:32:09Z")

</div>

After some reflection, I think the current Zygote behaviour is the right way to go. It supports pretending everything is holomorphic, but also defines the rules correctly such that you can get out the full Jacobian if you want / need. Following @sethaxen’s link to the Zygote docs, we see that the way it works is that if you do

```julia
using Zygote
y, back = Zygote.pullback(abs2, 1.0 + im)

julia> back(1), back(im)
((2.0 + 2.0im,), (0.0 + 0.0im,))

```

this is the full Jacobian. `back(1)` is asking for `(J*[1, 0])'` and `back(im)` is asking for `(J*[0, 1])'`, and we can then form the Wirtinger derivatives via

```julia
du, dv = back(1)[1], back(im)[1]
(du' + im*dv')/2, (du + im*dv)/2

```

To my surprise, this actually works on @oxinabox’s [Chainrules branch of Zygote](https://github.com/oxinabox/Zygote.jl/tree/ox/chainrules_step1b), even though ChainRules specifically defines

```julia
@scalar_rule abs2(x) 2x

```

Is there something I’m misunderstanding here or is Zygote somehow skipping that chain-rule on this branch?

---

_[View the full topic](https://discourse.julialang.org/t/taking-complex-autodiff-seriously-in-chainrules/39317)._
