Pluck - A Probabilistic Programming Language

2 min read Original article ↗

Pluck feather logo

Probabilistic Programming with Lazy Inference

Pluck is a probabilistic programming language with efficient inference based on lazy knowledge compilation. It supports higher-order functions, many recursive programs, and recursive types.

Expressive, Lazy, Functional Programs

Pluck programs are expressive functional programs, that can also make (discrete) random choices. It supports lazy algebraic data types, higher-order functions, and recursion.

Pluck code:

(define-type tree (Leaf) (Node nat tree tree))

(define (random-tree)
  (if (flip 0.6)
    (Leaf)
    (let ((left  (random-tree))
          (right (random-tree)))
      (Node (geom 0.5) left right))))

Sampled values for random-tree:

Node 2 (Leaf) (Node 0 (Leaf) (Leaf))
Leaf
Node 1 (Leaf) (Leaf)

Exact Inference

Pluck can compute the exact probability distributions of many expressions.

Pluck query:

;; What is the probability that a random tree has fewer than 4 nodes?
(query tree-size-small
  (Marginal (< (length (nodes (random-tree))) 4)))

Output:

tree-size-small:
  true   0.855
  false  0.145

Bayesian Conditioning

Pluck can also compute the exact conditional (i.e., posterior) distribution of an expression, given some Boolean condition.

Pluck code:

(query bst-given-size8-bounded
  (let ((t (random-tree)))
    (Posterior
      (isBST t)
      (and (== (size t) 8) (all-nodes-between t 0 10)))))

Output

bst-given-size8-bounded:
  false   0.9999999999998865
  true    1.1346479311669095e-13

Posterior Sampling

Pluck can draw exact samples from posterior distributions, even in infinite spaces.

Pluck code:

(query tree-samples-given-size8-bst-bounded
  (let ((t (random-tree)))
    (PosteriorSamples
      t
      (and (== (size t) 8)
           (all-nodes-between t 0 10)
           (isBST t))
      5)))

Sampled values for tree-samples-given-size8-bst-bounded:

(Node 9 (Node 7 (Node 6 (Node 4 (Node 3 (Node 2 (Node 1 (Leaf) (Leaf)) (Leaf)) (Leaf)) (Node 5 (Leaf) (Leaf))) (Leaf)) (Leaf)) (Leaf))
(Node 8 (Node 5 (Node 4 (Node 2 (Node 1 (Leaf) (Leaf)) (Node 3 (Leaf) (Leaf))) (Leaf)) (Node 6 (Leaf) (Leaf))) (Node 9 (Leaf) (Leaf)))
(Node 8 (Node 7 (Node 5 (Node 1 (Leaf) (Node 4 (Node 2 (Leaf) (Node 3 (Leaf) (Leaf))) (Leaf))) (Node 6 (Leaf) (Leaf))) (Leaf)) (Leaf))
(Node 8 (Node 6 (Node 3 (Node 1 (Leaf) (Node 2 (Leaf) (Leaf))) (Node 4 (Leaf) (Node 5 (Leaf) (Leaf)))) (Node 7 (Leaf) (Leaf))) (Leaf))
(Node 8 (Node 7 (Node 6 (Node 1 (Leaf) (Node 3 (Node 2 (Leaf) (Leaf)) (Node 5 (Node 4 (Leaf) (Leaf)) (Leaf)))) (Leaf)) (Leaf)) (Leaf))