On this page:
1.1 Disrupt
flip
query
observe!
with-observe
sample
with-sample
in-pmf
pmf?
1.2 Bayesian Network
1.3 Dice
9.2

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

Disrupt is an example discrete probabilistic programming language built on top of the RSDD inference engine.
> (define first-coin (flip 0.5))
> first-coin

┌─────┬───────────┐

│Value│Probability│

├─────┼───────────┤

│#t   │0.5        

│#f   │0.5        

└─────┴───────────┘

The flip construct returns a Boolean where #t has the given probability. Evaluating first-coin at the REPL prints out its probability distribution.
> (define second-coin (flip 0.5))
> (define both-heads (and first-coin second-coin))
> both-heads

┌─────┬───────────┐

│Value│Probability│

├─────┼───────────┤

│#t   │0.25       

│#f   │0.75       

└─────┴───────────┘

Now, both-heads is a Boolean that takes on the value #t when both coins are also #t.
> (observe! (not both-heads))
> first-coin

┌─────┬──────────────────┐

│Value│Probability       

├─────┼──────────────────┤

│#t   │0.3333333333333333│

│#f   │0.6666666666666666│

└─────┴──────────────────┘

Observing both-heads, specifically that it is #f, changes the probability of first-coin. Conditional on both-heads being #f, the probability first-coin being #t is 1/3.

procedure

(flip p)  boolean?

  p : (real-in 0 1)
Returns a Boolean where #t has probability p and #f has probability (- 1 p).
> (if (flip 1/2) 'a 'b)

┌─────┬───────────┐

│Value│Probability│

├─────┼───────────┤

│'b   │0.5        

│'a   │0.5        

└─────┴───────────┘

procedure

(query e)  pmf?

  e : any/c
Returns the probability mass function (PMF) associated with e. In other words, query performs top-level inference. See in-pmf for an example of how to use the result of this function.
> (query (flip 1/2))

(pmf [#t 0.5] [#f 0.5])

procedure

(observe! e)  void?

  e : boolean?
Conditions the current execution on e evaluating to #t.
> (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 ...+)

Delimits observations to the dynamic extent of body. After body has finished, any observations executed during body are forgotten.
> (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])

procedure

(sample e)  any/c

  e : any/c
Samples a concrete value from the given probabilistic value.
> (sample (flip 1/2))

#t

syntax

(with-sample iter body ...+)

Runs the body expression iter times, producing a probabilistic value according to the sampling distribution. Note that observations are automatically delimited (using with-observe) inside of body to prevent observations from leaking between samples.
> (with-sample 100
    (sample (flip 1/3)))

┌─────┬───────────────────┐

│Value│Probability        

├─────┼───────────────────┤

│#t   │0.37000000000000016│

│#f   │0.6299999999999999 │

└─────┴───────────────────┘

procedure

(in-pmf e)  stream?

  e : pmf?
Sequence constructor for PMFs.
> (define (expectation v)
    (for/sum ([(val prob) (in-pmf (query v))])
      (* val prob)))
> (expectation (if (flip 1/2) 5 10))

7.5

procedure

(pmf? e)  boolean?

  e : any/c
Predicate for PMFs.

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.