# Incorrect Hessian when using `exp` function with complex input

Incorrect Hessian by `exp` function · Issue #677 · JuliaDiff/ForwardDiff.jl (github.com)
I was trying to calculate the Hessian of a simple function such as

``````using ForwardDiff
function busPQ(Ybus, Vθ)
n = length(Vθ)
V=Vθ[1:Int(n/2)]
θ=Vθ[Int(n/2)+1:n]
Vbus=V.*exp.(im .*θ)
# Vbus=V.*(cos.(θ)+im .*sin.(θ))
# print(Vbus-Vbus)
I = Ybus.*Vbus
return vcat(reim(Vbus.*conj(I))...)
end

Ybus=[1 - 3im]
Vm=[1]
Va=[0]
Vθ = vcat(Vm,Va)
function Hessian(f, x)
n = length(x)
out = ForwardDiff.jacobian(x -> ForwardDiff.jacobian(f, x), x)
return reshape(out, n, n, n)
end
H(y) = Hessian(x-> busPQ(Ybus, x), y)
``````

At point `[1,0]`, the above codes produce the wrong Hessian. However, if I set very small perturbation to `Vθ`, then the results are correct.

``````julia> H([1,0])
2×2×2 Array{Float64, 3}:
[:, :, 1] =
2.0  0.0
6.0  0.0

[:, :, 2] =
0.0  2.0
0.0  6.0

julia> H([1,1e-10])
2×2×2 Array{Float64, 3}:
[:, :, 1] =
2.0  0.0
6.0  0.0

[:, :, 2] =
0.0  0.0
0.0  0.0

julia> H([1,-1e-10])
2×2×2 Array{Float64, 3}:
[:, :, 1] =
2.0  0.0
6.0  0.0

[:, :, 2] =
0.0  0.0
0.0  0.0

``````

It is found to be more robust to use `cos.(θ)+im .*sin.(θ)`, which functioned correctly at point `[1,0]`, instead of `exp.(im .*θ)`.
I think the problem has something in common with #653.

The difference between `cos.(θ)+im .*sin.(θ)` and `exp.(im .*θ)` is printed as follows

``````Complex{ForwardDiff.Dual{ForwardDiff.Tag{var"#21#22", ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20"{var"#21#22"}, Int64}, Int64, 2}}, ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20"{var"#21#22"}, Int64}, Float64, 2}, 2}}[Dual{ForwardDiff.Tag{var"#21#22", ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20"{var"#21#22"}, Int64}, Int64, 2}}}(Dual{ForwardDiff.Tag{var"#19#20"{var"#21#22"}, Int64}}(0.0,0.0,0.0),Dual{ForwardDiff.Tag{var"#19#20"{var"#21#22"}, Int64}}(0.0,0.0,0.0),Dual{ForwardDiff.Tag{var"#19#20"{var"#21#22"}, Int64}}(0.0,0.0,1.0)) + Dual{ForwardDiff.Tag{var"#21#22", ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20"{var"#21#22"}, Int64}, Int64, 2}}}(Dual{ForwardDiff.Tag{var"#19#20"{var"#21#22"}, Int64}}(0.0,0.0,0.0),Dual{ForwardDiff.Tag{var"#19#20"{var"#21#22"}, Int64}}(0.0,0.0,0.0),Dual{ForwardDiff.Tag{var"#19#20"{var"#21#22"}, Int64}}(0.0,0.0,0.0))*im]2×2×2 Array{Float64, 3}:
``````

It is clear that the above Dual is not all zero.

The dependencies are `ForwardDiff v0.10.36` and `Julia V1.9.3`.

Xref issue 677, this appears to be solved on the unreleased v0.11.

1 Like