liveBook · Manning

Rejection sampling

As explained in Fabulous Adventures in Data Structures and Algorithms

The rejection algorithm samples candidate outcomes and discards candidates that fail a probabilistic acceptance test.

Rejection sampling generates candidates from an easy-to-sample region, accepts candidates according to a probabilistic test, and repeats until one succeeds. The accepted outcomes follow the target weights because accepted area is proportional to target density. section 12.10 section 15.5

The algorithm adapts to discrete and continuous distributions:

  • For categorical weights, choose a row uniformly, choose a column uniformly, and return the row when the column falls below its weight; otherwise reject and retry. section 12.10
  • For a continuous target, sample x from a helper distribution, sample a height beneath its scaled density, and accept x when the height is below the target PDF. section 15.5
  • Choose a helper whose support covers the target and scale its non-normalized PDF so it stays above the target everywhere. section 15.5

Clamping a normal distribution

To remove impossible or undesirable tails, sample from the original normal distribution and reject values outside the permitted interval. A normal distribution centered at 0.5 with spread 0.2 can be clamped to [0.0, 1.0] using scale factor 1.0. section 15.5.1

Listing 15.6 Implementing the rejection-sampling algorithm
public sealed record class Rejection(
    Func<double, double> Target,
    IContinuousDistribution Helper,
    double Scale
    ) : IContinuousDistribution
{
    public double Weight(double x) => Target(x);
    public double Sample()
    {
        while(true)
        {
            double x = Helper.Sample();
            double weight = Weight(x);
            if (weight == 0.0)
                continue; #1
            double max = Helper.Weight(x) * Scale;
            double y = ContinuousUniform.Distribution(0.0, max).Sample();
            if (y <= weight)
                return x;        
        }
    }
}

Browse a compact C# implementation that samples from a helper distribution, computes the target weight, and retries rejected points. section 15.5

Rejection sampling is simple but can be inefficient: the retry loop has no finite worst-case bound, and selecting a well-fitting helper distribution and scale factor may require manual expertise. The alias algorithm is preferable for many discrete distributions. section 15.5.2 section 12.13

How Fabulous Adventures in Data Structures and Algorithms covers it

How deep it goes
Works through dartboard intuition, acceptance code, helper scaling, clamping, and unbounded retry costs.
Examples
Demonstrates weighted integer categories, a two-humped continuous density, and a normal distribution clamped to [0.0, 1.0].
What it assumes
Assumes familiarity with probability distributions, PDFs, uniform sampling, and non-normalized weights while defining helper and target roles.
What you can do after
Build it from scratch in C# using uniform samplers, a helper distribution, a target weight function, and an acceptance loop.
How it connects
Connects categorical distributions, continuous distributions, probability density functions, normal distributions, inverse transform sampling, and the alias algorithm.

Also explained in

Compare how 3 books explain rejection sampling →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Fabulous Adventures in Data Structures and Algorithms. The section links point to the parts of the book it draws on.