Project 12: Monte Carlo Pi Estimator

A visual tool that estimates π by randomly throwing “darts” at a square containing a circle. The ratio of darts inside the circle to total darts approaches π/4.

Quick Reference

Attribute Value
Difficulty Level 1: Beginner (The Tinkerer)
Main Programming Language Python
Alternative Programming Languages C, JavaScript, Rust
Coolness Level Level 3: Genuinely Clever
Business Potential 1. The “Resume Gold” (Educational/Personal Brand)
Knowledge Area Probability / Monte Carlo Methods
Software or Tool Pi Estimator
Main Book “Grokking Algorithms” by Aditya Bhargava

1. Learning Objectives

By completing this project, you will:

  1. Translate math definitions into deterministic implementation steps.
  2. Build validation checks that make correctness observable.
  3. Diagnose numerical, logical, and data-shape failures early.
  4. Explain tradeoffs in interviews using evidence from your own build.

2. All Theory Needed (Per-Concept Breakdown)

This project applies the following theory clusters:

  • Symbolic-to-numeric translation (expressions, data shapes, invariants)
  • Stability constraints (precision, scaling, stopping criteria)
  • Optimization or inference logic (depending on project objective)
  • Evaluation discipline (error analysis, test coverage, reproducibility)

Concept A: Mathematical Representation Discipline

Fundamentals A math expression is not executable until you define representation, ordering, and domain constraints. The same equation can be represented as a token stream, tree, matrix pipeline, or probability graph. Choosing representation determines what bugs you can catch early.

Deep Dive into the concept Most project failures begin before algorithm selection: they start with ambiguous representation. If your parser cannot distinguish unary minus from subtraction, your calculator fails. If your matrix dimensions are implicit rather than validated, your linear algebra pipeline fails silently. If your probabilistic assumptions (independence, stationarity, or class priors) are not explicit, your inference can look accurate on one split and collapse on another. The core implementation move is to treat representation as a contract. Define each object with shape, domain, and semantic intent. Then enforce invariants at boundaries: input parser, preprocessing, training loop, evaluation stage. This makes debugging local instead of global.

How this fits this project You will encode each operation with explicit contracts and invariant checks.

Definitions & key terms

  • Invariant: Property that must hold before and after each operation.
  • Shape contract: Expected dimensional structure of vectors/matrices/tensors.
  • Domain constraint: Allowed value range (for example log input > 0).

Mental model diagram

User Input -> Representation Layer -> Validated Operation -> Observable Output
              (tokens/shapes)        (invariants pass)       (tests/plots/logs)

How it works

  1. Parse/ingest data into typed structures.
  2. Validate shape/domain invariants.
  3. Execute operation.
  4. Compare observed output with expected behavior.
  5. Record failure signature if mismatch appears.

Minimal concrete example

PSEUDOCODE
read expression
tokenize with precedence rules
if token sequence invalid -> return syntax error
evaluate tree
if domain violation -> return bounded diagnostic
print value and confidence check

Common misconceptions

  • “If it runs once, representation is correct.” -> false.
  • “Type checks are enough without shape checks.” -> false.

Check-your-understanding questions

  1. Which invariant catches division-by-zero earliest?
  2. Why does shape validation belong at boundaries rather than only in core logic?
  3. Predict failure if tokenization ignores unary minus.

Check-your-understanding answers

  1. Domain check on denominator before operation execution.
  2. Boundary validation keeps errors local and diagnostic.
  3. Expressions like -2^2 get misinterpreted and produce wrong precedence behavior.

Real-world applications Feature preprocessing, model-serving input validation, and experiment-tracking schema enforcement.

Where you’ll apply it This project and every downstream project in the sprint.

References

  • CSAPP (Bryant & O’Hallaron), floating-point chapter
  • Math for Programmers (Paul Orland), representation-oriented chapters

Key insight Correct representation reduces the complexity of every later decision.

Summary Stable ML math implementations start with explicit contracts, not implicit assumptions.

Homework/Exercises

  1. Write five invariants for your project.
  2. Build a failing test input for each invariant.

Solutions

  1. Include at least one shape, one domain, one convergence, one reproducibility, and one output-range invariant.
  2. Each failing input should trigger exactly one diagnostic to keep root-cause analysis clean.

3. Build Blueprint

  1. Scope the smallest end-to-end slice that produces visible output.
  2. Add deterministic tests and edge-case probes.
  3. Layer complexity only after baseline behavior is stable.
  4. Add metrics logging before optimization.
  5. Run failure drills: perturb inputs, scale values, and check stability.

4. Real-World Outcome (Target)

$ python monte_carlo_pi.py 1000000

Throwing 1,000,000 random darts at a 2x2 square with inscribed circle...

Samples   | Inside Circle | Estimate of π | Error
----------+---------------+---------------+-------
100       | 79            | 3.160         | 0.6%
1,000     | 783           | 3.132         | 0.3%
10,000    | 7,859         | 3.144         | 0.08%
100,000   | 78,551        | 3.142         | 0.01%
1,000,000 | 785,426       | 3.1417        | 0.004%

Actual π = 3.14159265...

[Visual: Square with circle, dots accumulating, π estimate updating in real-time]

Implementation Hints:

import random

inside = 0
for _ in range(n):
    x = random.uniform(-1, 1)
    y = random.uniform(-1, 1)
    if x**2 + y**2 <= 1:  # Inside unit circle
        inside += 1

pi_estimate = 4 * inside / n

Why does this work? Area of circle = π·r² = π (for r=1). Area of square = 4. Ratio = π/4.

Error decreases as 1/√n (standard Monte Carlo convergence).

Learning milestones:

  1. Basic estimate works → You understand random sampling
  2. Estimate improves with more samples → You understand law of large numbers
  3. You can predict how many samples for desired accuracy → You understand convergence rates

5. Core Design Notes from Main Guide

Core Question

Can randomness give us certainty?

This seems paradoxical: we’re using random numbers to compute something that’s completely deterministic (pi is pi, always). Yet Monte Carlo methods show that throwing enough random darts will converge to the exact answer. This project reveals one of the most beautiful ideas in probability: individual randomness becomes collective certainty through the law of large numbers.

Concepts You Must Understand First

Stop and research these before coding:

  1. Uniform Random Distribution
    • What does it mean for a random number to be “uniformly distributed” over [-1, 1]?
    • Is random.uniform() truly random? What is pseudorandomness?
    • Why do we need uniform distribution specifically for this problem?
    • Book Reference: “Think Stats” Chapter 2 - Allen Downey
  2. Geometric Probability
    • What is the probability that a random point lands inside a unit circle inscribed in a 2x2 square?
    • How does area relate to probability for uniformly distributed points?
    • Why is the equation x^2 + y^2 <= 1 the test for being inside the circle?
    • Book Reference: “Probability” Chapter 2 - Pitman
  3. The Law of Large Numbers
    • What does the law of large numbers actually state mathematically?
    • Why does the sample average converge to the true expected value?
    • What’s the difference between the weak and strong law?
    • Book Reference: “All of Statistics” Chapter 5 - Larry Wasserman
  4. Convergence Rates
    • How does error decrease as sample size n increases?
    • Why is Monte Carlo convergence O(1/sqrt(n)) and not O(1/n)?
    • How many samples do you need to double your accuracy?
    • Book Reference: “Numerical Recipes” Chapter 7 - Press et al.
  5. Confidence Intervals for Estimates
    • How can you quantify uncertainty in your pi estimate?
    • What is the standard error of a proportion estimate?
    • How do you construct a 95% confidence interval for pi?
    • Book Reference: “Think Stats” Chapter 8 - Allen Downey

Questions to Guide Your Design

Before implementing, think through these:

  1. Random Number Generation: What range should your random x and y coordinates have? Why [-1, 1] rather than [0, 1]?

  2. Circle Containment Test: How do you mathematically test if a point (x, y) is inside a circle of radius 1 centered at the origin?

  3. Ratio to Pi: If you know the ratio of points inside the circle to total points, how do you convert this to an estimate of pi? (Hint: think about the ratio of areas.)

  4. Visualization Strategy: How will you plot points in real-time? Color-code inside vs outside? Show the estimate updating?

  5. Progress Tracking: At what intervals will you display the current estimate? Every 100 samples? Every 10%?

  6. Error Measurement: How will you quantify how close your estimate is to true pi?

Thinking Exercise

Work through this probability reasoning before coding:

Consider a 2x2 square centered at the origin (vertices at (-1,-1), (1,-1), (1,1), (-1,1)). A unit circle (radius 1) is inscribed in this square.

  1. Area Calculation:
    • Area of the square = ?
    • Area of the circle = pi * r^2 = pi * 1^2 = ?
  2. Probability Reasoning:
    • If I throw a dart uniformly at random onto the square…
    • P(dart lands in circle) = (Area of circle) / (Area of square) = ?
  3. Estimation Logic:
    • After n darts, let k = number that landed in the circle
    • k/n approximates P(dart lands in circle)
    • So k/n ≈ pi/4
    • Therefore pi ≈ ?
  4. Error Analysis:
    • The standard error of a proportion estimate is sqrt(p(1-p)/n)
    • For p ≈ pi/4 ≈ 0.785, and n = 10000…
    • Standard error ≈ ?
    • 95% confidence interval for pi ≈ ?

Now calculate: How many samples do you need for the error in pi to be less than 0.001?

Interview Questions

  1. “Explain how Monte Carlo methods work.”
    • Expected: Use random sampling to estimate quantities that might be deterministic. Relies on law of large numbers for convergence.
  2. “What is the convergence rate of Monte Carlo estimation?”
    • Expected: O(1/sqrt(n)). Error halves when you quadruple samples. This is independent of problem dimension.
  3. “Why is Monte Carlo useful for high-dimensional integrals?”
    • Expected: Grid-based methods suffer curse of dimensionality. Monte Carlo convergence is independent of dimension.
  4. “How would you estimate the error of a Monte Carlo estimate?”
    • Expected: Compute sample variance, then standard error = sqrt(variance / n). Can construct confidence intervals.
  5. “Give an example of Monte Carlo in machine learning.”
    • Expected: MCMC for Bayesian inference, dropout as approximate inference, policy gradient methods in RL.
  6. “What is the difference between Monte Carlo and Vegas integration?”
    • Expected: Vegas uses importance sampling to concentrate samples where the function contributes most, improving efficiency.

Hints in Layers (Treat as pseudocode guidance)

Hint 1: The Basic Setup Generate random (x, y) pairs where both x and y are uniform in [-1, 1]. Count how many satisfy x^2 + y^2 <= 1.

Hint 2: The Pi Formula If k out of n points are inside the circle, then k/n ≈ (area of circle) / (area of square) = pi/4. So pi ≈ 4*k/n.

Hint 3: The Counting Loop

inside = 0
for i in range(n):
    x = random.uniform(-1, 1)
    y = random.uniform(-1, 1)
    if x*x + y*y <= 1:
        inside += 1
pi_estimate = 4 * inside / n

Hint 4: Adding Visualization Use matplotlib’s scatter plot. Color points green if inside, red if outside. Update periodically to show the estimate converging.

Hint 5: Error Tracking

# Track how estimate evolves
estimates = []
for i in range(1, n+1):
    # ... sampling code ...
    estimates.append(4 * inside / i)

# Plot estimates vs true pi over time
# You'll see it converge and fluctuations decrease

Books That Will Help

Topic Book Chapter
Monte Carlo Basics “Grokking Algorithms” Chapter 10 - Aditya Bhargava
Uniform Distribution “Think Stats” Chapter 2 - Allen Downey
Law of Large Numbers “All of Statistics” Chapter 5 - Larry Wasserman
Monte Carlo Integration “Numerical Recipes” Chapter 7 - Press et al.
Convergence Analysis “Probability and Computing” Chapter 1 - Mitzenmacher & Upfal
Geometric Probability “Probability” Chapter 2 - Pitman


6. Validation, Pitfalls, and Completion

Common Pitfalls and Debugging

Problem 1: “Outputs drift after a few iterations”

  • Why: Hidden numerical instability (unscaled features, aggressive step size, or repeated subtraction of nearly equal values).
  • Fix: Normalize inputs, reduce step size, and track relative error rather than only absolute error.
  • Quick test: Run the same task with two scales of input (for example x and 10x) and compare normalized error curves.

Problem 2: “Results are inconsistent across runs”

  • Why: Random seeds, data split randomness, or non-deterministic ordering are uncontrolled.
  • Fix: Set seeds, log configuration, and store split indices and hyperparameters with each run.
  • Quick test: Re-run three times with the same seed and confirm metrics remain inside a tight tolerance band.

Problem 3: “The project works on the demo case but fails on edge cases”

  • Why: Tests only cover happy-path inputs.
  • Fix: Add adversarial inputs (empty values, extreme ranges, near-singular matrices, rare classes).
  • Quick test: Build an edge-case test matrix and ensure every scenario reports expected behavior.

Definition of Done

  • Core functionality works on reference inputs
  • Edge cases are tested and documented
  • Results are reproducible (seeded and versioned configuration)
  • Performance or convergence behavior is measured and explained
  • A short retrospective explains what failed first and how you fixed it

7. Extension Ideas

  1. Add a stress-test mode with adversarial inputs.
  2. Add a short benchmark report (runtime + memory + error trend).
  3. Add a reproducibility bundle (seed, config, and fixed test corpus).

8. Why This Project Matters

Not specified

This project is valuable because it creates observable evidence of mathematical reasoning under real implementation constraints.