Skip to content

FAQ suggestion: lazily allocate buffers for use with automatic differentiation #769

@stevengj

Description

@stevengj

As noted in the FAQ, using pre-allocated buffers is problematic for automatic differentiation, because then one sometimes needs a buffer of dual numbers instead.

The FAQ suggests using the undocumented get_tmp and dualcache functions. I have to admit that I had a hard time getting these to work in our problem, and the lack of documentation made them somewhat hard to recommend. (A basic difficulty seems to be choosing the right type parameters for the dual numbers ahead of time.)

It occurred to me that a much simpler solution is to allocate buffers lazily, of the same type as u, caching them for later usage. This worked well for us. The implementation is easy — perhaps something like this could be included and suggested in the FAQ?

"""
    b = LazyBufferCache(f=identity)

A lazily allocated buffer object.  Given a vector `u`, `b[u]` returns a `Vector` of the 
same element type and length `f(length(u))` (defaulting to the same length), which is
allocated as needed and then cached within `b` for subsequent usage.
"""
struct LazyBufferCache{F<:Function}
    bufs::Dict # a dictionary mapping types to buffers
    lengthmap::F
    LazyBufferCache(f::F=identity) where {F<:Function} = new{F}(Dict()) # start with empty dict
end

# override the [] method
function Base.getindex(b::LazyBufferCache, u::AbstractVector{T}) where {T}
    n = b.lengthmap(length(u)) # required buffer length
    buf = get!(b.bufs, T) do
        Vector{T}(undef, n) # buffer to allocate if it was not found in b.bufs
    end::Vector{T} # declare type since b.bufs dictionary is untyped
    return resize!(buf, n) # resize the buffer if needed, e.g. if problem was resized
end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions