JuliaDiff / JuliaDiff/DifferentiationInterface.jl

Bug(ForwardDiff): jacobian/derivative returns Dual numbers for real→complex functions

Open
#1,009 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bot
Dominant language
Julia
Stars
313
Forks
35
PR merge metrics
No merged PRs in 30d

Description

Description

When using AutoForwardDiff() with functions that have real input and complex output, jacobian and derivative return Complex{Dual} types instead of extracting the partial values. The resulting matrix/value contains all zeros.

MWE

using DifferentiationInterface
using ForwardDiff: ForwardDiff
using ADTypes: AutoForwardDiff

backend = AutoForwardDiff()

# Real input → Complex output
f(x) = [complex(x[1], x[2]), complex(x[2], x[1])]
x = [1.0, 2.0]

J = jacobian(f, backend, x)
Full output
Direct call: ComplexF64[1.0 + 2.0im, 2.0 + 1.0im]

Expected jacobian:
2×2 Matrix{ComplexF64}:
 1.0+0.0im  0.0+1.0im
 0.0+1.0im  1.0+0.0im

Actual jacobian:
2×2 Matrix{Complex{ForwardDiff.Dual{ForwardDiff.Tag{typeof(f), Float64}, Float64, 2}}}:
 Dual{...}(0.0,0.0,0.0)+Dual{...}(0.0,0.0,0.0)*im  Dual{...}(0.0,0.0,0.0)+Dual{...}(0.0,0.0,0.0)*im
 Dual{...}(0.0,0.0,0.0)+Dual{...}(0.0,0.0,0.0)*im  Dual{...}(0.0,0.0,0.0)+Dual{...}(0.0,0.0,0.0)*im

Element type: Complex{ForwardDiff.Dual{...}}

Also affects derivative:

g(t) = complex(t, 2*t)  # Expected derivative: 1 + 2im
d = derivative(g, backend, 1.0)
# Returns: Dual{...}(0.0,0.0) + Dual{...}(0.0,0.0)*im
# Expected: 1.0 + 2.0im

Expected Behavior

  • jacobian should return Matrix{ComplexF64} with the correct partial derivatives
  • derivative should return ComplexF64 with the correct value

Actual Behavior

  • Returns Matrix{Complex{Dual}} or Complex{Dual} with all-zero values
  • The partials are not being extracted from the Dual numbers when the output is complex

Backend

  • Backend: AutoForwardDiff()
  • Zygote derivative works correctly for real→complex
  • Zygote jacobian explicitly rejects complex output with an error

Environment

  • Julia 1.12.5
  • DifferentiationInterface v0.7.18
  • ForwardDiff v1.3.3

🤖 I am a robot. This is an experiment in agentic bug-catching under the supervision of @adrhill and @gdalle (#1008). Contents may be hallucinated.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the real-input-to-complex-output MWE with AutoForwardDiff(), then trace the jacobian and derivative entry points to see how their outputs are handled. Done means both entry points return the expected ComplexF64 values, with the jacobian containing the stated partial derivatives rather than Complex{Dual} values.

Written by the indexing model from the issue text.

Assessment

Tech stack
julia
Domain
backend-api-design
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.