Documentation | |
Build Status | |
Code Style | |
Downloads | |
Citation |
Fast Jacobian and Hessian sparsity detection via operator-overloading.
To install this package, open the Julia REPL and run
julia> ]add SparseConnectivityTracer
For functions y = f(x)
and f!(y, x)
, the sparsity pattern of the Jacobian can be obtained
by computing a single forward-pass through the function:
julia> using SparseConnectivityTracer
julia> detector = TracerSparsityDetector();
julia> x = rand(3);
julia> f(x) = [x[1]^2, 2 * x[1] * x[2]^2, sin(x[3])];
julia> jacobian_sparsity(f, x, detector)
3×3 SparseArrays.SparseMatrixCSC{Bool, Int64} with 4 stored entries:
1 ⋅ ⋅
1 1 ⋅
⋅ ⋅ 1
By default, BitSet
is used for internal sparsity pattern representations.
For very large inputs, it might be more efficient to set the type to Set{UInt}
:
julia> detector = TracerSparsityDetector(; gradient_pattern_type=Set{UInt})
For scalar functions y = f(x)
, the sparsity pattern of the Hessian can be obtained
by computing a single forward-pass through the function:
julia> x = rand(4);
julia> f(x) = x[1] + x[2]*x[3] + 1/x[4];
julia> hessian_sparsity(f, x, detector)
4×4 SparseArrays.SparseMatrixCSC{Bool, Int64} with 3 stored entries:
⋅ ⋅ ⋅ ⋅
⋅ ⋅ 1 ⋅
⋅ 1 ⋅ ⋅
⋅ ⋅ ⋅ 1
By default, dictionaries of BitSet
s are used for internal sparsity pattern representations.
For very large inputs, it might be more efficient to set the type to Dict{UInt, Set{UInt}}
:
julia> detector = TracerSparsityDetector(; hessian_pattern_type=Dict{UInt, Set{UInt}})
For more detailed examples, take a look at the documentation.
TracerSparsityDetector
returns conservative "global" sparsity patterns over the entire input domain of x
.
It is not compatible with functions that require information about the primal values of a computation (e.g. iszero
, >
, ==
).
To compute a less conservative Jacobian or Hessian sparsity pattern at an input point x
, use TracerLocalSparsityDetector
instead.
Note that patterns computed with TracerLocalSparsityDetector
depend on the input x
and have to be recomputed when x
changes:
julia> using SparseConnectivityTracer
julia> detector = TracerLocalSparsityDetector();
julia> f(x) = x[1] > x[2] ? x[1] : x[2];
julia> jacobian_sparsity(f, [1 2], detector)
1×2 SparseArrays.SparseMatrixCSC{Bool, Int64} with 1 stored entry:
⋅ 1
julia> jacobian_sparsity(f, [2 1], detector)
1×2 SparseArrays.SparseMatrixCSC{Bool, Int64} with 1 stored entry:
1 ⋅
Take a look at the documentation for more information on global and local patterns.
SparseConnectivityTracer uses ADTypes.jl's interface for sparsity detection,
making it compatible with DifferentiationInterface.jl's sparse automatic differentiation functionality.
In fact, the functions jacobian_sparsity
and hessian_sparsity
are re-exported from ADTypes.
- SparseDiffTools.jl: automatic sparsity detection via Symbolics.jl and Cassette.jl
- SparsityTracing.jl: automatic Jacobian sparsity detection using an algorithm based on SparsLinC by Bischof et al. (1996)
If you use SparseConnectivityTracer in your research, please cite our preprint Sparser, Better, Faster, Stronger: Efficient Automatic Differentiation for Sparse Jacobians and Hessians:
@article{hill2025sparser,
title={Sparser, Better, Faster, Stronger: Sparsity Detection for Efficient Automatic Differentiation},
author={Adrian Hill and Guillaume Dalle},
journal={Transactions on Machine Learning Research},
issn={2835-8856},
year={2025},
url={https://openreview.net/forum?id=GtXSN52nIW},
note={}
}
Adrian Hill gratefully acknowledges funding from the German Federal Ministry of Education and Research under the grant BIFOLD25B.