Skip to content

Commit 2e5cf4a

Browse files
committed
populate from MeasureTheory
1 parent b7ecab3 commit 2e5cf4a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2016
-1
lines changed

Project.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@ uuid = "fa1605e6-acd5-459c-a1e6-7e635759db14"
33
authors = ["Chad Scherrer <[email protected]> and contributors"]
44
version = "0.1.0"
55

6+
[deps]
7+
ConcreteStructs = "2569d6c7-a4a2-43d3-a901-331e8e4be471"
8+
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
9+
MappedArrays = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900"
10+
NamedTupleTools = "d9ec5142-1e00-5aa0-9d6a-321866360f50"
11+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
12+
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
13+
StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
14+
615
[compat]
716
julia = "1"
817

src/MeasureBase.jl

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,68 @@
11
module MeasureBase
22

3-
# Write your package code here.
3+
4+
using Random
5+
6+
using ConcreteStructs
7+
using MLStyle
8+
9+
export
10+
export sampletype
11+
12+
export AbstractMeasure
13+
14+
abstract type AbstractMeasure end
15+
16+
sampletype::AbstractMeasure) = typeof(testvalue(μ))
17+
18+
# sampletype(μ::AbstractMeasure) = sampletype(basemeasure(μ))
19+
20+
"""
21+
logdensity(μ::AbstractMeasure{X}, x::X)
22+
23+
Compute the logdensity of the measure μ at the point x. This is the standard way
24+
to define `logdensity` for a new measure. the base measure is implicit here, and
25+
is understood to be `basemeasure(μ)`.
26+
27+
Methods for computing density relative to other measures will be
28+
"""
29+
function logdensity end
30+
31+
include("paramorder.jl")
32+
include("exp.jl")
33+
include("domains.jl")
34+
include("utils.jl")
35+
include("absolutecontinuity.jl")
36+
include("basemeasures.jl")
37+
include("parameterized.jl")
38+
include("macros.jl")
39+
include("combinators/weighted.jl")
40+
include("combinators/superpose.jl")
41+
include("combinators/product.jl")
42+
include("combinators/for.jl")
43+
include("combinators/power.jl")
44+
include("combinators/likelihood.jl")
45+
include("combinators/elementwise.jl")
46+
include("combinators/spikemixture.jl")
47+
include("rand.jl")
48+
include("probability/dirac.jl")
49+
include("probability/normal.jl")
50+
include("probability/studentt.jl")
51+
include("probability/cauchy.jl")
52+
include("probability/laplace.jl")
53+
include("probability/uniform.jl")
54+
include("probability/beta.jl")
55+
include("probability/gumbel.jl")
56+
include("probability/exponential.jl")
57+
# include("probability/mvnormal.jl")
58+
include("probability/inverse-gamma.jl")
59+
include("probability/bernoulli.jl")
60+
include("probability/poisson.jl")
61+
include("probability/binomial.jl")
62+
# include("probability/LKJL.jl")
63+
include("probability/negativebinomial.jl")
64+
include("density.jl")
65+
# include("pushforward.jl")
66+
include("kernel.jl")
467

568
end

src/MeasureTheory.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module MeasureTheory
2+
3+
end # module

src/absolutecontinuity.jl

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
2+
"""
3+
≪(μ,ν)
4+
5+
# Absolute continuity
6+
7+
A measure μ is _absolutely continuous_ with respect to ν, written μ ≪ ν, if
8+
ν(A)==0 implies μ(A)==0 for every ν-measurable set A.
9+
10+
Less formally, suppose we have a set A with ν(A)==0. If μ(A)≠0, then there can
11+
be no way to "reweight" ν to get to μ. We can't make something from nothing.
12+
13+
This "reweighting" is really a density function. If μ≪ν, then there is some
14+
function f that makes `μ == ∫(f,ν)` (see the help section for `∫`).
15+
16+
We can get this f directly via the Radon-Nikodym derivative, `f == 𝒹(μ,ν)` (see
17+
the help section for `𝒹`).
18+
19+
Note that `≪` is not a partial order, because it is not antisymmetric. That is
20+
to say, it's possible (in fact, common) to have two different measures `μ` and
21+
`ν` with `μ ≪ ν` and `ν ≪ μ`. A simple example of this is
22+
```
23+
μ = Normal()
24+
ν = Lebesgue(ℝ)
25+
```
26+
27+
When `≪` holds in both directions, the measures μ and ν are _equivalent_,
28+
written `μ ≃ ν`. See the help section for `≃` for more information.
29+
"""
30+
function end
31+
32+
33+
export
34+
35+
"""
36+
≃(μ,ν)
37+
38+
# Equivalence of Measure
39+
40+
Measures μ and ν on the same space X are equivalent, written `μ ≃ ν`, if `μ ≪ ν`
41+
and `ν ≪ μ`. Note that this is often written `~` in the literature, but this is
42+
overloaded in probabilistic programming, so we use this alternate notation.
43+
44+
Also note that equivalence is very different from equality. For two equivalent
45+
measures, the sets of non-zero measure will be identical, but what that measure
46+
is in each case can be very different.
47+
"""
48+
function (μ,ν)
49+
returnν && νμ)
50+
end
51+
52+
export representative
53+
54+
"""
55+
representative(μ::AbstractMeasure) -> AbstractMeasure
56+
"""
57+
function representative(μ)
58+
function f(μ)
59+
# Check if we're done
60+
isprimitive(μ) && return μ
61+
62+
ν = basemeasure(μ)
63+
64+
# TODO: Make sure we don't leave the equivalence class
65+
# Make sure not to leave the equivalence class
66+
# (ν ≪ μ) || return μ
67+
68+
return ν
69+
end
70+
71+
fix(f, μ)
72+
end
73+
74+
# TODO: ≪ needs more work
75+
function (μ, ν)
76+
μ == ν && return true
77+
representative(μ) representative(ν) && return true
78+
end

src/basemeasures.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
export basemeasure
2+
3+
"""
4+
basemeasure(μ)
5+
6+
Many measures are defined in terms of a logdensity relative to some base
7+
measure. This makes it important to be able to find that base measure.
8+
9+
For measures not defined in this way, we'll typically have `basemeasure(μ) == μ`.
10+
"""
11+
function basemeasure end
12+
13+
include("basemeasures/trivial.jl")
14+
include("basemeasures/lebesgue.jl")
15+
include("basemeasures/counting.jl")
16+
17+
18+
19+
export isprimitive
20+
21+
"""
22+
isprimitive(μ)
23+
24+
Most measures are defined in terms of other measures, for example using a
25+
density or a pushforward. Those that are not are considered (in this library,
26+
it's not a general measure theory thing) to be _primitive_. The canonical
27+
example of a primitive measure is `Lebesgue(X)` for some `X`.
28+
29+
The default method is
30+
isprimitive(μ) = false
31+
32+
So when adding a new primitive measure, it's necessary to add a method for its type
33+
that returns `true`.
34+
"""
35+
isprimitive(μ) = false

src/basemeasures/counting.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export CountingMeasure
2+
3+
struct CountingMeasure{X} <: AbstractMeasure end
4+
5+
function Base.show(io::IO, μ::CountingMeasure{X}) where {X}
6+
io = IOContext(io, :compact => true)
7+
print(io, "CountingMeasure(", X, ")")
8+
end
9+
10+
CountingMeasure(X) = CountingMeasure{X}()
11+
12+
basemeasure::CountingMeasure) = μ
13+
14+
isprimitive(::CountingMeasure) = true
15+
16+
# sampletype(::CountingMeasure{ℝ}) = Float64
17+
# sampletype(::CountingMeasure{ℝ₊}) = Float64
18+
# sampletype(::CountingMeasure{𝕀}) = Float64
19+
20+
sampletype(::CountingMeasure) = Int
21+
22+
testvalue::CountingMeasure{X}) where {X} = testvalue(X)
23+
24+
logdensity(::CountingMeasure, x) = zero(float(x))
25+
26+
# (::CountingMeaure)(s) = length(Set(s))

src/basemeasures/lebesgue.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Lebesgue measure
2+
3+
export Lebesgue
4+
5+
struct Lebesgue{X} <: AbstractMeasure end
6+
7+
function Base.show(io::IO, μ::Lebesgue{X}) where X
8+
io = IOContext(io, :compact => true)
9+
print(io, "Lebesgue(", X, ")")
10+
end
11+
12+
Lebesgue(X) = Lebesgue{X}()
13+
14+
basemeasure::Lebesgue) = μ
15+
16+
isprimitive(::Lebesgue) = true
17+
18+
sampletype(::Lebesgue{ℝ}) = Float64
19+
sampletype(::Lebesgue{ℝ₊}) = Float64
20+
sampletype(::Lebesgue{𝕀}) = Float64
21+
22+
testvalue(::Lebesgue{ℝ}) = 0.0
23+
testvalue(::Lebesgue{𝕀}) = 0.5
24+
testvalue(::Lebesgue{ℝ₊}) = 1.0
25+
testvalue(::Lebesgue{<:Real}) = 0.0
26+
27+
logdensity(::Lebesgue, x) = zero(x)

src/basemeasures/trivial.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export TrivialMeasure
2+
3+
struct TrivialMeasure <: AbstractMeasure end
4+
5+
sampletype(::TrivialMeasure) = Nothing

src/combinators/elementwise.jl

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
export
2+
3+
@concrete terse struct ElementwiseProductMeasure{T} <: AbstractMeasure
4+
data :: T
5+
6+
ElementwiseProductMeasure(μs...) = new{typeof(μs)}(μs)
7+
ElementwiseProductMeasure(μs) = new{typeof(μs)}(μs)
8+
end
9+
10+
Base.size::ElementwiseProductMeasure) = size.data)
11+
12+
function Base.show(io::IO, μ::ElementwiseProductMeasure)
13+
io = IOContext(io, :compact => true)
14+
print(io, join(string.(μ.data), ""))
15+
end
16+
17+
function Base.show_unquoted(io::IO, μ::ElementwiseProductMeasure, indent::Int, prec::Int)
18+
if Base.operator_precedence(:*) prec
19+
print(io, "(")
20+
show(io, μ)
21+
print(io, ")")
22+
else
23+
show(io, μ)
24+
end
25+
return nothing
26+
end
27+
28+
Base.length(m::ElementwiseProductMeasure{T}) where {T} = length(m.data)
29+
30+
function ::ElementwiseProductMeasure{X}, ν::ElementwiseProductMeasure{Y}) where {X,Y}
31+
data =.data..., ν.data...)
32+
ElementwiseProductMeasure(data...)
33+
end
34+
35+
function (μ, ν::ElementwiseProductMeasure{Y}) where {Y}
36+
data = (μ, ν.data...)
37+
ElementwiseProductMeasure(data...)
38+
end
39+
40+
function ::ElementwiseProductMeasure{X}, ν::N) where {X, N <: AbstractMeasure}
41+
data =.data..., ν)
42+
ElementwiseProductMeasure(data...)
43+
end
44+
45+
function ::M, ν::N) where {M <: AbstractMeasure, N <: AbstractMeasure}
46+
data = (μ, ν)
47+
ElementwiseProductMeasure(data...)
48+
end
49+
50+
function ::AbstractMeasure, ℓ::LogLikelihood)
51+
data = (μ, ℓ)
52+
ElementwiseProductMeasure(data...)
53+
end
54+
55+
function logdensity(d::ElementwiseProductMeasure, x)
56+
sum((logdensity(dⱼ, x) for dⱼ in d.data))
57+
end
58+
59+
function sampletype(d::ElementwiseProductMeasure)
60+
@inbounds sampletype(first(d.data))
61+
end
62+
63+
basemeasure::ElementwiseProductMeasure) = @inbounds basemeasure(first(d.data))

0 commit comments

Comments
 (0)