Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/networkx/algorithms/chains.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author | guerler |
---|---|
date | Fri, 31 Jul 2020 00:32:28 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:d30785e31577 | 1:56ad4e20f292 |
---|---|
1 # -*- coding: utf-8 -*- | |
2 # chains.py - functions for finding chains in a graph | |
3 # | |
4 # Copyright 2004-2019 NetworkX developers. | |
5 # | |
6 # This file is part of NetworkX. | |
7 # | |
8 # NetworkX is distributed under a BSD license; see LICENSE.txt for more | |
9 # information. | |
10 """Functions for finding chains in a graph.""" | |
11 | |
12 import networkx as nx | |
13 from networkx.utils import not_implemented_for | |
14 | |
15 | |
16 @not_implemented_for('directed') | |
17 @not_implemented_for('multigraph') | |
18 def chain_decomposition(G, root=None): | |
19 """Returns the chain decomposition of a graph. | |
20 | |
21 The *chain decomposition* of a graph with respect a depth-first | |
22 search tree is a set of cycles or paths derived from the set of | |
23 fundamental cycles of the tree in the following manner. Consider | |
24 each fundamental cycle with respect to the given tree, represented | |
25 as a list of edges beginning with the nontree edge oriented away | |
26 from the root of the tree. For each fundamental cycle, if it | |
27 overlaps with any previous fundamental cycle, just take the initial | |
28 non-overlapping segment, which is a path instead of a cycle. Each | |
29 cycle or path is called a *chain*. For more information, see [1]_. | |
30 | |
31 Parameters | |
32 ---------- | |
33 G : undirected graph | |
34 | |
35 root : node (optional) | |
36 A node in the graph `G`. If specified, only the chain | |
37 decomposition for the connected component containing this node | |
38 will be returned. This node indicates the root of the depth-first | |
39 search tree. | |
40 | |
41 Yields | |
42 ------ | |
43 chain : list | |
44 A list of edges representing a chain. There is no guarantee on | |
45 the orientation of the edges in each chain (for example, if a | |
46 chain includes the edge joining nodes 1 and 2, the chain may | |
47 include either (1, 2) or (2, 1)). | |
48 | |
49 Raises | |
50 ------ | |
51 NodeNotFound | |
52 If `root` is not in the graph `G`. | |
53 | |
54 Notes | |
55 ----- | |
56 The worst-case running time of this implementation is linear in the | |
57 number of nodes and number of edges [1]_. | |
58 | |
59 References | |
60 ---------- | |
61 .. [1] Jens M. Schmidt (2013). "A simple test on 2-vertex- | |
62 and 2-edge-connectivity." *Information Processing Letters*, | |
63 113, 241–244. Elsevier. <https://doi.org/10.1016/j.ipl.2013.01.016> | |
64 | |
65 """ | |
66 | |
67 def _dfs_cycle_forest(G, root=None): | |
68 """Builds a directed graph composed of cycles from the given graph. | |
69 | |
70 `G` is an undirected simple graph. `root` is a node in the graph | |
71 from which the depth-first search is started. | |
72 | |
73 This function returns both the depth-first search cycle graph | |
74 (as a :class:`~networkx.DiGraph`) and the list of nodes in | |
75 depth-first preorder. The depth-first search cycle graph is a | |
76 directed graph whose edges are the edges of `G` oriented toward | |
77 the root if the edge is a tree edge and away from the root if | |
78 the edge is a non-tree edge. If `root` is not specified, this | |
79 performs a depth-first search on each connected component of `G` | |
80 and returns a directed forest instead. | |
81 | |
82 If `root` is not in the graph, this raises :exc:`KeyError`. | |
83 | |
84 """ | |
85 # Create a directed graph from the depth-first search tree with | |
86 # root node `root` in which tree edges are directed toward the | |
87 # root and nontree edges are directed away from the root. For | |
88 # each node with an incident nontree edge, this creates a | |
89 # directed cycle starting with the nontree edge and returning to | |
90 # that node. | |
91 # | |
92 # The `parent` node attribute stores the parent of each node in | |
93 # the DFS tree. The `nontree` edge attribute indicates whether | |
94 # the edge is a tree edge or a nontree edge. | |
95 # | |
96 # We also store the order of the nodes found in the depth-first | |
97 # search in the `nodes` list. | |
98 H = nx.DiGraph() | |
99 nodes = [] | |
100 for u, v, d in nx.dfs_labeled_edges(G, source=root): | |
101 if d == 'forward': | |
102 # `dfs_labeled_edges()` yields (root, root, 'forward') | |
103 # if it is beginning the search on a new connected | |
104 # component. | |
105 if u == v: | |
106 H.add_node(v, parent=None) | |
107 nodes.append(v) | |
108 else: | |
109 H.add_node(v, parent=u) | |
110 H.add_edge(v, u, nontree=False) | |
111 nodes.append(v) | |
112 # `dfs_labeled_edges` considers nontree edges in both | |
113 # orientations, so we need to not add the edge if it its | |
114 # other orientation has been added. | |
115 elif d == 'nontree' and v not in H[u]: | |
116 H.add_edge(v, u, nontree=True) | |
117 else: | |
118 # Do nothing on 'reverse' edges; we only care about | |
119 # forward and nontree edges. | |
120 pass | |
121 return H, nodes | |
122 | |
123 def _build_chain(G, u, v, visited): | |
124 """Generate the chain starting from the given nontree edge. | |
125 | |
126 `G` is a DFS cycle graph as constructed by | |
127 :func:`_dfs_cycle_graph`. The edge (`u`, `v`) is a nontree edge | |
128 that begins a chain. `visited` is a set representing the nodes | |
129 in `G` that have already been visited. | |
130 | |
131 This function yields the edges in an initial segment of the | |
132 fundamental cycle of `G` starting with the nontree edge (`u`, | |
133 `v`) that includes all the edges up until the first node that | |
134 appears in `visited`. The tree edges are given by the 'parent' | |
135 node attribute. The `visited` set is updated to add each node in | |
136 an edge yielded by this function. | |
137 | |
138 """ | |
139 while v not in visited: | |
140 yield u, v | |
141 visited.add(v) | |
142 u, v = v, G.nodes[v]['parent'] | |
143 yield u, v | |
144 | |
145 # Create a directed version of H that has the DFS edges directed | |
146 # toward the root and the nontree edges directed away from the root | |
147 # (in each connected component). | |
148 H, nodes = _dfs_cycle_forest(G, root) | |
149 | |
150 # Visit the nodes again in DFS order. For each node, and for each | |
151 # nontree edge leaving that node, compute the fundamental cycle for | |
152 # that nontree edge starting with that edge. If the fundamental | |
153 # cycle overlaps with any visited nodes, just take the prefix of the | |
154 # cycle up to the point of visited nodes. | |
155 # | |
156 # We repeat this process for each connected component (implicitly, | |
157 # since `nodes` already has a list of the nodes grouped by connected | |
158 # component). | |
159 visited = set() | |
160 for u in nodes: | |
161 visited.add(u) | |
162 # For each nontree edge going out of node u... | |
163 edges = ((u, v) for u, v, d in H.out_edges(u, data='nontree') if d) | |
164 for u, v in edges: | |
165 # Create the cycle or cycle prefix starting with the | |
166 # nontree edge. | |
167 chain = list(_build_chain(H, u, v, visited)) | |
168 yield chain |