{"record":{"id":"be827c50895fd990","repo":"aosabook/500lines","slug":"outcome-probabilities-do-not-sum-to-1","errorCode":null,"errorMessage":"outcome probabilities do not sum to 1","messagePattern":"outcome probabilities do not sum to 1","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sampler/code/multinomial.py","lineNumber":24,"sourceCode":"\n    def __init__(self, p, rso=np.random):\n        \"\"\"Initialize the multinomial random variable.\n\n        Parameters\n        ----------\n        p: numpy array of length `k`\n            The outcome probabilities\n        rso: numpy RandomState object (default: np.random)\n            The random number generator\n\n        \"\"\"\n\n        # Check that the probabilities sum to 1. If they don't, then\n        # something is wrong! We use `np.isclose` rather than checking\n        # for exact equality because in many cases, we won't have\n        # exact equality due to floating-point error.\n        if not np.isclose(np.sum(p), 1.0):\n            raise ValueError(\"outcome probabilities do not sum to 1\")\n\n        # Store the parameters that were passed in\n        self.p = p\n        self.rso = rso\n\n        # Precompute log probabilities, for use by the log-PMF, for\n        # each element of `self.p` (the function `np.log` operates\n        # elementwise over NumPy arrays, as well as on scalars.)\n        self.logp = np.log(self.p)\n\n    def sample(self, n):\n        \"\"\"Samples draws of `n` events from a multinomial distribution with\n        outcome probabilities `self.p`.\n\n        Parameters\n        ----------\n        n: integer\n            The number of total events","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/aosabook/500lines/blob/fba689d101eb5600f5c8f4d7fd79912498e950e2/sampler/code/multinomial.py#L6-L42","documentation":"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.","triggerScenarios":"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.","commonSituations":"Hand-coded probabilities that miscount; loading counts instead of probabilities; integer arrays; floating-point accumulation error on many categories exceeding the default tolerance.","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."],"exampleFix":"// before\ndist = MultinomialDistribution(np.array([0.2, 0.5, 0.2]))   # sums to 0.9 -> ValueError\n// after\np = np.array([0.2, 0.5, 0.2])\np = p / p.sum()\ndist = MultinomialDistribution(p)","handlingStrategy":"validation","validationCode":"import numpy as np\n\ndef valid_prob_vector(p):\n    p = np.asarray(p, dtype=float)\n    return (p.ndim == 1 and p.size > 0\n            and np.all(p >= 0)\n            and np.isclose(np.sum(p), 1.0))\n\nif not valid_prob_vector(p):\n    p = np.asarray(p, dtype=float)\n    p = p / p.sum()","typeGuard":"def is_probability_vector(p):\n    p = np.asarray(p, dtype=float)\n    return (isinstance(p, np.ndarray) and p.ndim == 1\n            and np.all(np.isfinite(p)) and np.all(p >= 0)\n            and np.isclose(p.sum(), 1.0))","tryCatchPattern":"try:\n    dist = MultinomialDistribution(p)\nexcept ValueError:\n    p = np.asarray(p, dtype=float) / np.sum(p)\n    dist = MultinomialDistribution(p)","preventionTips":["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)."],"tags":["probability","numpy","validation","statistics","constructor"],"backgroundTag":null,"analyzedSha":"fba689d101eb5600f5c8f4d7fd79912498e950e2","analyzedAt":"2026-08-13T06:26:32.792Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}