We had a big thread about this a while ago: Taking Complex Autodiff Seriously in ChainRules
The TL:DR is that holomorphic functions are not the only functions which exist and are widely used, they’re actually a very very small subset of the functions that exist and are used. It would be a really bad idea if AD packages automatically assumed that functions are holomorphic. Derivatives of complex functions are still perfectly well defined even if the function is not holomorphic.
The approach that won out was just computing pullback
s correctly, so that users could either construct the full jacobian from the pullback, or a wirtinger derivative ( that is, \partial \over \partial z) if they prefer. (explanation of the math here: Taking Complex Autodiff Seriously in ChainRules - #52 by Mason)
If you do indeed want to just deal with \partial \over \partial z alone, you can do that like so:
using Zygote
function ∂z(f, z)
_, back = Zygote.pullback(f, z)
du, dv = back(1)[1], back(im)[1]
(du' + im*dv')/2
end
julia> ∂z(f, 2+2im)
0.12000000000000002 + 0.16000000000000003im
Zygote.jl has docs on this here: Complex Differentiation · Zygote
And ChainRules.jl has docs on it here: Complex numbers · ChainRules