1 Examples
Roulette enables programmers to build languages that require the use of inference engines. This section gives examples of languages built on top of Roulette to show concretely how this works.
1.1 Disrupt
| #lang roulette/example/disrupt | package: roulette |
| #lang roulette/example/disrupt/safe | |
> (define first-coin (flip 0.5)) > first-coin
┌─────┬───────────┐
│Value│Probability│
├─────┼───────────┤
│#t │0.5 │
│#f │0.5 │
└─────┴───────────┘
> (define second-coin (flip 0.5)) > (define both-heads (and first-coin second-coin)) > both-heads
┌─────┬───────────┐
│Value│Probability│
├─────┼───────────┤
│#t │0.25 │
│#f │0.75 │
└─────┴───────────┘
> (observe! (not both-heads)) > first-coin
┌─────┬──────────────────┐
│Value│Probability │
├─────┼──────────────────┤
│#t │0.3333333333333333│
│#f │0.6666666666666666│
└─────┴──────────────────┘
> (if (flip 1/2) 'a 'b)
┌─────┬───────────┐
│Value│Probability│
├─────┼───────────┤
│'b │0.5 │
│'a │0.5 │
└─────┴───────────┘
> (define x (flip 1/2)) > (define y (flip 1/2)) > (and x y)
┌─────┬───────────┐
│Value│Probability│
├─────┼───────────┤
│#t │0.25 │
│#f │0.75 │
└─────┴───────────┘
> (observe! x) > (and x y)
┌─────┬───────────┐
│Value│Probability│
├─────┼───────────┤
│#t │0.5 │
│#f │0.5 │
└─────┴───────────┘
syntax
(with-observe body ...+)
> (define x (flip 1/2)) > (define y (flip 1/2))
> (with-observe (observe! x) (query (and x y))) (pmf [#t 0.5] [#f 0.5])
> (query (and x y)) (pmf [#t 0.25] [#f 0.75])
syntax
(with-sample iter body ...+)
> (with-sample 100 (sample (flip 1/3)))
┌─────┬───────────────────┐
│Value│Probability │
├─────┼───────────────────┤
│#t │0.37000000000000016│
│#f │0.6299999999999999 │
└─────┴───────────────────┘
> (define (expectation v) (for/sum ([(val prob) (in-pmf (query v))]) (* val prob))) > (expectation (if (flip 1/2) 5 10)) 7.5
1.2 Bayesian Network
| #lang roulette/example/bn | package: roulette |
A Bayesian network is a common kind of probabilistic graphical model that expresses conditional dependencies between variables. These networks are often described in the Bayesian Interchange Format (BIF). There are many such networks freely available online, including in the BNLearn repository. The BN language interprets Bayesian networks written in the BIF.
"cancer.rkt"
#lang roulette/example/bn
variable Pollution { type discrete [ 3 ] { low, medium, high }; }
variable Smoker { type discrete [ 2 ] { True, False }; }
variable Cancer { type discrete [ 2 ] { True, False }; }
variable Xray { type discrete [ 2 ] { positive, negative }; }
variable Dyspnoea { type discrete [ 2 ] { True, False }; }
probability ( Pollution ) {
table 0.5, 0.4, 0.1;
}
probability ( Smoker ) {
table 0.3, 0.7;
}
probability ( Cancer | Pollution, Smoker ) {
(low, True) 0.03, 0.97;
(medium, True) 0.03, 0.97;
(high, True) 0.05, 0.95;
(low, False) 0.001, 0.999;
(medium, False) 0.001, 0.999;
(high, False) 0.02, 0.98;
}
probability ( Xray | Cancer ) {
(True) 0.9, 0.1;
(False) 0.2, 0.8;
}
probability ( Dyspnoea | Cancer ) {
(True) 0.65, 0.35;
(False) 0.3, 0.7;
}
This Bayesian network is the famous "cancer" example that describes the relationship between several variables and whether a patient has lung cancer. Running this file in DrRacket allows one to explore the network with all the constructs from Disrupt in the interactions area. Additionally, the module exports all the variables, making them available to Disrupt programs via require.
> Cancer
┌──────┬────────────────────┐
│Value │Probability │
├──────┼────────────────────┤
│'True │0.011629999999999998│
│'False│0.98837 │
└──────┴────────────────────┘
> (observe! (equal? Xray 'positive)) > Cancer
┌──────┬────────────────────┐
│Value │Probability │
├──────┼────────────────────┤
│'True │0.050288025905515975│
│'False│0.949711974094484 │
└──────┴────────────────────┘
This interaction shows the posterior probability that a patient has lung cancer given that they have a positive X-ray result. Notice that the posterior probability of Cancer only marginally increases with a positive test result. Many people are surprised by this phenomenon, which is known as the base rate fallacy.
1.3 Dice
| #lang roulette/example/dice | package: roulette |
Dice is a small discrete probabilistic programming language. It was the first functional language to use knowledge-compilation-based probabilistic inference.
"noisy-or.rkt"
#lang roulette/example/dice
let n0 = flip 0.5 in
let n4 = flip 0.5 in
let n1 = if n0 then flip 0.8 else flip 0.1 in
let n21 = if n0 then flip 0.8 else flip 0.1 in
let n22 = if n4 then flip 0.8 else flip 0.1 in
let n33 = if n4 then flip 0.8 else flip 0.1 in
let n2 = (n21 || n22) in
let n31 = if n1 then flip 0.8 else flip 0.1 in
let n32 = if n2 then flip 0.8 else flip 0.1 in
let n3 = (n31 || (n32 || n33)) in
n3
Most programs should run out of the box, but there are a few limitations. A small number of operations are not supported. The implementation does not perform typechecking, so evaluating an ill-typed program is undefined behavior. Functions are not compiled modularly, and evaluation follows the "eager" strategy.