# Autodiff Enzyme reverse mode sometimes fails on on repeated evaluation

**URL:** https://discourse.julialang.org/t/autodiff-enzyme-reverse-mode-sometimes-fails-on-on-repeated-evaluation/110017
**Category:** Optimization (Mathematical)
**Tags:** enzyme
**Created:** [February 10, 2024, 5:16am UTC](https://discourse.julialang.org/t/autodiff-enzyme-reverse-mode-sometimes-fails-on-on-repeated-evaluation/110017 "2024-02-10T05:16:23Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![dchang10](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dchang10/32/44162_2.png) [@dchang10](https://discourse.julialang.org/u/dchang10)
#### Post date: [February 10, 2024, 5:16am UTC](https://discourse.julialang.org/t/autodiff-enzyme-reverse-mode-sometimes-fails-on-on-repeated-evaluation/110017/1 "2024-02-10T05:16:23Z")

</div>

I’m developing a package which has a function defined the following way

```julia
function emission_radius(pix::Krang.AbstractPixel, θs::T, isindir, n) where {T}
    α, β = screen_coordinate(pix)
    θo = inclination(pix)
    met = metric(pix)
    isincone = θo ≤ θs ≤ (π-θo) || (π-θo) ≤ θs ≤ θo
    if !isincone#cosθs > abs(cosθo)
        αmin = αboundary(met, θs)
        βbound = (abs(α) >= (αmin + eps(T)) ? βboundary(met, α, θo, θs) : zero(T))
        ((abs(β) + eps(T)) < βbound) && return (T(NaN), true, true, 0)
    end

    τ, _, _, _ = Gθ(pix, θs, isindir, n)

    # is θ̇s increasing or decreasing?
    νθ = !isindir
    if isincone 
        νθ = (θo > θs) ⊻ (n % 2 == 1) 
    end
    # is ṙs increasing or decreasing?
    rs, νr, numreals = emission_radius(pix, τ)

    return rs, νr, νθ, numreals, abs(τ)
end

```

I however get indeterministic behaviour when using autodiff in reverse mode on this function. Here is an example where I define the function and differentiate through it with the same variables 5 times.

```julia
using Enzyme

for _ in 1:5
function intensity_point(x,y)
    θo = π/4
    metric = Krang.Kerr(-0.94);
    px = Krang.IntensityPixel(metric, x, y, θo)
    

    return emission_radius(px, π / 2, true, 0)[1]
end
println(intensity_point(5.0, 4.0))
println(autodiff(ReverseWithPrimal, intensity_point, Active, Active(5.0), Active(4.0)))
end

```

The resulting output looks like this

```julia
5.2302506256226895
 caching call: %33 = call fastcc double @julia_K_36770(double %22) #95, !dbg !139
 caching call: %8 = call fastcc double @julia_serf_36810(double %5, double %1) #97, !dbg !102
 caching call: %27 = call fastcc double @julia_serf_36810(double %22, double %1) #101, !dbg !97
 caching call: %28 = call fastcc double @julia_K_36770(double %1) #100, !dbg !136
 caching call: %28 = call fastcc double @julia_K_36770(double %21) #100, !dbg !137
 caching call: %45 = call fastcc double @julia_K_36770(double %16) #100, !dbg !160
 caching call: %55 = call fastcc double @julia_atan_36837(double %53) #101, !dbg !173
 caching call: %9 = call fastcc double @julia_K_36770(double %1) #119, !dbg !106
 caching call: %10 = call fastcc double @julia_K_36770(double %1) #119, !dbg !106
 caching call: %17 = call fastcc double @julia_K_36770(double %16) #119, !dbg !122
 caching call: %18 = call fastcc double @julia_K_36770(double %16) #119, !dbg !122
((NaN, NaN), 5.2302506256226895)
5.2302506256226895
 caching call: %33 = call fastcc double @julia_K_37083(double %22) #95, !dbg !139
 caching call: %8 = call fastcc double @julia_serf_37123(double %5, double %1) #97, !dbg !102
 caching call: %27 = call fastcc double @julia_serf_37123(double %22, double %1) #101, !dbg !97
 caching call: %28 = call fastcc double @julia_K_37083(double %1) #100, !dbg !136
 caching call: %28 = call fastcc double @julia_K_37083(double %21) #100, !dbg !137
 caching call: %45 = call fastcc double @julia_K_37083(double %16) #100, !dbg !160
 caching call: %55 = call fastcc double @julia_atan_37150(double %53) #101, !dbg !173
 caching call: %9 = call fastcc double @julia_K_37083(double %1) #119, !dbg !106
 caching call: %10 = call fastcc double @julia_K_37083(double %1) #119, !dbg !106
 caching call: %17 = call fastcc double @julia_K_37083(double %16) #119, !dbg !122
 caching call: %18 = call fastcc double @julia_K_37083(double %16) #119, !dbg !122
((0.8447302895862908, 0.6627147492004235), 5.2302506256226895)
5.2302506256226895
 caching call: %33 = call fastcc double @julia_K_37396(double %22) #95, !dbg !139
 caching call: %8 = call fastcc double @julia_serf_37436(double %5, double %1) #97, !dbg !102
 caching call: %27 = call fastcc double @julia_serf_37436(double %22, double %1) #101, !dbg !97
 caching call: %28 = call fastcc double @julia_K_37396(double %1) #100, !dbg !136
 caching call: %28 = call fastcc double @julia_K_37396(double %21) #100, !dbg !137
 caching call: %45 = call fastcc double @julia_K_37396(double %16) #100, !dbg !160
 caching call: %55 = call fastcc double @julia_atan_37463(double %53) #101, !dbg !173
 caching call: %9 = call fastcc double @julia_K_37396(double %1) #119, !dbg !106
 caching call: %10 = call fastcc double @julia_K_37396(double %1) #119, !dbg !106
 caching call: %17 = call fastcc double @julia_K_37396(double %16) #119, !dbg !122
 caching call: %18 = call fastcc double @julia_K_37396(double %16) #119, !dbg !122
((NaN, NaN), 5.2302506256226895)

```

Enzyme is apparently is capable of taking the derivative sometimes, but not other times. What can I do to get more predictable behaviour out?

---

<div class="post-metadata">

### Author: ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)
#### Post date: [February 10, 2024, 6:14am UTC](https://discourse.julialang.org/t/autodiff-enzyme-reverse-mode-sometimes-fails-on-on-repeated-evaluation/110017/2 "2024-02-10T06:14:58Z")

</div>

Is the function `intensity_point` fully deterministic to start with?

I don’t know what exactly `Krang.Kerr` and `Krang.IntensityPixel` are doing, but it would be the easiest explanation that some randomness leads to different branches and then one could check what goes wrong in these particular branches…

---

<div class="post-metadata">

### Author: ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)
#### Post date: [February 10, 2024, 6:16am UTC](https://discourse.julialang.org/t/autodiff-enzyme-reverse-mode-sometimes-fails-on-on-repeated-evaluation/110017/3 "2024-02-10T06:16:04Z")

</div>

> [@dchang10](#):
>
> ```julia
> for _ in 1:5
> function intensity_point(x,y)
> θo = π/4
> metric = Krang.Kerr(-0.94);
> px = Krang.IntensityPixel(metric, x, y, θo)
>     
> 
> return emission_radius(px, π / 2, true, 0)[1]
> end
> 
> ```

Part of the issue is probably re-defining the function in a `for` loop. Does it happen if you just define the function once? Why do you need to keep redefining it?

---

<div class="post-metadata">

### Author: ![dchang10](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dchang10/32/44162_2.png) [@dchang10](https://discourse.julialang.org/u/dchang10)
#### Post date: [February 10, 2024, 2:35pm UTC](https://discourse.julialang.org/t/autodiff-enzyme-reverse-mode-sometimes-fails-on-on-repeated-evaluation/110017/4 "2024-02-10T14:35:39Z")

</div>

Yes, `intensity_point` is deterministic. `Kerr` and `IntensityPixel` are structs that I use to cache some information.

```julia
struct Kerr{T} <: AbstractMetric
    "M = mass"
    mass::T  
    "a = J/M, where J is the angular momentum and M is the mass of the blackhole."
    spin::T
    function Kerr(spin::T) where {T}
        new{T}(one(T), spin)
    end
end

```

```julia
struct IntensityPixel{T} <: AbstractPixel
    metric::Kerr{T}
    screen_coordinate::NTuple{2, T}
    "Radial roots"
    roots::NTuple{4,Complex{T}}
    "Radial antiderivative"
    I0_inf::T
    "Angular antiderivative"
    absGθo_Gθhat::NTuple{2,T}
    "Inclination"
    θo::T
    η::T
    λ::T
    function IntensityPixel(met::Kerr{T}, α, β, θo) where {T}
        tempη = Krang.η(met, α, β, θo)
        tempλ = Krang.λ(met, α, θo)
        roots = Krang.get_radial_roots(met, tempη, tempλ)
        numreals = sum(_isreal2.(roots))
        if (numreals == 2) && (abs(imag(roots[4])) < sqrt(eps(T)))
            roots = (roots[1], roots[4], roots[2], roots[3])
        end
        new{T}(
            met,
            (α, β), 
            roots,
            Krang.Ir_inf(met, roots), 
            Krang._absGθo_Gθhat(met, θo, tempη, tempλ), 
            θo, tempη, tempλ
        )
    end
end

```

---

<div class="post-metadata">

### Author: ![dchang10](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dchang10/32/44162_2.png) [@dchang10](https://discourse.julialang.org/u/dchang10)
#### Post date: [February 10, 2024, 2:37pm UTC](https://discourse.julialang.org/t/autodiff-enzyme-reverse-mode-sometimes-fails-on-on-repeated-evaluation/110017/5 "2024-02-10T14:37:10Z")

</div>

Defining the function once causes enzyme to either always return `NaN` or the an actual number. I was redefining the function to show that different answers for the derivative can be returned, even though the function itself always returns the same value.

---

<div class="post-metadata">

### Author: ![wsmoses](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsmoses/32/26497_2.png) [@wsmoses](https://discourse.julialang.org/u/wsmoses)
#### Post date: [February 10, 2024, 2:47pm UTC](https://discourse.julialang.org/t/autodiff-enzyme-reverse-mode-sometimes-fails-on-on-repeated-evaluation/110017/6 "2024-02-10T14:47:46Z")

</div>

Open an issue on Enzyme with the MWE, Enzyme version, and Julia/OS version?

---

<div class="post-metadata">

### Author: ![dchang10](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dchang10/32/44162_2.png) [@dchang10](https://discourse.julialang.org/u/dchang10)
#### Post date: [February 19, 2024, 1:46am UTC](https://discourse.julialang.org/t/autodiff-enzyme-reverse-mode-sometimes-fails-on-on-repeated-evaluation/110017/7 "2024-02-19T01:46:27Z")

</div>

Sure thing

---

<div class="post-metadata">

### Author: ![dchang10](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dchang10/32/44162_2.png) [@dchang10](https://discourse.julialang.org/u/dchang10)
#### Post date: [February 20, 2024, 3:27pm UTC](https://discourse.julialang.org/t/autodiff-enzyme-reverse-mode-sometimes-fails-on-on-repeated-evaluation/110017/8 "2024-02-20T15:27:04Z")

</div>

Created an issue with an MWE on [github](https://github.com/EnzymeAD/Enzyme.jl/issues/1298).
