From 019088400a5ea86caaa2eb0a0416fd832159f6f3 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Mon, 7 Sep 2026 11:19:37 +1200 Subject: [PATCH] [Nonlinear.SymbolicAD] fix derivative of atan --- src/Nonlinear/SymbolicAD/SymbolicAD.jl | 2 +- test/Nonlinear/test_SymbolicAD.jl | 29 +++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/Nonlinear/SymbolicAD/SymbolicAD.jl b/src/Nonlinear/SymbolicAD/SymbolicAD.jl index 97875bbceb..3c962eabf8 100644 --- a/src/Nonlinear/SymbolicAD/SymbolicAD.jl +++ b/src/Nonlinear/SymbolicAD/SymbolicAD.jl @@ -704,7 +704,7 @@ function derivative(f::MOI.ScalarNonlinearFunction, x::MOI.VariableIndex) return MOI.ScalarNonlinearFunction( :/, Any[ - MOI.ScalarNonlinearFunction(:+, Any[u_dv_dx, v_du_dx]), + MOI.ScalarNonlinearFunction(:-, Any[v_du_dx, u_dv_dx]), MOI.ScalarNonlinearFunction(:+, Any[u_2, v_2]), ], ) diff --git a/test/Nonlinear/test_SymbolicAD.jl b/test/Nonlinear/test_SymbolicAD.jl index a123100d17..0d2046bcfb 100644 --- a/test/Nonlinear/test_SymbolicAD.jl +++ b/test/Nonlinear/test_SymbolicAD.jl @@ -7,10 +7,10 @@ module TestMathOptSymbolicAD using Test +import ForwardDiff import MathOptInterface as MOI import MathOptInterface: Nonlinear - -const SymbolicAD = Nonlinear.SymbolicAD +import MathOptInterface.Nonlinear: SymbolicAD function runtests() for name in names(@__MODULE__; all = true) @@ -100,7 +100,7 @@ function test_derivative() # :atan op(:atan, x, sin_x)=>op( :/, - op(:+, op(:*, x, cos_x), sin_x), + op(:-, sin_x, op(:*, x, cos_x)), op(:+, op(:^, x, 2), op(:^, sin_x, 2)), ), # :min @@ -785,6 +785,29 @@ function test_simplify_drops_ones() return end +function test_atan_derivatives() + model = MOI.Utilities.Model{Float64}() + u, v = MOI.VariableIndex.(1:2) + f = MOI.ScalarNonlinearFunction(:atan, Any[u, v]) + f_u = MOI.Nonlinear.SymbolicAD.derivative(f, u) + f_v = MOI.Nonlinear.SymbolicAD.derivative(f, v) + for x in -1.0:0.5:1.0, y in -1.0:0.5:1.0 + if iszero(x) && iszero(y) + continue + end + point = Dict(u => x, v => y) + @test isapprox( + MOI.Utilities.eval_variables(xi -> point[xi], model, f_u), + ForwardDiff.derivative(a -> atan(a, y), x), + ) + @test isapprox( + MOI.Utilities.eval_variables(xi -> point[xi], model, f_v), + ForwardDiff.derivative(b -> atan(x, b), y), + ) + end + return +end + end # module TestMathOptSymbolicAD.runtests()