Intro Chapter 1: The Core Language Chapter 2: Forward Models Chapter 3: Conditioning Chapter 4: Inference Algorithms

Example of a generative model using a physic library, example taken from this chapter.

    var dim = function() { return uniform(5, 20) }
    var staticDim = function() { return uniform(10, 50) }
    var shape = function() { return flip() ? 'circle' : 'rect' }
    var xpos = function() { return uniform(100, worldWidth - 100) }
    var ypos = function() { return uniform(100, worldHeight - 100) }
    
    var ground = {shape: 'rect',
                  static: true,
                  dims: [worldWidth, 10],
                  x: worldWidth/2,
                  y: worldHeight}
    
    var falling = function() {
      return {
        shape: shape(),
        static: false,
        dims: [dim(), dim()],
        x: xpos(),
        y: 0}
    };
    
    var fixed = function() {
      return {
        shape: shape(),
        static: true,
        dims: [staticDim(), staticDim()],
        x: xpos(),
        y: ypos()}
    }
    
    var fallingWorld = [ground, falling(), falling(), falling(), fixed(), fixed()]
    physics.animate(1000, fallingWorld);

Flipping Coins

// Flip a fair coin 
flip()
//Do not confuse with the function 
flip

A bit more complex.

// Number of head with 3 Coins
flip() + flip() + flip() 
// You cannot repeat like this:
repeat(1000,flip() + flip() + flip())
// Or like this:
repeat(1000, flip + flip + flip)    
// You should define a thunk function:
var sumFlips = function() {
    flip() + flip() + flip()
}
repeat(1000,sumFlips)
// You can also use a lambda
repeat(1000, function() {flip() + flip() + flip()})

More Coins

// Compute n flips. (In practice, you should use the binomial distribution)
var moreFlips = function(n) {
    (n == 0) ? 0 : flip() + moreFlips(n-1)
}
print(moreFlips(10))
// Again, if you want to repeat, you need to define a thunk function 
viz(repeat(1000,function() {moreFlips(10)}))    
Or, you could also define:
// Create a function that returns a thunk function.  
var moreFlips = function(n) {
    return function() {
        (n == 0) ? 0 : flip() + moreFlips(n-1)()
    }
}
viz(repeat(1000,moreFlips(10)))

// Geometric Distribution 
var geometric = function() {
    (flip()) ? 0 : (1 + geometric())
}

viz(repeat(10000,geometric))

Trick Coins

// flip can be given an argument
var trickCoin = function() { return flip(0.95)}
viz(repeat(20, trickCoin))
// Make a trick coin (thunk)
var makeCoin = function(p) {
    return function() {
        flip(p)
    }
}
viz(repeat(1000,makeCoin(0.95)))

// Bending a coin: take a thunk function and return a thunk function
var bendCoin = function(coin) {
    return function() {
        (coin()) ? flip(0.7) : flip(0.1) 
    }
}

var fairCoin = flip 
var trickCoin = function() {flip(0.95)}

viz.table(repeat(10000,bendCoin(fairCoin)))
viz.table(repeat(10000,bendCoin(trickCoin)))

Example of Causal Model with Medical Symptoms

var lungCancer = flip(0.01)
var TB = flip(0.005)
var stomachFlu = flip(0.1)
var cold = flip(0.2)
var other = flip(0.1)

var cough = 
    (cold && flip(0.5)) ||
    (lungCancer && flip(0.3)) ||
    (TB && flip(0.7)) ||
    (other && flip(0.01))

var fever = 
    (cold && flip(0.3)) ||
    (stomachFlu && flip(0.5)) ||
    (TB && flip(0.1)) ||
    (other && flip(0.01))

var chestPain = 
    (lungCancer && flip(0.5)) ||
    (TB && flip(0.5)) ||
    (other && flip(0.01))

var shortnessOfBreath = 
    (lungCancer && flip(0.5)) ||
    (TB && flip(0.2)) ||
    (other && flip(0.01))

var symptoms = {
  cough: cough,
  fever: fever,
  chestPain: chestPain,
  shortnessOfBreath: shortnessOfBreath
}

symptoms

Distributions and Random Functions

//make a distribution using the Bernoulli constructor:
var b = Bernoulli({p: 0.5})

//sample from it with the sample operator:
print( sample(b) )

//compute the log-probability of sampling true:
print( b.score(true) )

//visualize the distribution:
viz(b)

Some examples of useful distributions for forward models.

// Binomial Distribution 
viz(Binomial({n : 50, p : 0.5}))
viz.table(Binomial({n : 50, p : 0.5}))
viz(Binomial({n : 50, p : 0.1}))
binomial(0.5,50)
// The categorical distribution takes an array and its associated (unnormalized) probabilities. 
viz(Categorical({ ps:[6,7,3,4] , vs: ["blue","orange","green","yellow"] }))
// Omitting ps gives the uniform distribution over vs
viz(Categorical({ vs: ["blue","orange","green","yellow"] }))
print(categorical([6,7,3,4] ,["blue","orange","green","yellow"]))
var vs = ["blue","orange","green","yellow"]
print(categorical({vs}))
// The discrete distribution over integers according to a probability array 
viz(Discrete({ps : [1,2,3,4,5,6]}))
// The extremely useful normal distribution (called Gaussian in webPPL) as it is often taken as a models of 
// the real world when we expect a noise around an observation. 
// mu is the mean, which is intuitively the value on which you distribution is centered 
// sigma is the stnadard deviation, intuitively it represent how far you can go from the mean 
viz(Gaussian({mu : 0, sigma : 1}))
viz(Gaussian({mu : 10, sigma : 1}))
viz(Gaussian({mu : 0, sigma : 10}))
// Uniform Distribution on integers between 0 and n-1 
viz(RandomInteger({n : 11}))
// Continuous Uniform Distribution on reals between a and b 
viz(Uniform({a : 10, b : 20}))

Inference

var SumFlips = function() {
  flip() + flip() + flip()
}
// Infer can transform a thunk function into a distribution
var d = Infer(SumFlips)
viz(d)
print(d.score(1))
print(sample(d))

Logarithmic Score

// Probability are stored with scores, logarithm of probability. 
print(Bernoulli({p : 0.5}).score(true)) 
print(Math.log(0.5))
// Take the usual power for small values (1000 samples of a small probability 0.05)
var badpow = function(x,n) {
  (n == 0) ? 1 : x * badpow(x,n-1)
}
// We cannot distinguish very small values from 0 
print(badpow(0.05,1000) == 0)
// But with logarithm, it is easy 
var logpow = function(x,n) {
  n * Math.log(x)
}
print(logpow(0.05,1000)) 
// Of course, going back to the value gives back 0, as the value is too small for the float representation 
print(Math.exp(logpow(0.05,1000)))

Persistent Randomness

var memFlip = mem(flip)
repeat(1000,memFlip)
var eyeColor = function (person) {
	return uniformDraw(['blue', 'green', 'brown'])
};

[eyeColor('bob'), eyeColor('alice'), eyeColor('bob')]
var flipAlot = mem(function (n) {
  return flip()
});

[[flipAlot(1), flipAlot(12), flipAlot(47), flipAlot(1548)],
 [flipAlot(1), flipAlot(12), flipAlot(47), flipAlot(1548)]]

Example : The Risk Game

// Modelization of a battle in the Risk Game 
var dice = function() {
  return (sample(RandomInteger({n:6})) + 1)
}

// Compute the number of remaining attackers and defenders for a given dice throw
var compare = function (nba,la,nbd,ld,n) {
  if (n == 0) {
    return {nba,nbd}
  }
  else {
    return (la.pop() > ld.pop()) ? compare(nba,la,nbd + 1,ld,n-1) : compare(nba + 1, la, nbd, ld ,n-1)
  }
}

// Define a single round of the risk game, with x attackers and y defenders
var round = function(x,y) {
  var att = sort(repeat(x,dice))
  var def = sort(repeat(y,dice))
  var take = Math.min(x,y)
  var c = compare(0,att,0,def,take)
  return c
}

// A full battle, which is a sucession of rounds. 
var war = function(x,y) {
  if (x == 0 || y == 0) {return {x,y}}
  else {
    var nbatt = Math.min(3,x)
    var nbdef = Math.min(2,y) 
    var c = round(nbatt,nbdef)
    return war(x - c.nba,y - c.nbd)
  }
}

var nbatt = 40 
var nbdef = 40

// Get the number of remaining defenders 
var distfun = function() {
  var res = war(nbatt,nbdef)
  return res.y
}

var dist = Infer(distfun)

viz(dist)