Overview
The desiderata for Omega are to increase the expressiveness of probabilistic programming, with minimal sacrifices to performance.
- Support conditioning on arbitrary predicates
- Support conditioning on distributional propereties
- Support causal inference
- Be based on solid probabilistic foundations (i.e., measure theory)
- Integrate seamlessly with Julia
- Be fast
Some of these points are contradictory. For example only pure functions exist in measure theory, whereas julia programs may have side effects. Also there are tradeoffs between being as fast as possible, while being as general as possible.
We think we have found a good compromise in Julia.
MiniOmega
Omega is structured around two primary abstract types Ω
and RandVar
.
module MiniOmega
using Random
mutable struct Ω <: Random.AbstractRNG
data::Dict{Int, Any}
i::Int
end
Ω() = Ω(Dict(), 0)
function Base.rand(w::Ω, args...)
w.i += 1
get!(w.data, w.i, rand(Random.GLOBAL_RNG, args...))
end
Base.rand(w::Ω, args...) = (w.i += 1; get!(w.data, w.i, rand(args...)))
Base.rand(w::Ω, dims::Vararg{Integer,N} where N) = (w.i += 1; get!(w.data, w.i, rand(dims)))
struct RandVar
f::Function
end
(rv::RandVar)(w::Ω) = (w.i = 0; rv.f(w))
Base.rand(x::RandVar) = x(Ω())
cond(x::RandVar, y::RandVar) = RandVar(rng -> y(rng) ? x(rng) : error())
"Rejetion Sampling"
Base.rand(x::RandVar) = try x(Ω()) catch; rand(x) end
export RandVar, Ω
end
## Example
using Main.MiniOmega
x_(rng) = rand(rng)
x = RandVar(x_)
ω = Ω()
x(ω)