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 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)
# 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 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 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 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 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