From 8067e78ce029c3e391e2eeb8fee697610c0857a5 Mon Sep 17 00:00:00 2001 From: Jimmy Envall Date: Fri, 5 Jan 2024 17:01:39 +0100 Subject: [PATCH 01/10] Define ForwardDiff.Dual - Num methods --- Project.toml | 1 + ext/SymbolicsForwardDiffExt.jl | 271 ++++++++++++++++++++++++++ test/forwarddiff_symbolic_dual_ops.jl | 98 ++++++++++ 3 files changed, 370 insertions(+) create mode 100644 ext/SymbolicsForwardDiffExt.jl create mode 100644 test/forwarddiff_symbolic_dual_ops.jl diff --git a/Project.toml b/Project.toml index 881541e4d..6764a580c 100644 --- a/Project.toml +++ b/Project.toml @@ -46,6 +46,7 @@ SymPy = "24249f21-da20-56a4-8eb1-6a02cf4ae2e6" [extensions] SymbolicsGroebnerExt = "Groebner" SymbolicsPreallocationToolsExt = ["ForwardDiff", "PreallocationTools"] +SymbolicsForwardDiffExt = "ForwardDiff" SymbolicsSymPyExt = "SymPy" [compat] diff --git a/ext/SymbolicsForwardDiffExt.jl b/ext/SymbolicsForwardDiffExt.jl new file mode 100644 index 000000000..06130c21f --- /dev/null +++ b/ext/SymbolicsForwardDiffExt.jl @@ -0,0 +1,271 @@ +module SymbolicsForwardDiffExt + +using ForwardDiff +using ForwardDiff.NaNMath +using ForwardDiff.DiffRules +using ForwardDiff: value, Dual, partials +using Symbolics + +const AMBIGUOUS_TYPES = (Num,) + +#################################### +# N-ary Operation Definition Tools # +#################################### + +macro define_binary_dual_op(f, xy_body, x_body, y_body, Ts) + FD = ForwardDiff + defs = quote end + for R in Ts + expr = quote + @inline $(f)(x::$FD.Dual{Tx}, y::$R) where {Tx} = $x_body + @inline $(f)(x::$R, y::$FD.Dual{Ty}) where {Ty} = $y_body + end + append!(defs.args, expr.args) + end + return esc(defs) +end + +macro define_ternary_dual_op(f, xyz_body, xy_body, xz_body, yz_body, x_body, y_body, z_body, Ts) + FD = ForwardDiff + defs = quote end + for R in Ts + expr = quote + @inline $(f)(x::$FD.Dual{Txy}, y::$FD.Dual{Txy}, z::$R) where {Txy} = $xy_body + @inline $(f)(x::$FD.Dual{Tx}, y::$FD.Dual{Ty}, z::$R) where {Tx, Ty} = Ty ≺ Tx ? $x_body : $y_body + @inline $(f)(x::$FD.Dual{Txz}, y::$R, z::$FD.Dual{Txz}) where {Txz} = $xz_body + @inline $(f)(x::$FD.Dual{Tx}, y::$R, z::$FD.Dual{Tz}) where {Tx,Tz} = Tz ≺ Tx ? $x_body : $z_body + @inline $(f)(x::$R, y::$FD.Dual{Tyz}, z::$FD.Dual{Tyz}) where {Tyz} = $yz_body + @inline $(f)(x::$R, y::$FD.Dual{Ty}, z::$FD.Dual{Tz}) where {Ty,Tz} = Tz ≺ Ty ? $y_body : $z_body + end + append!(defs.args, expr.args) + for Q in Ts + Q === R && continue + expr = quote + @inline $(f)(x::$FD.Dual{Tx}, y::$R, z::$Q) where {Tx} = $x_body + @inline $(f)(x::$R, y::$FD.Dual{Ty}, z::$Q) where {Ty} = $y_body + @inline $(f)(x::$R, y::$Q, z::$FD.Dual{Tz}) where {Tz} = $z_body + end + append!(defs.args, expr.args) + end + expr = quote + @inline $(f)(x::$FD.Dual{Tx}, y::$R, z::$R) where {Tx} = $x_body + @inline $(f)(x::$R, y::$FD.Dual{Ty}, z::$R) where {Ty} = $y_body + @inline $(f)(x::$R, y::$R, z::$FD.Dual{Tz}) where {Tz} = $z_body + end + append!(defs.args, expr.args) + end + return esc(defs) +end + +function binary_dual_definition(M, f, Ts) + FD = ForwardDiff + dvx, dvy = DiffRules.diffrule(M, f, :vx, :vy) + Mf = M == :Base ? f : :($M.$f) + xy_work = FD.qualified_cse!(quote + val = $Mf(vx, vy) + dvx = $dvx + dvy = $dvy + end) + dvx, _ = DiffRules.diffrule(M, f, :vx, :y) + x_work = FD.qualified_cse!(quote + val = $Mf(vx, y) + dvx = $dvx + end) + _, dvy = DiffRules.diffrule(M, f, :x, :vy) + y_work = FD.qualified_cse!(quote + val = $Mf(x, vy) + dvy = $dvy + end) + expr = quote + @define_binary_dual_op( + $M.$f, + begin + vx, vy = $FD.value(x), $FD.value(y) + $xy_work + return $FD.dual_definition_retval(Val{Txy}(), val, dvx, $FD.partials(x), dvy, $FD.partials(y)) + end, + begin + vx = $FD.value(x) + $x_work + return $FD.dual_definition_retval(Val{Tx}(), val, dvx, $FD.partials(x)) + end, + begin + vy = $FD.value(y) + $y_work + return $FD.dual_definition_retval(Val{Ty}(), val, dvy, $FD.partials(y)) + end, + $Ts + ) + end + return expr +end + +################################### +# General Mathematical Operations # +################################### + +for (M, f, arity) in DiffRules.diffrules(filter_modules = nothing) + if (M, f) in ((:Base, :^), (:NaNMath, :pow), (:Base, :/), (:Base, :+), (:Base, :-), (:Base, :sin), (:Base, :cos)) + continue # Skip methods which we define elsewhere. + elseif !(isdefined(@__MODULE__, M) && isdefined(getfield(@__MODULE__, M), f)) + continue # Skip rules for methods not defined in the current scope + end + if arity == 1 + # no-op + elseif arity == 2 + eval(binary_dual_definition(M, f, AMBIGUOUS_TYPES)) + else + # error("ForwardDiff currently only knows how to autogenerate Dual definitions for unary and binary functions.") + # However, the presence of N-ary rules need not cause any problems here, they can simply be ignored. + end +end + +################# +# Special Cases # +################# + +# +/- # +#-----# + +@eval begin + @define_binary_dual_op( + Base.:+, + begin + vx, vy = value(x), value(y) + Dual{Txy}(vx + vy, partials(x) + partials(y)) + end, + Dual{Tx}(value(x) + y, partials(x)), + Dual{Ty}(x + value(y), partials(y)), + $AMBIGUOUS_TYPES + ) +end + +@eval begin + @define_binary_dual_op( + Base.:-, + begin + vx, vy = value(x), value(y) + Dual{Txy}(vx - vy, partials(x) - partials(y)) + end, + Dual{Tx}(value(x) - y, partials(x)), + Dual{Ty}(x - value(y), -partials(y)), + $AMBIGUOUS_TYPES + ) +end + +# / # +#---# + +# We can't use the normal diffrule autogeneration for this because (x/y) === (x * (1/y)) +# doesn't generally hold true for floating point; see issue #264 +@eval begin + @define_binary_dual_op( + Base.:/, + begin + vx, vy = value(x), value(y) + Dual{Txy}(vx / vy, _div_partials(partials(x), partials(y), vx, vy)) + end, + Dual{Tx}(value(x) / y, partials(x) / y), + begin + v = value(y) + divv = x / v + Dual{Ty}(divv, -(divv / v) * partials(y)) + end, + $AMBIGUOUS_TYPES + ) +end + +# exponentiation # +#----------------# + +for f in (:(Base.:^), :(NaNMath.pow)) + @eval begin + @define_binary_dual_op( + $f, + begin + vx, vy = value(x), value(y) + expv = ($f)(vx, vy) + powval = vy * ($f)(vx, vy - 1) + if isconstant(y) + logval = one(expv) + elseif iszero(vx) && vy > 0 + logval = zero(vx) + else + logval = expv * log(vx) + end + new_partials = _mul_partials(partials(x), partials(y), powval, logval) + return Dual{Txy}(expv, new_partials) + end, + begin + v = value(x) + expv = ($f)(v, y) + if y == zero(y) || iszero(partials(x)) + new_partials = zero(partials(x)) + else + new_partials = partials(x) * y * ($f)(v, y - 1) + end + return Dual{Tx}(expv, new_partials) + end, + begin + v = value(y) + expv = ($f)(x, v) + deriv = (iszero(x) && v > 0) ? zero(expv) : expv*log(x) + return Dual{Ty}(expv, deriv * partials(y)) + end, + $AMBIGUOUS_TYPES + ) + end +end + +# hypot # +#-------# + +@eval begin + @define_ternary_dual_op( + Base.hypot, + calc_hypot(x, y, z, Txyz), + calc_hypot(x, y, z, Txy), + calc_hypot(x, y, z, Txz), + calc_hypot(x, y, z, Tyz), + calc_hypot(x, y, z, Tx), + calc_hypot(x, y, z, Ty), + calc_hypot(x, y, z, Tz), + $AMBIGUOUS_TYPES + ) +end + +# fma # +#-----# + +@eval begin + @define_ternary_dual_op( + Base.fma, + calc_fma_xyz(x, y, z), # xyz_body + calc_fma_xy(x, y, z), # xy_body + calc_fma_xz(x, y, z), # xz_body + Base.fma(y, x, z), # yz_body + Dual{Tx}(fma(value(x), y, z), partials(x) * y), # x_body + Base.fma(y, x, z), # y_body + Dual{Tz}(fma(x, y, value(z)), partials(z)), # z_body + $AMBIGUOUS_TYPES + ) +end + +# muladd # +#--------# + +@eval begin + @define_ternary_dual_op( + Base.muladd, + calc_muladd_xyz(x, y, z), # xyz_body + calc_muladd_xy(x, y, z), # xy_body + calc_muladd_xz(x, y, z), # xz_body + Base.muladd(y, x, z), # yz_body + Dual{Tx}(muladd(value(x), y, z), partials(x) * y), # x_body + Base.muladd(y, x, z), # y_body + Dual{Tz}(muladd(x, y, value(z)), partials(z)), # z_body + $AMBIGUOUS_TYPES + ) +end + +end diff --git a/test/forwarddiff_symbolic_dual_ops.jl b/test/forwarddiff_symbolic_dual_ops.jl new file mode 100644 index 000000000..4bb9af9f3 --- /dev/null +++ b/test/forwarddiff_symbolic_dual_ops.jl @@ -0,0 +1,98 @@ +using ForwardDiff +using Symbolics +using Symbolics.SymbolicUtils +using Symbolics.SymbolicUtils.SpecialFunctions +using Symbolics.NaNMath +using Test + +SF = SymbolicUtils.SpecialFunctions + +@variables x + +for f ∈ SymbolicUtils.basic_monadic + fun = eval(:(ξ ->($f)(ξ))) + + fd = ForwardDiff.derivative(fun, x) + sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives + + @test isequal(fd, sym) +end + +for f ∈ SymbolicUtils.monadic + # The polygamma and trigamma functions seem to be missing rules in ForwardDiff. + # The abs rule uses conditionals and cannot be used with Symbolics.Num. + # acsc, asech, NanMath.log2 and NaNMath.log10 are tested separately + if f ∈ (abs, SF.polygamma, SF.trigamma, acsc, asech, NaNMath.log2, NaNMath.log10) + continue + end + + fun = eval(:(ξ ->($f)(ξ))) + + fd = ForwardDiff.derivative(fun, x) + sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives + + @test isequal(fd, sym) +end + +for f ∈ (acsc, asech, NaNMath.log2, NaNMath.log10) + fun = eval(:(ξ ->($f)(ξ))) + + fd = ForwardDiff.derivative(fun, 1.0) + sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives + + @test isequal(fd, substitute(sym, Dict(x => 1.0))) +end + +for f ∈ SymbolicUtils.basic_diadic + if f ∈ (//,) + continue + end + + fun = eval(:(ξ ->($f)(ξ, 2.0))) + + fd = ForwardDiff.derivative(fun, x) + sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives + + @test isequal(fd, sym) +end + +for f ∈ SymbolicUtils.diadic + if f ∈ (max, min, NaNMath.atanh, mod, rem, copysign, besselj, bessely, besseli, besselk) + continue + end + + fun = eval(:(ξ ->($f)(ξ, 2.0))) + + fd = ForwardDiff.derivative(fun, x) + sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives + + @test isequal(fd, sym) +end + +for f ∈ (atanh,) + fun = eval(:(ξ ->($f)(ξ))) + + fd = ForwardDiff.derivative(fun, x) + sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives + + @test isequal(fd, sym) +end + +for f ∈ (besselj, bessely, besseli, besselk) + fun = eval(:(ξ ->($f)(ξ, 2))) + + fd = ForwardDiff.derivative(fun, x) + sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives + + @test isequal(fd, sym) +end + +# These are evaluated numerically. For some reason isequal evaluates to false for the symbolic expressions. +for f ∈ (acsc, asech, NaNMath.log2, NaNMath.log10) + fun = eval(:(ξ ->($f)(ξ))) + + fd = ForwardDiff.derivative(fun, 1.0) + sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives + + @test isequal(fd, substitute(sym, Dict(x => 1.0))) +end \ No newline at end of file From ab7e80504ce5ae026bb1591049230c8a3ff52eba Mon Sep 17 00:00:00 2001 From: Jimmy Envall Date: Sun, 7 Jan 2024 13:23:55 +0100 Subject: [PATCH 02/10] Add test comments --- test/forwarddiff_symbolic_dual_ops.jl | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/test/forwarddiff_symbolic_dual_ops.jl b/test/forwarddiff_symbolic_dual_ops.jl index 4bb9af9f3..439c60cac 100644 --- a/test/forwarddiff_symbolic_dual_ops.jl +++ b/test/forwarddiff_symbolic_dual_ops.jl @@ -9,6 +9,9 @@ SF = SymbolicUtils.SpecialFunctions @variables x +# Test functions from Symbolics # +#-------------------------------# + for f ∈ SymbolicUtils.basic_monadic fun = eval(:(ξ ->($f)(ξ))) @@ -95,4 +98,21 @@ for f ∈ (acsc, asech, NaNMath.log2, NaNMath.log10) sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives @test isequal(fd, substitute(sym, Dict(x => 1.0))) -end \ No newline at end of file +end + +# Additionally test these definitions from ForwardDiff # +#------------------------------------------------------# + +# https://github.com/JuliaDiff/ForwardDiff.jl/blob/d3002093beb88ff0b98ed178377961dfd55c1247/src/dual.jl#L599 +# and +# https://github.com/JuliaDiff/ForwardDiff.jl/blob/d3002093beb88ff0b98ed178377961dfd55c1247/src/dual.jl#L683 +for f ∈ (hypot, muladd) + fun = eval(:(ξ ->($f)(ξ, 2.0, 3.0))) + + fd = ForwardDiff.derivative(fun, 5.0) + sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives + + @test isequal(fd, substitute(sym, Dict(x => 5.0))) +end + +# fma is not defined for Symbolics.Num From e8ddd3e1959f80f604d9358d529b9568aa8c16a4 Mon Sep 17 00:00:00 2001 From: Jimmy Envall Date: Sun, 7 Jan 2024 13:29:04 +0100 Subject: [PATCH 03/10] Add source comment --- ext/SymbolicsForwardDiffExt.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ext/SymbolicsForwardDiffExt.jl b/ext/SymbolicsForwardDiffExt.jl index 06130c21f..130546d90 100644 --- a/ext/SymbolicsForwardDiffExt.jl +++ b/ext/SymbolicsForwardDiffExt.jl @@ -6,6 +6,9 @@ using ForwardDiff.DiffRules using ForwardDiff: value, Dual, partials using Symbolics +# The method generation in this file have been adapted from +# https://github.com/JuliaDiff/ForwardDiff.jl/blob/v0.10.36/src/dual.jl + const AMBIGUOUS_TYPES = (Num,) #################################### From 18f1abf55020e25bf4a7b4ad4c249bd504f82bbc Mon Sep 17 00:00:00 2001 From: Jimmy Envall Date: Sun, 7 Jan 2024 13:36:41 +0100 Subject: [PATCH 04/10] Add test to runtests.jl --- test/runtests.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/runtests.jl b/test/runtests.jl index d8e6e544c..7d42fb555 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -33,6 +33,7 @@ if GROUP == "All" || GROUP == "Core" @safetestset "Linear Solver Test" begin include("linear_solver.jl") end @safetestset "Algebraic Solver Test" begin include("solver.jl") end @safetestset "Overloading Test" begin include("overloads.jl") end + @safetestset "ForwardDiff Extension Test" begin include("forwarddiff_symbolic_dual_ops.jl") end @safetestset "Nested ForwardDiff Sparsity Test" begin include("nested_forwarddiff_sparsity.jl") end @safetestset "Build Function Test" begin include("build_function.jl") end @safetestset "Build Function Array Test" begin include("build_function_arrayofarray.jl") end From 6512edd8d964a14f01ef432040055e355d1b9fa3 Mon Sep 17 00:00:00 2001 From: Jimmy Envall Date: Mon, 8 Jan 2024 11:47:53 +0100 Subject: [PATCH 05/10] Remove comment that might be confusing in this context --- ext/SymbolicsForwardDiffExt.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/SymbolicsForwardDiffExt.jl b/ext/SymbolicsForwardDiffExt.jl index 130546d90..2fad70f31 100644 --- a/ext/SymbolicsForwardDiffExt.jl +++ b/ext/SymbolicsForwardDiffExt.jl @@ -118,8 +118,7 @@ for (M, f, arity) in DiffRules.diffrules(filter_modules = nothing) elseif arity == 2 eval(binary_dual_definition(M, f, AMBIGUOUS_TYPES)) else - # error("ForwardDiff currently only knows how to autogenerate Dual definitions for unary and binary functions.") - # However, the presence of N-ary rules need not cause any problems here, they can simply be ignored. + # no-op end end From 9f9dd8312fe15bc5fe2834925d0e8c32bcf363ad Mon Sep 17 00:00:00 2001 From: Jimmy Envall Date: Mon, 8 Jan 2024 11:48:10 +0100 Subject: [PATCH 06/10] Remove fma methods --- ext/SymbolicsForwardDiffExt.jl | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/ext/SymbolicsForwardDiffExt.jl b/ext/SymbolicsForwardDiffExt.jl index 2fad70f31..480fc83f5 100644 --- a/ext/SymbolicsForwardDiffExt.jl +++ b/ext/SymbolicsForwardDiffExt.jl @@ -236,23 +236,6 @@ end ) end -# fma # -#-----# - -@eval begin - @define_ternary_dual_op( - Base.fma, - calc_fma_xyz(x, y, z), # xyz_body - calc_fma_xy(x, y, z), # xy_body - calc_fma_xz(x, y, z), # xz_body - Base.fma(y, x, z), # yz_body - Dual{Tx}(fma(value(x), y, z), partials(x) * y), # x_body - Base.fma(y, x, z), # y_body - Dual{Tz}(fma(x, y, value(z)), partials(z)), # z_body - $AMBIGUOUS_TYPES - ) -end - # muladd # #--------# From 6e17be83a3454d67ed406c01bd91cbe13a849d03 Mon Sep 17 00:00:00 2001 From: Jimmy Envall Date: Mon, 8 Jan 2024 11:51:24 +0100 Subject: [PATCH 07/10] Test acsch numerically --- test/forwarddiff_symbolic_dual_ops.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/forwarddiff_symbolic_dual_ops.jl b/test/forwarddiff_symbolic_dual_ops.jl index 439c60cac..40a6f43d2 100644 --- a/test/forwarddiff_symbolic_dual_ops.jl +++ b/test/forwarddiff_symbolic_dual_ops.jl @@ -25,7 +25,7 @@ for f ∈ SymbolicUtils.monadic # The polygamma and trigamma functions seem to be missing rules in ForwardDiff. # The abs rule uses conditionals and cannot be used with Symbolics.Num. # acsc, asech, NanMath.log2 and NaNMath.log10 are tested separately - if f ∈ (abs, SF.polygamma, SF.trigamma, acsc, asech, NaNMath.log2, NaNMath.log10) + if f ∈ (abs, SF.polygamma, SF.trigamma, acsc, acsch, asech, NaNMath.log2, NaNMath.log10) continue end From 0b1271d728b3becc173c477d51313e59beb7d58d Mon Sep 17 00:00:00 2001 From: Jimmy Envall Date: Mon, 8 Jan 2024 11:52:13 +0100 Subject: [PATCH 08/10] Compare numerical evaluations approximately --- test/forwarddiff_symbolic_dual_ops.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/forwarddiff_symbolic_dual_ops.jl b/test/forwarddiff_symbolic_dual_ops.jl index 40a6f43d2..bd659e2b2 100644 --- a/test/forwarddiff_symbolic_dual_ops.jl +++ b/test/forwarddiff_symbolic_dual_ops.jl @@ -43,7 +43,7 @@ for f ∈ (acsc, asech, NaNMath.log2, NaNMath.log10) fd = ForwardDiff.derivative(fun, 1.0) sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives - @test isequal(fd, substitute(sym, Dict(x => 1.0))) + @test fd ≈ substitute(sym, Dict(x => 1.0)) end for f ∈ SymbolicUtils.basic_diadic @@ -112,7 +112,7 @@ for f ∈ (hypot, muladd) fd = ForwardDiff.derivative(fun, 5.0) sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives - @test isequal(fd, substitute(sym, Dict(x => 5.0))) + @test fd ≈ substitute(sym, Dict(x => 5.0)) end # fma is not defined for Symbolics.Num From f38dfcbed4c79c5389fa68356ecc5b7fdbbd068f Mon Sep 17 00:00:00 2001 From: Jimmy Envall Date: Mon, 8 Jan 2024 11:52:46 +0100 Subject: [PATCH 09/10] Remove duplicate test --- test/forwarddiff_symbolic_dual_ops.jl | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/test/forwarddiff_symbolic_dual_ops.jl b/test/forwarddiff_symbolic_dual_ops.jl index bd659e2b2..66612b9bb 100644 --- a/test/forwarddiff_symbolic_dual_ops.jl +++ b/test/forwarddiff_symbolic_dual_ops.jl @@ -37,6 +37,7 @@ for f ∈ SymbolicUtils.monadic @test isequal(fd, sym) end +# These are evaluated numerically. For some reason isequal evaluates to false for the symbolic expressions. for f ∈ (acsc, asech, NaNMath.log2, NaNMath.log10) fun = eval(:(ξ ->($f)(ξ))) @@ -90,16 +91,6 @@ for f ∈ (besselj, bessely, besseli, besselk) @test isequal(fd, sym) end -# These are evaluated numerically. For some reason isequal evaluates to false for the symbolic expressions. -for f ∈ (acsc, asech, NaNMath.log2, NaNMath.log10) - fun = eval(:(ξ ->($f)(ξ))) - - fd = ForwardDiff.derivative(fun, 1.0) - sym = Symbolics.Differential(x)(fun(x)) |> expand_derivatives - - @test isequal(fd, substitute(sym, Dict(x => 1.0))) -end - # Additionally test these definitions from ForwardDiff # #------------------------------------------------------# From 1b9069055c6a1b0b7d2a6ed79481c1f99dc0af6b Mon Sep 17 00:00:00 2001 From: Jimmy Envall Date: Mon, 8 Jan 2024 11:52:59 +0100 Subject: [PATCH 10/10] Add missing qualification --- test/forwarddiff_symbolic_dual_ops.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/forwarddiff_symbolic_dual_ops.jl b/test/forwarddiff_symbolic_dual_ops.jl index 66612b9bb..1b89c79e6 100644 --- a/test/forwarddiff_symbolic_dual_ops.jl +++ b/test/forwarddiff_symbolic_dual_ops.jl @@ -73,7 +73,7 @@ for f ∈ SymbolicUtils.diadic @test isequal(fd, sym) end -for f ∈ (atanh,) +for f ∈ (NaNMath.atanh,) fun = eval(:(ξ ->($f)(ξ))) fd = ForwardDiff.derivative(fun, x)