tpapp / TransformVariables.jl

Transformations to contrained variables from ℝⁿ.
Other
66 stars 14 forks source link

[not an issue] transform for a given distribution #74

Closed briochemc closed 3 years ago

briochemc commented 3 years ago

Given a distribution d::UnivariateContinuousDistribution from Distributions.jl, I would like to be able get a suitable change of variables and using TransformVariables seems like it provides exactly the right machinery for that. So I thought maybe I could define something like

as(Real, d) = as(Real, support(d).lb, support(d).ub)

but this does not work because Inf and are not the same. So my questions are

  1. How do you guys go about doing that?
  2. Is this even a good idea/use of TransformVariables, or should I look for something else?
briochemc commented 3 years ago

FYI, my use case and workaround is something like

using TransformVariables, Distributions, ForwardDiff
to∞(x) = isinf(x) ? TransformVariables.Infinity{x>0}() : x # <- convert `Inf` to `∞`
lb_domain(d::ContinuousUnivariateDistribution) = to∞(minimum(d))
ub_domain(d::ContinuousUnivariateDistribution) = to∞(maximum(d))
import TransformVariables: transform
transform(d::ContinuousUnivariateDistribution) = as(Real, lb_domain(d), ub_domain(d)) # <- transform a distribution directly
f(d::ContinuousUnivariateDistribution) = x -> transform(d)(x)     # make it into a simple function
∇f(d::ContinuousUnivariateDistribution) = x -> ForwardDiff.derivative(f(d), x)     # 1st derivative
∇²f(d::ContinuousUnivariateDistribution) = x -> ForwardDiff.derivative(∇f(d), x)     # 2nd derivative
invf(d::ContinuousUnivariateDistribution) = x -> inverse(transform(d))(x)       # inverse transform

Could you comment on this code and on how to improve it if possible?

tpapp commented 3 years ago

Sorry for not replying earlier. Generally, some special casing like this is the way to go.

Note that the construct will not be type stable because infinite domains require another kind of transformation anyway. This was the motivation for not supporting Inf directly in the API of this package, so that the type instability is not hidden from the user.

briochemc commented 3 years ago

No worries! Thanks for replying! Am I correct in that the

f(d::ContinuousUnivariateDistribution) = x -> transform(d)(x)     # make it into a simple function

line acts as a function barrier to type instability?

briochemc commented 3 years ago

(BTW, it would be great if you could chime in on https://github.com/JuliaStats/Distributions.jl/pull/1217, since you submitted the affine-trasnformation-for-MvNormal PR 🙏 😃)

tpapp commented 3 years ago

Yes. Generally I think that the type information (for domain finiteness) could be preserved since it is specific to the distribution, it's just that maximum and minimum loses it by returning Inf::Float64.

I will try to look at that PR, just can't promise anything since I am very busy now. Feel free to ping me in two weeks there if I don't get around to it.