diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 700707ced..4dae5f9d6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,3 +5,13 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" + - package-ecosystem: "julia" + directories: + - "/" + - "/docs" + schedule: + interval: "weekly" + groups: + all-julia-packages: + patterns: + - "*" diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index f2b96c5d9..416a68930 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -20,13 +20,13 @@ jobs: test: name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.allow-failure == true }} strategy: fail-fast: false matrix: version: - "lts" # Long-term support version - "1" # Latest Release - - "pre" # Pre-release/nightly os: - ubuntu-latest - macOS-latest @@ -35,8 +35,12 @@ jobs: - default include: - os: ubuntu-latest - version: "1" + version: "1" arch: x86 + - os: ubuntu-latest + version: "pre" + arch: default + allow-failure: true steps: - uses: actions/checkout@v7 - uses: julia-actions/setup-julia@v2 @@ -57,6 +61,7 @@ jobs: name: Documentation runs-on: ubuntu-latest permissions: + actions: write contents: write # Required when authenticating with `GITHUB_TOKEN`, not needed when authenticating with SSH deploy keys pull-requests: read # Required when using `push_preview=true` statuses: write # Optional, used to report documentation build statuses @@ -64,14 +69,10 @@ jobs: - uses: actions/checkout@v7 - uses: julia-actions/setup-julia@v2 with: - version: '1.10' + version: '1' - uses: julia-actions/cache@v3 - - run: | - julia --project=docs -e ' - using Pkg - Pkg.develop(PackageSpec(path=pwd())) - Pkg.instantiate() - include("docs/make.jl")' + - run: julia --project=docs -e 'using Pkg; Pkg.instantiate()' + - run: julia --project=docs docs/make.jl env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml deleted file mode 100644 index 804232605..000000000 --- a/.github/workflows/CompatHelper.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: CompatHelper -on: - schedule: - - cron: '0 0 * * *' # Everyday at midnight - workflow_dispatch: -jobs: - CompatHelper: - runs-on: ubuntu-latest - steps: - - name: Pkg.add("CompatHelper") - run: julia -e 'using Pkg; Pkg.add("CompatHelper")' - - name: CompatHelper.main() - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }} - run: julia -e 'using CompatHelper; CompatHelper.main(; subdirs = ["", "docs"])' diff --git a/.github/workflows/Downgrade.yml b/.github/workflows/Downgrade.yml index 725acdd8d..5a54b0fb1 100644 --- a/.github/workflows/Downgrade.yml +++ b/.github/workflows/Downgrade.yml @@ -10,27 +10,34 @@ on: - main paths-ignore: - 'docs/**' +concurrency: + # Skip intermediate builds: always. + # Cancel intermediate builds: only if it is a pull request build. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +# needed to allow julia-actions/cache to delete old caches that it has created +permissions: + actions: write + contents: read + jobs: test: runs-on: ubuntu-latest strategy: matrix: - group: - - Core downgrade_mode: ['alldeps'] - julia-version: ['1.10'] + julia-version: ['lts'] steps: - uses: actions/checkout@v7 - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.julia-version }} + - uses: julia-actions/cache@v3 - uses: julia-actions/julia-downgrade-compat@v2 -# if: ${{ matrix.version == '1.6' }} with: - skip: Pkg,TOML + mode: ${{ matrix.downgrade_mode }} - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 with: ALLOW_RERESOLVE: false - env: - GROUP: ${{ matrix.group }} diff --git a/.github/workflows/IntegrationTest.yml b/.github/workflows/IntegrationTest.yml index f3e26c4c4..a6fd0cb1f 100644 --- a/.github/workflows/IntegrationTest.yml +++ b/.github/workflows/IntegrationTest.yml @@ -11,6 +11,11 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} +# needed to allow julia-actions/cache to delete old caches that it has created +permissions: + actions: write + contents: read + jobs: test: name: ${{ matrix.package.name }} @@ -33,18 +38,12 @@ jobs: - {user: dfdx, name: Yota} - {user: JuliaStats, name: StatsFuns} - {user: JuliaStats, name: LogExpFunctions} - # Diffractor needs to run on Julia nightly - include: - - julia-version: nightly - os: ubuntu-latest - package: {user: JuliaDiff, name: Diffractor} steps: - uses: actions/checkout@v7 - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.julia-version }} - arch: x64 - uses: julia-actions/cache@v3 - uses: julia-actions/julia-buildpkg@v1 - name: Clone Downstream diff --git a/.github/workflows/JuliaNightly.yml b/.github/workflows/JuliaNightly.yml deleted file mode 100644 index e7817ee3e..000000000 --- a/.github/workflows/JuliaNightly.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: JuliaNightly -# Nightly Version of Julia. -# Runs on PRs and pushes to `master`, but seperate workflow to `CI` -# to avoid inclusion in nightly cron build with failure notifications. -on: - push: - branches: [main] - tags: ["*"] - pull_request: -concurrency: - # Skip intermediate builds: always. - # Cancel intermediate builds: only if it is a pull request build. - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} - -# needed to allow julia-actions/cache to delete old caches that it has created -permissions: - actions: write - contents: read - -jobs: - test: - name: Julia Nightly - Ubuntu - x64 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - uses: julia-actions/setup-julia@v2 - with: - version: nightly - - uses: julia-actions/cache@v3 - - uses: julia-actions/julia-buildpkg@v1 - - uses: julia-actions/julia-runtest@v1 - - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v6 - with: - files: lcov.info - token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: true \ No newline at end of file diff --git a/.github/workflows/SpellCheck.yml b/.github/workflows/SpellCheck.yml new file mode 100644 index 000000000..99782e94e --- /dev/null +++ b/.github/workflows/SpellCheck.yml @@ -0,0 +1,23 @@ +name: Spell Check + +on: + push: + branches: [main] + pull_request: + +concurrency: + # Skip intermediate builds: always. + # Cancel intermediate builds: only if it is a pull request build. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +permissions: + contents: read + +jobs: + typos: + name: Spell Check with Typos + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: crate-ci/typos@v1.51.1 diff --git a/README.md b/README.md index dbde80f15..333d02914 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ [![](https://img.shields.io/badge/docs-main-blue.svg)](https://juliadiff.org/ChainRulesCore.jl/dev) [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliadiff.org/ChainRulesCore.jl/stable) -| ⚠️ The ChainRules project is currently seeking a new primary maintainer ⚠️ | -|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| See this [Discourse thread](https://discourse.julialang.org/t/chainrules-project-looking-for-a-new-primary-maintainer/115636). We currently have many secondary maintainers and contributors with commit rights, but noone who has committed to leading the efforts. Until this is resolved PRs and issues may not recieve timely response. | +| ⚠️ The ChainRules project is currently seeking a new primary maintainer ⚠️ | +|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| See this [Discourse thread](https://discourse.julialang.org/t/chainrules-project-looking-for-a-new-primary-maintainer/115636). We currently have many secondary maintainers and contributors with commit rights, but no one who has committed to leading the efforts. Until this is resolved PRs and issues may not receive timely response. | The ChainRulesCore package provides a light-weight dependency for defining sensitivities for functions in your packages, without you needing to depend on ChainRules itself. diff --git a/docs/src/assets/make_logo.jl b/docs/src/assets/make_logo.jl index c023c308f..41b680344 100644 --- a/docs/src/assets/make_logo.jl +++ b/docs/src/assets/make_logo.jl @@ -1,5 +1,5 @@ using Pkg: @pkg_str -# For reproducability only dependency this has is Luxor, +# For reproducibility only dependency this has is Luxor, # and it was created with Luxor v1.6.0 pkg"add Luxor@v1.6" diff --git a/docs/src/rule_author/superpowers/opt_out.md b/docs/src/rule_author/superpowers/opt_out.md index 49b1dfe0e..f0a0b71d5 100644 --- a/docs/src/rule_author/superpowers/opt_out.md +++ b/docs/src/rule_author/superpowers/opt_out.md @@ -24,7 +24,7 @@ end That is a fairly reasonable `rrule` for the vast majority of cases. You might have a custom array type for which you could write a faster rule. In which case you would do that, by writing a faster, more specific, `rrule`. -But sometimes, it is the case that ADing the (faster, more specific) primal for your custom array type would yeild the faster pullback without you having to write a `rrule` by hand. +But sometimes, it is the case that ADing the (faster, more specific) primal for your custom array type would yield the faster pullback without you having to write a `rrule` by hand. Consider a summing [`SkewSymmetric` (anti-symmetric)](https://en.wikipedia.org/wiki/Skew-symmetric_matrix) matrix. The skew symmetric matrix has structural zeros on the diagonal, and off-diagonals are paired with their negation. diff --git a/docs/src/rule_author/tips_for_packages.md b/docs/src/rule_author/tips_for_packages.md index 5418ee76d..954314ee1 100644 --- a/docs/src/rule_author/tips_for_packages.md +++ b/docs/src/rule_author/tips_for_packages.md @@ -9,25 +9,25 @@ It captures the functionality of both `Zygote.ignore` and `Zygote.dropgrad`. For example, Zygote does not support mutation, so it will break if you try to store intermediate values as in the following example: ```julia -somes = [] +results = [] things = [] function loss(x, y) - some = f(x, y) + result = f(x, y) thing = g(x) # log - push!(somes, some) + push!(results, result) push!(things, thing) - return some + thing + return result + thing end ``` It is possible to get around this by using the `ignore_derivatives` function ```julia ignore_derivatives() do - push!(somes, some) + push!(results, result) push!(things, thing) end ``` diff --git a/docs/src/rule_author/writing_good_rules.md b/docs/src/rule_author/writing_good_rules.md index 5c1bf9340..a94c09378 100644 --- a/docs/src/rule_author/writing_good_rules.md +++ b/docs/src/rule_author/writing_good_rules.md @@ -173,7 +173,7 @@ They can be thought of as a wrapper of the value the computation returns. In this sense they wrap either a natural or structural tangent. !!! warning "You should support AbstractThunk inputs even if you don't use thunks" - Unfortunately the AD sytems do not know which rules support thunks and which do not. + Unfortunately the AD systems do not know which rules support thunks and which do not. So all rules have to; at least if they want to play nicely with arbitrary AD systems. Luckily it is not hard: much of the time they will duck-type as the object they wrap. If not, then just add a [`unthunk`](@ref) after the start of your pullback. @@ -181,7 +181,7 @@ In this sense they wrap either a natural or structural tangent. If you are using [`@thunk`](@ref) and the input is only needed for one of them then the `unthunk` should be in that one. If not, and you have a bunch of pullbacks you might like to write a little helper `unthunking(f) = x̄ -> f(unthunk(x̄))` that you can wrap your pullback function in before returning it from the `rrule`. Yes, this is a bit of boiler-plate, and it is unfortunate. - Sadly, it is needed because if the AD wants to benefit it can't get that benifit unless things are not unthunked unnecessarily. + Sadly, it is needed because if the AD wants to benefit it can't get that benefit unless things are not unthunked unnecessarily. Which eventually allows them in some cases to never be unthunked at all. There are two ways common things are never unthunked. One is if the unthunking happens inside a `@thunk` which is never unthunked itself because it is the tangent for a primal input that never has it's tangent queried. @@ -226,7 +226,7 @@ function ChainRulesCore.rrule(::typeof(double_it), x) return double_it(x), double_it_pullback end ``` -Ends up infering a return type of `Any` +Ends up inferring a return type of `Any` ```julia-repl julia> _, pullback = rrule(double_it, [2.0, 3.0]) ([4.0, 6.0], var"#double_it_pullback#8"(Core.Box(var"#double_it_pullback#8"(#= circular reference @-2 =#)))) diff --git a/src/accumulation.jl b/src/accumulation.jl index 26d0fbb27..093ab5361 100644 --- a/src/accumulation.jl +++ b/src/accumulation.jl @@ -93,8 +93,7 @@ function Base.showerror(io::IO, err::BadInplaceException) if err.accumuland == err.returned_value println( - io, - "Which in this case happenned to be equal. But they are not the same object.", + io, "Which in this case happened to be equal. But they are not the same object." ) end end diff --git a/src/projection.jl b/src/projection.jl index ba1696fd5..be8268b8a 100644 --- a/src/projection.jl +++ b/src/projection.jl @@ -183,7 +183,7 @@ end (::ProjectTo{T})(dx::Integer) where {T<:Complex{<:AbstractFloat}} = convert(T, dx) # Other numbers, including e.g. ForwardDiff.Dual and Symbolics.Sym, should pass through. -# We assume (lacking evidence to the contrary) that it is the right subspace of numebers. +# We assume (lacking evidence to the contrary) that it is the right subspace of numbers. (::ProjectTo{<:Number})(dx::Number) = dx (project::ProjectTo{<:Real})(dx::Complex) = project(real(dx)) @@ -275,7 +275,7 @@ end ##### # Ref -# Note that Ref is mutable. This causes Zygote to represent its structral tangent not as a NamedTuple, +# Note that Ref is mutable. This causes Zygote to represent its structural tangent not as a NamedTuple, # but as `Ref{Any}((x=val,))`. Here we use a Tangent, there is at present no mutable version, but see # https://github.com/JuliaDiff/ChainRulesCore.jl/issues/105 function ProjectTo(x::Ref) diff --git a/src/rule_definition_tools.jl b/src/rule_definition_tools.jl index c81eb3e62..f3e19cd6f 100644 --- a/src/rule_definition_tools.jl +++ b/src/rule_definition_tools.jl @@ -275,7 +275,7 @@ end """ _propagator_inputs(n) -Declares properly hygenic inputs for propagation expressions +Declares properly hygienic inputs for propagation expressions """ _propagator_inputs(n) = [esc(gensym(Symbol(:Δ, i))) for i in 1:n] @@ -487,7 +487,7 @@ end This allows you to opt-out of an `frule` or an `rrule` by providing a more specific method, that says to use the AD system to differentiate it. -For example, consider some function `foo(x::AbtractArray)`. +For example, consider some function `foo(x::AbstractArray)`. In general, you know an efficient and generic way to implement its `rrule`. You do so, (likely making use of [`ProjectTo`](@ref)). But it actually turns out that for some `FancyArray` type it is better to let the AD do its diff --git a/src/rules.jl b/src/rules.jl index 153a37b81..93985d4dd 100644 --- a/src/rules.jl +++ b/src/rules.jl @@ -45,7 +45,7 @@ julia> Δsincosx[2] == -sin(x) true ``` -Note that techically speaking julia does not have multiple output functions, just functions +Note that technically speaking julia does not have multiple output functions, just functions that return a single output that is iterable, like a `Tuple`. So this is actually a [`Tangent`](@ref): ```jldoctest frule @@ -149,7 +149,7 @@ end const NO_RRULE_DOC = """ no_rrule -This is an piece of infastructure supporting opting out of [`rrule`](@ref). +This is an piece of infrastructure supporting opting out of [`rrule`](@ref). It follows the signature for `rrule` exactly. A collection of type-tuples is stored in its method-table. If something has this defined, it means that it must having a must also have a `rrule`, diff --git a/src/tangent_arithmetic.jl b/src/tangent_arithmetic.jl index 9a93a67a8..269cb8e03 100644 --- a/src/tangent_arithmetic.jl +++ b/src/tangent_arithmetic.jl @@ -10,7 +10,7 @@ Notice: The precedence goes: `NotImplemented, NoTangent, ZeroTangent, AbstractThunk, Tangent, Any` Thus each of the @eval loops create most definitions of + and * - defines the combination this type with all types of lower precidence. + defines the combination this type with all types of lower precedence. This means each eval loops is 1 item smaller than the previous. ==# diff --git a/src/tangent_types/abstract_zero.jl b/src/tangent_types/abstract_zero.jl index c5260489e..cde5eeda9 100644 --- a/src/tangent_types/abstract_zero.jl +++ b/src/tangent_types/abstract_zero.jl @@ -106,9 +106,9 @@ and suitable for accumulating against. For types without a tangent space (e.g. singleton structs) this returns `NoTangent()`. In general, it is more likely to produce a structural tangent. -!!! warning "Exprimental" +!!! warning "Experimental" `zero_tangent`is an experimental feature, and is part of the mutation support featureset. - While this notice remains it may have changes in behavour, and interface in any _minor_ version of ChainRulesCore. + While this notice remains it may have changes in behaviour, and interface in any _minor_ version of ChainRulesCore. Exactly how it should be used (e.g. is it forward-mode only?) """ function zero_tangent end @@ -134,7 +134,7 @@ end zero_tangent(getfield(primal, $(QuoteNode(fname)))) else # This is going to be potentially bad, but that's what they get for not giving us a primal - # This will never me mutated inplace, rather it will alway be replaced with an actual value first + # This will never be mutated inplace, rather it will always be replaced with an actual value first ZeroTangent() end ) @@ -191,7 +191,7 @@ end guess_zero_tangent_type(T::Type) = Any guess_zero_tangent_type(::Type{Union{}}) = Union{} # This will only show up for empty containers -# Stuff that conceptually has its own identity regardless of structual implementation and doesn't have a tangent +# Stuff that conceptually has its own identity regardless of structural implementation and doesn't have a tangent zero_tangent(::Base.AbstractLogger) = NoTangent() # Prevent zero_tangent going wild on the internals diff --git a/src/tangent_types/structural_tangent.jl b/src/tangent_types/structural_tangent.jl index 05d90144d..94a0e4e48 100644 --- a/src/tangent_types/structural_tangent.jl +++ b/src/tangent_types/structural_tangent.jl @@ -4,12 +4,12 @@ Representing the type of the tangent of a `struct` `P` (or a `Tuple`/`NamedTuple`). as an object with mirroring fields. -!!! warning "Exprimental" +!!! warning "Experimental" `StructuralTangent` is an experimental feature, and is part of the mutation support featureset. The `StructuralTangent` constructor returns a `MutableTangent` for mutable structs. `MutableTangent` is an experimental feature. Thus use of `StructuralTangent` (rather than `Tangent` directly) is also experimental. - While this notice remains it may have changes in behavour, and interface in any _minor_ version of ChainRulesCore. + While this notice remains it may have changes in behaviour, and interface in any _minor_ version of ChainRulesCore. """ abstract type StructuralTangent{P} <: AbstractTangent end @@ -32,7 +32,7 @@ For `Tangent`s of `Tuple`s, `iterate` and `getindex` are overloaded to behave si to for a tuple. For `Tangent`s of `struct`s, `getproperty` is overloaded to allow for accessing values via `tangent.fieldname`. -Any fields not explictly present in the `Tangent` are treated as being set to `ZeroTangent()`. +Any fields not explicitly present in the `Tangent` are treated as being set to `ZeroTangent()`. To make a `Tangent` have all the fields of the primal the [`canonicalize`](@ref) function is provided. """ @@ -60,15 +60,15 @@ end This type represents the tangent to a mutable struct. It itself is also mutable. -!!! warning "Exprimental" +!!! warning "Experimental" MutableTangent is an experimental feature, and is part of the mutation support featureset. - While this notice remains it may have changes in behavour, and interface in any _minor_ version of ChainRulesCore. + While this notice remains it may have changes in behaviour, and interface in any _minor_ version of ChainRulesCore. Exactly how it should be used (e.g. is it forward-mode only?) !!! warning "Do not directly mess with the tangent backing data" It is relatively straight forward for a forwards-mode AD to work correctly in the presence of mutation and aliasing of primal values. However, this requires that the tangent is aliased in turn and conversely that it is copied when the primal is). - If you seperately alias the backing data, etc by using the internal `ChainRulesCore.backing` function you can break this. + If you separately alias the backing data, etc by using the internal `ChainRulesCore.backing` function you can break this. """ struct MutableTangent{P,F} <: StructuralTangent{P} backing::F @@ -127,7 +127,7 @@ Base.iszero(t::StructuralTangent) = all(iszero, backing(t)) function Base.map(f, tangent::StructuralTangent{P}) where {P} #TODO: is it even useful to support this on MutableTangents? - #TODO: we implictly assume only linear `f` are called and that it is safe to ignore noncanonical Zeros + #TODO: we implicitly assume only linear `f` are called and that it is safe to ignore noncanonical Zeros # This feels like a fair assumption since all normal operations on tangents are linear L = propertynames(backing(tangent)) vals = map(f, Tuple(backing(tangent))) @@ -185,7 +185,7 @@ backing(x::MutableTangent) = map(getindex, getfield(x, :backing)) # For generic structs function backing(x::T)::NamedTuple where {T} # note: all computation outside the if @generated happens at runtime. - # so the first 4 lines of the branchs look the same, but can not be moved out. + # so the first 4 lines of the branches look the same, but can not be moved out. # see https://github.com/JuliaLang/julia/issues/34283 if @generated !isstructtype(T) && @@ -223,7 +223,7 @@ This internally is called to construct structs of the primal type `T`, after an operation such as the addition of a primal to a tangent It should be overloaded, if `T` does not have a default constructor, -or if `T` needs to maintain some invarients between its fields. +or if `T` needs to maintain some invariants between its fields. """ function construct(::Type{T}, fields::NamedTuple{L}) where {T,L} # Tested and verified that that this avoids a ton of allocations @@ -246,7 +246,7 @@ construct(::Type{T}, fields::T) where {T<:Tuple} = fields elementwise_add(a::Tuple, b::Tuple) = map(+, a, b) function elementwise_add(a::NamedTuple{an}, b::NamedTuple{bn}) where {an,bn} - # Rule of Tangent addition: any fields not present are implict hard Zeros + # Rule of Tangent addition: any fields not present are implicit hard Zeros # Base on the `merge(:;NamedTuple, ::NamedTuple)` code from Base. # https://github.com/JuliaLang/julia/blob/592748adb25301a45bd6edef3ac0a93eed069852/base/namedtuple.jl#L220-L231 @@ -422,7 +422,7 @@ Base.conj(tangent::Tangent) = map(conj, tangent) Return the canonical `Tangent` for the primal type `P`. The property names of the returned `Tangent` match the field names of the primal, -and all fields of `P` not present in the input `tangent` are explictly set to `ZeroTangent()`. +and all fields of `P` not present in the input `tangent` are explicitly set to `ZeroTangent()`. """ function canonicalize(tangent::Tangent{P,<:NamedTuple{L}}) where {P,L} nil = _zeroed_backing(P) diff --git a/src/tangent_types/thunks.jl b/src/tangent_types/thunks.jl index 6f23ff782..cada27096 100644 --- a/src/tangent_types/thunks.jl +++ b/src/tangent_types/thunks.jl @@ -186,9 +186,9 @@ julia> unthunk(t) ``` ### When to `@thunk`? -When writing `rrule`s (and to a lesser exent `frule`s), it is important to `@thunk` +When writing `rrule`s (and to a lesser extent `frule`s), it is important to `@thunk` appropriately. -Propagation rules that return multiple derivatives may not have all deriviatives used. +Propagation rules that return multiple derivatives may not have all derivatives used. By `@thunk`ing the work required for each derivative, they then compute only what is needed. #### How do thunks prevent work? @@ -231,7 +231,7 @@ Base.convert(::Type{<:Thunk}, a::AbstractZero) = @thunk(a) A wrapper for a `Thunk`, that allows it to define an inplace `add!` function. `add!` should be defined such that: `ithunk.add!(Δ) = Δ .+= ithunk.val` -but it should do this more efficently than simply doing this directly. +but it should do this more efficiently than simply doing this directly. (Otherwise one can just use a normal `Thunk`). Most operations on an `InplaceableThunk` treat it just like a normal `Thunk`; diff --git a/test/config.jl b/test/config.jl index 58d943252..e0f7d24f6 100644 --- a/test/config.jl +++ b/test/config.jl @@ -45,7 +45,7 @@ end #define some functions for testing @testset "config.jl" begin - @testset "basic fall to two arg verion for $Config" for Config in ( + @testset "basic fall to two arg version for $Config" for Config in ( MostBoringConfig, MockForwardsConfig, MockReverseConfig, MockBothConfig ) counting_id_count = Ref(0) diff --git a/test/projection.jl b/test/projection.jl index 3d1e150bf..cf4ac3b17 100644 --- a/test/projection.jl +++ b/test/projection.jl @@ -458,7 +458,7 @@ struct NoSuperType end psymm = ProjectTo(Symmetric(rand(10^3, 10^3))) # The Union{Symmetric{…,Matrix}, Symmetric{…,ReshapedArray}} return value is only - # unboxed since JuliaLang/julia#55045 (sret_union ABI for pointer-ful types) + # unboxed since JuliaLang/julia#55045 (sret_union ABI for types containing pointers) @test 0 == @ballocated($psymm(dx), setup = (dx = Symmetric(rand(10^3, 10^3)))) broken = ( VERSION < v"1.14.0-DEV.1348" ) diff --git a/test/rule_definition_tools.jl b/test/rule_definition_tools.jl index bad5b5b3d..89ca372d3 100644 --- a/test/rule_definition_tools.jl +++ b/test/rule_definition_tools.jl @@ -143,7 +143,7 @@ end # https://github.com/JuliaDiff/ChainRulesCore.jl/issues/213 # problem was that `@nondiff Foo(x)` was also defining rules for other types. - # make sure that isn't happenning + # make sure that isn't happening @test frule((ZeroTangent(), 1.2), NonDiffCounterExample, 2.0) === nothing @test rrule(NonDiffCounterExample, 2.0) === nothing diff --git a/test/rules.jl b/test/rules.jl index 54c10b160..1eb71f4d7 100644 --- a/test/rules.jl +++ b/test/rules.jl @@ -43,10 +43,10 @@ function ChainRulesCore.frule( return type_constraints(x, y), Δx + Δy end -mixed_vararg_type_constaint(x::Float64, y::Real, z::Vararg{Float64}) = x + y + sum(z) +mixed_vararg_type_constraint(x::Float64, y::Real, z::Vararg{Float64}) = x + y + sum(z) function ChainRulesCore.frule( dargs::Tuple{Any,Float64,Real,Vararg{Float64}}, - ::typeof(mixed_vararg_type_constaint), + ::typeof(mixed_vararg_type_constraint), x::Float64, y::Real, z::Vararg{Float64}, @@ -107,13 +107,14 @@ _second(t) = Base.tuple_type_head(Base.tuple_type_tail(t)) @test( frule( - (nothing, 3.0, 2.0, 1.0, 0.0), mixed_vararg_type_constaint, 3.0, 2.0, 1.0, 0.0 + (nothing, 3.0, 2.0, 1.0, 0.0), mixed_vararg_type_constraint, 3.0, 2.0, 1.0, 0.0 ) == (6.0, 6.0) ) # violates type constraints, thus an frule should not be found. - @test frule((nothing, 3, 2.0, 1.0, 5.0), mixed_vararg_type_constaint, 3, 2.0, 1.0, 0) == - nothing + @test frule( + (nothing, 3, 2.0, 1.0, 5.0), mixed_vararg_type_constraint, 3, 2.0, 1.0, 0 + ) == nothing @test frule((nothing, nothing, 5.0), Core._apply, dummy_identity, 4.0) == (4.0, 5.0) diff --git a/test/tangent_types/abstract_zero.jl b/test/tangent_types/abstract_zero.jl index 85a9e1d07..51bd2d1e1 100644 --- a/test/tangent_types/abstract_zero.jl +++ b/test/tangent_types/abstract_zero.jl @@ -104,22 +104,22 @@ end @testset "NoTangent" begin - dne = NoTangent() - @test dne + dne == dne - @test dne + 1 == 1 - @test 1 + dne == 1 - @test dne - dne == dne - @test dne - 1 == -1 - @test 1 - dne == 1 - @test -dne == dne - @test dne * dne == dne - @test dne * 11.1 == dne - @test 12.1 * dne == dne - @test dot(dne, dne) == dne - @test dot(dne, 17.2) == dne - @test dot(11.9, dne) == dne - - @test eltype(dne) === NoTangent + no_tangent = NoTangent() + @test no_tangent + no_tangent == no_tangent + @test no_tangent + 1 == 1 + @test 1 + no_tangent == 1 + @test no_tangent - no_tangent == no_tangent + @test no_tangent - 1 == -1 + @test 1 - no_tangent == 1 + @test -no_tangent == no_tangent + @test no_tangent * no_tangent == no_tangent + @test no_tangent * 11.1 == no_tangent + @test 12.1 * no_tangent == no_tangent + @test dot(no_tangent, no_tangent) == no_tangent + @test dot(no_tangent, 17.2) == no_tangent + @test dot(11.9, no_tangent) == no_tangent + + @test eltype(no_tangent) === NoTangent @test eltype(NoTangent) === NoTangent @test promote_type(NoTangent, Bool) == Bool @@ -131,36 +131,36 @@ @test promote_type(NoTangent, ComplexF64) == ComplexF64 @test promote_type(ComplexF64, NoTangent) == ComplexF64 - @test ZeroTangent() + dne == dne - @test dne + ZeroTangent() == dne - @test ZeroTangent() - dne == dne - @test dne - ZeroTangent() == dne + @test ZeroTangent() + no_tangent == no_tangent + @test no_tangent + ZeroTangent() == no_tangent + @test ZeroTangent() - no_tangent == no_tangent + @test no_tangent - ZeroTangent() == no_tangent - @test ZeroTangent() * dne == ZeroTangent() - @test dne * ZeroTangent() == ZeroTangent() - @test dot(ZeroTangent(), dne) == ZeroTangent() - @test dot(dne, ZeroTangent()) == ZeroTangent() + @test ZeroTangent() * no_tangent == ZeroTangent() + @test no_tangent * ZeroTangent() == ZeroTangent() + @test dot(ZeroTangent(), no_tangent) == ZeroTangent() + @test dot(no_tangent, ZeroTangent()) == ZeroTangent() @test norm(ZeroTangent()) == 0 @test norm(ZeroTangent(), 0.4) == 0 - for x in dne - @test x === dne + for x in no_tangent + @test x === no_tangent end - @test broadcastable(dne) isa Ref{NoTangent} + @test broadcastable(no_tangent) isa Ref{NoTangent} for f in (transpose, adjoint, conj) - @test f(dne) === dne + @test f(no_tangent) === no_tangent end - @test dne / 2 === dne / [1, 3] === dne + @test no_tangent / 2 === no_tangent / [1, 3] === no_tangent @test convert(Int64, NoTangent()) == 0 @test convert(Float64, NoTangent()) == 0.0 - @test dne[1] === dne - @test dne[1:3] === dne - @test dne[1, 2] === dne - @test getindex(dne) === dne - @test dne.foo === dne + @test no_tangent[1] === no_tangent + @test no_tangent[1:3] === no_tangent + @test no_tangent[1, 2] === no_tangent + @test getindex(no_tangent) === no_tangent + @test no_tangent.foo === no_tangent end @testset "ambiguities" begin @@ -228,7 +228,7 @@ end end @testset "Weird types" begin - @test iszero(zero_tangent(typeof(Int))) # primative type + @test iszero(zero_tangent(typeof(Int))) # primitive type @test iszero(zero_tangent(typeof(Base.RefValue))) # struct @test iszero(zero_tangent(Vector)) # UnionAll @test iszero(zero_tangent(Union{Int, Float64})) # Union diff --git a/test/tangent_types/structural_tangent.jl b/test/tangent_types/structural_tangent.jl index 0972e1dce..c0b26217e 100644 --- a/test/tangent_types/structural_tangent.jl +++ b/test/tangent_types/structural_tangent.jl @@ -14,7 +14,7 @@ struct Bar x::Float64 end -# For testing Tangent: it is an invarient of the type that x2 = 2x +# For testing Tangent: it is an invariant of the type that x2 = 2x # so simple addition can not be defined struct StructWithInvariant x @@ -306,8 +306,8 @@ end ChainRulesCore.debug_mode() = false # disable it again end - # Now we define constuction for ChainRulesCore.jl's purposes: - # It is going to determine the root quanity of the invarient + # Now we define construction for ChainRulesCore.jl's purposes: + # It is going to determine the root quantity of the invariant function ChainRulesCore.construct(::Type{StructWithInvariant}, nt::NamedTuple) x = (nt.x + nt.x2 / 2) / 2 return StructWithInvariant(x) @@ -407,7 +407,7 @@ end @testset "show" begin @test repr(Tangent{Foo}(; x=1)) == "Tangent{Foo}(x = 1,)" - # check for exact regex match not occurence( `^...$`) + # check for exact regex match not occurrence( `^...$`) # and allowing optional whitespace (`\s?`) @test occursin( r"^Tangent{Tuple{Int64,\s?Int64}}\(1,\s?2\)$", @@ -423,7 +423,7 @@ end end @testset "internals" begin - @testset "Can't do backing on primative type" begin + @testset "Can't do backing on primitive type" begin @test_throws Exception ChainRulesCore.backing(1.4) end diff --git a/test/tangent_types/thunks.jl b/test/tangent_types/thunks.jl index f9c5801fb..cca5df782 100644 --- a/test/tangent_types/thunks.jl +++ b/test/tangent_types/thunks.jl @@ -39,7 +39,7 @@ end @testset "erroring thunks should include the source in the backtrack" begin - expected_line = (@__LINE__) + 2 # for testing it is at right palce + expected_line = (@__LINE__) + 2 # for testing it is at right place try x = @thunk(error()) unthunk(x) @@ -156,7 +156,7 @@ @test diagm(0 => v) == diagm(0 => tv) @test diagm(3, 4, 0 => v) == diagm(3, 4, 0 => tv) - # Check against accidential type piracy + # Check against accidental type piracy # https://github.com/JuliaDiff/ChainRulesCore.jl/issues/472 @test Base.which(diagm, Tuple{}()).module != ChainRulesCore @test Base.which(diagm, Tuple{Int,Int}).module != ChainRulesCore