-
Notifications
You must be signed in to change notification settings - Fork 64
Introduce MutableTangent #626
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
92f6a03
rename files
oxinabox f9b5a24
move functionality up to StructuralTangent
oxinabox 35aff30
Formatting
oxinabox c7932f1
WIP mutable Tangent (squash me)
oxinabox 4b50fd2
wip
oxinabox 87ceddf
First pass at something that maybe works
oxinabox e75a364
accept int index
oxinabox b566581
add == and hash for MutableTangent
oxinabox f8900c4
add and test zero_tangent
oxinabox bcb5587
export StructuralTangent
oxinabox 63c450b
Style
oxinabox 53e8f0d
handle unassigned a bit more
oxinabox 17064c2
add some more test cases to zero_tangent
oxinabox 5a19913
style
oxinabox dac92bd
Handle Structs with undef fields
oxinabox 98a7e39
overhaul zero_tangent and MutableTangent for type stability
oxinabox 7d88acd
set MutableTangent setproperty! on index
oxinabox b3562c6
formatting
oxinabox dd3f1ab
handle abstract fields right in mutable tangents outside of zero tangent
oxinabox db45626
formatting
oxinabox ad29971
Add docs for forward mutation support
oxinabox 8471f39
use ismutabletype from Compat
oxinabox 9b6d6e5
wrap structural tangent tests in a common testset
oxinabox f5efd7d
Support types that have no tangent space in zero_tangent
oxinabox 8a54fae
define zero_tangent for Tangent
oxinabox b67686d
Add structural zero tangent code for higher order
oxinabox b3a4d57
Formatting
oxinabox f481d05
overload show for mutable tangent
oxinabox da8c204
formatting
oxinabox 26138a9
move show code to `Common` area
oxinabox e886589
docs more consistent
oxinabox d3380bc
Update src/tangent_types/structural_tangent.jl
oxinabox 501857d
Update test/tangent_types/structural_tangent.jl
oxinabox 2d61f41
Add broken tests for Aliasing and Cyclic references
oxinabox 95e63d0
improve docs
oxinabox 73b7508
stronger statement about aliasing
oxinabox File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# Mutation Support | ||
|
||
ChainRulesCore.jl offers experimental support for mutation, targeting use in forward mode AD. | ||
(Mutation support in reverse mode AD is more complicated and will likely require more changes to the interface) | ||
|
||
!!! warning "Experimental" | ||
This page documents an experimental feature. | ||
Expect breaking changes in minor versions while this remains. | ||
It is not suitable for general use unless you are prepared to modify how you are using it each minor release. | ||
It is thus suggested that if you are using it to use _tilde_ bounds on supported minor versions. | ||
|
||
|
||
## `MutableTangent` | ||
The [`MutableTangent`](@ref) type is designed to be a partner to the [`Tangent`](@ref) type, with specific support for being mutated in place. | ||
It is required to be a structural tangent, having one tangent for each field of the primal object. | ||
|
||
Technically, not all `mutable struct`s need to use `MutableTangent` to represent their tangents. | ||
Just like not all `struct`s need to use `Tangent`s. | ||
Common examples away from this are natural tangent types like for arrays. | ||
However, if one is setting up to use a custom tangent type for this it is sufficiently off the beaten path that we can not provide much guidance. | ||
|
||
## `zero_tangent` | ||
|
||
The [`zero_tangent`](@ref) function functions to give you a zero (i.e. additive identity) for any primal value. | ||
The [`ZeroTangent`](@ref) type also does this. | ||
The difference is that [`zero_tangent`](@ref) is in general full structural tangent mirroring the structure of the primal. | ||
To be technical the promise of [`zero_tangent`](@ref) is that it will be a value that supports mutation. | ||
However, in practice[^1] this is achieved through in a structural tangent | ||
For mutation support this is important, since it means that there is mutable memory available in the tangent to be mutated when the primal changes. | ||
To support this you thus need to make sure your zeros are created in various places with [`zero_tangent`](@ref) rather than []`ZeroTangent`](@ref). | ||
|
||
|
||
|
||
It is also useful for reasons of type stability, since it forces a consistent type (generally a structural tangent) for any given primal type. | ||
For this reason AD system implementors might chose to use this to create the tangent for all literal values they encounter, mutable or not, | ||
and to process the output of `frule`s to convert [`ZeroTangent`](@ref) into corresponding [`zero_tangent`](@ref)s. | ||
|
||
## Writing a frule for a mutating function | ||
It is relatively straight forward to write a frule for a mutating function. | ||
There are a few key points to follow: | ||
- There must be a mutable tangent input for every mutated primal input | ||
- When the primal value is changed, the corresponding change must be made to its tangent partner | ||
- When a value is returned, return its partnered tangent. | ||
- If (and only if) primal values alias, then their tangents must also alias. | ||
|
||
### Example | ||
For example, consider the primal function with: | ||
1. takes two `Ref`s | ||
2. doubles the first one in place | ||
3. overwrites the second one's value with the literal 5.0 | ||
4. returns the first one | ||
|
||
|
||
```julia | ||
function foo!(a::Base.RefValue, b::Base.RefValue) | ||
a[] *= 2 | ||
b[] = 5.0 | ||
return a | ||
end | ||
``` | ||
|
||
The frule for this would be: | ||
```julia | ||
function ChainRulesCore.frule((_, ȧ, ḃ), ::typeof(foo!), a::Base.RefValue, b::Base.RefValue) | ||
@assert ȧ isa MutableTangent{typeof(a)} | ||
@assert ḃ isa MutableTangent{typeof(b)} | ||
|
||
a[] *= 2 | ||
ȧ.x *= 2 # `.x` is the field that lives behind RefValues | ||
|
||
b[] = 5.0 | ||
ḃ.x = zero_tangent(5.0) # or since we know that the zero for a Float64 is zero could write `ḃ.x = 0.0` | ||
|
||
return a, ȧ | ||
end | ||
``` | ||
|
||
Then assuming the AD system does its part to makes sure you are indeed given mutable values to mutate (i.e. those `@assert`ions are true) then all is well and this rule will make mutation correct. | ||
|
||
[^1]: | ||
Further, it is hard to achieve this promise of allowing mutation to be supported without returning a structural tangent. | ||
Except in the special case of where the struct is not mutable and has no nested fields that are mutable. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.