Source code for egc.utils.normalization

"""
Normalization Utils
"""
import sys

import numpy as np
import scipy.sparse as sp
import torch

# pylint: disable=no-else-return
EOS = 1e-10

############################################################################
# START: This section of code is adapted from https://github.com/tkipf/gcn #
############################################################################


[docs]def normalize_feature(features: sp.lil_matrix) -> np.array: """Row-normalize feature matrix. Args: features (scipy.sparse.lil.lil_matrix): 2D sparse features Returns: features_norm (numpy.matrix): 2D row-normalized features """ row_sum_inv = np.power(np.array(features.sum(1)), -1).flatten() row_sum_inv[np.isinf(row_sum_inv)] = 0.0 row_sum_inv_diag = sp.diags(row_sum_inv) return row_sum_inv_diag.dot(features).todense()
[docs]def symmetrically_normalize_adj(adj: sp.csr_matrix) -> sp.coo_matrix: """Symmetrically normalize adjacency matrix. Args: adj (scipy.sparse.csr.csr_matrix): 2D sparse adjacency matrix Returns: daj_norm (scipy.sparse.coo.coo_matrix): 2D Symmetrically normalized sparse adjacency matrix """ adj = sp.coo_matrix(adj) rowsum = np.array(adj.sum(1)) d_inv_sqrt = np.power(rowsum, -0.5).flatten() d_inv_sqrt[np.isinf(d_inv_sqrt)] = 0.0 d_mat_inv_sqrt = sp.diags(d_inv_sqrt) return adj.dot(d_mat_inv_sqrt).transpose().dot(d_mat_inv_sqrt).tocoo()
############################################################################ # END: This section of code is adapted from https://github.com/tkipf/gcn # ############################################################################
[docs]def asymmetric_normalize_adj(adj, loop=True): """Get convolution operator Args: adj (ndarray) : the adjacency matrix of improved graph loop (boolean,optional) : add self loop Returns: (ndarray) convolution_operator = D'^-1 * A' """ if loop: adj = adj + sp.eye(adj.shape[0]) if sp.issparse(adj): adj = adj.todense() rowsum = np.array(adj.sum(1)) d_inv = np.power(rowsum, -1.0).flatten() d_inv[np.isinf(d_inv)] = 0.0 d_mat_inv = sp.diags(d_inv) conv_operator = d_mat_inv.dot(adj) return conv_operator
[docs]def normalize_sublime(adj, mode, sparse=False): """Normalize adjacency matrix for SUBLIME model Args: adj: adjacency matrix mode (str): mode of normalize adjacency matrix sparse (boolean,optional): if use sparse. Defaults to False. Returns: adj after normalize """ if not sparse: if mode == "sym": inv_sqrt_degree = 1.0 / ( torch.sqrt(adj.sum(dim=1, keepdim=False)) + EOS) return inv_sqrt_degree[:, None] * adj * inv_sqrt_degree[None, :] elif mode == "row": inv_degree = 1.0 / (adj.sum(dim=1, keepdim=False) + EOS) return inv_degree[:, None] * adj else: sys.exit("wrong norm mode") else: adj = adj.coalesce() if mode == "sym": inv_sqrt_degree = 1.0 / (torch.sqrt( torch.sparse.sum(adj, dim=1).values())) D_value = (inv_sqrt_degree[adj.indices()[0]] * inv_sqrt_degree[adj.indices()[1]]) elif mode == "row": # aa = torch.sparse.sum(adj, dim=1) # bb = aa.values() inv_degree = 1.0 / (torch.sparse.sum(adj, dim=1).values() + EOS) D_value = inv_degree[adj.indices()[0]] else: sys.exit("wrong norm mode") new_values = adj.values() * D_value return torch.sparse.FloatTensor(adj.indices(), new_values, adj.size())