code: def sparse_euclidean_random_projection_split(
      inds, indptr, data, indices, rng_state
  ):
      """Given a set of ``graph_indices`` for graph_data points from a sparse graph_data set
      presented in csr sparse format as inds, graph_indptr and graph_data, create
      a random hyperplane to split the graph_data, returning two arrays graph_indices
      that fall on either side of the hyperplane. This is the basis for a
      random projection tree, which simply uses this splitting recursively.
      This particular split uses cosine distance to determine the hyperplane
      and which side each graph_data sample falls on.
      Parameters
      ----------
      inds: array
          CSR format index array of the matrix
      indptr: array
          CSR format index pointer array of the matrix
      data: array
          CSR format graph_data array of the matrix
      indices: array of shape (tree_node_size,)
          The graph_indices of the elements in the ``graph_data`` array that are to
          be split in the current operation.
      rng_state: array of int64, shape (3,)
          The internal state of the rng
      Returns
      -------
      indices_left: array
          The elements of ``graph_indices`` that fall on the "left" side of the
          random hyperplane.
      indices_right: array
          The elements of ``graph_indices`` that fall on the "left" side of the
          random hyperplane.
      """
      # Select two random points, set the hyperplane between them
      left_index = np.abs(tau_rand_int(rng_state)) % indices.shape[0]
      right_index = np.abs(tau_rand_int(rng_state)) % indices.shape[0]
      right_index += left_index == right_index
      right_index = right_index % indices.shape[0]
      left = indices[left_index]
      right = indices[right_index]
  
      left_inds = inds[indptr[left] : indptr[left + 1]]
      left_data = data[indptr[left] : indptr[left + 1]]
      right_inds = inds[indptr[right] : indptr[right + 1]]
      right_data = data[indptr[right] : indptr[right + 1]]
  
      # Compute the normal vector to the hyperplane (the vector between
      # the two points) and the offset from the origin
      hyperplane_offset = 0.0
      hyperplane_inds, hyperplane_data = sparse_diff(
          left_inds, left_data, right_inds, right_data
      )
      offset_inds, offset_data = sparse_sum(
          left_inds, left_data, right_inds, right_data
      )
      offset_data = offset_data / 2.0
      offset_inds, offset_data = sparse_mul(
          hyperplane_inds,
          hyperplane_data,
          offset_inds,
          offset_data.astype(np.float32),
      )
  
      for val in offset_data:
          hyperplane_offset -= val
  
      # For each point compute the margin (project into normal vector, add offset)
      # If we are on lower side of the hyperplane put in one pile, otherwise
      # put it in the other pile (if we hit hyperplane on the nose, flip a coin)
      n_left = 0
      n_right = 0
      side = np.empty(indices.shape[0], np.int8)
      for i in range(indices.shape[0]):
          margin = hyperplane_offset
          i_inds = inds[indptr[indices[i]] : indptr[indices[i] + 1]]
          i_data = data[indptr[indices[i]] : indptr[indices[i] + 1]]
  
          _, mul_data = sparse_mul(
              hyperplane_inds, hyperplane_data, i_inds, i_data
          )
          for val in mul_data:
              margin += val
  
          if abs(margin) < EPS:
              side[i] = abs(tau_rand_int(rng_state)) % 2
              if side[i] == 0:
                  n_left += 1
              else:
                  n_right += 1
          elif margin > 0:
              side[i] = 0
              n_left += 1
          else:
              side[i] = 1
              n_right += 1
  
      # If all points end up on one side, something went wrong numerically
      # In this case, assign points randomly; they are likely very close anyway
      if n_left == 0 or n_right == 0:
          n_left = 0
          n_right = 0
          for i in range(indices.shape[0]):
              side[i] = abs(tau_rand_int(rng_state)) % 2
              if side[i] == 0:
                  n_left += 1
              else:
                  n_right += 1
  
      # Now that we have the counts allocate arrays
      indices_left = np.empty(n_left, dtype=np.int32)
      indices_right = np.empty(n_right, dtype=np.int32)
  
      # Populate the arrays with graph_indices according to which side they fell on
      n_left = 0
      n_right = 0
      for i in range(side.shape[0]):
          if side[i] == 0:
              indices_left[n_left] = indices[i]
              n_left += 1
          else:
              indices_right[n_right] = indices[i]
              n_right += 1
  
      hyperplane = np.vstack((hyperplane_inds, hyperplane_data))
  
      return indices_left, indices_right, hyperplane, hyperplane_offset
  
imports: from warnings import warn
  import locale
  import numpy
  import numba
  import scipy.sparse
  from pynndescent.sparse import sparse_mul, sparse_diff, sparse_sum, arr_intersect, sparse_dot_product
  from pynndescent.utils import tau_rand_int, norm
  import joblib
  from collections import namedtuple
label_desc: Use image node_id 4 for calling a global function with example usage: sparse_euclidean_random_projection_split(inds, indptr, data, indices, rng_state) and returns: indices_left,  indices_right,  hyperplane,  hyperplane_offset