docs: def sparse_euclidean_random_projection_split(inds, indptr, data, indices, rng_state):
      """Given a set of ``indices`` for data points from a sparse data set
      presented in csr sparse format as inds, indptr and data, create
      a random hyperplane to split the data, returning two arrays 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 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 data array of the matrix
      indices: array of shape (tree_node_size,)
          The indices of the elements in the ``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 ``indices`` that fall on the "left" side of the
          random hyperplane.
      indices_right: array
          The elements of ``indices`` that fall on the "left" side of the
          random hyperplane.
      """
      # Select two random points, set the hyperplane between them
      left_index = tau_rand_int(rng_state) % indices.shape[0]
      right_index = 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
      )
  
      for d in range(offset_data.shape[0]):
          hyperplane_offset -= offset_data[d]
  
      # 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_inds, mul_data = sparse_mul(
              hyperplane_inds, hyperplane_data, i_inds, i_data
          )
          for d in range(mul_data.shape[0]):
              margin += mul_data[d]
  
          if abs(margin) < EPS:
              side[i] = 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
  
      # Now that we have the counts allocate arrays
      indices_left = np.empty(n_left, dtype=np.int64)
      indices_right = np.empty(n_right, dtype=np.int64)
  
      # Populate the arrays with 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