text: """
  _normalize_columns.py : Normalize columns.
  """
  
  import numpy as np
  
  
  def normalize_columns(columns):
      """
      Normalize columns of matrix.
  
      Parameters
      ----------
      columns : 2d array (M x N)
          Matrix with columns
  
      Returns
      -------
      normalized_columns : 2d array (M x N)
          columns/np.sum(columns, axis=0, keepdims=1)
      """
  
      # broadcast sum over columns
      normalized_columns = columns/np.sum(columns, axis=0, keepdims=1)
      return normalized_columns
  
  
  def normalize_power_columns(x, exponent):
      """
      Calculate normalize_columns(x**exponent)
      in a numerically safe manner.
  
      Parameters
      ----------
      x : 2d array (M x N)
          Matrix with columns
      n : float
          Exponent
  
      Returns
      -------
      result : 2d array (M x N)
          normalize_columns(x**n) but safe
      """
  
      assert np.all(x >= 0.0)
  
      x = x.astype(np.float64)
  
      # values in range [0, 1]
      x = x/np.max(x, axis=0, keepdims=True)
  
      # values in range [eps, 1]
      x = np.fmax(x, np.finfo(x.dtype).eps)
  
      if exponent < 0:
          # values in range [1, 1/eps]
          x /= np.min(x, axis=0, keepdims=True)
  
          # values in range [1, (1/eps)**exponent] where exponent < 0
          # this line might trigger an underflow warning
          # if (1/eps)**exponent becomes zero, but that's ok
          x = x**exponent
      else:
          # values in range [eps**exponent, 1] where exponent >= 0
          x = x**exponent
      result = normalize_columns(x)
      return result
  