From c16d7110f9b7f1612fd0a94832e31876d6f1bb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20K=2E=20Papp?= Date: Fri, 9 May 2025 15:16:54 +0200 Subject: [PATCH 1/2] first draft of precompute API --- docs/src/index.md | 16 +++++++- src/LogDensityProblems.jl | 81 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 3 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index ed4e65c..0c41d0e 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -170,6 +170,10 @@ end If the gradient is a mutable vector (eg `Vector`), it should not be reused for another purpose. Practically, each call to [`LogDensityProblems.logdensity_and_gradient`](@ref) should allocate a new one, or use immutables like `StaticArrays.SVector` for small dimensions. +# Precomputation API + +FIXME + # Various utilities You may find these utilities useful for debugging and optimization. @@ -180,7 +184,7 @@ LogDensityProblems.stresstest # [Log densities API](@id log-density-api) -Use the functions below for evaluating gradients and querying their dimension and other information. These symbols are not exported, as they are mostly used by package developers and in any case would need to be `import`ed or qualified to add methods to. +Use the functions below for evaluating gradients and querying their dimension and other information. These symbols are `public`, but not exported, as they are mostly used by package developers and in any case would need to be `import`ed or qualified to add methods to. ```@docs LogDensityProblems.capabilities @@ -190,3 +194,13 @@ LogDensityProblems.logdensity LogDensityProblems.logdensity_and_gradient LogDensityProblems.logdensity_gradient_and_hessian ``` + +The methods below only need to be implemented for storing precomputed information with coordinates, otherwise the defaults just work. + +```@docs +LogDensityProblems.precompute +LogDensityProblems.move +LogDensityProblems.move! +``` + + diff --git a/src/LogDensityProblems.jl b/src/LogDensityProblems.jl index 2cea958..8efb4d0 100644 --- a/src/LogDensityProblems.jl +++ b/src/LogDensityProblems.jl @@ -16,6 +16,9 @@ using ArgCheck: @argcheck using DocStringExtensions: SIGNATURES, TYPEDEF using Random: AbstractRNG, default_rng +public LogDensityOrder, capabilities, dimension, logdensity, logdensity_and_gradient, + logdensity_gradient_and_hessian, precompute, move, move! + #### #### interface for problems #### @@ -51,7 +54,7 @@ return values are invalid*. # Interface description -The following methods need to be implemented for the interface: +The following methods **need to be implemented** for the interface: 1. [`dimension`](@ref) returns the *dimension* of the domain, @@ -61,7 +64,34 @@ The following methods need to be implemented for the interface: 4. [`logdensity_gradient_and_hessian`](@ref) when `K ≥ 2`. -See also [`LogDensityProblems.stresstest`](@ref) for stress testing. +The precomputation API (see below) has sensible fallbacks and should only be implemented +as needed. + +# Coordinate points with precomputed information + +The interface also allows for encapsulating extra information associated with +coordinates. The idea is that a coordinate ``x ∈ ℝⁿ`` may be associated with quantities +precomputed from `x` (such as solutions to implicit equations), which can be updated at +a lower computational cost when the position is changed instead of recomputed from +scratch. + +The following methods **may be implemented**; but if they are not needed for your +application this package provides sensible defaults. + +1. A type that encapsulates the precomputed information. It should be + `<:AbstractVector{T}` for some `T` and support the read-only interface for vectors, + ie `Base.size` and `Base.getindex`. When used as a vector, it should just correspond + to the position in ``ℝⁿ``. + +2. [`precompute`](@ref), which precomputes the relevant information and returns objects of the + type above. + +3. [`move`](@ref) and [`move!`](@ref) to change the coordinates and recompute the + associated information. + +# See also + +[`LogDensityProblems.stresstest`](@ref) for stress testing. """ capabilities(T::Type) = nothing @@ -151,6 +181,53 @@ The first argument (the log density) can be shifted by a constant, see the note """ function logdensity_gradient_and_hessian end +""" +$(SIGNATURES) + +Precompute information associated with the coordinates `x` and return it as a +user-defined type. + +Cf [`move`](@ref). +""" +function precompute(ℓ, x::AbstractVector{T}) where T + if T <: AbstractFloat + x + else + float.(x) + end +end + +""" +$(SIGNATURES) + +Change the coordinates by `Δ`. Conceptually equivalent to `x .+ Δ`, which is the +fallback implementation, but user-defined types for the second argument can take +advantage of the information there to compute the new associated information for small +changes. + +The result should be **the same type** as `x` if `eltype(x) ≡ eltype(Δ)`. + +Caller ensures that `x` is the result of [`precompute`](@ref). It is valid for an +implementation to error in all other cases. +""" +move(ℓ, x::AbstractVector, Δ) = x .+ Δ + +""" +$(SIGNATURES) + +Equivalent to [`move`](@ref), but *may* modify `x`, which is returned, or choose to +return a new value. + +If a new value is returned, it should be the same type as `x` if `eltype(x) ≡ eltype(Δ)`. + +Caller ensures that `x` is the result of [`precompute`](@ref). It is valid for an +implementation to error in all other cases. +""" +function move!(ℓ, x::AbstractVector, Δ) + x .+= Δ + x +end + include("utilities.jl") end # module From e1f8aaf376324f7b87e6bf1e0a9416b00357270e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20K=2E=20Papp?= Date: Fri, 9 May 2025 15:21:49 +0200 Subject: [PATCH 2/2] use Compat for public --- Project.toml | 4 +++- src/LogDensityProblems.jl | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 3bc0c2a..be0af51 100644 --- a/Project.toml +++ b/Project.toml @@ -1,15 +1,17 @@ name = "LogDensityProblems" uuid = "6fdf6af0-433a-55f7-b3ed-c6c6e0b8df7c" -authors = ["Tamas K. Papp "] version = "2.1.2" +authors = ["Tamas K. Papp "] [deps] ArgCheck = "dce04be8-c92d-5529-be00-80e4d2c0e197" +Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [compat] ArgCheck = "1, 2" +Compat = "4.16.0" DocStringExtensions = "0.8, 0.9" julia = "1.10" diff --git a/src/LogDensityProblems.jl b/src/LogDensityProblems.jl index 8efb4d0..56802cc 100644 --- a/src/LogDensityProblems.jl +++ b/src/LogDensityProblems.jl @@ -15,8 +15,9 @@ module LogDensityProblems using ArgCheck: @argcheck using DocStringExtensions: SIGNATURES, TYPEDEF using Random: AbstractRNG, default_rng +using Compat: @compat -public LogDensityOrder, capabilities, dimension, logdensity, logdensity_and_gradient, +@compat public LogDensityOrder, capabilities, dimension, logdensity, logdensity_and_gradient, logdensity_gradient_and_hessian, precompute, move, move! ####