def vertex_branching(graph: nx.Graph, budget: int): #print("in branching start:", graph.number_of_nodes(), graph.number_of_edges(), "budget", budget, file=sys.stderr) flag, graph, vc, folded_verts = reduction.rrhandler(graph, budget) #print("in branching vc:", vc, "fold_verts:", folded_verts, "new graph", graph.number_of_nodes(), file=sys.stderr) if not flag: # NO instance return False, set() budget -= len(vc) + len(folded_verts) num_edges = graph.number_of_edges() if budget < 0: return False, set() if budget <= 0 and num_edges > 0: return False, set() elif num_edges == 0: return True, utils.unfold(vc, folded_verts) else: # budget > 0 and num_edges > 0 cur_node, max_degree = max(graph.degree_iter(), key=itemgetter(1)) # print("branching on vertex ", cur_node, "of degree", max_degree, file=sys.stderr) nbrs = set(graph.neighbors_iter(cur_node)) flip = random.random() < 0.5 # flip coin to decide branch order if flip: branches = [(nbrs, len(nbrs)), (set(), 1)] else: branches = [(set(), 1), (nbrs, len(nbrs))] nodes = set(graph.nodes_iter()) for branch, budget_change in branches: if budget_change > budget: continue res, vc_new = vertex_branching( graph.subgraph(nodes - {cur_node} - branch), budget - budget_change) if res: final_vc = vc | vc_new | (branch or {cur_node}) return True, utils.unfold(final_vc, folded_verts) return False, set()
def degreeone(graph: nx.Graph, k: int = -1): """ Degree 1 vertices (RR2) :param graph: graph to reduce :param k: parameter k :return: 4-tuple (flag, changed, new_graph, vc) where flag=false denotes that this is a NO-instance and vice-versa, changed indicates if the reduction rule caused any change, new_graph is the reduced subgraph, vc is the partial vc constructed while applying reduction rules """ deg_one = set() for v, deg in graph.degree_iter(): if deg == 1: deg_one.add(v) if len(deg_one) == 0: # no degree 1 vertices found, so no change return True, False, graph, set() vc = set() to_delete = set() while deg_one: v = deg_one.pop() if v in vc: continue neigh = utils.first(graph.neighbors_iter(v)) to_delete.add(v) vc.add(neigh) if len(vc) > k: # NO-instance return False, False, graph, set() nodes = set(graph.nodes_iter()) new_graph = graph.subgraph(nodes - vc - to_delete) return True, True, new_graph, vc
def __init__(self, graph: nx.Graph): self.graph = graph.copy() self.degrees = [] self.entry_finder = dict() for v, d in graph.degree_iter(): entry = [-d, v] self.degrees.append(entry) self.entry_finder[v] = entry heapq.heapify(self.degrees)
def degree_k(graph: nx.Graph, budget: int): """ Delete high-degree (degre > budget) vertices :param graph: copy of graph to reduce :param budget: parameter k :return: (new_graph, vc) """ vc = set() for v, d in graph.degree_iter(): if d > budget: vc.add(v) graph.remove_nodes_from(vc) return graph, vc
def degreedel(graph: nx.Graph, k: int): """ Degree 0 and degree greater than k vertices (RR1) :param graph: graph to reduce :param k: parameter k :return: 4-tuple (flag, changed, new_graph, vc) where flag=false denotes that this is a NO-instance and vice-versa, changed indicates if the reduction rule caused any change, new_graph is the reduced subgraph, vc is the partial vc constructed while applying reduction rules """ n = graph.number_of_nodes() # print('n:', n) # print('V',v) degree_dir = graph.degree_iter() # print('degree_dir', degree_dir) to_delete = set() # delete degree 0 vc = set() # add degree>k to vc for v, deg in degree_dir: if deg == 0: to_delete.add(v) if deg > k: vc.add(v) # handling high degree vertices len_vc = len(vc) #graph.remove_nodes_from(deg_large) if len_vc > k: # more than k high-degree => NO-instance return False, False, graph, set() # print('VC-del:', vc) # repeatedly applying reduction rules if len_vc + len(to_delete) == 0: # no improvement in this case return True, False, graph, vc else: nodes = set(graph.nodes_iter()) new_graph = graph.subgraph(nodes - vc - to_delete) #graph_new, vc_small, k, flag = degreedel(graph, k) # print('vc_small, vc_new', vc_small, vc_new) #c = vc.union(vc_small) # print('c', c) #graph = graph_new return True, True, new_graph, vc
def degree_hist(graph: nx.Graph): hist = {} for v, d in graph.degree_iter(): hist[d] = hist.get(d, 0) + 1 return hist
from os import path import numpy as np from networkx import Graph, transitivity, clustering, average_shortest_path_length, connected_component_subgraphs from networkx.readwrite import json_graph if __name__ == '__main__': with open(sys.argv[1]) as g_file: data = json.load(g_file) g = Graph(json_graph.node_link_graph(data)) print('Number of nodes:', g.number_of_nodes()) print('Average degree:', 2 * g.number_of_edges()/g.number_of_nodes()) print('Transitivity:', transitivity(g)) cc = clustering(g) print('Average clustering coefficient:', np.mean(list(cc.values()))) for subgraph in connected_component_subgraphs(g): if subgraph.number_of_nodes() > 1: print('Average shortest path length for subgraph of', subgraph.number_of_nodes(), ':', average_shortest_path_length(subgraph)) # Calculating average clustering coefficient for different degrees degree_cc = {} for node, degree in g.degree_iter(): if degree not in degree_cc: degree_cc[degree] = [] degree_cc[degree].append(cc[node]) with open(path.join(path.dirname(sys.argv[1]), 'clustering.csv'), 'w', newline='') as cc_file: writer = csv.DictWriter(cc_file, ['degree', 'average_cc']) writer.writeheader() for degree in degree_cc: writer.writerow({'degree': degree, 'average_cc': np.mean(degree_cc[degree])})
def get_degree_heap(graph: nx.Graph): degrees = [(-d, v) for (v, d) in graph.degree_iter()] heapq.heapify(degrees) return degrees