{"record":{"id":"d9b1feaeee854531","repo":"stanfordnlp/CoreNLP","slug":"total-mass-must-be-positive","errorCode":null,"errorMessage":"total mass must be positive!","messagePattern":"total mass must be positive!","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/stats/Multinomial.java","lineNumber":25,"sourceCode":" * a counter.  It is assumed that the Counter's keySet() contains all of the parameters (i.e., there are not other\n * possible values which are set to 0).  It makes a copy of the Counter, so tha parameters cannot be changes,\n * and it normalizes the values if they are not already normalized.\n *\n * @author Jenny Finkel\n */\n\npublic class Multinomial<E> implements ProbabilityDistribution<E> {\n\n  /**\n   * \n   */\n  private static final long serialVersionUID = -697457414113362926L;\n  private Counter<E> parameters;\n\n  public Multinomial(Counter<E> parameters) {\n    double totalMass = parameters.totalCount();\n    if (totalMass <= 0.0) {\n      throw new RuntimeException(\"total mass must be positive!\");\n    }\n\n    this.parameters = new ClassicCounter<>();\n    for (E object : parameters.keySet()) {\n      double oldCount = parameters.getCount(object);\n      if (oldCount < 0.0) {\n        throw new RuntimeException(\"no negative parameters allowed!\");\n      }\n      this.parameters.setCount(object, oldCount/totalMass);\n    }\n  }\n\n  public Counter<E> getParameters() {\n    return new ClassicCounter<>(parameters);\n  }\n  \n  public double probabilityOf(E object) {\n    if (!parameters.keySet().contains(object)) {","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/stats/Multinomial.java#L7-L43","documentation":"The Multinomial constructor normalizes the supplied Counter by its total mass; a total mass of zero or negative makes normalization meaningless, so the constructor throws immediately. This guards against building a distribution from an empty or all-zero counter.","triggerScenarios":"new Multinomial(counter) where counter.totalCount() <= 0.0 — an empty counter, a counter whose entries are all 0, or one with only negative counts.","commonSituations":"Estimating a multinomial from training data that produced no counts for a context (e.g. unseen n-gram context); forgetting to set counts before constructing; smearing/counting bugs that zero out all entries.","solutions":["Verify totalCount() > 0 before constructing; if not, fall back to a uniform distribution","Add smoothing (e.g. add-k smoothing) so total mass is positive even for unseen events","Fix upstream counting code that produced an empty/zero counter"],"exampleFix":"// before\nMultinomial<String> m = new Multinomial<>(counts); // throws if total is 0\n// after\ncounts.incrementCount(UNKNOWN, 1.0); // smooth\nMultinomial<String> m = new Multinomial<>(counts);","handlingStrategy":"validation","validationCode":"if (counter == null || counter.totalCount() <= 0.0) {\n  counter = new ClassicCounter<>(); counter.incrementCount(DEFAULT_KEY, 1.0); // uniform fallback\n}","typeGuard":"boolean isPositiveMass(Counter<?> c) { return c != null && c.totalCount() > 0.0; }","tryCatchPattern":"try {\n  return new Multinomial<>(counter);\n} catch (RuntimeException e) {\n  if (\"total mass must be positive!\".equals(e.getMessage())) {\n    return uniformMultinomial(counter == null ? Collections.emptySet() : counter.keySet());\n  }\n  throw e;\n}","preventionTips":["Add-k smoothing before building multinomials from sparse data","Check totalCount() after any counting pipeline stage","Treat empty contexts explicitly rather than passing empty counters"],"tags":["java","statistics","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a","analyzedAt":"2026-09-10T02:24:07.274Z","contentChangedAt":"2026-09-10T02:24:07.274Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}