# Holomorphic function not being recognized as such by ChainRules.jl

**URL:** <https://discourse.julialang.org/t/holomorphic-function-not-being-recognized-as-such-by-chainrules-jl/95806>\
**Category:** Machine Learning\
**Tags:** chainrules\
**Created:** [March 9, 2023, 3:54pm UTC](https://discourse.julialang.org/t/holomorphic-function-not-being-recognized-as-such-by-chainrules-jl/95806 "2023-03-09T15:54:24Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Hareruya](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hareruya/32/47536_2.png) [@Hareruya](https://discourse.julialang.org/u/Hareruya)\
**Post date:** [March 9, 2023, 3:54pm UTC](https://discourse.julialang.org/t/holomorphic-function-not-being-recognized-as-such-by-chainrules-jl/95806/1 "2023-03-09T15:54:24Z")

</div>

Greetings.

I am currently trying to implement some code using @scalar\_rule for a custom gradient for a very important group of functions in Physics and Engineering, the spherical bessel functions, in this case particularly of order 0. Despite being a Holomorphic, and in fact an Entire function, I usually write this function with an exception:

```julia
j0(x::Number) = iszero(x) ? one(x) : sin(x)/x 

```

This creates problems when trying to use automatic differentiation, as ChainRules.jl and Flux.jl do not function well on that exception point, despite a derivative existing and being continuous everywhere, including the origin. In the past, I have skirted around this issue by adding an eps to the numerator and denominator to avoid making an exception for 0, but I’d like to do this properly. I found what I thought was the solution for my problem in the macro @scalar\_rule. I defined the derivative explicitly as a separate function and created the rule:

```julia
using ChainRules, Flux
import ChainRules: @scalar_rule
j0(x::Number) = iszero(x) ? one(x) : sin(x)/x 
dj0(x::Number) = iszero(x) ? zero(x) : (x*cos(x) - sin(x))/(x^2)
@scalar_rule(j0(x), (dj0(x)))

```

For real inputs, this solved my problem. It performs exactly as I expected it to, evading the conditional clause I put in:

```julia
julia>gradient(j0, 0.0)
(0.0,)
julia>gradient(j0, 1.0)
(-0.30116867893975674,)

```

However, in my research, I often have to calculate this function and its derivative for complex input. In that case, the documentation for @scalar\_rule says that the function is presumed Holomorphic, which `j0` is, meaning I expected the results to hold with no issue. However, any attempt to calculate a derivative at a complex point results in an error:

```julia
julia> gradient(j0, 0.0im)
ERROR: Output is complex, so the gradient is not defined.
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:35
 [2] sensitivity(y::ComplexF64)
   @ Zygote ~/.julia/packages/Zygote/hLzJT/src/compiler/interface.jl:66
 [3] gradient(f::Function, args::ComplexF64)
   @ Zygote ~/.julia/packages/Zygote/hLzJT/src/compiler/interface.jl:97
 [4] top-level scope
   @ REPL[18]:1
 [5] top-level scope
   @ ~/.julia/packages/CUDA/BbliS/src/initialization.jl:52

```

Any idea what exactly my mistake might have been? I have been cracking my head at this for some time.  
For the record, my system is running Arch Linux, and my Julia version is 1.8.5. I also updated all my packages right before running the test above. Any help would be very appreciated.

---

<div class="post-metadata">

**Author:** ![ToucheSir](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/touchesir/32/14411_2.png) [@ToucheSir](https://discourse.julialang.org/u/ToucheSir)\
**Post date:** [March 9, 2023, 4:35pm UTC](https://discourse.julialang.org/t/holomorphic-function-not-being-recognized-as-such-by-chainrules-jl/95806/2 "2023-03-09T16:35:55Z")

</div>

This is not the fault of ChainRules, but of `Zygote.gradient` (Zygote.jl is the actual library doing the work when you call `Flux.gradient`). Because `gradient` isn’t provided a seed, it has to calculate one itself based on the inputs. Zygote seems to be very conservative about what kinds of inputs it can work with here.

Instead of using `gradient`, you can use the lower level `pullback` function and provide your own seed.

```julia
y, back = pullback(j0, 0.0)
back(<seed>)

```

I’m not familiar with taking derivatives of holomorphic functions, but [Complex numbers · ChainRules](https://juliadiff.org/ChainRulesCore.jl/stable/maths/complex.html) may be helpful here.

---

<div class="post-metadata">

**Author:** ![Hareruya](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hareruya/32/47536_2.png) [@Hareruya](https://discourse.julialang.org/u/Hareruya)\
**Post date:** [March 9, 2023, 5:11pm UTC](https://discourse.julialang.org/t/holomorphic-function-not-being-recognized-as-such-by-chainrules-jl/95806/3 "2023-03-09T17:11:56Z")

</div>

This did indeed work and now it shows expected behavior. It is rather inconvenient not being able to use the `gradient` function, but I’ll make do.  
Thank you very much for your help.
