API
DifferentiationInterface — ModuleDifferentiationInterfaceAn interface to various automatic differentiation backends in Julia.
Argument wrappers
DifferentiationInterface.Context — TypeContextAbstract supertype for additional context arguments, which can be passed to differentiation operators after the active input x but are not differentiated.
Subtypes
DifferentiationInterface.Constant — TypeConstantConcrete type of Context argument which is kept constant during differentiation.
Note that an operator can be prepared with an arbitrary value of the constant. However, same-point preparation must occur with the exact value that will be reused later.
Example
julia> using DifferentiationInterface
julia> using ForwardDiff: ForwardDiff
julia> f(x, c) = c * sum(abs2, x);
julia> gradient(f, AutoForwardDiff(), [1.0, 2.0], Constant(10))
2-element Vector{Float64}:
20.0
40.0
julia> gradient(f, AutoForwardDiff(), [1.0, 2.0], Constant(100))
2-element Vector{Float64}:
200.0
400.0DifferentiationInterface.Cache — TypeCacheConcrete type of Context argument which can be mutated with active values during differentiation.
The initial values present inside the cache do not matter.
For some backends, preparation allocates the required memory for Cache contexts with the right element type, similar to PreallocationTools.jl.
Some backends require any Cache context to be an AbstractArray, others accept nested (named) tuples of AbstractArrays.
Example
julia> using DifferentiationInterface
julia> using ForwardDiff: ForwardDiff
julia> f(x, c) = sum(copyto!(c, x));
julia> prep = prepare_gradient(f, AutoForwardDiff(), [1.0, 2.0], Cache(zeros(2)));
julia> gradient(f, prep, AutoForwardDiff(), [3.0, 4.0], Cache(zeros(2)))
2-element Vector{Float64}:
1.0
1.0DifferentiationInterface.ConstantOrCache — TypeConstantOrCacheConcrete type of Context argument which can contain a mixture of constants and caches, passed along to the backend without modification.
Unlike for Cache, it is up to the user to ensure that the internal storage can adapt to the required element types, for instance by using PreallocationTools.jl directly.
First order
Pushforward
DifferentiationInterface.prepare_pushforward — Functionprepare_pushforward(f, backend, x, tx, [contexts...]; strict=Val(true)) -> prep
prepare_pushforward(f!, y, backend, x, tx, [contexts...]; strict=Val(true)) -> prepCreate a prep object that can be given to pushforward and its variants to speed them up.
Depending on the backend, this can have several effects (preallocating memory, recording an execution trace) which are transparent to the user.
For in-place functions, y is mutated by f! during preparation.
The preparation result prep is only reusable as long as the arguments to pushforward do not change type or size, and the function and backend themselves are not modified. Otherwise, preparation becomes invalid and you need to run it again. In some settings, invalid preparations may still give correct results (e.g. for backends that require no preparation), but this is not a semantic guarantee and should not be relied upon.
The preparation result prep is not thread-safe. Sharing it between threads may lead to unexpected behavior. If you need to run differentiation concurrently, prepare separate prep objects for each thread.
When strict=Val(true) (the default), type checking is enforced between preparation and execution (but size checking is left to the user). While your code may work for different types by setting strict=Val(false), this is not guaranteed by the API and can break without warning.
DifferentiationInterface.prepare_pushforward_same_point — Functionprepare_pushforward_same_point(f, backend, x, tx, [contexts...]; strict=Val(true)) -> prep_same
prepare_pushforward_same_point(f!, y, backend, x, tx, [contexts...]; strict=Val(true)) -> prep_sameCreate a prep object that can be given to pushforward and its variants to speed them up, if they are applied at the same point x and with the same contexts.
Depending on the backend, this can have several effects (preallocating memory, recording an execution trace) which are transparent to the user.
For in-place functions, y is mutated by f! during preparation.
The preparation result prep is only reusable as long as the arguments to pushforward do not change type or size, and the function and backend themselves are not modified. Otherwise, preparation becomes invalid and you need to run it again. In some settings, invalid preparations may still give correct results (e.g. for backends that require no preparation), but this is not a semantic guarantee and should not be relied upon.
The preparation result prep is not thread-safe. Sharing it between threads may lead to unexpected behavior. If you need to run differentiation concurrently, prepare separate prep objects for each thread.
When strict=Val(true) (the default), type checking is enforced between preparation and execution (but size checking is left to the user). While your code may work for different types by setting strict=Val(false), this is not guaranteed by the API and can break without warning.
DifferentiationInterface.pushforward — Functionpushforward(f, [prep,] backend, x, tx, [contexts...]) -> ty
pushforward(f!, y, [prep,] backend, x, tx, [contexts...]) -> tyCompute the pushforward of the function f at point x with a tuple of tangents tx.
To improve performance via operator preparation, refer to prepare_pushforward and prepare_pushforward_same_point.
DifferentiationInterface.pushforward! — Functionpushforward!(f, dy, [prep,] backend, x, tx, [contexts...]) -> ty
pushforward!(f!, y, dy, [prep,] backend, x, tx, [contexts...]) -> tyCompute the pushforward of the function f at point x with a tuple of tangents tx, overwriting ty.
To improve performance via operator preparation, refer to prepare_pushforward and prepare_pushforward_same_point.
DifferentiationInterface.value_and_pushforward — Functionvalue_and_pushforward(f, [prep,] backend, x, tx, [contexts...]) -> (y, ty)
value_and_pushforward(f!, y, [prep,] backend, x, tx, [contexts...]) -> (y, ty)Compute the value and the pushforward of the function f at point x with a tuple of tangents tx.
To improve performance via operator preparation, refer to prepare_pushforward and prepare_pushforward_same_point.
DifferentiationInterface.value_and_pushforward! — Functionvalue_and_pushforward!(f, dy, [prep,] backend, x, tx, [contexts...]) -> (y, ty)
value_and_pushforward!(f!, y, dy, [prep,] backend, x, tx, [contexts...]) -> (y, ty)Compute the value and the pushforward of the function f at point x with a tuple of tangents tx, overwriting ty.
To improve performance via operator preparation, refer to prepare_pushforward and prepare_pushforward_same_point.
Pullback
DifferentiationInterface.prepare_pullback — Functionprepare_pullback(f, backend, x, ty, [contexts...]; strict=Val(true)) -> prep
prepare_pullback(f!, y, backend, x, ty, [contexts...]; strict=Val(true)) -> prepCreate a prep object that can be given to pullback and its variants to speed them up.
Depending on the backend, this can have several effects (preallocating memory, recording an execution trace) which are transparent to the user.
For in-place functions, y is mutated by f! during preparation.
The preparation result prep is only reusable as long as the arguments to pullback do not change type or size, and the function and backend themselves are not modified. Otherwise, preparation becomes invalid and you need to run it again. In some settings, invalid preparations may still give correct results (e.g. for backends that require no preparation), but this is not a semantic guarantee and should not be relied upon.
The preparation result prep is not thread-safe. Sharing it between threads may lead to unexpected behavior. If you need to run differentiation concurrently, prepare separate prep objects for each thread.
When strict=Val(true) (the default), type checking is enforced between preparation and execution (but size checking is left to the user). While your code may work for different types by setting strict=Val(false), this is not guaranteed by the API and can break without warning.
DifferentiationInterface.prepare_pullback_same_point — Functionprepare_pullback_same_point(f, backend, x, ty, [contexts...]; strict=Val(true)) -> prep_same
prepare_pullback_same_point(f!, y, backend, x, ty, [contexts...]; strict=Val(true)) -> prep_sameCreate a prep object that can be given to pullback and its variants to speed them up, if they are applied at the same point x and with the same contexts.
Depending on the backend, this can have several effects (preallocating memory, recording an execution trace) which are transparent to the user.
For in-place functions, y is mutated by f! during preparation.
The preparation result prep is only reusable as long as the arguments to pullback do not change type or size, and the function and backend themselves are not modified. Otherwise, preparation becomes invalid and you need to run it again. In some settings, invalid preparations may still give correct results (e.g. for backends that require no preparation), but this is not a semantic guarantee and should not be relied upon.
The preparation result prep is not thread-safe. Sharing it between threads may lead to unexpected behavior. If you need to run differentiation concurrently, prepare separate prep objects for each thread.
When strict=Val(true) (the default), type checking is enforced between preparation and execution (but size checking is left to the user). While your code may work for different types by setting strict=Val(false), this is not guaranteed by the API and can break without warning.
DifferentiationInterface.pullback — Functionpullback(f, [prep,] backend, x, ty, [contexts...]) -> tx
pullback(f!, y, [prep,] backend, x, ty, [contexts...]) -> txCompute the pullback of the function f at point x with a tuple of tangents ty.
To improve performance via operator preparation, refer to prepare_pullback and prepare_pullback_same_point.
DifferentiationInterface.pullback! — Functionpullback!(f, dx, [prep,] backend, x, ty, [contexts...]) -> tx
pullback!(f!, y, dx, [prep,] backend, x, ty, [contexts...]) -> txCompute the pullback of the function f at point x with a tuple of tangents ty, overwriting dx.
To improve performance via operator preparation, refer to prepare_pullback and prepare_pullback_same_point.
DifferentiationInterface.value_and_pullback — Functionvalue_and_pullback(f, [prep,] backend, x, ty, [contexts...]) -> (y, tx)
value_and_pullback(f!, y, [prep,] backend, x, ty, [contexts...]) -> (y, tx)Compute the value and the pullback of the function f at point x with a tuple of tangents ty.
To improve performance via operator preparation, refer to prepare_pullback and prepare_pullback_same_point.
DifferentiationInterface.value_and_pullback! — Functionvalue_and_pullback!(f, dx, [prep,] backend, x, ty, [contexts...]) -> (y, tx)
value_and_pullback!(f!, y, dx, [prep,] backend, x, ty, [contexts...]) -> (y, tx)Compute the value and the pullback of the function f at point x with a tuple of tangents ty, overwriting dx.
To improve performance via operator preparation, refer to prepare_pullback and prepare_pullback_same_point.
Derivative
DifferentiationInterface.prepare_derivative — Functionprepare_derivative(f, backend, x, [contexts...]; strict=Val(true)) -> prep
prepare_derivative(f!, y, backend, x, [contexts...]; strict=Val(true)) -> prepCreate a prep object that can be given to derivative and its variants to speed them up.
Depending on the backend, this can have several effects (preallocating memory, recording an execution trace) which are transparent to the user.
For in-place functions, y is mutated by f! during preparation.
The preparation result prep is only reusable as long as the arguments to derivative do not change type or size, and the function and backend themselves are not modified. Otherwise, preparation becomes invalid and you need to run it again. In some settings, invalid preparations may still give correct results (e.g. for backends that require no preparation), but this is not a semantic guarantee and should not be relied upon.
The preparation result prep is not thread-safe. Sharing it between threads may lead to unexpected behavior. If you need to run differentiation concurrently, prepare separate prep objects for each thread.
When strict=Val(true) (the default), type checking is enforced between preparation and execution (but size checking is left to the user). While your code may work for different types by setting strict=Val(false), this is not guaranteed by the API and can break without warning.
DifferentiationInterface.derivative — Functionderivative(f, [prep,] backend, x, [contexts...]) -> der
derivative(f!, y, [prep,] backend, x, [contexts...]) -> derCompute the derivative of the function f at point x.
To improve performance via operator preparation, refer to prepare_derivative.
DifferentiationInterface.derivative! — Functionderivative!(f, der, [prep,] backend, x, [contexts...]) -> der
derivative!(f!, y, der, [prep,] backend, x, [contexts...]) -> derCompute the derivative of the function f at point x, overwriting der.
To improve performance via operator preparation, refer to prepare_derivative.
DifferentiationInterface.value_and_derivative — Functionvalue_and_derivative(f, [prep,] backend, x, [contexts...]) -> (y, der)
value_and_derivative(f!, y, [prep,] backend, x, [contexts...]) -> (y, der)Compute the value and the derivative of the function f at point x.
To improve performance via operator preparation, refer to prepare_derivative.
DifferentiationInterface.value_and_derivative! — Functionvalue_and_derivative!(f, der, [prep,] backend, x, [contexts...]) -> (y, der)
value_and_derivative!(f!, y, der, [prep,] backend, x, [contexts...]) -> (y, der)Compute the value and the derivative of the function f at point x, overwriting der.
To improve performance via operator preparation, refer to prepare_derivative.
Gradient
DifferentiationInterface.prepare_gradient — Functionprepare_gradient(f, backend, x, [contexts...]; strict=Val(true)) -> prepCreate a prep object that can be given to gradient and its variants to speed them up.
Depending on the backend, this can have several effects (preallocating memory, recording an execution trace) which are transparent to the user.
The preparation result prep is only reusable as long as the arguments to gradient do not change type or size, and the function and backend themselves are not modified. Otherwise, preparation becomes invalid and you need to run it again. In some settings, invalid preparations may still give correct results (e.g. for backends that require no preparation), but this is not a semantic guarantee and should not be relied upon.
The preparation result prep is not thread-safe. Sharing it between threads may lead to unexpected behavior. If you need to run differentiation concurrently, prepare separate prep objects for each thread.
When strict=Val(true) (the default), type checking is enforced between preparation and execution (but size checking is left to the user). While your code may work for different types by setting strict=Val(false), this is not guaranteed by the API and can break without warning.
DifferentiationInterface.gradient — Functiongradient(f, [prep,] backend, x, [contexts...]) -> gradCompute the gradient of the function f at point x.
To improve performance via operator preparation, refer to prepare_gradient.
DifferentiationInterface.gradient! — Functiongradient!(f, grad, [prep,] backend, x, [contexts...]) -> gradCompute the gradient of the function f at point x, overwriting grad.
To improve performance via operator preparation, refer to prepare_gradient.
DifferentiationInterface.value_and_gradient — Functionvalue_and_gradient(f, [prep,] backend, x, [contexts...]) -> (y, grad)Compute the value and the gradient of the function f at point x.
To improve performance via operator preparation, refer to prepare_gradient.
DifferentiationInterface.value_and_gradient! — Functionvalue_and_gradient!(f, grad, [prep,] backend, x, [contexts...]) -> (y, grad)Compute the value and the gradient of the function f at point x, overwriting grad.
To improve performance via operator preparation, refer to prepare_gradient.
Jacobian
DifferentiationInterface.prepare_jacobian — Functionprepare_jacobian(f, backend, x, [contexts...]; strict=Val(true)) -> prep
prepare_jacobian(f!, y, backend, x, [contexts...]; strict=Val(true)) -> prepCreate a prep object that can be given to jacobian and its variants to speed them up.
Depending on the backend, this can have several effects (preallocating memory, recording an execution trace) which are transparent to the user.
For in-place functions, y is mutated by f! during preparation.
The preparation result prep is only reusable as long as the arguments to jacobian do not change type or size, and the function and backend themselves are not modified. Otherwise, preparation becomes invalid and you need to run it again. In some settings, invalid preparations may still give correct results (e.g. for backends that require no preparation), but this is not a semantic guarantee and should not be relied upon.
The preparation result prep is not thread-safe. Sharing it between threads may lead to unexpected behavior. If you need to run differentiation concurrently, prepare separate prep objects for each thread.
When strict=Val(true) (the default), type checking is enforced between preparation and execution (but size checking is left to the user). While your code may work for different types by setting strict=Val(false), this is not guaranteed by the API and can break without warning.
DifferentiationInterface.jacobian — Functionjacobian(f, [prep,] backend, x, [contexts...]) -> jac
jacobian(f!, y, [prep,] backend, x, [contexts...]) -> jacCompute the Jacobian matrix of the function f at point x.
To improve performance via operator preparation, refer to prepare_jacobian.
DifferentiationInterface.jacobian! — Functionjacobian!(f, jac, [prep,] backend, x, [contexts...]) -> jac
jacobian!(f!, y, jac, [prep,] backend, x, [contexts...]) -> jacCompute the Jacobian matrix of the function f at point x, overwriting jac.
To improve performance via operator preparation, refer to prepare_jacobian.
DifferentiationInterface.value_and_jacobian — Functionvalue_and_jacobian(f, [prep,] backend, x, [contexts...]) -> (y, jac)
value_and_jacobian(f!, y, [prep,] backend, x, [contexts...]) -> (y, jac)Compute the value and the Jacobian matrix of the function f at point x.
To improve performance via operator preparation, refer to prepare_jacobian.
DifferentiationInterface.value_and_jacobian! — Functionvalue_and_jacobian!(f, jac, [prep,] backend, x, [contexts...]) -> (y, jac)
value_and_jacobian!(f!, y, jac, [prep,] backend, x, [contexts...]) -> (y, jac)Compute the value and the Jacobian matrix of the function f at point x, overwriting jac.
To improve performance via operator preparation, refer to prepare_jacobian.
Second order
DifferentiationInterface.SecondOrder — TypeSecondOrderCombination of two backends for second-order differentiation.
Constructor
SecondOrder(outer_backend, inner_backend)Fields
outer::AbstractADType: backend for the outer differentiationinner::AbstractADType: backend for the inner differentiation
Second derivative
DifferentiationInterface.prepare_second_derivative — Functionprepare_second_derivative(f, backend, x, [contexts...]; strict=Val(true)) -> prepCreate a prep object that can be given to second_derivative and its variants to speed them up.
Depending on the backend, this can have several effects (preallocating memory, recording an execution trace) which are transparent to the user.
The preparation result prep is only reusable as long as the arguments to second_derivative do not change type or size, and the function and backend themselves are not modified. Otherwise, preparation becomes invalid and you need to run it again. In some settings, invalid preparations may still give correct results (e.g. for backends that require no preparation), but this is not a semantic guarantee and should not be relied upon.
The preparation result prep is not thread-safe. Sharing it between threads may lead to unexpected behavior. If you need to run differentiation concurrently, prepare separate prep objects for each thread.
When strict=Val(true) (the default), type checking is enforced between preparation and execution (but size checking is left to the user). While your code may work for different types by setting strict=Val(false), this is not guaranteed by the API and can break without warning.
DifferentiationInterface.second_derivative — Functionsecond_derivative(f, [prep,] backend, x, [contexts...]) -> der2Compute the second derivative of the function f at point x.
To improve performance via operator preparation, refer to prepare_second_derivative.
DifferentiationInterface.second_derivative! — Functionsecond_derivative!(f, der2, [prep,] backend, x, [contexts...]) -> der2Compute the second derivative of the function f at point x, overwriting der2.
To improve performance via operator preparation, refer to prepare_second_derivative.
DifferentiationInterface.value_derivative_and_second_derivative — Functionvalue_derivative_and_second_derivative(f, [prep,] backend, x, [contexts...]) -> (y, der, der2)Compute the value, first derivative and second derivative of the function f at point x.
To improve performance via operator preparation, refer to prepare_second_derivative.
DifferentiationInterface.value_derivative_and_second_derivative! — Functionvalue_derivative_and_second_derivative!(f, der, der2, [prep,] backend, x, [contexts...]) -> (y, der, der2)Compute the value, first derivative and second derivative of the function f at point x, overwriting der and der2.
To improve performance via operator preparation, refer to prepare_second_derivative.
Hessian-vector product
DifferentiationInterface.prepare_hvp — Functionprepare_hvp(f, backend, x, tx, [contexts...]; strict=Val(true)) -> prepCreate a prep object that can be given to hvp and its variants to speed them up.
Depending on the backend, this can have several effects (preallocating memory, recording an execution trace) which are transparent to the user.
The preparation result prep is only reusable as long as the arguments to hvp do not change type or size, and the function and backend themselves are not modified. Otherwise, preparation becomes invalid and you need to run it again. In some settings, invalid preparations may still give correct results (e.g. for backends that require no preparation), but this is not a semantic guarantee and should not be relied upon.
The preparation result prep is not thread-safe. Sharing it between threads may lead to unexpected behavior. If you need to run differentiation concurrently, prepare separate prep objects for each thread.
When strict=Val(true) (the default), type checking is enforced between preparation and execution (but size checking is left to the user). While your code may work for different types by setting strict=Val(false), this is not guaranteed by the API and can break without warning.
DifferentiationInterface.prepare_hvp_same_point — Functionprepare_hvp_same_point(f, backend, x, tx, [contexts...]; strict=Val(true)) -> prep_sameCreate a prep object that can be given to hvp and its variants to speed them up, if they are applied at the same point x and with the same contexts.
Depending on the backend, this can have several effects (preallocating memory, recording an execution trace) which are transparent to the user.
The preparation result prep is only reusable as long as the arguments to hvp do not change type or size, and the function and backend themselves are not modified. Otherwise, preparation becomes invalid and you need to run it again. In some settings, invalid preparations may still give correct results (e.g. for backends that require no preparation), but this is not a semantic guarantee and should not be relied upon.
The preparation result prep is not thread-safe. Sharing it between threads may lead to unexpected behavior. If you need to run differentiation concurrently, prepare separate prep objects for each thread.
When strict=Val(true) (the default), type checking is enforced between preparation and execution (but size checking is left to the user). While your code may work for different types by setting strict=Val(false), this is not guaranteed by the API and can break without warning.
DifferentiationInterface.hvp — Functionhvp(f, [prep,] backend, x, tx, [contexts...]) -> tgCompute the Hessian-vector product of f at point x with a tuple of tangents tx.
To improve performance via operator preparation, refer to prepare_hvp and prepare_hvp_same_point.
DifferentiationInterface.hvp! — Functionhvp!(f, tg, [prep,] backend, x, tx, [contexts...]) -> tgCompute the Hessian-vector product of f at point x with a tuple of tangents tx, overwriting tg.
To improve performance via operator preparation, refer to prepare_hvp and prepare_hvp_same_point.
DifferentiationInterface.gradient_and_hvp — Functiongradient_and_hvp(f, [prep,] backend, x, tx, [contexts...]) -> (grad, tg)Compute the gradient and the Hessian-vector product of f at point x with a tuple of tangents tx.
To improve performance via operator preparation, refer to prepare_hvp and prepare_hvp_same_point.
DifferentiationInterface.gradient_and_hvp! — Functiongradient_and_hvp!(f, grad, tg, [prep,] backend, x, tx, [contexts...]) -> (grad, tg)Compute the gradient and the Hessian-vector product of f at point x with a tuple of tangents tx, overwriting grad and tg.
To improve performance via operator preparation, refer to prepare_hvp and prepare_hvp_same_point.
Hessian
DifferentiationInterface.prepare_hessian — Functionprepare_hessian(f, backend, x, [contexts...]; strict=Val(true)) -> prepCreate a prep object that can be given to hessian and its variants to speed them up.
Depending on the backend, this can have several effects (preallocating memory, recording an execution trace) which are transparent to the user.
The preparation result prep is only reusable as long as the arguments to hessian do not change type or size, and the function and backend themselves are not modified. Otherwise, preparation becomes invalid and you need to run it again. In some settings, invalid preparations may still give correct results (e.g. for backends that require no preparation), but this is not a semantic guarantee and should not be relied upon.
The preparation result prep is not thread-safe. Sharing it between threads may lead to unexpected behavior. If you need to run differentiation concurrently, prepare separate prep objects for each thread.
When strict=Val(true) (the default), type checking is enforced between preparation and execution (but size checking is left to the user). While your code may work for different types by setting strict=Val(false), this is not guaranteed by the API and can break without warning.
DifferentiationInterface.hessian — Functionhessian(f, [prep,] backend, x, [contexts...]) -> hessCompute the Hessian matrix of the function f at point x.
To improve performance via operator preparation, refer to prepare_hessian.
DifferentiationInterface.hessian! — Functionhessian!(f, hess, [prep,] backend, x, [contexts...]) -> hessCompute the Hessian matrix of the function f at point x, overwriting hess.
To improve performance via operator preparation, refer to prepare_hessian.
DifferentiationInterface.value_gradient_and_hessian — Functionvalue_gradient_and_hessian(f, [prep,] backend, x, [contexts...]) -> (y, grad, hess)Compute the value, gradient vector and Hessian matrix of the function f at point x.
To improve performance via operator preparation, refer to prepare_hessian.
DifferentiationInterface.value_gradient_and_hessian! — Functionvalue_gradient_and_hessian!(f, grad, hess, [prep,] backend, x, [contexts...]) -> (y, grad, hess)Compute the value, gradient vector and Hessian matrix of the function f at point x, overwriting grad and hess.
To improve performance via operator preparation, refer to prepare_hessian.
Utilities
Backend queries
DifferentiationInterface.check_available — Functioncheck_available(backend)Check whether backend is available (i.e. whether the extension is loaded) and return a Bool.
DifferentiationInterface.check_inplace — Functioncheck_inplace(backend)Check whether backend supports differentiation of in-place functions and return a Bool.
DifferentiationInterface.outer — Functionouter(backend::SecondOrder)
outer(backend::AbstractADType)Return the outer backend of a SecondOrder object, tasked with differentiation at the second order.
For any other backend type, this function acts like the identity.
DifferentiationInterface.inner — Functioninner(backend::SecondOrder)
inner(backend::AbstractADType)Return the inner backend of a SecondOrder object, tasked with differentiation at the first order.
For any other backend type, this function acts like the identity.
Backend switch
DifferentiationInterface.DifferentiateWith — TypeDifferentiateWithFunction wrapper that enforces differentiation with a "substitute" AD backend, possible different from the "true" AD backend that is called.
For instance, suppose a function f is not differentiable with Zygote because it involves mutation, but you know that it is differentiable with Enzyme. Then f2 = DifferentiateWith(f, AutoEnzyme()) is a new function that behaves like f, except that f2 is differentiable with Zygote (thanks to a chain rule which calls Enzyme under the hood). Moreover, any larger algorithm alg that calls f2 instead of f will also be differentiable with Zygote (as long as f was the only Zygote blocker).
This is mainly relevant for package developers who want to produce differentiable code at low cost, without writing the differentiation rules themselves. If you sprinkle a few DifferentiateWith in places where some AD backends may struggle, end users can pick from a wider variety of packages to differentiate your algorithms.
DifferentiateWith only supports out-of-place functions y = f(x) without additional context arguments. It only makes these functions differentiable if the true backend is either ForwardDiff, reverse-mode Mooncake, or if it automatically importing rules from ChainRules (e.g. Zygote). Some backends are also able to manually import rules from ChainRules. For any other true backend, the differentiation behavior is not altered by DifferentiateWith (it becomes a transparent wrapper).
When using DifferentiateWith(f, AutoSomething()), the function f must not close over any active data. As of now, we cannot differentiate with respect to parameters stored inside f.
Fields
f: the function in question, with signaturef(x)backend::AbstractADType: the substitute backend to use for differentiation
For the substitute AD backend to be called under the hood, its package needs to be loaded in addition to the package of the true AD backend.
Constructor
DifferentiateWith(f, backend)Example
julia> using DifferentiationInterface
julia> using FiniteDiff: FiniteDiff
using ForwardDiff: ForwardDiff
using Zygote: Zygote
julia> function f(x::Vector{Float64})
a = Vector{Float64}(undef, 1) # type constraint breaks ForwardDiff
a[1] = sum(abs2, x) # mutation breaks Zygote
return a[1]
end;
julia> f2 = DifferentiateWith(f, AutoFiniteDiff());
julia> f([3.0, 5.0]) == f2([3.0, 5.0])
true
julia> alg(x) = 7 * f2(x);
julia> ForwardDiff.gradient(alg, [3.0, 5.0])
2-element Vector{Float64}:
42.0
70.0
julia> Zygote.gradient(alg, [3.0, 5.0])[1]
2-element Vector{Float64}:
42.0
70.0Sparsity tools
DifferentiationInterface.MixedMode — TypeMixedModeCombination of a forward and a reverse mode backend for mixed-mode sparse Jacobian computation.
MixedMode backends only support jacobian and its variants, and it should be used inside an AutoSparse wrapper.
Constructor
MixedMode(forward_backend, reverse_backend)DifferentiationInterface.DenseSparsityDetector — TypeDenseSparsityDetectorSparsity pattern detector satisfying the detection API of ADTypes.jl.
The nonzeros in a Jacobian or Hessian are detected by computing the relevant matrix with dense AD, and thresholding the entries with a given tolerance (which can be numerically inaccurate). This process can be very slow, and should only be used if its output can be exploited multiple times to compute many sparse matrices.
In general, the sparsity pattern you obtain can depend on the provided input x. If you want to reuse the pattern, make sure that it is input-agnostic.
DenseSparsityDetector functionality is now located in a package extension, please load the SparseArrays.jl standard library before you use it.
Fields
backend::AbstractADTypeis the dense AD backend used under the hoodatol::Float64is the minimum magnitude of a matrix entry to be considered nonzero
Constructor
DenseSparsityDetector(backend; atol, method=:iterative)The keyword argument method::Symbol can be either:
:iterative: compute the matrix in a sequence of matrix-vector products (memory-efficient):direct: compute the matrix all at once (memory-hungry but sometimes faster).
Note that the constructor is type-unstable because method ends up being a type parameter of the DenseSparsityDetector object (this is not part of the API and might change).
Examples
using ADTypes, DifferentiationInterface, SparseArrays
using ForwardDiff: ForwardDiff
detector = DenseSparsityDetector(AutoForwardDiff(); atol=1e-5, method=:direct)
ADTypes.jacobian_sparsity(diff, rand(5), detector)
# output
4×5 SparseMatrixCSC{Bool, Int64} with 8 stored entries:
1 1 ⋅ ⋅ ⋅
⋅ 1 1 ⋅ ⋅
⋅ ⋅ 1 1 ⋅
⋅ ⋅ ⋅ 1 1Sometimes the sparsity pattern is input-dependent:
ADTypes.jacobian_sparsity(x -> [prod(x)], rand(2), detector)
# output
1×2 SparseMatrixCSC{Bool, Int64} with 2 stored entries:
1 1ADTypes.jacobian_sparsity(x -> [prod(x)], [0, 1], detector)
# output
1×2 SparseMatrixCSC{Bool, Int64} with 1 stored entry:
1 ⋅From primitive
DifferentiationInterface.AutoForwardFromPrimitive — TypeAutoForwardFromPrimitive(backend::AbstractADType)Wrapper which forces a given backend to act as a forward-mode backend, using only its native value_and_pushforward primitive and re-implementing the rest from scratch.
DifferentiationInterface.AutoReverseFromPrimitive — TypeAutoReverseFromPrimitive(backend::AbstractADType)Wrapper which forces a given backend to act as a reverse-mode backend, using only its native value_and_pullback implementation and rebuilding the rest from scratch.
Preparation type
DifferentiationInterface.Prep — TypePrepAbstract supertype for all preparation results (outputs of prepare_operator functions).