code: def _kl_divergence_bh(
      params,
      P,
      neighbors,
      degrees_of_freedom,
      n_samples,
      n_components,
      angle=0.5,
      skip_num_points=0,
      verbose=False,
  ):
      """t-SNE objective function: KL divergence of p_ijs and q_ijs.
  
      Uses Barnes-Hut tree methods to calculate the gradient that
      runs in O(NlogN) instead of O(N^2)
  
      Parameters
      ----------
      params : array, shape (n_params,)
          Unraveled embedding.
  
      P : array, shape (n_samples * (n_samples-1) / 2,)
          Condensed joint probability matrix.
  
      neighbors: int64 array, shape (n_samples, K)
          Array with element [i, j] giving the index for the jth
          closest neighbor to point i.
  
      degrees_of_freedom : float
          Degrees of freedom of the Student's-t distribution.
  
      n_samples : int
          Number of samples.
  
      n_components : int
          Dimension of the embedded space.
  
      angle : float (default: 0.5)
          This is the trade-off between speed and accuracy for Barnes-Hut T-SNE.
          'angle' is the angular size (referred to as theta in [3]) of a distant
          node as measured from a point. If this size is below 'angle' then it is
          used as a summary node of all points contained within it.
          This method is not very sensitive to changes in this parameter
          in the range of 0.2 - 0.8. Angle less than 0.2 has quickly increasing
          computation time and angle greater 0.8 has quickly increasing error.
  
      skip_num_points : int (optional, default:0)
          This does not compute the gradient for points with indices below
          `skip_num_points`. This is useful when computing transforms of new
          data where you'd like to keep the old data fixed.
  
      verbose : int
          Verbosity level.
  
      Returns
      -------
      kl_divergence : float
          Kullback-Leibler divergence of p_ij and q_ij.
  
      grad : array, shape (n_params,)
          Unraveled gradient of the Kullback-Leibler divergence with respect to
          the embedding.
      """
      params = astype(params, np.float32, copy=False)
      X_embedded = params.reshape(n_samples, n_components)
      neighbors = astype(neighbors, np.int64, copy=False)
      if len(P.shape) == 1:
          sP = squareform(P).astype(np.float32)
      else:
          sP = P.astype(np.float32)
  
      grad = np.zeros(X_embedded.shape, dtype=np.float32)
      error = _barnes_hut_tsne.gradient(
          sP,
          X_embedded,
          neighbors,
          grad,
          angle,
          n_components,
          verbose,
          dof=degrees_of_freedom,
      )
      c = 2.0 * (degrees_of_freedom + 1.0) / degrees_of_freedom
      grad = grad.ravel()
      grad *= c
  
      return error, grad
  
imports: import numpy
  from scipy import linalg
  import scipy.sparse
  from scipy.spatial.distance import pdist
  from scipy.spatial.distance import squareform
  from ..neighbors import BallTree
  from ..base import BaseEstimator
  from ..utils import check_array
  from ..utils import check_random_state
  from ..utils.extmath import _ravel
  from ..decomposition import PCA
  from ..metrics.pairwise import pairwise_distances
  from .None import _utils
  from .None import _barnes_hut_tsne
  from ..utils.fixes import astype
  from ..externals.six import string_types
label_desc: Use image node_id 5 for calling a global function with example usage: _kl_divergence_bh(params, P, neighbors, degrees_of_freedom, n_samples, n_components, angle, skip_num_points, verbose) and returns: error,  grad