Theory NotebookMath for LLMs

Radon Nikodym Theorem

Measure Theory / Radon Nikodym Theorem

Run notebook
Theory Notebook

Theory Notebook

Converted from theory.ipynb for web reading.

Radon-Nikodym Theorem

The Radon-Nikodym theorem explains when densities, likelihood ratios, importance weights, KL divergence, and change-of-measure formulas exist.

This notebook is the executable companion to notes.md. It uses finite spaces and synthetic measures so the measure-theoretic objects are visible.

Code cell 2

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

try:
    import seaborn as sns
    sns.set_theme(style="whitegrid", palette="colorblind")
    HAS_SNS = True
except ImportError:
    plt.style.use("seaborn-v0_8-whitegrid")
    HAS_SNS = False

mpl.rcParams.update({
    "figure.figsize":    (10, 6),
    "figure.dpi":         120,
    "font.size":           13,
    "axes.titlesize":      15,
    "axes.labelsize":      13,
    "xtick.labelsize":     11,
    "ytick.labelsize":     11,
    "legend.fontsize":     11,
    "legend.framealpha":   0.85,
    "lines.linewidth":      2.0,
    "axes.spines.top":     False,
    "axes.spines.right":   False,
    "savefig.bbox":       "tight",
    "savefig.dpi":         150,
})
np.random.seed(42)
print("Plot setup complete.")

Code cell 3


COLORS = {
    "primary":   "#0077BB",
    "secondary": "#EE7733",
    "tertiary":  "#009988",
    "error":     "#CC3311",
    "neutral":   "#555555",
    "highlight": "#EE3377",
}

def header(title):
    print("\n" + "=" * 72)
    print(title)
    print("=" * 72)

def check_true(condition, name):
    ok = bool(condition)
    print(f"{'PASS' if ok else 'FAIL'} - {name}")
    assert ok, name

def check_close(value, target, tol=1e-8, name="value"):
    ok = abs(float(value) - float(target)) <= tol
    print(f"{'PASS' if ok else 'FAIL'} - {name}: got {float(value):.6f}, expected {float(target):.6f}")
    assert ok, name

def powerset(universe):
    items = tuple(universe)
    out = [frozenset()]
    for item in items:
        out += [s | {item} for s in out]
    return set(out)

def sigma_generated(universe, generators):
    universe = frozenset(universe)
    family = {frozenset(), universe} | {frozenset(g) for g in generators}
    changed = True
    while changed:
        old = set(family)
        family |= {universe - a for a in old}
        for a in old:
            for b in old:
                family.add(a | b)
                family.add(a & b)
        changed = len(family) != len(old)
    return family

def is_sigma_algebra(universe, family):
    universe = frozenset(universe)
    family = {frozenset(a) for a in family}
    if frozenset() not in family or universe not in family:
        return False
    for a in list(family):
        if universe - a not in family:
            return False
        for b in list(family):
            if a | b not in family:
                return False
    return True

def simple_integral(values, masses):
    values = np.asarray(values, dtype=float)
    masses = np.asarray(masses, dtype=float)
    return float(np.sum(values * masses))

def pushforward(prob, mapping):
    out = {}
    for omega, mass in prob.items():
        y = mapping[omega]
        out[y] = out.get(y, 0.0) + float(mass)
    return out

def product_measure(p, q):
    return {(a, b): float(pa) * float(qb) for a, pa in p.items() for b, qb in q.items()}

def rn_derivative(target, proposal):
    ratio = {}
    for key, p_mass in target.items():
        q_mass = proposal.get(key, 0.0)
        if p_mass > 0 and q_mass <= 0:
            raise ValueError("target is not absolutely continuous with respect to proposal")
        ratio[key] = 0.0 if q_mass == 0 else float(p_mass) / float(q_mass)
    return ratio

def expectation_under(prob, values):
    return float(sum(prob[k] * values[k] for k in prob))

print("Measure-theory helpers ready.")

Demo 1: Densities as derivatives of measures

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 5

header("Demo 1 - Densities as derivatives of measures: generated sigma algebra")
universe = {0, 1, 2, 3}
generators = [{0, 1}]
family = sigma_generated(universe, generators)
print("Generated family:", sorted([sorted(s) for s in family]))
check_true(is_sigma_algebra(universe, family), "generated family is a sigma algebra")
print("Number of measurable events:", len(family))

Demo 2: Absolute continuity PQP\ll Q

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 7

header("Demo 2 - Absolute continuity $P\\ll Q$: measurable observation")
omega = ["raw_a", "raw_b", "raw_c", "raw_d"]
scores = {"raw_a": "safe", "raw_b": "safe", "raw_c": "risky", "raw_d": "risky"}
event = {w for w in omega if scores[w] == "risky"}
family = sigma_generated(omega, [event])
print("Risky preimage:", sorted(event))
check_true(frozenset(event) in family, "threshold event is measurable")
print("Observation-generated event count:", len(family))

Demo 3: Likelihood ratios and change of measure

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 9

header("Demo 3 - Likelihood ratios and change of measure: simple-function integral")
values = np.array([0.2, 0.5, 1.5, 2.0])
masses = np.array([0.1, 0.2, 0.3, 0.4])
integral = simple_integral(values, masses)
print("Integral:", integral)
check_close(integral, 1.37, name="finite Lebesgue integral")
print("Interpretation: expected loss under a finite empirical measure.")

Demo 4: Why density is not always PDF with respect to dxdx

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 11

header("Demo 4 - Why density is not always PDF with respect to $dx$: dominated convergence toy")
x = np.linspace(0, 1, 1001)
dx = x[1] - x[0]
integrals = []
for n in [1, 2, 5, 10, 20, 50]:
    f_n = x ** n
    integrals.append(float(np.sum(f_n) * dx))
print("Integrals of x^n:", [round(v, 4) for v in integrals])
check_true(integrals[-1] < integrals[0], "integrals shrink toward zero")
fig, ax = plt.subplots()
ax.plot([1, 2, 5, 10, 20, 50], integrals, color=COLORS["primary"], marker="o", label="Integral")
ax.set_title("Dominated convergence toy: integral of x^n")
ax.set_xlabel("n")
ax.set_ylabel("Approximate integral")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)
print("Interpretation: domination allows limit and integral to agree.")

Demo 5: Historical and ML motivation

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 13

header("Demo 5 - Historical and ML motivation: pushforward law")
prob = {"a": 0.15, "b": 0.35, "c": 0.25, "d": 0.25}
mapping = {"a": "short", "b": "short", "c": "long", "d": "long"}
law = pushforward(prob, mapping)
print("Pushforward law:", law)
check_close(sum(law.values()), 1.0, name="pushforward total mass")
print("Interpretation: feature maps transform probability measures.")

Demo 6: Signed and finite measures preview

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 15

header("Demo 6 - Signed and finite measures preview: product measure independence")
p = {"H": 0.6, "T": 0.4}
q = {"red": 0.25, "blue": 0.75}
joint = product_measure(p, q)
print("Joint entries:", joint)
check_close(joint[("H", "blue")], 0.45, name="product probability")
print("Interpretation: independence is factorization of the joint measure.")

Demo 7: Absolute continuity and singularity

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 17

header("Demo 7 - Absolute continuity and singularity: Radon-Nikodym ratios")
target = {"a": 0.2, "b": 0.5, "c": 0.3}
proposal = {"a": 0.4, "b": 0.4, "c": 0.2}
ratio = rn_derivative(target, proposal)
print("dP/dQ:", ratio)
values = {"a": 1.0, "b": 2.0, "c": 4.0}
direct = expectation_under(target, values)
weighted = sum(proposal[k] * ratio[k] * values[k] for k in proposal)
print("Direct E_P[f]:", direct)
print("Weighted E_Q[f dP/dQ]:", weighted)
check_close(direct, weighted, name="change of measure identity")

Demo 8: Radon-Nikodym derivative dPdQ\frac{dP}{dQ}

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 19

header("Demo 8 - Radon-Nikodym derivative $\\frac{dP}{dQ}$: support mismatch")
target = {"a": 0.5, "b": 0.5}
proposal = {"a": 1.0, "b": 0.0}
try:
    rn_derivative(target, proposal)
    ok = False
except ValueError as exc:
    print("Caught expected error:", exc)
    ok = True
check_true(ok, "support mismatch blocks dP/dQ")
print("Interpretation: absolute continuity is a support condition.")

Demo 9: Density with respect to a base measure

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 21

header("Demo 9 - Density with respect to a base measure: generated sigma algebra")
universe = {0, 1, 2, 3}
generators = [{0, 1}]
family = sigma_generated(universe, generators)
print("Generated family:", sorted([sorted(s) for s in family]))
check_true(is_sigma_algebra(universe, family), "generated family is a sigma algebra")
print("Number of measurable events:", len(family))

Demo 10: Uniqueness up to QQ-almost everywhere equality

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 23

header("Demo 10 - Uniqueness up to $Q$-almost everywhere equality: measurable observation")
omega = ["raw_a", "raw_b", "raw_c", "raw_d"]
scores = {"raw_a": "safe", "raw_b": "safe", "raw_c": "risky", "raw_d": "risky"}
event = {w for w in omega if scores[w] == "risky"}
family = sigma_generated(omega, [event])
print("Risky preimage:", sorted(event))
check_true(frozenset(event) in family, "threshold event is measurable")
print("Observation-generated event count:", len(family))

Demo 11: Radon-Nikodym theorem statement

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 25

header("Demo 11 - Radon-Nikodym theorem statement: simple-function integral")
values = np.array([0.2, 0.5, 1.5, 2.0])
masses = np.array([0.1, 0.2, 0.3, 0.4])
integral = simple_integral(values, masses)
print("Integral:", integral)
check_close(integral, 1.37, name="finite Lebesgue integral")
print("Interpretation: expected loss under a finite empirical measure.")

Demo 12: Proof sketch via Hilbert-space or decomposition intuition

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 27

header("Demo 12 - Proof sketch via Hilbert-space or decomposition intuition: dominated convergence toy")
x = np.linspace(0, 1, 1001)
dx = x[1] - x[0]
integrals = []
for n in [1, 2, 5, 10, 20, 50]:
    f_n = x ** n
    integrals.append(float(np.sum(f_n) * dx))
print("Integrals of x^n:", [round(v, 4) for v in integrals])
check_true(integrals[-1] < integrals[0], "integrals shrink toward zero")
fig, ax = plt.subplots()
ax.plot([1, 2, 5, 10, 20, 50], integrals, color=COLORS["primary"], marker="o", label="Integral")
ax.set_title("Dominated convergence toy: integral of x^n")
ax.set_xlabel("n")
ax.set_ylabel("Approximate integral")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)
print("Interpretation: domination allows limit and integral to agree.")

Demo 13: Change-of-measure formula

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 29

header("Demo 13 - Change-of-measure formula: pushforward law")
prob = {"a": 0.15, "b": 0.35, "c": 0.25, "d": 0.25}
mapping = {"a": "short", "b": "short", "c": "long", "d": "long"}
law = pushforward(prob, mapping)
print("Pushforward law:", law)
check_close(sum(law.values()), 1.0, name="pushforward total mass")
print("Interpretation: feature maps transform probability measures.")

Demo 14: Lebesgue decomposition theorem

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 31

header("Demo 14 - Lebesgue decomposition theorem: product measure independence")
p = {"H": 0.6, "T": 0.4}
q = {"red": 0.25, "blue": 0.75}
joint = product_measure(p, q)
print("Joint entries:", joint)
check_close(joint[("H", "blue")], 0.45, name="product probability")
print("Interpretation: independence is factorization of the joint measure.")

Demo 15: Chain rule for derivatives dPdR=dPdQdQdR\frac{dP}{dR}=\frac{dP}{dQ}\frac{dQ}{dR}

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 33

header("Demo 15 - Chain rule for derivatives $\\frac{dP}{dR}=\\frac{dP}{dQ}\\frac{dQ}{dR}$: Radon-Nikodym ratios")
target = {"a": 0.2, "b": 0.5, "c": 0.3}
proposal = {"a": 0.4, "b": 0.4, "c": 0.2}
ratio = rn_derivative(target, proposal)
print("dP/dQ:", ratio)
values = {"a": 1.0, "b": 2.0, "c": 4.0}
direct = expectation_under(target, values)
weighted = sum(proposal[k] * ratio[k] * values[k] for k in proposal)
print("Direct E_P[f]:", direct)
print("Weighted E_Q[f dP/dQ]:", weighted)
check_close(direct, weighted, name="change of measure identity")

Demo 16: Importance sampling weights

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 35

header("Demo 16 - Importance sampling weights: support mismatch")
target = {"a": 0.5, "b": 0.5}
proposal = {"a": 1.0, "b": 0.0}
try:
    rn_derivative(target, proposal)
    ok = False
except ValueError as exc:
    print("Caught expected error:", exc)
    ok = True
check_true(ok, "support mismatch blocks dP/dQ")
print("Interpretation: absolute continuity is a support condition.")

Demo 17: KL divergence as logdPdQdP\int \log\frac{dP}{dQ}\,dP

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 37

header("Demo 17 - KL divergence as $\\int \\log\\frac{dP}{dQ}\\,dP$: generated sigma algebra")
universe = {0, 1, 2, 3}
generators = [{0, 1}]
family = sigma_generated(universe, generators)
print("Generated family:", sorted([sorted(s) for s in family]))
check_true(is_sigma_algebra(universe, family), "generated family is a sigma algebra")
print("Number of measurable events:", len(family))

Demo 18: Likelihood ratios in classification and density-ratio estimation

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 39

header("Demo 18 - Likelihood ratios in classification and density-ratio estimation: measurable observation")
omega = ["raw_a", "raw_b", "raw_c", "raw_d"]
scores = {"raw_a": "safe", "raw_b": "safe", "raw_c": "risky", "raw_d": "risky"}
event = {w for w in omega if scores[w] == "risky"}
family = sigma_generated(omega, [event])
print("Risky preimage:", sorted(event))
check_true(frozenset(event) in family, "threshold event is measurable")
print("Observation-generated event count:", len(family))

Demo 19: Variational inference and ELBO

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 41

header("Demo 19 - Variational inference and ELBO: simple-function integral")
values = np.array([0.2, 0.5, 1.5, 2.0])
masses = np.array([0.1, 0.2, 0.3, 0.4])
integral = simple_integral(values, masses)
print("Integral:", integral)
check_close(integral, 1.37, name="finite Lebesgue integral")
print("Interpretation: expected loss under a finite empirical measure.")

Demo 20: Off-policy evaluation and policy-change corrections

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 43

header("Demo 20 - Off-policy evaluation and policy-change corrections: dominated convergence toy")
x = np.linspace(0, 1, 1001)
dx = x[1] - x[0]
integrals = []
for n in [1, 2, 5, 10, 20, 50]:
    f_n = x ** n
    integrals.append(float(np.sum(f_n) * dx))
print("Integrals of x^n:", [round(v, 4) for v in integrals])
check_true(integrals[-1] < integrals[0], "integrals shrink toward zero")
fig, ax = plt.subplots()
ax.plot([1, 2, 5, 10, 20, 50], integrals, color=COLORS["primary"], marker="o", label="Integral")
ax.set_title("Dominated convergence toy: integral of x^n")
ax.set_xlabel("n")
ax.set_ylabel("Approximate integral")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)
print("Interpretation: domination allows limit and integral to agree.")

Demo 21: Densities as derivatives of measures

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 45

header("Demo 21 - Densities as derivatives of measures: pushforward law")
prob = {"a": 0.15, "b": 0.35, "c": 0.25, "d": 0.25}
mapping = {"a": "short", "b": "short", "c": "long", "d": "long"}
law = pushforward(prob, mapping)
print("Pushforward law:", law)
check_close(sum(law.values()), 1.0, name="pushforward total mass")
print("Interpretation: feature maps transform probability measures.")

Demo 22: Absolute continuity PQP\ll Q

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 47

header("Demo 22 - Absolute continuity $P\\ll Q$: product measure independence")
p = {"H": 0.6, "T": 0.4}
q = {"red": 0.25, "blue": 0.75}
joint = product_measure(p, q)
print("Joint entries:", joint)
check_close(joint[("H", "blue")], 0.45, name="product probability")
print("Interpretation: independence is factorization of the joint measure.")

Demo 23: Likelihood ratios and change of measure

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 49

header("Demo 23 - Likelihood ratios and change of measure: Radon-Nikodym ratios")
target = {"a": 0.2, "b": 0.5, "c": 0.3}
proposal = {"a": 0.4, "b": 0.4, "c": 0.2}
ratio = rn_derivative(target, proposal)
print("dP/dQ:", ratio)
values = {"a": 1.0, "b": 2.0, "c": 4.0}
direct = expectation_under(target, values)
weighted = sum(proposal[k] * ratio[k] * values[k] for k in proposal)
print("Direct E_P[f]:", direct)
print("Weighted E_Q[f dP/dQ]:", weighted)
check_close(direct, weighted, name="change of measure identity")

Demo 24: Why density is not always PDF with respect to dxdx

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 51

header("Demo 24 - Why density is not always PDF with respect to $dx$: support mismatch")
target = {"a": 0.5, "b": 0.5}
proposal = {"a": 1.0, "b": 0.0}
try:
    rn_derivative(target, proposal)
    ok = False
except ValueError as exc:
    print("Caught expected error:", exc)
    ok = True
check_true(ok, "support mismatch blocks dP/dQ")
print("Interpretation: absolute continuity is a support condition.")

Demo 25: Historical and ML motivation

This demo turns the approved TOC concept into a finite, executable measure-theory calculation.

Code cell 53

header("Demo 25 - Historical and ML motivation: generated sigma algebra")
universe = {0, 1, 2, 3}
generators = [{0, 1}]
family = sigma_generated(universe, generators)
print("Generated family:", sorted([sorted(s) for s in family]))
check_true(is_sigma_algebra(universe, family), "generated family is a sigma algebra")
print("Number of measurable events:", len(family))