Flip

Signature

flip([p]) -> bool

  • p: real number in [0, 1] (default: p = 0.5)

  • return value: true / false (boolean)

flip is a convenience function: it samples from a Bernoulli distribution.

Relationship to Bernoulli

Conceptual and practical equivalence:

  • flip(p) ~ sample(Bernoulli({p: p}))

When to use which?

  • Use flip when you just need a quick weighted coin flip and a boolean result is fine.

  • Use Bernoulli({p: ...}) when you want an explicit distribution object (e.g. to pass around, call score on it, or observe against it).

Relationship to Categorical

Categorical({ps: ..., vs: ...}) is the general discrete distribution that returns one of the values in vs, with probabilities proportional to ps (ps may be unnormalized).

You can express flip(p) as a categorical distribution over explicit outcomes:

  • sample(Categorical({ps: [p, 1-p], vs: [true, false]}))

When is Categorical better?

  • When you want non-boolean outcomes (e.g. 'H'/'T' or 1/0).

  • When you have more than two outcomes.

Working examples

1) One flip (default p=0.5 and explicit p)

1display(flip());     // default p = 0.5
2display(flip(0.8));  // explicit p = 0.8
true
true
undefined

2) Many flips: repeat + count trues + empirical rate

 1var p = 0.3;
 2var n = 20;
 3
 4var xs = repeat(n, function() { return flip(p); });
 5
 6// bool -> 0/1
 7var ones = map(function(b) { return b ? 1 : 0; }, xs);
 8
 9display(xs);
10display(sum(ones));       // number of trues
11display(listMean(ones));  // empirical rate (~p)
[
  true,  true,  false, false,
  false, true,  false, false,
  false, true,  false, true,
  false, false, false, false,
  false, false, true,  true
]
7
0.35
undefined

3) Same distribution: flip vs Bernoulli vs Categorical (enumerate)

 1var p = 0.7;
 2
 3var modelFlip = function() {
 4  return flip(p);
 5};
 6
 7var modelBern = function() {
 8  return sample(Bernoulli({p: p}));
 9};
10
11var modelCat = function() {
12  return sample(Categorical({ps: [p, 1 - p], vs: [true, false]}));
13};
14
15var d1 = Infer({method: 'enumerate', model: modelFlip});
16var d2 = Infer({method: 'enumerate', model: modelBern});
17var d3 = Infer({method: 'enumerate', model: modelCat});
18
19var summary = function(d) {
20  return {
21    support: d.support(),
22    pTrue: Math.exp(d.score(true)),
23    pFalse: Math.exp(d.score(false))
24  };
25};
26
27display([summary(d1), summary(d2), summary(d3)]);
[
  { support: [ false, true ], pTrue: 0.7, pFalse: 0.30000000000000004 },
  { support: [ false, true ], pTrue: 0.7, pFalse: 0.30000000000000004 },
  { support: [ false, true ], pTrue: 0.7, pFalse: 0.30000000000000004 }
]
undefined

Common pitfall: function vs result (repeat)

  • flip (without parentheses) is a function you can pass: repeat(10, flip)

  • flip() is the result of one flip (a boolean), and cannot be passed as the callback

If you want repeated parameterized flips, wrap it:

  • correct: repeat(10, function() { return flip(0.3); })