code: def batched_negative_sampling(
      edge_index: Tensor,
      batch: Union[Tensor, Tuple[Tensor, Tensor]],
      num_neg_samples: Optional[int] = None,
      method: str = "sparse",
      force_undirected: bool = False,
  ) -> Tensor:
      r"""Samples random negative edges of multiple graphs given by
      :attr:`edge_index` and :attr:`batch`.
  
      Args:
          edge_index (LongTensor): The edge indices.
          batch (LongTensor or Tuple[LongTensor, LongTensor]): Batch vector
              :math:`\mathbf{b} \in {\{ 0, \ldots, B-1\}}^N`, which assigns each
              node to a specific example.
              If given as a tuple, then :obj:`edge_index` is interpreted as a
              bipartite graph connecting two different node types.
          num_neg_samples (int, optional): The number of negative samples to
              return. If set to :obj:`None`, will try to return a negative edge
              for every positive edge. (default: :obj:`None`)
          method (str, optional): The method to use for negative sampling,
              *i.e.* :obj:`"sparse"` or :obj:`"dense"`.
              This is a memory/runtime trade-off.
              :obj:`"sparse"` will work on any graph of any size, while
              :obj:`"dense"` can perform faster true-negative checks.
              (default: :obj:`"sparse"`)
          force_undirected (bool, optional): If set to :obj:`True`, sampled
              negative edges will be undirected. (default: :obj:`False`)
  
      :rtype: LongTensor
  
      Examples:
          >>> # Standard usage
          >>> edge_index = torch.as_tensor([[0, 0, 1, 2], [0, 1, 2, 3]])
          >>> edge_index = torch.cat([edge_index, edge_index + 4], dim=1)
          >>> edge_index
          tensor([[0, 0, 1, 2, 4, 4, 5, 6],
                  [0, 1, 2, 3, 4, 5, 6, 7]])
          >>> batch = torch.tensor([0, 0, 0, 0, 1, 1, 1, 1])
          >>> batched_negative_sampling(edge_index, batch)
          tensor([[3, 1, 3, 2, 7, 7, 6, 5],
                  [2, 0, 1, 1, 5, 6, 4, 4]])
  
          >>> # For bipartite graph
          >>> edge_index1 = torch.as_tensor([[0, 0, 1, 1], [0, 1, 2, 3]])
          >>> edge_index2 = edge_index1 + torch.tensor([[2], [4]])
          >>> edge_index3 = edge_index2 + torch.tensor([[2], [4]])
          >>> edge_index = torch.cat([edge_index1, edge_index2,
          ...                         edge_index3], dim=1)
          >>> edge_index
          tensor([[ 0,  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5],
                  [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11]])
          >>> src_batch = torch.tensor([0, 0, 1, 1, 2, 2])
          >>> dst_batch = torch.tensor([0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2])
          >>> batched_negative_sampling(edge_index,
          ...                           (src_batch, dst_batch))
          tensor([[ 0,  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5],
                  [ 2,  3,  0,  1,  6,  7,  4,  5, 10, 11,  8,  9]])
      """
      if isinstance(batch, Tensor):
          src_batch, dst_batch = batch, batch
      else:
          src_batch, dst_batch = batch[0], batch[1]
  
      split = degree(
          src_batch[edge_index[0]], dtype=torch.long
      ).tolist()
      edge_indices = torch.split(edge_index, split, dim=1)
  
      num_src = degree(src_batch, dtype=torch.long)
      cum_src = cumsum(num_src)[:-1]
  
      if isinstance(batch, Tensor):
          num_nodes = num_src.tolist()
          ptr = cum_src
      else:
          num_dst = degree(dst_batch, dtype=torch.long)
          cum_dst = cumsum(num_dst)[:-1]
  
          num_nodes = torch.stack([num_src, num_dst], dim=1).tolist()
          ptr = torch.stack([cum_src, cum_dst], dim=1).unsqueeze(-1)
  
      neg_edge_indices = []
      for i, edge_index in enumerate(edge_indices):
          edge_index = edge_index - ptr[i]
          neg_edge_index = negative_sampling(
              edge_index,
              num_nodes[i],
              num_neg_samples,
              method,
              force_undirected,
          )
          neg_edge_index += ptr[i]
          neg_edge_indices.append(neg_edge_index)
  
      return torch.cat(neg_edge_indices, dim=1)
  
file_path: pytorch_geometric/torch_geometric/utils/_negative_sampling.py
imports: import random
  from typing import Optional, Tuple, Union
  import numpy
  import torch
  from torch import Tensor
  from torch_geometric.utils import coalesce, cumsum, degree, remove_self_loops
  from torch_geometric.utils.num_nodes import maybe_num_nodes
label_desc: Use image node_id 2 for calling a global function with example usage: batched_negative_sampling(edge_index, batch, num_neg_samples, method, force_undirected) and returns: torch