Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "ChainRulesCore"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "0.10.1"
version = "0.10.2"

[deps]
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
Expand Down
5 changes: 5 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ ChainRulesCore.is_inplaceable_destination
ChainRulesCore.AbstractTangent
ChainRulesCore.debug_mode
```

## Deprecated
```@docs
ChainRulesCore.extern
```
52 changes: 52 additions & 0 deletions src/deprecated.jl
Original file line number Diff line number Diff line change
@@ -1 +1,53 @@
Base.@deprecate_binding NO_FIELDS NoTangent()

const EXTERN_DEPRECATION = "`extern` is deprecated, use `unthunk` or `backing` instead, " *
"depending on the use case."

"""
extern(x)

Makes a best effort attempt to convert a differential into a primal value.
This is not always a well-defined operation.
For two reasons:
- It may not be possible to determine the primal type for a given differential.
For example, `Zero` is a valid differential for any primal.
- The primal type might not be a vector space, thus might not be a valid differential type.
For example, if the primal type is `DateTime`, it's not a valid differential type as two
`DateTime` can not be added (fun fact: `Milisecond` is a differential for `DateTime`).

Where it is defined the operation of `extern` for a primal type `P` should be
`extern(x) = zero(P) + x`.

!!! note
Because of its limitations, `extern` should only really be used for testing.
It can be useful, if you know what you are getting out, as it recursively removes
thunks, and otherwise makes outputs more consistent with finite differencing.

The more useful action in general is to call `+`, or in the case of a [`Thunk`](@ref)
to call [`unthunk`](@ref).

!!! warning
`extern` may return an alias (not necessarily a copy) to data
wrapped by `x`, such that mutating `extern(x)` might mutate `x` itself.
"""
@inline function extern(x)
Base.depwarn(EXTERN_DEPRECATION, :extern)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought I asked this before, but if so github has eaten the reply.
(Probably i forget to ask)

Why are we using Base.depwarn rather than @deprecate?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I think it's because we are not providing a definite alternative. I.e. it isn't always just extern -> unthunk, it could be using backing as well

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general we are not.
But for any specific case they can make the change to put the RHS of the deprecation in the place of the extern.
which they might have to do recursively til it stops but still.
Though perhaps that is worse.

return x
end

extern(x::ZeroTangent) = (Base.depwarn(EXTERN_DEPRECATION, :extern); return false) # false is a strong 0. E.g. `false * NaN = 0.0`

function extern(x::NoTangent)
Base.depwarn(EXTERN_DEPRECATION, :extern)
throw(ArgumentError("Derivative does not exit. Cannot be converted to an external type."))
end

extern(comp::Tangent) = (Base.depwarn(EXTERN_DEPRECATION, :extern); return backing(map(extern, comp))) # gives a NamedTuple or Tuple

extern(x::NotImplemented) = (Base.depwarn(EXTERN_DEPRECATION, :extern); throw(NotImplementedException(x)))

@inline extern(x::AbstractThunk) = (Base.depwarn(EXTERN_DEPRECATION, :extern); return extern(unthunk(x)))




29 changes: 0 additions & 29 deletions src/differentials/abstract_differential.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,33 +37,4 @@ abstract type AbstractTangent end

Base.:+(x::AbstractTangent) = x

"""
extern(x)

Makes a best effort attempt to convert a differential into a primal value.
This is not always a well-defined operation.
For two reasons:
- It may not be possible to determine the primal type for a given differential.
For example, `Zero` is a valid differential for any primal.
- The primal type might not be a vector space, thus might not be a valid differential type.
For example, if the primal type is `DateTime`, it's not a valid differential type as two
`DateTime` can not be added (fun fact: `Milisecond` is a differential for `DateTime`).

Where it is defined the operation of `extern` for a primal type `P` should be
`extern(x) = zero(P) + x`.

!!! note
Because of its limitations, `extern` should only really be used for testing.
It can be useful, if you know what you are getting out, as it recursively removes
thunks, and otherwise makes outputs more consistent with finite differencing.

The more useful action in general is to call `+`, or in the case of a [`Thunk`](@ref)
to call [`unthunk`](@ref).

!!! warning
`extern` may return an alias (not necessarily a copy) to data
wrapped by `x`, such that mutating `extern(x)` might mutate `x` itself.
"""
@inline extern(x) = x

@inline Base.conj(x::AbstractTangent) = x
6 changes: 0 additions & 6 deletions src/differentials/abstract_zero.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ A derivative of `ZeroTangent()` does not propagate through the primal function.
"""
struct ZeroTangent <: AbstractZero end

extern(x::ZeroTangent) = false # false is a strong 0. E.g. `false * NaN = 0.0`

Base.eltype(::Type{ZeroTangent}) = ZeroTangent

Base.zero(::AbstractTangent) = ZeroTangent()
Expand Down Expand Up @@ -72,7 +70,3 @@ arguments.
```
"""
struct NoTangent <: AbstractZero end

function extern(x::NoTangent)
throw(ArgumentError("Derivative does not exit. Cannot be converted to an external type."))
end
3 changes: 0 additions & 3 deletions src/differentials/composite.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,6 @@ end

Base.conj(comp::Tangent) = map(conj, comp)

extern(comp::Tangent) = backing(map(extern, comp)) # gives a NamedTuple or Tuple


"""
backing(x)

Expand Down
2 changes: 0 additions & 2 deletions src/differentials/notimplemented.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ Base.Broadcast.broadcastable(x::NotImplemented) = Ref(x)

# throw error with debugging information for other standard information
# (`+`, `-`, `*`, and `dot` are defined in differential_arithmetic.jl)
extern(x::NotImplemented) = throw(NotImplementedException(x))

Base.:/(x::NotImplemented, ::Any) = throw(NotImplementedException(x))
Base.:/(::Any, x::NotImplemented) = throw(NotImplementedException(x))
Base.:/(x::NotImplemented, ::NotImplemented) = throw(NotImplementedException(x))
Expand Down
9 changes: 0 additions & 9 deletions src/differentials/thunks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,9 @@ end

On `AbstractThunk`s this removes 1 layer of thunking.
On any other type, it is the identity operation.

In contrast to [`extern`](@ref) this is nonrecursive.
"""
@inline unthunk(x) = x

@inline extern(x::AbstractThunk) = extern(unthunk(x))

Base.conj(x::AbstractThunk) = @thunk(conj(unthunk(x)))
Base.adjoint(x::AbstractThunk) = @thunk(adjoint(unthunk(x)))
Base.transpose(x::AbstractThunk) = @thunk(transpose(unthunk(x)))
Expand All @@ -54,16 +50,11 @@ It wraps a zero argument closure that when invoked returns a differential.
Calling a thunk, calls the wrapped closure.
If you are unsure if you have a `Thunk`, call [`unthunk`](@ref) which is a no-op when the
argument is not a `Thunk`.
If you need to unthunk recursively, call [`extern`](@ref), which also externs the differial
that the closure returns.

```jldoctest
julia> t = @thunk(@thunk(3))
Thunk(var"#4#6"())

julia> extern(t)
3

julia> t()
Thunk(var"#5#7"())

Expand Down
21 changes: 21 additions & 0 deletions test/deprecated.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
@testset "NO_FIELDS" begin
@test (@test_deprecated NO_FIELDS) isa NoTangent
end

@testset "extern" begin
@test extern(@thunk(3)) == 3
@test extern(@thunk(@thunk(3))) == 3

@test extern(Tangent{Foo}(x=2.0)) == (;x=2.0)
@test extern(Tangent{Tuple{Float64,}}(2.0)) == (2.0,)
@test extern(Tangent{Dict}(Dict(4 => 3))) == Dict(4 => 3)

# with differentials on the inside
@test extern(Tangent{Foo}(x=@thunk(0+2.0))) == (;x=2.0)
@test extern(Tangent{Tuple{Float64,}}(@thunk(0+2.0))) == (2.0,)
@test extern(Tangent{Dict}(Dict(4 => @thunk(3)))) == Dict(4 => 3)

z = ZeroTangent()
@test extern(z) === false
dne = NoTangent()
@test_throws Exception extern(dne)
E = ChainRulesCore.NotImplementedException
@test_throws E extern(ni)
end
2 changes: 0 additions & 2 deletions test/differentials/abstract_zero.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

@testset "ZeroTangent" begin
z = ZeroTangent()
@test extern(z) === false
@test z + z === z
@test z + 1 === 1
@test 1 + z === 1
Expand Down Expand Up @@ -64,7 +63,6 @@

@testset "NoTangent" begin
dne = NoTangent()
@test_throws Exception extern(dne)
@test dne + dne == dne
@test dne + 1 == 1
@test 1 + dne == 1
Expand Down
11 changes: 0 additions & 11 deletions test/differentials/composite.jl
Original file line number Diff line number Diff line change
Expand Up @@ -123,17 +123,6 @@ end
)
end

@testset "extern" begin
@test extern(Tangent{Foo}(x=2.0)) == (;x=2.0)
@test extern(Tangent{Tuple{Float64,}}(2.0)) == (2.0,)
@test extern(Tangent{Dict}(Dict(4 => 3))) == Dict(4 => 3)

# with differentials on the inside
@test extern(Tangent{Foo}(x=@thunk(0+2.0))) == (;x=2.0)
@test extern(Tangent{Tuple{Float64,}}(@thunk(0+2.0))) == (2.0,)
@test extern(Tangent{Dict}(Dict(4 => @thunk(3)))) == Dict(4 => 3)
end

@testset "canonicalize" begin
# Testing iterate via collect
@test ==(
Expand Down
1 change: 0 additions & 1 deletion test/differentials/notimplemented.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@

# unsupported operations
E = ChainRulesCore.NotImplementedException
@test_throws E extern(ni)
@test_throws E +ni
@test_throws E -ni
@test_throws E ni - rand()
Expand Down
7 changes: 1 addition & 6 deletions test/differentials/thunks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@
@test occursin(r"Thunk\(.*rand.*\)", rep)
end

@testset "Externing" begin
@test extern(@thunk(3)) == 3
@test extern(@thunk(@thunk(3))) == 3
end

@testset "unthunk" begin
@test unthunk(@thunk(3)) == 3
@test unthunk(@thunk(@thunk(3))) isa Thunk
Expand All @@ -25,7 +20,7 @@
expected_line = (@__LINE__) + 2 # for testing it is at right palce
try
x = @thunk(error())
extern(x)
unthunk(x)
catch err
err isa ErrorException || rethrow()
st = stacktrace(catch_backtrace())
Expand Down