class_docstr: An implementation of the Efficient Graph Convolution (EGC-S) layer of
  
  @misc{tailor2021adaptive,
    title={Adaptive Filters and Aggregator Fusion for Efficient Graph Convolutions},
    author={Shyam A. Tailor and Felix L. Opolka and Pietro Liò and Nicholas D. Lane},
    year={2021},
    eprint={2104.01481},
    note={GNNSys Workshop, MLSys '21 and HAET Workshop, ICLR '21}
  }
  
  Differences compared to the paper:
  * Allow using a single but different aggregator similar to EGC-M.
  * Different bases per edge-type
code: def forward(
      self,
      node_states: torch.Tensor,
      adjacency_lists: List[Tuple[torch.Tensor, torch.Tensor]],
      node_to_graph_idx: torch.Tensor,
      reference_node_ids: Dict[str, torch.Tensor],
      reference_node_graph_idx: Dict[str, torch.Tensor],
      edge_features: List[torch.Tensor],
  ) -> torch.Tensor:
      assert len(adjacency_lists) == len(self.__bases)
      node_weights = self.__weight_coeffs(node_states).reshape(
          -1, self.__num_heads, self.__num_bases, 1
      )
  
      all_message_targets, all_messages = [], []
      for edge_type_idx, (
          adj_list,
          features,
          edge_bases_layer,
      ) in enumerate(zip(adjacency_lists, edge_features, self.__bases)):
          edge_sources_idxs, edge_target_idxs = adj_list
          all_message_targets.append(edge_target_idxs)
  
          edge_source_states = nn.functional.embedding(
              edge_sources_idxs, node_states
          )
          edge_source_states = self.__dropout(edge_source_states)
          all_base_inputs = edge_bases_layer(
              edge_source_states
          ).reshape(
              -1,
              self.__num_heads,
              self.__num_bases,
              self.__output_state_dim // self.__num_heads,
          )
          all_messages.append(all_base_inputs)
  
      aggregated_messages = self._aggregate_messages(
          messages=torch.cat(all_messages, dim=0),
          message_targets=torch.cat(all_message_targets, dim=0),
          num_nodes=node_states.shape[0],
          aggregation_fn=self.__aggregation_fn,
      )  # [num_nodes, num_heads, num_bases, D]
  
      return (
          (aggregated_messages * node_weights)
          .sum(axis=-2)
          .reshape(-1, self.__output_state_dim)
      )
  
file_path: ptgnn/ptgnn/neuralmodels/gnn/messagepassing/egcmessagepassing.py
imports: import torch
  from torch import nn
  from typing import Dict, List, Tuple
  from ptgnn.neuralmodels.gnn.messagepassing.abstractmessagepassing import AbstractMessagePassingLayer
label_desc: Use image node_id 2 for calling the EGCMessagePassingLayer obj's underlying member method code with example usage: obj.forward(node_states, adjacency_lists, node_to_graph_idx, reference_node_ids, reference_node_graph_idx, edge_features) and returns: unknown