⚙️ Setup¶
import numpy as np
rng = np.random.default_rng(313)
print("ready")
ready
p_red = 26/52; p_king = 4/52; p_red_king = 2/52 # king of hearts, king of diamonds
p_or = p_red + p_king - p_red_king
print(f"P(red OR king) = 26/52 + 4/52 - 2/52 = {p_or:.3f}")
# simulate: encode a deck
colors = np.repeat([0,1],26) # 0=black,1=red
ranks = np.tile(np.arange(13),4) # 12 = king
idx = rng.integers(0,52,300_000)
emp = np.mean((colors[idx]==1) | (ranks[idx]==12))
print(f"empirical (300k draws) = {emp:.3f}")
P(red OR king) = 26/52 + 4/52 - 2/52 = 0.538 empirical (300k draws) = 0.539
Answer: there are 26 red cards and 4 kings, but 2 cards (king of hearts, king of diamonds) are both, so they would be counted twice. P(red or king) = 26/52 + 4/52 - 2/52 = 28/52 ≈ 0.538. Subtracting the overlap is the whole point of the addition rule.
p2, p5 = 1/6, 1/6
print(f"P(2 or 5) = P(2) + P(5) = {p2:.3f} + {p5:.3f} = {p2+p5:.3f}")
print("P(2 AND 5) = 0 on a single die -> mutually exclusive, so no overlap term")
P(2 or 5) = P(2) + P(5) = 0.167 + 0.167 = 0.333 P(2 AND 5) = 0 on a single die -> mutually exclusive, so no overlap term
Answer: a single die cannot show both a 2 and a 5, so the events are mutually exclusive: P(2 and 5) = 0. The addition rule loses its overlap term and becomes plain addition, P(2 or 5) = 1/6 + 1/6 = 1/3.
p_h, p_6 = 1/2, 1/6
p_and = p_h * p_6
print(f"P(heads AND six) = P(heads) x P(six) = {p_h} x {p_6:.3f} = {p_and:.3f}")
flips = rng.integers(0,2,300_000); rolls = rng.integers(1,7,300_000)
emp = np.mean((flips==1) & (rolls==6))
print(f"empirical (300k) = {emp:.3f}")
P(heads AND six) = P(heads) x P(six) = 0.5 x 0.167 = 0.083 empirical (300k) = 0.084
Answer: the coin and the die do not influence each other, so they are independent and the probabilities multiply: P(heads and six) = 1/2 x 1/6 = 1/12 ≈ 0.083, confirmed by simulation. For independent events, AND means multiply.
pA, pB = 0.5, 0.4
for label, pAB in [("case (i)",0.2),("case (ii)",0.0)]:
indep = np.isclose(pAB, pA*pB)
mutex = np.isclose(pAB, 0.0)
print(f"{label}: P(A and B)={pAB}, P(A)xP(B)={pA*pB:.2f} -> independent={indep}, mutually exclusive={mutex}")
case (i): P(A and B)=0.2, P(A)xP(B)=0.20 -> independent=True, mutually exclusive=False case (ii): P(A and B)=0.0, P(A)xP(B)=0.20 -> independent=False, mutually exclusive=True
Answer: case (i) has P(A and B) = 0.2 = 0.5 x 0.4, so the events are independent (and clearly not mutually exclusive, they overlap). Case (ii) has P(A and B) = 0, so they are mutually exclusive, and since 0 ≠ 0.20 they are not independent. Same two events, opposite relationships, decided only by the test P(A and B) = P(A)xP(B).
p_make = 0.8
p_all_make = p_make**5
p_at_least_one_miss = 1 - p_all_make
print(f"P(make all 5) = 0.8^5 = {p_all_make:.3f}")
print(f"P(at least one miss) = 1 - that = {p_at_least_one_miss:.3f}")
shots = rng.random((300_000,5)) < 0.8
emp = np.mean(~shots.all(axis=1))
print(f"empirical (300k) = {emp:.3f}")
P(make all 5) = 0.8^5 = 0.328 P(at least one miss) = 1 - that = 0.672 empirical (300k) = 0.672
Answer: "at least one miss" is the complement of "makes all five". Made shots are independent, so P(all five) = 0.8^5 ≈ 0.328 by the multiplication rule, and P(at least one miss) = 1 - 0.328 ≈ 0.672. Even an 80% shooter misses at least once about two-thirds of the time over five attempts, the complement makes that easy to see.