comparison env/lib/python3.7/site-packages/networkx/classes/multidigraph.py @ 0:26e78fe6e8c4 draft

"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author shellac
date Sat, 02 May 2020 07:14:21 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:26e78fe6e8c4
1 # Copyright (C) 2004-2019 by
2 # Aric Hagberg <hagberg@lanl.gov>
3 # Dan Schult <dschult@colgate.edu>
4 # Pieter Swart <swart@lanl.gov>
5 # All rights reserved.
6 # BSD license.
7 #
8 # Authors: Aric Hagberg <hagberg@lanl.gov>
9 # Dan Schult <dschult@colgate.edu>
10 # Pieter Swart <swart@lanl.gov>
11 """Base class for MultiDiGraph."""
12 from copy import deepcopy
13
14 import networkx as nx
15 from networkx.classes.graph import Graph # for doctests
16 from networkx.classes.digraph import DiGraph
17 from networkx.classes.multigraph import MultiGraph
18 from networkx.classes.coreviews import MultiAdjacencyView
19 from networkx.classes.reportviews import OutMultiEdgeView, InMultiEdgeView, \
20 DiMultiDegreeView, OutMultiDegreeView, InMultiDegreeView
21 from networkx.exception import NetworkXError
22
23
24 class MultiDiGraph(MultiGraph, DiGraph):
25 """A directed graph class that can store multiedges.
26
27 Multiedges are multiple edges between two nodes. Each edge
28 can hold optional data or attributes.
29
30 A MultiDiGraph holds directed edges. Self loops are allowed.
31
32 Nodes can be arbitrary (hashable) Python objects with optional
33 key/value attributes. By convention `None` is not used as a node.
34
35 Edges are represented as links between nodes with optional
36 key/value attributes.
37
38 Parameters
39 ----------
40 incoming_graph_data : input graph (optional, default: None)
41 Data to initialize graph. If None (default) an empty
42 graph is created. The data can be any format that is supported
43 by the to_networkx_graph() function, currently including edge list,
44 dict of dicts, dict of lists, NetworkX graph, NumPy matrix
45 or 2d ndarray, SciPy sparse matrix, or PyGraphviz graph.
46
47 attr : keyword arguments, optional (default= no attributes)
48 Attributes to add to graph as key=value pairs.
49
50 See Also
51 --------
52 Graph
53 DiGraph
54 MultiGraph
55 OrderedMultiDiGraph
56
57 Examples
58 --------
59 Create an empty graph structure (a "null graph") with no nodes and
60 no edges.
61
62 >>> G = nx.MultiDiGraph()
63
64 G can be grown in several ways.
65
66 **Nodes:**
67
68 Add one node at a time:
69
70 >>> G.add_node(1)
71
72 Add the nodes from any container (a list, dict, set or
73 even the lines from a file or the nodes from another graph).
74
75 >>> G.add_nodes_from([2, 3])
76 >>> G.add_nodes_from(range(100, 110))
77 >>> H = nx.path_graph(10)
78 >>> G.add_nodes_from(H)
79
80 In addition to strings and integers any hashable Python object
81 (except None) can represent a node, e.g. a customized node object,
82 or even another Graph.
83
84 >>> G.add_node(H)
85
86 **Edges:**
87
88 G can also be grown by adding edges.
89
90 Add one edge,
91
92 >>> key = G.add_edge(1, 2)
93
94 a list of edges,
95
96 >>> keys = G.add_edges_from([(1, 2), (1, 3)])
97
98 or a collection of edges,
99
100 >>> keys = G.add_edges_from(H.edges)
101
102 If some edges connect nodes not yet in the graph, the nodes
103 are added automatically. If an edge already exists, an additional
104 edge is created and stored using a key to identify the edge.
105 By default the key is the lowest unused integer.
106
107 >>> keys = G.add_edges_from([(4,5,dict(route=282)), (4,5,dict(route=37))])
108 >>> G[4]
109 AdjacencyView({5: {0: {}, 1: {'route': 282}, 2: {'route': 37}}})
110
111 **Attributes:**
112
113 Each graph, node, and edge can hold key/value attribute pairs
114 in an associated attribute dictionary (the keys must be hashable).
115 By default these are empty, but can be added or changed using
116 add_edge, add_node or direct manipulation of the attribute
117 dictionaries named graph, node and edge respectively.
118
119 >>> G = nx.MultiDiGraph(day="Friday")
120 >>> G.graph
121 {'day': 'Friday'}
122
123 Add node attributes using add_node(), add_nodes_from() or G.nodes
124
125 >>> G.add_node(1, time='5pm')
126 >>> G.add_nodes_from([3], time='2pm')
127 >>> G.nodes[1]
128 {'time': '5pm'}
129 >>> G.nodes[1]['room'] = 714
130 >>> del G.nodes[1]['room'] # remove attribute
131 >>> list(G.nodes(data=True))
132 [(1, {'time': '5pm'}), (3, {'time': '2pm'})]
133
134 Add edge attributes using add_edge(), add_edges_from(), subscript
135 notation, or G.edges.
136
137 >>> key = G.add_edge(1, 2, weight=4.7 )
138 >>> keys = G.add_edges_from([(3, 4), (4, 5)], color='red')
139 >>> keys = G.add_edges_from([(1,2,{'color':'blue'}), (2,3,{'weight':8})])
140 >>> G[1][2][0]['weight'] = 4.7
141 >>> G.edges[1, 2, 0]['weight'] = 4
142
143 Warning: we protect the graph data structure by making `G.edges[1, 2]` a
144 read-only dict-like structure. However, you can assign to attributes
145 in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change
146 data attributes: `G.edges[1, 2]['weight'] = 4`
147 (For multigraphs: `MG.edges[u, v, key][name] = value`).
148
149 **Shortcuts:**
150
151 Many common graph features allow python syntax to speed reporting.
152
153 >>> 1 in G # check if node in graph
154 True
155 >>> [n for n in G if n<3] # iterate through nodes
156 [1, 2]
157 >>> len(G) # number of nodes in graph
158 5
159 >>> G[1] # adjacency dict-like view keyed by neighbor to edge attributes
160 AdjacencyView({2: {0: {'weight': 4}, 1: {'color': 'blue'}}})
161
162 Often the best way to traverse all edges of a graph is via the neighbors.
163 The neighbors are available as an adjacency-view `G.adj` object or via
164 the method `G.adjacency()`.
165
166 >>> for n, nbrsdict in G.adjacency():
167 ... for nbr, keydict in nbrsdict.items():
168 ... for key, eattr in keydict.items():
169 ... if 'weight' in eattr:
170 ... # Do something useful with the edges
171 ... pass
172
173 But the edges() method is often more convenient:
174
175 >>> for u, v, keys, weight in G.edges(data='weight', keys=True):
176 ... if weight is not None:
177 ... # Do something useful with the edges
178 ... pass
179
180 **Reporting:**
181
182 Simple graph information is obtained using methods and object-attributes.
183 Reporting usually provides views instead of containers to reduce memory
184 usage. The views update as the graph is updated similarly to dict-views.
185 The objects `nodes, `edges` and `adj` provide access to data attributes
186 via lookup (e.g. `nodes[n], `edges[u, v]`, `adj[u][v]`) and iteration
187 (e.g. `nodes.items()`, `nodes.data('color')`,
188 `nodes.data('color', default='blue')` and similarly for `edges`)
189 Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`.
190
191 For details on these and other miscellaneous methods, see below.
192
193 **Subclasses (Advanced):**
194
195 The MultiDiGraph class uses a dict-of-dict-of-dict-of-dict structure.
196 The outer dict (node_dict) holds adjacency information keyed by node.
197 The next dict (adjlist_dict) represents the adjacency information and holds
198 edge_key dicts keyed by neighbor. The edge_key dict holds each edge_attr
199 dict keyed by edge key. The inner dict (edge_attr_dict) represents
200 the edge data and holds edge attribute values keyed by attribute names.
201
202 Each of these four dicts in the dict-of-dict-of-dict-of-dict
203 structure can be replaced by a user defined dict-like object.
204 In general, the dict-like features should be maintained but
205 extra features can be added. To replace one of the dicts create
206 a new graph class by changing the class(!) variable holding the
207 factory for that dict-like structure. The variable names are
208 node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory,
209 adjlist_outer_dict_factory, edge_key_dict_factory, edge_attr_dict_factory
210 and graph_attr_dict_factory.
211
212 node_dict_factory : function, (default: dict)
213 Factory function to be used to create the dict containing node
214 attributes, keyed by node id.
215 It should require no arguments and return a dict-like object
216
217 node_attr_dict_factory: function, (default: dict)
218 Factory function to be used to create the node attribute
219 dict which holds attribute values keyed by attribute name.
220 It should require no arguments and return a dict-like object
221
222 adjlist_outer_dict_factory : function, (default: dict)
223 Factory function to be used to create the outer-most dict
224 in the data structure that holds adjacency info keyed by node.
225 It should require no arguments and return a dict-like object.
226
227 adjlist_inner_dict_factory : function, (default: dict)
228 Factory function to be used to create the adjacency list
229 dict which holds multiedge key dicts keyed by neighbor.
230 It should require no arguments and return a dict-like object.
231
232 edge_key_dict_factory : function, (default: dict)
233 Factory function to be used to create the edge key dict
234 which holds edge data keyed by edge key.
235 It should require no arguments and return a dict-like object.
236
237 edge_attr_dict_factory : function, (default: dict)
238 Factory function to be used to create the edge attribute
239 dict which holds attribute values keyed by attribute name.
240 It should require no arguments and return a dict-like object.
241
242 graph_attr_dict_factory : function, (default: dict)
243 Factory function to be used to create the graph attribute
244 dict which holds attribute values keyed by attribute name.
245 It should require no arguments and return a dict-like object.
246
247 Typically, if your extension doesn't impact the data structure all
248 methods will inherited without issue except: `to_directed/to_undirected`.
249 By default these methods create a DiGraph/Graph class and you probably
250 want them to create your extension of a DiGraph/Graph. To facilitate
251 this we define two class variables that you can set in your subclass.
252
253 to_directed_class : callable, (default: DiGraph or MultiDiGraph)
254 Class to create a new graph structure in the `to_directed` method.
255 If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used.
256
257 to_undirected_class : callable, (default: Graph or MultiGraph)
258 Class to create a new graph structure in the `to_undirected` method.
259 If `None`, a NetworkX class (Graph or MultiGraph) is used.
260
261 Examples
262 --------
263
264 Please see :mod:`~networkx.classes.ordered` for examples of
265 creating graph subclasses by overwriting the base class `dict` with
266 a dictionary-like object.
267 """
268 # node_dict_factory = dict # already assigned in Graph
269 # adjlist_outer_dict_factory = dict
270 # adjlist_inner_dict_factory = dict
271 edge_key_dict_factory = dict
272 # edge_attr_dict_factory = dict
273
274 def __init__(self, incoming_graph_data=None, **attr):
275 """Initialize a graph with edges, name, or graph attributes.
276
277 Parameters
278 ----------
279 incoming_graph_data : input graph
280 Data to initialize graph. If incoming_graph_data=None (default)
281 an empty graph is created. The data can be an edge list, or any
282 NetworkX graph object. If the corresponding optional Python
283 packages are installed the data can also be a NumPy matrix
284 or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph.
285
286 attr : keyword arguments, optional (default= no attributes)
287 Attributes to add to graph as key=value pairs.
288
289 See Also
290 --------
291 convert
292
293 Examples
294 --------
295 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc
296 >>> G = nx.Graph(name='my graph')
297 >>> e = [(1, 2), (2, 3), (3, 4)] # list of edges
298 >>> G = nx.Graph(e)
299
300 Arbitrary graph attribute pairs (key=value) may be assigned
301
302 >>> G = nx.Graph(e, day="Friday")
303 >>> G.graph
304 {'day': 'Friday'}
305
306 """
307 self.edge_key_dict_factory = self.edge_key_dict_factory
308 DiGraph.__init__(self, incoming_graph_data, **attr)
309
310 @property
311 def adj(self):
312 """Graph adjacency object holding the neighbors of each node.
313
314 This object is a read-only dict-like structure with node keys
315 and neighbor-dict values. The neighbor-dict is keyed by neighbor
316 to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets
317 the color of the edge `(3, 2, 0)` to `"blue"`.
318
319 Iterating over G.adj behaves like a dict. Useful idioms include
320 `for nbr, datadict in G.adj[n].items():`.
321
322 The neighbor information is also provided by subscripting the graph.
323 So `for nbr, foovalue in G[node].data('foo', default=1):` works.
324
325 For directed graphs, `G.adj` holds outgoing (successor) info.
326 """
327 return MultiAdjacencyView(self._succ)
328
329 @property
330 def succ(self):
331 """Graph adjacency object holding the successors of each node.
332
333 This object is a read-only dict-like structure with node keys
334 and neighbor-dict values. The neighbor-dict is keyed by neighbor
335 to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets
336 the color of the edge `(3, 2, 0)` to `"blue"`.
337
338 Iterating over G.adj behaves like a dict. Useful idioms include
339 `for nbr, datadict in G.adj[n].items():`.
340
341 The neighbor information is also provided by subscripting the graph.
342 So `for nbr, foovalue in G[node].data('foo', default=1):` works.
343
344 For directed graphs, `G.succ` is identical to `G.adj`.
345 """
346 return MultiAdjacencyView(self._succ)
347
348 @property
349 def pred(self):
350 """Graph adjacency object holding the predecessors of each node.
351
352 This object is a read-only dict-like structure with node keys
353 and neighbor-dict values. The neighbor-dict is keyed by neighbor
354 to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets
355 the color of the edge `(3, 2, 0)` to `"blue"`.
356
357 Iterating over G.adj behaves like a dict. Useful idioms include
358 `for nbr, datadict in G.adj[n].items():`.
359 """
360 return MultiAdjacencyView(self._pred)
361
362 def add_edge(self, u_for_edge, v_for_edge, key=None, **attr):
363 """Add an edge between u and v.
364
365 The nodes u and v will be automatically added if they are
366 not already in the graph.
367
368 Edge attributes can be specified with keywords or by directly
369 accessing the edge's attribute dictionary. See examples below.
370
371 Parameters
372 ----------
373 u_for_edge, v_for_edge : nodes
374 Nodes can be, for example, strings or numbers.
375 Nodes must be hashable (and not None) Python objects.
376 key : hashable identifier, optional (default=lowest unused integer)
377 Used to distinguish multiedges between a pair of nodes.
378 attr_dict : dictionary, optional (default= no attributes)
379 Dictionary of edge attributes. Key/value pairs will
380 update existing data associated with the edge.
381 attr : keyword arguments, optional
382 Edge data (or labels or objects) can be assigned using
383 keyword arguments.
384
385 Returns
386 -------
387 The edge key assigned to the edge.
388
389 See Also
390 --------
391 add_edges_from : add a collection of edges
392
393 Notes
394 -----
395 To replace/update edge data, use the optional key argument
396 to identify a unique edge. Otherwise a new edge will be created.
397
398 NetworkX algorithms designed for weighted graphs cannot use
399 multigraphs directly because it is not clear how to handle
400 multiedge weights. Convert to Graph using edge attribute
401 'weight' to enable weighted graph algorithms.
402
403 Default keys are generated using the method `new_edge_key()`.
404 This method can be overridden by subclassing the base class and
405 providing a custom `new_edge_key()` method.
406
407 Examples
408 --------
409 The following all add the edge e=(1, 2) to graph G:
410
411 >>> G = nx.MultiDiGraph()
412 >>> e = (1, 2)
413 >>> key = G.add_edge(1, 2) # explicit two-node form
414 >>> G.add_edge(*e) # single edge as tuple of two nodes
415 1
416 >>> G.add_edges_from( [(1, 2)] ) # add edges from iterable container
417 [2]
418
419 Associate data to edges using keywords:
420
421 >>> key = G.add_edge(1, 2, weight=3)
422 >>> key = G.add_edge(1, 2, key=0, weight=4) # update data for key=0
423 >>> key = G.add_edge(1, 3, weight=7, capacity=15, length=342.7)
424
425 For non-string attribute keys, use subscript notation.
426
427 >>> ekey = G.add_edge(1, 2)
428 >>> G[1][2][0].update({0: 5})
429 >>> G.edges[1, 2, 0].update({0: 5})
430 """
431 u, v = u_for_edge, v_for_edge
432 # add nodes
433 if u not in self._succ:
434 self._succ[u] = self.adjlist_inner_dict_factory()
435 self._pred[u] = self.adjlist_inner_dict_factory()
436 self._node[u] = self.node_attr_dict_factory()
437 if v not in self._succ:
438 self._succ[v] = self.adjlist_inner_dict_factory()
439 self._pred[v] = self.adjlist_inner_dict_factory()
440 self._node[v] = self.node_attr_dict_factory()
441 if key is None:
442 key = self.new_edge_key(u, v)
443 if v in self._succ[u]:
444 keydict = self._adj[u][v]
445 datadict = keydict.get(key, self.edge_key_dict_factory())
446 datadict.update(attr)
447 keydict[key] = datadict
448 else:
449 # selfloops work this way without special treatment
450 datadict = self.edge_attr_dict_factory()
451 datadict.update(attr)
452 keydict = self.edge_key_dict_factory()
453 keydict[key] = datadict
454 self._succ[u][v] = keydict
455 self._pred[v][u] = keydict
456 return key
457
458 def remove_edge(self, u, v, key=None):
459 """Remove an edge between u and v.
460
461 Parameters
462 ----------
463 u, v : nodes
464 Remove an edge between nodes u and v.
465 key : hashable identifier, optional (default=None)
466 Used to distinguish multiple edges between a pair of nodes.
467 If None remove a single (arbitrary) edge between u and v.
468
469 Raises
470 ------
471 NetworkXError
472 If there is not an edge between u and v, or
473 if there is no edge with the specified key.
474
475 See Also
476 --------
477 remove_edges_from : remove a collection of edges
478
479 Examples
480 --------
481 >>> G = nx.MultiDiGraph()
482 >>> nx.add_path(G, [0, 1, 2, 3])
483 >>> G.remove_edge(0, 1)
484 >>> e = (1, 2)
485 >>> G.remove_edge(*e) # unpacks e from an edge tuple
486
487 For multiple edges
488
489 >>> G = nx.MultiDiGraph()
490 >>> G.add_edges_from([(1, 2), (1, 2), (1, 2)]) # key_list returned
491 [0, 1, 2]
492 >>> G.remove_edge(1, 2) # remove a single (arbitrary) edge
493
494 For edges with keys
495
496 >>> G = nx.MultiDiGraph()
497 >>> G.add_edge(1, 2, key='first')
498 'first'
499 >>> G.add_edge(1, 2, key='second')
500 'second'
501 >>> G.remove_edge(1, 2, key='second')
502
503 """
504 try:
505 d = self._adj[u][v]
506 except KeyError:
507 raise NetworkXError(
508 "The edge %s-%s is not in the graph." % (u, v))
509 # remove the edge with specified data
510 if key is None:
511 d.popitem()
512 else:
513 try:
514 del d[key]
515 except KeyError:
516 msg = "The edge %s-%s with key %s is not in the graph."
517 raise NetworkXError(msg % (u, v, key))
518 if len(d) == 0:
519 # remove the key entries if last edge
520 del self._succ[u][v]
521 del self._pred[v][u]
522
523 @property
524 def edges(self):
525 """An OutMultiEdgeView of the Graph as G.edges or G.edges().
526
527 edges(self, nbunch=None, data=False, keys=False, default=None)
528
529 The OutMultiEdgeView provides set-like operations on the edge-tuples
530 as well as edge attribute lookup. When called, it also provides
531 an EdgeDataView object which allows control of access to edge
532 attributes (but does not provide set-like operations).
533 Hence, `G.edges[u, v]['color']` provides the value of the color
534 attribute for edge `(u, v)` while
535 `for (u, v, c) in G.edges(data='color', default='red'):`
536 iterates through all the edges yielding the color attribute
537 with default `'red'` if no color attribute exists.
538
539 Edges are returned as tuples with optional data and keys
540 in the order (node, neighbor, key, data).
541
542 Parameters
543 ----------
544 nbunch : single node, container, or all nodes (default= all nodes)
545 The view will only report edges incident to these nodes.
546 data : string or bool, optional (default=False)
547 The edge attribute returned in 3-tuple (u, v, ddict[data]).
548 If True, return edge attribute dict in 3-tuple (u, v, ddict).
549 If False, return 2-tuple (u, v).
550 keys : bool, optional (default=False)
551 If True, return edge keys with each edge.
552 default : value, optional (default=None)
553 Value used for edges that don't have the requested attribute.
554 Only relevant if data is not True or False.
555
556 Returns
557 -------
558 edges : EdgeView
559 A view of edge attributes, usually it iterates over (u, v)
560 (u, v, k) or (u, v, k, d) tuples of edges, but can also be
561 used for attribute lookup as `edges[u, v, k]['foo']`.
562
563 Notes
564 -----
565 Nodes in nbunch that are not in the graph will be (quietly) ignored.
566 For directed graphs this returns the out-edges.
567
568 Examples
569 --------
570 >>> G = nx.MultiDiGraph()
571 >>> nx.add_path(G, [0, 1, 2])
572 >>> key = G.add_edge(2, 3, weight=5)
573 >>> [e for e in G.edges()]
574 [(0, 1), (1, 2), (2, 3)]
575 >>> list(G.edges(data=True)) # default data is {} (empty dict)
576 [(0, 1, {}), (1, 2, {}), (2, 3, {'weight': 5})]
577 >>> list(G.edges(data='weight', default=1))
578 [(0, 1, 1), (1, 2, 1), (2, 3, 5)]
579 >>> list(G.edges(keys=True)) # default keys are integers
580 [(0, 1, 0), (1, 2, 0), (2, 3, 0)]
581 >>> list(G.edges(data=True, keys=True))
582 [(0, 1, 0, {}), (1, 2, 0, {}), (2, 3, 0, {'weight': 5})]
583 >>> list(G.edges(data='weight', default=1, keys=True))
584 [(0, 1, 0, 1), (1, 2, 0, 1), (2, 3, 0, 5)]
585 >>> list(G.edges([0, 2]))
586 [(0, 1), (2, 3)]
587 >>> list(G.edges(0))
588 [(0, 1)]
589
590 See Also
591 --------
592 in_edges, out_edges
593 """
594 return OutMultiEdgeView(self)
595
596 # alias out_edges to edges
597 out_edges = edges
598
599 @property
600 def in_edges(self):
601 """An InMultiEdgeView of the Graph as G.in_edges or G.in_edges().
602
603 in_edges(self, nbunch=None, data=False, keys=False, default=None)
604
605 Parameters
606 ----------
607 nbunch : single node, container, or all nodes (default= all nodes)
608 The view will only report edges incident to these nodes.
609 data : string or bool, optional (default=False)
610 The edge attribute returned in 3-tuple (u, v, ddict[data]).
611 If True, return edge attribute dict in 3-tuple (u, v, ddict).
612 If False, return 2-tuple (u, v).
613 keys : bool, optional (default=False)
614 If True, return edge keys with each edge.
615 default : value, optional (default=None)
616 Value used for edges that don't have the requested attribute.
617 Only relevant if data is not True or False.
618
619 Returns
620 -------
621 in_edges : InMultiEdgeView
622 A view of edge attributes, usually it iterates over (u, v)
623 or (u, v, k) or (u, v, k, d) tuples of edges, but can also be
624 used for attribute lookup as `edges[u, v, k]['foo']`.
625
626 See Also
627 --------
628 edges
629 """
630 return InMultiEdgeView(self)
631
632 @property
633 def degree(self):
634 """A DegreeView for the Graph as G.degree or G.degree().
635
636 The node degree is the number of edges adjacent to the node.
637 The weighted node degree is the sum of the edge weights for
638 edges incident to that node.
639
640 This object provides an iterator for (node, degree) as well as
641 lookup for the degree for a single node.
642
643 Parameters
644 ----------
645 nbunch : single node, container, or all nodes (default= all nodes)
646 The view will only report edges incident to these nodes.
647
648 weight : string or None, optional (default=None)
649 The name of an edge attribute that holds the numerical value used
650 as a weight. If None, then each edge has weight 1.
651 The degree is the sum of the edge weights adjacent to the node.
652
653 Returns
654 -------
655 If a single nodes is requested
656 deg : int
657 Degree of the node
658
659 OR if multiple nodes are requested
660 nd_iter : iterator
661 The iterator returns two-tuples of (node, degree).
662
663 See Also
664 --------
665 out_degree, in_degree
666
667 Examples
668 --------
669 >>> G = nx.MultiDiGraph()
670 >>> nx.add_path(G, [0, 1, 2, 3])
671 >>> G.degree(0) # node 0 with degree 1
672 1
673 >>> list(G.degree([0, 1, 2]))
674 [(0, 1), (1, 2), (2, 2)]
675
676 """
677 return DiMultiDegreeView(self)
678
679 @property
680 def in_degree(self):
681 """A DegreeView for (node, in_degree) or in_degree for single node.
682
683 The node in-degree is the number of edges pointing in to the node.
684 The weighted node degree is the sum of the edge weights for
685 edges incident to that node.
686
687 This object provides an iterator for (node, degree) as well as
688 lookup for the degree for a single node.
689
690 Parameters
691 ----------
692 nbunch : single node, container, or all nodes (default= all nodes)
693 The view will only report edges incident to these nodes.
694
695 weight : string or None, optional (default=None)
696 The edge attribute that holds the numerical value used
697 as a weight. If None, then each edge has weight 1.
698 The degree is the sum of the edge weights adjacent to the node.
699
700 Returns
701 -------
702 If a single node is requested
703 deg : int
704 Degree of the node
705
706 OR if multiple nodes are requested
707 nd_iter : iterator
708 The iterator returns two-tuples of (node, in-degree).
709
710 See Also
711 --------
712 degree, out_degree
713
714 Examples
715 --------
716 >>> G = nx.MultiDiGraph()
717 >>> nx.add_path(G, [0, 1, 2, 3])
718 >>> G.in_degree(0) # node 0 with degree 0
719 0
720 >>> list(G.in_degree([0, 1, 2]))
721 [(0, 0), (1, 1), (2, 1)]
722
723 """
724 return InMultiDegreeView(self)
725
726 @property
727 def out_degree(self):
728 """Returns an iterator for (node, out-degree) or out-degree for single node.
729
730 out_degree(self, nbunch=None, weight=None)
731
732 The node out-degree is the number of edges pointing out of the node.
733 This function returns the out-degree for a single node or an iterator
734 for a bunch of nodes or if nothing is passed as argument.
735
736 Parameters
737 ----------
738 nbunch : single node, container, or all nodes (default= all nodes)
739 The view will only report edges incident to these nodes.
740
741 weight : string or None, optional (default=None)
742 The edge attribute that holds the numerical value used
743 as a weight. If None, then each edge has weight 1.
744 The degree is the sum of the edge weights.
745
746 Returns
747 -------
748 If a single node is requested
749 deg : int
750 Degree of the node
751
752 OR if multiple nodes are requested
753 nd_iter : iterator
754 The iterator returns two-tuples of (node, out-degree).
755
756 See Also
757 --------
758 degree, in_degree
759
760 Examples
761 --------
762 >>> G = nx.MultiDiGraph()
763 >>> nx.add_path(G, [0, 1, 2, 3])
764 >>> G.out_degree(0) # node 0 with degree 1
765 1
766 >>> list(G.out_degree([0, 1, 2]))
767 [(0, 1), (1, 1), (2, 1)]
768
769 """
770 return OutMultiDegreeView(self)
771
772 def is_multigraph(self):
773 """Returns True if graph is a multigraph, False otherwise."""
774 return True
775
776 def is_directed(self):
777 """Returns True if graph is directed, False otherwise."""
778 return True
779
780 def to_undirected(self, reciprocal=False, as_view=False):
781 """Returns an undirected representation of the digraph.
782
783 Parameters
784 ----------
785 reciprocal : bool (optional)
786 If True only keep edges that appear in both directions
787 in the original digraph.
788 as_view : bool (optional, default=False)
789 If True return an undirected view of the original directed graph.
790
791 Returns
792 -------
793 G : MultiGraph
794 An undirected graph with the same name and nodes and
795 with edge (u, v, data) if either (u, v, data) or (v, u, data)
796 is in the digraph. If both edges exist in digraph and
797 their edge data is different, only one edge is created
798 with an arbitrary choice of which edge data to use.
799 You must check and correct for this manually if desired.
800
801 See Also
802 --------
803 MultiGraph, copy, add_edge, add_edges_from
804
805 Notes
806 -----
807 This returns a "deepcopy" of the edge, node, and
808 graph attributes which attempts to completely copy
809 all of the data and references.
810
811 This is in contrast to the similar D=MultiiGraph(G) which
812 returns a shallow copy of the data.
813
814 See the Python copy module for more information on shallow
815 and deep copies, https://docs.python.org/2/library/copy.html.
816
817 Warning: If you have subclassed MultiDiGraph to use dict-like
818 objects in the data structure, those changes do not transfer
819 to the MultiGraph created by this method.
820
821 Examples
822 --------
823 >>> G = nx.path_graph(2) # or MultiGraph, etc
824 >>> H = G.to_directed()
825 >>> list(H.edges)
826 [(0, 1), (1, 0)]
827 >>> G2 = H.to_undirected()
828 >>> list(G2.edges)
829 [(0, 1)]
830 """
831 graph_class = self.to_undirected_class()
832 if as_view is True:
833 return nx.graphviews.generic_graph_view(self, graph_class)
834 # deepcopy when not a view
835 G = graph_class()
836 G.graph.update(deepcopy(self.graph))
837 G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items())
838 if reciprocal is True:
839 G.add_edges_from((u, v, key, deepcopy(data))
840 for u, nbrs in self._adj.items()
841 for v, keydict in nbrs.items()
842 for key, data in keydict.items()
843 if v in self._pred[u] and key in self._pred[u][v])
844 else:
845 G.add_edges_from((u, v, key, deepcopy(data))
846 for u, nbrs in self._adj.items()
847 for v, keydict in nbrs.items()
848 for key, data in keydict.items())
849 return G
850
851 def reverse(self, copy=True):
852 """Returns the reverse of the graph.
853
854 The reverse is a graph with the same nodes and edges
855 but with the directions of the edges reversed.
856
857 Parameters
858 ----------
859 copy : bool optional (default=True)
860 If True, return a new DiGraph holding the reversed edges.
861 If False, the reverse graph is created using a view of
862 the original graph.
863 """
864 if copy:
865 H = self.__class__()
866 H.graph.update(deepcopy(self.graph))
867 H.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items())
868 H.add_edges_from((v, u, k, deepcopy(d)) for u, v, k, d
869 in self.edges(keys=True, data=True))
870 return H
871 return nx.graphviews.reverse_view(self)