code: def to_bidirectional(
      row: Tensor,
      col: Tensor,
      rev_row: Tensor,
      rev_col: Tensor,
      edge_id: OptTensor = None,
      rev_edge_id: OptTensor = None,
  ) -> Tuple[Tensor, Tensor, OptTensor]:
      assert row.numel() == col.numel()
      assert rev_row.numel() == rev_col.numel()
  
      edge_index = row.new_empty(2, row.numel() + rev_row.numel())
      edge_index[0, : row.numel()] = row
      edge_index[1, : row.numel()] = col
      edge_index[0, row.numel() :] = rev_col
      edge_index[1, row.numel() :] = rev_row
  
      if edge_id is not None:
          edge_id = torch.cat([edge_id, rev_edge_id], dim=0)
  
      (row, col), edge_id = coalesce(
          edge_index,
          edge_id,
          sort_by_row=False,
          reduce="any",
      )
  
      return row, col, edge_id
  
file_path: pytorch_geometric/torch_geometric/sampler/utils.py
imports: from typing import Any, Dict, List, Optional, Tuple, TypeVar, Union
  import torch
  from torch import Tensor
  from torch_geometric.data import Data, HeteroData
  from torch_geometric.data.storage import EdgeStorage
  from torch_geometric.typing import EdgeType, NodeType, OptTensor
  from torch_geometric.utils import coalesce, index_sort, lexsort
  from torch_geometric.utils.sparse import index2ptr
label_desc: Use image node_id 4 for calling a global function with example usage: to_bidirectional(row, col, rev_row, rev_col, edge_id, rev_edge_id) and returns: row,  col,  edge_id