class_docstr: Base class for creating message passing layers of the form
  
  .. math::
      \mathbf{x}_i^{\prime} = \gamma_{\mathbf{\Theta}} \left( \mathbf{x}_i,
      \square_{j \in \mathcal{N}(i)} \, \phi_{\mathbf{\Theta}}
      \left(\mathbf{x}_i, \mathbf{x}_j,\mathbf{e}_{j,i}\right) \right),
  
  where :math:`\square` denotes a differentiable, permutation invariant
  function, *e.g.*, sum, mean or max, and :math:`\gamma_{\mathbf{\Theta}}`
  and :math:`\phi_{\mathbf{\Theta}}` denote differentiable functions such as
  MLPs.
  See `here <https://pytorch-geometric.readthedocs.io/en/latest/notes/
  create_gnn.html>`__ for the accompanying tutorial.
  
  Args:
      aggr (string, optional): The aggregation scheme to use
          (:obj:`"add"`, :obj:`"mean"`, :obj:`"max"` or :obj:`None`).
          (default: :obj:`"add"`)
      flow (string, optional): The flow direction of message passing
          (:obj:`"source_to_target"` or :obj:`"target_to_source"`).
          (default: :obj:`"source_to_target"`)
      node_dim (int, optional): The axis along which to propagate.
          (default: :obj:`-2`)
docstr: The initial call to start propagating messages.
  
  Args:
      edge_index (Tensor or SparseTensor): A :obj:`torch.LongTensor` or a
          :obj:`torch_sparse.SparseTensor` that defines the underlying
          graph connectivity/message passing flow.
          :obj:`edge_index` holds the indices of a general (sparse)
          assignment matrix of shape :obj:`[N, M]`.
          If :obj:`edge_index` is of type :obj:`torch.LongTensor`, its
          shape must be defined as :obj:`[2, num_messages]`, where
          messages from nodes in :obj:`edge_index[0]` are sent to
          nodes in :obj:`edge_index[1]`
          (in case :obj:`flow="source_to_target"`).
          If :obj:`edge_index` is of type
          :obj:`torch_sparse.SparseTensor`, its sparse indices
          :obj:`(row, col)` should relate to :obj:`row = edge_index[1]`
          and :obj:`col = edge_index[0]`.
          The major difference between both formats is that we need to
          input the *transposed* sparse adjacency matrix into
          :func:`propagate`.
      size (tuple, optional): The size :obj:`(N, M)` of the assignment
          matrix in case :obj:`edge_index` is a :obj:`LongTensor`.
          If set to :obj:`None`, the size will be automatically inferred
          and assumed to be quadratic.
          This argument is ignored in case :obj:`edge_index` is a
          :obj:`torch_sparse.SparseTensor`. (default: :obj:`None`)
      **kwargs: Any additional data which is needed to construct and
          aggregate messages, and to update node embeddings.
docstr_tok: ["The","initial","call","to","start","propagating","messages",".","Args",":","edge_index","(","Tensor","or","SparseTensor",")",":","A",":","obj",":","`","torch.LongTensor","`","or","a",":","obj",":","`","torch_sparse.SparseTensor","`","that","defines","the","underlying","graph","connectivity\/message","passing","flow",".",":","obj",":","`","edge_index","`","holds","the","indices","of","a","general","(","sparse",")","assignment","matrix","of","shape",":","obj",":","`","[","N",",","M","]","`",".","If",":","obj",":","`","edge_index","`","is","of","type",":","obj",":","`","torch.LongTensor","`",",","its","shape","must","be","defined","as",":","obj",":","`","[","2",",","num_messages","]","`",",","where","messages","from","nodes","in",":","obj",":","`","edge_index","[","0","]","`","are","sent","to","nodes","in",":","obj",":","`","edge_index","[","1","]","`","(","in","case",":","obj",":","`","flow=","''","source_to_target","''","`",")",".","If",":","obj",":","`","edge_index","`","is","of","type",":","obj",":","`","torch_sparse.SparseTensor","`",",","its","sparse","indices",":","obj",":","`","(","row",",","col",")","`","should","relate","to",":","obj",":","`","row","=","edge_index","[","1","]","`","and",":","obj",":","`","col","=","edge_index","[","0","]","`",".","The","major","difference","between","both","formats","is","that","we","need","to","input","the","*","transposed","*","sparse","adjacency","matrix","into",":","func",":","`","propagate","`",".","size","(","tuple",",","optional",")",":","The","size",":","obj",":","`","(","N",",","M",")","`","of","the","assignment","matrix","in","case",":","obj",":","`","edge_index","`","is","a",":","obj",":","`","LongTensor","`",".","If","set","to",":","obj",":","`","None","`",",","the","size","will","be","automatically","inferred","and","assumed","to","be","quadratic",".","This","argument","is","ignored","in","case",":","obj",":","`","edge_index","`","is","a",":","obj",":","`","torch_sparse.SparseTensor","`",".","(","default",":",":","obj",":","`","None","`",")","*","*","kwargs",":","Any","additional","data","which","is","needed","to","construct","and","aggregate","messages",",","and","to","update","node","embeddings","."]
code: def propagate(self, edge_index: Adj, size: Size = None, **kwargs):
      r"""The initial call to start propagating messages.
  
      Args:
          edge_index (Tensor or SparseTensor): A :obj:`torch.LongTensor` or a
              :obj:`torch_sparse.SparseTensor` that defines the underlying
              graph connectivity/message passing flow.
              :obj:`edge_index` holds the indices of a general (sparse)
              assignment matrix of shape :obj:`[N, M]`.
              If :obj:`edge_index` is of type :obj:`torch.LongTensor`, its
              shape must be defined as :obj:`[2, num_messages]`, where
              messages from nodes in :obj:`edge_index[0]` are sent to
              nodes in :obj:`edge_index[1]`
              (in case :obj:`flow="source_to_target"`).
              If :obj:`edge_index` is of type
              :obj:`torch_sparse.SparseTensor`, its sparse indices
              :obj:`(row, col)` should relate to :obj:`row = edge_index[1]`
              and :obj:`col = edge_index[0]`.
              The major difference between both formats is that we need to
              input the *transposed* sparse adjacency matrix into
              :func:`propagate`.
          size (tuple, optional): The size :obj:`(N, M)` of the assignment
              matrix in case :obj:`edge_index` is a :obj:`LongTensor`.
              If set to :obj:`None`, the size will be automatically inferred
              and assumed to be quadratic.
              This argument is ignored in case :obj:`edge_index` is a
              :obj:`torch_sparse.SparseTensor`. (default: :obj:`None`)
          **kwargs: Any additional data which is needed to construct and
              aggregate messages, and to update node embeddings.
      """
      size = self.__check_input__(edge_index, size)
  
      # Run "fused" message and aggregation (if applicable).
      if (
          isinstance(edge_index, SparseTensor)
          and self.fuse
          and not self.__explain__
      ):
          coll_dict = self.__collect__(
              self.__fused_user_args__, edge_index, size, kwargs
          )
  
          msg_aggr_kwargs = self.inspector.distribute(
              "message_and_aggregate", coll_dict
          )
          out = self.message_and_aggregate(
              edge_index, **msg_aggr_kwargs
          )
  
          update_kwargs = self.inspector.distribute("update", coll_dict)
          return self.update(out, **update_kwargs)
  
      # Otherwise, run both functions in separation.
      elif isinstance(edge_index, Tensor) or not self.fuse:
          coll_dict = self.__collect__(
              self.__user_args__, edge_index, size, kwargs
          )
  
          msg_kwargs = self.inspector.distribute("message", coll_dict)
          out = self.message(**msg_kwargs)
  
          # For `GNNExplainer`, we require a separate message and aggregate
          # procedure since this allows us to inject the `edge_mask` into the
          # message passing computation scheme.
          if self.__explain__:
              edge_mask = self.__edge_mask__.sigmoid()
              # Some ops add self-loops to `edge_index`. We need to do the
              # same for `edge_mask` (but do not train those).
              if out.size(self.node_dim) != edge_mask.size(0):
                  loop = edge_mask.new_ones(size[0])
                  edge_mask = torch.cat([edge_mask, loop], dim=0)
              assert out.size(self.node_dim) == edge_mask.size(0)
              out = out * edge_mask.view([-1] + [1] * (out.dim() - 1))
  
          aggr_kwargs = self.inspector.distribute(
              "aggregate", coll_dict
          )
          out = self.aggregate(out, **aggr_kwargs)
  
          update_kwargs = self.inspector.distribute("update", coll_dict)
          return self.update(out, **update_kwargs)
  
imports: import os
  import re
  import inspect
  import os.path
  from uuid import uuid1
  from itertools import chain
  from inspect import Parameter
  from typing import List, Optional, Set
  from torch_geometric.typing import Adj, Size
  import torch
  from torch import Tensor
  from jinja2 import Template
  from torch_sparse import SparseTensor
  from torch_scatter import gather_csr, scatter, segment_csr
  from .utils.helpers import expand_left
  from .utils.jit import class_from_module_repr
  from .utils.typing import sanitize, split_types_repr, parse_types, resolve_types
  from .utils.inspector import Inspector, func_header_repr, func_body_repr
label_desc: Use image node_id 6 for calling the MessagePassing obj's underlying member method code with example usage: obj.propagate(edge_index, size) and returns: self, self