Pluck feather logo

Pluck

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.

Quick Start

Install Pluck and run your first program:

# In your shell:
git clone --recurse-submodules https://github.com/mlb2251/Pluck.jl.git
cd Pluck.jl

# Compile the rsdd library (required for Pluck)
cd src/RSDD/rsdd
cargo build --release --features ffi
cd ../../..

# In Julia:
using Pkg
Pkg.activate(".")
Pkg.instantiate()
using Pluck
load_pluck_file("programs/simple_example.pluck");

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))