IV.1 · Probability
What could happen before we see what did happen?
Select possible outcomes and build an event. The model assigns probability to all possibilities; one observed roll supplies only one result.
An experiment and its sample space
Observed sequence · first 16 at most
- 2
- 1
- 4
- 2
- 3
- 1
- 3
- 1
- 6
- 6
- 6
- 3
Sample space: 1, 2, 3, 4, 5, 6. Equal weights explicitly assume equiprobable outcomes. A = {2, 4, 6}; B = {4, 5, 6}. The fixed model assigns probabilities before a trial. Seed 42 selects this reproducible observed sequence; its frequencies do not redefine the model.
- Total probability
- 1
- Event A
- 0.5
- Event B
- 0.5
- Intersection
- 1/30.333333…
- Observed frequency of A
- 0.5
= exact model quantity · ≈ numerical companion or observed estimate
from 0 to 100, whole numbers only
from 0 to 4294967295, whole numbers only
from 1 to 2000, whole numbers only
Define the experiment
6 mutually exclusive outcomes, total mass one. Equal weights explicitly assume equiprobable outcomes.
Before changing anything, predict the mass of the even faces. Select just one face, then all six. Explain why an event can contain several outcomes although a single roll produces only one outcome.
Intuition: possibilities are not observations
A die in your hand has not yet produced a result. A probability model describes what may happen and assigns weights to those possibilities. After a roll, you observe one face. The five other faces remain possibilities for a new roll under the same model; the observation does not erase them from the sample space.
An event answers a question such as “was the face even?” It collects every outcome that would make the answer yes. A probability is the total mass of that collection, not a promise about the next observed result.
Definition
A finite sample space is a nonempty set of distinct outcomes. A probability model assigns a mass to each outcome, subject to
An event is a subset of , with probability . The empty event has probability zero and the whole sample space has probability one. A possible label may have mass zero in a specified model; nonempty does not always mean positive probability.
For the canonical fair six-sided die, and every mass is . Fairness is an explicit assumption, not a consequence of having six labels.
Mechanics: one state, several views
The stage holds the experiment’s outcome weights and event membership. Selecting a face for A changes membership. Edit weight selects a face whose nonnegative raw weight you can change; the model divides all raw weights by their positive total to obtain normalized probabilities. Equal raw weights express the fairness assumption. The selected outcomes, mass inspector, equation, accessible description, and trace refer to that same state.
Read the trace from defining the weighted experiment through its first seeded observation and the bounded repeated-trial counts. Compare those observations with the fixed model mass in the inspector. Replay the same seed to recover the same sequence; changing event membership changes which observations count toward its frequency, not the sequence itself.
Derivation: when counting is enough
If there are equally likely outcomes, normalization gives , hence . If contains of them, then
This shortcut follows from equal masses. With unequal masses, the set still tells you which terms to add, but its size no longer tells you their sum. Nor does a short observed sequence determine the weights of a future experiment.
Worked examples
For on the fair die, three selected outcomes each contribute , so . For , as well. Their shared faces are and , with total mass ; equal event masses do not make the events identical.
Worked example: An experiment and its sample space
Observed sequence · first 16 at most
- 2
- 1
- 4
- 2
- 3
- 1
- 3
- 1
- 6
- 6
- 6
- 3
Sample space: 1, 2, 3, 4, 5, 6. Equal weights explicitly assume equiprobable outcomes. A = {2, 4, 6}; B = {4, 5, 6}. The fixed model assigns probabilities before a trial. Seed 42 selects this reproducible observed sequence; its frequencies do not redefine the model.
- Total probability
- 1
- Event A
- 0.5
- Event B
- 0.5
- Intersection
- 1/30.333333…
- Observed frequency of A
- 0.5
= exact model quantity · ≈ numerical companion or observed estimate
from 0 to 100, whole numbers only
from 0 to 4294967295, whole numbers only
from 1 to 2000, whole numbers only
Define the experiment
6 mutually exclusive outcomes, total mass one. Equal weights explicitly assume equiprobable outcomes.
For two independent fair coins, distinguish the first and second positions: , each mass . The event “exactly one head” contains and , so its mass is . If we describe only the number of heads, the labels have masses . Grouping outcomes changes the labels, not the total mass associated with each group.
Executable reference code
The standard-library program spells out exact Fraction masses, validates the finite model, sums event weights, and prints the die and coin examples. Its bounded observation sequence uses an explicit seed. The NumPy program compares boolean-mask sums against independently specified exact fractions; it performs no random experiment to manufacture an answer.
"""A finite probability model is not an observed sequence of trials.
Fractions made from integers keep these model probabilities exact. The seeded,
bounded die sequence illustrates observations; its frequency is not the model.
"""
from collections import Counter
from fractions import Fraction as F
from random import Random
def validate_model(weights):
if not weights or any(not isinstance(p, F) or p < 0 for p in weights.values()):
raise ValueError("Use a nonempty outcome map with nonnegative Fraction masses")
if sum(weights.values(), F(0)) != 1:
raise ValueError("Outcome masses must sum exactly to one")
def event_mass(weights, event):
validate_model(weights)
if not set(event) <= weights.keys():
raise ValueError("An event must be a subset of the sample space")
return sum((weights[outcome] for outcome in set(event)), F(0))
def main():
die = {face: F(1, 6) for face in range(1, 7)}
even = {2, 4, 6}
assert event_mass(die, even) == F(1, 2)
assert event_mass(die, set()) == 0
assert event_mass(die, set(die)) == 1
coins = {outcome: F(1, 4) for outcome in ("HH", "HT", "TH", "TT")}
assert event_mass(coins, {"HT", "TH"}) == F(1, 2)
weighted = {"red": F(1, 2), "green": F(1, 3), "blue": F(1, 6)}
assert event_mass(weighted, {"green", "blue"}) == F(1, 2)
for bad in ({}, {1: F(1, 2)}, {1: F(-1, 4), 2: F(5, 4)}):
try:
validate_model(bad)
except ValueError:
pass
else:
raise AssertionError("Invalid model was accepted")
try:
event_mass(die, {7})
except ValueError:
pass
else:
raise AssertionError("An outcome outside the sample space was accepted")
# The random generator samples the fair-die model, not arbitrary weights.
def observations(seed, count):
rng = Random(seed)
return tuple(rng.randrange(1, 7) for _ in range(count))
rolls = observations(2026, 24)
assert rolls == observations(2026, 24)
counts = Counter(rolls)
observed_even = F(sum(counts[face] for face in even), len(rolls))
print("Fair die: Ω =", tuple(die), "; exact P(even) =", event_mass(die, even))
print("Two fair independent coins: exact P(one head) =", event_mass(coins, {"HT", "TH"}))
print("Unequal weights: exact P(green or blue) =", event_mass(weighted, {"green", "blue"}))
print("24 observed rolls, seed 2026:", rolls)
print("Empirical even frequency =", observed_even, "(not a replacement for P(even) = 1/2)")
if __name__ == "__main__":
main()"""Finite experiment masses as arrays; NumPy decimals approximate exact fractions.
Small-array comparisons use absolute tolerance 1e-12 and zero relative tolerance.
The tolerance checks arithmetic, not whether a physical experiment is fair.
"""
from fractions import Fraction as F
import numpy as np
ATOL = 1e-12
def validate_weights(weights):
p = np.asarray(weights, dtype=float)
if p.ndim != 1 or p.size == 0 or not np.all(np.isfinite(p)) or np.any(p < 0):
raise ValueError("Use a nonempty finite nonnegative mass vector")
if not np.isclose(p.sum(), 1.0, rtol=0, atol=ATOL):
raise ValueError("Mass vector must sum to one within floating-point tolerance")
return p # No clipping or silent normalization.
def main():
faces = np.arange(1, 7)
p = validate_weights(np.full(6, 1 / 6))
even = faces % 2 == 0
even_mass = p[even].sum()
np.testing.assert_allclose(even_mass, float(F(1, 2)), rtol=0, atol=ATOL)
np.testing.assert_allclose(p[faces == 6].sum(), float(F(1, 6)), rtol=0, atol=ATOL)
assert p[np.zeros(6, dtype=bool)].sum() == 0
coins = np.array(["HH", "HT", "TH", "TT"])
coin_mass = validate_weights(np.full(4, 1 / 4))
one_head = np.isin(coins, ["HT", "TH"])
np.testing.assert_allclose(coin_mass[one_head].sum(), float(F(1, 2)), rtol=0, atol=ATOL)
# Counting heads merges HT and TH into a group with twice the other masses.
head_counts = np.array([2, 1, 1, 0])
grouped = np.bincount(head_counts, weights=coin_mass, minlength=3)
np.testing.assert_allclose(grouped, [float(F(1, 4)), float(F(1, 2)), float(F(1, 4))], rtol=0, atol=ATOL)
weighted = validate_weights([float(F(1, 2)), float(F(1, 3)), float(F(1, 6))])
np.testing.assert_allclose(weighted[[1, 2]].sum(), float(F(1, 2)), rtol=0, atol=ATOL)
for bad in ([], [0.5, 0.4], [-0.25, 1.25], [np.nan, 1.0], [np.inf], [[1.0]]):
try:
validate_weights(bad)
except ValueError:
pass
else:
raise AssertionError("Invalid mass vector was accepted")
print("Die event mask:", even, "; P(even) ≈", even_mass, "(exact 1/2)")
print("Two-coin head-count masses ≈", grouped, "(exact 1/4, 1/2, 1/4)")
print("Weighted green-or-blue mass ≈", weighted[[1, 2]].sum(), "(exact 1/2)")
if __name__ == "__main__":
main()Explore
Construct the singleton event containing , the empty event, and the whole die space. Predict , , and before inspecting the answers. Return to the even faces and compare their model mass with the observed frequency. Change Experiment seed, increase Observed trials, then use Replay seed. Neither setting changes the model probabilities. The stage’s display shows at most the first 16 outcomes while its frequency includes all requested trials, bounded at 2000.
Choose Weighted die or edit a raw weight to break equiprobability. In the weighted reference example, compare two selected labels with half the total mass: the number of labels is not the denominator of a universal probability rule. Choose Two fair coins to inspect the four ordered outcomes.
Common mistakes and counterexamples
Three even observations in a row do not imply that the model now contains only even faces. A fair independent die does not owe you an odd face after a streak. Conversely, a streak does not prove a die fair: fairness is stipulated here; estimating a physical die’s probabilities from data is a later statistical problem.
For a counterexample to counting alone, assign red, green, and blue masses . Selecting green and blue gives , although two of three labels are selected. Treating those labels as equally likely silently replaces the model.
Numerical considerations
The finite examples have exact rational answers. Python constructs Fraction(1, 6) from integers; constructing a fraction from a binary floating-point approximation would preserve that approximation instead. NumPy arrays use floating-point masses and sums, so the reference marks these comparisons as approximate and checks absolute error with an explicit tolerance, not a claim of exact equality.
An empirical frequency is an integer count divided by the number of observed trials. It may differ substantially from model probability at small sample sizes. The seeded sequence is reproducible in the reference environment, bounded, and illustrative; it is not a proof of a probability or a cross-language random-generator contract.
Engineering and ML connections
Finite models appear in categorical predictions, randomized tests, and simulation design. Before using a probability vector, check that labels are distinct, weights are nonnegative, and total mass is one. A model’s predicted probability and an observed class count answer different questions; mixing them can make evaluation circular.
Exercises
Enter exact fractions where appropriate. Each exercise offers corrective feedback and a worked solution after an attempt.
Summary and checkpoints
A sample space lists possibilities; a probability model weights them; an event selects a set; an observation records what happened. Check that you can justify the fair-die denominator, keep two coin positions distinct, sum unequal weights, and reject invalid models without confusing them with rare outcomes.