aosabook/500lines · error · ValueError
outcome probabilities do not sum to 1
Error message
outcome probabilities do not sum to 1
What it means
Raised by MultinomialDistribution.__init__ when np.sum(p) is not close to 1.0 (np.isclose default tolerances: rtol=1e-05, atol=1e-08). The constructor treats a normalized probability vector as a hard precondition because sampling, log_pmf, and pmf all assume a valid distribution. A vector summing to anything else is treated as a programming/data error, not tolerated input.
Source
Thrown at sampler/code/multinomial.py:24
def __init__(self, p, rso=np.random):
"""Initialize the multinomial random variable.
Parameters
----------
p: numpy array of length `k`
The outcome probabilities
rso: numpy RandomState object (default: np.random)
The random number generator
"""
# Check that the probabilities sum to 1. If they don't, then
# something is wrong! We use `np.isclose` rather than checking
# for exact equality because in many cases, we won't have
# exact equality due to floating-point error.
if not np.isclose(np.sum(p), 1.0):
raise ValueError("outcome probabilities do not sum to 1")
# Store the parameters that were passed in
self.p = p
self.rso = rso
# Precompute log probabilities, for use by the log-PMF, for
# each element of `self.p` (the function `np.log` operates
# elementwise over NumPy arrays, as well as on scalars.)
self.logp = np.log(self.p)
def sample(self, n):
"""Samples draws of `n` events from a multinomial distribution with
outcome probabilities `self.p`.
Parameters
----------
n: integer
The number of total eventsView on GitHub (pinned to fba689d101)
Solutions
- Normalize p before constructing: p = np.asarray(p, dtype=float); p = p / p.sum().
- Recheck each probability and the category count for missing/extra entries.
- Ensure p is non-negative and 1-dimensional.
- If a tiny deviation is expected, normalize it away rather than loosening the library's check.
Example fix
// before dist = MultinomialDistribution(np.array([0.2, 0.5, 0.2])) # sums to 0.9 -> ValueError // after p = np.array([0.2, 0.5, 0.2]) p = p / p.sum() dist = MultinomialDistribution(p)
Defensive patterns
Strategy: validation
Validate before calling
import numpy as np
def valid_prob_vector(p):
p = np.asarray(p, dtype=float)
return (p.ndim == 1 and p.size > 0
and np.all(p >= 0)
and np.isclose(np.sum(p), 1.0))
if not valid_prob_vector(p):
p = np.asarray(p, dtype=float)
p = p / p.sum() Type guard
def is_probability_vector(p):
p = np.asarray(p, dtype=float)
return (isinstance(p, np.ndarray) and p.ndim == 1
and np.all(np.isfinite(p)) and np.all(p >= 0)
and np.isclose(p.sum(), 1.0)) Try / catch
try:
dist = MultinomialDistribution(p)
except ValueError:
p = np.asarray(p, dtype=float) / np.sum(p)
dist = MultinomialDistribution(p) Prevention
- Always normalize probability vectors before construction.
- Validate shape, finiteness, and non-negativity in addition to the sum.
- Unit-test constructors with edge vectors (a single 1.0, large k, zeros).
When it happens
Trigger: Constructing MultinomialDistribution(p=...) where p does not sum to 1, e.g. np.array([0.2, 0.5]) sums to 0.7; probabilities loaded from a misconfigured source; forgetting to normalize; rounding on a large k that pushes the sum outside np.isclose tolerance.
Common situations: Hand-coded probabilities that miscount; loading counts instead of probabilities; integer arrays; floating-point accumulation error on many categories exceeding the default tolerance.
AI-assisted analysis of aosabook/500lines@fba689d101 (2026-08-13).
Data as JSON: /api/errors/be827c50895fd990.
Report an issue: GitHub.