From 5c8e1231220940b3e06fdfa0dccce62217a66b93 Mon Sep 17 00:00:00 2001 From: Daniel Ingraham Date: Wed, 20 May 2026 15:41:16 -0400 Subject: [PATCH 1/5] Avoid `MArrays` with FiniteDiff backend --- .../ext/DifferentiationInterfaceFiniteDiffExt/onearg.jl | 4 ++-- .../ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/onearg.jl b/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/onearg.jl index 82b769ef6..4a3712c0f 100644 --- a/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/onearg.jl +++ b/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/onearg.jl @@ -14,7 +14,7 @@ function DI.prepare_pushforward_nokwarg( _sig = DI.signature(f, backend, x, tx, contexts...; strict) fc = DI.fix_tail(f, map(DI.unwrap, contexts)...) y = fc(x) - cache = if x isa Number || y isa Number + cache = if x isa Number || y isa Number || (! DI.ismutable_array(x)) || (! DI.ismutable_array(y)) nothing else JVPCache(similar(x), y, fdtype(backend)) @@ -130,7 +130,7 @@ function DI.prepare_derivative_nokwarg( _sig = DI.signature(f, backend, x, contexts...; strict) fc = DI.fix_tail(f, map(DI.unwrap, contexts)...) y = fc(x) - cache = if y isa Number + cache = if y isa Number || (! DI.ismutable_array(y)) nothing elseif y isa AbstractArray df = similar(y) diff --git a/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl b/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl index e30ba1ec7..90c789f81 100644 --- a/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl +++ b/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl @@ -18,7 +18,7 @@ function DI.prepare_pushforward_nokwarg( contexts::Vararg{DI.Context, C} ) where {C} _sig = DI.signature(f!, y, backend, x, tx, contexts...; strict) - cache = if x isa Number + cache = if x isa Number || (! DI.ismutable_array(x)) nothing else JVPCache(similar(x), similar(y), fdtype(backend)) From 5cc1b38639ea80bab726da06145266ae98a49ea2 Mon Sep 17 00:00:00 2001 From: Daniel Ingraham Date: Tue, 26 May 2026 14:56:07 -0400 Subject: [PATCH 2/5] Remove `ismutable_array` checks --- .../onearg.jl | 14 +++++++------- .../twoarg.jl | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/onearg.jl b/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/onearg.jl index 4a3712c0f..61e79aae2 100644 --- a/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/onearg.jl +++ b/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/onearg.jl @@ -14,10 +14,10 @@ function DI.prepare_pushforward_nokwarg( _sig = DI.signature(f, backend, x, tx, contexts...; strict) fc = DI.fix_tail(f, map(DI.unwrap, contexts)...) y = fc(x) - cache = if x isa Number || y isa Number || (! DI.ismutable_array(x)) || (! DI.ismutable_array(y)) + cache = if x isa Number || y isa Number nothing else - JVPCache(similar(x), y, fdtype(backend)) + JVPCache(copy(x), y, fdtype(backend)) end relstep = if isnothing(backend.relstep) default_relstep(fdtype(backend), eltype(x)) @@ -130,10 +130,10 @@ function DI.prepare_derivative_nokwarg( _sig = DI.signature(f, backend, x, contexts...; strict) fc = DI.fix_tail(f, map(DI.unwrap, contexts)...) y = fc(x) - cache = if y isa Number || (! DI.ismutable_array(y)) + cache = if y isa Number nothing elseif y isa AbstractArray - df = similar(y) + df = copy(y) cache = GradientCache(df, x, fdtype(backend), eltype(y), FUNCTION_NOT_INPLACE) end relstep = if isnothing(backend.relstep) @@ -347,9 +347,9 @@ function DI.prepare_jacobian_nokwarg( _sig = DI.signature(f, backend, x, contexts...; strict) fc = DI.fix_tail(f, map(DI.unwrap, contexts)...) y = fc(x) - x1 = similar(x) - fx = similar(y) - fx1 = similar(y) + x1 = copy(x) + fx = copy(y) + fx1 = copy(y) cache = JacobianCache(x1, fx, fx1, fdjtype(backend)) relstep = if isnothing(backend.relstep) default_relstep(fdjtype(backend), eltype(x)) diff --git a/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl b/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl index 90c789f81..adb64388f 100644 --- a/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl +++ b/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl @@ -18,10 +18,10 @@ function DI.prepare_pushforward_nokwarg( contexts::Vararg{DI.Context, C} ) where {C} _sig = DI.signature(f!, y, backend, x, tx, contexts...; strict) - cache = if x isa Number || (! DI.ismutable_array(x)) + cache = if x isa Number nothing else - JVPCache(similar(x), similar(y), fdtype(backend)) + JVPCache(copy(x), copy(y), fdtype(backend)) end relstep = if isnothing(backend.relstep) default_relstep(fdtype(backend), eltype(x)) From a946ff4cb63f1632defc6b122615796318663d15 Mon Sep 17 00:00:00 2001 From: Daniel Ingraham Date: Fri, 19 Jun 2026 07:08:31 -0400 Subject: [PATCH 3/5] Add simple allocation test for StaticArrays to FiniteDiff extension Also revert buggy switch from `copy` to `similar` in FiniteDiff `twoarg.jl` --- .../twoarg.jl | 2 +- .../test/Back/FiniteDiff/allocations.jl | 15 +++++++++++++++ .../test/Back/FiniteDiff/test.jl | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 DifferentiationInterface/test/Back/FiniteDiff/allocations.jl diff --git a/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl b/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl index adb64388f..e30ba1ec7 100644 --- a/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl +++ b/DifferentiationInterface/ext/DifferentiationInterfaceFiniteDiffExt/twoarg.jl @@ -21,7 +21,7 @@ function DI.prepare_pushforward_nokwarg( cache = if x isa Number nothing else - JVPCache(copy(x), copy(y), fdtype(backend)) + JVPCache(similar(x), similar(y), fdtype(backend)) end relstep = if isnothing(backend.relstep) default_relstep(fdtype(backend), eltype(x)) diff --git a/DifferentiationInterface/test/Back/FiniteDiff/allocations.jl b/DifferentiationInterface/test/Back/FiniteDiff/allocations.jl new file mode 100644 index 000000000..6681e755f --- /dev/null +++ b/DifferentiationInterface/test/Back/FiniteDiff/allocations.jl @@ -0,0 +1,15 @@ +using StaticArrays: @SVector + +@testset "allocations checks" begin + function doit() + backend = AutoFiniteDiff() + x = @SVector [1.0, 2.0] + tx = (2.0.*x,) + f(x) = @. 3.0 * x + prep = DifferentiationInterface.prepare_pushforward(f, backend, x, tx); + return prep + end + doit() + allocs = @allocated prep = doit() + @test allocs == 0 +end diff --git a/DifferentiationInterface/test/Back/FiniteDiff/test.jl b/DifferentiationInterface/test/Back/FiniteDiff/test.jl index d2a63f03e..670da5d46 100644 --- a/DifferentiationInterface/test/Back/FiniteDiff/test.jl +++ b/DifferentiationInterface/test/Back/FiniteDiff/test.jl @@ -113,3 +113,5 @@ end; end include("benchmark.jl") + +include("allocations.jl") From 12fb22662fb040b5195cb5f763eeaa5aa96ff723 Mon Sep 17 00:00:00 2001 From: Daniel Ingraham Date: Fri, 19 Jun 2026 11:31:15 -0400 Subject: [PATCH 4/5] Fix up formatting, more tests --- .../test/Back/FiniteDiff/Project.toml | 3 +- .../test/Back/FiniteDiff/allocations.jl | 35 ++++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/DifferentiationInterface/test/Back/FiniteDiff/Project.toml b/DifferentiationInterface/test/Back/FiniteDiff/Project.toml index eeeda8b24..ef07d9e78 100644 --- a/DifferentiationInterface/test/Back/FiniteDiff/Project.toml +++ b/DifferentiationInterface/test/Back/FiniteDiff/Project.toml @@ -8,7 +8,8 @@ ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" SparseConnectivityTracer = "9f842d2f-2579-4b1d-911e-f412cf18a3f5" SparseMatrixColorings = "0a514795-09f3-496d-8182-132a7b665d35" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [sources] -DifferentiationInterface = { path = "../../.." } +DifferentiationInterface = {path = "../../.."} diff --git a/DifferentiationInterface/test/Back/FiniteDiff/allocations.jl b/DifferentiationInterface/test/Back/FiniteDiff/allocations.jl index 6681e755f..275939c4f 100644 --- a/DifferentiationInterface/test/Back/FiniteDiff/allocations.jl +++ b/DifferentiationInterface/test/Back/FiniteDiff/allocations.jl @@ -1,15 +1,40 @@ using StaticArrays: @SVector @testset "allocations checks" begin - function doit() + function pushforward_allocs() backend = AutoFiniteDiff() x = @SVector [1.0, 2.0] - tx = (2.0.*x,) + tx = (2.0 .* x,) f(x) = @. 3.0 * x - prep = DifferentiationInterface.prepare_pushforward(f, backend, x, tx); + prep = DifferentiationInterface.prepare_pushforward(f, backend, x, tx) return prep end - doit() - allocs = @allocated prep = doit() + pushforward_allocs() + allocs = @allocated prep = pushforward_allocs() + # This needs https://github.com/JuliaDiff/FiniteDiff.jl/pull/216 to be released. + # Should be FiniteDiff v2.31.1. + @test_broken allocs == 0 + + function derivative_allocs() + backend = AutoFiniteDiff() + x = 3.0 + f(x) = x .* (@SVector [1.0, 2.0]) + prep = DifferentiationInterface.prepare_derivative(f, backend, x) + return prep + end + derivative_allocs() + allocs = @allocated prep = derivative_allocs() @test allocs == 0 + + function jacobian_allocs() + backend = AutoFiniteDiff() + x = @SVector [1.0, 2.0] + f(x) = 3.0 .* x + prep = DifferentiationInterface.prepare_jacobian(f, backend, x) + return prep + end + jacobian_allocs() + allocs = @allocated prep = jacobian_allocs() + # Using FiniteDiff.jl with StaticArrays to calculate a Jacobian does result in some allocations, apparently because the `FiniteDiff.JacobianCache` is a `mutable struct`. + @test_broken allocs == 0 end From 1bc5352ceb045ab0ce23465736bd79c4068124bd Mon Sep 17 00:00:00 2001 From: Daniel Ingraham Date: Fri, 19 Jun 2026 11:32:53 -0400 Subject: [PATCH 5/5] Ruinic... --- DifferentiationInterface/test/Back/FiniteDiff/allocations.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DifferentiationInterface/test/Back/FiniteDiff/allocations.jl b/DifferentiationInterface/test/Back/FiniteDiff/allocations.jl index 275939c4f..4215db157 100644 --- a/DifferentiationInterface/test/Back/FiniteDiff/allocations.jl +++ b/DifferentiationInterface/test/Back/FiniteDiff/allocations.jl @@ -19,7 +19,7 @@ using StaticArrays: @SVector backend = AutoFiniteDiff() x = 3.0 f(x) = x .* (@SVector [1.0, 2.0]) - prep = DifferentiationInterface.prepare_derivative(f, backend, x) + prep = DifferentiationInterface.prepare_derivative(f, backend, x) return prep end derivative_allocs() @@ -30,7 +30,7 @@ using StaticArrays: @SVector backend = AutoFiniteDiff() x = @SVector [1.0, 2.0] f(x) = 3.0 .* x - prep = DifferentiationInterface.prepare_jacobian(f, backend, x) + prep = DifferentiationInterface.prepare_jacobian(f, backend, x) return prep end jacobian_allocs()