def sampler_initializer(self): ''' Numba functions are compiled just in time the first time we call them. This function initializes both numba classes and the link sampler in order not to incourr into the computational overhead when we need to add a massive number of edges :return: Initializes numba methods and functions ''' # links dir_sampler = Dirichlet(size=self.pop_size, alpha=1) pdist = dir_sampler.sample() _link_sampler(1, dir_sampler)
def add_links(self, get_richer_step=0.1, links_to_add='default', n_jobs=None): ''' Method used to add randomly to the graph links with preferential attachment :param get_richer_step: (real number > 0) The higher is this parameter, the heavier are the degree distribution tails :param links_to_add: (integer > 0) Number of edges to add to the graph with this procedure :return: Adds drawn link to self.adjacency ''' if (links_to_add == 'default'): links = self.pop_size * 3 else: links = links_to_add # initialize the dirichlet sampler and draw the first distrib dir_sampler = Dirichlet(size=self.pop_size, alpha=1) edge_a, edge_b = _link_sampler(links, dir_sampler, get_richer_step) # todo this could be made way more efficient through the use of COO matrices if (n_jobs is None): # fianally we insert in the adjacency matrix the obtained links for j in range(links): # print(edge_a[j],edge_b[j]) row = edge_a[j] # - 1 column = edge_b[j] # - 1 self.adjacency[row, column] = True self.adjacency[column, row] = True # todo not very fast, should undestand why else: Parallel(n_jobs=n_jobs, backend='threading')( delayed(_adj_writer)(self.adjacency, in_node, out_node) for in_node in edge_a for out_node in edge_b) # we remove self loops self.adjacency.setdiag(0)
def add_links(self, get_richer_step=0.1, links_to_add='default'): ''' Method used to add randomly to the graph links with preferential attachment :param get_richer_step: (real number > 0) The higher is this parameter, the heavier are the degree distribution tails :param links_to_add: (integer > 0) Number of edges to add to the graph with this procedure :return: Adds drawn link to self.adjacency ''' if (links_to_add == 'default'): links = self.pop_size * 3 else: links = links_to_add dir_sampler = Dirichlet(size=self.pop_size, alpha=1) pdist = dir_sampler.sample() multi_sampler = Multinomial(size=1, pdist=pdist) #multi_sampler = Multinomial_with_randomization(pdist=pdist,randomization=0) added = 0 edge_a = np.empty(links, dtype=np.int32) edge_b = np.empty(links, dtype=np.int32) while (added < links): if (added == 0): edge_a, edge_b = _link_sampler(links - added, dir_sampler, multi_sampler, get_richer_step) edge_a = edge_a.astype(np.int32) edge_b = edge_b.astype(np.int32) else: warnings.warn( 'Numerical error occurred, remaning links {}'.format( links - added)) # print('Numerical occurred, remaining links:',links-added) temp_a, temp_b = _link_sampler(links - added, dir_sampler, multi_sampler) edge_a = np.append(edge_a, temp_a) edge_b = np.append(edge_b, temp_b) added += len(temp_a) # first filter filter1 = np.where( np.abs(edge_a.astype(np.int64)) > self.pop_size, False, True) edge_a = edge_a[filter1] edge_b = edge_b[filter1] # second filter filter2 = np.where( np.abs(edge_b.astype(np.int64)) > self.pop_size, False, True) edge_a = edge_a[filter2] edge_b = edge_b[filter2] if (added == 0): added += len(edge_a) for j in range(links): # print(edge_a[j],edge_b[j]) row = edge_a[j] #- 1 column = edge_b[j] #- 1 self.adjacency[row, column] = True self.adjacency[column, row] = True self.adjacency.setdiag(0)