def compute_tukey_hh_params()

in tensorflow_transform/gaussianization.py [0:0]


def compute_tukey_hh_params(l_skewness_and_kurtosis):
  """Computes the H paramesters of a Tukey HH distribution.

  Given the L-skewness and L-kurtosis of a Tukey HH distribution we compute
  the H parameters of the distribution.

  Args:
    l_skewness_and_kurtosis: A np.array with shape (2,) containing L-skewness
    and L-kurtosis.

  Returns:
    An np.array with the same type and shape of the argument containing the
    left and right H parameters of the distribution.
  """

  # Exit conditions for the search loop.
  stop_iter_step = 20  # Max number of iteration for the search loop.
  stop_error_step = 1e-6  # Minimum function variation.
  stop_value_step = 1e-6  # Minimum variable variation.

  dtype = l_skewness_and_kurtosis.dtype

  # Returns zero parameters (i.e. treat as gaussian) if L-kurtosis is smaller
  # than for a gaussian.

  result = np.zeros_like(l_skewness_and_kurtosis)
  if l_skewness_and_kurtosis[1] < 0.1226017:
    return result

  # If L-skewness is negative, swap the parameters.

  swap_params = False
  if l_skewness_and_kurtosis[0] < 0.0:
    l_skewness_and_kurtosis[0] = -l_skewness_and_kurtosis[0]
    swap_params = True

  l_skewness_and_kurtosis[1] = np.minimum(
      l_skewness_and_kurtosis[1], 1.0 - 1.0e-5)

  # If L-skewness is zero, left and right parameters are equal and there is a
  # a closed form to compute them from L-kurtosis. We start from this value
  # and then change them to match simultaneously L-skeweness and L-kurtosis.
  # For that, we parametrize the search space with the array
  # [h_rigth, h_right - h_left], i.e. the value of the right parameter and the
  # difference right minus left paramerters. In the search iteration, we
  # alternate between updates on the first and the second entry of the search
  # parameters.

  initial_h = 3.0 - 1.0 / np.cos(
      np.pi / 15.0 * (l_skewness_and_kurtosis[1] - 6.0))
  search_params = np.array([initial_h, 0.0], dtype=dtype)

  # Current lower and upper bounds for the search parameters.

  min_search_params = np.array([initial_h, 0.0], dtype=dtype)
  max_search_params = np.array([1.0 - 1.0e-7, initial_h], dtype=dtype)

  current_iter = 0
  previous_search_params = np.zeros_like(search_params)
  while current_iter < stop_iter_step:
    # Search for L-skewness at constant h. Increase delta_h.
    error_skewness = lambda x: _params_to_errors(  # pylint: disable=g-long-lambda
        search_params[0], x, l_skewness_and_kurtosis)[0]
    if error_skewness(max_search_params[1]) > 0.0:
      low_delta_h, high_delta_h = _binary_search(
          error_skewness, min_search_params[1], max_search_params[1])
      search_params[1] = high_delta_h
      max_search_params[1] = high_delta_h  # The new delta is an upperbound.
      upperbound_delta_found = True
    else:
      search_params[1] = max_search_params[1]
      min_search_params[1] = max_search_params[1]  # No solution: lowerbound.
      upperbound_delta_found = False

    # Search for L-kurtosis at constant possibly overestimated delta.
    error_kurtosis = lambda x: _params_to_errors(  # pylint: disable=g-long-lambda
        x, search_params[1], l_skewness_and_kurtosis)[1]
    low_h, high_h = _binary_search(
        error_kurtosis, min_search_params[0], max_search_params[0])
    if upperbound_delta_found:
      search_params[0] = high_h
      max_search_params[0] = high_h   # Delta overestimated: upperbound for h.
    else:
      search_params[0] = low_h
      min_search_params[0] = low_h   # Delta underestimated: lowerbound for h.
      max_search_params[1] = low_h  # Delta not found, search on full range.

    if upperbound_delta_found:  # If not found, we repeat the first 2 steps.
      # Otherwise, Search for delta at constant overestimated h.
      error_skewness = lambda x: _params_to_errors(  # pylint: disable=g-long-lambda
          search_params[0], x, l_skewness_and_kurtosis)[0]
      low_delta_h, high_delta_h = _binary_search(
          error_skewness, min_search_params[1], max_search_params[1])
      search_params[1] = low_delta_h
      min_search_params[1] = low_delta_h

      # Search for h at constant delta.
      error_kurtosis = lambda x: _params_to_errors(  # pylint: disable=g-long-lambda
          x, search_params[1], l_skewness_and_kurtosis)[1]
      low_h, high_h = _binary_search(
          error_kurtosis, min_search_params[0], max_search_params[0])
      search_params[0] = low_h
      min_search_params[0] = low_h

    current_error = _params_to_errors(
        search_params[0], search_params[1], l_skewness_and_kurtosis)
    delta_search_params = search_params - previous_search_params
    current_iter += 1
    previous_search_params = search_params.copy()
    if (np.all(np.abs(current_error) < stop_error_step) or
        np.all(np.abs(delta_search_params) < stop_value_step)):
      break

  result[0] = search_params[0] - search_params[1]
  result[1] = search_params[0]
  if swap_params:
    result = result[::-1]
  return result