def copy_attr_from(overlay_src, overlay_dst, src_attr, dst_attr = None, nbunch = None, type = None): #TODO: add dest format, eg to convert to int if not dst_attr: dst_attr = src_attr graph_src = unwrap_graph(overlay_src) graph_dst = unwrap_graph(overlay_dst) if not nbunch: nbunch = graph_src.nodes() for n in nbunch: try: val = graph_src.node[n][src_attr] except KeyError: #TODO: check if because node doesn't exist in dest, or because attribute doesn't exist in graph_src log.debug("Unable to copy node attribute %s for %s in %s" % (src_attr, n, overlay_src)) else: #TODO: use a dtype to take an int, float, etc if type is float: val = float(val) elif type is int: val = int(val) if n in graph_dst: graph_dst.node[n][dst_attr] = val
def neigh_average( NmGraph, node, attribute, attribute_graph=None, ): """ averages out attribute from neighbors in specified NmGraph attribute_graph is the graph to read the attribute from if property is numeric, then return mean else return most frequently occuring value """ graph = unwrap_graph(NmGraph) if attribute_graph: attribute_graph = unwrap_graph(attribute_graph) else: attribute_graph = graph # use input graph node = unwrap_nodes(node) values = [attribute_graph.node[n].get(attribute) for n in graph.neighbors(node)] # TODO: use neigh_attr try: values = [float(val) for val in values] return sum(values) / len(values) except ValueError: return most_frequent(values)
def copy_attr_from(overlay_src, overlay_dst, src_attr, dst_attr = None, nbunch = None, type = None, default = None): #TODO: add dest format, eg to convert to int if not dst_attr: dst_attr = src_attr graph_src = unwrap_graph(overlay_src) graph_dst = unwrap_graph(overlay_dst) if not nbunch: nbunch = graph_src.nodes() for n in nbunch: try: val = graph_src.node[n].get(src_attr, default) except KeyError: #TODO: check if because node doesn't exist in dest, or because attribute doesn't exist in graph_src log.debug("Unable to copy node attribute %s for %s in %s" % (src_attr, n, overlay_src)) else: #TODO: use a dtype to take an int, float, etc if type is float: val = float(val) elif type is int: val = int(val) if n in graph_dst: graph_dst.node[n][dst_attr] = val
def copy_edge_attr_from(overlay_src, overlay_dst, attr): graph_src = unwrap_graph(overlay_src) graph_dst = unwrap_graph(overlay_dst) for src, dst in graph_src.edges(): try: graph_dst[src][dst][attr] = graph_src[src][dst][attr] except KeyError: #TODO: check if because edge doesn't exist in dest, or because attribute doesn't exist in graph_src log.warning("Unable to copy edge attribute %s for (%s, %s) in %s" % (attr, src, dst, overlay_src))
def neigh_most_frequent(OverlayGraph, node, attribute, attribute_graph = None): """Used to explicitly force most frequent - useful if integers such as ASN which would otherwise return mean""" graph = unwrap_graph(OverlayGraph) if attribute_graph: attribute_graph = unwrap_graph(attribute_graph) else: attribute_graph = graph # use input graph node = unwrap_nodes(node) values = [attribute_graph.node[n].get(attribute) for n in graph.neighbors(node)] return most_frequent(values)
def neigh_most_frequent(overlay_graph, node, attribute, attribute_graph = None): """Used to explicitly force most frequent - useful if integers such as ASN which would otherwise return mean""" graph = unwrap_graph(overlay_graph) if attribute_graph: attribute_graph = unwrap_graph(attribute_graph) else: attribute_graph = graph # use input graph node = unwrap_nodes(node) values = [attribute_graph.node[n].get(attribute) for n in graph.neighbors(node)] return most_frequent(values)
def neigh_most_frequent(NmGraph, node, attribute, attribute_graph = None, allow_none = False): """Used to explicitly force most frequent - useful if integers such as ASN which would otherwise return mean""" #TODO: rename to median? graph = unwrap_graph(NmGraph) if attribute_graph: attribute_graph = unwrap_graph(attribute_graph) else: attribute_graph = graph # use input graph node = unwrap_nodes(node) values = [attribute_graph.node[n].get(attribute) for n in graph.neighbors(node)] values = sorted(values) if not allow_none: values = [v for v in values if v is not None] return most_frequent(values)
def neigh_attr(NmGraph, node, attribute, attribute_graph = None): #TODO: tidy up parameters to take attribute_graph first, and then evaluate if attribute_graph set, if not then use attribute_graph as attribute #TODO: explain how NmGraph and attribute_graph work, eg for G_ip and G_phy graph = unwrap_graph(NmGraph) node = unwrap_nodes(node) if attribute_graph: attribute_graph = unwrap_graph(attribute_graph) else: attribute_graph = graph # use input graph #Only look at nodes which exist in attribute_graph neighs = (n for n in graph.neighbors(node)) valid_nodes = (n for n in neighs if n in attribute_graph) return (attribute_graph.node[node].get(attribute) for node in valid_nodes)
def neigh_attr(OverlayGraph, node, attribute, attribute_graph = None): #TODO: tidy up parameters to take attribute_graph first, and then evaluate if attribute_graph set, if not then use attribute_graph as attribute #TODO: explain how OverlayGraph and attribute_graph work, eg for G_ip and G_phy graph = unwrap_graph(OverlayGraph) node = unwrap_nodes(node) if attribute_graph: attribute_graph = unwrap_graph(attribute_graph) else: attribute_graph = graph # use input graph #Only look at nodes which exist in attribute_graph neighs = (n for n in graph.neighbors(node)) valid_nodes = (n for n in neighs if n in attribute_graph) return (attribute_graph.node[node].get(attribute) for node in valid_nodes)
def set_node_default(nm_graph, nbunch=None, **kwargs): """Sets all nodes in nbunch to value if key not already set Note: this won't apply to future nodes added >>> anm = autonetkit.topos.house() >>> g_phy = anm['phy'] >>> r1 = g_phy.node("r1") >>> r1.color = "blue" >>> [(n, n.color) for n in g_phy] [(r4, None), (r5, None), (r1, 'blue'), (r2, None), (r3, None)] >>> set_node_default(g_phy, color="red") >>> [(n, n.color) for n in g_phy] [(r4, 'red'), (r5, 'red'), (r1, 'blue'), (r2, 'red'), (r3, 'red')] Can also set for a specific bunch of nodes >>> nodes = ["r1", "r2", "r3"] >>> set_node_default(g_phy, nodes, role="core") >>> [(n, n.role) for n in g_phy] [(r4, None), (r5, None), (r1, 'core'), (r2, 'core'), (r3, 'core')] """ # work with the underlying NetworkX graph for efficiency graph = unwrap_graph(nm_graph) if nbunch is None: nbunch = graph.nodes() else: nbunch = unwrap_nodes(nbunch) for node in nbunch: for (key, val) in kwargs.items(): if key not in graph.node[node]: graph.node[node][key] = val
def connected_subgraphs(nm_graph, nodes=None): """ >>> anm = autonetkit.topos.house() >>> g_phy = anm['phy'] >>> connected_subgraphs(g_phy) [[r4, r5, r1, r2, r3]] >>> edges = [("r2", "r4"), ("r3", "r5")] >>> g_phy.remove_edges_from(edges) >>> connected_subgraphs(g_phy) [[r1, r2, r3], [r4, r5]] """ if nodes is None: nodes = nm_graph.nodes() else: nodes = list(unwrap_nodes(nodes)) graph = unwrap_graph(nm_graph) subgraph = graph.subgraph(nodes) if not len(subgraph.edges()): # print "Nothing to aggregate for %s: no edges in subgraph" pass if graph.is_directed(): component_nodes_list = nx.strongly_connected_components(subgraph) else: component_nodes_list = nx.connected_components(subgraph) wrapped = [] for component in component_nodes_list: wrapped.append(list(wrap_nodes(nm_graph, component))) return wrapped
def explode_nodes(overlay_graph, nodes, retain=[]): """Explodes all nodes in nodes TODO: explain better """ try: retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(overlay_graph) nodes = unwrap_nodes(nodes) added_edges = [] #TODO: need to keep track of edge_ids here also? nodes = list(nodes) for node in nodes: neighbors = graph.neighbors(node) neigh_edge_pairs = ((s, t) for s in neighbors for t in neighbors if s != t) edges_to_add = [] for (src, dst) in neigh_edge_pairs: data = dict((key, graph[src][dst][key]) for key in retain) edges_to_add.append((src, dst, data)) graph.add_edges_from(edges_to_add) added_edges.append(edges_to_add) graph.remove_node(node) return wrap_edges(overlay_graph, added_edges)
def in_edges(nm_graph, nodes=None): # TODO: make support multigraphs graph = unwrap_graph(nm_graph) edges = graph.in_edges(nodes) return wrap_edges(nm_graph, edges)
def aggregate_nodes(nm_graph, nodes, retain=None): """Combines connected into a single node""" if retain is None: retain = [] try: retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list nodes = list(unwrap_nodes(nodes)) graph = unwrap_graph(nm_graph) subgraph = graph.subgraph(nodes) if not len(subgraph.edges()): # print "Nothing to aggregate for %s: no edges in subgraph" pass total_added_edges = [] if graph.is_directed(): component_nodes_list = nx.strongly_connected_components(subgraph) else: component_nodes_list = nx.connected_components(subgraph) for component_nodes in component_nodes_list: if len(component_nodes) > 1: component_nodes = [nm_graph.node(n) for n in component_nodes] # TODO: could choose most connected, or most central? # TODO: refactor so use nodes_to_remove nodes_to_remove = list(component_nodes) base = nodes_to_remove.pop() # choose a base device to retain log.debug("Retaining %s, removing %s", base, nodes_to_remove) external_edges = [] for node in nodes_to_remove: external_edges += [e for e in node.edges() if e.dst not in component_nodes] # all edges out of component log.debug("External edges %s", external_edges) edges_to_add = [] for edge in external_edges: dst = edge.dst data = dict((key, edge._data.get(key)) for key in retain) ports = edge.raw_interfaces dst_int_id = ports[dst.node_id] # TODO: bind to (and maybe add) port on the new switch? data["_ports"] = {dst.node_id: dst_int_id} append = (base.node_id, dst.node_id, data) edges_to_add.append(append) nm_graph.add_edges_from(edges_to_add) total_added_edges += edges_to_add nm_graph.remove_nodes_from(nodes_to_remove) return wrap_edges(nm_graph, total_added_edges)
def explode_nodes(overlay_graph, nodes, retain = []): """Explodes all nodes in nodes TODO: explain better """ try: retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(overlay_graph) nodes = unwrap_nodes(nodes) added_edges = [] #TODO: need to keep track of edge_ids here also? nodes = list(nodes) for node in nodes: neighbors = graph.neighbors(node) neigh_edge_pairs = ( (s,t) for s in neighbors for t in neighbors if s != t) edges_to_add = [] for (src, dst) in neigh_edge_pairs: data = dict( (key, graph[src][dst][key]) for key in retain) edges_to_add.append((src, dst, data)) graph.add_edges_from(edges_to_add) added_edges.append(edges_to_add) graph.remove_node(node) return wrap_edges(overlay_graph, added_edges)
def split(OverlayGraph, edges, retain = []): try: retain.lower() #TODO: find more efficient operation to test if string-like retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(OverlayGraph) edges = list(unwrap_edges(edges)) edges_to_add = [] added_nodes = [] for (src, dst) in edges: cd_id = "cd_%s_%s" % (src, dst) interfaces = graph[src][dst]["_interfaces"] data = dict( (key, graph[src][dst][key]) for key in retain) #TODO: check how this behaves for directed graphs src_data = data.copy() if src in interfaces: src_int_id = interfaces[src] src_data['_interfaces'] = {src: src_int_id} dst_data = data.copy() if dst in interfaces: dst_int_id = interfaces[dst] dst_data['_interfaces'] = {dst: dst_int_id} edges_to_add.append( (src, cd_id, src_data)) edges_to_add.append( (dst, cd_id, dst_data)) added_nodes.append(cd_id) graph.remove_edges_from(edges) graph.add_edges_from(edges_to_add) return wrap_nodes(OverlayGraph, added_nodes)
def explode_nodes(overlay_graph, nodes, retain = []): """Explodes all nodes in nodes TODO: explain better TODO: Add support for digraph - check if overlay_graph.is_directed() """ log.debug("Exploding nodes") try: retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(overlay_graph) nodes = unwrap_nodes(nodes) added_edges = [] #TODO: need to keep track of edge_ids here also? nodes = list(nodes) for node in nodes: log.debug("Exploding from %s" % node) neighbors = graph.neighbors(node) neigh_edge_pairs = ( (s,t) for s in neighbors for t in neighbors if s != t) edges_to_add = [] for (src, dst) in neigh_edge_pairs: src_to_node_data = dict( (key, graph[src][node][key]) for key in retain) node_to_dst_data = dict( (key, graph[node][dst][key]) for key in retain) src_to_node_data.update(node_to_dst_data) edges_to_add.append((src, dst, src_to_node_data)) graph.add_edges_from(edges_to_add) added_edges.append(edges_to_add) graph.remove_node(node) return wrap_edges(overlay_graph, added_edges)
def copy_attr_from(overlay_src, overlay_dst, src_attr, dst_attr = None, nbunch = None): #TODO: add dest format, eg to convert to int if not dst_attr: dst_attr = src_attr graph_src = unwrap_graph(overlay_src) graph_dst = unwrap_graph(overlay_dst) if not nbunch: nbunch = graph_src.nodes() for n in nbunch: try: graph_dst.node[n][dst_attr] = graph_src.node[n][src_attr] except KeyError: #TODO: check if because node doesn't exist in dest, or because attribute doesn't exist in graph_src log.debug("Unable to copy node attribute %s for %s in %s" % (src_attr, n, overlay_src))
def set_node_default(OverlayGraph, nbunch, **kwargs): """Sets all nodes in nbunch to value if key not already set""" graph = unwrap_graph(OverlayGraph) nbunch = unwrap_nodes(nbunch) for node in nbunch: for key, val in kwargs.items(): if key not in graph.node[node]: graph.node[node][key] = val
def set_node_default(overlay_graph, nbunch, **kwargs): """Sets all nodes in nbunch to value if key not already set""" graph = unwrap_graph(overlay_graph) nbunch = unwrap_nodes(nbunch) for node in nbunch: for key, val in kwargs.items(): if key not in graph.node[node]: graph.node[node][key] = val
def neigh_most_frequent(nm_graph, node, attribute, attribute_graph=None, allow_none=False): """Used to explicitly force most frequent - useful if integers such as ASN which would otherwise return mean""" # TODO: rename to median? graph = unwrap_graph(nm_graph) if attribute_graph: attribute_graph = unwrap_graph(attribute_graph) else: attribute_graph = graph # use input graph node = unwrap_nodes(node) values = [attribute_graph.node[n].get(attribute) for n in graph.neighbors(node)] values = sorted(values) if not allow_none: values = [v for v in values if v is not None] return most_frequent(values)
def copy_edge_attr_from(overlay_src, overlay_dst, src_attr, dst_attr = None, type = None): graph_src = unwrap_graph(overlay_src) graph_dst = unwrap_graph(overlay_dst) if not dst_attr: dst_attr = src_attr for src, dst in graph_src.edges(): try: val = graph_src[src][dst][src_attr] except KeyError: #TODO: check if because edge doesn't exist in dest, or because attribute doesn't exist in graph_src log.debug("Unable to copy edge attribute %s for (%s, %s) in %s" % (src_attr, src, dst, overlay_src)) else: #TODO: use a dtype to take an int, float, etc if type is float: val = float(val) elif type is int: val = int(val) if (src, dst) in graph_dst: graph_dst[src][dst][dst_attr] = val
def set_node_default(NmGraph, nbunch = None, **kwargs): """Sets all nodes in nbunch to value if key not already set Note: this won't apply to future nodes added """ graph = unwrap_graph(NmGraph) if nbunch is None: nbunch = graph.nodes() else: nbunch = unwrap_nodes(nbunch) for node in nbunch: for key, val in kwargs.items(): if key not in graph.node[node]: graph.node[node][key] = val
def shortest_path(nm_graph, src, dst): # TODO: move to utils # TODO: use networkx boundary nodes directly: does the same thing graph = unwrap_graph(nm_graph) src_id = unwrap_nodes(src) dst_id = unwrap_nodes(dst) # TODO: check path works for muli-edge graphs too path = nx.shortest_path(graph, src_id, dst_id) return wrap_nodes(nm_graph, path)
def boundary_nodes(graph, nodes): # TODO: move to utils #TODO: use networkx boundary nodes directly: does the same thing """ returns nodes at boundary of G based on edge_boundary from networkx """ graph = unwrap_graph(graph) nodes = list(nodes) nbunch = list(unwrap_nodes(nodes)) # find boundary b_edges = nx.edge_boundary(graph, nbunch) # boundary edges internal_nodes = [s for (s, t) in b_edges] assert(all(n in nbunch for n in internal_nodes)) # check internal return wrap_nodes(graph, internal_nodes)
def shortest_path(nm_graph, src, dst): # TODO: move to utils # TODO: use networkx boundary nodes directly: does the same thing graph = unwrap_graph(nm_graph) src_id = unwrap_nodes(src) dst_id = unwrap_nodes(dst) #TODO: check path works for muli-edge graphs too path = nx.shortest_path(graph, src_id, dst_id) return wrap_nodes(nm_graph, path)
def set_node_default(NmGraph, nbunch=None, **kwargs): """Sets all nodes in nbunch to value if key not already set Note: this won't apply to future nodes added """ graph = unwrap_graph(NmGraph) if nbunch is None: nbunch = graph.nodes() else: nbunch = unwrap_nodes(nbunch) for node in nbunch: for (key, val) in kwargs.items(): if key not in graph.node[node]: graph.node[node][key] = val
def connected_subgraphs(NmGraph, nodes): nodes = list(unwrap_nodes(nodes)) graph = unwrap_graph(NmGraph) subgraph = graph.subgraph(nodes) if not len(subgraph.edges()): #print "Nothing to aggregate for %s: no edges in subgraph" pass total_added_edges = [] if graph.is_directed(): component_nodes_list = nx.strongly_connected_components(subgraph) else: component_nodes_list = nx.connected_components(subgraph) wrapped = [] for component in component_nodes_list: wrapped.append(list(wrap_nodes(NmGraph, component))) return wrapped
def split(NmGraph, edges, retain = [], id_prepend = ""): try: retain.lower() #TODO: find more efficient operation to test if string-like retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(NmGraph) edges = list(unwrap_edges(edges)) edges_to_add = [] added_nodes = [] for (src, dst) in edges: if graph.is_directed(): new_id = "%s%s_%s" % (id_prepend, src, dst) else: try: if float(src) < float(dst): (node_a, node_b) = (src, dst) # numeric ordering else: (node_a, node_b) = (dst, src) # numeric ordering except ValueError: # not numeric, use string sort (node_a, node_b) = sorted([src, dst]) # use sorted for consistency new_id = "%s%s_%s" % (id_prepend, node_a, node_b) interfaces = graph[src][dst]["_interfaces"] data = dict( (key, graph[src][dst][key]) for key in retain) #TODO: check how this behaves for directed graphs src_data = data.copy() if src in interfaces: src_int_id = interfaces[src] src_data['_interfaces'] = {src: src_int_id} dst_data = data.copy() if dst in interfaces: dst_int_id = interfaces[dst] dst_data['_interfaces'] = {dst: dst_int_id} edges_to_add.append( (src, new_id, src_data)) edges_to_add.append( (dst, new_id, dst_data)) added_nodes.append(new_id) graph.remove_edges_from(edges) graph.add_edges_from(edges_to_add) return wrap_nodes(NmGraph, added_nodes)
def split(OverlayGraph, edges, retain = [], id_prepend = ""): try: retain.lower() #TODO: find more efficient operation to test if string-like retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(OverlayGraph) edges = list(unwrap_edges(edges)) edges_to_add = [] added_nodes = [] for (src, dst) in edges: if graph.is_directed(): new_id = "%s%s_%s" % (id_prepend, src, dst) else: try: if float(src) < float(dst): (node_a, node_b) = (src, dst) # numeric ordering else: (node_a, node_b) = (dst, src) # numeric ordering except ValueError: # not numeric, use string sort (node_a, node_b) = sorted([src, dst]) # use sorted for consistency new_id = "%s%s_%s" % (id_prepend, node_a, node_b) interfaces = graph[src][dst]["_interfaces"] data = dict( (key, graph[src][dst][key]) for key in retain) #TODO: check how this behaves for directed graphs src_data = data.copy() if src in interfaces: src_int_id = interfaces[src] src_data['_interfaces'] = {src: src_int_id} dst_data = data.copy() if dst in interfaces: dst_int_id = interfaces[dst] dst_data['_interfaces'] = {dst: dst_int_id} edges_to_add.append( (src, new_id, src_data)) edges_to_add.append( (dst, new_id, dst_data)) added_nodes.append(new_id) graph.remove_edges_from(edges) graph.add_edges_from(edges_to_add) return wrap_nodes(OverlayGraph, added_nodes)
def aggregate_nodes(overlay_graph, nodes, retain=[]): """Combines connected into a single node""" try: retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list nodes = list(unwrap_nodes(nodes)) graph = unwrap_graph(overlay_graph) subgraph = graph.subgraph(nodes) if not len(subgraph.edges()): #print "Nothing to aggregate for %s: no edges in subgraph" pass total_added_edges = [] for component_nodes in nx.connected_components(subgraph): if len(component_nodes) > 1: base = component_nodes.pop() # choose one base device to retain nodes_to_remove = set( component_nodes ) # remaining nodes, set for fast membership test external_edges = nx.edge_boundary(graph, component_nodes) edges_to_add = [] for src, dst in external_edges: # src is the internal node to remove if src == base or dst == base: continue # don't alter edges from base else: if src in nodes_to_remove: # edge from component to outside data = dict( (key, graph[src][dst][key]) for key in retain) edges_to_add.append((base, dst, data)) else: # edge from outside into component data = dict( (key, graph[dst][src][key]) for key in retain) edges_to_add.append((base, src, data)) graph.add_edges_from(edges_to_add) total_added_edges += edges_to_add graph.remove_nodes_from(nodes_to_remove) return wrap_edges(overlay_graph, total_added_edges)
def explode_nodes(OverlayGraph, nodes, retain = []): """Explodes all nodes in nodes TODO: explain better TODO: Add support for digraph - check if OverlayGraph.is_directed() """ log.debug("Exploding nodes") try: retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(OverlayGraph) nodes = unwrap_nodes(nodes) added_edges = [] #TODO: need to keep track of edge_ids here also? nodes = list(nodes) #TODO: if graph is bidirectional, need to explode here too #TODO: how do we handle explode for multi graphs? for node in nodes: log.debug("Exploding from %s" % node) neighbors = graph.neighbors(node) neigh_edge_pairs = ( (s,t) for s in neighbors for t in neighbors if s != t) neigh_edge_pairs = list(neigh_edge_pairs) edges_to_add = [] for (src, dst) in neigh_edge_pairs: src_to_node_data = dict( (key, graph[src][node][key]) for key in retain) node_to_dst_data = dict( (key, graph[node][dst][key]) for key in retain) # copy interfaces src_int_id = graph[src][node]["_interfaces"][src] dst_int_id = graph[node][dst]["_interfaces"][dst] src_to_node_data["_interfaces"] = {src: src_int_id, dst: dst_int_id} src_to_node_data.update(node_to_dst_data) #TODO: handle interfaces for explode edges_to_add.append((src, dst, src_to_node_data)) graph.add_edges_from(edges_to_add) added_edges += edges_to_add graph.remove_node(node) return wrap_edges(OverlayGraph, added_edges)
def connected_subgraphs(NmGraph, nodes): nodes = list(unwrap_nodes(nodes)) graph = unwrap_graph(NmGraph) subgraph = graph.subgraph(nodes) if not len(subgraph.edges()): # print "Nothing to aggregate for %s: no edges in subgraph" pass if graph.is_directed(): component_nodes_list = \ nx.strongly_connected_components(subgraph) else: component_nodes_list = nx.connected_components(subgraph) wrapped = [] for component in component_nodes_list: wrapped.append(list(wrap_nodes(NmGraph, component))) return wrapped
def split(overlay_graph, edges, retain = []): try: retain.lower() #TODO: find more efficient operation to test if string-like retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(overlay_graph) edges = list(unwrap_edges(edges)) edges_to_add = [] added_nodes = [] for (src, dst) in edges: cd_id = "cd_%s_%s" % (src, dst) data = dict( (key, graph[src][dst][key]) for key in retain) edges_to_add.append( (src, cd_id, data)) edges_to_add.append( (dst, cd_id, data)) added_nodes.append(cd_id) graph.remove_edges_from(edges) graph.add_edges_from(edges_to_add) return wrap_nodes(overlay_graph, added_nodes)
def aggregate_nodes(overlay_graph, nodes, retain = []): """Combines connected into a single node""" try: retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list nodes = list(unwrap_nodes(nodes)) graph = unwrap_graph(overlay_graph) subgraph = graph.subgraph(nodes) if not len(subgraph.edges()): #print "Nothing to aggregate for %s: no edges in subgraph" pass total_added_edges = [] for component_nodes in nx.connected_components(subgraph): if len(component_nodes) > 1: base = component_nodes.pop() # choose one base device to retain nodes_to_remove = set(component_nodes) # remaining nodes, set for fast membership test external_edges = nx.edge_boundary(graph, component_nodes) edges_to_add = [] for src, dst in external_edges: # src is the internal node to remove if src == base or dst == base: continue # don't alter edges from base else: if src in nodes_to_remove: # edge from component to outside data = dict( (key, graph[src][dst][key]) for key in retain) edges_to_add.append((base, dst, data)) else: # edge from outside into component data = dict( (key, graph[dst][src][key]) for key in retain) edges_to_add.append((base, src, data)) graph.add_edges_from(edges_to_add) total_added_edges += edges_to_add graph.remove_nodes_from(nodes_to_remove) return wrap_edges(overlay_graph, total_added_edges)
def split(overlay_graph, edges, retain=[]): try: retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(overlay_graph) edges = list(unwrap_edges(edges)) edges_to_add = [] added_nodes = [] for (src, dst) in edges: cd_id = "cd_%s_%s" % (src, dst) data = dict((key, graph[src][dst][key]) for key in retain) edges_to_add.append((src, cd_id, data)) edges_to_add.append((dst, cd_id, data)) added_nodes.append(cd_id) graph.remove_edges_from(edges) graph.add_edges_from(edges_to_add) return wrap_nodes(overlay_graph, added_nodes)
def connected_subgraphs(nm_graph, nodes = None): """ >>> anm = autonetkit.topos.house() >>> g_phy = anm['phy'] >>> connected_subgraphs(g_phy) [[r4, r5, r1, r2, r3]] >>> edges = [("r2", "r4"), ("r3", "r5")] >>> g_phy.remove_edges_from(edges) >>> connected_subgraphs(g_phy) [[r1, r2, r3], [r4, r5]] """ if nodes is None: nodes = nm_graph.nodes() else: nodes = list(unwrap_nodes(nodes)) graph = unwrap_graph(nm_graph) subgraph = graph.subgraph(nodes) if not len(subgraph.edges()): # print "Nothing to aggregate for %s: no edges in subgraph" pass if graph.is_directed(): component_nodes_list = \ nx.strongly_connected_components(subgraph) else: component_nodes_list = nx.connected_components(subgraph) wrapped = [] for component in component_nodes_list: wrapped.append(list(wrap_nodes(nm_graph, component))) return wrapped
def split( NmGraph, edges, retain=[], id_prepend='', ): try: retain.lower() # TODO: find more efficient operation to test if string-like retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(NmGraph) edges_to_add = [] added_nodes = [] edges = list(edges) for edge in edges: src = edge.src dst = edge.dst # Form ID for the new node if graph.is_directed(): new_id = '%s%s_%s' % (id_prepend, src, dst) else: # undirected, make id deterministic across ank runs (node_a, node_b) = sorted([src, dst]) # use sorted for consistency new_id = '%s%s_%s' % (id_prepend, node_a, node_b) if NmGraph.is_multigraph(): new_id = new_id + '_%s' % edge.ekey ports = edge.raw_interfaces data = edge._data src_data = data.copy() if src in ports: src_int_id = ports[src.node_id] src_data['_ports'] = {src.node_id: src_int_id} dst_data = data.copy() if dst in ports: dst_int_id = ports[dst.node_id] dst_data['_ports'] = {dst.node_id: dst_int_id} # Note: don't retain ekey since adding to a new node append = (src.node_id, new_id, src_data) edges_to_add.append(append) append = (dst.node_id, new_id, dst_data) edges_to_add.append(append) added_nodes.append(new_id) NmGraph.add_nodes_from(added_nodes) NmGraph.add_edges_from(edges_to_add) # remove the pre-split edges NmGraph.remove_edges_from(edges) return wrap_nodes(NmGraph, added_nodes)
def aggregate_nodes(OverlayGraph, nodes, retain = []): """Combines connected into a single node""" try: retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list nodes = list(unwrap_nodes(nodes)) graph = unwrap_graph(OverlayGraph) subgraph = graph.subgraph(nodes) if not len(subgraph.edges()): #print "Nothing to aggregate for %s: no edges in subgraph" pass total_added_edges = [] if graph.is_directed(): component_nodes_list = nx.strongly_connected_components(subgraph) else: component_nodes_list = nx.connected_components(subgraph) for component_nodes in component_nodes_list: if len(component_nodes) > 1: base = component_nodes.pop() # choose one base device to retain nodes_to_remove = set(component_nodes) # remaining nodes, set for fast membership test external_edges = nx.edge_boundary(graph, component_nodes) edges_to_add = [] for src, dst in external_edges: # src is the internal node to remove if src == base or dst == base: continue # don't alter edges from base else: if src in nodes_to_remove: # edge from component to outside interfaces = graph[src][dst]["_interfaces"] dst_int_id = interfaces[dst] data = dict( (key, graph[src][dst][key]) for key in retain) data['_interfaces'] = {dst: dst_int_id} edges_to_add.append((base, dst, data)) if graph.is_directed(): # other direction #TODO: check which data should be copied dst_data = dict( (key, graph[src][dst][key]) for key in retain) dst_data['_interfaces'] = {dst: dst_int_id} edges_to_add.append((dst, base, dst_data)) else: # edge from outside into component interfaces = graph[dst][src]["_interfaces"] src_int_id = interfaces[src] data = dict( (key, graph[dst][src][key]) for key in retain) data['_interfaces'] = {src: src_int_id} edges_to_add.append((base, src, data)) if graph.is_directed(): # other direction #TODO: check which data should be copied dst_data = dict( (key, graph[src][dst][key]) for key in retain) dst_data['_interfaces'] = {src: src_int_id} edges_to_add.append((src, base, dst_data)) graph.add_edges_from(edges_to_add) total_added_edges += edges_to_add graph.remove_nodes_from(nodes_to_remove) return wrap_edges(OverlayGraph, total_added_edges)
def unique_attr(NmGraph, attribute): graph = unwrap_graph(NmGraph) return set(graph.node[node].get(attribute) for node in graph)
def split(nm_graph, edges, retain=None, id_prepend=""): """ Splits edges in two, retaining any attributes specified. >>> anm = autonetkit.topos.house() >>> g_phy = anm['phy'] >>> edge = g_phy.edge("r1", "r2") >>> new_nodes = split(g_phy, edge) >>> new_nodes [r1_r2] >>> [n.neighbors() for n in new_nodes] [[r1, r2]] For multiple edges and specifying a prepend for the new nodes >>> anm = autonetkit.topos.house() >>> g_phy = anm['phy'] >>> edges = g_phy.node("r2").edges() >>> new_nodes = split(g_phy, edges, id_prepend="split_") >>> new_nodes [split_r2_r4, split_r1_r2, split_r2_r3] >>> [n.neighbors() for n in new_nodes] [[r4, r2], [r1, r2], [r2, r3]] """ if retain is None: retain = [] try: # TODO: find more efficient operation to test if string-like retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(nm_graph) edges_to_add = [] added_nodes = [] # handle single edge if edges in nm_graph.edges(): edges = [edges] # place into list for iteration edges = list(edges) for edge in edges: src = edge.src dst = edge.dst # Form ID for the new node if graph.is_directed(): new_id = "%s%s_%s" % (id_prepend, src, dst) else: # undirected, make id deterministic across ank runs # use sorted for consistency (node_a, node_b) = sorted([src, dst]) new_id = "%s%s_%s" % (id_prepend, node_a, node_b) if nm_graph.is_multigraph(): new_id = new_id + "_%s" % edge.ekey ports = edge.raw_interfaces data = edge._data src_data = data.copy() if src in ports: src_int_id = ports[src.node_id] src_data["_ports"] = {src.node_id: src_int_id} dst_data = data.copy() if dst in ports: dst_int_id = ports[dst.node_id] dst_data["_ports"] = {dst.node_id: dst_int_id} # Note: don't retain ekey since adding to a new node append = (src.node_id, new_id, src_data) edges_to_add.append(append) append = (dst.node_id, new_id, dst_data) edges_to_add.append(append) added_nodes.append(new_id) nm_graph.add_nodes_from(added_nodes) nm_graph.add_edges_from(edges_to_add) # remove the pre-split edges nm_graph.remove_edges_from(edges) return wrap_nodes(nm_graph, added_nodes)
def in_edges(OverlayGraph, nodes=None): graph = unwrap_graph(OverlayGraph) edges = graph.in_edges(nodes) return wrap_edges(OverlayGraph, edges)
def aggregate_nodes(NmGraph, nodes, retain = []): """Combines connected into a single node""" try: retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list nodes = list(unwrap_nodes(nodes)) graph = unwrap_graph(NmGraph) subgraph = graph.subgraph(nodes) if not len(subgraph.edges()): #print "Nothing to aggregate for %s: no edges in subgraph" pass total_added_edges = [] if graph.is_directed(): component_nodes_list = nx.strongly_connected_components(subgraph) else: component_nodes_list = nx.connected_components(subgraph) for component_nodes in component_nodes_list: if len(component_nodes) > 1: base = component_nodes.pop() # choose one base device to retain nodes_to_remove = set(component_nodes) # remaining nodes, set for fast membership test external_edges = nx.edge_boundary(graph, component_nodes) edges_to_add = [] for src, dst in external_edges: # src is the internal node to remove if src == base or dst == base: continue # don't alter edges from base else: if src in nodes_to_remove: # edge from component to outside interfaces = graph[src][dst]["_interfaces"] dst_int_id = interfaces[dst] data = dict( (key, graph[src][dst][key]) for key in retain) data['_interfaces'] = {dst: dst_int_id} edges_to_add.append((base, dst, data)) if graph.is_directed(): # other direction #TODO: check which data should be copied dst_data = dict( (key, graph[src][dst][key]) for key in retain) dst_data['_interfaces'] = {dst: dst_int_id} edges_to_add.append((dst, base, dst_data)) else: # edge from outside into component interfaces = graph[dst][src]["_interfaces"] src_int_id = interfaces[src] data = dict( (key, graph[dst][src][key]) for key in retain) data['_interfaces'] = {src: src_int_id} edges_to_add.append((base, src, data)) if graph.is_directed(): # other direction #TODO: check which data should be copied dst_data = dict( (key, graph[src][dst][key]) for key in retain) dst_data['_interfaces'] = {src: src_int_id} edges_to_add.append((src, base, dst_data)) graph.add_edges_from(edges_to_add) total_added_edges += edges_to_add graph.remove_nodes_from(nodes_to_remove) return wrap_edges(NmGraph, total_added_edges)
def copy_attr_from(overlay_src, overlay_dst, src_attr, dst_attr=None, nbunch=None, type=None, default=None): """ >>> anm = autonetkit.topos.house() >>> g_in = anm['input'] >>> g_phy = anm['phy'] >>> [n.color for n in g_phy] [None, None, None, None, None] >>> set_node_default(g_in, color="red") >>> copy_attr_from(g_in, g_phy, "color") >>> [n.color for n in g_phy] ['red', 'red', 'red', 'red', 'red'] Can specify a default value if unset >>> nodes = ["r1", "r2", "r3"] >>> set_node_default(g_in, nodes, role="core") >>> copy_attr_from(g_in, g_phy, "role", default="edge") >>> [(n, n.role) for n in g_phy] [(r4, 'edge'), (r5, 'edge'), (r1, 'core'), (r2, 'core'), (r3, 'core')] Can specify the remote attribute to set >>> copy_attr_from(g_in, g_phy, "role", "device_role", default="edge") Can specify the type to cast to >>> g_in.update(memory = "32") >>> copy_attr_from(g_in, g_phy, "memory", type=int) >>> [n.memory for n in g_phy] [32, 32, 32, 32, 32] Supported types to case to are float and int """ if not dst_attr: dst_attr = src_attr graph_src = unwrap_graph(overlay_src) graph_dst = unwrap_graph(overlay_dst) if not nbunch: nbunch = graph_src.nodes() for node in nbunch: try: val = graph_src.node[node].get(src_attr, default) except KeyError: # TODO: check if because node doesn't exist in dest, or because # attribute doesn't exist in graph_src log.debug("Unable to copy node attribute %s for %s in %s", src_attr, node, overlay_src) else: # TODO: use a dtype to take an int, float, etc if type is float: val = float(val) elif type is int: val = int(val) if node in graph_dst: graph_dst.node[node][dst_attr] = val
def copy_attr_from(overlay_src, overlay_dst, src_attr, dst_attr=None, nbunch=None, type=None, default=None): """ >>> anm = autonetkit.topos.house() >>> g_in = anm['input'] >>> g_phy = anm['phy'] >>> [n.color for n in g_phy] [None, None, None, None, None] >>> set_node_default(g_in, color="red") >>> copy_attr_from(g_in, g_phy, "color") >>> [n.color for n in g_phy] ['red', 'red', 'red', 'red', 'red'] Can specify a default value if unset >>> nodes = ["r1", "r2", "r3"] >>> set_node_default(g_in, nodes, role="core") >>> copy_attr_from(g_in, g_phy, "role", default="edge") >>> [(n, n.role) for n in g_phy] [(r4, 'edge'), (r5, 'edge'), (r1, 'core'), (r2, 'core'), (r3, 'core')] Can specify the remote attribute to set >>> copy_attr_from(g_in, g_phy, "role", "device_role", default="edge") Can specify the type to cast to >>> g_in.update(memory = "32") >>> copy_attr_from(g_in, g_phy, "memory", type=int) >>> [n.memory for n in g_phy] [32, 32, 32, 32, 32] Supported types to case to are float and int """ if not dst_attr: dst_attr = src_attr graph_src = unwrap_graph(overlay_src) graph_dst = unwrap_graph(overlay_dst) if not nbunch: nbunch = graph_src.nodes() for node in nbunch: try: val = graph_src.node[node].get(src_attr, default) except KeyError: # TODO: check if because node doesn't exist in dest, or because # attribute doesn't exist in graph_src log.debug('Unable to copy node attribute %s for %s in %s', src_attr, node, overlay_src) else: # TODO: use a dtype to take an int, float, etc if type is float: val = float(val) elif type is int: val = int(val) if node in graph_dst: graph_dst.node[node][dst_attr] = val
def in_edges(NmGraph, nodes=None): graph = unwrap_graph(NmGraph) edges = graph.in_edges(nodes) return wrap_edges(NmGraph, edges)
def in_edges(overlay_graph, nodes=None): graph = unwrap_graph(overlay_graph) edges = graph.in_edges(nodes) return wrap_edges(overlay_graph, edges)
def split(nm_graph, edges, retain=None, id_prepend=''): """ Splits edges in two, retaining any attributes specified. >>> anm = autonetkit.topos.house() >>> g_phy = anm['phy'] >>> edge = g_phy.edge("r1", "r2") >>> new_nodes = split(g_phy, edge) >>> new_nodes [r1_r2] >>> [n.neighbors() for n in new_nodes] [[r1, r2]] For multiple edges and specifying a prepend for the new nodes >>> anm = autonetkit.topos.house() >>> g_phy = anm['phy'] >>> edges = g_phy.node("r2").edges() >>> new_nodes = split(g_phy, edges, id_prepend="split_") >>> new_nodes [split_r2_r4, split_r1_r2, split_r2_r3] >>> [n.neighbors() for n in new_nodes] [[r4, r2], [r1, r2], [r2, r3]] """ if retain is None: retain = [] try: # TODO: find more efficient operation to test if string-like retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list graph = unwrap_graph(nm_graph) edges_to_add = [] added_nodes = [] # handle single edge if edges in nm_graph.edges(): edges = [edges] # place into list for iteration edges = list(edges) for edge in edges: src = edge.src dst = edge.dst # Form ID for the new node if graph.is_directed(): new_id = '%s%s_%s' % (id_prepend, src, dst) else: # undirected, make id deterministic across ank runs # use sorted for consistency (node_a, node_b) = sorted([src, dst]) new_id = '%s%s_%s' % (id_prepend, node_a, node_b) if nm_graph.is_multigraph(): new_id = new_id + '_%s' % edge.ekey ports = edge.raw_interfaces data = edge._data src_data = data.copy() if src in ports: src_int_id = ports[src.node_id] src_data['_ports'] = {src.node_id: src_int_id} dst_data = data.copy() if dst in ports: dst_int_id = ports[dst.node_id] dst_data['_ports'] = {dst.node_id: dst_int_id} # Note: don't retain ekey since adding to a new node append = (src.node_id, new_id, src_data) edges_to_add.append(append) append = (dst.node_id, new_id, dst_data) edges_to_add.append(append) added_nodes.append(new_id) nm_graph.add_nodes_from(added_nodes) nm_graph.add_edges_from(edges_to_add) # remove the pre-split edges nm_graph.remove_edges_from(edges) return wrap_nodes(nm_graph, added_nodes)
def aggregate_nodes(nm_graph, nodes, retain=None): """Combines connected into a single node""" if retain is None: retain = [] try: retain.lower() retain = [retain] # was a string, put into list except AttributeError: pass # already a list nodes = list(unwrap_nodes(nodes)) graph = unwrap_graph(nm_graph) subgraph = graph.subgraph(nodes) if not len(subgraph.edges()): # print "Nothing to aggregate for %s: no edges in subgraph" pass total_added_edges = [] if graph.is_directed(): component_nodes_list = \ nx.strongly_connected_components(subgraph) else: component_nodes_list = nx.connected_components(subgraph) for component_nodes in component_nodes_list: if len(component_nodes) > 1: component_nodes = [nm_graph.node(n) for n in component_nodes] # TODO: could choose most connected, or most central? # TODO: refactor so use nodes_to_remove nodes_to_remove = list(component_nodes) base = nodes_to_remove.pop() # choose a base device to retain log.debug('Retaining %s, removing %s', base, nodes_to_remove) external_edges = [] for node in nodes_to_remove: external_edges += [e for e in node.edges() if e.dst not in component_nodes] # all edges out of component log.debug('External edges %s', external_edges) edges_to_add = [] for edge in external_edges: dst = edge.dst data = dict((key, edge._data.get(key)) for key in retain) ports = edge.raw_interfaces dst_int_id = ports[dst.node_id] # TODO: bind to (and maybe add) port on the new switch? data['_ports'] = {dst.node_id: dst_int_id} append = (base.node_id, dst.node_id, data) edges_to_add.append(append) nm_graph.add_edges_from(edges_to_add) total_added_edges += edges_to_add nm_graph.remove_nodes_from(nodes_to_remove) return wrap_edges(nm_graph, total_added_edges)
def unique_attr(OverlayGraph, attribute): graph = unwrap_graph(OverlayGraph) return set(graph.node[node].get(attribute) for node in graph)