A simple probabilistic Julia program
Consider the following Julia code:
The function f
calls three functions provided by Gen, each of which returns a random value, sampled from a certain probability distribution:
uniform_discrete(a, b)
returns an integer uniformly sampled from the set{a, .., b}
bernoulli(p)
returnstrue
with probabilityp
andfalse
with probability1-p
.categorical(probs)
returns the integeri
with probabilityprobs[i]
fori
in the set{1, .., length(probs)}
.
These are three of the many probability distributions that are provided by Gen.
The function f
first sets the initial value of n
to a random value drawn from the set of integers {1, .., 10}
:
Then, with probability p
, it multiplies by n
by two:
Then, it samples an integer in the set {1, ..., 20}
. With probability 0.5
the integer is n
, and with probability 0.5
it is uniformly chosen from the remaining 19
integers. It returns this sampled integer:
If we run this function many times, we can see the probability distribution on its return values. The distribution depends on the argument p
to the function:
Suppose we wanted to see what the distribution on return values would be if the initial value of n
was 2
. Because we don’t know what random values were sampled during a given execution, we can’t use simulations of f
to answer this question. We would have to modify f
first, to return the initial value of n
:
Then, we could only include executions in which our desired events did happen, when making our histogram:
Suppose we wanted to ask more questions. We might need to modify each time we have a new question, to make sure that the function returns the particular pieces of information about the execution that the question requires.
Note that if the function always returned the value of every random choice, then these values are sufficient to answer any question using executions of the function, because all states in the execution of the function are deterministic given the random choices. We will call the record of all the random choies a trace. In order to store all the random choices in the trace, we need to come up with a unique name or address for each random choice.
Below, we implement the trace as a dictionary that maps addresses of random choices to their values. We use a unique Julia Symbol
for each address:
We run the function, and get the return value and the trace:
However, this program looks more complicated than the original program. We could make the syntax for tracing more concise:
We run the function, and get the return value and the trace:
Now that we have instrumented the function, we can answer the following different question without needing to modify the function:
“What is the probability that the branch was taken, given that the result took the value 4?”
What about a result value that is greater than 10?
Last updated
Was this helpful?