Skip to content

Make extern recursive? #47

@oxinabox

Description

@oxinabox

it is not too hard to endup in a situtation where you have say
Thunk(()->Thunk(()->3)) ie., @thunk(@thunk(3))

One example (written in #30 style) is if you have

rrule(::typeof(f), x) = f(x), y->(NO_FIELDS, @thunk(3))
function rrule(::typeof(g), x)
    _, inner_pullback = rrule(f, x)
   function g_pullback(y)
        (NO_FIELDS, @thunk(g_pullback(y)[2])
   end
   return g(x), g_pullback
end

Especially with #30 where we (by nescity) throw a lot more @thunks around.

This is particularly annoying in test right now, and so probably in real use too.


I see two ways to resolve this:

1. make extern(::Thunk) recursive

this is just changing

@inline extern(x::Thunk) = x.f()

to

@inline extern(x::Thunk) = extern(x.f())

This doesn't help for (Casted(Zero()) or Casted(@thunk(3)) etc
but Casted could have the same change I guess,
or it could just or away #10

2. make all externing recursive

We would change current definitions of extern into
extern1
then change extern to call extern1 until the result is no longer a AbstractDifferential.
(either via recursion, or via a loop)

3. Make `Thunk(()->Thunk

Way harder than it looks.
Similarly does not apply to things other than thunks


Not sure on the implications of these on inlining,
I know inlining hates recursion.

Here is some test code I prepared earlier.

    @testset "Thunk" begin
        @test extern(Thunk(()->3)) == 3 == extern(@thunk(3))
        @test extern(Thunk(()->Thunk(()->3))) == 3 == extern(@thunk(@thunk(3)))
        @test @thunk(3) isa Thunk
    end

I think the first one is a good place to start.
And will likely PR that and rebase it into #30

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions