Spaces for "base measures"

For MeasureTheory.jl, we need a nice way to represent some domains, like

  • continuous sets , ℝ₊, and 𝕀 (unit interval)
  • Infinite discrete sets , ℤ₊, ℤ₀₊
  • Also finite sets a:b, but that’s easier

Eventually we’ll need to be able to represent measures on manifolds, either as in Manifolds.jl or as in Bijectors.jl or TransformVariables.jl. That’s further down the line, but I want to be sure to set things up in a way that doesn’t lead to headaches going forward.

To be a little more specific, we define most measures in terms of a density over some base measure. The most common of these is Lebesgue(X) for some X.

We’ve been using Lebesgue(Real) for a while, but…

  • The type hierarchy approach is kind of rigid, for example getting in the way of things like symbolic evaluation
  • There’s not a clean way to have subsets like ℝ₊ and 𝕀.

We could build , ℝ₊, and 𝕀 as part of MeasureTheory, but I want to be sure we can play nice with other packages, especially Manifolds.jl and the JuliaApproximation ecosystem.

What’s a good approach to keep consistency with these packages?

cc @kellertuer @jagot @dlfivefifty

5 Likes

What about sets like:
0 \cup [3,5]

With superposition of measure, this case should be pretty easy :slight_smile:

2 Likes

Thanks for this nice topic.

We currently have a little different approach, maybe call it implicitly. If the points we have on a manifolds (or tangent vectors at a point) are represented in some embedding (imagine the sphere of unit vectors in R2 embedded in R3) we use
check_manifold_point(M,p)(or p ∈ M for short) to check whether p is a point on m in Manifolds.jl.

But sure both @mateuszbaran and @sethaxen can also help how to represent domains for measures. I would really like to have that in a unified way .

1 Like

I’m rather fuzzy about these details, since I am just a physicist :stuck_out_tongue:, but in QuasiArrays.jl, we use the axes machinery to indicate that one or more axes of a quasi-array span a continuous interval using IntervalSets.jl [on the real line; I’m also interested in getting this to work in the complex plane]. @dlfivefifty would know more about the details.

1 Like

Checkout DomainSets.jl, I think it should do what you want

1 Like

Thanks for the responses :slight_smile:

I guess my big concern was just working in terms of one ecosystem or the other, and limiting compatibility with the other or one down the road. But maybe these primitives are simple enough that it’s not really an issue.

2 Likes

Is there actually any fundamental incompatibility between Manifolds.jl and Bijectors.jl? I haven’t looked too closely at the interface of Bijectors.jl but it looks like we could relatively easily make a bridge package between these two, so that distributions on manifolds and their transformations could be defined. Manifolds.jl actually needs some updates regarding distributions (currently it builds upon only Distributions.jl) so I think building distributions on manifolds upon Bijectors.jl may be a good way forward. In any case please don’t feel restricted by what Manifolds.jl does right now in terms of distributions.

@sethaxen opened a great issue about distributions here: https://github.com/JuliaManifolds/Manifolds.jl/issues/57 so you may want to check it out as well :slightly_smiling_face:.

1 Like

Ooo, this is interesting! I played around with this a bit some time ago because I wanted a nice way to handle constraints and whatnot in Bijectors.jl, e.g. you specify domain and codomain and then we return the corresponding bijector. On my “wanted feature”-list indeed was compatibility with Manifolds.jl. I remember running into some issues that resulted in me just going “Ughh, another time maybe”; don’t recall what that was though.

DomainSets.jl looks pretty sick.

Is there actually any fundamental incompatibility between Manifolds.jl and Bijectors.jl? I haven’t looked too closely at the interface of Bijectors.jl but it looks like we could relatively easily make a bridge package between these two, so that distributions on manifolds and their transformations could be defined.

Regarding this in particular, I’d love to chat more:) I could also see a package which bridges the two, but if we could do it “properly” through MeasureTheory.jl, that would of course be preferable. I’ll have a look at it and maybe just make a separate issue for this on Bijectors.jl where we can chat about a “bridge package” while MeasureTheory.jl is still being hammered out.

EDIT: Regarding the last topic, I remember @setaxen had an issue in Bijectors.jl on certain distributions he thought could easily be implemented in Bijectors.jl if we dropped the requirement for bijectivity. At the time we weren’t entirely certain about the design, and so the issue just turned into a discussion about whether or not this was a good idea. I’d be more open to such now that Bijectors.jl is rather stable:)

1 Like

The most pressing thing right now for MeasureTheory.jl is a simple, clean representation for some common spaces. Right now I’m thinking something like this:

abstract type AbstractDomain end

struct RealNumbers <: AbstractDomain end
ℝ = RealNumbers()
Base.show(io::IO, ::RealNumbers) = print(io, "ℝ")

struct PositiveReals <: AbstractDomain end
ℝ₊ = PositiveReals()
Base.show(io::IO, ::PositiveReals) = print(io, "ℝ₊")

struct UnitInterval <: AbstractDomain end
𝕀 = UnitInterval()
Base.show(io::IO, ::RealNumbers) = print(io, "𝕀")

struct Integers <: AbstractDomain end
ℤ = Integers()
Base.show(io::IO, ::Integers) = print(io, "ℤ")

struct NonnegativeIntegers <: AbstractDomain end
ℤ₊ = NonnegativeIntegers()
Base.show(io::IO, ::NonnegativeIntegers) = print(io, "ℤ₊")

struct PositiveIntegers <: AbstractDomain end
ℤ₀₊ = PositiveIntegers()
Base.show(io::IO, ::PositiveIntegers) = print(io, "ℤ₀₊")

Ideally, these could be provided in a separate package, and used for the basis of both DomainSets and Manifolds. But it should be ok anyway, since most of this is at the type level and is easy enough to manipulate.

The point of this is to be able to say things like

@measure Beta(α, β) ≃ Lebesgue(𝕀)

This means

  • Beta is an AbstractMeasure
  • The default parameterization is in terms of α and β. So e.g., Beta(2.0, 3.0) is converted to Beta(α=2.0, β=3.0)
  • basemeasure(::Beta) = Lebesgue(𝕀)
  • It’s an equivalent measure to Lebesgue on the unit interval, meaning it’s absolutely continuous () wrt Lebesgue and vice-versa

Separately from this, we define a logdensity.

2 Likes

You may have swapped the strings to print for NonnegativeIntegers and PositiveIntegers.

1 Like

Good catch, thanks :slightly_smiling_face: