diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d60f0707..a1b6231d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,3 +5,15 @@ updates: directory: "/" # Location of package manifests schedule: interval: "monthly" + - package-ecosystem: "julia" + directories: # Location of Julia projects + - "/" + schedule: + interval: "daily" + groups: + # Group all Julia package updates into a single PR: + all-julia-packages: + patterns: + - "*" + ignore: + - dependency-name: "ReverseDiff" diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml deleted file mode 100644 index 535861c7..00000000 --- a/.github/workflows/CompatHelper.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: CompatHelper -on: - schedule: - - cron: 0 0 * * * - workflow_dispatch: -permissions: - contents: write - pull-requests: write -jobs: - CompatHelper: - runs-on: ubuntu-latest - steps: - - name: Check if Julia is already available in the PATH - id: julia_in_path - run: which julia - continue-on-error: true - - name: Install Julia, but only if it is not already available in the PATH - uses: julia-actions/setup-julia@v3 - with: - version: '1' - arch: ${{ runner.arch }} - if: steps.julia_in_path.outcome != 'success' - - name: "Add the General registry via Git" - run: | - import Pkg - ENV["JULIA_PKG_SERVER"] = "" - Pkg.Registry.add("General") - shell: julia --color=yes {0} - - name: "Install CompatHelper" - run: | - import Pkg - name = "CompatHelper" - uuid = "aa819f21-2bde-4658-8897-bab36330d9b7" - version = "3" - Pkg.add(; name, uuid, version) - shell: julia --color=yes {0} - - name: "Run CompatHelper" - run: | - import CompatHelper - CompatHelper.main(; subdirs = ["", "docs"]) - shell: julia --color=yes {0} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/Downgrade.yml b/.github/workflows/Downgrade.yml new file mode 100644 index 00000000..9ccbd196 --- /dev/null +++ b/.github/workflows/Downgrade.yml @@ -0,0 +1,56 @@ +name: Downgrade + +on: + pull_request: + branches: + - master + push: + branches: + - master + workflow_dispatch: + +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/') }} + +jobs: + test: + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ github.event_name }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + version: + - '1' + os: + - ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: julia-actions/setup-julia@v3 + with: + version: ${{ matrix.version }} + - uses: julia-actions/cache@v3 + - uses: julia-actions/julia-downgrade-compat@v2 + with: + projects: ".,test" + skip: LinearAlgebra,Random,Statistics,Test + name: Downgrade dependencies to oldest supported versions + - uses: julia-actions/julia-buildpkg@v1 + with: + project: "test" + - uses: julia-actions/julia-runtest@v1 + with: + coverage: true + allow_reresolve: false + force_latest_compatible_version: false + env: + # `julia-downgrade-compat` promotes weakdeps to deps, so extensions always load + DOWNGRADE_TEST: "true" + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v7 + with: + files: lcov.info + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8381f79..1ad1ff41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: fail-fast: false matrix: version: - - 'min' + - 'min-patch' - 'lts' - '1' os: diff --git a/Project.toml b/Project.toml index 2ac8d0de..596d5dd1 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "ReverseDiff" uuid = "37e2e3b7-166d-5795-8a7a-e32c996b4267" -version = "1.17.3" +version = "1.18.0-dev" [deps] ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" @@ -15,31 +15,28 @@ NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + +[weakdeps] Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +[extensions] +StatisticsExt = "Statistics" + [compat] ChainRulesCore = "1" DiffResults = "1" DiffRules = "1.4" -DiffTests = "< 0.1.2" -ForwardDiff = "0.10, 1" -FunctionWrappers = "1" -IrrationalConstants = "0.2" -LinearAlgebra = "<0.0.1, 1" -LogExpFunctions = "0.3, 1" -MacroTools = "0.5" -NaNMath = "0.3, 1" -Random = "<0.0.1, 1" -SpecialFunctions = "0.8, 0.9, 0.10, 1.0, 2" -StaticArrays = "0.10, 0.11, 0.12, 1.0" -Statistics = "<0.0.1, 1" -julia = "1" - -[extras] -DiffTests = "de460e47-3fe3-5279-bb4a-814414816d5d" -FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" -IrrationalConstants = "92d709cd-6900-40b7-9082-c6be49f344b6" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +ForwardDiff = "1" +FunctionWrappers = "1.1.2" +LinearAlgebra = "1" +LogExpFunctions = "1" +MacroTools = "0.5.16" +NaNMath = "1" +Random = "1" +SpecialFunctions = "2" +StaticArrays = "1.6.4" +Statistics = "1" +julia = "1.10" -[targets] -test = ["DiffTests", "FillArrays", "IrrationalConstants", "Test"] +[workspace] +projects = ["test", "docs"] diff --git a/docs/Project.toml b/docs/Project.toml index 18704e95..4b8c876b 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -4,7 +4,6 @@ ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" [compat] Documenter = "1" -ReverseDiff = "1" [sources] ReverseDiff = { path = ".." } \ No newline at end of file diff --git a/ext/StatisticsExt.jl b/ext/StatisticsExt.jl new file mode 100644 index 00000000..727b9a6c --- /dev/null +++ b/ext/StatisticsExt.jl @@ -0,0 +1,28 @@ +module StatisticsExt + +using ReverseDiff: ReverseDiff, SpecialInstruction, TrackedArray, deriv, increment_deriv!, + istracked, record!, tape, track, unseed!, value, value! +using Statistics: Statistics, mean + +function Statistics.mean(x::TrackedArray{V,D}) where {V,D} + tp = tape(x) + out = track(mean(value(x)), D, tp) + record!(tp, SpecialInstruction, mean, x, out) + return out +end + +@noinline function ReverseDiff.special_reverse_exec!(instruction::SpecialInstruction{typeof(mean)}) + input = instruction.input + output = instruction.output + istracked(input) && increment_deriv!(input, inv(length(input)) * deriv(output)) + unseed!(output) + return nothing +end + +@noinline function ReverseDiff.special_forward_exec!(instruction::SpecialInstruction{typeof(mean)}) + input = instruction.input + value!(instruction.output, mean(value(input))) + return nothing +end + +end # module diff --git a/src/ReverseDiff.jl b/src/ReverseDiff.jl index 0c99f069..011a026f 100644 --- a/src/ReverseDiff.jl +++ b/src/ReverseDiff.jl @@ -3,7 +3,6 @@ module ReverseDiff using Base: RefValue using Random using LinearAlgebra -using Statistics using FunctionWrappers: FunctionWrapper diff --git a/src/derivatives/linalg/reductions.jl b/src/derivatives/linalg/reductions.jl index 0887a045..dbdb5ca3 100644 --- a/src/derivatives/linalg/reductions.jl +++ b/src/derivatives/linalg/reductions.jl @@ -59,31 +59,6 @@ end return nothing end -######## -# mean # -######## - -function Statistics.mean(x::TrackedArray{V,D}) where {V,D} - tp = tape(x) - out = track(mean(value(x)), D, tp) - record!(tp, SpecialInstruction, mean, x, out) - return out -end - -@noinline function special_reverse_exec!(instruction::SpecialInstruction{typeof(mean)}) - input = instruction.input - output = instruction.output - istracked(input) && increment_deriv!(input, inv(length(input)) * deriv(output)) - unseed!(output) - return nothing -end - -@noinline function special_forward_exec!(instruction::SpecialInstruction{typeof(mean)}) - input = instruction.input - value!(instruction.output, mean(value(input))) - return nothing -end - ####### # dot # ####### diff --git a/src/tracked.jl b/src/tracked.jl index f619c091..81ea7b5d 100644 --- a/src/tracked.jl +++ b/src/tracked.jl @@ -489,11 +489,7 @@ Base.fld(a::TrackedReal, b::TrackedReal) = fld(value(a), value(b)) Base.cld(a::TrackedReal, b::TrackedReal) = cld(value(a), value(b)) -if VERSION ≥ v"1.4" - Base.div(x::TrackedReal, y::TrackedReal, r::RoundingMode) = div(value(x), value(y), r) -else - Base.div(x::TrackedReal, y::TrackedReal) = div(value(x), value(y)) -end +Base.div(x::TrackedReal, y::TrackedReal, r::RoundingMode) = div(value(x), value(y), r) Base.trunc(t::TrackedReal) = trunc(value(t)) Base.trunc(::Type{R}, t::TrackedReal) where {R<:Real} = trunc(R, value(t)) diff --git a/test/Project.toml b/test/Project.toml new file mode 100644 index 00000000..33298a9e --- /dev/null +++ b/test/Project.toml @@ -0,0 +1,37 @@ +[deps] +ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" +DiffResults = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" +DiffRules = "b552c78f-8df3-52c6-915a-8e097449b14b" +DiffTests = "de460e47-3fe3-5279-bb4a-814414816d5d" +FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" +ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" +IrrationalConstants = "92d709cd-6900-40b7-9082-c6be49f344b6" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +LogExpFunctions = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" +SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +ChainRulesCore = "1" +DiffResults = "1" +DiffRules = "1.4" +DiffTests = "< 0.1.2" +FillArrays = "1" +ForwardDiff = "1" +IrrationalConstants = "0.2" +LinearAlgebra = "1" +LogExpFunctions = "1" +NaNMath = "1" +Random = "1" +SpecialFunctions = "2" +StaticArrays = "1.6.4" +Statistics = "1" +Test = "1" + +[sources] +ReverseDiff = { path = ".." } \ No newline at end of file diff --git a/test/TrackedTests.jl b/test/TrackedTests.jl index 59cce2f1..c3c34eb5 100644 --- a/test/TrackedTests.jl +++ b/test/TrackedTests.jl @@ -822,12 +822,10 @@ tr_rand = rand(MersenneTwister(1), TrackedReal{Int,Float64,Nothing}) @test div(v_float, tr_float2) === div(v_float, v_float2) @test div(tr_float, v_float2) === div(v_float, v_float2) -if VERSION ≥ v"1.4" - for r in (RoundUp, RoundDown) - @test div(tr_float, tr_float2, r) === div(v_float, v_float2, r) - @test div(v_float, tr_float2, r) === div(v_float, v_float2, r) - @test div(tr_float, v_float2, r) === div(v_float, v_float2, r) - end +for r in (RoundUp, RoundDown) + @test div(tr_float, tr_float2, r) === div(v_float, v_float2, r) + @test div(v_float, tr_float2, r) === div(v_float, v_float2, r) + @test div(tr_float, v_float2, r) === div(v_float, v_float2, r) end @test trunc(tr_float) === trunc(v_float) diff --git a/test/derivatives/ArrayFunctionTests.jl b/test/derivatives/ArrayFunctionTests.jl index ad86baaf..3bae169b 100644 --- a/test/derivatives/ArrayFunctionTests.jl +++ b/test/derivatives/ArrayFunctionTests.jl @@ -16,10 +16,9 @@ end @test any(iszero, track([ones(2); 0.0])) end -# SparseArrays >= 1.10 pirates `hcat`/`vcat` for `Union{AbstractVecOrMat{<:Number},Number}`, +# SparseArrays pirates `hcat`/`vcat` for `Union{AbstractVecOrMat{<:Number},Number}`, # which is ambiguous with the methods defined for `TrackedArray`. -const SPARSE_CAT_AMBIGUITY = - VERSION >= v"1.10" && any(k -> k.name == "SparseArrays", keys(Base.loaded_modules)) +const SPARSE_CAT_AMBIGUITY = any(k -> k.name == "SparseArrays", keys(Base.loaded_modules)) function testcat(f, args::Tuple, type, kwargs=NamedTuple()) x = f(track.(args)...; kwargs...) diff --git a/test/derivatives/LinAlgTests.jl b/test/derivatives/LinAlgTests.jl index 8c4c9fdb..dd53bdfa 100644 --- a/test/derivatives/LinAlgTests.jl +++ b/test/derivatives/LinAlgTests.jl @@ -1,8 +1,16 @@ module LinAlgTests -using ReverseDiff, ForwardDiff, Test, LinearAlgebra, Statistics +using ReverseDiff, ForwardDiff, Test, LinearAlgebra -include(joinpath(dirname(@__FILE__), "../utils.jl")) +if get(ENV, "DOWNGRADE_TEST", "false")::String != "true" + @test Base.get_extension(ReverseDiff, :StatisticsExt) === nothing +end + +using Statistics + +@test Base.get_extension(ReverseDiff, :StatisticsExt) !== nothing + +include("../utils.jl") x, a, b = rand(3, 3), rand(3, 3), rand(3, 3) tp = InstructionTape()