def is_k_edge_connected(G, k): """ Tests to see if a graph is k-edge-connected See Also -------- is_locally_k_edge_connected Example ------- >>> G = nx.barbell_graph(10, 0) >>> is_k_edge_connected(G, k=1) True >>> is_k_edge_connected(G, k=2) False """ if k < 1: raise ValueError('k must be positive, not {}'.format(k)) # First try to quickly determine if G is not k-edge-connected if G.number_of_nodes() < k + 1: return False elif any(d < k for n, d in G.degree()): return False else: # Otherwise perform the full check if k == 1: return nx.is_connected(G) elif k == 2: return not nx.has_bridges(G) else: # return nx.edge_connectivity(G, cutoff=k) >= k return nx.edge_connectivity(G) >= k
def is_k_edge_connected(G, k): """Tests to see if a graph is k-edge-connected. Is it impossible to disconnect the graph by removing fewer than k edges? If so, then G is k-edge-connected. Parameters ---------- G : NetworkX graph An undirected graph. k : integer edge connectivity to test for Returns ------- boolean True if G is k-edge-connected. See Also -------- :func:`is_locally_k_edge_connected` Example ------- >>> G = nx.barbell_graph(10, 0) >>> nx.is_k_edge_connected(G, k=1) True >>> nx.is_k_edge_connected(G, k=2) False """ if k < 1: raise ValueError('k must be positive, not {}'.format(k)) # First try to quickly determine if G is not k-edge-connected if G.number_of_nodes() < k + 1: return False elif any(d < k for n, d in G.degree()): return False else: # Otherwise perform the full check if k == 1: return nx.is_connected(G) elif k == 2: return not nx.has_bridges(G) else: return nx.edge_connectivity(G, cutoff=k) >= k
def weighted_bridge_augmentation(G, avail, weight=None): """Finds an approximate min-weight 2-edge-augmentation of G. This is an implementation of the approximation algorithm detailed in [1]_. It chooses a set of edges from avail to add to G that renders it 2-edge-connected if such a subset exists. This is done by finding a minimum spanning arborescence of a specially constructed metagraph. Parameters ---------- G : NetworkX graph An undirected graph. avail : set of 2 or 3 tuples. candidate edges (with optional weights) to choose from weight : string key to use to find weights if avail is a set of 3-tuples where the third item in each tuple is a dictionary. Yields ------ edge : tuple Edges in the subset of avail chosen to bridge augment G. Notes ----- Finding a weighted 2-edge-augmentation is NP-hard. Any edge not in ``avail`` is considered to have a weight of infinity. The approximation factor is 2 if ``G`` is connected and 3 if it is not. Runs in :math:`O(m + n log(n))` time References ---------- .. [1] Khuller, Samir, and Ramakrishna Thurimella. (1993) Approximation algorithms for graph augmentation. http://www.sciencedirect.com/science/article/pii/S0196677483710102 See Also -------- :func:`bridge_augmentation` :func:`k_edge_augmentation` Example ------- >>> G = nx.path_graph((1, 2, 3, 4)) >>> # When the weights are equal, (1, 4) is the best >>> avail = [(1, 4, 1), (1, 3, 1), (2, 4, 1)] >>> sorted(weighted_bridge_augmentation(G, avail)) [(1, 4)] >>> # Giving (1, 4) a high weight makes the two edge solution the best. >>> avail = [(1, 4, 1000), (1, 3, 1), (2, 4, 1)] >>> sorted(weighted_bridge_augmentation(G, avail)) [(1, 3), (2, 4)] >>> #------ >>> G = nx.path_graph((1, 2, 3, 4)) >>> G.add_node(5) >>> avail = [(1, 5, 11), (2, 5, 10), (4, 3, 1), (4, 5, 1)] >>> sorted(weighted_bridge_augmentation(G, avail=avail)) [(1, 5), (4, 5)] >>> avail = [(1, 5, 11), (2, 5, 10), (4, 3, 1), (4, 5, 51)] >>> sorted(weighted_bridge_augmentation(G, avail=avail)) [(1, 5), (2, 5), (4, 5)] """ if weight is None: weight = 'weight' # If input G is not connected the approximation factor increases to 3 if not nx.is_connected(G): H = G.copy() connectors = list(one_edge_augmentation(H, avail=avail, weight=weight)) H.add_edges_from(connectors) for edge in connectors: yield edge else: connectors = [] H = G if len(avail) == 0: if nx.has_bridges(H): raise nx.NetworkXUnfeasible('no augmentation possible') avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=H) # Collapse input into a metagraph. Meta nodes are bridge-ccs bridge_ccs = nx.connectivity.bridge_components(H) C = collapse(H, bridge_ccs) # Use the meta graph to shrink avail to a small feasible subset mapping = C.graph['mapping'] # Choose the minimum weight feasible edge in each group meta_to_wuv = { (mu, mv): (w, uv) for (mu, mv), uv, w in _lightest_meta_edges(mapping, avail_uv, avail_w) } # Mapping of terms from (Khuller and Thurimella): # C : G_0 = (V, E^0) # This is the metagraph where each node is a 2-edge-cc in G. # The edges in C represent bridges in the original graph. # (mu, mv) : E - E^0 # they group both avail and given edges in E # T : \Gamma # D : G^D = (V, E_D) # The paper uses ancestor because children point to parents, which is # contrary to networkx standards. So, we actually need to run # nx.least_common_ancestor on the reversed Tree. # Pick an arbitrary leaf from C as the root root = next(n for n in C.nodes() if C.degree(n) == 1) # Root C into a tree TR by directing all edges away from the root # Note in their paper T directs edges towards the root TR = nx.dfs_tree(C, root) # Add to D the directed edges of T and set their weight to zero # This indicates that it costs nothing to use edges that were given. D = nx.reverse(TR).copy() nx.set_edge_attributes(D, name='weight', values=0) # The LCA of mu and mv in T is the shared ancestor of mu and mv that is # located farthest from the root. lca_gen = nx.tree_all_pairs_lowest_common_ancestor( TR, root=root, pairs=meta_to_wuv.keys()) for (mu, mv), lca in lca_gen: w, uv = meta_to_wuv[(mu, mv)] if lca == mu: # If u is an ancestor of v in TR, then add edge u->v to D D.add_edge(lca, mv, weight=w, generator=uv) elif lca == mv: # If v is an ancestor of u in TR, then add edge v->u to D D.add_edge(lca, mu, weight=w, generator=uv) else: # If neither u nor v is a ancestor of the other in TR # let t = lca(TR, u, v) and add edges t->u and t->v # Track the original edge that GENERATED these edges. D.add_edge(lca, mu, weight=w, generator=uv) D.add_edge(lca, mv, weight=w, generator=uv) # Then compute a minimum rooted branching try: # Note the original edges must be directed towards to root for the # branching to give us a bridge-augmentation. A = _minimum_rooted_branching(D, root) except nx.NetworkXException: # If there is no branching then augmentation is not possible raise nx.NetworkXUnfeasible('no 2-edge-augmentation possible') # For each edge e, in the branching that did not belong to the directed # tree T, add the correponding edge that **GENERATED** it (this is not # necesarilly e itself!) # ensure the third case does not generate edges twice bridge_connectors = set() for mu, mv in A.edges(): data = D.get_edge_data(mu, mv) if 'generator' in data: # Add the avail edge that generated the branching edge. edge = data['generator'] bridge_connectors.add(edge) for edge in bridge_connectors: yield edge
def edgeConnectivity(G, layout): graphs = list() figures = list() graphData, bridges, articulationPoints = list(), list(), list() sortedEdges = sorted(dict(G.edges), key=lambda g: g[0]) graphData.append('') graphData.append(nx.is_connected(G)) if nx.has_bridges(G): graphData.append(nx.has_bridges(G)) bridges.extend(nx.bridges(G)) graphData.append(bridges) articulationPoints.extend(nx.articulation_points(G)) graphData.append(articulationPoints) else: graphData.append(nx.has_bridges(G)) graphs.append(graphData) sortedNodes = sorted(dict(G.nodes), key=lambda g: g[0]) nodeColor = list() for n in sortedNodes: if n in list(articulationPoints): nodeColor.append("green") else: nodeColor.append("#1f78b4") edgeColor = list() for e in dict(G.edges): if e in list(bridges): edgeColor.append("#ff8000") else: edgeColor.append("black") figures.append( createFigure(G, layout=layout, sortedNodes=sortedNodes, articulationPoints=articulationPoints, bridges=bridges, nodeColor=nodeColor, edgeColor=edgeColor)) for edge in sortedEdges: graphData, bridges, articulationPoints = list(), list(), list() newG = G.copy() newG.remove_edge(edge[0], edge[1]) graphData.append(edge) graphData.append(nx.is_connected(newG)) if nx.has_bridges(newG): graphData.append(nx.has_bridges(newG)) bridges.extend(nx.bridges(newG)) graphData.append(bridges) articulationPoints.extend(nx.articulation_points(newG)) graphData.append(articulationPoints) else: graphData.append(nx.has_bridges(newG)) graphs.append(graphData) sortedNodes = sorted(dict(G.nodes), key=lambda g: g[0]) nodeColor = list() for n in sortedNodes: if n in list(articulationPoints): nodeColor.append("green") else: nodeColor.append("#1f78b4") edgeColor = list() for e in dict(G.edges): if e == edge: edgeColor.append("red") elif e in list(bridges): edgeColor.append("#ff8000") else: edgeColor.append("black") figures.append( createFigure(G, layout=layout, sortedNodes=sortedNodes, removedEdge=edge, articulationPoints=articulationPoints, bridges=bridges, nodeColor=nodeColor, edgeColor=edgeColor)) return graphs, figures
def kNodeAlgorithm(G, layout): # For k=3 newG = G.copy() articulationPoints = list() newEndpoints = set() graphs, figures, nodes = list(), list(), list() figures.append(createFigure( G, layout=layout, )) graphs.append(G) nodes.append([]) if nx.has_bridges(newG): articulationPoints.extend(nx.articulation_points(G)) for point in nx.articulation_points(G): edges = newG.edges(point) for edge in edges: newEndpoints.add(edge[0] + "'") if edge[1] not in newEndpoints: newG.add_edge(edge[0] + "'", edge[1]) # for point in articulationPoints: # newG.add_edge(point, point + 10) sortedNodes = sorted(dict(newG.nodes), key=lambda g: g[0]) nodeColor = list() for n in sortedNodes: if n in newEndpoints: nodeColor.append("lightblue") elif n in articulationPoints: nodeColor.append("green") else: nodeColor.append("#1f78b4") graphs.append(newG.copy()) nodes.append(list(newEndpoints)) figures.append( createFigure(newG, layout=layout, sortedNodes=sortedNodes, articulationPoints=articulationPoints, nodeColor=nodeColor, kAugmentedNodes=newEndpoints)) """K=3""" criticalNodes = list() for node1 in dict(newG.nodes): loopG = newG.copy() loopG.remove_node(node1) for node2 in dict(loopG.nodes): loopG2 = loopG.copy() loopG2.remove_node(node2) if not nx.is_connected(loopG2): criticalNodes.append((node1, node2)) newG.add_node(node2) newG.add_node(node1) loopG3 = newG.copy() usedNodes = set() for critNode in criticalNodes: edges1 = loopG3.edges(critNode[0]) edges2 = loopG3.edges(critNode[1]) edgeSet = set() for edge in edges1: edgeSet.add(edge) for edge in edges2: edgeSet.add(edge) for edge in edgeSet: if critNode[1] + critNode[0] not in usedNodes: newG.add_edge(critNode[0] + critNode[1], edge[1]) usedNodes.add(critNode[0] + critNode[1]) createFigure(newG, layout=layout) sortedNodes = sorted(dict(newG.nodes), key=lambda g: g[0]) nodeColor = list() for n in sortedNodes: if n in usedNodes: nodeColor.append("lightblue") else: nodeColor.append("#1f78b4") edgeColor = list() usedEdges = list() for e in newG.edges: if e[1] in usedNodes: edgeColor.append("green") usedEdges.append(e) else: edgeColor.append("black") graphs.append(newG) nodes.append(list(usedNodes)) figures.append( createFigure(newG, layout=layout, sortedNodes=sortedNodes, nodeColor=nodeColor, edgeColor=edgeColor, kAugmentedNodes=usedNodes, kAugmentedEdges=usedEdges)) print(graphs, figures) return graphs, figures, nodes
def recursive_algorithmic_play(player_output, cutter_flag=True): ''' this one will check all algorithmically approved moves in the step (according to our playing algorithms) what I need to change is the edges that are recursed into so, remove edges from the thing. also, run the trim function ''' graph = player_output[0] drawn_name = str(hash(graph)) draw(graph, drawn_name) # base case if player_output[1] == 'saver': # draw(graph, 'saver_' + str(hash(graph))) return (drawn_name, []), {'saver_wins': 1, 'cutter_wins': 0} if player_output[1] == 'cutter': # draw(graph, 'cutter_' + str(hash(graph))) return (drawn_name, []), {'saver_wins': 0, 'cutter_wins': 1} trim(graph) # edit the graph in place to remove all extra nodes # recursive step # get all the result dicts in a list results = [] recursive_step = [] if cutter_flag: # cutter move #TODO # get list of edges to try cutting move_list = [] if ('A', 'B') in list(graph.edges()): move_list = [('A', 'B')] elif nx.has_bridges(nx.Graph(graph)): # cut a bridge between A and B # get bridges from a simple graph (not implemented for multi) possible_bridges = list(nx.bridges(nx.Graph(graph))) # remove the ones that are parallel edges and thus not bridges for edge in possible_bridges: if (edge[0], edge[1], 1) not in list(graph.edges): move_list.append((edge[0], edge[1], 0)) elif False: # TODO implement creation of long bridge test pass else: move_list = list(graph.edges) for edge in move_list: recursive_step.append( recursive_algorithmic_play(cut(graph, edge), False)) else: # saver move # get list of edges to try saving # list(graph.edges) is the list of edges in the graph move_list = [] if ('A', 'B') in list(graph.edges()): # winning move for saver move_list = [('A', 'B')] elif nx.has_bridges(nx.Graph(graph)): # save a bridge between A and B # get bridges from a simple graph (not implemented for multi) possible_bridges = list(nx.bridges(nx.Graph(graph))) # remove the ones that are parallel edges for edge in possible_bridges: if (edge[0], edge[1], 1) not in list(graph.edges): move_list.append((edge[0], edge[1], 0)) else: move_list = list(graph.edges) for edge in move_list: # we don't want to remove A or B from the graph when contracting # so we make sure A, then B are at the beginning of the edge if edge[1] == 'B': edge = edge[1], edge[0] if edge[1] == 'A': edge = edge[1], edge[0] recursive_step.append( recursive_algorithmic_play(save(graph, edge), True)) # we currently have recursive_step as a tuple as below # get the results for game winners results = [item[1] for item in recursive_step] # add them together output = {'saver_wins': 0, 'cutter_wins': 0} for result in results: output['saver_wins'] += result['saver_wins'] output['cutter_wins'] += result['cutter_wins'] lower_levels = [item[0] for item in recursive_step] # graph is the current graph's state # lower levels is a list of these tuples return (str(hash(graph)), lower_levels), output
def calculate(graph): return nx.has_bridges(graph)
df, "state1", "state2", ["ratio", "p", "h"], create_using=(nx.DiGraph if valid_comps else nx.Graph)) pos = nx.spring_layout(graph, center=(0.5, 0.5), scale=0.5, k=1 / len(graph)**0.1, seed=1) # pos = nx.kamada_kawai_layout(graph, center=(0.5, 0.5), scale=0.5) # Base edges nx.draw_networkx_edges(graph, pos=pos, width=0.2) # Bridges if type(graph) is not nx.DiGraph and nx.has_bridges(graph): nx.draw_networkx_edges(graph, edgelist=list(nx.bridges(graph)), pos=pos, width=3, alpha=0.5, edge_color="r") # Nodes with colors groups = list(asyn_lpa_communities(graph, weight="h")) colors = [[state in com for com in groups].index(True) for state in graph] nx.draw_networkx_nodes(graph, pos=pos, node_color=colors, cmap="tab20") # Labels nx.draw_networkx_labels(graph, pos, font_size=10)
def Analyze(G): GraphData['Has Bridges?'] = nx.has_bridges(G) addBridges(G) logtoFile()