code: def message_passing(g, mfunc, rfunc, afunc):
      """Invoke message passing computation on the whole graph.
  
      Parameters
      ----------
      g : DGLGraph
          The input graph.
      mfunc : callable or dgl.function.BuiltinFunction
          Message function.
      rfunc : callable or dgl.function.BuiltinFunction
          Reduce function.
      afunc : callable or dgl.function.BuiltinFunction
          Apply function.
  
      Returns
      -------
      dict[str, Tensor]
          Results from the message passing computation.
      """
      if (
          is_builtin(mfunc)
          and is_builtin(rfunc)
          and getattr(ops, "{}_{}".format(mfunc.name, rfunc.name), None)
          is not None
      ):
          # invoke fused message passing
          ndata = invoke_gspmm(g, mfunc, rfunc)
      else:
          # invoke message passing in two separate steps
          # message phase
          if is_builtin(mfunc):
              msgdata = invoke_gsddmm(g, mfunc)
          else:
              orig_eid = g.edata.get(EID, None)
              msgdata = invoke_edge_udf(
                  g,
                  ALL,
                  g.canonical_etypes[0],
                  mfunc,
                  orig_eid=orig_eid,
              )
          # reduce phase
          if is_builtin(rfunc):
              msg = rfunc.msg_field
              ndata = invoke_gspmm(
                  g, fn.copy_e(msg, msg), rfunc, edata=msgdata
              )
          else:
              orig_nid = g.dstdata.get(NID, None)
              ndata = invoke_udf_reduce(
                  g, rfunc, msgdata, orig_nid=orig_nid
              )
      # apply phase
      if afunc is not None:
          for (
              k,
              v,
          ) in g.dstdata.items():  # include original node features
              if k not in ndata:
                  ndata[k] = v
          orig_nid = g.dstdata.get(NID, None)
          ndata = invoke_node_udf(
              g,
              ALL,
              g.dsttypes[0],
              afunc,
              ndata=ndata,
              orig_nid=orig_nid,
          )
      return ndata
  
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 9 for calling a global function with example usage: message_passing(g, mfunc, rfunc, afunc) and returns: ndata