class_docstr: A general class for graph pooling layers based on the "Select, Reduce,
  Connect" framework presented in:
  
  > [Understanding Pooling in Graph Neural Networks.](https://arxiv.org/abs/2110.05292)<br>
  > Daniele Grattarola et al.
  
  This layer computes:
  $$
      \begin{align}
          & \mathcal{S} = \left\{\mathcal{S}_k\right\}_{k=1:K} = \textrm{Sel}(\mathcal{G}) \\
          & \mathcal{X}'=\left\{\textrm{Red}( \mathcal{G}, \mathcal{S}_k )\right\}_{k=1:K} \\
          & \mathcal{E}'=\left\{\textrm{Con}( \mathcal{G}, \mathcal{S}_k, \mathcal{S}_l )\right\}_{k,L=1:K} \\
      \end{align}
  $$
  Where \(\textrm{Sel}\) is a node equivariant selection function that computes
  the supernode assignments \(\mathcal{S}_k\), \(\textrm{Red}\) is a
  permutation-invariant function to reduce the supernodes into the new node
  attributes, and \(\textrm{Con}\) is a permutation-invariant connection
  function that computes the link between the pooled nodes.
  
  By extending this class, it is possible to create any pooling layer in the
  SRC formalism.
  
  **Input**
  
  - `x`: Tensor of shape `([batch], N, F)` representing node features;
  - `a`: Tensor or SparseTensor of shape `([batch], N, N)` representing the
  adjacency matrix;
  - `i`: (optional) Tensor of integers with shape `(N, )` representing the
  batch index;
  
  **Output**
  
  - `x_pool`: Tensor of shape `([batch], K, F)`, representing the node
  features of the output. `K` is the number of output nodes and depends on the
  specific pooling strategy;
  - `a_pool`: Tensor or SparseTensor of shape `([batch], K, K)` representing
  the adjacency matrix of the output;
  - `i_pool`: (only if i was given as input) Tensor of integers with shape
  `(K, )` representing the batch index of the output;
  - `s`: (if `return_selection=True`) Tensor or SparseTensor representing the
  supernode assignments;
  
  **API**
  
  - `pool(x, a, i, **kwargs)`: pools the graph and returns the reduced node
  features and adjacency matrix. If the batch index `i` is not `None`, a
  reduced version of `i` will be returned as well.
  Any given `kwargs` will be passed as keyword arguments to `select()`,
  `reduce()` and `connect()` if any matching key is found.
  The mandatory arguments of `pool()` **must** be computed in `call()` by
  calling `self.get_inputs(inputs)`.
  - `select(x, a, i, **kwargs)`: computes supernode assignments mapping the
  nodes of the input graph to the nodes of the output.
  - `reduce(x, s, **kwargs)`: reduces the supernodes to form the nodes of the
  pooled graph.
  - `connect(a, s, **kwargs)`: connects the reduced supernodes.
  - `reduce_index(i, s, **kwargs)`: helper function to reduce the batch index
  (only called if `i` is given as input).
  
  When overriding any function of the API, it is possible to access the
  true number of nodes of the input (`n_nodes`) as a Tensor in the instance variable
  `self.n_nodes` (this is populated by `self.get_inputs()` at the beginning of
  `call()`).
  
  **Arguments**:
  
  - `return_selection`: if `True`, the Tensor used to represent supernode assignments
  will be returned with `x_pool`, `a_pool`, and `i_pool`;
docstr: This is the core method of the SRC class, which runs a full pass of
  selection, reduction and connection.
  It is usually not necessary to modify this function. Any previous/shared
  operations should be done in `call()` and their results can be passed to
  the three SRC functions via keyword arguments (any kwargs given to this
  function will be matched to the signature of `select()`, `reduce()` and
  `connect()` and propagated as input to the three functions).
  Any pooling logic should go in the SRC functions themselves.
  :param x: Tensor of shape `([batch], N, F)`;
  :param a: Tensor or SparseTensor of shape `([batch], N, N)`;
  :param i: only in single/disjoint mode, Tensor of integers with shape
  `(N, )`; otherwise, `None`;
  :param kwargs: additional keyword arguments for `select()`, `reduce()`
  and `connect()`. Any matching kwargs will be passed to each of the three
  functions.
  :return:
      - `x_pool`: Tensor of shape `([batch], K, F)`, where `K` is the
      number of output nodes and depends on the pooling strategy;
      - `a_pool`: Tensor or SparseTensor of shape `([batch], K, K)`;
      - `i_pool`: (only if `i` is not `None`) Tensor of integers with shape
      `(K, )`;
docstr_tok: ["This","is","the","core","method","of","the","SRC","class",",","which","runs","a","full","pass","of","selection",",","reduction","and","connection",".","It","is","usually","not","necessary","to","modify","this","function",".","Any","previous\/shared","operations","should","be","done","in","`","call","(",")","`","and","their","results","can","be","passed","to","the","three","SRC","functions","via","keyword","arguments","(","any","kwargs","given","to","this","function","will","be","matched","to","the","signature","of","`","select","(",")","`",",","`","reduce","(",")","`","and","`","connect","(",")","`","and","propagated","as","input","to","the","three","functions",")",".","Any","pooling","logic","should","go","in","the","SRC","functions","themselves",".",":","param","x",":","Tensor","of","shape","`","(","[","batch","]",",","N",",","F",")","`",";",":","param","a",":","Tensor","or","SparseTensor","of","shape","`","(","[","batch","]",",","N",",","N",")","`",";",":","param","i",":","only","in","single\/disjoint","mode",",","Tensor","of","integers","with","shape","`","(","N",",",")","`",";","otherwise",",","`","None","`",";",":","param","kwargs",":","additional","keyword","arguments","for","`","select","(",")","`",",","`","reduce","(",")","`","and","`","connect","(",")","`",".","Any","matching","kwargs","will","be","passed","to","each","of","the","three","functions",".",":","return",":","-","`","x_pool","`",":","Tensor","of","shape","`","(","[","batch","]",",","K",",","F",")","`",",","where","`","K","`","is","the","number","of","output","nodes","and","depends","on","the","pooling","strategy",";","-","`","a_pool","`",":","Tensor","or","SparseTensor","of","shape","`","(","[","batch","]",",","K",",","K",")","`",";","-","`","i_pool","`",":","(","only","if","`","i","`","is","not","`","None","`",")","Tensor","of","integers","with","shape","`","(","K",",",")","`",";"]
code: def pool(self, x, a, i, **kwargs):
      """
      This is the core method of the SRC class, which runs a full pass of
      selection, reduction and connection.
      It is usually not necessary to modify this function. Any previous/shared
      operations should be done in `call()` and their results can be passed to
      the three SRC functions via keyword arguments (any kwargs given to this
      function will be matched to the signature of `select()`, `reduce()` and
      `connect()` and propagated as input to the three functions).
      Any pooling logic should go in the SRC functions themselves.
      :param x: Tensor of shape `([batch], N, F)`;
      :param a: Tensor or SparseTensor of shape `([batch], N, N)`;
      :param i: only in single/disjoint mode, Tensor of integers with shape
      `(N, )`; otherwise, `None`;
      :param kwargs: additional keyword arguments for `select()`, `reduce()`
      and `connect()`. Any matching kwargs will be passed to each of the three
      functions.
      :return:
          - `x_pool`: Tensor of shape `([batch], K, F)`, where `K` is the
          number of output nodes and depends on the pooling strategy;
          - `a_pool`: Tensor or SparseTensor of shape `([batch], K, K)`;
          - `i_pool`: (only if `i` is not `None`) Tensor of integers with shape
          `(K, )`;
      """
      # Select
      sel_kwargs = self._get_kwargs(x, a, i, self.sel_signature, kwargs)
      s = self.select(x, a, i, **sel_kwargs)
  
      # Reduce
      red_kwargs = self._get_kwargs(x, a, i, self.red_signature, kwargs)
      x_pool = self.reduce(x, s, **red_kwargs)
  
      # Index reduce
      i_red_kwargs = self._get_kwargs(
          x, a, i, self.i_red_signature, kwargs
      )
      i_pool = (
          self.reduce_index(i, s, **i_red_kwargs)
          if i is not None
          else None
      )
  
      # Connect
      con_kwargs = self._get_kwargs(x, a, i, self.con_signature, kwargs)
      a_pool = self.connect(a, s, **con_kwargs)
  
      return self.get_outputs(x_pool, a_pool, i_pool, s)
  
imports: import inspect
  import tensorflow
  from tensorflow.keras import backend
  from tensorflow.keras.layers import Layer
  from spektral.utils.keras import deserialize_kwarg, is_keras_kwarg, is_layer_kwarg, serialize_kwarg
label_desc: Use image node_id 4 for calling the SRCPool obj's underlying member method code with example usage: obj.pool(x, a, i) and returns: self