class_docstr: This class implements the preprocessing of adjacency matrices in GCN. We implement it in tensorflow so that
  while computing the saliency maps, we are able to calculate the gradients in an end-to-end way.
  We currently only support this for tensorflow backend.
  
  Args:
  num_of_nodes (int pair): The number of nodes in the graph.
class_docstr_tok: ["This","class","implements","the","preprocessing","of","adjacency","matrices","in","GCN",".","We","implement","it","in","tensorflow","so","that","while","computing","the","saliency","maps",",","we","are","able","to","calculate","the","gradients","in","an","end-to-end","way",".","We","currently","only","support","this","for","tensorflow","backend",".","Args",":","num_of_nodes","(","int","pair",")",":","The","number","of","nodes","in","the","graph","."]
docstr: The adjacency matrix preprocessing in tensorflow.
  This function applies the matrix transformations on the adjacency matrix, which are required by GCN.
  GCN requires that the input adjacency matrix should be symmetric, with self-loops, and normalized.
  
  Args:
      adj (Numpy array): the adjacency matrix to transform.
  
  Returns:
      The tensor of the transformed adjacency matrix.
docstr_tok: ["The","adjacency","matrix","preprocessing","in","tensorflow",".","This","function","applies","the","matrix","transformations","on","the","adjacency","matrix",",","which","are","required","by","GCN",".","GCN","requires","that","the","input","adjacency","matrix","should","be","symmetric",",","with","self-loops",",","and","normalized",".","Args",":","adj","(","Numpy","array",")",":","the","adjacency","matrix","to","transform",".","Returns",":","The","tensor","of","the","transformed","adjacency","matrix","."]
code: def call(self, adj):
      """
      The adjacency matrix preprocessing in tensorflow.
      This function applies the matrix transformations on the adjacency matrix, which are required by GCN.
      GCN requires that the input adjacency matrix should be symmetric, with self-loops, and normalized.
  
      Args:
          adj (Numpy array): the adjacency matrix to transform.
  
      Returns:
          The tensor of the transformed adjacency matrix.
      """
  
      # Build a symmetric adjacency matrix.
      adj_T = tf.transpose(adj)
      adj = (
          adj
          + tf.multiply(
              adj_T,
              tf.where(
                  adj_T > adj, tf.ones_like(adj), tf.zeros_like(adj)
              ),
          )
          - tf.multiply(
              adj,
              tf.where(
                  adj_T > adj, tf.ones_like(adj), tf.zeros_like(adj)
              ),
          )
      )
      # Add self loops.
      adj = adj + tf.linalg.diag(
          tf.ones(adj.shape[0]) - tf.diag_part(adj)
      )
      # Normalization
      rowsum = tf.reduce_sum(adj, 1)
      d_mat_inv_sqrt = tf.diag(tf.rsqrt(rowsum))
      adj_normalized = tf.matmul(
          tf.matmul(d_mat_inv_sqrt, adj), d_mat_inv_sqrt
      )
      return adj_normalized
  
file_path: stellargraph/stellargraph/layer/preprocessing_layer.py
imports: from tensorflow.keras import backend
  import tensorflow
  from tensorflow.keras.layers import Layer
  from tensorflow import keras
  import numpy
label_desc: Use image node_id 3 for calling the SymmetricGraphPreProcessingLayer obj's underlying member method code with example usage: obj.call(adj) and returns: adj_normalized