Skip to content

Commit 22f206a

Browse files
bump and document
1 parent 55d1268 commit 22f206a

File tree

3 files changed

+106
-68
lines changed

3 files changed

+106
-68
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "PreallocationTools"
22
uuid = "d236fae5-4411-538c-8e31-a6e3d9e00b46"
33
authors = ["Chris Rackauckas <accounts@chrisrackauckas.com>"]
4-
version = "0.4.5"
4+
version = "0.4.6"
55

66
[deps]
77
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"

README.md

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,62 +16,62 @@ edge cases of automatic differentiation to make it easier for users to get
1616
high performance even in the cases where code generation may change the
1717
function that is being called.
1818

19-
## dualcache
19+
## DiffCache
2020

21-
`dualcache` is a method for generating doubly-preallocated vectors which are
21+
`DiffCache` is a type for doubly-preallocated vectors which are
2222
compatible with non-allocating forward-mode automatic differentiation by
2323
ForwardDiff.jl. Since ForwardDiff uses chunked duals in its forward pass, two
2424
vector sizes are required in order for the arrays to be properly defined.
25-
`dualcache` creates a dispatching type to solve this, so that by passing a
25+
`DiffCache` creates a dispatching type to solve this, so that by passing a
2626
qualifier it can automatically switch between the required cache. This method
2727
is fully type-stable and non-dynamic, made for when the highest performance is
2828
needed.
2929

30-
### Using dualcache
30+
### Using DiffCache
3131

3232
```julia
33-
dualcache(u::AbstractArray, N::Int=ForwardDiff.pickchunksize(length(u)); levels::Int = 1)
34-
dualcache(u::AbstractArray, N::AbstractArray{<:Int})
33+
DiffCache(u::AbstractArray, N::Int=ForwardDiff.pickchunksize(length(u)); levels::Int = 1)
34+
DiffCache(u::AbstractArray, N::AbstractArray{<:Int})
3535
```
3636

37-
The `dualcache` function builds a `DualCache` object that stores both a version
37+
The `DiffCache` function builds a `DiffCache` object that stores both a version
3838
of the cache for `u` and for the `Dual` version of `u`, allowing use of
3939
pre-cached vectors with forward-mode automatic differentiation. Note that
40-
`dualcache`, due to its design, is only compatible with arrays that contain concretely
40+
`DiffCache`, due to its design, is only compatible with arrays that contain concretely
4141
typed elements.
4242

4343
To access the caches, one uses:
4444

4545
```julia
46-
get_tmp(tmp::DualCache, u)
46+
get_tmp(tmp::DiffCache, u)
4747
```
4848

4949
When `u` has an element subtype of `Dual` numbers, then it returns the `Dual`
5050
version of the cache. Otherwise it returns the standard cache (for use in the
5151
calls without automatic differentiation).
5252

53-
In order to preallocate to the right size, the `dualcache` needs to be specified
54-
to have the correct `N` matching the chunk size of the dual numbers or larger.
55-
If the chunk size `N` specified is too large, `get_tmp` will automatically resize
56-
when dispatching; this remains type-stable and non-allocating, but comes at the
53+
In order to preallocate to the right size, the `DiffCache` needs to be specified
54+
to have the correct `N` matching the chunk size of the dual numbers or larger.
55+
If the chunk size `N` specified is too large, `get_tmp` will automatically resize
56+
when dispatching; this remains type-stable and non-allocating, but comes at the
5757
expense of additional memory.
5858

5959
In a differential equation, optimization, etc., the default chunk size is computed
60-
from the state vector `u`, and thus if one creates the `dualcache` via
61-
`dualcache(u)` it will match the default chunking of the solver libraries.
60+
from the state vector `u`, and thus if one creates the `DiffCache` via
61+
`DiffCache(u)` it will match the default chunking of the solver libraries.
6262

63-
`dualcache` is also compatible with nested automatic differentiation calls through
64-
the `levels` keyword (`N` for each level computed using based on the size of the
63+
`DiffCache` is also compatible with nested automatic differentiation calls through
64+
the `levels` keyword (`N` for each level computed using based on the size of the
6565
state vector) or by specifying `N` as an array of integers of chunk sizes, which
6666
enables full control of chunk sizes on all differentation levels.
6767

68-
### dualcache Example 1: Direct Usage
68+
### DiffCache Example 1: Direct Usage
6969

7070
```julia
7171
using ForwardDiff, PreallocationTools
7272
randmat = rand(5, 3)
7373
sto = similar(randmat)
74-
stod = dualcache(sto)
74+
stod = DiffCache(sto)
7575

7676
function claytonsample!(sto, τ, α; randmat=randmat)
7777
sto = get_tmp(sto, τ)
@@ -93,13 +93,13 @@ ForwardDiff.jacobian(x -> claytonsample!(stod, x[1], x[2]), [0.3; 0.0])
9393
```
9494

9595
In the above, the chunk size of the dual numbers has been selected based on the size
96-
of `randmat`, resulting in a chunk size of 8 in this case. However, since the derivative
97-
is calculated with respect to τ and the Jacobian is calculated with respect to τ and α,
98-
specifying the `dualcache` with `stod = dualcache(sto, 1)` or `stod = dualcache(sto, 2)`,
96+
of `randmat`, resulting in a chunk size of 8 in this case. However, since the derivative
97+
is calculated with respect to τ and the Jacobian is calculated with respect to τ and α,
98+
specifying the `DiffCache` with `stod = DiffCache(sto, 1)` or `stod = DiffCache(sto, 2)`,
9999
respectively, would have been the most memory efficient way of performing these calculations
100100
(only really relevant for much larger problems).
101101

102-
### dualcache Example 2: ODEs
102+
### DiffCache Example 2: ODEs
103103

104104
```julia
105105
using LinearAlgebra, OrdinaryDiffEq
@@ -125,7 +125,7 @@ function foo(du, u, (A, tmp), t)
125125
nothing
126126
end
127127
chunk_size = 5
128-
prob = ODEProblem(foo, ones(5, 5), (0., 1.0), (ones(5,5), dualcache(zeros(5,5), chunk_size)))
128+
prob = ODEProblem(foo, ones(5, 5), (0., 1.0), (ones(5,5), DiffCache(zeros(5,5), chunk_size)))
129129
solve(prob, TRBDF2(chunk_size=chunk_size))
130130
```
131131

@@ -140,10 +140,10 @@ function foo(du, u, (A, tmp), t)
140140
nothing
141141
end
142142
chunk_size = 5
143-
prob = ODEProblem(foo, ones(5, 5), (0., 1.0), (ones(5,5), dualcache(zeros(5,5))))
143+
prob = ODEProblem(foo, ones(5, 5), (0., 1.0), (ones(5,5), DiffCache(zeros(5,5))))
144144
solve(prob, TRBDF2())
145145
```
146-
### dualcache Example 3: Nested AD calls in an optimization problem involving a Hessian matrix
146+
### DiffCache Example 3: Nested AD calls in an optimization problem involving a Hessian matrix
147147

148148
```julia
149149
using LinearAlgebra, OrdinaryDiffEq, PreallocationTools, Optim, Optimization
@@ -157,7 +157,7 @@ function foo(du, u, p, t)
157157
end
158158

159159
coeffs = -collect(0.1:0.1:0.4)
160-
cache = dualcache(zeros(2,2), levels = 3)
160+
cache = DiffCache(zeros(2,2), levels = 3)
161161
prob = ODEProblem(foo, ones(2, 2), (0., 1.0), (coeffs, cache))
162162
realsol = solve(prob, TRBDF2(), saveat = 0.0:0.1:10.0, reltol = 1e-8)
163163

@@ -170,7 +170,7 @@ function objfun(x, prob, realsol, cache)
170170
ofv = 1e12
171171
else
172172
ofv = sum((sol.-realsol).^2)
173-
end
173+
end
174174
return ofv
175175
end
176176
fn(x,p) = objfun(x, p[1], p[2], p[3])
@@ -179,10 +179,29 @@ optprob = OptimizationProblem(optfun, zeros(length(coeffs)), (prob, realsol, cac
179179
solve(optprob, Newton())
180180
```
181181
Solves an optimization problem for the coefficients, `coeffs`, appearing in a differential equation.
182-
The optimization is done with [Optim.jl](https://github.com/JuliaNLSolvers/Optim.jl)'s `Newton()`
183-
algorithm. Since this involves automatic differentiation in the ODE solver and the calculation
184-
of Hessians, three automatic differentiations are nested within each other. Therefore, the `dualcache`
185-
is specified with `levels = 3`.
182+
The optimization is done with [Optim.jl](https://github.com/JuliaNLSolvers/Optim.jl)'s `Newton()`
183+
algorithm. Since this involves automatic differentiation in the ODE solver and the calculation
184+
of Hessians, three automatic differentiations are nested within each other. Therefore, the `DiffCache`
185+
is specified with `levels = 3`.
186+
187+
## FixedSizeDiffCache
188+
189+
`FixedSizeDiffCache` is a lot like `DiffCache`, but it stores dual numbers in its caches
190+
instead of a flat array. Because of this, it can avoid a view, making it a little bit
191+
more performant for generating caches of non-`Array` types. However, it is a lot less
192+
flexible than `DiffCache`, and is thus only recommended for cases where the chunk size
193+
is known in advance (for example, ODE solvers) and where `u` is not an `Array`.
194+
195+
The interface is almost exactly the same, except with the constructor:
196+
197+
```julia
198+
FixedSizeDiffCache(u::AbstractArray, chunk_size = Val{ForwardDiff.pickchunksize(length(u))})
199+
FixedSizeDiffCache(u::AbstractArray, chunk_size::Integer)
200+
```
201+
202+
Note that the `FixedSizeDiffCache` can support duals that are of a small chunk size than
203+
the preallocated ones, but not a larger size. Nested duals are not supported with this
204+
construct.
186205

187206
## LazyBufferCache
188207

@@ -215,7 +234,7 @@ prob = ODEProblem(foo, ones(5, 5), (0., 1.0), (ones(5,5), LazyBufferCache()))
215234
solve(prob, TRBDF2())
216235
```
217236

218-
## Note About ReverseDiff Support for LazyBuffer
237+
## Note About ReverseDiff Support for LazyBuffer
219238

220239
ReverseDiff support is done in SciMLSensitivity.jl to reduce the AD requirements on this package.
221240
Load that package if ReverseDiff overloads are required.

docs/src/index.md

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,62 +6,62 @@ edge cases of automatic differentiation to make it easier for users to get
66
high performance even in the cases where code generation may change the
77
function that is being called.
88

9-
## dualcache
9+
## DiffCache
1010

11-
`dualcache` is a method for generating doubly-preallocated vectors which are
11+
`DiffCache` is a method for generating doubly-preallocated vectors which are
1212
compatible with non-allocating forward-mode automatic differentiation by
1313
ForwardDiff.jl. Since ForwardDiff uses chunked duals in its forward pass, two
1414
vector sizes are required in order for the arrays to be properly defined.
15-
`dualcache` creates a dispatching type to solve this, so that by passing a
15+
`DiffCache` creates a dispatching type to solve this, so that by passing a
1616
qualifier it can automatically switch between the required cache. This method
1717
is fully type-stable and non-dynamic, made for when the highest performance is
1818
needed.
1919

20-
### Using dualcache
20+
### Using DiffCache
2121

2222
```julia
23-
dualcache(u::AbstractArray, N::Int=ForwardDiff.pickchunksize(length(u)); levels::Int = 1)
24-
dualcache(u::AbstractArray, N::AbstractArray{<:Int})
23+
DiffCache(u::AbstractArray, N::Int=ForwardDiff.pickchunksize(length(u)); levels::Int = 1)
24+
DiffCache(u::AbstractArray, N::AbstractArray{<:Int})
2525
```
2626

27-
The `dualcache` function builds a `DualCache` object that stores both a version
27+
The `DiffCache` function builds a `DiffCache` object that stores both a version
2828
of the cache for `u` and for the `Dual` version of `u`, allowing use of
2929
pre-cached vectors with forward-mode automatic differentiation. Note that
30-
`dualcache`, due to its design, is only compatible with arrays that contain concretely
30+
`DiffCache`, due to its design, is only compatible with arrays that contain concretely
3131
typed elements.
3232

3333
To access the caches, one uses:
3434

3535
```julia
36-
get_tmp(tmp::DualCache, u)
36+
get_tmp(tmp::DiffCache, u)
3737
```
3838

3939
When `u` has an element subtype of `Dual` numbers, then it returns the `Dual`
4040
version of the cache. Otherwise it returns the standard cache (for use in the
4141
calls without automatic differentiation).
4242

43-
In order to preallocate to the right size, the `dualcache` needs to be specified
44-
to have the correct `N` matching the chunk size of the dual numbers or larger.
45-
If the chunk size `N` specified is too large, `get_tmp` will automatically resize
46-
when dispatching; this remains type-stable and non-allocating, but comes at the
43+
In order to preallocate to the right size, the `DiffCache` needs to be specified
44+
to have the correct `N` matching the chunk size of the dual numbers or larger.
45+
If the chunk size `N` specified is too large, `get_tmp` will automatically resize
46+
when dispatching; this remains type-stable and non-allocating, but comes at the
4747
expense of additional memory.
4848

4949
In a differential equation, optimization, etc., the default chunk size is computed
50-
from the state vector `u`, and thus if one creates the `dualcache` via
51-
`dualcache(u)` it will match the default chunking of the solver libraries.
50+
from the state vector `u`, and thus if one creates the `DiffCache` via
51+
`DiffCache(u)` it will match the default chunking of the solver libraries.
5252

53-
`dualcache` is also compatible with nested automatic differentiation calls through
54-
the `levels` keyword (`N` for each level computed using based on the size of the
53+
`DiffCache` is also compatible with nested automatic differentiation calls through
54+
the `levels` keyword (`N` for each level computed using based on the size of the
5555
state vector) or by specifying `N` as an array of integers of chunk sizes, which
5656
enables full control of chunk sizes on all differentation levels.
5757

58-
### dualcache Example 1: Direct Usage
58+
### DiffCache Example 1: Direct Usage
5959

6060
```julia
6161
using ForwardDiff, PreallocationTools
6262
randmat = rand(5, 3)
6363
sto = similar(randmat)
64-
stod = dualcache(sto)
64+
stod = DiffCache(sto)
6565

6666
function claytonsample!(sto, τ, α; randmat=randmat)
6767
sto = get_tmp(sto, τ)
@@ -83,13 +83,13 @@ ForwardDiff.jacobian(x -> claytonsample!(stod, x[1], x[2]), [0.3; 0.0])
8383
```
8484

8585
In the above, the chunk size of the dual numbers has been selected based on the size
86-
of `randmat`, resulting in a chunk size of 8 in this case. However, since the derivative
87-
is calculated with respect to τ and the Jacobian is calculated with respect to τ and α,
88-
specifying the `dualcache` with `stod = dualcache(sto, 1)` or `stod = dualcache(sto, 2)`,
86+
of `randmat`, resulting in a chunk size of 8 in this case. However, since the derivative
87+
is calculated with respect to τ and the Jacobian is calculated with respect to τ and α,
88+
specifying the `DiffCache` with `stod = DiffCache(sto, 1)` or `stod = DiffCache(sto, 2)`,
8989
respectively, would have been the most memory efficient way of performing these calculations
9090
(only really relevant for much larger problems).
9191

92-
### dualcache Example 2: ODEs
92+
### DiffCache Example 2: ODEs
9393

9494
```julia
9595
using LinearAlgebra, OrdinaryDiffEq
@@ -115,7 +115,7 @@ function foo(du, u, (A, tmp), t)
115115
nothing
116116
end
117117
chunk_size = 5
118-
prob = ODEProblem(foo, ones(5, 5), (0., 1.0), (ones(5,5), dualcache(zeros(5,5), chunk_size)))
118+
prob = ODEProblem(foo, ones(5, 5), (0., 1.0), (ones(5,5), DiffCache(zeros(5,5), chunk_size)))
119119
solve(prob, TRBDF2(chunk_size=chunk_size))
120120
```
121121

@@ -130,10 +130,10 @@ function foo(du, u, (A, tmp), t)
130130
nothing
131131
end
132132
chunk_size = 5
133-
prob = ODEProblem(foo, ones(5, 5), (0., 1.0), (ones(5,5), dualcache(zeros(5,5))))
133+
prob = ODEProblem(foo, ones(5, 5), (0., 1.0), (ones(5,5), DiffCache(zeros(5,5))))
134134
solve(prob, TRBDF2())
135135
```
136-
### dualcache Example 3: Nested AD calls in an optimization problem involving a Hessian matrix
136+
### DiffCache Example 3: Nested AD calls in an optimization problem involving a Hessian matrix
137137

138138
```julia
139139
using LinearAlgebra, OrdinaryDiffEq, PreallocationTools, Optim, Optimization
@@ -147,7 +147,7 @@ function foo(du, u, p, t)
147147
end
148148

149149
coeffs = -collect(0.1:0.1:0.4)
150-
cache = dualcache(zeros(2,2), levels = 3)
150+
cache = DiffCache(zeros(2,2), levels = 3)
151151
prob = ODEProblem(foo, ones(2, 2), (0., 1.0), (coeffs, cache))
152152
realsol = solve(prob, TRBDF2(), saveat = 0.0:0.1:10.0, reltol = 1e-8)
153153

@@ -160,7 +160,7 @@ function objfun(x, prob, realsol, cache)
160160
ofv = 1e12
161161
else
162162
ofv = sum((sol.-realsol).^2)
163-
end
163+
end
164164
return ofv
165165
end
166166
fn(x,p) = objfun(x, p[1], p[2], p[3])
@@ -169,10 +169,29 @@ optprob = OptimizationProblem(optfun, zeros(length(coeffs)), (prob, realsol, cac
169169
solve(optprob, Newton())
170170
```
171171
Solves an optimization problem for the coefficients, `coeffs`, appearing in a differential equation.
172-
The optimization is done with [Optim.jl](https://github.com/JuliaNLSolvers/Optim.jl)'s `Newton()`
173-
algorithm. Since this involves automatic differentiation in the ODE solver and the calculation
174-
of Hessians, three automatic differentiations are nested within each other. Therefore, the `dualcache`
175-
is specified with `levels = 3`.
172+
The optimization is done with [Optim.jl](https://github.com/JuliaNLSolvers/Optim.jl)'s `Newton()`
173+
algorithm. Since this involves automatic differentiation in the ODE solver and the calculation
174+
of Hessians, three automatic differentiations are nested within each other. Therefore, the `DiffCache`
175+
is specified with `levels = 3`.
176+
177+
## FixedSizeDiffCache
178+
179+
`FixedSizeDiffCache` is a lot like `DiffCache`, but it stores dual numbers in its caches
180+
instead of a flat array. Because of this, it can avoid a view, making it a little bit
181+
more performant for generating caches of non-`Array` types. However, it is a lot less
182+
flexible than `DiffCache`, and is thus only recommended for cases where the chunk size
183+
is known in advance (for example, ODE solvers) and where `u` is not an `Array`.
184+
185+
The interface is almost exactly the same, except with the constructor:
186+
187+
```julia
188+
FixedSizeDiffCache(u::AbstractArray, chunk_size = Val{ForwardDiff.pickchunksize(length(u))})
189+
FixedSizeDiffCache(u::AbstractArray, chunk_size::Integer)
190+
```
191+
192+
Note that the `FixedSizeDiffCache` can support duals that are of a small chunk size than
193+
the preallocated ones, but not a larger size. Nested duals are not supported with this
194+
construct.
176195

177196
## LazyBufferCache
178197

@@ -205,7 +224,7 @@ prob = ODEProblem(foo, ones(5, 5), (0., 1.0), (ones(5,5), LazyBufferCache()))
205224
solve(prob, TRBDF2())
206225
```
207226

208-
## Note About ReverseDiff Support for LazyBuffer
227+
## Note About ReverseDiff Support for LazyBuffer
209228

210229
ReverseDiff support is done in SciMLSensitivity.jl to reduce the AD requirements on this package.
211230
Load that package if ReverseDiff overloads are required.
@@ -263,7 +282,7 @@ Pkg.status(;mode = PKGMODE_MANIFEST) # hide
263282
</details>
264283
```
265284
```@raw html
266-
You can also download the
285+
You can also download the
267286
<a href="
268287
```
269288
```@eval

0 commit comments

Comments
 (0)