I would like to implement a z/sqrt(s^2+z^2) that
- works for when
zandshave wildly different magnitudes, but are both finite, - also gives the correct result when AD’s via the most common frameworks.
I would prefer to avoid writing custom rules if possible. This part makes the exercise tricky.
Here is an MWE of failures using Enzyme as a demo because it traps NaNs. I would appreciate suggestions on how to do this. Or maybe someone convincing me that this is not possible without custom rules.
using Enzyme, Test
Enzyme.Compiler.CheckNan[] = true # error for NaNs
function _z_over_hypot(z, s)
r = z / s
if abs(r) ≤ 1
r / sqrt(one(r) + r^2)
else
u = inv(r)
sign(r) / sqrt(one(u) + u^2)
end
end
@testset "z over hypot torture test" begin
# V = [1.0, 2.0, 3.0] # for simple tests
V = [1e-180, -1e-180, 0.5e-100, 1e-100, 2e-100, 1e-50, 1e100, 1e200]
for s in V
for z in V
for dz in V
@show s, z, dz
dx, x = Enzyme.autodiff(Enzyme.ForwardWithPrimal, z -> SK._z_over_hypot(z, s),
Enzyme.Duplicated(z, dz))
_z = BigFloat(z)
_s = BigFloat(s)
_r = _z / _s
_q = 1 + _r^2
_x = z / √(z^2 + s^2)
_dx = 1 / _s / (_q * √_q)
@test x ≈ Float64(_x)
@test dx ≈ Float64(_dx) * dz
end
end
end
end