docs: def perp(weights):
      r"""Calculate the normalized perplexity :math:`\mathcal{P}` of samples
      with ``weights`` :math:`\omega_i`. :math:`\mathcal{P}=0` is
      terrible and :math:`\mathcal{P}=1` is perfect.
  
      .. math::
  
          \mathcal{P} = exp(H) / N
  
      where
  
      .. math::
  
          H = - \sum_{i=1}^N \bar{\omega}_i log ~ \bar{\omega}_i
  
      .. math::
  
          \bar{\omega}_i = \frac{\omega_i}{\sum_i \omega_i}
  
      :param weights:
  
          Vector-like array; the samples' weights
  
      """
      # normalize weights
      w = _np.asarray(weights) / _np.sum(weights)
  
      # mask zero weights
      w = _np.ma.MaskedArray(w, copy=False, mask=(w == 0))
  
      # avoid NaN due to log(0) by log(1)=0
      entr = - _np.sum( w * _np.log(w.filled(1.0)))
  
      return  _np.exp(entr) / len(w)