code: def PruningLogprobChange(
      self, count, discount, backoff_count, backoff_total
  ):
      if count == 0:
          return 0.0
  
      assert (
          discount > 0
          and backoff_total >= backoff_count
          and backoff_total >= 0.99 * discount
      )
  
      # augmented_count is like 'count', but with the extra count for symbol
      # 'a' due to backoff included.
      augmented_count = count + discount * backoff_count / backoff_total
  
      # We imagine a phantom symbol 'b' that represents all symbols other than
      # 'a' appearing in this history-state that are accessed via backoff.  We
      # treat these as being distinct symbols from the same symbol if accessed
      # not-via-backoff.  (Treating same symbols as distinct gives an upper bound
      # on the divergence).  We also treat them as distinct from the same symbols
      # that are being accessed via backoff from other states.  b_count is the
      # observed count of symbol 'b' in this state (the backed-off count is
      # zero).  b_count is also the count of symbol 'b' in the backoff state.
      # Note: b_count will not be negative because backoff_total >= backoff_count.
      b_count = discount * (
          (backoff_total - backoff_count) / backoff_total
      )
      assert b_count >= -0.001 * backoff_total
  
      # We imagine a phantom symbol 'c' that represents all symbols other than
      # 'a' and 'b' appearing in the backoff state, which got there from
      # backing off other states (other than 'this' state).  Again, we imagine
      # the symbols are distinct even though they may not be (i.e. that c and
      # b represent disjoint sets of symbol, even though they might not really
      # be disjoint), and this gives us an upper bound on the divergence.
      c_count = backoff_total - backoff_count - b_count
      assert c_count >= -0.001 * backoff_total
  
      # a_other is the count of 'a' in the backoff state that comes from
      # 'other sources', i.e. it was backed off from history-states other than
      # the current history state.
      a_other_count = (
          backoff_count - discount * backoff_count / backoff_total
      )
      assert a_other_count >= -0.001 * backoff_count
  
      # the following sub-expressions are the 'new' versions of certain
      # quantities after we assign the total count 'count' to backoff.  it
      # increases the backoff count in 'this' state, and also the total count
      # in the backoff state, and the count of symbol 'a' in the backoff
      # state.
      new_backoff_count = (
          backoff_count + count
      )  # new count of symbol 'a' in
      # backoff state
      new_backoff_total = backoff_total + count  # new total count in
      # backoff state.
      new_discount = (
          discount + count
      )  # new discount-count in 'this' state.
  
      # all the loglike changes below are of the form
      # count-of-symbol * log(new prob / old prob)
      # which can be more conveniently written (by canceling the denominators),
      # count-of-symbol * log(new count / old count).
  
      # this_a_change is the log-like change of symbol 'a' coming from 'this'
      # state.  bear in mind that
      # augmented_count = count + discount * backoff_count / backoff_total,
      # and the 'count' term is zero in the numerator part of the log expression,
      # because symbol 'a' is completely backed off in 'this' state.
      this_a_change = augmented_count * math.log(
          (new_discount * new_backoff_count / new_backoff_total)
          / augmented_count
      )
  
      # other_a_change is the log-like change of symbol 'a' coming from all
      # other states than 'this'.  For speed reasons we don't examine the
      # direct (non-backoff) counts of symbol 'a' in all other states than
      # 'this' that back off to the backoff state-- it would be slower.
      # Instead we just treat the direct part of the prob for symbol 'a' as a
      # distinct symbol when it comes from those other states... as usual,
      # doing so gives us an upper bound on the divergence.
      other_a_change = a_other_count * math.log(
          (new_backoff_count / new_backoff_total)
          / (backoff_count / backoff_total)
      )
  
      # b_change is the log-like change of phantom symbol 'b' coming from
      # 'this' state (and note: it only comes from this state, that's how we
      # defined it).
      # note: the expression below could be more directly written as a
      # ratio of pseudo-counts as follows, by converting the backoff probabilities
      # into pseudo-counts in 'this' state:
      #  b_count * logf((new_discount * b_count / new_backoff_total) /
      #                 (discount * b_count / backoff_total),
      # but we cancel b_count to give us the expression below.
      b_change = b_count * math.log(
          (new_discount / new_backoff_total)
          / (discount / backoff_total)
      )
  
      # c_change is the log-like change of phantom symbol 'c' coming from
      # all other states that back off to the backoff sate (and all prob. mass of
      # 'c' comes from those other states).  The expression below could be more
      # directly written as a ratio of counts, as c_count * logf((c_count /
      # new_backoff_total) / (c_count / backoff_total)), but we simplified it to
      # the expression below.
      c_change = c_count * math.log(backoff_total / new_backoff_total)
  
      ans = this_a_change + other_a_change + b_change + c_change
      # the answer should not be positive.
      assert ans <= 0.0001 * (
          count + discount + backoff_count + backoff_total
      )
      if args.verbose >= 4:
          print(
              "pruning-logprob-change for {0},{1},{2},{3} is {4}".format(
                  count, discount, backoff_count, backoff_total, ans
              ),
              file=sys.stderr,
          )
      return ans
  
imports: import argparse
  import math
  import sys
  from collections import defaultdict
label_desc: Use image node_id 14 for calling the NgramCounts obj's underlying member method code with example usage: obj.PruningLogprobChange(count, discount, backoff_count, backoff_total) and returns: ans, int