Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Part 4: Random Sampling - From Theory to Computation

How Nature Computes | Statistical Thinking Module 1 | COMP 521

Learning Outcomes

By the end of Part 4, you will be able to:


4.1 Why Random Sampling Matters

Priority: 🔴 Essential

Sampling is how we generate distributions; moments are how we audit them. Theory tells us distributions exist. But for simulations, we need to generate samples. The challenge: computers only produce uniform random numbers [0,1]. How do we transform these into complex astrophysical distributions? Sampling feels like randomness; precisely, it is measure-preserving transforms from uniform draws. Catchphrase -> Precision: “Random draws solve deterministic problems” means unbiased estimators converge with standard error ∝1/N\propto 1/\sqrt{N} under the right assumptions.

This is where theory meets computation. Random sampling bridges the gap between:

Monte Carlo \pi estimation: random sampling converts a geometric area ratio into a convergent numerical estimate with 1/\sqrt{N} error scaling.{#fig-monte-carlo-pi-estimation width=“100%”}

What to notice:

Project Hook: This appears in Project 2 when you transform uniform RNG draws into physically consistent mass, radius, and velocity samples.

4.2 The Cumulative Distribution Function (CDF) and Inverse Transform Sampling

Priority: 🔴 Essential

The key to sampling from any distribution lies in understanding the cumulative distribution function (CDF) and how it enables the inverse transform method — the most fundamental technique for converting uniform random numbers into samples from any distribution.

Understanding the CDF

The CDF is defined as:

F(x)=P(X≤x)=∫−∞xp(x′) dx′\boxed{F(x) = P(X \leq x) = \int_{-\infty}^{x} p(x')\,dx'}

While the probability density function (pdf) p(x)p(x) tells us the relative likelihood at each point, the CDF F(x)F(x) tells us the accumulated probability up to that point. This accumulation is what makes sampling possible.

To understand why this is so powerful, consider what the CDF actually represents. If you have a pdf p(x)p(x) that describes the distribution of stellar masses, then F(m)F(m) answers the question: “What fraction of stars have mass less than or equal to mm?”

For example, in a stellar population:

Key properties of CDFs:

The Inverse Transform Method

The crucial insight is that the CDF transforms any distribution — no matter how complex — into a uniform distribution on [0,1]. This provides the bridge between uniform random numbers (which computers generate) and any distribution we want.

Assumption break cue: This method can fail in practice when the CDF is not reliably invertible, numerical inversion is unstable, or endpoint handling is ignored.

Visual intuition: Imagine the CDF as a transformation that “stretches” the uniform distribution. Regions where the PDF is large (high probability density) correspond to steep sections of the CDF. When we invert, these steep sections get “compressed” back, allocating more samples to high-probability regions.

Example: Exponential Distribution

Before tackling power laws, let’s see how this works for the exponential distribution (which describes photon path lengths, radioactive decay, and time between stellar collisions):

pdf: p(x)=λe−λxp(x) = \lambda e^{-\lambda x} for x ≥\ge 0

CDF: F(x)=∫0xλe−λx′ dx′=1−e−λxF(x) = \int_0^x \lambda e^{-\lambda x'}\,dx' = 1 - e^{-\lambda x}

Inverse: Solve u=1−e−λxu = 1 - e^{-\lambda x} for x:

Equivalent form: x=−1λln⁡(u)x = -\frac{1}{\lambda}\ln(u), since uu and (1−u)(1-u) are both uniform on [0,1].

import numpy as np

# Sample exponential distribution (e.g., photon mean free paths)
def sample_exponential(lambda_param, n_samples, rng=None):
    if rng is None:
        rng = np.random.default_rng()
    u = rng.uniform(0, 1, n_samples)
    u = np.clip(u, 1e-15, 1 - 1e-15)
    return -np.log(1 - u) / lambda_param

# Example: mean free path of 1 pc
mfp = 1.0  # pc
rng = np.random.default_rng(536)
lambda_param = 1.0 / mfp
path_lengths = sample_exponential(lambda_param, 10000, rng=rng)
print(f"Mean path: {np.mean(path_lengths):.2f} pc")
print(f"Theory: {mfp:.2f} pc")

Copy/paste quick-check: Imports: numpy. Seed: set rng = np.random.default_rng(536) for repeatable means. Variability: sample mean fluctuates around the theoretical mean at finite draw counts.

Power Law Distributions: The Foundation of Astrophysics

Power law distributions appear everywhere in astronomy:

Deriving the sampling formula:

  1. Normalize the PDF: p(x)=(α−1)x−αxmin⁡1−α−xmax⁡1−αp(x) = \frac{(\alpha-1) x^{-\alpha}}{x_{\min}^{1-\alpha} - x_{\max}^{1-\alpha}} (for α≠1\alpha \neq 1)

  2. Compute the CDF: F(x)=∫xmin⁡xf(x′)dx′=x1−α−xmin⁡1−αxmax⁡1−α−xmin⁡1−αF(x) = \int_{x_{\min}}^x f(x')dx' = \frac{x^{1-\alpha} - x_{\min}^{1-\alpha}}{x_{\max}^{1-\alpha} - x_{\min}^{1-\alpha}}

  3. Invert to get sampling formula: Set F(x) = u and solve for x: x=[xmin⁡1−α+u(xmax⁡1−α−xmin⁡1−α)]1/(1−α)\boxed{x = \left[x_{\min}^{1-\alpha} + u(x_{\max}^{1-\alpha} - x_{\min}^{1-\alpha})\right]^{1/(1-\alpha)}}

Special case α=1\alpha = 1: The integral of 1/x1/x is ln⁡(x)\ln(x), so: x=xmin⁡(xmax⁡xmin⁡)u\boxed{x = x_{\min} \left(\frac{x_{\max}}{x_{\min}}\right)^u}

Sample Size Determines Accuracy in Power Law Distributions. The Salpeter Initial Mass Function (\alpha=2.35) demonstrates how statistical convergence works in practice. Left panel (N=100): small samples show noisy histograms with poor fits to the theoretical power law. Center panel (N=1{,}000): medium samples begin to reveal the underlying distribution structure with better agreement. Right panel (N=10{,}000): large samples produce smooth histograms that closely match theory. Statistics boxes show quantitative metrics: mean mass, median mass, and fraction below 1\,M_\odot. This convergence behavior is universal across Monte Carlo methods, following the expected 1/\sqrt{N} error scaling from Section 4.1.{#fig-power-law-sampling width=“100%”}

Implementation and Visualization

The figure above shows our power law sampling in action. Keep the production path small: sample, then run the Sampling Diagnostic Trio.

import numpy as np

def sample_simple_power_law(alpha, x_min, x_max, n_samples, rng=None):
    if rng is None:
        rng = np.random.default_rng()
    u = rng.uniform(0, 1, n_samples)
    return (x_min**(1-alpha) + u*(x_max**(1-alpha) - x_min**(1-alpha)))**(1/(1-alpha))

samples = sample_simple_power_law(2.35, 0.1, 100, 10_000, rng=np.random.default_rng(536))
print(np.mean(samples), np.var(samples), np.mean(samples > 10.0))

Use the Sampling Diagnostic Trio here: histogram-vs-theory for pdf shape, empirical CDF (or QQ) for distributional agreement, and moments plus a high-mass tail fraction for inference.

Copy/paste quick-check: Imports: numpy, matplotlib. Seed: set rng = np.random.default_rng(536) for reproducible sampling tables/plots. Variability: slope-dependent trends persist, while exact summary values vary with seed and sample count.

Why the Inverse Transform is Powerful

The inverse transform method is the foundation of Monte Carlo sampling because:

  1. It’s exact: Every uniform random number produces exactly one sample from your distribution

  2. It’s efficient: 100% of random numbers are used (no rejections)

  3. It’s deterministic: The same uniform input always gives the same output (useful for debugging)

  4. It works in any dimension: Can be extended to multivariate distributions

However, it requires that you can:

When these conditions aren’t met, you’ll need other methods like rejection sampling (Section 4.3) or Markov Chain Monte Carlo (Project 4).

Example: Exponential distribution (photon path lengths!)

Simple implementation:

import numpy as np

# Sample exponential distribution (e.g., photon path lengths)
def sample_exponential(lambda_param, n_samples, rng=None):
    if rng is None:
        rng = np.random.default_rng()
    u = rng.uniform(0, 1, n_samples)
    u = np.clip(u, 1e-15, 1 - 1e-15)
    # Inverse CDF transform
    return -np.log(1 - u) / lambda_param

# Example: mean free path of 1 pc
mfp = 1.0  # pc
rng = np.random.default_rng(536)
lambda_param = 1.0 / mfp
path_lengths = sample_exponential(lambda_param, 10000, rng=rng)
print(f"Mean path: {np.mean(path_lengths):.2f} pc")
print(f"Theory: {mfp:.2f} pc")

Copy/paste quick-check: Imports: numpy. Seed: set rng = np.random.default_rng(536) to reproduce output means. Variability: finite-sample mean fluctuates around the target mean free path.

4.3 Rejection Sampling

Priority: 🟡 Standard Path

When inverse transform fails, use rejection sampling:

Example: Throw darts at rectangle, keep those under curve.

import numpy as np

# Example: Sample from arbitrary distribution
def rejection_sample(p_func, x_min, x_max, f_max, n_samples, max_tries=10_000_000, rng=None):
    """Sample using rejection method"""
    if rng is None:
        rng = np.random.default_rng()
    samples = []
    n_tries = 0

    while len(samples) < n_samples:
        if n_tries >= max_tries:
            raise RuntimeError("Exceeded max_tries; check f_max envelope or target PDF.")
        x = rng.uniform(x_min, x_max)
        y = rng.uniform(0, f_max)
        n_tries += 1

        if y <= p_func(x):
            samples.append(x)

    efficiency = n_samples / n_tries
    print(f"Efficiency: {efficiency:.1%}")
    return np.array(samples)

Copy/paste quick-check: Imports: numpy. Seed recommendation: pass rng=np.random.default_rng(536) for repeatable envelope comparisons. Variability: efficiency varies stochastically even with fixed target PDF.

Inverse-transform and rejection sampling comparison: both map uniform random numbers to target distributions, with different efficiency tradeoffs.{#fig-random-sampling-methods width=“100%”}

What to notice:

4.4 Spatial Distributions: The Plummer Sphere

Priority: 🔴 Essential for Project 2

Now that you can sample stellar masses from the Kroupa IMF, you need to place these stars in space. The Plummer sphere is a standard density profile for globular clusters and stellar systems.

The Plummer Profile

The Plummer sphere has density profile:

ρ(r)=3Mtotal4πa3(1+r2a2)−5/2\rho(r) = \frac{3M_{total}}{4\pi a^3} \left(1 + \frac{r^2}{a^2}\right)^{-5/2}

where:

This creates a smooth, centrally concentrated distribution that avoids the infinite density at r=0 that plagues some other profiles.

The Sampling Challenge

You can’t sample directly from ρ(r)\rho(r) because density isn’t probability! The key insight: the probability of finding a star between radius rr and r+drr+dr is proportional to the mass in that shell, not the density.

dP∝ρ(r)×(volume of shell)∝ρ(r)×4πr2drdP \propto \rho(r) \times \text{(volume of shell)} \propto \rho(r) \times 4\pi r^2 dr

So the radial PDF is:

p(r)∝r2ρ(r)=r2(1+r2a2)−5/2p(r) \propto r^2 \rho(r) = r^2 \left(1 + \frac{r^2}{a^2}\right)^{-5/2}

Approach 1: Mass Profile Method

The enclosed mass within radius rr is:

M(<r)=Mtotalr3(r2+a2)3/2M(<r) = M_{total} \frac{r^3}{(r^2 + a^2)^{3/2}}

The cumulative mass fraction (which IS a CDF!) is:

F(r)=M(<r)Mtotal=r3(r2+a2)3/2F(r) = \frac{M(<r)}{M_{total}} = \frac{r^3}{(r^2 + a^2)^{3/2}}

To sample:

  1. Generate u∼U(0,1)u \sim U(0,1) (this represents a mass fraction)

  2. Solve u=r3(r2+a2)3/2u = \frac{r^3}{(r^2 + a^2)^{3/2}} for rr

  3. Place the star at radius rr with random angular coordinates

Assumption break cue: Radial sampling is biased if isotropy is violated in angle draws or if finite-radius truncation is introduced without updating the CDF.

Approach 2: Rejection Sampling in 3D

Alternatively, you could:

  1. Generate random positions in a cube containing your cluster

  2. Accept/reject based on the density at that position

  3. But this becomes inefficient for large clusters!

From Radius to 3D Positions

Once you have radius rr:

  1. Generate random direction on sphere:

    • μ=cos⁡θ∼U(−1,1)\mu = \cos\theta \sim U(-1,1)

    • ϕ∼U(0,2π)\phi \sim U(0, 2\pi) (azimuthal angle)

    • θ=arccos⁡(μ)\theta = \arccos(\mu)

  2. Convert to Cartesian:

    • x=rsin⁡θcos⁡ϕx = r \sin\theta \cos\phi

    • y=rsin⁡θsin⁡ϕy = r \sin\theta \sin\phi

    • z=rcos⁡θz = r \cos\theta

Or use the simpler method: generate a random unit vector and scale by rr.

Verification

Your sampled positions should reproduce:

  1. The density profile ρ(r)\rho(r) when binned radially

  2. The enclosed mass profile M(<r)M(<r)

  3. The half-mass radius rhalf≈1.3ar_{half} \approx 1.3a for Plummer

  4. The Sampling Diagnostic Trio: histogram-vs-theory for ρ(r)\rho(r), empirical CDF-vs-theory for M(<r)/MtotalM(<r)/M_{\mathrm{total}}, and summary moments/tail fraction for radial structure

Plummer-sphere sampling validation: inverse-transform draws reproduce both radial density and enclosed-mass structure in 3D.{#fig-plummer-sphere-sampling width=“100%”}

What to notice:

Part 4 Synthesis: Theory to Computation