|
@@ -9,17 +9,37 @@ import scipy.sparse as sp |
|
|
import torch
|
|
|
import torch
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_eye_sparse(adj_mat: torch.Tensor) -> torch.Tensor:
|
|
|
|
|
|
|
|
|
def _check_tensor(adj_mat):
|
|
|
if not isinstance(adj_mat, torch.Tensor):
|
|
|
if not isinstance(adj_mat, torch.Tensor):
|
|
|
raise ValueError('adj_mat must be a torch.Tensor')
|
|
|
raise ValueError('adj_mat must be a torch.Tensor')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _check_sparse(adj_mat):
|
|
|
if not adj_mat.is_sparse:
|
|
|
if not adj_mat.is_sparse:
|
|
|
raise ValueError('adj_mat must be sparse')
|
|
|
raise ValueError('adj_mat must be sparse')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _check_dense(adj_mat):
|
|
|
|
|
|
if adj_mat.is_sparse:
|
|
|
|
|
|
raise ValueError('adj_mat must be dense')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _check_square(adj_mat):
|
|
|
if len(adj_mat.shape) != 2 or \
|
|
|
if len(adj_mat.shape) != 2 or \
|
|
|
adj_mat.shape[0] != adj_mat.shape[1]:
|
|
|
adj_mat.shape[0] != adj_mat.shape[1]:
|
|
|
raise ValueError('adj_mat must be a square matrix')
|
|
|
raise ValueError('adj_mat must be a square matrix')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _check_2d(adj_mat):
|
|
|
|
|
|
if len(adj_mat.shape) != 2:
|
|
|
|
|
|
raise ValueError('adj_mat must be a square matrix')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_eye_sparse(adj_mat: torch.Tensor) -> torch.Tensor:
|
|
|
|
|
|
_check_tensor(adj_mat)
|
|
|
|
|
|
_check_sparse(adj_mat)
|
|
|
|
|
|
_check_square(adj_mat)
|
|
|
|
|
|
|
|
|
adj_mat = adj_mat.coalesce()
|
|
|
adj_mat = adj_mat.coalesce()
|
|
|
indices = adj_mat.indices()
|
|
|
indices = adj_mat.indices()
|
|
|
values = adj_mat.values()
|
|
|
values = adj_mat.values()
|
|
@@ -36,12 +56,42 @@ def add_eye_sparse(adj_mat: torch.Tensor) -> torch.Tensor: |
|
|
return adj_mat
|
|
|
return adj_mat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def norm_adj_mat_one_node_type_sparse(adj_mat):
|
|
|
|
|
|
if len(adj_mat.shape) != 2 or \
|
|
|
|
|
|
adj_mat.shape[0] != adj_mat.shape[1]:
|
|
|
|
|
|
raise ValueError('adj_mat must be a square matrix')
|
|
|
|
|
|
|
|
|
def norm_adj_mat_one_node_type_sparse(adj_mat: torch.Tensor) -> torch.Tensor:
|
|
|
|
|
|
_check_tensor(adj_mat)
|
|
|
|
|
|
_check_sparse(adj_mat)
|
|
|
|
|
|
_check_square(adj_mat)
|
|
|
|
|
|
|
|
|
adj_mat = add_eye_sparse(adj_mat)
|
|
|
adj_mat = add_eye_sparse(adj_mat)
|
|
|
|
|
|
adj_mat = norm_adj_mat_two_node_types_sparse(adj_mat)
|
|
|
|
|
|
|
|
|
|
|
|
return adj_mat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def norm_adj_mat_one_node_type_dense(adj_mat: torch.Tensor) -> torch.Tensor:
|
|
|
|
|
|
_check_tensor(adj_mat)
|
|
|
|
|
|
_check_dense(adj_mat)
|
|
|
|
|
|
_check_square(adj_mat)
|
|
|
|
|
|
|
|
|
|
|
|
adj_mat = adj_mat + torch.eye(adj_mat.shape[0], dtype=adj_mat.dtype)
|
|
|
|
|
|
adj_mat = norm_adj_mat_two_node_types_dense(adj_mat)
|
|
|
|
|
|
|
|
|
|
|
|
return adj_mat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def norm_adj_mat_one_node_type(adj_mat: torch.Tensor) -> torch.Tensor:
|
|
|
|
|
|
_check_tensor(adj_mat)
|
|
|
|
|
|
_check_square(adj_mat)
|
|
|
|
|
|
|
|
|
|
|
|
if adj_mat.is_sparse:
|
|
|
|
|
|
return norm_adj_mat_one_node_type_sparse(adj_mat)
|
|
|
|
|
|
else:
|
|
|
|
|
|
return norm_adj_mat_one_node_type_dense(adj_mat)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def norm_adj_mat_two_node_types_sparse(adj_mat: torch.Tensor) -> torch.Tensor:
|
|
|
|
|
|
_check_tensor(adj_mat)
|
|
|
|
|
|
_check_sparse(adj_mat)
|
|
|
|
|
|
_check_2d(adj_mat)
|
|
|
|
|
|
|
|
|
adj_mat = adj_mat.coalesce()
|
|
|
adj_mat = adj_mat.coalesce()
|
|
|
indices = adj_mat.indices()
|
|
|
indices = adj_mat.indices()
|
|
@@ -50,28 +100,17 @@ def norm_adj_mat_one_node_type_sparse(adj_mat): |
|
|
degrees_row = degrees_row.index_add(0, indices[0], values.to(degrees_row.dtype))
|
|
|
degrees_row = degrees_row.index_add(0, indices[0], values.to(degrees_row.dtype))
|
|
|
degrees_col = torch.zeros(adj_mat.shape[1])
|
|
|
degrees_col = torch.zeros(adj_mat.shape[1])
|
|
|
degrees_col = degrees_col.index_add(0, indices[1], values.to(degrees_col.dtype))
|
|
|
degrees_col = degrees_col.index_add(0, indices[1], values.to(degrees_col.dtype))
|
|
|
# degrees_row = torch.sqrt(degrees_row)
|
|
|
|
|
|
# degrees_col = torch.sqrt(degrees_col)
|
|
|
|
|
|
# print('degrees:', degrees)
|
|
|
|
|
|
# print('values:', values)
|
|
|
|
|
|
values = values.to(degrees_row.dtype) / torch.sqrt(degrees_row[indices[0]] * degrees_col[indices[1]])
|
|
|
values = values.to(degrees_row.dtype) / torch.sqrt(degrees_row[indices[0]] * degrees_col[indices[1]])
|
|
|
adj_mat = torch.sparse_coo_tensor(indices=indices, values=values, size=adj_mat.shape)
|
|
|
adj_mat = torch.sparse_coo_tensor(indices=indices, values=values, size=adj_mat.shape)
|
|
|
|
|
|
|
|
|
return adj_mat
|
|
|
return adj_mat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def norm_adj_mat_one_node_type_dense(adj_mat):
|
|
|
|
|
|
if not isinstance(adj_mat, torch.Tensor):
|
|
|
|
|
|
raise ValueError('adj_mat must be a torch.Tensor')
|
|
|
|
|
|
|
|
|
|
|
|
if adj_mat.is_sparse:
|
|
|
|
|
|
raise ValueError('adj_mat must be dense')
|
|
|
|
|
|
|
|
|
|
|
|
if len(adj_mat.shape) != 2 or \
|
|
|
|
|
|
adj_mat.shape[0] != adj_mat.shape[1]:
|
|
|
|
|
|
raise ValueError('adj_mat must be a square matrix')
|
|
|
|
|
|
|
|
|
def norm_adj_mat_two_node_types_dense(adj_mat: torch.Tensor) -> torch.Tensor:
|
|
|
|
|
|
_check_tensor(adj_mat)
|
|
|
|
|
|
_check_dense(adj_mat)
|
|
|
|
|
|
_check_2d(adj_mat)
|
|
|
|
|
|
|
|
|
adj_mat = adj_mat + torch.eye(adj_mat.shape[0], dtype=adj_mat.dtype)
|
|
|
|
|
|
degrees_row = adj_mat.sum(1).view(-1, 1).to(torch.float32)
|
|
|
degrees_row = adj_mat.sum(1).view(-1, 1).to(torch.float32)
|
|
|
degrees_col = adj_mat.sum(0).view(1, -1).to(torch.float32)
|
|
|
degrees_col = adj_mat.sum(0).view(1, -1).to(torch.float32)
|
|
|
degrees_row = torch.sqrt(degrees_row)
|
|
|
degrees_row = torch.sqrt(degrees_row)
|
|
@@ -82,29 +121,11 @@ def norm_adj_mat_one_node_type_dense(adj_mat): |
|
|
return adj_mat
|
|
|
return adj_mat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def norm_adj_mat_one_node_type(adj_mat):
|
|
|
|
|
|
|
|
|
def norm_adj_mat_two_node_types(adj_mat: torch.Tensor) -> torch.Tensor:
|
|
|
|
|
|
_check_tensor(adj_mat)
|
|
|
|
|
|
_check_2d(adj_mat)
|
|
|
|
|
|
|
|
|
if adj_mat.is_sparse:
|
|
|
if adj_mat.is_sparse:
|
|
|
return norm_adj_mat_one_node_type_sparse(adj_mat)
|
|
|
|
|
|
|
|
|
return norm_adj_mat_two_node_types_sparse(adj_mat)
|
|
|
else:
|
|
|
else:
|
|
|
return norm_adj_mat_one_node_type_dense(adj_mat)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# def norm_adj_mat_one_node_type(adj):
|
|
|
|
|
|
# adj = sp.coo_matrix(adj)
|
|
|
|
|
|
# assert adj.shape[0] == adj.shape[1]
|
|
|
|
|
|
# adj_ = adj + sp.eye(adj.shape[0])
|
|
|
|
|
|
# rowsum = np.array(adj_.sum(1))
|
|
|
|
|
|
# degree_mat_inv_sqrt = np.power(rowsum, -0.5).flatten()
|
|
|
|
|
|
# degree_mat_inv_sqrt = sp.diags(degree_mat_inv_sqrt)
|
|
|
|
|
|
# adj_normalized = adj_.dot(degree_mat_inv_sqrt).transpose().dot(degree_mat_inv_sqrt)
|
|
|
|
|
|
# return adj_normalized
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def norm_adj_mat_two_node_types(adj):
|
|
|
|
|
|
adj = sp.coo_matrix(adj)
|
|
|
|
|
|
rowsum = np.array(adj.sum(1))
|
|
|
|
|
|
colsum = np.array(adj.sum(0))
|
|
|
|
|
|
rowdegree_mat_inv = sp.diags(np.nan_to_num(np.power(rowsum, -0.5)).flatten())
|
|
|
|
|
|
coldegree_mat_inv = sp.diags(np.nan_to_num(np.power(colsum, -0.5)).flatten())
|
|
|
|
|
|
adj_normalized = rowdegree_mat_inv.dot(adj).dot(coldegree_mat_inv).tocoo()
|
|
|
|
|
|
return adj_normalized
|
|
|
|
|
|
|
|
|
return norm_adj_mat_two_node_types_dense(adj_mat)
|