code: def invoke_gspmm(
      graph, mfunc, rfunc, *, srcdata=None, dstdata=None, edata=None
  ):
      """Invoke g-SPMM computation on the graph.
  
      Parameters
      ----------
      graph :  DGLGraph
          The input graph.
      mfunc : dgl.function.BaseMessageFunction
          Built-in message function.
      rfunc : dgl.function.BaseReduceFunction
          Built-in reduce function.
      srcdata : dict[str, Tensor], optional
          Source node feature data. If not provided, it use ``graph.srcdata``.
      dstdata : dict[str, Tensor], optional
          Destination node feature data. If not provided, it use ``graph.dstdata``.
      edata : dict[str, Tensor], optional
          Edge feature data. If not provided, it use ``graph.edata``.
  
      Returns
      -------
      dict[str, Tensor]
          Results from the g-SPMM computation.
      """
      # sanity check
      if mfunc.out_field != rfunc.msg_field:
          raise DGLError(
              "Invalid message ({}) and reduce ({}) function pairs."
              " The output field of the message function must be equal to the"
              " message field of the reduce function.".format(
                  mfunc, rfunc
              )
          )
      if edata is None:
          edata = graph.edata
      if srcdata is None:
          srcdata = graph.srcdata
      if dstdata is None:
          dstdata = graph.dstdata
      alldata = [srcdata, dstdata, edata]
  
      if isinstance(mfunc, fn.BinaryMessageFunction):
          x = alldata[mfunc.lhs][mfunc.lhs_field]
          y = alldata[mfunc.rhs][mfunc.rhs_field]
          op = getattr(ops, "{}_{}".format(mfunc.name, rfunc.name))
          if graph._graph.number_of_etypes() > 1:
              lhs_target, _, rhs_target = mfunc.name.split("_", 2)
              x = data_dict_to_list(graph, x, mfunc, lhs_target)
              y = data_dict_to_list(graph, y, mfunc, rhs_target)
          z = op(graph, x, y)
      else:
          x = alldata[mfunc.target][mfunc.in_field]
          op = getattr(ops, "{}_{}".format(mfunc.name, rfunc.name))
          if graph._graph.number_of_etypes() > 1 and not isinstance(
              x, tuple
          ):
              if mfunc.name == "copy_u":
                  x = data_dict_to_list(graph, x, mfunc, "u")
              else:  # "copy_e"
                  x = data_dict_to_list(graph, x, mfunc, "e")
          z = op(graph, x)
      return {rfunc.out_field: z}
  
file_path: dgl/python/dgl/core.py
imports: import numpy
  from .None import backend, function, ops
  from .base import ALL, dgl_warning, DGLError, EID, is_all, NID
  from .frame import Frame
  from .udf import EdgeBatch, NodeBatch
label_desc: Use image node_id 8 for calling a global function with example usage: invoke_gspmm(graph, mfunc, rfunc) and returns: dict