NetAnalyzer 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,165 @@
1
+ import sys
2
+ import os
3
+ import glob
4
+ import numpy as np
5
+ import concurrent.futures
6
+ import itertools
7
+ import logging
8
+
9
+ class Kernels:
10
+
11
+ def __init__(self):
12
+ self.kernels_raw = [] # [Mat1, Mat2, Mat3,...]
13
+ self.local_indexes = [] # [{Node1 => idx1, Node2=> idx2},{Node1 => idx4, Node2 => idx2}]
14
+ self.general_nodes = [] # list of all nodes
15
+ self.kernels_position_index = {} # { Node1 => [idx1, idx2, None], Node2 => ...}
16
+ self.integrated_kernel = [] # [integrated_matrix, list_of_nodes]
17
+
18
+ def move2zero_reference(self):
19
+ moved_kernels = []
20
+ for idx, kernel in enumerate(self.kernels_raw):
21
+ min_kernel = np.min(kernel)
22
+ if min_kernel < 0:
23
+ logging.warning(f"Fixing negative values on matrix {idx}")
24
+ kernel -= min_kernel
25
+ moved_kernels.append(kernel)
26
+ self.kernels_raw = moved_kernels
27
+
28
+
29
+ def load_kernels_by_bin_matrixes(self, input_matrix, input_nodes, kernels_names):
30
+ for pos, kernel_name in enumerate(kernels_names):
31
+ self.kernels_raw.append(np.load(input_matrix[pos]))
32
+ self.local_indexes.append(self.build_matrix_index(self.lst2arr(input_nodes[pos])))
33
+
34
+ def create_general_index(self):
35
+ self.general_nodes = []
36
+ for index in self.local_indexes:
37
+ self.general_nodes += index.keys()
38
+ self.general_nodes = sorted(list(set(self.general_nodes))) # Uniq elements and sorted to remove permutated matrixes.
39
+
40
+ for node in self.general_nodes:
41
+ self.kernels_position_index[node] = [ind.get(node) for ind in self.local_indexes]
42
+ self.local_indexes = [] # Removing not needed local indexes
43
+
44
+ def integrate(self, method, n_workers = 8, symmetry = True, n_partition_axis = None):
45
+ general_nodes = self.general_nodes.copy()
46
+ nodes_dimension = len(general_nodes)
47
+ general_kernel = np.zeros((nodes_dimension,nodes_dimension))
48
+ n_kernel = len(self.kernels_raw)
49
+ if n_partition_axis == None: n_partition_axis = int(np.trunc(np.sqrt(n_workers))) # Default value to use the corect number of blocks for n_workers
50
+
51
+ # Filling the argument section
52
+ splitted_general_nodes = list(self.split(general_nodes, n_partition_axis))
53
+ if symmetry:
54
+ pair_nodes = list(itertools.combinations_with_replacement(splitted_general_nodes, 2))
55
+ else:
56
+ pair_nodes = list(itertools.product(splitted_general_nodes, repeat = 2))
57
+ process_number = len(pair_nodes)
58
+
59
+ # Calling the multiprocessing
60
+ with concurrent.futures.ProcessPoolExecutor(max_workers=n_workers) as executor:
61
+
62
+ results = [executor.submit(self.build_matrix_block, pair_nodes[i][0],
63
+ pair_nodes[i][1], method, n_kernel, general_nodes, splitted_general_nodes, symmetry) for i in range(process_number)]
64
+
65
+ for f in concurrent.futures.as_completed(results):
66
+ row_start, row_end, col_start, col_end, block_matrix = f.result()
67
+ general_kernel[row_start:row_end, col_start:col_end] = block_matrix
68
+ if row_start != col_start and symmetry:
69
+ general_kernel[col_start:col_end, row_start:row_end] = block_matrix.transpose()
70
+
71
+ self.integrated_kernel = [general_kernel, self.general_nodes]
72
+
73
+
74
+ def build_matrix_block(self, row_nodes, col_nodes, method, n_kernel, general_nodes, splitted_general_nodes, symmetry):
75
+ general_block_matrix = np.zeros((len(row_nodes),len(col_nodes))) # TODO: Add option to considerar matrixes (maybe the min.
76
+
77
+ row_start = general_nodes.index(row_nodes[0])
78
+ row_end = row_start + len(row_nodes)
79
+ col_start = general_nodes.index(col_nodes[0])
80
+ col_end = col_start + len(col_nodes)
81
+
82
+ if symmetry and row_start == col_start:
83
+ # Filling main diagonal blocks with upper triang.
84
+ nodes_dimension = len(row_nodes)
85
+ i = 0
86
+ while len(row_nodes) > 0:
87
+ node_A = row_nodes[-1]
88
+ ind = len(row_nodes) - 1
89
+ for node_B in reversed(row_nodes):
90
+ j = ind
91
+ values = self.get_values(node_A, node_B)
92
+ if values:
93
+ reversed_i = nodes_dimension -1 - i
94
+ general_block_matrix[reversed_i, j] = method(values, n_kernel)
95
+ general_block_matrix[j, reversed_i] = general_block_matrix[reversed_i, j]
96
+ ind -= 1
97
+ row_nodes.pop()
98
+ i += 1
99
+ else:
100
+ # Filling all vs all
101
+ for i, node_A in enumerate(row_nodes):
102
+ for j, node_B in enumerate(col_nodes):
103
+ values = self.get_values(node_A, node_B)
104
+ if values:
105
+ general_block_matrix[i, j] = method(values, n_kernel)
106
+
107
+
108
+ return row_start, row_end, col_start, col_end, general_block_matrix
109
+
110
+ def get_values(self, node_A, node_B):
111
+ rows = self.kernels_position_index[node_A]
112
+ cols = self.kernels_position_index[node_B]
113
+ values = []
114
+ for i, r_ind in enumerate(rows): #Load just the pairs in both sides of the kernel matrix
115
+ if r_ind is not None:
116
+ c_ind = cols[i] # Maybe a get is needed watch out!!!
117
+ if c_ind is not None:
118
+ values.append(self.kernels_raw[i][r_ind, c_ind])
119
+ return values
120
+
121
+ def mean(self, values, n_kernel):
122
+ return sum(values)/n_kernel
123
+
124
+ def mean_by_presence(self, values, n_kernel):
125
+ return sum(values)/len(values)
126
+
127
+ def median(self, values, n_kernel):
128
+ return np.median(values)
129
+
130
+ def max(self, values, n_kernel):
131
+ return max(values)
132
+
133
+ def geometric_mean(self, values, n_kernel):
134
+ # TODO: Talk about the possibility of improving execution time with a non-log formula.
135
+ # log to avoid overflows
136
+ return np.exp(np.log(values).mean())
137
+
138
+ def integrate_matrix(self, method, n_workers = 8, symmetry = True):
139
+ if method == "mean":
140
+ self.integrate(method = self.mean, n_workers = n_workers, symmetry = symmetry)
141
+ elif method == "integration_mean_by_presence":
142
+ self.integrate(method = self.mean_by_presence, n_workers = n_workers, symmetry = symmetry)
143
+ elif method == "median":
144
+ self.integrate(method = self.median, n_workers = n_workers, symmetry = symmetry)
145
+ elif method == "max":
146
+ self.integrate(method = self.max, n_workers = n_workers, symmetry = symmetry)
147
+ elif method == "geometric_mean":
148
+ self.integrate(method = self.geometric_mean, n_workers = n_workers, symmetry = symmetry)
149
+
150
+ ## AUXILIAR METHODS
151
+ ##############################
152
+
153
+ def split(self, a, n): # https://stackoverflow.com/questions/2130016/splitting-a-list-into-n-parts-of-approximately-equal-length
154
+ k, m = divmod(len(a), n)
155
+ return (a[i*k+min(i, m):(i+1)*k+min(i+1, m)] for i in range(n))
156
+
157
+ def lst2arr(self,lst_file):
158
+ nodes = []
159
+ with open(lst_file, "r") as file:
160
+ for line in file:
161
+ nodes.append(line.rstrip())
162
+ return nodes
163
+
164
+ def build_matrix_index(self, node_list):
165
+ return {node: i for i, node in enumerate(node_list)}