-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathgraph_construction.py
70 lines (63 loc) · 3.3 KB
/
graph_construction.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
__author__ = "shekkizh"
import numpy as np
from non_neg_qpsolver import non_negative_qpsolver
import scipy.sparse as sparse
def knn_graph(G, mask, knn_param, reg=1e-6):
"""
Function to generate KNN graph given similarity matrix and mask
:param G: Similarity matrix
:param mask: each row corresponds to the neighbors to be considered for NNK optimization
:param knn_param: maximum number of neighbors for each node
:param reg: weights below this threshold are removed (set to 0)
:return: Adjacency matrix of size num of nodes x num of nodes
"""
num_of_nodes = G.shape[0]
neighbor_indices = np.zeros((num_of_nodes, knn_param))
weight_values = np.zeros((num_of_nodes, knn_param))
for node_i in range(num_of_nodes):
non_zero_index = np.array(mask[node_i, :])
non_zero_index = np.delete(non_zero_index, np.where(non_zero_index == node_i))
g_i = G[non_zero_index, node_i]
g_i[g_i < reg] = 0
weight_values[node_i, :] = g_i
neighbor_indices[node_i, :] = non_zero_index
row_indices = np.expand_dims(np.arange(0, num_of_nodes), 1)
row_indices = np.tile(row_indices, [1, knn_param])
adjacency = sparse.coo_matrix((weight_values.ravel(), (row_indices.ravel(), neighbor_indices.ravel())),
shape=(num_of_nodes, num_of_nodes))
# Symmetrize adjacency matrix
adjacency = adjacency.maximum(adjacency.T)
return adjacency
def nnk_graph(G, mask, knn_param, reg=1e-6):
"""
Function to generate NNK graph given similarity matrix and mask
:param G: Similarity matrix
:param mask: each row corresponds to the neighbors to be considered for NNK optimization
:param knn_param: maximum number of neighbors for each node
:param reg: weights below this threshold are removed (set to 0)
:return: Adjacency matrix of size num of nodes x num of nodes
"""
num_of_nodes = G.shape[0]
neighbor_indices = np.zeros((num_of_nodes, knn_param))
weight_values = np.zeros((num_of_nodes, knn_param))
error_values = np.zeros((num_of_nodes, knn_param))
for node_i in range(num_of_nodes):
non_zero_index = np.array(mask[node_i, :])
non_zero_index = np.delete(non_zero_index, np.where(non_zero_index == node_i))
G_i = G[np.ix_(non_zero_index, non_zero_index)]
g_i = G[non_zero_index, node_i]
x_opt, check = non_negative_qpsolver(G_i, g_i, g_i, reg)
error_values[node_i, :] = G[node_i, node_i] - 2 * np.dot(x_opt, g_i) + np.dot(x_opt, np.dot(G_i, x_opt))
weight_values[node_i, :] = x_opt
neighbor_indices[node_i, :] = non_zero_index
row_indices = np.expand_dims(np.arange(0, num_of_nodes), 1)
row_indices = np.tile(row_indices, [1, knn_param])
adjacency = sparse.coo_matrix((weight_values.ravel(), (row_indices.ravel(), neighbor_indices.ravel())),
shape=(num_of_nodes, num_of_nodes))
error = sparse.coo_matrix((error_values.ravel(), (row_indices.ravel(), neighbor_indices.ravel())),
shape=(num_of_nodes, num_of_nodes))
# Alternate way of doing: error_index = sparse.find(error > error.T); adjacency[error_index[0], error_index[
# 1]] = 0
adjacency = adjacency.multiply(error < error.T)
adjacency = adjacency.maximum(adjacency.T)
return adjacency