docs: def mi(x, y):
      '''
      compute and return the mutual information between x and y
  
      inputs:
      -------
          x, y:   iterables of hashable items
  
      output:
      -------
          mi:     float
  
      Notes:
      ------
          if you are trying to mix several symbols together as in mi(x, (y0,y1,...)), try
  
          info[p] = _info.mi(x, info.combine_symbols(y0, y1, ...) )
      '''
      # dict.values() returns a view object that has to be converted to a list before being
      # converted to an array
      # the following lines will execute properly in python3, but not python2 because there
      # is no zip object
      try:
          if isinstance(x, zip):
              x = list(x)
          if isinstance(y, zip):
              y = list(y)
      except:
          pass
  
      probX = symbols_to_prob(x).prob()
      probY = symbols_to_prob(y).prob()
      probXY = symbols_to_prob(combine_symbols(x, y)).prob()
  
      return entropy(prob=probX) + entropy(prob=probY) - entropy(prob=probXY)