-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Moving function logdensity into super-lightweight package for abstract densities? #78
Comments
Intuitively, I would think that it is a bit limiting and opinionated if an abstract interface would enforce a specific type structure since multiple inheritance does not exist and packages (such as ones in the Turing ecosystem) already use custom type structures. I think I also think that one has to be careful about the interpretation/meaning of
Is this actually necessary to be part of the interface? One can always just use struct LogDensityFunction{F}
f::F
end
logdensity(f) = LogDensityFunction(f)
logdensity(l::LogDensityFunction, x) = l.f(x) without a supertype that 1) would make it easy to obtain something that supports BTW (a bit unrelated): in the Bayesian setting with |
Good point. So how about the same as I proposed above, but minus an
Oh sure - that was absolutely my intention. My own use cases would be mostly probability densities, but I thought the interface should just be about positive (incl. zero) mathematical densities, not even with an implication that the density can be interpreted as a probability, and nothing at all about Bayes in there.
I think it should be, yes - for example so that if a density is defined via a log-density function, And we should have So I think it would be very valuable to have |
This seems reasonable (even though it's not completely clear to me how relevant
Or maybe DensityBase, DensityCore, or DensityInterface? |
It's necessary for Holy-trait-dispatch (like other So to enable type-stable code (assuming the result of some_function(density) = some_function_impl(Val(isdensity(density)), density)
some_function_impl(::Val{true}, density) = handle_density_trait_compatible(density)
some_function_impl(::Val{false}, density) = some_other_generic_action_or_so(density) And to implement sanity checks: function find_max_density(density, x_init)
isdensity(density) || throw(ArgumentError("density not compatible with the DensityTraits interface"))
...
end |
The technical reason is clear, I just don't recall any instance in the Turing ecosystem or another package where it would be needed. Even in the |
True, for I feel it would just be nice to test if something is a density, if we don't have an abstract type for it. Also for debugging, etc. Do you think |
I don't mind if it's added, I was just curious if there exists already a specific example where it is needed. |
Ok, maybe I make a quick draft for the package? |
I think that a minimal API package for log densities will make sense when the API is mature. For LogDensityProblems, this is not the case at this point, I plan various changes. So I am not in favor of a shared symbol at this point. |
Ok, no worries I'll choose a different name then. Sorry for spamming your repo with this longish thread, in this case. @devmotion, Ok, if I CC you on my draft repo? I'd really like to do something that would be acceptable to the community, so Turing, etc., and I'd value your input. |
Sure, I can have a look. |
@phipsgabler This is the discussion about DensityInterface from a year ago. Link to your PoC: https://github.com/phipsgabler/LogDensityProblems.jl/tree/phg/densityinterface I think a bit less intrusive and breaking would be to start with just supporting the DensityInterface API on top but keeping (Another comment regarding the sketch: I think one should refrain from making additional changes unrelated to supporting DensityInterface such as adding StaticNumbers. I'm not convinced yet that this is a good idea since most functionality is not needed, and my experience with Static.jl leads me to believe that these kinds of packages are prone to causing a lot of invalidations.) |
@tpapp ,I've been thinking about creating a super-lightweight package
AbstractDensities
or so with a minimal interface for (log-)densities. At the moment, we have so many different approaches in the ecosystem and IMHO not enough compatibility.Would you consider "donating" the function name
logdensity
(so have the function defined inAbstractDensities
andLogDensityProblems
would import/re-export if from there?I was thinking about a really minimal non-opinionated package with just
abstract type AbstractDensity
, for direct dispatch.isdensity(some_density)::Bool
, for Holy-trait dispatchlogdensity(some_density, x)::Real
logdensity(some_density)(x) == logdensity(some_density, x)
(for convenient use in AD, optimization, sampling, etc.)LogFuncDensity(f) <: AbstractDensity
as a convenient way for users to create a density from a function (e.g. a log-likelihood) that returns the log of a density (logdensity(::LogFuncDensity)
would simply returnf
).I think it would be great to have a common way to pass around densities that are labeled as such instead of "naked" log-density/likelihood functions. It's kinda awkward/wrong to write
likelihood = some_function
when that function returns a log-likelihood, but it's also awkward/asymmetric to writelog_likelihood = some_function; prior = some_distribution
(having "log" in the one and not in the other).@devmotion , what would be your take on this? Maybe the Turing ecosystem (e.g.
AdvancedMH
) could support this too? And maybe a lightweight package like this could find a home under JuliaStats?I would support this in BAT.jl too, of course (I'm looking for a way for users to define log-likelihoods/densities without adding a dependency on a heavy inference package).
The text was updated successfully, but these errors were encountered: