aosabook/500lines · error · ValueError

event probabilities do not sum to 1

Error message

event probabilities do not sum to 1

What it means

Raised by the constructor of the multinomial distribution class in the sampler chapter. It validates that the supplied event-probability vector p sums to 1 using np.isclose(np.sum(p), 1.0) to tolerate floating-point drift; if not close it raises ValueError('event probabilities do not sum to 1'). The probabilities are then stored and used to precompute log-probabilities for the log-PMF.

Source

Thrown at sampler/sampler.markdown:223

    def __init__(self, p, rso=np.random):
        """Initialize the multinomial random variable.

        Parameters
        ----------
        p: numpy array of length `k`
            The event probabilities
        rso: numpy RandomState object (default: None)
            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("event 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)
```

The class takes as arguments the event probabilities, $p$, and a
variable called `rso`. First, the constructor checks that the
parameters are valid; i.e., that `p` sums to 1. Then it stores
the arguments that were passed in, and uses the event probabilities to
compute the event *log* probabilities. (We'll go into why this is
necessary in a bit). The `rso` object is what we'll use later to
produce random numbers. (We'll talk more about what it is a bit later

View on GitHub (pinned to fba689d101)

Solutions

  1. Normalise the vector before constructing: p = np.asarray(p, float); p = p / p.sum().
  2. Fix the source data so the intended probabilities genuinely sum to 1.
  3. If the values are weights, divide by their sum explicitly and document the transformation.
  4. Verify the array is non-empty and 1-D of length k.

Example fix

# before
p = np.array([0.2, 0.3, 0.3])            # sum 0.8 -> ValueError
dist = MultinomialDistribution(p, rso)

# after: normalise first
p = np.array([0.2, 0.3, 0.3], dtype=float)
p = p / p.sum()                          # -> [0.25, 0.375, 0.375], sum 1.0
assert np.isclose(p.sum(), 1.0)
dist = MultinomialDistribution(p, rso)
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np
p = np.asarray(raw_p, dtype=float)
assert p.ndim == 1 and p.size > 0, 'p must be a non-empty 1-D array'
if not np.isclose(p.sum(), 1.0):
    p = p / p.sum()      # normalise in place
assert np.isclose(p.sum(), 1.0)
dist = MultinomialDistribution(p, rso=rso)

Type guard

def is_probability_vector(p):
    p = np.asarray(p, dtype=float)
    return p.ndim == 1 and p.size > 0 and np.all(p >= 0) and np.isclose(p.sum(), 1.0)

Try / catch

try:
    dist = MultinomialDistribution(p, rso=rso)
except ValueError as e:
    if 'sum to 1' in str(e):
        p = np.asarray(p, float) / np.sum(p)
        dist = MultinomialDistribution(p, rso=rso)
    else:
        raise

Prevention

When it happens

Trigger: Constructing the distribution with a p whose sum is not ~1.0, e.g. [0.3, 0.3] (sum 0.6), [0.5, 0.6] (sum 1.1), or an empty array. Fires at instantiation time, before any sampling.

Common situations: Reading probabilities from a config/CSV that were not normalised; hand-tuning weights and forgetting to renormalise; rounding/truncation that drifts the sum outside np.isclose tolerance (~1e-8 relative); passing log-probabilities or counts instead of probabilities.


AI-assisted analysis of aosabook/500lines@fba689d101 (2026-08-13). Data as JSON: /api/errors/05ec572dbc3d7ab2. Report an issue: GitHub.