Complex-valued functions with real arguments - ForwardDiff, JuliaDiff

When executing the following code to apply ForwardDiff to a complex-valued function with real argument:

using ForwardDiff
f2(t::Real) = real( (cos(t) + 1im*sin(t))^(1/2) )
t = pi/2
ForwardDiff.derivative(f2,t)

I get the following error:

ERROR: StackOverflowError:
Stacktrace:
 [1] Type at ./complex.jl:12 [inlined] (repeats 2 times)
 [2] float at ./complex.jl:1002 [inlined]
 [3] 
_cpow(::Complex{ForwardDiff.Dual{ForwardDiff.Tag{typeof(f2),Float64},Float64,1}}, ::ForwardDiff.Dual{ForwardDiff.Tag{typeof(f2),Float64},Float64,1}) at ./complex.jl:770 (repeats 80000 times)

I wonder what the constraints are when using ForwardDiff to this type of functions.
All help is appreciated.

ForwardDiff needs a lot more than just opening up type signatures to work with complex numbers, so I wouldn’t expect this to just work any time soon. You can split to real and imaginary parts and diff that. We are making essentially a ForwardDiff 2.0 (with Jarrett’s blessing :slight_smile: ) to address this, along with the lack of multivariate rules (use BLAS!) and post-hoc rule definition (via ChainRules).

5 Likes

Can you please link the repository? Or is it just a new, breaking release of ForwardDiff?

1 Like

It’s a new repo. I hope we can open it up by next week with some preliminary results. It’s quite cool: it’s struct of arrays and matrix backed with Cassette generating the connection to ChainRules.jl

2 Likes

Also, you will be able to do this type of automatic differentiation with Grassmann.jl after I finish implementing the Leibniz.jl package for working with the symmetric differentials. Complex number algebra is simply a subalgera of the geometric algebra in Grassmann and by extending it with the symmetric Leibniz algebra the automatic differentiation is automatically built-in, as described in my paper.

julia> using Grassmann, basis"2"
(⟨++⟩, v, v₁, v₂, v₁₂)

julia> f2(t) = real(sqrt(cos(t)+vectorspace(t)(I)*sin(t)))
f2 (generic function with 1 method)

julia> f2((pi/2)v)
0.7070714177261098v⃖

All of the methods needed for your AD example are already implemented in Grassmann variables so now I only need to finish implementing the extended support for the Leibniz indices and then you will be able to also tack on the derivatives also to get the forward mode AD.

julia> @basis tangent(ℝ^2)
(⟨++₁⟩, v, v₁, v₂, ∂₁, v₁₂, ∂₁v₁, ∂₁v₂, ∂₁v₁₂)

You will be able to work with it using this extended tangent basis… which is still a work in progress. In the near future I will resume work on this aspect when I get around to it.

4 Likes