docs: def softmax(x: np.ndarray,
              b: float = 1.0) -> np.ndarray:
      r"""
      Standard softmax function:
  
      .. math::
  
          P_i = \frac {e ^ {\beta \cdot x_i}} { \sum_{i}{\beta \cdot x_i} }
  
      Args:
          x: vector (``numpy.array``) of values
          b: exploration parameter :math:`\beta`, or inverse temperature
              [Daw2009], or :math:`1/t`; see below
  
      Returns:
          vector of probabilities corresponding to the input values
  
      where:
  
      - :math:`t` is temperature (towards infinity: all actions equally likely;
        towards zero: probability of action with highest value tends to 1)
      - Temperature is not used directly as optimizers may take it to zero,
        giving an infinity; use inverse temperature instead.
      - [Daw2009] Daw ND, "Trial-by-trial data analysis using computational
        methods", 2009/2011; in "Decision Making, Affect, and Learning: Attention
        and Performance XXIII"; Delgado MR, Phelps EA, Robbins TW (eds),
        Oxford University Press.
  
      """
      constant = np.mean(x)
      products = x * b - constant
      # ... softmax is invariant to addition of a constant: Daw article and
      # http://www.faqs.org/faqs/ai-faq/neural-nets/part2/section-12.html#b
      # noinspection PyUnresolvedReferences
      if products.max() > sys.float_info.max_exp:
          # ... max_exp for base e; max_10_exp for base 10
          log.warning("OVERFLOW in softmax(): x = {}, b = {}, constant = {}, "
                      "x*b - constant = {}".format(x, b, constant, products))
          # map the maximum to 1, other things to zero
          n = len(x)
          index_of_max = np.argmax(products)
          answer = np.zeros(n)
          answer[index_of_max] = 1.0
      else:
          # noinspection PyUnresolvedReferences
          exponented = np.exp(products)
          answer = exponented / np.sum(exponented)
      return answer