def heat_diffusion_ind(graph, taus=TAUS, order=ORDER, proc=PROC): ''' This method computes the heat diffusion waves for each of the nodes INPUT: ----------------------- graph : Graph (etworkx) taus : list of scales for the wavelets. The higher the tau, the better the spread of the heat over the graph order : order of the polynomial approximation proc : which procedure to compute the signatures (approximate == that is, with Chebychev approx -- or exact) OUTPUT: ----------------------- heat : tensor of length len(tau) x n_nodes x n_nodes where heat[tau,:,u] is the wavelet for node u at scale tau taus : the associated scales ''' # Compute Laplacian a = nx.adjacency_matrix(graph) n_nodes, _ = a.shape #thres = np.vectorize(lambda x : x if x > 1e-4 * 1.0 / n_nodes else 0) lap = laplacian(a) print('n_nodes:', n_nodes) print('laplacian nnz(GB):', "%.3f" % (lap.nnz / 1024 / 1024 / 1024 * 4)) n_filters = len(taus) if proc == 'exact': ### Compute the exact signature lamb, U = np.linalg.eigh(lap.todense()) heat = {} for i in range(n_filters): heat[i] = U.dot(np.diagflat(np.exp(-taus[i] * lamb).flatten())).dot(U.T) else: # Create a constant matrix sparse_eye = sc.sparse.eye(n_nodes) heat = { i: sc.sparse.csc_matrix((n_nodes, n_nodes)) for i in range(n_filters) } monome = {0: sparse_eye, 1: lap - sparse_eye} for k in range(2, order + 1): monome[k] = 2 * (lap - sparse_eye).dot(monome[k - 1]) - monome[k - 2] print("Computing monome", k) print("monome number of nonzero(GB):", "%.3f" % (monome[k].nnz / 1024 / 1024 / 1024 * 4)) for i in range(n_filters): coeffs = compute_cheb_coeff_basis(taus[i], order) heat[i] = sc.sum( [coeffs[k] * monome[k] for k in range(0, order + 1)]) #temp = thres(heat[i].A) # cleans up the small coefficients temp = heat[i] temp.data = np.where(temp.data > 1e-4 * 1.0 / n_nodes, temp.data, 0) heat[i] = sc.sparse.csc_matrix(temp) print("Computing heat map for filter", i) return heat, taus
def graphwave_alg(graph, time_pnts, taus='auto', verbose=False, approximate_lambda=True, order=ORDER, proc=PROC, nb_filters=NB_FILTERS, **kwargs): ''' wrapper function for computing the structural signatures using GraphWave INPUT -------------------------------------------------------------------------------------- graph : nx Graph time_pnts : time points at which to evaluate the characteristic function taus : list of scales that we are interested in. Alternatively, 'auto' for the automatic version of GraphWave verbose : the algorithm prints some of the hidden parameters as it goes along approximate_lambda: (boolean) should the range oflambda be approximated or computed? proc : which procedure to compute the signatures (approximate == that is, with Chebychev approx -- or exact) nb_filters : nuber of taus that we require if taus=='auto' OUTPUT -------------------------------------------------------------------------------------- chi : embedding of the function in Euclidean space heat_print : returns the actual embeddings of the nodes taus : returns the list of scales used. ''' if taus == 'auto': if approximate_lambda is not True: a = nx.adjacency_matrix(graph) lap = laplacian(a) try: l1 = np.sort( sc.sparse.linalg.eigsh(lap, 2, which='SM', return_eigenvectors=False))[1] except: l1 = np.sort( sc.sparse.linalg.eigsh(lap, 5, which='SM', return_eigenvectors=False))[1] else: l1 = 1.0 / graph.number_of_nodes() smax = -np.log(ETA_MIN) * np.sqrt(0.5 / l1) smin = -np.log(ETA_MAX) * np.sqrt(0.5 / l1) taus = np.linspace(smin, smax, nb_filters) print(taus) heat_print, _ = heat_diffusion_ind(graph, list(taus), order=order, proc=proc) chi = charac_function_multiscale(heat_print, time_pnts) return chi, heat_print, taus
def heat_diffusion_ind(graph, taus=TAUS, order = ORDER, proc = PROC): ''' This method computes the heat diffusion waves for each of the nodes INPUT: ----------------------- graph : Graph, can be of type networkx or pygsp taus : list of 4 scales for the wavelets. The higher the tau, the better the spread order : order of the polynomial approximation OUTPUT: ----------------------- heat : tensor of length len(tau) x n_nodes x n_nodes where heat[tau,:,u] is the wavelet for node u at scale tau ''' # Compute Laplacian a = nx.adjacency_matrix(graph) n_nodes, _ = a.shape thres = np.vectorize(lambda x : x if x > 1e-4 * 1.0 / n_nodes else 0) lap = laplacian(a) n_filters = len(taus) if proc == 'exact': ### Compute the exact signature lamb, U = np.linalg.eigh(lap.todense()) heat = {} for i in range(n_filters): heat[i] = U.dot(np.diagflat(np.exp(- taus[i] * lamb).flatten())).dot(U.T) else: heat = {i: sc.sparse.csc_matrix((n_nodes, n_nodes)) for i in range(n_filters) } monome = {0: sc.sparse.eye(n_nodes), 1: lap - sc.sparse.eye(n_nodes)} for k in range(2, order + 1): monome[k] = 2 * (lap - sc.sparse.eye(n_nodes)).dot(monome[k-1]) - monome[k - 2] for i in range(n_filters): coeffs = compute_cheb_coeff_basis(taus[i], order) heat[i] = sc.sum([ coeffs[k] * monome[k] for k in range(0, order + 1)]) temp = thres(heat[i].A) # cleans up the small coefficients heat[i] = sc.sparse.csc_matrix(temp) return heat, taus