code: def _gspmm(gidx, op, reduce_op, u, e):
      r"""Generalized Sparse Matrix Multiplication interface. It takes the result of
      :attr:`op` on source node feature and edge feature, leads to a message on edge.
      Then aggregates the message by :attr:`reduce_op` on destination nodes.
  
      .. math::
          x_v = \psi_{(u, v, e)\in \mathcal{G}}(\rho(x_u, x_e))
  
      where :math:`x_v` is the returned feature on destination nodes, and :math`x_u`,
      :math:`x_e` refers to :attr:`u`, :attr:`e` respectively. :math:`\rho` means binary
      operator :attr:`op` and :math:`\psi` means reduce operator :attr:`reduce_op`,
      :math:`\mathcal{G}` is the graph we apply gspmm on: :attr:`g`.
  
      Note that this function does not handle gradients.
  
      Parameters
      ----------
      gidx : HeteroGraphIndex
          The input graph index.
      op : str
          The binary op's name, could be ``add``, ``sub``, ``mul``, ``div``, ``copy_lhs``,
          ``copy_rhs``.
      reduce_op : str
          Reduce operator, could be ``sum``, ``max``, ``min``.
      u : tensor or None
          The feature on source nodes, could be None if op is ``copy_rhs``.
      e : tensor or None
          The feature on edges, could be None if op is ``copy_lhs``.
  
      Returns
      -------
      tuple
          The returned tuple is composed of two elements:
          - The first element refers to the result tensor.
          - The second element refers to a tuple composed of arg_u and arg_e
            (which is useful when reducer is `min`/`max`).
  
      Notes
      -----
      This function does not handle gradients.
      """
      if gidx.number_of_etypes() != 1:
          raise DGLError(
              "We only support gspmm on graph with one edge type"
          )
      use_u = op != "copy_rhs"
      use_e = op != "copy_lhs"
      if use_u and use_e:
          if F.dtype(u) != F.dtype(e):
              raise DGLError(
                  "The node features' data type {} doesn't match edge"
                  " features' data type {}, please convert them to the"
                  " same type.".format(F.dtype(u), F.dtype(e))
              )
      # deal with scalar features.
      expand_u, expand_e = False, False
      if use_u:
          if F.ndim(u) == 1:
              u = F.unsqueeze(u, -1)
              expand_u = True
      if use_e:
          if F.ndim(e) == 1:
              e = F.unsqueeze(e, -1)
              expand_e = True
  
      ctx = F.context(u) if use_u else F.context(e)
      dtype = F.dtype(u) if use_u else F.dtype(e)
      u_shp = F.shape(u) if use_u else (0,)
      e_shp = F.shape(e) if use_e else (0,)
      _, dsttype = gidx.metagraph.find_edge(0)
      v_shp = (gidx.num_nodes(dsttype),) + infer_broadcast_shape(
          op, u_shp[1:], e_shp[1:]
      )
      v = F.zeros(v_shp, dtype, ctx)
      use_cmp = reduce_op in ["max", "min"]
      arg_u, arg_e = None, None
      idtype = getattr(F, gidx.dtype)
      if use_cmp:
          if use_u:
              arg_u = F.zeros(v_shp, idtype, ctx)
          if use_e:
              arg_e = F.zeros(v_shp, idtype, ctx)
      arg_u_nd = to_dgl_nd_for_write(arg_u)
      arg_e_nd = to_dgl_nd_for_write(arg_e)
      if gidx.num_edges(0) > 0:
          _CAPI_DGLKernelSpMM(
              gidx,
              op,
              reduce_op,
              to_dgl_nd(u if use_u else None),
              to_dgl_nd(e if use_e else None),
              to_dgl_nd_for_write(v),
              arg_u_nd,
              arg_e_nd,
          )
      # NOTE(zihao): actually we can avoid the following step, because arg_*_nd
      # refers to the data that stores arg_*. After we call _CAPI_DGLKernelSpMM,
      # arg_* should have already been changed. But we found this doesn't work
      # under Tensorflow when index type is int32. (arg_u and arg_e would be
      # all zero).
      # The workaround is proposed by Jinjing, and we still need to investigate
      # where the problem is.
      arg_u = (
          None
          if arg_u is None
          else F.zerocopy_from_dgl_ndarray(arg_u_nd)
      )
      arg_e = (
          None
          if arg_e is None
          else F.zerocopy_from_dgl_ndarray(arg_e_nd)
      )
      # To deal with scalar node/edge features.
      if (expand_u or not use_u) and (expand_e or not use_e):
          v = F.squeeze(v, -1)
      if expand_u and use_cmp:
          arg_u = F.squeeze(arg_u, -1)
      if expand_e and use_cmp:
          arg_e = F.squeeze(arg_e, -1)
      return v, (arg_u, arg_e)
  
imports: from __future__ import absolute_import
  from .None import backend, ndarray
  from ._ffi.function import _init_api
  from .base import DGLError
label_desc: Use image node_id 7 for calling a global function with example usage: _gspmm(gidx, op, reduce_op, u, e) and returns: v,  arg_u,  arg_e