Metropolis-Hastings, or how to sample without the integral

The Metropolis-Hastings Algorithm is not trending anywhere. Meanwhile, quantitative finance and risk management still run on probabilistic algorithms that handle uncertainty properly, not on the newest LLM wrapper. The advice junior devs keep getting is to throw more data at the problem, and on a complex multi-dimensional distribution that sets up a race condition between your budget and your compute time.

I have watched systems fail because someone approximated a distribution with a standard normal curve when the real data looked like a volcano. If “close enough” is not an acceptable answer in what you are building, you need Markov Chain Monte Carlo (MCMC), and specifically you need to know how the Metropolis-Hastings Algorithm steps around the math that makes ordinary sampling impossible.

The normalization crisis: why standard math fails

Sampling from a distribution should just mean reaching for a Cumulative Distribution Function (CDF). The bottleneck is that Bayesian statistics hands you unnormalized density functions. Turning one into a probability means finding the normalization constant \(C\), and that means integrating over every possible value of \(x\).

In high-dimensional space that integral is not solvable. You are left holding a formula you cannot integrate and a distribution you cannot invert. MCMC walks the sample space at random instead, spends most of its time in the high-density regions, and never touches the integral at all.

On a related note, I wrote about using local LLMs to find high-performance algorithms.

Detailed balance, in plain terms

What makes the Metropolis-Hastings Algorithm work is Detailed Balance. The probability of moving from state \(x\) to \(x’\) has to equal the flow back from \(x’\) to \(x\). Get that right and the Markov Chain settles into a stationary distribution, the point where your samples actually represent the target density.

In code the transition splits into two steps, Proposal and Acceptance. The Hastings correction is the part that lets the proposal be asymmetric, which you need the moment your search space stops being uniform.

Implementing the Metropolis-Hastings algorithm in Python

The naive approach, where every jump gets accepted, gives you a chain that never converges. Here is the logic with NumPy handling the random walk.

import numpy as np

def bbioon_metropolis_hastings(target_density, n_samples=10000):
    samples = []
    current_x = 0.5  # Initial state
    
    for _ in range(n_samples):
        # 1. Propose a new state using a random walk
        proposed_x = current_x + np.random.normal(0, 1)
        
        # 2. Calculate the acceptance ratio (R)
        # Note: The normalization constant C cancels out here!
        prob_current = target_density(current_x)
        prob_proposed = target_density(proposed_x)
        
        # Avoid division by zero transients
        ratio = prob_proposed / (prob_current + 1e-10)
        acceptance_prob = min(1, ratio)
        
        # 3. Acceptance step (The "Coin Flip")
        if np.random.rand() < acceptance_prob:
            current_x = proposed_x
            
        samples.append(current_x)
        
    return samples

The trick is in the ratio: the constant \(C\) cancels, so the unnormalized density is all you ever need. The ArXiv paper on MCMC foundations works through it properly.

Mathematical conditions for ergodicity

A chain can still get stuck in a local minimum or loop forever, a sort of deadlock. Three conditions for ergodicity keep that from happening:

  • Irreducible: every point in the space has to be reachable. A proposal function with a zero-probability region leaves you dead in the water.
  • Aperiodic: the chain must not return to the same states at fixed intervals. The rejection step in Metropolis-Hastings breaks periodicity on its own.
  • Positive Recurrent: the average return time to any state has to be finite, which you get for free if your target integrates to 1.

If this Metropolis-Hastings Algorithm work is eating your dev hours, I can take it on. I have been wrestling with complex WordPress logic and backend performance since the 4.x days.

The bottom line

Treat the Metropolis-Hastings Algorithm as a working answer to the inversion problem rather than a math exercise. A random walk plus an acceptance ratio gets you samples with no explicit integral anywhere in the pipeline. Next in this series is Hamiltonian Monte Carlo (HMC), which uses the geometry of the distribution to converge faster in high-dimensional spaces.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.