def update(self, ebunch, attr_dict=None, **attr): # set up attribute dict if attr_dict is None: attr_dict = attr else: try: attr_dict.update(attr) except AttributeError: raise NetworkXError( "The attr_dict argument must be a dictionary.") # process ebunch for e in ebunch: ne = len(e) if ne == 3: u, v, dd = e elif ne == 2: u, v = e try: {v} # is v hashable, i.e. a datadict? except TypeError: dd = v u, v = u else: dd = {} # doesnt need edge_attr_dict_factory else: msg = "Edge tuple %s must be a 2-tuple or 3-tuple." % (e, ) raise NetworkXError(msg) datadict = attr_dict.copy() datadict.update(dd) self._add_edge(u, v, datadict)
def check_vrp(G: DiGraph = None): """Checks if graph is well defined.""" # if G is not a DiGraph if not isinstance(G, DiGraph): raise TypeError( "Input graph must be of type networkx.classes.digraph.DiGraph.") for v in ["Source", "Sink"]: # If Source or Sink is missing if v not in G.nodes(): raise KeyError("Input graph requires Source and Sink nodes.") # If Source has incoming edges if len(list(G.predecessors("Source"))) > 0: raise NetworkXError("Source must have no incoming edges.") # If Sink has outgoing edges if len(list(G.successors("Sink"))) > 0: raise NetworkXError("Sink must have no outgoing edges.") # Roundtrips should always be possible # Missing edges are added with a high cost for v in G.nodes(): if v not in ["Source", "Sink"]: if v not in G.successors("Source"): logger.warning("Source not connected to %s" % v) G.add_edge("Source", v, cost=1e10) if v not in G.predecessors("Sink"): logger.warning("%s not connected to Sink" % v) G.add_edge(v, "Sink", cost=1e10) # If graph is disconnected if not has_path(G, "Source", "Sink"): raise NetworkXError("Source and Sink are not connected.") # If cost is missing for (i, j) in G.edges(): if "cost" not in G.edges[i, j]: raise KeyError("Edge (%s,%s) requires cost attribute" % (i, j))
def _check_vrp(self): """Checks if graph and vrp constraints are consistent.""" # if G is not a DiGraph if not isinstance(self.G, DiGraph): raise TypeError( "Input graph must be of type networkx.classes.digraph.DiGraph." ) for v in ["Source", "Sink"]: # If Source or Sink is missing if v not in self.G.nodes(): raise KeyError("Input graph requires Source and Sink nodes.") # If Source has incoming edges if len(list(self.G.predecessors("Source"))) > 0: raise NetworkXError("Source must have no incoming edges.") # If Sink has outgoing edges if len(list(self.G.successors("Sink"))) > 0: raise NetworkXError("Sink must have no outgoing edges.") # If graph is disconnected if not has_path(self.G, "Source", "Sink"): raise NetworkXError("Source and Sink are not connected.") # If cost is missing for (i, j) in self.G.edges(): if "cost" not in self.G.edges[i, j]: raise KeyError("Edge (%s,%s) requires cost attribute" % (i, j)) # If num_stops/load_capacity/duration are not integers if self.num_stops is not None and (not isinstance(self.num_stops, int) or self.num_stops <= 0): raise TypeError( "Maximum number of stops must be positive integer.") if self.load_capacity is not None and (not isinstance( self.load_capacity, int) or self.load_capacity <= 0): raise TypeError("Load capacity must be positive integer.") if self.duration is not None and (not isinstance(self.duration, int) or self.duration <= 0): raise TypeError("Maximum duration must be positive integer.")
def page_rank(G, alpha=0.85, personalization=None, max_iter=100, tol=1.0e-6, nstart=None, weight='weight', dangling=None): if len(G) == 0: return {} if not G.is_directed(): D = G.to_directed() else: D = G W = nx.stochastic_grap(D, weight=weight) N = W.number_of_nodes() if nstart is None: x = dict.fromkeys(W, 1.0 / N) else: s = float(sum(nstart.values())) x = dict((k, v / s) for k, v in nstart.items()) if personalization is None: p = dict.fromkeys(W, 1.0 / N) else: missing = set(G) - set(personalization) if missing: raise NetworkXError( 'Personalization dictionary must have a value for every node. Missing nodes %s' % missing) s = float(sum(personalization.values())) p = dict((k, v / s) for k, v in personalization.items()) if dangling is None: dangling_weights = p else: missing = set(G) - set(dangling) if missing: raise NetworkXError( 'Dangling node dictionary must have a value for every node. Missing nodes %s' % missing) s = float(sum(dangling.values())) dangling_weights = dict((k, v / s) for k, v in dangling.items()) dangling_nodes = [ n for n in W if W.out_degree(n, weight=weight) == 0.0 ] for _ in range(max_iter): xlast = xx = dict.fromkeys(xlast.keys(), 0) danglesum = alpha * sum(xlast[n] for n in dangling_nodes) for n in x: for nbr in W[n]: x[nbr] += alpha * xlast[n] * W[n][nbr][weight] x[n] += danglesum * dangling_weights[n] + (1.0 - alpha) * p[n] err = sum([abs(x[n] - xlast[n]) for n in x]) if err < N * tol: return x raise NetworkXError( 'Pagerank: power iteration failed to converge in %d iterations.' % max_iter)
def init(g): if isinstance(g, nx.MultiGraph): raise NetworkXError('freeman does not support multigraphs') for n, m in g.edges: if n == m: raise NetworkXError('freeman does not support self loops') for n in g.nodes: if 'pos' not in g.nodes[n]: x = random() y = random() g.nodes[n]['pos'] = (x, y) set_nodeframe(g) set_edgeframe(g)
def _triangles_and_degree_iter(G, nbunch=None): """ Return an iterator of (node, degree, triangles). This double counts triangles so you may want to divide by 2. See degree() and triangles() for definitions and details. """ if G.is_multigraph(): raise NetworkXError("Not defined for multigraphs.") if nbunch is None: nodes_nbrs = G.adj.iteritems() else: nodes_nbrs = ((n, G[n]) for n in G.nbunch_iter(nbunch)) for v, v_nbrs in nodes_nbrs: vs = set(v_nbrs) if v in vs: vs.remove(v) ntriangles = 0 for w in vs: ws = set(G[w]) if w in ws: ws.remove(w) ntriangles += len(vs.intersection(ws)) yield (v, len(vs), ntriangles)
def _add_edge(self, u, v, attr_dict): if not isinstance(attr_dict, Mapping): # Mapping includes dict raise NetworkXError("The attr_dict argument must be a Mapping.") succ = self._mapping pred = self._graph._pred nodes = self._graph._nodes # add nodes u_new = u not in succ v_new = v not in succ if u_new: succ[u] = {} # fixme factory pred[u] = {} # fixme factory nodes[u] = {} if v_new: succ[v] = {} # fixme factory pred[v] = {} # fixme factory nodes[v] = {} # find the edge if not (u_new or v_new): if v in succ[u]: datadict = succ[u][v] datadict.update(attr_dict) return False # not new edge # if not directed check other direction if (not self._graph._directed) and v in pred[u]: datadict = pred[u][v] datadict.update(attr_dict) return False # not new edge # else new edge-- drop out of if # add new edge datadict = attr_dict succ[u][v] = datadict pred[v][u] = datadict return True # new edge
def stochastic_graph(G,copy=True): """Return a right-stochastic representation of G. A right-stochastic graph is a weighted graph in which all of the node (out) neighbors edge weights sum to 1. Parameters ----------- G : graph A networkx graph, must have valid edge weights copy : bool, optional If True make a copy of the graph, otherwise modify original graph """ if not G.weighted: raise NetworkXError("Input to stochastic_graph() must be a weighted graph.") if copy: if G.directed: W=networkx.DiGraph(G) else: W=networkx.Graph(G) else: W=G # reference original graph, no copy for n in W: deg=float(sum(W[n].values())) for p in W[n]: W[n][p]/=deg # also adjust pred entry for consistency # though it is not used in pagerank algorithm if G.directed: W.pred[p][n]/=deg return W
def get_edge_label(self, u, v): """ Returns the edge label of (u,v). INPUT: u,v: vertex labels OUTPUT: label of (u,v) DOCTEST: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.get_edge_label(1,2) Traceback (most recent call last): ... NetworkXError: Edge (1,2) requested via get_edge_label does not exist. """ try: assert(not isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() try: E = self._nxg.edge[u][v] except KeyError: from networkx import NetworkXError raise NetworkXError("Edge (%s,%s) requested via get_edge_label does not exist."%(u,v)) if self._nxg.is_multigraph(): return [ e.get('weight',None) for e in E.itervalues() ] else: return E.get('weight',None)
def _weighted_triangles_and_degree_iter(G, nodes=None, weight='weight'): """ Return an iterator of (node, degree, weighted_triangles). Used for weighted clustering. """ if G.is_multigraph(): raise NetworkXError("Not defined for multigraphs.") if weight is None or G.edges()==[]: max_weight=1.0 else: max_weight=float(max(d.get(weight,1.0) for u,v,d in G.edges(data=True))) if nodes is None: nodes_nbrs = G.adj.items() else: nodes_nbrs= ( (n,G[n]) for n in G.nbunch_iter(nodes) ) for i,nbrs in nodes_nbrs: inbrs=set(nbrs)-set([i]) weighted_triangles=0.0 seen=set() for j in inbrs: wij=G[i][j].get(weight,1.0)/max_weight seen.add(j) jnbrs=set(G[j])-seen # this keeps from double counting for k in inbrs&jnbrs: wjk=G[j][k].get(weight,1.0)/max_weight wki=G[i][k].get(weight,1.0)/max_weight weighted_triangles+=(wij*wjk*wki)**(1.0/3.0) yield (i,len(inbrs),weighted_triangles*2)
def barabasi_albert_graph(n, m, **kwargs): """ Generate a random graph using the Barabasi-Albert preferential attachment model. **Args**: * ``n`` (int): the number of nodes to add to the graph * ``m`` (int): the number of edges a new node will add to the graph **KwArgs**: * ``directed [=False]`` (boolean): whether to build the graph directed. If ``True``, then the ``m`` edges created by a node upon its creation are instantiated as out-edges. All others are in-edges to that node. * ``seed [=-1]`` (int): a seed for the random number generator * ``graph [=None]`` (:py:class:`networkx.Graph` or :py:class:`networkx.DiGraph`): this is the actual graph instance to populate. It must be empty and its directionality must agree with the value of ``directed``. **Returns**: :py:class:`networkx.Graph` or :py:class:`networkx.DiGraph`. The graph generated. If ``directed = True``, then a :py:class:`networkx.DiGraph` will be returned. .. note:: Source: A. L. Barabasi and R. Albert "Emergence of scaling in random networks", Science 286, pp 509-512, 1999. """ seed = kwargs.pop('seed', None) directed = kwargs.pop('directed', False) graph = kwargs.pop('graph', None) if graph is not None: if len(graph) > 0: raise NetworkXError('the graph must be empty, if provided') if type(graph) == DiGraph != directed: raise NetworkXError('graph and directed arguments must agree') else: if directed: graph = DiGraph() else: graph = Graph() if len(kwargs) > 0: raise NetworkXError('Unknown arguments: %s' % ', '.join(kwargs.keys())) if seed is None: seed = -1 if not directed: return __inner_barabasi_albert_udir(n, m, seed, graph) else: return __inner_barabasi_albert_dir(n, m, seed, graph)
def _add_edge(self, u, v, k, attr_dict): if not isinstance(attr_dict, Mapping): # Mapping includes dict raise NetworkXError( "The attr_dict argument must be a Mapping.") succ = self._mapping pred = self._graph._pred nodes = self._graph._nodes # add nodes u_new = u not in succ v_new = v not in succ if u_new: succ[u] = {} # fixme factory pred[u] = {} # fixme factory nodes[u] = {} if v_new: succ[v] = {} # fixme factory pred[v] = {} # fixme factory nodes[v] = {} # find the edge if not (u_new or v_new): new_succ = new_pred = False if v in succ[u]: skeydict = succ[u][v] if k in skeydict: datadict = skeydict[k] datadict.update(attr_dict) return False # not new edge # add edge to keydict if k is None: k = len(skeydict) while k in skeydict: k += 1 datadict = attr_dict skeydict[k] = datadict return True # New edge # if not directed check other direction if (not self._graph._directed) and v in pred[u]: pkeydict = pred[u][v] if k in pkeydict: datadict = pkeydict[k] datadict.update(attr_dict) return False # not new edge # add edge to keydict if k is None: k = len(pkeydict) while k in pkeydict: k += 1 datadict = attr_dict pkeydict[k] = datadict return True # New edge # else new edge-- drop out of if # add new edge k = 0 if k is None else k datadict = attr_dict keydict = {k: datadict} # fixme factory succ[u][v] = keydict pred[v][u] = keydict return True # new edge
def read_mtx(path: str, node_type=str, edge_key_type=int) -> Union[Graph, DiGraph]: reader = MatrixMarketReader( node_type=node_type, edge_key_type=edge_key_type ) glist: List[Union[Graph, DiGraph]] = [reader(path=path)] if len(glist) == 0: raise NetworkXError('file not successfully read as mtx') return glist[0]
def erdos_renyi_graph(n, p, **kwargs): """ Generate an Erdos-Renyi graph. **Args**: * ``num_nodes`` (int): the number of nodes to populate the graph with. * ``p`` (0 <= float <= 1): the probability p given to each edge's existence. **KwArgs**: * ``directed [=False]`` (boolean): indicates whether the network generated is directed. * ``self_loops [=False]`` (boolean): indicates whether self-loops are permitted in the generated graph. * ``seed [=-1]`` (int): the seed provided to the random generator used to drive the graph construction. * ``graph [=None]`` (:py:class:`zen.Graph` or :py:class:`zen.DiGraph`): this is the actual graph instance to populate. It must be empty and its directionality must agree with the value of ``directed``. """ directed = kwargs.pop('directed', False) self_loops = kwargs.pop('self_loops', False) seed = kwargs.pop('seed', None) graph = kwargs.pop('graph', None) if graph is not None: if len(graph) > 0: raise NetworkXError('the graph must be empty, if provided') if isinstance(graph, DiGraph) != directed: raise NetworkXError('graph and directed arguments must agree') else: if directed: graph = DiGraph() else: graph = Graph() if p > 1 or p < 0: msg = f"NetworkXError p={p} is not in [0,1]." raise NetworkXError(msg) if len(kwargs) > 0: raise NetworkXError('Unknown arguments: %s' % ', '.join(kwargs.keys())) if seed is None: seed = -1 if directed: return __erdos_renyi_directed(n, p, self_loops, seed, graph) else: return __erdos_renyi_undirected(n, p, self_loops, seed, graph)
def add(self, u, v, attr_dict=None, **attr): if attr_dict is None: attr_dict = attr else: try: attr_dict.update(attr) except AttributeError: raise NetworkXError( "The attr_dict argument must be a dictionary.") return self._add_edge(u, v, attr_dict)
def discard(self, ekeys): try: u, v = ekeys except TypeError: raise NetworkXError('bad edge key: use edge key = (u,v)') try: del self._graph._succ[u][v] del self._graph._pred[v][u] return True except KeyError: return False
def __getitem__(self, ekeys): try: u, v = ekeys except TypeError: raise NetworkXError('bad edge key: use edge key = (u,v)') try: return self._mapping[u][v] except KeyError: if self._graph._directed: raise return self._graph._pred[u][v]
def small_world_graph(n, q, p, graph=None): ''' q must be even ''' if graph is not None and not isinstance(graph, Graph): raise NetworkXError('The graph provided must be undirected') if graph is not None and len(graph) > 0: raise NetworkXError('the graph must be empty, if provided') if type(q) != int: raise NetworkXError('q must be an integer') if q % 2 != 0: raise NetworkXError('q must be even') if p > 1 or p < 0: msg = f"NetworkXError p={p} is not in [0,1]." raise NetworkXError(msg) G = graph if G is None: G = Graph() for i in range(n): G.add_node(i) # add the regular edges for u in range(n): for v in range(u + 1, int(u + 1 + q / 2)): v = v % n G.add_edge(u, v) # add the random edges for u in range(n): for v in range(u + 1, n): if not G.has_edge(u, v): if random.random() <= p: G.add_edge(u, v) return G
def __init__(self, data=None, **attr): self._nodes = nd = {} # fixme factory self._mapping = nd self._succ = succ = {} # fixme factory self._pred = pred = {} # fixme factory self._directed = attr.pop("directed", False) self._multigraph = attr.pop("multigraph", False) if self._multigraph: myEdges = MultiEdges myAdjacency = MultiAdjacency myAtlasUnion = MultiAtlasUnion else: myEdges = Edges myAdjacency = Adjacency myAtlasUnion = AtlasUnion # Interface self.n = Nodes(self) self.e = myEdges(self) self.a = myAdjacency(myAtlasUnion(self._succ, self._pred)) if self._directed: self.su = myAdjacency(self._succ) self.pr = myAdjacency(self._pred) else: self.su = self.a self.pr = self.a # graph data attributes self.data = attr # Handle input if data is None: return if hasattr(data, "_nodes"): # new datadicts but with same info (containers in datadicts same) self.data.update(data.data) for n in data.n: self.n.update(data.n.items()) self.e.update(data.e.items()) elif len(data) == 2: try: V,E = data self.n.update(V) self.e.update(E) except: # something else d=self.data.copy() convert.to_networkx_graph(data, create_using=self) self.data.update(d) else: msg = ("Graph argument must be a graph " "or (V, E)-tuple of nodes and edges.") raise NetworkXError(msg)
def _check_vrp(self): """Checks if graph is well defined.""" # if G is not a DiGraph if not isinstance(self.G, DiGraph): raise TypeError( "Input graph must be of type networkx.classes.digraph.DiGraph." ) for v in ["Source", "Sink"]: # If Source or Sink is missing if v not in self.G.nodes(): raise KeyError("Input graph requires Source and Sink nodes.") # If Source has incoming edges if len(list(self.G.predecessors("Source"))) > 0: raise NetworkXError("Source must have no incoming edges.") # If Sink has outgoing edges if len(list(self.G.successors("Sink"))) > 0: raise NetworkXError("Sink must have no outgoing edges.") # If graph is disconnected if not has_path(self.G, "Source", "Sink"): raise NetworkXError("Source and Sink are not connected.") # If cost is missing for (i, j) in self.G.edges(): if "cost" not in self.G.edges[i, j]: raise KeyError("Edge (%s,%s) requires cost attribute" % (i, j))
def reciprocity(G, nodes=None): """Compute the reciprocity in a directed graph. The reciprocity of a directed graph is defined as the ratio of the number of edges pointing in both directions to the total number of edges in the graph. Formally, :math:`r = |{(u,v) \in G|(v,u) \in G}| / |{(u,v) \in G}|`. The reciprocity of a single node u is defined similarly, it is the ratio of the number of edges in both directions to the total number of edges attached to node u. Parameters ---------- G : graph A networkx directed graph nodes : container of nodes, optional (default=None, in such case return the reciprocity of the whole graph.) Compute reciprocity for nodes in this container. Returns ------- out : dictionary Reciprocity keyed by node label. Notes ----- The reciprocity is not defined for isolated nodes. In such cases this function will return None. """ # If `nodes` is not specified, calculate the reciprocity of the graph. if nodes is None: return overall_reciprocity(G) # If `nodes` represents a single node in the graph, return only its # reciprocity. if nodes in G: reciprocity = next(_reciprocity_iter(G,nodes))[1] if reciprocity is None: raise NetworkXError('Not defined for isolated nodes.') else: return reciprocity # Otherwise, `nodes` represents an iterable of nodes, so return a # dictionary mapping node to its reciprocity. return dict(_reciprocity_iter(G,nodes))
def triangles(G, nbunch=None, with_labels=False): """Compute the number of triangles. Finds the number of triangles that include a node as one of the vertices. Parameters ---------- G : graph A networkx graph nbunch : container of nodes, optional Compute triangles for nodes in nbunch. The default is all nodes in G. with_labels: bool, optional If True return a dictionary keyed by node label. Returns ------- out : list or dictionary Number of trianges Examples -------- >>> G=nx.complete_graph(5) >>> print nx.triangles(G,0) 6 >>> print nx.triangles(G,with_labels=True) {0: 6, 1: 6, 2: 6, 3: 6, 4: 6} >>> print nx.triangles(G,(0,1)) [6, 6] Notes ----- When computing triangles for the entire graph each triangle is counted three times, once at each node. Self loops are ignored. """ if G.is_directed(): raise NetworkXError("triangles() is not defined for directed graphs.") if with_labels: return dict( (v, t / 2) for v, d, t in _triangles_and_degree_iter(G, nbunch)) elif nbunch in G: return _triangles_and_degree_iter( G, nbunch).next()[2] / 2 # return single value return [t / 2 for n, d, t in _triangles_and_degree_iter(G, nbunch)]
def add(self, n, attr_dict=None, **attr): if attr_dict is None: attr_dict = attr else: try: attr_dict.update(attr) except AttributeError: msg = "The attr_dict argument must be a dictionary." raise NetworkXError(msg) nodes = self._mapping if n not in nodes: self._graph._succ[n] = {} # FIXME factory self._graph._pred[n] = {} # FIXME factory nodes[n] = attr_dict return True # new node # update attr even if node already exists nodes[n].update(attr_dict) return False # not new node
def overall_reciprocity(G): """Compute the reciprocity for the whole graph. See the doc of reciprocity for the definition. Parameters ---------- G : graph A networkx graph """ n_all_edge = G.number_of_edges() n_overlap_edge = (n_all_edge - G.to_undirected().number_of_edges()) * 2 if n_all_edge == 0: raise NetworkXError("Not defined for empty graphs") return float(n_overlap_edge) / float(n_all_edge)
def remove_edge(self, u, v, key=None): """Remove the edge between u and v. Parameters ---------- u,v: nodes Remove edge or edges between nodes u and v. key : hashable identifier, optional (default= None) Used to distinguish multiedges between a pair of nodes. If None, remove all edges between u and v. Raises ------ NetworkXError If there is not an edge between u and v. See Also -------- remove_edges_from : remove a collection of edges Examples -------- >>> G = nx.MultiGraph() # or MultiDiGraph, etc >>> G.add_path([0,1,2,3]) >>> G.remove_edge(0,1) >>> e = (1,2) >>> G.remove_edge(*e) # unpacks e from an edge tuple >>> G.remove_edge(2,3,key=0) # identify an individual edge with key """ if key is None: super(MultiGraph, self).remove_edge(u,v) else: try: d=self.adj[u][v] # remove the edge with specified data del d[key] if len(d)==0: # remove the key entries if last edge del self.adj[u][v] if u!=v: # check for selfloop del self.adj[v][u] except (KeyError,ValueError): raise NetworkXError( "The edge %s-%s with key %s not in the graph."%(u,v,key))
def triangles(G, nodes=None): """Compute the number of triangles. Finds the number of triangles that include a node as one vertex. Parameters ---------- G : graph A networkx graph nodes : container of nodes, optional (default= all nodes in G) Compute triangles for nodes in this container. Returns ------- out : dictionary Number of triangles keyed by node label. Examples -------- >>> G=nx.complete_graph(5) >>> print(nx.triangles(G,0)) 6 >>> print(nx.triangles(G)) {0: 6, 1: 6, 2: 6, 3: 6, 4: 6} >>> print(list(nx.triangles(G,(0,1)).values())) [6, 6] Notes ----- When computing triangles for the entire graph each triangle is counted three times, once at each node. Self loops are ignored. """ if G.is_directed(): raise NetworkXError("triangles() is not defined for directed graphs.") if nodes in G: # return single value return next(_triangles_and_degree_iter(G, nodes))[2] // 2 return dict( (v, t // 2) for v, d, t in _triangles_and_degree_iter(G, nodes))
def add_edges_from(self, ebunch_to_add, **attr): """Add all the edges in ebunch_to_add. Parameters ---------- ebunch_to_add : container of edges Each edge given in the container will be added to the interval graph. The edges must be given as as 4-tuples (u, v, being, end). Both begin and end must be orderable and the same type across all edges. attr : keyword arguments, optional Edge data (or labels or objects) can be assigned using keyword arguments. See Also -------- add_edge : add a single edge Notes ----- Adding the same edge (with the same interval) twice has no effect but any edge data will be updated when each duplicate edge is added. Examples -------- >>> G = dnx.IntervalDiGraph() >>> G.add_edges_from([(1, 2, 3, 10), (2, 4, 1, 11)]) # using a list of edge tuples Associate data to edges >>> G.add_edges_from([(1, 2, 3, 10), (2, 4, 1, 11)], weight=3) >>> G.add_edges_from([(3, 4, 2, 19), (1, 4, 1, 3)], label='WN2898') """ for e in ebunch_to_add: if len(e) != 4: raise NetworkXError( "Edge tuple {0} must be a 4-tuple.".format(e)) self.add_edge(e[0], e[1], e[2], e[3], **attr)
def discard(self, ekeys): try: u,v,k = ekeys except (TypeError, ValueError): try: u,v = ekeys except (TypeError, ValueError): raise NetworkXError('bad edge key: %s' % (ekeys,)) if u in self._graph._succ and v in self._graph._succ[u]: keydict = self._graph._succ[u][v] keydict.popitem() if len(keydict) == 0: del self._graph._succ[u][v] del self._graph._pred[v][u] return True elif self._graph._directed is False\ and v in self._graph._pred\ and u in self._graph._pred[v]: keydict = self._graph._pred[u][v] keydict.popitem() if len(keydict) == 0: del self._graph._pred[u][v] del self._graph._succ[v][u] return True return False # Didn't remove edge try: del self._graph._succ[u][v] del self._graph._pred[v][u] return True except KeyError: if self._graph._directed is True: return False try: del self._graph._pred[u][v] del self._graph._succ[v][u] return True except KeyError: return False
def __getitem__(self, ekeys): try: u,v,k = ekeys except (TypeError, ValueError): try: u,v = ekeys k = None except (TypeError, ValueError): raise NetworkXError('bad edge key: %s' % (ekeys,)) if k is None: try: keydict = self._mapping[u][v] except KeyError: if self._graph._directed: raise keydict = self._graph._pred[u][v] k = next(iter(keydict)) return keydict[k] try: return self._mapping[u][v][k] except KeyError: if self._graph._directed: raise return self._graph._pred[u][v][k]
def remove_edge(self, u, v, key=None): """Remove an edge between u and v. Parameters ---------- u, v : nodes Remove an edge between nodes u and v. key : hashable identifier, optional (default=None) Used to distinguish multiple edges between a pair of nodes. If None remove a single (arbitrary) edge between u and v. Raises ------ NetworkXError If there is not an edge between u and v, or if there is no edge with the specified key. See Also -------- remove_edges_from : remove a collection of edges Examples -------- >>> G = nx.MultiGraph() >>> nx.add_path(G, [0, 1, 2, 3]) >>> G.remove_edge(0,1) >>> e = (1,2) >>> G.remove_edge(*e) # unpacks e from an edge tuple For multiple edges >>> G = nx.MultiGraph() # or MultiDiGraph, etc >>> G.add_edges_from([(1,2),(1,2),(1,2)]) >>> G.remove_edge(1,2) # remove a single (arbitrary) edge For edges with keys >>> G = nx.MultiGraph() # or MultiDiGraph, etc >>> G.add_edge(1,2,key='first') >>> G.add_edge(1,2,key='second') >>> G.remove_edge(1,2,key='second') """ try: d = self.adj[u][v] except (KeyError): raise NetworkXError("The edge %s-%s is not in the graph." % (u, v)) # remove the edge with specified data if key is None: d.popitem() else: try: del d[key] except (KeyError): raise NetworkXError( "The edge %s-%s with key %s is not in the graph." % (u, v, key)) if len(d) == 0: # remove the key entries if last edge del self.adj[u][v] if u != v: # check for selfloop del self.adj[v][u]