alltom.com

Intro to WebPPL, a Probabilistic Programming Language (PPL)

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.

Inference

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…