I didn't get WebPPL at first. Or PPLs (Probabilistic Programming Languages) generally.
Nearly every language can pick random numbers:
uniform(0, 1)
And nearly every language can flip coins:
repeat(10, function() {
flip(0.3) ? 'Heads' : 'Tails'
})
In those ways, WebPPL is like any other language
… but other languages don't have Infer.
Infer(…) returns distributions. How often does a function return this value vs that value.
So Infer can confirm that yes, uniform(0, 1) returns a fairly even distribution of numbers between 0 and 1, and yes, flip(0.3) yields heads about 30% of the time:
viz(Infer({method: 'MCMC', samples: 10000}, function() {
return {x: uniform(0, 1)}
}))
viz(Infer(function() {
return flip(0.3) ? 'Heads' : 'Tails'
}))
… But it can go backwards, too!
Let's say you wrote a program to generate random ASCII art of a creature-buddy snacking on pellets:
var trail = function(steps, sawPac, pacProb) {
if (steps == 0) return ''
if (sawPac) return 'o' + trail(steps-1, sawPac, pacProb)
if (flip(pacProb)) {
return 'ᗧ ' + trail(steps-1, true)
} else {
return '.' + trail(steps-1, sawPac, pacProb)
}
}
var p = 0.5
print(trail(30, false, p))
print(trail(30, false, p))
print(trail(30, false, p))
print(trail(30, false, p))
And now you're like, "What p do I pick if I want 'em to make it to the other side more often?" Well, let's infer p:
var trail = function(steps, sawPac, pacProb) {
if (steps == 0) return ''
if (sawPac) return 'o' + trail(steps-1, sawPac, pacProb)
if (flip(pacProb)) {
return 'ᗧ ' + trail(steps-1, true)
} else {
return '.' + trail(steps-1, sawPac, pacProb)
}
}
Infer({method: 'MCMC', samples: 10000}, function() {
// Pick a random pacProb.
var p = uniform(0, 1)
// Bail unless we generate a trail with our friend at the far end.
condition(trail(30, false, p).slice(28, 30) == 'ᗧ ')
return {p: p}
})
It looks like values between 0.025 and 0.1 are good?
var trail = function(steps, sawPac, pacProb) {
if (steps == 0) return ''
if (sawPac) return 'o' + trail(steps-1, sawPac, pacProb)
if (flip(pacProb)) {
return 'ᗧ ' + trail(steps-1, true)
} else {
return '.' + trail(steps-1, sawPac, pacProb)
}
}
var p = 0.06
print(trail(30, false, p))
print(trail(30, false, p))
print(trail(30, false, p))
print(trail(30, false, p))
ML achieved.
To be continued…