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);
// 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))
// 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)))
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
//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}))
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))
// 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)))
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)]]
// 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)