code: def edge_index_to_vector(
      edge_index: Tensor,
      size: Tuple[int, int],
      bipartite: bool,
      force_undirected: bool = False,
  ) -> Tuple[Tensor, int]:
      row, col = edge_index
  
      if bipartite:  # No need to account for self-loops.
          idx = (row * size[1]).add_(col)
          population = size[0] * size[1]
          return idx, population
  
      elif force_undirected:
          assert size[0] == size[1]
          num_nodes = size[0]
  
          # We only operate on the upper triangular matrix:
          mask = row < col
          row, col = row[mask], col[mask]
          offset = torch.arange(1, num_nodes, device=row.device).cumsum(
              0
          )[row]
          idx = row.mul_(num_nodes).add_(col).sub_(offset)
          population = (num_nodes * (num_nodes + 1)) // 2 - num_nodes
          return idx, population
  
      else:
          assert size[0] == size[1]
          num_nodes = size[0]
  
          # We remove self-loops as we do not want to take them into account
          # when sampling negative values.
          mask = row != col
          row, col = row[mask], col[mask]
          col[row < col] -= 1
          idx = row.mul_(num_nodes - 1).add_(col)
          population = num_nodes * num_nodes - num_nodes
          return idx, population
  
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 6 for calling a global function with example usage: edge_index_to_vector(edge_index, size, bipartite, force_undirected) and returns: idx,  population, idx,  population, idx,  population