code: def propagate(self, edge_index: Adj, size: Size = None, **kwargs):
      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__
              # 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 torch
  import torch.nn
  from functools import partial
  from typing import Union, List
  import torch.nn.functional
  from torch_geometric.data import Batch
  from torch_geometric.nn.conv.gcn_conv import gcn_norm
  from torch_geometric.nn.conv import GCNConv
  from torch_geometric.nn.glob import global_mean_pool, global_add_pool, global_max_pool
  from torch import Tensor
  from torch_sparse import SparseTensor, fill_diag
  from torch_geometric.typing import Adj, OptTensor, Size
  from torch_geometric.utils import add_self_loops
  from dig.xgraph.models import GNNPool
  from collections import OrderedDict
label_desc: Use image node_id 3 for calling the GCNConv obj's underlying member method code with example usage: obj.propagate(edge_index, size) and returns: self, self