def rem(g: nx.MultiGraph) -> None: node_attributes = nx.get_node_attributes(G, 'elderly') nodes = list(g.nodes) for node in nodes: neigh = list(g.neighbors(node)) if len(neigh) == 2 and (g.degree(node) % 2) == 0: try: set1 = { edge['label'] for edge in g.get_edge_data(node, neigh[0]).values() } except: print(g.get_edge_data(node, neigh[0])) set2 = { edge['label'] for edge in g.get_edge_data(node, neigh[1]).values() } if set1 == set2: #prec=node_attributes[neigh[0]]+0.001 succ = node_attributes[neigh[1]] + 0.001 node_attr = node_attributes[node] + 0.001 # if (abs((node_attr-prec))<1000) and (abs((node_attr-succ))<1000): if (abs((node_attr - succ)) < 1000): g.remove_node(node) for edge_label in set1: g.add_edge(neigh[0], neigh[1], label=edge_label)
def auto_neb(m1, m2, graph: MultiGraph, model: models.ModelWrapper, config: config.AutoNEBConfig, callback: callable = None): # Continue existing cycles or start from scratch if m2 in graph[m1]: existing_edges = graph[m1][m2] previous_cycle_idx = max(existing_edges) connection_data = graph[m1][m2][previous_cycle_idx] start_cycle_idx = previous_cycle_idx + 1 else: connection_data = { "path_coords": torch.cat([graph.nodes[m]["coords"].view(1, -1) for m in (m1, m2)]), "target_distances": torch.ones(1) } start_cycle_idx = 1 assert start_cycle_idx <= config.cycle_count # Run NEB and add to graph for cycle_idx in helper.pbar( range(start_cycle_idx, config.cycle_count + 1), "AutoNEB"): cycle_config = config.neb_configs[cycle_idx - 1] connection_data = neb(connection_data, model, cycle_config) graph.add_edge(m1, m2, key=cycle_idx, **helper.move_to(connection_data, "cpu")) if callback is not None: callback()
def connect_routes(lab, lst, g: nx.MultiGraph): links = list(lst.linkid) if len(links) == 0: return for i in range(len(links)-1): conn = g.edges.get((links[i], links[i+1], 0)) if conn is None or conn['label'] != lab.iloc[0]: g.add_edge(links[i], links[i+1], label=lab.iloc[0])
def graph_minus(g: MultiGraph, w: set) -> MultiGraph: gx = MultiGraph() for (n1, n2) in g.edges(): if n1 not in w and n2 not in w: gx.add_edge(n1, n2) for n in g.nodes(): if n not in w: gx.add_node(n) return gx
def add_edge_journal_in_graph(graph: nwx.MultiGraph, journal_edge): for item in journal_edge: if item['edge_list']: for edge in item['edge_list']: graph.add_edge(edge[0], edge[1], journal=item['journal'], date=item['date']) return graph
def add_edge_clinical_in_graph(graph: nwx.MultiGraph, clinical_edge): for item in clinical_edge: if item['edge_list']: for edge in item['edge_list']: graph.add_edge(edge[0], edge[1], id_clinical=item['id_clinical'], title_clinical=item['title_clinical'], date=item['date']) return graph
def add_edge_pubmed_in_graph(graph: nwx.MultiGraph, pubmed_edge): for item in pubmed_edge: if item['edge_list']: for edge in item['edge_list']: graph.add_edge(edge[0], edge[1], id_pubmed=item['id_pubmed'], title_pubmed=item['title_pubmed'], date=item['date']) return graph
def add_weak_gene(gene: EdgeGene, graph: nx.MultiGraph) -> bool: key = gene.A1 + gene.A2 edge = (gene.P1, gene.P2, key) if any(starmap( lambda p, a: p in graph and not any(x == a for x in get_node_space(graph, p)), [(gene.P1, gene.A1), (gene.P2, gene.A2)])): return False if graph.has_edge(gene.P1, gene.P2): keys = graph[gene.P1][gene.P2] if len(keys) > 1: return False graph.remove_edge(gene.P1, gene.P2, next(iter(keys))) graph.add_edge(*edge, gene=gene) return True
def test_sequence(self): graph = MultiGraph() graph.add_node(1, value=1) # Global minimum graph.add_node(2, value=2) graph.add_node(3, value=3) graph.add_node(4, value=4) def weight(id_pair): return sum(node ** 2 for node in id_pair) unfinished_edge = (1, 3) config = LandscapeExplorationConfig("value", "weight", [], None, AutoNEBConfig([None, None])) # Disconnect suggest correct_order = [ (1, 2), (1, 3), (1, 4), ] config.suggest_methods = [disconnected] while True: pair = suggest_pair(graph, config) if pair[0] is None: break self.assertGreater(len(correct_order), 0, "disconnected_suggest gives more pairs than necessary") assert pair == correct_order.pop(0) graph.add_edge(*pair, key=1, weight=weight(pair)) if pair != unfinished_edge: # Skip the second edge for this pair, to test unfinished suggest graph.add_edge(*pair, key=2, weight=weight(pair)) self.assertEqual(len(correct_order), 0, "disconnected_suggest missing suggestions!") # Unfinished suggest correct_order = [ unfinished_edge ] config.suggest_methods = [unfinished] while True: pair = suggest_pair(graph, config) if pair[0] is None: break self.assertGreater(len(correct_order), 0, "unfinished_suggest gives more pairs than necessary") assert pair == correct_order.pop(0) graph.add_edge(*pair, key=2, weight=weight(pair)) self.assertEqual(len(correct_order), 0, "unfinished_suggest missing suggestions!") # Core: MST suggest correct_order = [ (2, 4), (3, 4), # Replace (1, 4) (2, 3), # Replace (1, 3) ] config.suggest_methods = [mst] while True: pair = suggest_pair(graph, config) if pair[0] is None: break self.assertGreater(len(correct_order), 0, "mst_suggest gives more pairs than necessary") assert pair == correct_order.pop(0) graph.add_edge(*pair, key=1, weight=weight(pair)) graph.add_edge(*pair, key=2, weight=weight(pair)) self.assertEqual(len(correct_order), 0, "mst_suggest missing suggestions!")
def reduction3(g: MultiGraph, w: set, h: MultiGraph, k: int) -> (int, int, bool): for v in h.nodes(): if g.degree(v) == 2: # If v has a neighbour in H, short-curcuit it. if len(h[v]) >= 1: # Delete v and make its neighbors adjacent. [n1, n2] = g.neighbors(v) g.remove_node(v) g.add_edge(n1, n2) # Update H accordingly. h.remove_nodes_from([v]) if n1 not in w and n2 not in w: h.add_edge(n1, n2) return (k, None, True) return (k, None, False)
def test_run_walks(): mg = MultiGraph() mg.add_edge('a', 'b') mg.add_edge('b', 'c') dw = DeepWalk(mg, 10, 100) dw.get_walks(workers=1) # Number of neighbors for all nodes together is 4, times niter: 400 assert len(dw.walks) == 400, len(dw.walks) assert len([w for w in dw.walks if w[0] == 'a']) == 100 assert len([w for w in dw.walks if w[0] == 'b']) == 200 dw.get_walks(workers=2) # Number of neighbors for all nodes together is 4, times niter: 400 assert len(dw.walks) == 400, len(dw.walks) assert len([w for w in dw.walks if w[0] == 'a']) == 100 assert len([w for w in dw.walks if w[0] == 'b']) == 200
def add_node_edge(graph: nx.MultiGraph, from_node, to_nodes, c): graph.add_node(from_node) for i in to_nodes.split(';'): graph.add_node(i) graph.add_edge( from_node, i, viz={'color': { 'r': c[0], 'g': c[1], 'b': c[2], 'a': 1.0 }}) graph.add_edge() # graph.add_edge(frm, i) return graph
def main(): g = MultiGraph() analyzer = TraceAnalyzer() analyzer.parse("../pintool.log") # Get all the chunks used by the application chunks = analyzer.getChunks() for chunk in chunks: g.add_node("%x-%x" % (chunk.chunk_addr, chunk.timestamp)) writes = analyzer.getMemoryWrites() for write in writes: b = "C:%x-%x" % (write.chunk_addr, write.timestamp) a = "W:%x-%x" % (write.write_addr, write.content) g.add_edge(a, b) draw_shell(g) plt.show()
def connect_matching_pair_edges(self, Gu: nx.MultiGraph, ls, rs, obj_node_id='obj', connect_obj_rel_edges=False) -> nx.Graph: """ Ground truth (_gt_)generator function for a combined graph. Used for training S_0 :param Gu: A (unconnected) composed graph of Gs, Gt. No relational links between head nodes, thus, the number_connected_components(Gs|Gt) = number of object nodes in each graph. :param Gs: The source Graph, i.e., the text graph representation :param Gt: The target Graph, i.e., the grounding (image features) graph representation :param obj_node_id: the identifier determining a obj (or head) node :return: matching_pairs: List of matching pair tuples between Gs, Gt """ matching_pairs, unmatched_pairs = self.get_matching_pairs_in_bipartite_graph(Gu, ls, rs, obj_node_id) NDV = Gu.nodes(data=True) # Connect the matching pairs if not connected # for pair in matching_pairs: s_node, t_node = pair if not Gu.has_edge(s_node, t_node): Gu.add_edge(s_node, t_node, '<gt>') # Connect Attr Nodes # is_head_node = lambda x: obj_node_id in x Ns = nx.neighbors(Gu, s_node) Nt = list(nx.neighbors(Gu, t_node)) for ns in Ns: if is_head_node(ns): continue # Check label equality only, 'val' equality already verified ns_label = NDV[ns]['label'] #logger.debug(f'Source attr node label = {ns_label}') # TODO: potential issue here, Nt should always have a matching attr node for nt in filter(lambda x: NDV[x]['label'] == ns_label, Nt): if not Gu.has_edge(ns, nt): Gu.add_edge(ns, nt, key='<gt>') if connect_obj_rel_edges: # TODO: Add a obj relation edge among all Gs, Gt obj nodes. Actually # should be done earlier in the parse cycle. pass return Gu
def reduction3(self, g: MultiGraph, w: set, h: MultiGraph, k: int) -> (int, int, bool): """ If there is a node v ∈ V(H) of degree 2 in G such that at least one neighbor of v in G is from V (H), then delete this node and make its neighbors adjacent (even if they were adjacent before; the graph could become a multigraph now). """ for v in h.nodes(): if g.degree(v) == 2: # If v has a neighbour in H, short-curcuit it. if len(h[v]) >= 1: # Delete v and make its neighbors adjacent. [n1, n2] = g.neighbors(v) g.remove_node(v) g.add_edge(n1, n2) # Update H accordingly. h.remove_nodes_from([v]) if n1 not in w and n2 not in w: h.add_edge(n1, n2) return k, None, True return k, None, False
def reduction4(self, g: MultiGraph, k: int) -> (int, List[int], bool): """ If there is a vertex v of degree 2, delete v and connect its two neighbors by a new edge. """ for v in g.nodes(): if g.degree(v) == 2: # Delete v and make its neighbors adjacent. ne = g.neighbors(v) # We must check whether v has 2 neighbors, or just one but connected to v by multiple edges if len(ne) == 2: [n1, n2] = ne else: [n1] = ne n2 = n1 g.remove_node(v) # Only add the edge if there are currently less than 2 edges between these two nodes es = g[n1].get(n2, {}) if len(es) < 2: g.add_edge(n1, n2) return k, None, True return k, None, False
def add_strong_gene(gene: EdgeGene, graph: nx.MultiGraph, coupling_threshold: float) -> bool: key = gene.A1 + gene.A2 edge = (gene.P1, gene.P2, key) if not graph.has_edge(gene.P1, gene.P2): graph.add_edge(*edge, gene=gene) return True keys = graph[gene.P1][gene.P2] if key in keys: return False if len(keys) > 1: graph.add_edge(*edge, gene=gene) return True if graph[gene.P1][gene.P2][next(iter(keys))]['gene'].C < coupling_threshold: graph.remove_edge(gene.P1, gene.P2, next(iter(keys))) graph.add_edge(*edge, gene=gene) return True
class ShuttlingGraph(list): def __init__(self, shuttlingEdges=list() ): super(ShuttlingGraph, self).__init__(shuttlingEdges) self.currentPosition = None self.currentPositionName = None self.nodeLookup = dict() self.currentPositionObservable = Observable() self.graphChangedObservable = Observable() self.initGraph() self._hasChanged = True def initGraph(self): self.shuttlingGraph = MultiGraph() for edge in self: self.shuttlingGraph.add_node(edge.startName) self.shuttlingGraph.add_node(edge.stopName) self.shuttlingGraph.add_edge(edge.startName, edge.stopName, key=hash(edge), edge=edge, weight=abs(edge.stopLine-edge.startLine)) self.nodeLookup[edge.startLine] = edge.startName self.nodeLookup[edge.stopLine] = edge.stopName def rgenerateNodeLookup(self): self.nodeLookup.clear() for edge in self: self.nodeLookup[edge.startLine] = edge.startName self.nodeLookup[edge.stopLine] = edge.stopName @property def hasChanged(self): return self._hasChanged @hasChanged.setter def hasChanged(self, value): self._hasChanged = value def position(self, line): return self.nodeLookup.get(line) def setPosition(self, line): if self.currentPosition!=line: self.currentPosition = line self.currentPositionName = self.position(line) self.currentPositionObservable.fire( line=line, text=firstNotNone(self.currentPositionName, "") ) def getMatchingPosition(self,graph): """Try to match node name/position to the current settings in the provided ShuttlingGraph.""" if not graph: return self.currentPosition # no change # Matching node name. Need to set the corresponding position for edge in self: if edge.startName == graph.currentPositionName: return edge.startLine if edge.stopName == graph.currentPositionName: return edge.stopLine #if graph.currentPosition: # return graph.currentPosition #just use the graph's position return self.currentPosition def addEdge(self, edge): self._hasChanged = True self.append(edge) self.shuttlingGraph.add_edge(edge.startName, edge.stopName, key=hash(edge), edge=edge, weight=abs(edge.stopLine-edge.startLine)) self.nodeLookup[edge.startLine] = edge.startName self.nodeLookup[edge.stopLine] = edge.stopName self.graphChangedObservable.firebare() self.setPosition(self.currentPosition) def isValidEdge(self, edge): return ((edge.startLine not in self.nodeLookup or self.nodeLookup[edge.startLine] == edge.startName) and (edge.stopLine not in self.nodeLookup or self.nodeLookup[edge.stopLine] == edge.stopName)) def getValidEdge(self): index = 0 while self.shuttlingGraph.has_node("Start_{0}".format(index)): index += 1 startName = "Start_{0}".format(index) index = 0 while self.shuttlingGraph.has_node("Stop_{0}".format(index)): index += 1 stopName = "Stop_{0}".format(index) index = 0 startLine = (max( self.nodeLookup.keys() )+1) if self.nodeLookup else 1 stopLine = startLine + 1 return ShuttleEdge(startName, stopName, startLine, stopLine, 0, 0, 0, 0) def removeEdge(self, edgeno): self._hasChanged = True edge = self.pop(edgeno) self.shuttlingGraph.remove_edge(edge.startName, edge.stopName, hash(edge)) if self.shuttlingGraph.degree(edge.startName) == 0: self.shuttlingGraph.remove_node(edge.startName) if self.shuttlingGraph.degree(edge.stopName) == 0: self.shuttlingGraph.remove_node(edge.stopName) self.graphChangedObservable.firebare() self.rgenerateNodeLookup() self.setPosition(self.currentPosition) def setStartName(self, edgeno, startName): self._hasChanged = True startName = str(startName) edge = self[edgeno] if edge.startName != startName: self.shuttlingGraph.remove_edge(edge.startName, edge.stopName, key=hash(edge)) if self.shuttlingGraph.degree(edge.startName) == 0: self.shuttlingGraph.remove_node(edge.startName) edge.startName = startName self.shuttlingGraph.add_edge(edge.startName, edge.stopName, key=hash(edge), edge=edge, weight=abs(edge.stopLine-edge.startLine) ) self.graphChangedObservable.firebare() self.setPosition(self.currentPosition) self.rgenerateNodeLookup() return True def setStopName(self, edgeno, stopName): self._hasChanged = True stopName = str(stopName) edge = self[edgeno] if edge.stopName != stopName: self.shuttlingGraph.remove_edge(edge.startName, edge.stopName, key=hash(edge)) if self.shuttlingGraph.degree(edge.stopName) == 0: self.shuttlingGraph.remove_node(edge.stopName) edge.stopName = stopName self.shuttlingGraph.add_edge(edge.startName, edge.stopName, key=hash(edge), edge=edge, weight=abs(edge.stopLine-edge.startLine) ) self.graphChangedObservable.firebare() self.rgenerateNodeLookup() self.setPosition(self.currentPosition) return True def setStartLine(self, edgeno, startLine): self._hasChanged = True edge = self[edgeno] if startLine != edge.startLine and (startLine not in self.nodeLookup or self.nodeLookup[startLine] == edge.startName): self.nodeLookup.pop(edge.startLine) edge.startLine = startLine self.shuttlingGraph.edge[edge.startName][edge.stopName][hash(edge)]['weight'] = abs(edge.stopLine-edge.startLine) self.rgenerateNodeLookup() self.graphChangedObservable.firebare() self.setPosition(self.currentPosition) return True return False def setStopLine(self, edgeno, stopLine): self._hasChanged = True edge = self[edgeno] if stopLine != edge.stopLine and (stopLine not in self.nodeLookup or self.nodeLookup[stopLine] == edge.stopName): self.nodeLookup.pop(edge.stopLine) edge.stopLine = stopLine self.shuttlingGraph.edge[edge.startName][edge.stopName][hash(edge)]['weight'] = abs(edge.stopLine-edge.startLine) self.rgenerateNodeLookup() self.graphChangedObservable.firebare() self.setPosition(self.currentPosition) return True return False def setIdleCount(self, edgeno, idleCount): self._hasChanged = True self[edgeno].idleCount = idleCount return True def setSteps(self, edgeno, steps): self._hasChanged = True self[edgeno].steps = steps return True def shuttlePath(self, fromName, toName ): fromName = firstNotNone(fromName, self.currentPositionName) fromName = fromName if fromName else self.position(float(self.currentPosition)) if fromName not in self.shuttlingGraph: raise ShuttlingGraphException("Shuttling failed, origin '{0}' is not a valid shuttling node".format(fromName)) if toName not in self.shuttlingGraph: raise ShuttlingGraphException("Shuttling failed, target '{0}' is not a valid shuttling node".format(toName)) sp = shortest_path(self.shuttlingGraph, fromName, toName) path = list() for a, b in pairs_iter(sp): edge = sorted(self.shuttlingGraph.edge[a][b].values(), key=itemgetter('weight'))[0]['edge'] path.append((a, b, edge, self.index(edge))) return path def nodes(self): return self.shuttlingGraph.nodes() def toXmlElement(self, root): mydict = dict( ( (key, str(getattr(self, key))) for key in ('currentPosition', 'currentPositionName') if getattr(self, key) is not None ) ) myElement = ElementTree.SubElement(root, "ShuttlingGraph", attrib=mydict ) for edge in self: edge.toXmlElement( myElement ) return myElement def setStartType(self, edgeno, Type): self._hasChanged = True self[edgeno].startType = str(Type) return True def setStopType(self, edgeno, Type): self._hasChanged = True self[edgeno].stopType = str(Type) return True def setStartLength(self, edgeno, length): edge = self[edgeno] if length!=edge.startLength: if length+edge.stopLength<edge.sampleCount: self._hasChanged = True edge.startLength = int(length) else: return False return True def setStopLength(self, edgeno, length): edge = self[edgeno] if length!=edge.stopLength: if edge.startLength+length<edge.sampleCount: self._hasChanged = True edge.stopLength = int(length) else: return False return True @staticmethod def fromXmlElement( element ): edgeElementList = element.findall("ShuttleEdge") edgeList = [ ShuttleEdge.fromXmlElement(e) for e in edgeElementList ] return ShuttlingGraph(edgeList)
class MultiEdgeUndirectedTopology(BaseTopology): """Class representing a topology with mutltiple undirected edges. :param iter nodes: Nodes in the graph :param iter edges: Edges in the graph """ # Names used to hold the node longitude and latitude NODE_LONG = 'long' NODE_LAT = 'lat' # Name used to hold the edge type EDGE_TYPE = 'type' def __init__(self, nodes=None, edges=None): self.graph = MultiGraph() # Nodes nodes = nodes or {} for node_id, (lon, lat) in nodes.items(): self.add_node(node_id, lon, lat) # Edges edges = edges or {} for (n1, n2), (edge_type, dict_attrs) in edges.items(): self.add_edge(n1, n2, edge_type, **dict_attrs) @property def num_of_nodes(self): """The number of nodes in the topology.""" return self.graph.number_of_nodes() @property def num_of_edges(self): """The number of nodes in the topology.""" return self.graph.number_of_edges() @property def nodes(self): """The nodes in the graph.""" return self.graph.nodes def add_node(self, node_id, longitude, latitude, **node_attrs): """Add a node defined by its label. :param int node_id: Node id. :param dict node_attrs: Node attributes. :raises: :py:class:`RuntimeError`: if a node with the same ID already exists. """ # If there is no node with the same ID already, raise exception if self.graph.has_node(node_id): raise RuntimeError("Node %s already exists." % node_id) # Adding longitude and latitude to attributes node_attrs[self.NODE_LONG] = longitude node_attrs[self.NODE_LAT] = latitude # Create node self.graph.add_node(node_id, **node_attrs) def get_node(self, node_id): """Return node from its ID.""" try: return self.graph.nodes[node_id] except KeyError: raise KeyError("Node %s does not exist." % node_id) def distance(self, n1, n2): """ Calculate the distance between two nodes on the Earth. :param int n1: ID of the first node. :param int n2: ID of the second node. :returns: Distance in cm :rtype: float """ n1 = self.get_node(n1) n2 = self.get_node(n2) return utility_distance( n1[self.NODE_LONG], n1[self.NODE_LAT], n2[self.NODE_LONG], n2[self.NODE_LAT] ) def add_edge(self, node1, node2, edge_type, **edge_attrs): """Add an edge between two nodes in the graph. :param obj node1: Label of the first node. :param obj node2: Label of the second node. :param obj edge_type: Edge type. :param dict edge_attrs: Additional attributes of the edge. :raises: :py:class:`RuntimeError`: if an edge with the same type already exists. """ _ = self.get_node(node1) _ = self.get_node(node2) # If an edge of the given type between the two nodes already exits: error # We take into account that the graph in undirected with suppress(KeyError): types_existing_edges = [e[self.EDGE_TYPE] == edge_type for e in self.get_edges(node1, node2).values()] if any(types_existing_edges): raise RuntimeError( 'Already existing edge %s between nodes %s and %s' % (edge_type, node1, node2) ) # Adding type to attributes edge_attrs[self.EDGE_TYPE] = edge_type # Create edge self.graph.add_edge(node1, node2, **edge_attrs) def get_edges(self, node1, node2, edge_types=None): """Return all the edges between two nodes. :param obj node1: Label of the first node. :param obj node2: Label of the second node. :param iterable edge_types: If provided, return only the edges for these types. :returns: A dictionary where the keys are the edge number and the values a dictionary of the edges attributes. :rtype: dict :raises: :py:class:`ValueError`: if there is no edge between the nodes. """ try: edges = dict(self.graph[node1][node2]) except KeyError: # undirected graph try: edges = dict(self.graph[node2][node1]) except KeyError: raise KeyError('No edge between nodes %s and %s' % (node1, node2)) # Filter if necessary if edge_types: edges = {e: v for e, v in edges.items() if edges[e][self.EDGE_TYPE] in edge_types} # If dict is empty, there is no edge if not edges: raise KeyError('No edge between nodes %s and %s' % (node1, node2)) return edges def _get_min_weight(self, weight, allowed_types, best_types, node1, node2, _d): """ Find the edge with the minimum weight between two nodes. :param str weight: Weight name. :param allowed_types: Edge type(s) allowed to build path. :type allowed_types: dict-like object with TransportType as keys. :param dict best_types: dictionnary containing the best type for each pair of nodes. :note: other arguments are the ones needed by the NetworkX API. """ # The algorithm uses the full (symmetric) matrix # instead of considering the upper triangular only. # This means that for two nodes u ≠ v, the weight is extracted twice: # once for (u,v), once for (v,u). We do not need to do the work for both. if (node2, node1) in best_types: return None # Get all edges between the two nodes edges = self.get_edges(node1, node2) # Get all the weights but keep only those that are allowed # This will throw a KeyError is some edges do not have the weight specified try: weights = [(attrs[self.EDGE_TYPE], attrs[weight]) for attrs in edges.values() if attrs[self.EDGE_TYPE] in allowed_types] except KeyError: raise KeyError( "No edge with attribute %s found between nodes %s and %s" % ( weight, node1, node2 )) # If there is no valid edge if not weights: return None # If the weights need to be weighted. Skip if they are all None. if list(set(allowed_types.values()))[0]: weights = [(t, w * allowed_types[t]) for t, w in weights] # Otherwise, save type and return minimum weight min_type, min_weight = min(weights, key=lambda t: t[1]) best_types[(node1, node2)] = min_type return min_weight def get_shortest_path(self, node1, node2, criterion, allowed_types, edge_data=None): """Find the shortest path between two nodes using specified edges. :param obj node1: Label of the first node. :param obj node2: Label of the second node. :param str criterion: Criterion used to find shortest path. Must be an edge attribute. :param dict allowed_types: Edge type(s) allowed to build path. The keys are the edge types, the values (if any) indicate the preference for each type. :param iter(str) edge_data: Edge attributes for which data along the path is requested. :returns: A 3-tuple containing in this order * the score of the optimal path * the list of nodes along the path * a dict containing the edge type and values for the attributes specified in edge_data (data are stored in numpy arrays) :rtype: tuple :raises: :py:class:`.ValueError`: if nodes dont exists or no path has been found between them. :note: If `allowed_types` is a dict-like object, the weight of an edge will be weighted by the value of the given edge type. """ # Check that the nodes exist for node in node1, node2: if not self.graph.has_node(node): raise ValueError("Node %s does not exist." % node) # Using partial function to pass the edge types # The weight_func will be called for each edge on the graph # Even those which will not been part of the optimial path # So best_types cannot be a simple list to which we append values # Instead it will be a dict where the key is a pair of nodes # We will extract the relevant values and attributes afterwards best_types = {} weight_func = partial(self._get_min_weight, criterion, allowed_types, best_types) # Calculate path try: score, path = single_source_dijkstra( self.graph, node1, node2, weight=weight_func) except NetworkXNoPath: raise RuntimeError("No path found with type %s between %s and %s." % (allowed_types, node1, node2)) # Build the dict containing the attributes data # Because we do not want to assume anything about the data, # we build an intermediate list first. data = {} # Always extract the edge types edge_types = [] for u, v in zip(path, path[1:]): # The key could be (u,v) or (v,u) try: edge_types.append(best_types[(u, v)]) except KeyError: edge_types.append(best_types[(v, u)]) data[self.EDGE_TYPE] = np.array(edge_types) # Additional data if needed edge_data = edge_data or [] for attr in edge_data: try: temp_list = [ list(self.get_edges(u, v, [t]).values())[0][attr] for u, v, t in zip( path, path[1:], data[self.EDGE_TYPE])] data[attr] = np.array(temp_list) except KeyError: raise KeyError("Some edges do not have the attribute '%s'." % attr) return (score, path, data) def add_energy_based_edges( self, edge_types, num_edges_per_step, max_iterations, degree_energy_factor, distance_energy_factor, rng, attribute_name='distance'): """ This algorithm creates edges based on an energy sampling mechanism. At each iteration, the total energy (degree energy + potential energy) is calculated between all nodes and transformed into a Boltzmann distribution. Edges are more likely to be created between nodes which are: * close * already connected to other nodes A fixed number of random connections are then created based on this distribution, masking previous connections and self-edges. The process is repeated until either the maximum number of iterations is reached, or all nodes have been connected at least once to another node. :param iter edge_types: Types of the edges to add. :param int num_edges_per_step: Number of edges to create at each step :param int max_iterations: Maximum number of iterations. If None, the algorithm stops when each node has been connected at least once. :param float degree_energy_factor: Multiplier applied to the degree enery component during the search for new edges (higher means more prominent). :param float distance_energy_factor: Multiplier applied to the distance energy component during the search for new edges (higher means more prominent). :param rng: Random number generator. :type rng: :py:class:`RandomGenerator<city_graph.utils.RandomGenerator>` :note: The algorithm does take into account already exisiting edges to compute the probabilities. """ print("[Topology] Starting energy sampling algorithm to build edges.") # Step 1: prepare # Compute all distances: graph is undirected so we want all combinations with replacements # so we should have in total C(2,n) + n distances # TODO: We compute things twice for now, so things might be improved array_shape = (self.num_of_nodes,) * 2 distances = np.zeros(shape=array_shape) array_size = distances.size for (i, n1), (j, n2) in product(enumerate(self.nodes), repeat=2): distances[i, j] = self.distance(n1, n2) # Normalize by maximum distance - save scaling factor as it will be needed max_distance = distances.max() distances /= max_distance # Adjacency matrix (not taking into account previously existing edges) adjacency_matrix = np.zeros(shape=array_shape) # Step 2: sampling step = 0 termination = TerminationReason.NO_TERMINATION while termination == TerminationReason.NO_TERMINATION: # This loop could be put in a separate function. # We will see if it is necessary # Sampling step # a) compute the degree energies degree_energy = -1 / 2 * ( adjacency_matrix.sum(0, keepdims=True) + adjacency_matrix.sum(1, keepdims=True) ) if degree_energy_factor: degree_energy = degree_energy_factor * degree_energy # b) compute the distance energies distance_energy = distances if distance_energy_factor: distance_energy = distance_energy_factor * distances # c) compute edge sampling probability distribution total_energy = degree_energy + distance_energy # mask existing edges total_energy[adjacency_matrix > EPS_PRECISION] = np.inf # mask self-edges np.fill_diagonal(total_energy, np.inf) # compute Boltzmann distribution and normalize it bolz_dist = np.exp(-total_energy) bolz_dist /= bolz_dist.sum() # d) sample step # sample indices to activate sample_indices = rng.choice( np.arange(array_size), size=(num_edges_per_step,), p=bolz_dist.ravel(), replace=True) # unravel indices - get a tuple unravel_indices = np.unravel_index(sample_indices, array_shape) # add sample edges to the adjacency matrix # and make matric symmetric adjacency_matrix[unravel_indices] = 1 adjacency_matrix[unravel_indices[::-1]] = 1 # Increase counter step += 1 # Check termination # Maximum step number reached if max_iterations: if step >= max_iterations: termination = TerminationReason.MAX_ITER # All nodes are connected if adjacency_matrix.sum(0).min() > EPS_PRECISION: termination = TerminationReason.ALL_NODES_CONNECTED # Inform the user why the algorithm has stopped print("[Topology] Sampling finished after", step, "steps. Reason:", termination) # Build edges from the adjacency matrix # Rescale the distances distances *= max_distance # Get pair of nodes to connect # Here we use indices because we will need them later on for the distances pairs = [(i, j) for i, j in zip(*adjacency_matrix.nonzero())] # Create edges old_num_edges = self.num_of_edges node_ids = list(self.nodes) for i, j in pairs: for edge_type in edge_types: # TODO: exception might be raised here because we now check # That there is no outgoing/incoming edges. # Should we fix when we use an actual triangular matrix with suppress(RuntimeError): self.add_edge(node_ids[i], node_ids[j], edge_type, **{attribute_name: distances[i, j]}) # Inform that edges have been built print("[Topology] %i edges have been created" % (self.num_of_edges - old_num_edges)) def add_edges_between_centroids(self, edge_types, num_centroids, rng, attribute_name='distance'): """ This algorithm creates edges between central nodes. These central nodes are determined by a clustering algorithm (here the Fluid Communities algorithm). :param iter edge_types: Types of the edges to add. :param int num_centroids: Number of centroids. :param rng: Random number generator. :type rng: :py:class:`RandomGenerator<city_graph.utils.RandomGenerator>` """ print("[Topology] Starting building edges between %s central nodes." % num_centroids) # Calculate clusters # TODO: I think it would make sense to instead use e.g. a k-means for two reasons: # * this algo assumes that the clusters have the same density, which is not necessarily # application to cities (some areas are more crowded) # * the implementation needs the graph to be fully connected to begin with. It seems # to be a limitation clusters = (list(c) for c in asyn_fluidc( self.graph, k=num_centroids, seed=rng.rand_int())) # Extract centroids: we take the node with the highest degree centroids = [c[int(np.argmax([self.graph.degree[n] for n in c]))] for c in clusters] # Create temporary graph for the centroids tmp_graph = Graph() tmp_graph.add_nodes_from(centroids) # We need the combinations because the graph is undirected and we dont want self-edges for n1, n2 in combinations(centroids, 2): tmp_graph.add_edge(n1, n2, **{attribute_name: self.distance(n1, n2)}) # Calculate subgraph with the minimum sum of edge weights # TODO: to investigate why we do this here... subgraph = minimum_spanning_tree(tmp_graph, weight=attribute_name) # Build edges # Here we can reuse the previously calculated distances old_num_edges = self.num_of_edges for (n1, n2) in subgraph.edges: for edge_type in edge_types: # TODO: exception might be raised here because we now check # That there is no outgoing/incoming edges. # Should we fix when we use an actual triangular matrix with suppress(RuntimeError): self.add_edge(n1, n2, edge_type, **subgraph[n1][n2]) # Inform that edges have been built print("[Topology] %i edges have been created" % (self.num_of_edges - old_num_edges))
return '10Gb' elif 'OC3' in label: return '155Mb' elif 'OC12' in label: return '622Mb' elif 'OC48' in label: return '2.4Gb' else: return '1Gb' for n1, n2, ed in graph.edges_iter(data=True): # print n1, n2, ed n1d = graph.node[n1] n2d = graph.node[n2] # print n1d,n2d dist = distance(n1d['Longitude'], n1d['Latitude'], n2d['Longitude'], n2d['Latitude']) # print dist loc1 = '{}, {}'.format(n1d['label'], n1d['Country']) loc2 = '{}, {}'.format(n2d['label'], n2d['Country']) span = '{} to {}'.format(loc1, loc2) newgraph.add_node(n1, autoack='False', location=loc1) newgraph.add_node(n2, autoack='False', location=loc2) cap = get_cap(ed['LinkLabel']) newgraph.add_edge(n1, n2, weight=1, capacity=cap, delay=dist, span=span) add_measurement(newgraph) add_traffic(newgraph) write_dot(newgraph, outname)
f.close() fh = open("trash","w") call(["./blossom4","-3", "-x","data.dat", "-w", "output.dat"], stdout=fh) fh.close() result = genfromtxt('output.dat', delimiter=' ', usecols = (0, 1)) result = result[1:] #MINMAXMATCHING END H = MultiGraph() H.add_nodes_from(T.nodes()) H.add_edges_from(T.edges()) for (key, value) in a.items(): if N < N: H.add_edge(N, N) t = Set() for (i, j) in eulerian_circuit(H): if i in t: continue t.add(i) print i #the result is t #t_e = zip(t[:-1], t[1:]) #distance = 0 #for (i, j) in t_e: # distance += Y[i, j]
def get_cap(label): if 'OC192/STM64' in label: return '10Gb' elif 'OC3' in label: return '155Mb' elif 'OC12' in label: return '622Mb' elif 'OC48' in label: return '2.4Gb' else: return '1Gb' for n1,n2,ed in graph.edges_iter(data=True): # print n1, n2, ed n1d = graph.node[n1] n2d = graph.node[n2] # print n1d,n2d dist = distance(n1d['Longitude'],n1d['Latitude'],n2d['Longitude'],n2d['Latitude']) # print dist loc1 = '{}, {}'.format(n1d['label'], n1d['Country']) loc2 = '{}, {}'.format(n2d['label'], n2d['Country']) span = '{} to {}'.format(loc1, loc2) newgraph.add_node(n1, autoack='False', location=loc1) newgraph.add_node(n2, autoack='False', location=loc2) cap = get_cap(ed['LinkLabel']) newgraph.add_edge(n1, n2, weight=1, capacity=cap, delay=dist, span=span) add_measurement(newgraph) add_traffic(newgraph) write_dot(newgraph, outname)
# with or without fee is hereby granted, provided that the above copyright notice # and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND # FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, # OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, # DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. from networkx import MultiGraph # create a new graph my_graph = MultiGraph() # create four nodes my_graph.add_node(1) my_graph.add_node(2) my_graph.add_node(3) my_graph.add_node(4) # create seven edges my_graph.add_edge(1, 2) my_graph.add_edge(1, 2) my_graph.add_edge(1, 3) my_graph.add_edge(1, 4) my_graph.add_edge(1, 4) my_graph.add_edge(2, 3) my_graph.add_edge(3, 4)
with open('excel_files', 'r') as ef: for each_excel_file in ef: each_excel_file = each_excel_file.strip() excel_file_object = pd.read_excel( r'C:\\Network Programmability and Automation\network_diagram\\' + each_excel_file) #print(excel_file_object) #filter specific columns from excel sheet remote_device_id = pd.DataFrame(excel_file_object, columns=['remote device-Id']) Local_device_id = pd.DataFrame(excel_file_object, columns=['Local device-Id']) #print(list(remote_device_id)) #print('\n\n') #print(remote_device_id) #print('\n\n\n') #print(Local_device_id) #print('test') #print() local_device_name = Local_device_id.values[0][0] remote_device_list = remote_device_id.values for i in remote_device_list: graph.add_edge(local_device_name, i[0]) draw(graph, with_labels=True) show()
f.write("\n") f.close() fh = open("trash.dat","w") call(["./blossom4","-3", "-x","data.dat", "-w", "output.dat"], stdout=fh) fh.close() result = genfromtxt('output.dat', delimiter=' ', usecols = (0, 1)) result = result[1:] #MINMAXMATCHING END H = MultiGraph() H.add_nodes_from(T.nodes()) H.add_edges_from(T.edges()) for (key, value) in result: H.add_edge(N[int(key)], N[int(value)]) f = open("data.dat", "wb") t = Set() for (i, j) in eulerian_circuit(H): if i in t: continue t.add(i) f.write(str(i) + " ") f.close() fh = open("trash.dat", "w") call(["./exe", 'input.dat'], stdout = fh) fh.close() #the result is t
def graph_from_dataframe( dataframe, threshold_by_percent_unique=0.1, threshold_by_count_unique=None, node_id_columns=[], node_property_columns=[], edge_property_columns=[], node_type_key="type", edge_type_key="type", collapse_edges=True, edge_agg_key="weight", ): """ Build an undirected graph from a pandas dataframe. This function attempts to infer which cells should become nodes based on either: a. what percentage of the column are unique values (defaults to 10%) b. an explicit count of unique values (i.e. any column with 7 unique values or less) c. an explicit list of column keys (i.e. ['employee_id', 'location_code']) Column headers are preserved as node and edge 'types'. By default, this is stored using the key 'type' which is used by some graph import processes but can be reconfigured. This function uses a MultiGraph structure during the build phase so that it is possible to make multiple connections between nodes. By default, at the end of the build phase, the MultiGraph is converted to a Graph and the count of edges between each node-pair is written as a 'weight' property. :param pandas.DataFrame dataframe: A pandas dataframe containing the data to be converted into a graph. :param float threshold_by_percent_unique: A percent value used to determine whether a column should be used to generate nodes based on its cardinality (i.e. in a dataframe with 100 rows, treat any column with 10 or less unique values as a node) :param int threshold_by_count_unique: A numeric value used to determine whether a column should be used to generate nodes based on its cardinality (i.e. if 7 is supplied, treat any column with 7 or less unique values as a node) - supplying a value will take priority over percent_unique :param list node_id_columns: A list of column headers to use for generating nodes. Suppyling any value will take precedence over threshold_by_percent_unique or threshold_by_count_unique. Note: this can cause the size of the graph to expand significantly since every unique value in a column will become a node. :param list node_property_columns: A list of column headers to use for generating properties of nodes. These can include the same column headers used for the node id. :param list edge_property_columns: A list of column headers to use for generating properties of edges. :param str node_type_key: A string that sets the key will be used to preserve the column name as node property (this is useful for importing networkx graphs to databases that distinguish between node 'types' or for visually encoding those types in plots). :param str edge_type_key: A string that sets the key will be used to keep track of edge relationships an 'types' (this is useful for importing networkx graphs to databases that distinguish between edge'types' or for visually encoding those types in plots). Edge type values are automatically set to <node_a_id>_<node_b_id>. :param bool collapse_edges: Graphs are instantiated as a 'MultiGraph' (allow multiple edges between nodes) and then collapsed into a 'Graph' which only has a single edge between any two nodes. Information is preserved by aggregating the count of those edges as a 'weight' value. Set this value to False to return the MultiGraph. Note: this can cause the size of the graph to expand significantly since each row can potentially have n! edges where n is the number of columns in the dataframe. :param str edge_agg_key: A string that sets the key the edge count will be assigned to when edges are aggregated. :returns: A networkx Graph (or MultiGraph if collapse_edges is set to False). """ assert isinstance( dataframe, pd.DataFrame), "{} is not a pandas DataFrame".format(dataframe) M = MultiGraph() # if explicit specification of node_id_columns is provided, use those if len(node_id_columns) > 0: node_columns = node_id_columns else: # otherwise, compute with thresholds based on the dataframe if threshold_by_count_unique: node_columns = sorted([ col for col in dataframe.columns if dataframe[col].nunique() <= threshold_by_count_unique ]) else: node_columns = sorted([ col for col in dataframe.columns if dataframe[col].nunique() / dataframe.shape[0] <= threshold_by_percent_unique # NOQA to preserve meaningful variable names ]) # use the unique values for each node column as node types for node_type in node_columns: M.add_nodes_from([(node, { node_type_key: node_type }) for node in dataframe[node_type].unique()]) # iterate over the rows and generate an edge for each pair of node columns for i, row in dataframe.iterrows(): # assemble the edge properties as a dictionary edge_properties = {k: row[k] for k in edge_property_columns} # iterate over the node_ids in each node_column of the dataframe row node_buffer = [] for node_type in node_columns: node_id = row[node_type] # get a reference to the node and assign any specified properties node = M.nodes[node_id] for k in node_property_columns: # if values are not identical, append with a pipe delimiter if k not in node: node[k] = row[k] elif isinstance(node[k], str) and str(row[k]) not in node[k]: node[k] += "|{}".format(str(row[k])) elif str(row[k]) not in str(node[k]): node[k] = str(node[k]) + "|{}".format(str(row[k])) # build edges using precomputed edge properties for other_node_id, other_node_type in node_buffer: # sort node_type so undirected edges all share the same type ordered_name = "_".join(sorted([node_type, other_node_type])) edge_properties[edge_type_key] = ordered_name M.add_edge(node_id, other_node_id, **edge_properties) # store the node from this column in the buffer for future edges node_buffer.append((node_id, node_type)) if collapse_edges: # convert the MultiGraph to a Graph G = Graph(M) k = edge_agg_key # preserve the edge count as a sum of the weight values for u, v, data in M.edges(data=True): w = data[k] if k in data else 1.0 edge = G[u][v] edge[k] = (w + edge[k]) if k in edge else w return G return M