code: def edge_subgraph(
      graph,
      edges,
      *,
      relabel_nodes=True,
      store_ids=True,
      output_device=None,
  ):
      """Return a subgraph induced on the given edges.
  
      An edge-induced subgraph is equivalent to creating a new graph using the given
      edges. In addition to extracting the subgraph, DGL also copies the features
      of the extracted nodes and edges to the resulting graph. The copy is *lazy*
      and incurs data movement only when needed.
  
      If the graph is heterogeneous, DGL extracts a subgraph per relation and composes
      them as the resulting graph. Thus, the resulting graph has the same set of relations
      as the input one.
  
      Parameters
      ----------
      graph : DGLGraph
          The graph to extract the subgraph from.
      edges : edges or dict[(str, str, str), edges]
          The edges to form the subgraph. The allowed edges formats are:
  
          * Int Tensor: Each element is an edge ID. The tensor must have the same device type
            and ID data type as the graph's.
          * iterable[int]: Each element is an edge ID.
          * Bool Tensor: Each :math:`i^{th}` element is a bool flag indicating whether
            edge :math:`i` is in the subgraph.
  
          If the graph is homogeneous, one can directly pass the above formats.
          Otherwise, the argument must be a dictionary with keys being edge types
          and values being the edge IDs in the above formats.
      relabel_nodes : bool, optional
          If True, it will remove the isolated nodes and relabel the incident nodes in the
          extracted subgraph.
      store_ids : bool, optional
          If True, it will store the raw IDs of the extracted edges in the ``edata`` of the
          resulting graph under name ``dgl.EID``; if ``relabel_nodes`` is ``True``, it will
          also store the raw IDs of the incident nodes in the ``ndata`` of the resulting
          graph under name ``dgl.NID``.
      output_device : Framework-specific device context object, optional
          The output device.  Default is the same as the input graph.
  
      Returns
      -------
      G : DGLGraph
          The subgraph.
  
      Notes
      -----
  
      This function discards the batch information. Please use
      :func:`dgl.DGLGraph.set_batch_num_nodes`
      and :func:`dgl.DGLGraph.set_batch_num_edges` on the transformed graph
      to maintain the information.
  
      Examples
      --------
      The following example uses PyTorch backend.
  
      >>> import dgl
      >>> import torch
  
      Extract a subgraph from a homogeneous graph.
  
      >>> g = dgl.graph(([0, 1, 2, 3, 4], [1, 2, 3, 4, 0]))  # 5-node cycle
      >>> sg = dgl.edge_subgraph(g, [0, 4])
      >>> sg
      Graph(num_nodes=3, num_edges=2,
            ndata_schemes={'_ID': Scheme(shape=(), dtype=torch.int64)}
            edata_schemes={'_ID': Scheme(shape=(), dtype=torch.int64)})
      >>> sg.edges()
      (tensor([0, 1]), tensor([2, 0]))
      >>> sg.ndata[dgl.NID]  # original node IDs
      tensor([0, 4, 1])
      >>> sg.edata[dgl.EID]  # original edge IDs
      tensor([0, 4])
  
      Extract a subgraph without node relabeling.
  
      >>> sg = dgl.edge_subgraph(g, [0, 4], relabel_nodes=False)
      >>> sg
      Graph(num_nodes=5, num_edges=2,
            ndata_schemes={}
            edata_schemes={'_ID': Scheme(shape=(), dtype=torch.int64)})
      >>> sg.edges()
      (tensor([0, 4]), tensor([1, 0]))
  
      Specify edges using a boolean mask.
  
      >>> nodes = torch.tensor([True, False, False, False, True])  # choose edges [0, 4]
      >>> dgl.edge_subgraph(g, nodes)
      Graph(num_nodes=3, num_edges=2,
            ndata_schemes={'_ID': Scheme(shape=(), dtype=torch.int64)}
            edata_schemes={'_ID': Scheme(shape=(), dtype=torch.int64)})
  
      The resulting subgraph also copies features from the parent graph.
  
      >>> g.ndata['x'] = torch.arange(10).view(5, 2)
      >>> sg = dgl.edge_subgraph(g, [0, 4])
      >>> sg
      Graph(num_nodes=3, num_edges=2,
            ndata_schemes={'x': Scheme(shape=(2,), dtype=torch.int64),
                           '_ID': Scheme(shape=(), dtype=torch.int64)}
            edata_schemes={'_ID': Scheme(shape=(), dtype=torch.int64)})
      >>> sg.ndata[dgl.NID]
      tensor([0, 4, 1])
      >>> sg.ndata['x']
      tensor([[0, 1],
              [8, 9],
              [2, 3]])
  
      Extract a subgraph from a hetergeneous graph.
  
      >>> g = dgl.heterograph({
      >>>     ('user', 'plays', 'game'): ([0, 1, 1, 2], [0, 0, 2, 1]),
      >>>     ('user', 'follows', 'user'): ([0, 1, 1], [1, 2, 2])
      >>> })
      >>> sub_g = dgl.edge_subgraph(g, {('user', 'follows', 'user'): [1, 2],
      ...                               ('user', 'plays', 'game'): [2]})
      >>> print(sub_g)
      Graph(num_nodes={'game': 1, user': 2},
            num_edges={('user', 'follows', 'user'): 2, ('user', 'plays', 'game'): 1},
            metagraph=[('user', 'user', 'follows'), ('user', 'game', 'plays')])
  
      See Also
      --------
      node_subgraph
      """
      if graph.is_block and relabel_nodes:
          raise DGLError(
              "Extracting subgraph from a block graph is not allowed."
          )
      if not isinstance(edges, Mapping):
          assert (
              len(graph.canonical_etypes) == 1
          ), "need a dict of edge type and IDs for graph with multiple edge types"
          edges = {graph.canonical_etypes[0]: edges}
  
      def _process_edges(etype, e):
          if F.is_tensor(e) and F.dtype(e) == F.bool:
              return F.astype(
                  F.nonzero_1d(F.copy_to(e, graph.device)), graph.idtype
              )
          else:
              return utils.prepare_tensor(
                  graph, e, 'edges["{}"]'.format(etype)
              )
  
      edges = {
          graph.to_canonical_etype(etype): e
          for etype, e in edges.items()
      }
      edges = {
          etype: _process_edges(etype, e) for etype, e in edges.items()
      }
      device = context_of(edges)
      induced_edges = [
          edges.get(
              cetype, F.copy_to(F.tensor([], graph.idtype), device)
          )
          for cetype in graph.canonical_etypes
      ]
  
      sgi = graph._graph.edge_subgraph(induced_edges, not relabel_nodes)
      induced_nodes_or_device = (
          sgi.induced_nodes if relabel_nodes else device
      )
      subg = _create_hetero_subgraph(
          graph,
          sgi,
          induced_nodes_or_device,
          induced_edges,
          store_ids=store_ids,
      )
      return subg if output_device is None else subg.to(output_device)
  
file_path: dgl/python/dgl/subgraph.py
imports: from collections.abc import Mapping
  from .None import backend, graph_index, heterograph_index, utils
  from ._ffi.function import _init_api
  from .base import DGLError
  from .heterograph import DGLGraph
  from .utils import context_of, recursive_apply
label_desc: Use image node_id 2 for calling a global function with example usage: edge_subgraph(graph, edges) and returns: unknown, F, utils