class_docstr: A general class for message passing networks from the paper
  
  > [Neural Message Passing for Quantum Chemistry](https://arxiv.org/abs/1704.01212)<br>
  > Justin Gilmer et al.
  
  **Mode**: single, disjoint.
  
  **This layer and all of its extensions expect a sparse adjacency matrix.**
  
  This layer computes:
  $$
      \x_i' = \gamma \left( \x_i, \square_{j \in \mathcal{N}(i)} \,
      \phi \left(\x_i, \x_j, \e_{j \rightarrow i} \right) \right),
  $$
  
  where \( \gamma \) is a differentiable update function, \( \phi \) is a
  differentiable message function, \( \square \) is a permutation-invariant
  function to aggregate the messages (like the sum or the average), and
  \(\E_{ij}\) is the edge attribute of edge j-i.
  
  By extending this class, it is possible to create any message-passing layer
  in single/disjoint mode.
  
  **API**
  
  ```python
  propagate(x, a, e=None, **kwargs)
  ```
  Propagates the messages and computes embeddings for each node in the graph. <br>
  Any `kwargs` will be forwarded as keyword arguments to `message()`,
  `aggregate()` and `update()`.
  
  ```python
  message(x, **kwargs)
  ```
  Computes messages, equivalent to \(\phi\) in the definition. <br>
  Any extra keyword argument of this function will be populated by
  `propagate()` if a matching keyword is found. <br>
  The `get_sources` and `get_targets` built-in methods can be used to automatically
  retrieve the node attributes of nodes that are sending (sources) or receiving
  (targets) a message.
  If you need direct access to the edge indices, you can use the `index_sources` and
  `index_targets` attributes.
  
  ```python
  aggregate(messages, **kwargs)
  ```
  Aggregates the messages, equivalent to \(\square\) in the definition. <br>
  The behaviour of this function can also be controlled using the `aggregate`
  keyword in the constructor of the layer (supported aggregations: sum, mean,
  max, min, prod). <br>
  Any extra keyword argument of this function will be  populated by
  `propagate()` if a matching keyword is found.
  
  ```python
  update(embeddings, **kwargs)
  ```
  Updates the aggregated messages to obtain the final node embeddings,
  equivalent to \(\gamma\) in the definition. <br>
  Any extra keyword argument of this function will be  populated by
  `propagate()` if a matching keyword is found.
  
  **Arguments**:
  
  - `aggregate`: string or callable, an aggregation function. This flag can be
  used to control the behaviour of `aggregate()` wihtout re-implementing it.
  Supported aggregations: 'sum', 'mean', 'max', 'min', 'prod'.
  If callable, the function must have the signature `foo(updates, indices, n_nodes)`
  and return a rank 2 tensor with shape `(n_nodes, ...)`.
  - `kwargs`: additional keyword arguments specific to Keras' Layers, like
  regularizers, initializers, constraints, etc.
class_docstr_tok: ["A","general","class","for","message","passing","networks","from","the","paper",">","[","Neural","Message","Passing","for","Quantum","Chemistry","]","(","https",":","\/\/arxiv.org\/abs\/1704.01212",")","<","br",">",">","Justin","Gilmer","et","al",".","*","*","Mode","*","*",":","single",",","disjoint",".","*","*","This","layer","and","all","of","its","extensions","expect","a","sparse","adjacency","matrix",".","*","*","This","layer","computes",":","$","$","\\x_i","'","=","\\gamma","\\left","(","\\x_i",",","\\square_","{","j","\\in","\\mathcal","{","N","}","(","i",")","}","\\",",","\\phi","\\left","(","\\x_i",",","\\x_j",",","\\e_","{","j","\\rightarrow","i","}","\\right",")","\\right",")",",","$","$","where","\\","(","\\gamma","\\",")","is","a","differentiable","update","function",",","\\","(","\\phi","\\",")","is","a","differentiable","message","function",",","\\","(","\\square","\\",")","is","a","permutation-invariant","function","to","aggregate","the","messages","(","like","the","sum","or","the","average",")",",","and","\\","(","\\E_","{","ij","}","\\",")","is","the","edge","attribute","of","edge","j-i",".","By","extending","this","class",",","it","is","possible","to","create","any","message-passing","layer","in","single\/disjoint","mode",".","*","*","API","*","*","``","`","python","propagate","(","x",",","a",",","e=None",",","*","*","kwargs",")","``","`","Propagates","the","messages","and","computes","embeddings","for","each","node","in","the","graph",".","<","br",">","Any","`","kwargs","`","will","be","forwarded","as","keyword","arguments","to","`","message","(",")","`",",","`","aggregate","(",")","`","and","`","update","(",")","`",".","``","`","python","message","(","x",",","*","*","kwargs",")","``","`","Computes","messages",",","equivalent","to","\\","(","\\phi\\",")","in","the","definition",".","<","br",">","Any","extra","keyword","argument","of","this","function","will","be","populated","by","`","propagate","(",")","`","if","a","matching","keyword","is","found",".","<","br",">","The","`","get_sources","`","and","`","get_targets","`","built-in","methods","can","be","used","to","automatically","retrieve","the","node","attributes","of","nodes","that","are","sending","(","sources",")","or","receiving","(","targets",")","a","message",".","If","you","need","direct","access","to","the","edge","indices",",","you","can","use","the","`","index_sources","`","and","`","index_targets","`","attributes",".","``","`","python","aggregate","(","messages",",","*","*","kwargs",")","``","`","Aggregates","the","messages",",","equivalent","to","\\","(","\\square\\",")","in","the","definition",".","<","br",">","The","behaviour","of","this","function","can","also","be","controlled","using","the","`","aggregate","`","keyword","in","the","constructor","of","the","layer","(","supported","aggregations",":","sum",",","mean",",","max",",","min",",","prod",")",".","<","br",">","Any","extra","keyword","argument","of","this","function","will","be","populated","by","`","propagate","(",")","`","if","a","matching","keyword","is","found",".","``","`","python","update","(","embeddings",",","*","*","kwargs",")","``","`","Updates","the","aggregated","messages","to","obtain","the","final","node","embeddings",",","equivalent","to","\\","(","\\gamma\\",")","in","the","definition",".","<","br",">","Any","extra","keyword","argument","of","this","function","will","be","populated","by","`","propagate","(",")","`","if","a","matching","keyword","is","found",".","*","*","Arguments","*","*",":","-","`","aggregate","`",":","string","or","callable",",","an","aggregation","function",".","This","flag","can","be","used","to","control","the","behaviour","of","`","aggregate","(",")","`","wihtout","re-implementing","it",".","Supported","aggregations",":","'sum","'",",","'mean","'",",","'max","'",",","'min","'",",","'prod","'",".","If","callable",",","the","function","must","have","the","signature","`","foo","(","updates",",","indices",",","n_nodes",")","`","and","return","a","rank","2","tensor","with","shape","`","(","n_nodes",",","...",")","`",".","-","`","kwargs","`",":","additional","keyword","arguments","specific","to","Keras","'","Layers",",","like","regularizers",",","initializers",",","constraints",",","etc","."]
code: def message(self, x, **kwargs):
      return self.get_sources(x)
  
imports: import inspect
  import tensorflow
  from tensorflow.keras import backend
  from tensorflow.keras.layers import Layer
  from spektral.layers.ops.scatter import deserialize_scatter, serialize_scatter
  from spektral.utils.keras import deserialize_kwarg, is_keras_kwarg, is_layer_kwarg, serialize_kwarg
label_desc: Use image node_id 5 for calling the MessagePassing obj's underlying member method code with example usage: obj.message(x) and returns: self