docs: def entropy(data=None, prob=None, tol=1e-5):
      '''
      given a probability distribution (prob) or an interable of symbols (data) compute and
      return its entropy
  
      inputs:
      ------
          data:       iterable of symbols
  
          prob:       iterable with probabilities
  
          tol:        if prob is given, 'entropy' checks that the sum is about 1.
                      It raises an error if abs(sum(prob)-1) >= tol
      '''
  
      if prob is None and data is None:
          raise ValueError("%s.entropy requires either 'prob' or 'data' to be defined" % __name__)
  
      if prob is not None and data is not None:
          raise ValueError("%s.entropy requires only 'prob' or 'data to be given but not both" % __name__)
  
      if prob is not None and not isinstance(prob, np.ndarray):
          raise TypeError("'entropy' in '%s' needs 'prob' to be an ndarray" % __name__)
  
      if prob is not None and abs(prob.sum()-1) > tol:
          raise ValueError("parameter 'prob' in '%s.entropy' should sum to 1" % __name__)
  
      if data is not None:
          prob = symbols_to_prob(data).prob()
  
      # compute the log2 of the probability and change any -inf by 0s
      logProb = np.log2(prob)
      logProb[logProb == -np.inf] = 0
  
      # return dot product of logProb and prob
      return -float(np.dot(prob, logProb))