class_docstr: A CensNet convolutional layer from the paper
  
  > [Co-embedding of Nodes and Edges with Graph Neural Networks](https://arxiv.org/abs/2010.13242)<br>
  > Xiaodong Jiang et al.
  
  This implements both the node and edge propagation rules as a single layer.
  
  **Mode**: single, disjoint, batch.
  
  **Input**
  
  - Node features of shape `([batch], n_nodes, n_node_features)`;
  - A tuple containing:
      - Modified Laplacian of shape `([batch], n_nodes, n_nodes)`; can be
          computed with `spektral.utils.convolution.gcn_filter`.
      - Modified line graph Laplacian of shape `([batch], n_edges, n_edges)`;
          can be computed with `spektral.utils.convolution.line_graph` and
          `spektral.utils.convolution.gcn_filter`.
      - Incidence matrix of shape `([batch], n_nodes, n_edges)`; can be
          computed with `spektral.utils.convolution.incidence_matrix`.
  - Edge features of shape `([batch], n_edges, n_edge_features)`;
  
  **Output**
  
  - Node features with the same shape as the input, but with the last
  dimension changed to `node_channels`.
  - Edge features with the same shape as the input, but with the last
  dimension changed to `edge_channels`.
  
  **Arguments**
  
  - `node_channels`: number of output channels for the node features;
  - `edge_channels`: number of output channels for the edge features;
  - `activation`: activation function;
  - `use_bias`: bool, add a bias vector to the output;
  - `kernel_initializer`: initializer for the weights;
  - `node_initializer`: initializer for the node feature weights (P_n);
  - `edge_initializer`: initializer for the edge feature weights (P_e);
  - `bias_initializer`: initializer for the bias vector;
  - `kernel_regularizer`: regularization applied to the weights;
  - `edge_regularizer`: regularization applied to the edge feature weights;
  - `bias_regularizer`: regularization applied to the bias vector;
  - `activity_regularizer`: regularization applied to the output;
  - `kernel_constraint`: constraint applied to the weights;
  - `edge_constraint`: constraint applied to the edge feature weights;
  - `bias_constraint`: constraint applied to the bias vector.
docstr: Performs the node feature propagation step.
  
  :param inputs: All the inputs to the layer.
  :param mask: The mask to use.
  :return: The propagated node features.
docstr_tok: ["Performs","the","node","feature","propagation","step",".",":","param","inputs",":","All","the","inputs","to","the","layer",".",":","param","mask",":","The","mask","to","use",".",":","return",":","The","propagated","node","features","."]
code: def _propagate_nodes(self, inputs, mask=None):
      """
      Performs the node feature propagation step.
  
      :param inputs: All the inputs to the layer.
      :param mask: The mask to use.
      :return: The propagated node features.
      """
      node_features, (laplacian, _, incidence), edge_features = inputs
  
      weighted_edge_features = tf.matmul(
          edge_features, self.edge_weights
      )
      # Remove the extra 1-dimension.
      weighted_edge_features = tf.squeeze(
          weighted_edge_features, axis=[-1]
      )
      weighted_edge_features = tf.linalg.diag(weighted_edge_features)
      weighted_edge_features = ops.modal_dot(
          incidence, weighted_edge_features
      )
      weighted_edge_features = ops.modal_dot(
          weighted_edge_features, incidence, transpose_b=True
      )
  
      node_adjacency = weighted_edge_features * laplacian
      output = ops.modal_dot(node_adjacency, node_features)
      output = ops.modal_dot(output, self.node_kernel)
  
      return self._bias_and_activation(
          output, bias_weights=self.node_bias, mask=mask
      )
  
file_path: spektral/spektral/layers/convolutional/censnet_conv.py
imports: import tensorflow
  from spektral.layers import ops
  from spektral.layers.convolutional.conv import Conv
  from spektral.utils.convolution import gcn_filter, incidence_matrix, line_graph
label_desc: Use image node_id 4 for calling the CensNetConv obj's underlying member method code with example usage: obj._propagate_nodes(inputs, mask) and returns: self