zenna / Sigma.jl

Sigma is a probabilistic programming environment implemented in Julia
Other
68 stars 3 forks source link

Random Composite Types #34

Open zenna opened 9 years ago

zenna commented 9 years ago

The mechanism for RandVars whose rangetype is some arbitrary Julia type, needs to be fleshed out. This, surprisingly, hasn't been much of an issue before because we could just use normal types, whose composite elements where RandVars, e.g.;

immutable Point
  x::RandVar{Real}
  y::RandVar{Real}
end

But this breaks down easily, I would like to be able to do something like

P = RandVar{Point}(normal(0,1),normal(0,1))
rand(P,P.x + Y.y > 0)

Additionally the need for this becomes clear when random variables interact with non random variables. Currently, Sigma supports properly supports things like

X = normal(0,1)
Y = X + 10 # Y is a random variable

But what about

a = [1,2,3,4,5]
X = discreteuniform(1,4)
Y = a[X]

Y of course, should be a random variable

zenna commented 9 years ago

One proposal for the latter case is something this:

immutable RandVarChoice{T} <: RandVar{T}
  base::Array{T}
  I::RandVar #The Random Index
end

getindex{T<:RandVar{Int}}(A::Array, i0::T) = RandVarChoice(A, i0)

call(X::RandVarChoice,ω) = X.base[call(X.I,ω)]

# Functions originally defined on base type, e..g

function (==){T}(X::RandVarChoice{T}, Y::RandVarChoice{T})
  RandVarSymbolic{Bool}(:(call($X,ω) == call($Y,ω)))
end

The problems with this approach are

  1. A RandVarChoice can't in many ways be used as an element of the base type. We can't for instance, extract a property using the dot notation
  2. Consider these two different scenarios
normal_points = [Point(i,-i) for i = 1:10]
rand_points = [RandVar{Point}(Point(normal(i,1),normal(-i,1)) for i =1:10]
rand_index = discreteuniform(1,10)

# What are these?
normal_points[rand_index].x + normal_points[rand_index].y #1
normal_points[rand_index] == normal_points[rand_index]  #2
rand_points[1].x + rand_points[2].y #3
rand_points[rand_index].x + rand_points[rand_index].y #4
  1. When we index the normal array with a random index, as in our proposal, we get back this RandVarChoice. But then we try to access properties x and y from it, which is invalid. One solution is to use a get method
get(normal_points[rand_index],:x)

But then I've lost compatibility with a lot of existing code.

  1. Why should functions of RandVarChoce e.g. (==) evaluate to RandVarSymbolics. What should it be?
  2. The result of #1 and of #3 should both be Real valued random variables, but for different reasons. The latter because the properties x and y and themselves real random variables, and the former because the Point itself is randomly chosen, even though x and y are just normal Reals. #4 has both of these kinds of randomness.

For #3 once a bit of random is chosen, we have a Point. Hence the addition should be a RandVar which given some random input, creates the Point or set of, and does the addition on the point Points or sets of Points. This seems to fall under RandVarSymbolic but i) We cannot overload fields and so we will have the parameter problem RandVarSymbolic ii) What about use with the solver? Is all our work there, and with RandVarMeta redundant? iii) RandVarSymbolic currently has representation compactness issues, can we fix these.

concrete proposal: