@@ -195,6 +195,38 @@ macro define_ternary_dual_op(f, xyz_body, xy_body, xz_body, yz_body, x_body, y_b
195195 return esc (defs)
196196end
197197
198+ # Support complex-valued functions such as `hankelh1`
199+ function dual_definition_retval (:: Val{T} , val:: Real , deriv:: Real , partial:: Partials ) where {T}
200+ return Dual {T} (val, deriv * partial)
201+ end
202+ function dual_definition_retval (:: Val{T} , val:: Real , deriv1:: Real , partial1:: Partials , deriv2:: Real , partial2:: Partials ) where {T}
203+ return Dual {T} (val, _mul_partials (partial1, partial2, deriv1, deriv2))
204+ end
205+ function dual_definition_retval (:: Val{T} , val:: Complex , deriv:: Union{Real,Complex} , partial:: Partials ) where {T}
206+ reval, imval = reim (val)
207+ if deriv isa Real
208+ p = deriv * partial
209+ return Complex (Dual {T} (reval, p), Dual {T} (imval, zero (p)))
210+ else
211+ rederiv, imderiv = reim (deriv)
212+ return Complex (Dual {T} (reval, rederiv * partial), Dual {T} (imval, imderiv * partial))
213+ end
214+ end
215+ function dual_definition_retval (:: Val{T} , val:: Complex , deriv1:: Union{Real,Complex} , partial1:: Partials , deriv2:: Union{Real,Complex} , partial2:: Partials ) where {T}
216+ reval, imval = reim (val)
217+ if deriv1 isa Real && deriv2 isa Real
218+ p = _mul_partials (partial1, partial2, deriv1, deriv2)
219+ return Complex (Dual {T} (reval, p), Dual {T} (imval, zero (p)))
220+ else
221+ rederiv1, imderiv1 = reim (deriv1)
222+ rederiv2, imderiv2 = reim (deriv2)
223+ return Complex (
224+ Dual {T} (reval, _mul_partials (partial1, partial2, rederiv1, rederiv2)),
225+ Dual {T} (imval, _mul_partials (partial1, partial2, imderiv1, imderiv2)),
226+ )
227+ end
228+ end
229+
198230function unary_dual_definition (M, f)
199231 FD = ForwardDiff
200232 Mf = M == :Base ? f : :($ M.$ f)
@@ -206,7 +238,7 @@ function unary_dual_definition(M, f)
206238 @inline function $M. $f (d:: $FD.Dual{T} ) where T
207239 x = $ FD. value (d)
208240 $ work
209- return $ FD. Dual {T} (val, deriv * $ FD. partials (d))
241+ return $ FD. dual_definition_retval ( Val {T} (), val, deriv, $ FD. partials (d))
210242 end
211243 end
212244end
@@ -236,17 +268,17 @@ function binary_dual_definition(M, f)
236268 begin
237269 vx, vy = $ FD. value (x), $ FD. value (y)
238270 $ xy_work
239- return $ FD. Dual {Txy} (val, $ FD. _mul_partials ( $ FD . partials (x), $ FD. partials (y), dvx, dvy ))
271+ return $ FD. dual_definition_retval ( Val {Txy} (), val, dvx, $ FD. partials (x), dvy, $ FD. partials (y))
240272 end ,
241273 begin
242274 vx = $ FD. value (x)
243275 $ x_work
244- return $ FD. Dual {Tx} (val, dvx * $ FD. partials (x))
276+ return $ FD. dual_definition_retval ( Val {Tx} (), val, dvx, $ FD. partials (x))
245277 end ,
246278 begin
247279 vy = $ FD. value (y)
248280 $ y_work
249- return $ FD. Dual {Ty} (val, dvy * $ FD. partials (y))
281+ return $ FD. dual_definition_retval ( Val {Ty} (), val, dvy, $ FD. partials (y))
250282 end
251283 )
252284 end
0 commit comments