class_docstr: An accelerated relational graph convolution layer from `Modeling
  Relational Data with Graph Convolutional Networks
  <https://arxiv.org/abs/1703.06103>`__ that leverages the highly-optimized
  aggregation primitives in cugraph-ops.
  
  See :class:`dgl.nn.pytorch.conv.RelGraphConv` for mathematical model.
  
  This module depends on :code:`pylibcugraphops` package, which can be
  installed via :code:`conda install -c nvidia pylibcugraphops=23.04`.
  :code:`pylibcugraphops` 23.04 requires python 3.8.x or 3.10.x.
  
  .. note::
      This is an **experimental** feature.
  
  Parameters
  ----------
  in_feat : int
      Input feature size.
  out_feat : int
      Output feature size.
  num_rels : int
      Number of relations.
  regularizer : str, optional
      Which weight regularizer to use ("basis" or ``None``):
       - "basis" is for basis-decomposition.
       - ``None`` applies no regularization.
      Default: ``None``.
  num_bases : int, optional
      Number of bases. It comes into effect when a regularizer is applied.
      Default: ``None``.
  bias : bool, optional
      True if bias is added. Default: ``True``.
  self_loop : bool, optional
      True to include self loop message. Default: ``True``.
  dropout : float, optional
      Dropout rate. Default: ``0.0``.
  apply_norm : bool, optional
      True to normalize aggregation output by the in-degree of the destination
      node per edge type, i.e. :math:`|\mathcal{N}^r_i|`. Default: ``True``.
  
  Examples
  --------
  >>> import dgl
  >>> import torch
  >>> from dgl.nn import CuGraphRelGraphConv
  ...
  >>> device = 'cuda'
  >>> g = dgl.graph(([0,1,2,3,2,5], [1,2,3,4,0,3])).to(device)
  >>> feat = torch.ones(6, 10).to(device)
  >>> conv = CuGraphRelGraphConv(
  ...     10, 2, 3, regularizer='basis', num_bases=2).to(device)
  >>> etype = torch.tensor([0,1,2,0,1,2]).to(device)
  >>> res = conv(g, feat, etype)
  >>> res
  tensor([[-1.7774, -2.0184],
          [-1.4335, -2.3758],
          [-1.7774, -2.0184],
          [-0.4698, -3.0876],
          [-1.4335, -2.3758],
          [-1.4331, -2.3295]], device='cuda:0', grad_fn=<AddBackward0>)
docstr: Forward computation.
  
  Parameters
  ----------
  g : DGLGraph
      The graph.
  feat : torch.Tensor
      A 2D tensor of node features. Shape: :math:`(|V|, D_{in})`.
  etypes : torch.Tensor
      A 1D integer tensor of edge types. Shape: :math:`(|E|,)`.
      Note that cugraph-ops only accepts edge type tensors in int32,
      so any input of other integer types will be casted into int32,
      thus introducing some overhead. Pass in int32 tensors directly
      for best performance.
  max_in_degree : int, optional
      Maximum in-degree of destination nodes. It is only effective when
      :attr:`g` is a :class:`DGLBlock`, i.e., bipartite graph. When
      :attr:`g` is generated from a neighbor sampler, the value should be
      set to the corresponding :attr:`fanout`. If not given,
      :attr:`max_in_degree` will be calculated on-the-fly.
  
  Returns
  -------
  torch.Tensor
      New node features. Shape: :math:`(|V|, D_{out})`.
docstr_tok: ["Forward","computation",".","Parameters","--","--","--","--","--","g",":","DGLGraph","The","graph",".","feat",":","torch.Tensor","A","2D","tensor","of","node","features",".","Shape",":",":","math",":","`","(","|V|",",","D_","{","in","}",")","`",".","etypes",":","torch.Tensor","A","1D","integer","tensor","of","edge","types",".","Shape",":",":","math",":","`","(","|E|",",",")","`",".","Note","that","cugraph-ops","only","accepts","edge","type","tensors","in","int32",",","so","any","input","of","other","integer","types","will","be","casted","into","int32",",","thus","introducing","some","overhead",".","Pass","in","int32","tensors","directly","for","best","performance",".","max_in_degree",":","int",",","optional","Maximum","in-degree","of","destination","nodes",".","It","is","only","effective","when",":","attr",":","`","g","`","is","a",":","class",":","`","DGLBlock","`",",","i.e.",",","bipartite","graph",".","When",":","attr",":","`","g","`","is","generated","from","a","neighbor","sampler",",","the","value","should","be","set","to","the","corresponding",":","attr",":","`","fanout","`",".","If","not","given",",",":","attr",":","`","max_in_degree","`","will","be","calculated","on-the-fly",".","Returns","--","--","--","-","torch.Tensor","New","node","features",".","Shape",":",":","math",":","`","(","|V|",",","D_","{","out","}",")","`","."]
code: def forward(self, g, feat, etypes, max_in_degree=None):
      r"""Forward computation.
  
      Parameters
      ----------
      g : DGLGraph
          The graph.
      feat : torch.Tensor
          A 2D tensor of node features. Shape: :math:`(|V|, D_{in})`.
      etypes : torch.Tensor
          A 1D integer tensor of edge types. Shape: :math:`(|E|,)`.
          Note that cugraph-ops only accepts edge type tensors in int32,
          so any input of other integer types will be casted into int32,
          thus introducing some overhead. Pass in int32 tensors directly
          for best performance.
      max_in_degree : int, optional
          Maximum in-degree of destination nodes. It is only effective when
          :attr:`g` is a :class:`DGLBlock`, i.e., bipartite graph. When
          :attr:`g` is generated from a neighbor sampler, the value should be
          set to the corresponding :attr:`fanout`. If not given,
          :attr:`max_in_degree` will be calculated on-the-fly.
  
      Returns
      -------
      torch.Tensor
          New node features. Shape: :math:`(|V|, D_{out})`.
      """
      offsets, indices, edge_ids = g.adj_tensors("csc")
      edge_types_perm = etypes[edge_ids.long()].int()
  
      if g.is_block:
          if max_in_degree is None:
              max_in_degree = g.in_degrees().max().item()
  
          if max_in_degree < self.MAX_IN_DEGREE_MFG:
              _graph = SampledHeteroCSC(
                  offsets,
                  indices,
                  edge_types_perm,
                  max_in_degree,
                  g.num_src_nodes(),
                  self.num_rels,
              )
          else:
              offsets_fg = self.pad_offsets(
                  offsets, g.num_src_nodes() + 1
              )
              _graph = StaticHeteroCSC(
                  offsets_fg,
                  indices,
                  edge_types_perm,
                  self.num_rels,
              )
      else:
          _graph = StaticHeteroCSC(
              offsets,
              indices,
              edge_types_perm,
              self.num_rels,
          )
  
      h = RelGraphConvAgg(
          feat,
          self.coeff,
          _graph,
          concat_own=self.self_loop,
          norm_by_out_degree=self.apply_norm,
      )[: g.num_dst_nodes()]
      h = h @ self.W.view(-1, self.out_feat)
      if self.bias is not None:
          h = h + self.bias
      h = self.dropout(h)
  
      return h
  
file_path: dgl/python/dgl/nn/pytorch/conv/cugraph_relgraphconv.py
imports: import math
  import torch
  from torch import nn
  from .cugraph_base import CuGraphBaseConv
label_desc: Use image node_id 3 for calling the CuGraphRelGraphConv obj's underlying member method code with example usage: obj.forward(g, feat, etypes, max_in_degree) and returns: h