class_docstr: The sampling output of a :class:`~torch_geometric.sampler.BaseSampler`
  on heterogeneous graphs.
  
  Args:
      node (Dict[str, torch.Tensor]): The sampled nodes in the original graph
          for each node type.
      row (Dict[Tuple[str, str, str], torch.Tensor]): The source node indices
          of the sampled subgraph for each edge type.
          Indices must be re-indexed to :obj:`{ 0, ..., num_nodes - 1 }`
          corresponding to the nodes in the :obj:`node` tensor of the source
          node type.
      col (Dict[Tuple[str, str, str], torch.Tensor]): The destination node
          indices of the sampled subgraph for each edge type.
          Indices must be re-indexed to :obj:`{ 0, ..., num_nodes - 1 }`
          corresponding to the nodes in the :obj:`node` tensor of the
          destination node type.
      edge (Dict[Tuple[str, str, str], torch.Tensor], optional): The sampled
          edges in the original graph for each edge type.
          This tensor is used to obtain edge features from the original
          graph. If no edge attributes are present, it may be omitted.
      batch (Dict[str, torch.Tensor], optional): The vector to identify the
          seed node for each sampled node for each node type. Can be present
          in case of disjoint subgraph sampling per seed node.
          (default: :obj:`None`)
      num_sampled_nodes (Dict[str, List[int]], optional): The number of
          sampled nodes for each node type and each layer.
          (default: :obj:`None`)
      num_sampled_edges (Dict[EdgeType, List[int]], optional): The number of
          sampled edges for each edge type and each layer.
          (default: :obj:`None`)
      metadata: (Any, optional): Additional metadata information.
          (default: :obj:`None`)
docstr: Converts the sampled subgraph into a bidirectional variant, in
  which all sampled edges are guaranteed to be bidirectional.
docstr_tok: ["Converts","the","sampled","subgraph","into","a","bidirectional","variant",",","in","which","all","sampled","edges","are","guaranteed","to","be","bidirectional","."]
code: def to_bidirectional(self) -> "SamplerOutput":
      r"""Converts the sampled subgraph into a bidirectional variant, in
      which all sampled edges are guaranteed to be bidirectional.
      """
      out = copy.copy(self)
      out.row = copy.copy(self.row)
      out.col = copy.copy(self.col)
      out.edge = copy.copy(self.edge)
  
      src_dst_dict = defaultdict(list)
      edge_types = self.row.keys()
      edge_types = [
          k for k in edge_types if not k[1].startswith("rev_")
      ]
      for edge_type in edge_types:
          src, rel, dst = edge_type
          rev_edge_type = (dst, f"rev_{rel}", src)
  
          if src == dst and rev_edge_type not in self.row:
              (
                  out.row[edge_type],
                  out.col[edge_type],
                  _,
              ) = to_bidirectional(
                  row=self.row[edge_type],
                  col=self.col[edge_type],
                  rev_row=self.row[edge_type],
                  rev_col=self.col[edge_type],
              )
              if out.edge is not None:
                  out.edge[edge_type] = None
  
          elif rev_edge_type in self.row:
              (
                  out.row[edge_type],
                  out.col[edge_type],
                  _,
              ) = to_bidirectional(
                  row=self.row[edge_type],
                  col=self.col[edge_type],
                  rev_row=self.row[rev_edge_type],
                  rev_col=self.col[rev_edge_type],
              )
              out.row[rev_edge_type] = out.col[edge_type]
              out.col[rev_edge_type] = out.row[edge_type]
              if out.edge is not None:
                  out.edge[edge_type] = None
                  out.edge[rev_edge_type] = None
  
          else:  # Find the reverse edge type (if it is unique):
              if len(src_dst_dict) == 0:  # Create mapping lazily.
                  for key in self.row.keys():
                      v1, _, v2 = key
                      src_dst_dict[(v1, v2)].append(key)
  
              if len(src_dst_dict[(dst, src)]) == 1:
                  rev_edge_type = src_dst_dict[(dst, src)][0]
                  row, col, _ = to_bidirectional(
                      row=self.row[edge_type],
                      col=self.col[edge_type],
                      rev_row=self.row[rev_edge_type],
                      rev_col=self.col[rev_edge_type],
                  )
                  out.row[edge_type] = row
                  out.col[edge_type] = col
                  if out.edge is not None:
                      out.edge[edge_type] = None
  
              else:
                  warnings.warn(
                      f"Cannot convert to bidirectional graph "
                      f"since the edge type {edge_type} does not "
                      f"seem to have a reverse edge type"
                  )
  
      out.num_sampled_nodes = out.num_sampled_edges = None
  
      return out
  
imports: import copy
  import math
  import warnings
  from abc import ABC
  from collections import defaultdict
  from dataclasses import dataclass
  from enum import Enum
  from typing import Any, Dict, List, Optional, Union
  import torch
  from torch import Tensor
  from torch_geometric.data import Data, FeatureStore, GraphStore, HeteroData
  from torch_geometric.sampler.utils import to_bidirectional
  from torch_geometric.typing import EdgeType, EdgeTypeStr, NodeType, OptTensor
  from torch_geometric.utils.mixin import CastMixin
label_desc: Use image node_id 1 for calling the HeteroSamplerOutput obj's underlying member method code with example usage: obj.to_bidirectional() and returns: out