code: def _sampler_output_from_sampling_results_heterogeneous(
      sampling_results: cudf.DataFrame,
      renumber_map: cudf.Series,
      graph_store: CuGraphStore,
      metadata: Sequence = None,
  ) -> HeteroSamplerOutput:
      """
      Parameters
      ----------
      sampling_results: cudf.DataFrame
          The dataframe containing sampling results.
      renumber_map: cudf.Series
          The series containing the renumber map, or None if there
          is no renumber map.
      graph_store: CuGraphStore
          The graph store containing the structure of the sampled graph.
      metadata: Tensor
          The metadata for the sampled batch.
  
      Returns
      -------
      HeteroSamplerOutput
      """
  
      hops = torch.arange(
          sampling_results.hop_id.max() + 1, device="cuda"
      )
      hops = torch.searchsorted(
          torch.as_tensor(sampling_results.hop_id, device="cuda"), hops
      )
  
      num_nodes_per_hop_dict = {}
      num_edges_per_hop_dict = {}
  
      # Fill out hop 0 in num_nodes_per_hop_dict, which is based on src instead of dst
      sampling_results_hop_0 = sampling_results.iloc[
          0 : (hops[1] if len(hops) > 1 else len(sampling_results))
      ]
  
      for node_type in graph_store.node_types:
          num_unique_nodes = _get_unique_nodes(
              sampling_results_hop_0, graph_store, node_type, "src"
          ).nunique()
  
          if num_unique_nodes > 0:
              num_nodes_per_hop_dict[node_type] = torch.zeros(
                  len(hops) + 1, dtype=torch.int64
              )
              num_nodes_per_hop_dict[node_type][0] = num_unique_nodes
  
      if renumber_map is not None:
          raise ValueError(
              "Precomputing the renumber map is currently "
              "unsupported for heterogeneous graphs."
          )
  
      # Calculate nodes of interest based on unique nodes in order of appearance
      # Use hop 0 sources since those are the only ones not included in destinations
      # Use torch.concat based on benchmark performance (vs. cudf.concat)
  
      if sampling_results_hop_0 is None:
          sampling_results_hop_0 = sampling_results.iloc[
              0 : (hops[1] if len(hops) > 1 else len(sampling_results))
          ]
  
      nodes_of_interest = (
          cudf.Series(
              torch.concat(
                  [
                      torch.as_tensor(
                          sampling_results_hop_0.majors, device="cuda"
                      ),
                      torch.as_tensor(
                          sampling_results.minors, device="cuda"
                      ),
                  ]
              ),
              name="nodes_of_interest",
          )
          .drop_duplicates()
          .sort_index()
      )
  
      # Get the grouped node index (for creating the renumbered grouped edge index)
      noi_index = graph_store._get_vertex_groups_from_sample(
          torch.as_tensor(nodes_of_interest, device="cuda")
      )
      del nodes_of_interest
  
      # Get the new edge index (by type as expected for HeteroData)
      # FIXME handle edge ids/types after the C++ updates
      (
          row_dict,
          col_dict,
      ) = graph_store._get_renumbered_edge_groups_from_sample(
          sampling_results, noi_index
      )
  
      for hop in range(len(hops)):
          hop_ix_start = hops[hop]
          hop_ix_end = (
              hops[hop + 1]
              if hop < len(hops) - 1
              else len(sampling_results)
          )
          sampling_results_to_hop = sampling_results.iloc[0:hop_ix_end]
  
          for node_type in graph_store.node_types:
              unique_nodes_hop = _get_unique_nodes(
                  sampling_results_to_hop, graph_store, node_type, "dst"
              )
  
              unique_nodes_0 = _get_unique_nodes(
                  sampling_results_hop_0, graph_store, node_type, "src"
              )
  
              num_unique_nodes = cudf.concat(
                  [unique_nodes_0, unique_nodes_hop]
              ).nunique()
  
              if num_unique_nodes > 0:
                  if node_type not in num_nodes_per_hop_dict:
                      num_nodes_per_hop_dict[node_type] = torch.zeros(
                          len(hops) + 1, dtype=torch.int64
                      )
                  num_nodes_per_hop_dict[node_type][
                      hop + 1
                  ] = num_unique_nodes - int(
                      num_nodes_per_hop_dict[node_type][: hop + 1].sum(
                          0
                      )
                  )
  
          numeric_etypes, counts = torch.unique(
              torch.as_tensor(
                  sampling_results.iloc[
                      hop_ix_start:hop_ix_end
                  ].edge_type,
                  device="cuda",
              ),
              return_counts=True,
          )
          numeric_etypes = list(numeric_etypes)
          counts = list(counts)
          for num_etype, count in zip(numeric_etypes, counts):
              can_etype = graph_store.numeric_edge_type_to_canonical(
                  num_etype
              )
              if can_etype not in num_edges_per_hop_dict:
                  num_edges_per_hop_dict[can_etype] = torch.zeros(
                      len(hops), dtype=torch.int64
                  )
              num_edges_per_hop_dict[can_etype][hop] = count
  
      if HeteroSamplerOutput is None:
          raise ImportError("Error importing from pyg")
  
      return HeteroSamplerOutput(
          node=noi_index,
          row=row_dict,
          col=col_dict,
          edge=None,
          num_sampled_nodes=num_nodes_per_hop_dict,
          num_sampled_edges=num_edges_per_hop_dict,
          metadata=metadata,
      )
  
file_path: cugraph/python/cugraph-pyg/cugraph_pyg/sampler/cugraph_sampler.py
imports: from typing import Sequence, Dict, Tuple
  from cugraph_pyg.data import CuGraphStore
  from cugraph.utilities.utils import import_optional
  import cudf
label_desc: Use image node_id 4 for calling a global function with example usage: _sampler_output_from_sampling_results_heterogeneous(sampling_results, renumber_map, graph_store, metadata) and returns: HeteroSamplerOutput