def bansal(signed_graph): # start of the algorithm execution_time = ExecutionTime() # initialize the solution as empty solution_x = None solution_objective_function = np.finfo(float).min # get the best clustering from the neighborhood of each node for node, neighbors in enumerate(signed_graph.adjacency_list): x = np.zeros(signed_graph.number_of_nodes) x[node] = 1 for neighbor in neighbors[0]: x[neighbor] = 1 for neighbor in neighbors[1]: x[neighbor] = -1 # update the solution if needed objective_function = evaluate_objective_function(signed_graph, x) if objective_function > solution_objective_function: solution_x = x solution_objective_function = objective_function # build the solution solution = build_solution(solution_x) # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, solution_x, signed_graph) # return the solution return solution, solution_x
def union_core(core_decomposition_file_name, multilayer_graph, gammas, min_sup, min_size, print_file): # start of the algorithm execution_time = ExecutionTime() # obtain a restricted set of nodes from core decomposition nodes = compute_union_core(core_decomposition_file_name, gammas, min_sup, min_size) # execute crochet+ fcgqc = crochet_plus(multilayer_graph, gammas, min_sup, min_size, None, nodes=nodes, print_end_algorithm=False) # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm_fcgqc(gammas, min_sup, min_size, execution_time.execution_time_seconds, len(fcgqc), len(nodes)) # print the resulting fcgqc to file if print_file is not None: print_fcgqc(print_file, fcgqc) return fcgqc
def naive_decomposition(temporal_graph, print_file): # measures number_of_cores = [0] processed_nodes = 0 # start of the algorithm execution_time = ExecutionTime() # cores cores = {} # initialize the queue of intervals intervals_queue = deque() # initialize the set of intervals in the queue intervals = set() # add each singleton interval to the queue for timestamp in temporal_graph.timestamps_iterator: interval = get_interval(timestamp) intervals_queue.append(interval) intervals.add(interval) # while the queue is not empty while len(intervals_queue) > 0: # remove an interval from the queue interval = intervals_queue.popleft() intervals.remove(interval) # store the results of the subroutine to cores processed_nodes += temporal_graph.number_of_nodes cores[interval] = subroutine(temporal_graph, set(temporal_graph.nodes_iterator), interval, print_file=print_file, number_of_cores=number_of_cores)[0] # if there are cores in the interval if len(cores[interval]) > 0: # get its descendant intervals descendant_intervals = get_descendant_intervals( interval, temporal_graph) # for each descendant interval for descendant_interval in descendant_intervals: # if the descendant interval has not already been found if descendant_interval not in intervals: # add the descendant interval to the queue intervals_queue.append(descendant_interval) intervals.add(descendant_interval) # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, number_of_cores[0], processed_nodes)
def eigensign(signed_graph): # start of the algorithm execution_time = ExecutionTime() # initialize the solution as empty solution_x = None solution_objective_function = np.finfo(float).min solution_threshold = None # obtain the adjacency matrix a = signed_graph.get_adjacency_matrix() # get the eigenvector corresponding to the maximum eigenvalue maximum_eigenvector = np.squeeze(eigsh(a, k=1, which='LA')[1]) # get the thresholds from the eigenvector thresholds = { int(np.abs(element) * 1000) / 1000.0 for element in maximum_eigenvector } # compute x for all the values of the threshold for threshold in thresholds: x = np.array([ np.sign(element) if np.abs(element) >= threshold else 0 for element in maximum_eigenvector ]) # update the solution if needed objective_function = evaluate_objective_function(signed_graph, x) if objective_function > solution_objective_function: solution_x = x solution_objective_function = objective_function solution_threshold = threshold # build the solution solution = build_solution(solution_x) # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, solution_x, signed_graph, threshold=solution_threshold) # return the solution return solution, solution_x
def random_eigensign(signed_graph, beta, maximum_eigenvector=None, execution_time_seconds=None): # start of the algorithm execution_time = ExecutionTime() if maximum_eigenvector is None: # obtain the adjacency matrix a = signed_graph.get_adjacency_matrix() # get the eigenvector corresponding to the maximum eigenvalue maximum_eigenvector = np.squeeze(eigsh(a, k=1, which='LA')[1]) # consolidate beta if beta == 'l1': beta = np.linalg.norm(maximum_eigenvector, ord=1) elif beta == 'sqrt': beta = np.sqrt(signed_graph.number_of_nodes) else: beta = float(beta) # multiply the maximum eigenvector by beta maximum_eigenvector *= beta # compute x x = np.array([0 for _ in signed_graph.nodes_iterator]) for node, element in enumerate(maximum_eigenvector): # check the probability for a certain number of times if np.random.choice((True, False), p=(min(np.abs(element), 1), max(1 - np.abs(element), 0))): x[node] = np.sign(element) # build the solution solution = build_solution(x) # end of the algorithm execution_time.end_algorithm() # print algorithm's results if execution_time_seconds is None: execution_time_seconds = execution_time.execution_time_seconds print_end_algorithm(execution_time_seconds, x, signed_graph, beta=beta) # return the solution return solution, x, maximum_eigenvector, execution_time_seconds, beta
def decomposition(temporal_graph, print_file): # measures number_of_cores = [0] processed_nodes = 0 # start of the algorithm execution_time = ExecutionTime() # cores cores = {} # initialize the queue of intervals intervals_queue = deque() # initialize the dict of ancestors ancestors = {} # add each singleton interval to the queue for timestamp in temporal_graph.timestamps_iterator: intervals_queue.append(get_interval(timestamp)) # dict counting the number of descendants in the queue descendants_count = {} # while the queue is not empty while len(intervals_queue) > 0: # remove an interval from the queue interval = intervals_queue.popleft() # get the nodes from which start the computation nodes = get_ancestors_intersection(interval, ancestors, cores, temporal_graph, descendants_count) # if nodes is not empty if len(nodes) > 0: # store the results of the subroutine to cores processed_nodes += len(nodes) cores[interval] = subroutine(temporal_graph, nodes, interval, print_file=print_file, number_of_cores=number_of_cores)[0] # if there are cores in the interval if len(cores[interval]) > 0: # add its descendant intervals to the queue add_descendants_to_queue(interval, temporal_graph, intervals_queue, ancestors, descendants_count) # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, number_of_cores[0], processed_nodes)
def inner_most(multilayer_graph, print_file): # start of the algorithm execution_time = ExecutionTime() # create the data structure m = {} # create the vector of zeros and the set of nodes vector = tuple([0] * multilayer_graph.number_of_layers) nodes = array('i', multilayer_graph.nodes_iterator) # call the subroutine number_of_inner_most_cores, number_of_computed_cores = right_inner_most_cores( multilayer_graph, vector, 0, nodes, m, print_file) # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, number_of_inner_most_cores, number_of_computed_cores)
def crochet_plus(multilayer_graph, gammas, min_sup, min_size, print_file, nodes=None, print_end_algorithm=True): # start of the algorithm execution_time = ExecutionTime() # if the subset of nodes is not provided if nodes is None: # consider every node nodes = set(multilayer_graph.nodes_iterator) # solution list of frequent cross-graph quasi-cliques fcgqc = [] # order the nodes by Heuristic 1 nodes_order = order_nodes(multilayer_graph, gammas, nodes, set(multilayer_graph.layers_iterator)) # for each node (except the last in the ordering) for index, node in enumerate(nodes_order[:-1]): # create the starting node of the enumeration tree tree_node = {node} # call the recursive subroutine recursive_mine(tree_node, set(nodes_order[index + 1:]), set(multilayer_graph.layers_iterator), multilayer_graph, gammas, min_sup, min_size, fcgqc, nodes_order) # end of the algorithm execution_time.end_algorithm() # print algorithm's results if print_end_algorithm: print_end_algorithm_fcgqc(gammas, min_sup, min_size, execution_time.execution_time_seconds, len(fcgqc), None) # print the resulting fcgqc to file if print_file is not None: print_fcgqc(print_file, fcgqc) return fcgqc
def maximal(temporal_graph, print_file): # measures number_of_maximal_cores = 0 processed_nodes = 0 # start of the algorithm execution_time = ExecutionTime() # structures for the maximal cores j_maximal_index = [0 for _ in temporal_graph.timestamps_iterator ] # end of interval, maximum k # for each timestamp i for i in temporal_graph.timestamps_iterator: # edges intersection and differences intersection = set(temporal_graph.edge_sets[i]) differences = [] # while the interval exists j = i + 1 while j < temporal_graph.number_of_timestamps: # compute the new intersection temp_intersection = intersection & set(temporal_graph.edge_sets[j]) # break if it is empty if len(temp_intersection) == 0: break # update the structures differences.append(tuple(intersection - temp_intersection)) intersection = temp_intersection j += 1 differences.append(tuple(intersection)) # adjacency list and nodes divided by degree adjacency_list = defaultdict(list) nodes_by_degree = [[]] # minimum and maximal indexes minimum_index = 1 maximal_index = 0 # for every interval starting from timestamp i j -= 1 while j >= i: # get the [i, j] interval interval = get_interval(i, j) # add the edges for edge in differences[j - i]: adjacency_list[edge[0]].append(edge[1]) adjacency_list[edge[1]].append(edge[0]) try: nodes_by_degree[len(adjacency_list[edge[0]])].append( edge[0]) except IndexError: nodes_by_degree.append([edge[0]]) try: nodes_by_degree[len(adjacency_list[edge[1]])].append( edge[1]) except IndexError: nodes_by_degree.append([edge[1]]) # compute the core decomposition for [i, j] if len(nodes_by_degree) > minimum_index and len( nodes_by_degree[minimum_index]) > minimum_index: processed_nodes += len(nodes_by_degree[minimum_index]) subroutine_result = subroutine( adjacency_list, set(nodes_by_degree[minimum_index])) new_maximal_index = subroutine_result[0] new_maximal_core = subroutine_result[1] # add the new maximal core to the solution if new_maximal_index > maximal_index: maximal_index = new_maximal_index if new_maximal_index > j_maximal_index[j]: minimum_index = new_maximal_index + 1 number_of_maximal_cores += 1 j_maximal_index[j] = new_maximal_index if print_file is not None: print_file.print_core(interval, new_maximal_index, new_maximal_core) # decrement j j -= 1 # end of the algorithm execution_time.end_algorithm() # print algorithm results print_end_algorithm(execution_time.execution_time_seconds, number_of_maximal_cores, processed_nodes)
def hybrid(multilayer_graph, print_file, distinct_flag): # measures number_of_cores = 0 number_of_computed_cores = 0 # start of the algorithm execution_time = ExecutionTime() # create the vector of zeros from which start the computation start_vector = tuple([0] * multilayer_graph.number_of_layers) # dict of cores cores = {} # core [0] if print_file is not None and not distinct_flag: print_file.print_core(start_vector, array('i', multilayer_graph.get_nodes())) elif distinct_flag: cores[start_vector] = array('i', multilayer_graph.get_nodes()) number_of_computed_cores -= 1 number_of_cores += 1 # initialize the queue of vectors with the descendants of start_vector and the structure that for each vector saves its ancestor vectors vectors_queue = deque() ancestors = {} for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(start_vector, index) vectors_queue.append(descendant_vector) ancestors[descendant_vector] = [start_vector] # initialize the dictionary that for each vector counts the number of descendants in the queue descendants_count = defaultdict(int) # compute the core decomposition layer by layer for layer in multilayer_graph.layers_iterator: cores.update( pure_core_decomposition(multilayer_graph, start_vector, layer, print_file=print_file, distinct_flag=distinct_flag)[0]) number_of_computed_cores += len(cores) + multilayer_graph.number_of_layers # while vectors_queue is not empty while len(vectors_queue) > 0: # remove a vector from vectors_queue (FIFO policy) vector = vectors_queue.popleft() # if the number of non zero indexes of vector is equal to the number of its ancestors and is more than 1, build the intersection of its ancestor cores number_of_non_zero_indexes = len( [index for index in vector if index > 0]) number_of_ancestors = len(ancestors[vector]) if number_of_non_zero_indexes == number_of_ancestors and number_of_non_zero_indexes > 1 and vector not in cores: ancestors_intersection = build_ancestors_intersection( ancestors[vector], cores, descendants_count, distinct_flag) # if the intersection of its ancestor cores is not empty if len(ancestors_intersection) > 0: # compute the core from it k_core, minimum_degrees_vector = core(multilayer_graph, vector, ancestors_intersection, algorithm='h') number_of_computed_cores += 1 # if the core is not empty if len(k_core) > 0: # add the core to the dict of cores cores[vector] = k_core if print_file is not None and not distinct_flag: print_file.print_core(vector, k_core) # if the vector of the minimum degrees is not equal to vector if minimum_degrees_vector != vector: # fill the cores that are equals bottom_up_visit(multilayer_graph, minimum_degrees_vector, vector, cores, print_file, distinct_flag) else: # for each ancestor of vector for ancestor in ancestors[vector]: # decrement its number of descendants decrement_descendants_count(ancestor, cores, descendants_count, distinct_flag) # if the core corresponding to the vector is in the dict of cores if vector in cores: # increment the number of cores number_of_cores += 1 # compute its descendant vectors for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(vector, index) try: # update the list of the ancestors of the descendant vector ancestors[descendant_vector].append(vector) # if the descendant vector has not already been found except KeyError: # add the descendant vector to the queue vectors_queue.append(descendant_vector) ancestors[descendant_vector] = [vector] # increment descendants_count descendants_count[vector] += 1 # delete vector's entry from ancestors del ancestors[vector] # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, number_of_cores, number_of_computed_cores) # execute the post processing post_processing(cores, distinct_flag, print_file)
def breadth_first(multilayer_graph, print_file, distinct_flag): # measures number_of_cores = 0 number_of_computed_cores = 0 # start of the algorithm execution_time = ExecutionTime() # create the vector of zeros from which start the computation start_vector = tuple([0] * multilayer_graph.number_of_layers) # dict of cores cores = {} # core [0] if print_file is not None and not distinct_flag: print_file.print_core(start_vector, array('i', multilayer_graph.get_nodes())) elif distinct_flag: cores[start_vector] = array('i', multilayer_graph.get_nodes()) number_of_cores += 1 # initialize the queue of vectors with the descendants of start_vector and the structure that for each vector saves its ancestor vectors vectors_queue = deque() ancestors = {} for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(start_vector, index) vectors_queue.append(descendant_vector) ancestors[descendant_vector] = [start_vector] # initialize the dictionary that for each vector counts the number of descendants in the queue descendants_count = defaultdict(int) # while vectors_queue is not empty while len(vectors_queue) > 0: # remove a vector from vectors_queue (FIFO policy) vector = vectors_queue.popleft() # if the number of non zero indexes of vector is equal to the number of its ancestors, build the intersection of its ancestor cores number_of_non_zero_indexes = len( [index for index in vector if index > 0]) number_of_ancestors = len(ancestors[vector]) if number_of_non_zero_indexes == number_of_ancestors: ancestors_intersection = build_ancestors_intersection( ancestors[vector], cores, descendants_count, distinct_flag, multilayer_graph=multilayer_graph) # if the intersection of its ancestor cores is not empty if len(ancestors_intersection) > 0: # compute the core from it k_core = core(multilayer_graph, vector, ancestors_intersection) number_of_computed_cores += 1 # otherwise else: # delete its entry from ancestors and continue del ancestors[vector] continue # if the core is not empty if len(k_core) > 0: # add the core to the dict of cores and increment the number of cores cores[vector] = k_core number_of_cores += 1 if print_file is not None and not distinct_flag: print_file.print_core(vector, k_core) # compute its descendant vectors for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(vector, index) try: # update the list of the ancestors of the descendant vector ancestors[descendant_vector].append(vector) # if the descendant vector has not already been found except KeyError: # add the descendant vector to the queue vectors_queue.append(descendant_vector) ancestors[descendant_vector] = [vector] # increment descendants_count descendants_count[vector] += 1 else: # for each ancestor of vector for ancestor in ancestors[vector]: # decrement its number of descendants decrement_descendants_count(ancestor, cores, descendants_count, distinct_flag) # delete vector's entry from ancestors del ancestors[vector] # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, number_of_cores, number_of_computed_cores) # execute the post processing post_processing(cores, distinct_flag, print_file)
def naive_maximal(temporal_graph, print_file): # start of the algorithm execution_time = ExecutionTime() processed_nodes = 0 # cores cores = {} maximal_cores = {} # initialize the queue of intervals intervals_queue = deque() # initialize the dict of ancestors ancestors = {} # add each singleton interval to the queue for timestamp in temporal_graph.timestamps_iterator: intervals_queue.append(get_interval(timestamp)) # dict counting the number of descendants in the queue descendants_count = {} # while the queue is not empty while len(intervals_queue) > 0: # remove an interval from the queue interval = intervals_queue.popleft() # get the nodes from which start the computation nodes = get_ancestors_intersection(interval, ancestors, cores, temporal_graph, descendants_count) # if nodes is not empty if len(nodes) > 0: # store the results of the subroutine to interval_cores processed_nodes += len(nodes) interval_cores = subroutine(temporal_graph, nodes, interval, in_memory=True) # if there are cores in the interval if len(interval_cores[0]) > 0: # store the first to cores cores[interval] = {1: interval_cores[0][1]} # add its descendant intervals to the queue add_descendants_to_queue(interval, temporal_graph, intervals_queue, ancestors, descendants_count) # add the maximal core to maximal maximal_cores[interval] = ( interval_cores[1], interval_cores[0][interval_cores[1]]) # delete the maximal cores of the ancestor intervals if needed try: for ancestor_interval in ancestors[interval]: if ancestor_interval in maximal_cores and maximal_cores[ ancestor_interval][0] == interval_cores[1]: maximal_cores.pop(ancestor_interval) except KeyError: pass else: cores[interval] = interval_cores[0] # print the output file if print_file is not None: print_file.print_maximal_cores(maximal_cores) # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, len(maximal_cores), processed_nodes)
def breadth_first_community_search(multilayer_graph, query_nodes, beta): # measures number_of_computed_cores = 0 # start of the algorithm execution_time = ExecutionTime() # create the vector of zeros from which start the computation start_vector = tuple([0] * multilayer_graph.number_of_layers) # dict of cores cores = {} # solution initialized with the whole input graph community_search_density = 0.0 community_search_nodes = array('i', multilayer_graph.get_nodes()) community_search_layers = set(multilayer_graph.layers_iterator) community_search_vector = start_vector # initialize the queue of vectors with the descendants of start_vector and the structure that for each vector saves its ancestor vectors vectors_queue = deque() ancestors = {} for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(start_vector, index) vectors_queue.append(descendant_vector) ancestors[descendant_vector] = [start_vector] # initialize the dictionary that for each vector counts the number of descendants in the queue descendants_count = defaultdict(int) # while vectors_queue is not empty while len(vectors_queue) > 0: # remove a vector from vectors_queue (FIFO policy) vector = vectors_queue.popleft() # if the number of non zero indexes of vector is equal to the number of its ancestors, build the intersection of its ancestor cores number_of_non_zero_indexes = len( [index for index in vector if index > 0]) number_of_ancestors = len(ancestors[vector]) if number_of_non_zero_indexes == number_of_ancestors: ancestors_intersection = build_ancestors_intersection( ancestors[vector], cores, descendants_count, False, multilayer_graph=multilayer_graph) # if the intersection of its ancestor contains the query nodes if query_nodes <= ancestors_intersection: # compute the core from it k_core = core(multilayer_graph, vector, ancestors_intersection) number_of_computed_cores += 1 # otherwise else: # delete its entry from ancestors and continue del ancestors[vector] continue # if the core contains the query nodes if query_nodes <= set(k_core): # add the core to the dict of cores cores[vector] = k_core # update the community search solution if needed core_density, core_layers = objective_function(vector, beta) if core_density >= community_search_density: community_search_density = core_density community_search_nodes = k_core community_search_layers = core_layers community_search_vector = vector # compute its descendant vectors for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(vector, index) try: # update the list of the ancestors of the descendant vector ancestors[descendant_vector].append(vector) # if the descendant vector has not already been found except KeyError: # add the descendant vector to the queue vectors_queue.append(descendant_vector) ancestors[descendant_vector] = [vector] # increment descendants_count descendants_count[vector] += 1 else: # for each ancestor of vector for ancestor in ancestors[vector]: # decrement its number of descendants decrement_descendants_count(ancestor, cores, descendants_count, False) # delete vector's entry from ancestors del ancestors[vector] # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm_community_search(execution_time.execution_time_seconds, number_of_computed_cores) print_community_search(query_nodes, beta, community_search_density, community_search_nodes, community_search_layers, community_search_vector)
# for each line for line in cores_file: # remove the \n from the line line = line.replace('\n', '') # split the line split_line = line.split('\t') vector = literal_eval(split_line[0]) nodes = array('i', map(int, split_line[2].strip().split(', '))) # add the core cores[vector] = nodes # filter distinct cores filter_distinct_cores(cores) # print cores to file for vector, nodes in cores.iteritems(): sorted_nodes = list(nodes) sorted_nodes.sort() distinct_cores_file.write( str(vector) + '\t' + str(len(nodes)) + '\t' + str(sorted_nodes).replace('[', '').replace(']', '') + '\n') # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, len(cores), None)
def depth_first_community_search(multilayer_graph, query_nodes, beta): # measures number_of_computed_cores = 0 # start of the algorithm execution_time = ExecutionTime() # create the vector of zeros from which start the computation start_vector = tuple([0] * multilayer_graph.number_of_layers) # solution initialized with the whole input graph community_search_density = 0.0 community_search_nodes = array('i', multilayer_graph.get_nodes()) community_search_layers = set(multilayer_graph.layers_iterator) community_search_vector = start_vector # initialize the set of layers layers = set(multilayer_graph.layers_iterator) # initialize the base of layers base_layers = set(layers) # initialize the base of cores base_cores = {start_vector: array('i', multilayer_graph.nodes_iterator)} # set of the vectors corresponding to the computed cores computed_core_vectors = set() computed_core_vectors.add(start_vector) # for each layer while len(base_layers) > 0: # delete a layer from base_layers base_layers.pop() # set of the temporary base of cores temp_base_cores = {} # for each core in the base for vector, nodes in base_cores.iteritems(): # for each layer in the base for base_layer in base_layers: # compute its core decomposition and store it in temp_base_cores if vector[base_layer] == 0: new_cores, new_cores_order = core_decomposition( multilayer_graph, vector, base_layer, nodes, query_nodes=query_nodes) temp_base_cores.update(new_cores) number_of_computed_cores += len(new_cores) + 1 # update the community search solution if needed try: core_density, core_layers = objective_function( new_cores_order[-1], beta) if core_density >= community_search_density and [ 1 if i > j else -1 if i < j else 0 for i, j in zip(new_cores_order[-1], community_search_vector) ].count(1) > 0: community_search_density = core_density community_search_nodes = new_cores[ new_cores_order[-1]] community_search_layers = core_layers community_search_vector = new_cores_order[-1] except IndexError: pass # add the new cores to computed_core_vectors computed_core_vectors |= set(new_cores) # for each layer not in base_layers for layer in layers - base_layers: # compute its core decomposition if vector[layer] == 0: new_cores, new_cores_order = core_decomposition( multilayer_graph, vector, layer, nodes, query_nodes=query_nodes) number_of_computed_cores += len(new_cores) + 1 # update the community search solution if needed try: core_density, core_layers = objective_function( new_cores_order[-1], beta) if core_density >= community_search_density and [ 1 if i > j else -1 if i < j else 0 for i, j in zip(new_cores_order[-1], community_search_vector) ].count(1) > 0: community_search_density = core_density community_search_nodes = new_cores[ new_cores_order[-1]] community_search_layers = core_layers community_search_vector = new_cores_order[-1] except IndexError: pass # add the new cores to computed_core_vectors computed_core_vectors |= set(new_cores) # remove every node from the processed core to save memory base_cores[vector] = array('i') # update the base base_cores = temp_base_cores # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm_community_search(execution_time.execution_time_seconds, number_of_computed_cores) print_community_search(query_nodes, beta, community_search_density, community_search_nodes, community_search_layers, community_search_vector)
def densest_subgraph(multilayer_graph, beta): # start of the algorithm execution_time = ExecutionTime() # create the vector of zeros from which start the computation start_vector = tuple([0] * multilayer_graph.number_of_layers) # dict of cores cores = {} # solution initialized with the objective function of the whole input graph densest_subgraph = array('i', multilayer_graph.get_nodes()) maximum_density, maximum_layers, maximum_average_degrees = objective_function( multilayer_graph.number_of_nodes, multilayer_graph.get_number_of_edges_layer_by_layer(), beta) densest_subgraph_vector = start_vector # initialize the queue of vectors with the descendants of start_vector and the structure that for each vector saves its ancestor vectors vectors_queue = deque() ancestors = {} for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(start_vector, index) vectors_queue.append(descendant_vector) ancestors[descendant_vector] = [start_vector] # initialize the dictionary that for each vector counts the number of descendants in the queue descendants_count = defaultdict(int) # while vectors_queue is not empty while len(vectors_queue) > 0: # remove a vector from vectors_queue (FIFO policy) vector = vectors_queue.popleft() # if the number of non zero indexes of vector is equal to the number of its ancestors, build the intersection of its ancestor cores number_of_non_zero_indexes = len( [index for index in vector if index > 0]) number_of_ancestors = len(ancestors[vector]) if number_of_non_zero_indexes == number_of_ancestors: ancestors_intersection = build_ancestors_intersection( ancestors[vector], cores, descendants_count, False, multilayer_graph=multilayer_graph) # if the intersection of its ancestor cores is not empty if len(ancestors_intersection) > 0: # compute the core from it core_result = core(multilayer_graph, beta, vector, ancestors_intersection) k_core = core_result[0] # otherwise else: # delete its entry from ancestors and continue del ancestors[vector] continue # if the core is not empty if len(k_core) > 0: # add the core to the dict of cores and increment the number of cores cores[vector] = k_core # update the densest subgraph if needed current_objective_function = core_result[1] if current_objective_function[0] >= maximum_density: densest_subgraph = k_core maximum_density = current_objective_function[0] maximum_layers = current_objective_function[1] maximum_average_degrees = current_objective_function[2] densest_subgraph_vector = vector # compute its descendant vectors for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(vector, index) try: # update the list of the ancestors of the descendant vector ancestors[descendant_vector].append(vector) # if the descendant vector has not already been found except KeyError: # add the descendant vector to the queue vectors_queue.append(descendant_vector) ancestors[descendant_vector] = [vector] # increment descendants_count descendants_count[vector] += 1 else: # for each ancestor of vector for ancestor in ancestors[vector]: # decrement its number of descendants decrement_descendants_count(ancestor, cores, descendants_count, False) # delete vector's entry from ancestors del ancestors[vector] # end of the algorithm execution_time.end_algorithm() # print the densest subgraph print_densest_subgraph(beta, maximum_density, densest_subgraph, maximum_layers, densest_subgraph_vector, maximum_average_degrees)
def depth_first(multilayer_graph, print_file, distinct_flag): # measures number_of_computed_cores = 0 # start of the algorithm execution_time = ExecutionTime() # create the vector of zeros from which start the computation start_vector = tuple([0] * multilayer_graph.number_of_layers) # dict of cores cores = {} # core [0] if print_file is not None and not distinct_flag: print_file.print_core(start_vector, array('i', multilayer_graph.get_nodes())) elif distinct_flag: cores[start_vector] = array('i', multilayer_graph.get_nodes()) # initialize the set of layers layers = set(multilayer_graph.layers_iterator) # initialize the base of layers base_layers = set(layers) # initialize the base of cores base_cores = {start_vector: array('i', multilayer_graph.nodes_iterator)} # set of the vectors corresponding to the computed cores computed_core_vectors = set() computed_core_vectors.add(start_vector) # for each layer while len(base_layers) > 0: # delete a layer from base_layers base_layers.pop() # set of the temporary base of cores temp_base_cores = {} # for each core in the base for vector, nodes in base_cores.iteritems(): # for each layer in the base for base_layer in base_layers: # compute its core decomposition and store it in temp_base_cores if vector[base_layer] == 0: new_cores, _ = core_decomposition(multilayer_graph, vector, base_layer, nodes) temp_base_cores.update(new_cores) number_of_computed_cores += len(new_cores) + 1 new_cores_set = set(new_cores) if print_file is not None and not distinct_flag: for new_core in new_cores_set - computed_core_vectors: print_file.print_core(new_core, new_cores[new_core]) elif distinct_flag: for new_core in new_cores_set - computed_core_vectors: cores[new_core] = new_cores[new_core] # add the new cores to computed_core_vectors computed_core_vectors |= new_cores_set # for each layer not in base_layers for layer in layers - base_layers: # compute its core decomposition if vector[layer] == 0: new_cores, _ = core_decomposition(multilayer_graph, vector, layer, nodes) number_of_computed_cores += len(new_cores) + 1 new_cores_set = set(new_cores) if print_file is not None and not distinct_flag: for new_core in new_cores_set - computed_core_vectors: print_file.print_core(new_core, new_cores[new_core]) elif distinct_flag: for new_core in new_cores_set - computed_core_vectors: cores[new_core] = new_cores[new_core] # add the new cores to computed_core_vectors computed_core_vectors |= new_cores_set # remove every node from the processed core to save memory base_cores[vector] = array('i') # update the base base_cores = temp_base_cores # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, len(computed_core_vectors), number_of_computed_cores) # execute the post processing post_processing(cores, distinct_flag, print_file)
def naive(multilayer_graph, print_file, distinct_flag): # measures number_of_cores = 0 number_of_computed_cores = 0 # start of the algorithm execution_time = ExecutionTime() # create the vector of zeros from which start the computation start_vector = tuple([0] * multilayer_graph.number_of_layers) # dict of cores cores = {} # core [0] if print_file is not None and not distinct_flag: print_file.print_core(start_vector, array('i', multilayer_graph.get_nodes())) elif distinct_flag: cores[start_vector] = array('i', multilayer_graph.get_nodes()) number_of_cores += 1 # initialize the queue of vectors with the descendants of start_vector vectors_queue = deque() computed_vectors = set() for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(start_vector, index) vectors_queue.append(descendant_vector) computed_vectors.add(descendant_vector) # set of the nodes of the input graph nodes = set(multilayer_graph.nodes_iterator) # while vectors_queue is not empty while len(vectors_queue) > 0: # remove a vector from vectors_queue (FIFO policy) vector = vectors_queue.popleft() # compute the corresponding core k_core = core(multilayer_graph, vector, nodes) number_of_computed_cores += 1 # if the core is not empty if len(k_core) > 0: # add the core to the dict of cores and increment the number of cores if print_file is not None and not distinct_flag: print_file.print_core(vector, k_core) elif distinct_flag: cores[vector] = k_core number_of_cores += 1 # compute its descendant vectors for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(vector, index) # if the descendant vector has not already been added to the queue if descendant_vector not in computed_vectors: # add the descendant vector to the queue vectors_queue.append(descendant_vector) computed_vectors.add(descendant_vector) # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, number_of_cores, number_of_computed_cores) # execute the post processing post_processing(cores, distinct_flag, print_file)
def greedy_degree_removal(signed_graph, signed_degree=True): # start of the algorithm execution_time = ExecutionTime() # initialize the solution with all nodes solution = set(signed_graph.nodes_iterator) solution_x = build_x(signed_graph, solution) solution_objective_function = evaluate_objective_function( signed_graph, solution_x) # compute the degree of each node and divide them in sets degree = {} degree_sets = sorteddict() for node, neighbors in enumerate(signed_graph.adjacency_list): degree[node] = len(neighbors[0]) if signed_degree: degree[node] -= len(neighbors[1]) try: degree_sets[degree[node]].add(node) except KeyError: degree_sets[degree[node]] = {node} # pick a lowest degree node nodes = solution.copy() x = solution_x.copy() while len(degree_sets) > 0: lowest_degree = degree_sets.keys()[0] while len(degree_sets[lowest_degree]) > 0: node = degree_sets[lowest_degree].pop() # update the degree of its neighbors for neighbor in signed_graph.adjacency_list[node][0]: if neighbor in nodes: degree_sets[degree[neighbor]].remove(neighbor) degree[neighbor] -= 1 try: degree_sets[degree[neighbor]].add(neighbor) except KeyError: degree_sets[degree[neighbor]] = {neighbor} if degree[neighbor] < lowest_degree: lowest_degree = degree[neighbor] if signed_degree: for neighbor in signed_graph.adjacency_list[node][1]: if neighbor in nodes: degree_sets[degree[neighbor]].remove(neighbor) degree[neighbor] += 1 try: degree_sets[degree[neighbor]].add(neighbor) except KeyError: degree_sets[degree[neighbor]] = {neighbor} # remove the node from the current set of nodes nodes.remove(node) # update the solution if needed x[node] = 0 objective_function = evaluate_objective_function(signed_graph, x) if objective_function > solution_objective_function: solution = nodes.copy() solution_x = x.copy() solution_objective_function = objective_function # remove the empty set from the dict del degree_sets[lowest_degree] # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, solution_x, signed_graph) # return the solution return solution, solution_x
def local_search(signed_graph, maximum_changes, convergence_threshold, partial_solution='r'): # start of the algorithm execution_time = ExecutionTime() # solution and value of the objective function if partial_solution == 'b': solution, _, original_x = bansal(signed_graph, verbose=False) else: solution = random_solution(signed_graph) original_x = build_x(signed_graph, set(signed_graph.nodes_iterator)) solution_x = build_x(signed_graph, solution, eigenvector=original_x) solution_objective_function = evaluate_objective_function( signed_graph, solution_x) # while there might be improvements to the solution improvable = True changes = 0 while improvable and (maximum_changes is None or changes < maximum_changes): # find the node of highest gain best_node = None best_gain = .0 # move each node in or out the solution for node in signed_graph.nodes_iterator: if node in solution: solution.remove(node) solution_x[node] = 0 objective_function = evaluate_objective_function( signed_graph, solution_x) solution.add(node) solution_x[node] = original_x[node] else: solution.add(node) solution_x[node] = original_x[node] objective_function = evaluate_objective_function( signed_graph, solution_x) solution.remove(node) solution_x[node] = 0 # update the node of highest gain gain = objective_function - solution_objective_function if gain > best_gain: best_node = node best_gain = gain # update the solution if there is a considerable gain if best_gain >= convergence_threshold: if best_node in solution: solution.remove(best_node) solution_x[best_node] = 0 else: solution.add(best_node) solution_x[best_node] = original_x[best_node] solution_objective_function = evaluate_objective_function( signed_graph, solution_x) changes += 1 else: # stop the algorithm otherwise improvable = False # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm(execution_time.execution_time_seconds, solution_x, signed_graph) # return the solution return solution, solution_x
def hybrid_community_search(multilayer_graph, query_nodes, beta): # measures number_of_computed_cores = 0 # start of the algorithm execution_time = ExecutionTime() # create the vector of zeros from which start the computation start_vector = tuple([0] * multilayer_graph.number_of_layers) # dict of cores cores = {} # solution initialized with the whole input graph community_search_density = 0.0 community_search_nodes = array('i', multilayer_graph.get_nodes()) community_search_layers = set(multilayer_graph.layers_iterator) community_search_vector = start_vector # initialize the queue of vectors with the descendants of start_vector and the structure that for each vector saves its ancestor vectors vectors_queue = deque() ancestors = {} for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(start_vector, index) vectors_queue.append(descendant_vector) ancestors[descendant_vector] = [start_vector] # initialize the dictionary that for each vector counts the number of descendants in the queue descendants_count = defaultdict(int) # compute the core decomposition layer by layer for layer in multilayer_graph.layers_iterator: layer_cores, layer_cores_order = pure_core_decomposition(multilayer_graph, start_vector, layer, query_nodes=query_nodes) cores.update(layer_cores) # update the community search solution if needed try: core_density, core_layers = objective_function(layer_cores_order[-1], beta) if core_density >= community_search_density: community_search_density = core_density community_search_nodes = layer_cores[layer_cores_order[-1]] community_search_layers = core_layers community_search_vector = layer_cores_order[-1] except IndexError: pass number_of_computed_cores += len(cores) + multilayer_graph.number_of_layers # while vectors_queue is not empty while len(vectors_queue) > 0: # remove a vector from vectors_queue (FIFO policy) vector = vectors_queue.popleft() # if the number of non zero indexes of vector is equal to the number of its ancestors and is more than 1, build the intersection of its ancestor cores number_of_non_zero_indexes = len([index for index in vector if index > 0]) number_of_ancestors = len(ancestors[vector]) if number_of_non_zero_indexes == number_of_ancestors and number_of_non_zero_indexes > 1 and vector not in cores: ancestors_intersection = build_ancestors_intersection(ancestors[vector], cores, descendants_count, False) # if the intersection of its ancestor contains the query nodes if query_nodes <= set(ancestors_intersection): # compute the core from it k_core, minimum_degrees_vector = core(multilayer_graph, vector, ancestors_intersection, algorithm='h') number_of_computed_cores += 1 # if the core contains the query nodes if query_nodes <= set(k_core): # add the core to the dict of cores cores[vector] = k_core # if the vector of the minimum degrees is not equal to vector if minimum_degrees_vector != vector: # fill the cores that are equals bottom_up_visit(multilayer_graph, minimum_degrees_vector, vector, cores, None, False) # update the community search solution if needed core_density, core_layers = objective_function(minimum_degrees_vector, beta) if core_density >= community_search_density: community_search_density = core_density community_search_nodes = k_core community_search_layers = core_layers community_search_vector = minimum_degrees_vector else: # for each ancestor of vector for ancestor in ancestors[vector]: # decrement its number of descendants decrement_descendants_count(ancestor, cores, descendants_count, False) # if the core corresponding to the vector is in the dict of cores if vector in cores: # compute its descendant vectors for index in multilayer_graph.layers_iterator: descendant_vector = build_descendant_vector(vector, index) try: # update the list of the ancestors of the descendant vector ancestors[descendant_vector].append(vector) # if the descendant vector has not already been found except KeyError: # add the descendant vector to the queue vectors_queue.append(descendant_vector) ancestors[descendant_vector] = [vector] # increment descendants_count descendants_count[vector] += 1 # delete vector's entry from ancestors del ancestors[vector] # end of the algorithm execution_time.end_algorithm() # print algorithm's results print_end_algorithm_community_search(execution_time.execution_time_seconds, number_of_computed_cores) print_community_search(query_nodes, beta, community_search_density, community_search_nodes, community_search_layers, community_search_vector)