networkx 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/{CODE_OF_CONDUCT.md → .github/CODE_OF_CONDUCT.md} +0 -0
- data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +20 -10
- data/{ISSUE_TEMPLATE.md → .github/ISSUE_TEMPLATE.md} +1 -1
- data/{PULL_REQUEST_TEMPLATE.md → .github/PULL_REQUEST_TEMPLATE.md} +2 -4
- data/.github/workflows/ci.yml +17 -0
- data/.github/workflows/doc.yml +23 -0
- data/.rspec +0 -1
- data/.rubocop.yml +57 -71
- data/.yardopts +0 -1
- data/README.md +32 -34
- data/Rakefile +2 -3
- data/lib/networkx/auxillary_functions/cliques.rb +9 -12
- data/lib/networkx/auxillary_functions/cycles.rb +17 -7
- data/lib/networkx/auxillary_functions/dag.rb +10 -5
- data/lib/networkx/auxillary_functions/eccentricity.rb +2 -1
- data/lib/networkx/auxillary_functions/mis.rb +2 -2
- data/lib/networkx/auxillary_functions/mst.rb +1 -3
- data/lib/networkx/auxillary_functions/union_find.rb +92 -12
- data/lib/networkx/auxillary_functions/wiener.rb +1 -1
- data/lib/networkx/converters/to_csv.rb +1 -3
- data/lib/networkx/converters/to_json.rb +0 -2
- data/lib/networkx/digraph.rb +55 -49
- data/lib/networkx/flow/capacityscaling.rb +29 -35
- data/lib/networkx/flow/edmondskarp.rb +17 -15
- data/lib/networkx/flow/preflowpush.rb +29 -32
- data/lib/networkx/flow/shortestaugmentingpath.rb +17 -20
- data/lib/networkx/flow/utils.rb +6 -27
- data/lib/networkx/graph.rb +179 -72
- data/lib/networkx/link_analysis/hits.rb +9 -9
- data/lib/networkx/link_analysis/pagerank.rb +29 -31
- data/lib/networkx/multidigraph.rb +90 -81
- data/lib/networkx/multigraph.rb +91 -63
- data/lib/networkx/operators/all.rb +8 -4
- data/lib/networkx/operators/binary.rb +106 -128
- data/lib/networkx/operators/product.rb +61 -64
- data/lib/networkx/operators/unary.rb +1 -1
- data/lib/networkx/others/bridges.rb +30 -0
- data/lib/networkx/others/generators.rb +237 -0
- data/lib/networkx/others/grid_2d_graph.rb +38 -0
- data/lib/networkx/others/info.rb +11 -0
- data/lib/networkx/others/number_connected_components.rb +17 -0
- data/lib/networkx/others/reads.rb +52 -0
- data/lib/networkx/shortest_path/astar.rb +10 -8
- data/lib/networkx/shortest_path/dense.rb +1 -3
- data/lib/networkx/shortest_path/unweighted.rb +13 -16
- data/lib/networkx/shortest_path/weighted.rb +51 -42
- data/lib/networkx/to_matrix.rb +2 -3
- data/lib/networkx/traversals/bfs.rb +54 -2
- data/lib/networkx/traversals/dfs.rb +62 -6
- data/lib/networkx/traversals/edge_dfs.rb +36 -12
- data/lib/networkx/version.rb +1 -1
- data/lib/networkx.rb +7 -1
- data/networkx.gemspec +17 -14
- metadata +74 -84
- data/.rspec_formatter.rb +0 -24
- data/.travis.yml +0 -18
- data/Guardfile +0 -7
- data/RELEASE_POLICY.md +0 -20
@@ -10,12 +10,13 @@ module NetworkX
|
|
10
10
|
class MultiDiGraph < DiGraph
|
11
11
|
# Returns a new key
|
12
12
|
#
|
13
|
-
# @param
|
14
|
-
# @param
|
15
|
-
def new_edge_key(
|
16
|
-
return 0 if @adj[
|
17
|
-
|
18
|
-
key
|
13
|
+
# @param node1 [Object] the first node of a given edge
|
14
|
+
# @param node2 [Object] the second node of a given edge
|
15
|
+
def new_edge_key(node1, node2)
|
16
|
+
return 0 if @adj[node1][node2].nil?
|
17
|
+
|
18
|
+
key = @adj[node1][node2].length
|
19
|
+
key += 1 while @adj[node1][node2].has_key?(key)
|
19
20
|
key
|
20
21
|
end
|
21
22
|
|
@@ -27,52 +28,60 @@ module NetworkX
|
|
27
28
|
# @example Add an edge with no attribute
|
28
29
|
# graph.add_edge("Bangalore", "Chennai")
|
29
30
|
#
|
30
|
-
# @param
|
31
|
-
# @param
|
31
|
+
# @param node1 [Object] the first node of the edge
|
32
|
+
# @param node2 [Object] the second node of the edge
|
32
33
|
# @param edge_attrs [Hash{ Object => Object }] the hash of the edge attributes
|
33
|
-
def add_edge(
|
34
|
-
add_node(
|
35
|
-
add_node(
|
36
|
-
key = new_edge_key(
|
37
|
-
all_edge_attrs = @adj[
|
34
|
+
def add_edge(node1, node2, **edge_attrs)
|
35
|
+
add_node(node1)
|
36
|
+
add_node(node2)
|
37
|
+
key = new_edge_key(node1, node2)
|
38
|
+
all_edge_attrs = @adj[node1][node2] || {}
|
38
39
|
all_edge_attrs[key] = edge_attrs
|
39
|
-
@adj[
|
40
|
-
@pred[
|
40
|
+
@adj[node1][node2] = all_edge_attrs
|
41
|
+
@pred[node2][node1] = all_edge_attrs
|
41
42
|
end
|
42
43
|
|
43
|
-
# TODO: Reduce method complexity
|
44
|
-
|
45
44
|
# Removes edge from the graph
|
46
45
|
#
|
47
46
|
# @example
|
48
47
|
# graph.remove_edge('Noida', 'Bangalore')
|
49
48
|
#
|
50
|
-
# @param
|
51
|
-
# @param
|
52
|
-
def remove_edge(
|
53
|
-
if key.nil?
|
54
|
-
|
55
|
-
|
49
|
+
# @param node1 [Object] the first node of the edge
|
50
|
+
# @param node2 [Object] the second node of the edge
|
51
|
+
def remove_edge(node1, node2, key = nil)
|
52
|
+
return super(node1, node2) if key.nil?
|
53
|
+
|
54
|
+
raise KeyError, "#{node1} is not a valid node." unless @nodes.has_key?(node1)
|
55
|
+
raise KeyError, "#{node2} is not a valid node" unless @nodes.has_key?(node2)
|
56
|
+
raise KeyError, 'The given edge is not a valid one.' unless @adj[node1].has_key?(node2)
|
57
|
+
if @adj[node1][node2].none? { |_index, data| data[:key] == key }
|
58
|
+
raise KeyError, 'The given edge is not a valid one'
|
56
59
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
raise KeyError, 'The given edge is not a valid one.' unless @adj[node_1][node_2].key?(key)
|
61
|
-
@adj[node_1][node_2].delete(key)
|
62
|
-
@pred[node_2][node_1].delete(key)
|
60
|
+
|
61
|
+
@adj[node1][node2].delete_if { |_indx, data| data[:key] == key }
|
62
|
+
@pred[node2][node1].delete_if { |_indx, data| data[:key] == key }
|
63
63
|
end
|
64
64
|
|
65
65
|
# Checks if the the edge consisting of two nodes is present in the graph
|
66
66
|
#
|
67
67
|
# @example
|
68
|
-
# graph.edge?(
|
68
|
+
# graph.edge?(node1, node2)
|
69
69
|
#
|
70
|
-
# @param
|
71
|
-
# @param
|
70
|
+
# @param node1 [Object] the first node of the edge to be checked
|
71
|
+
# @param node2 [Object] the second node of the edge to be checked
|
72
72
|
# @param key [Integer] the key of the given edge
|
73
|
-
def edge?(
|
74
|
-
super(
|
75
|
-
|
73
|
+
def edge?(node1, node2, key = nil)
|
74
|
+
return super(node1, node2) if key.nil?
|
75
|
+
|
76
|
+
node?(node1) && @adj[node1].has_key?(node2) && @adj[node1][node2].has_key?(key)
|
77
|
+
end
|
78
|
+
|
79
|
+
def has_edge?(node1, node2, key = nil)
|
80
|
+
return super(node1, node2) if key.nil?
|
81
|
+
|
82
|
+
return false unless node?(node1) && @adj[node1].has_key?(node2)
|
83
|
+
|
84
|
+
@adj[node1][node2].any? { |_index, data| data[:key] == key }
|
76
85
|
end
|
77
86
|
|
78
87
|
# Returns the undirected version of the graph
|
@@ -80,13 +89,13 @@ module NetworkX
|
|
80
89
|
# @example
|
81
90
|
# graph.to_undirected
|
82
91
|
def to_undirected
|
83
|
-
graph = NetworkX::Graph.new(
|
84
|
-
@nodes.each { |node, node_attr| graph.add_node(node, node_attr) }
|
85
|
-
@adj.each do |
|
86
|
-
|
92
|
+
graph = NetworkX::Graph.new(**@graph)
|
93
|
+
@nodes.each { |node, node_attr| graph.add_node(node, **node_attr) }
|
94
|
+
@adj.each do |node1, node1_edges|
|
95
|
+
node1_edges.each do |node2, node1_node2|
|
87
96
|
edge_attrs = {}
|
88
|
-
|
89
|
-
graph.add_edge(
|
97
|
+
node1_node2.each { |_key, attrs| edge_attrs.merge!(attrs) }
|
98
|
+
graph.add_edge(node1, node2, **edge_attrs)
|
90
99
|
end
|
91
100
|
end
|
92
101
|
graph
|
@@ -97,13 +106,13 @@ module NetworkX
|
|
97
106
|
# @example
|
98
107
|
# graph.to_directed
|
99
108
|
def to_directed
|
100
|
-
graph = NetworkX::DiGraph.new(
|
101
|
-
@nodes.each { |node, node_attr| graph.add_node(node, node_attr) }
|
102
|
-
@adj.each do |
|
103
|
-
|
109
|
+
graph = NetworkX::DiGraph.new(**@graph)
|
110
|
+
@nodes.each { |node, node_attr| graph.add_node(node, **node_attr) }
|
111
|
+
@adj.each do |node1, node1_edges|
|
112
|
+
node1_edges.each do |node2, node1_node2|
|
104
113
|
edge_attrs = {}
|
105
|
-
|
106
|
-
graph.add_edge(
|
114
|
+
node1_node2.each { |_key, attrs| edge_attrs.merge!(attrs) }
|
115
|
+
graph.add_edge(node1, node2, **edge_attrs)
|
107
116
|
end
|
108
117
|
end
|
109
118
|
graph
|
@@ -114,13 +123,11 @@ module NetworkX
|
|
114
123
|
# @example
|
115
124
|
# graph.to_multigraph
|
116
125
|
def to_multigraph
|
117
|
-
graph = NetworkX::MultiGraph.new(
|
118
|
-
@nodes.each { |node, node_attr| graph.add_node(node, node_attr) }
|
119
|
-
@adj.each do |
|
120
|
-
|
121
|
-
|
122
|
-
node_1_node_2.each { |_key, attrs| graph.add_edge(node_1, node_2, attrs) }
|
123
|
-
graph.add_edge(node_1, node_2, edge_attrs)
|
126
|
+
graph = NetworkX::MultiGraph.new(**@graph)
|
127
|
+
@nodes.each { |node, node_attr| graph.add_node(node, **node_attr) }
|
128
|
+
@adj.each do |node1, node2_edges|
|
129
|
+
node2_edges.each do |node2, edges|
|
130
|
+
edges.each { |_key, attrs| graph.add_edge(node1, node2, **attrs) }
|
124
131
|
end
|
125
132
|
end
|
126
133
|
graph
|
@@ -131,10 +138,10 @@ module NetworkX
|
|
131
138
|
# @example
|
132
139
|
# graph.reverse
|
133
140
|
def reverse
|
134
|
-
new_graph = NetworkX::MultiDiGraph.new(
|
135
|
-
@nodes.each { |node, attrs| new_graph.add_node(node, attrs) }
|
141
|
+
new_graph = NetworkX::MultiDiGraph.new(**@graph)
|
142
|
+
@nodes.each { |node, attrs| new_graph.add_node(node, **attrs) }
|
136
143
|
@adj.each do |u, u_edges|
|
137
|
-
u_edges.each { |v, uv_attrs| uv_attrs.each { |_k, edge_attrs| new_graph.add_edge(v, u, edge_attrs) } }
|
144
|
+
u_edges.each { |v, uv_attrs| uv_attrs.each { |_k, edge_attrs| new_graph.add_edge(v, u, **edge_attrs) } }
|
138
145
|
end
|
139
146
|
new_graph
|
140
147
|
end
|
@@ -146,7 +153,7 @@ module NetworkX
|
|
146
153
|
#
|
147
154
|
# @param node [Object] the node whose in degree is to be calculated
|
148
155
|
def in_degree(node)
|
149
|
-
@pred[node].values.map(
|
156
|
+
@pred[node].values.map(&:length).sum
|
150
157
|
end
|
151
158
|
|
152
159
|
# Returns out-degree of a given node
|
@@ -156,7 +163,7 @@ module NetworkX
|
|
156
163
|
#
|
157
164
|
# @param node [Object] the node whose out degree is to be calculated
|
158
165
|
def out_degree(node)
|
159
|
-
@adj[node].values.map(
|
166
|
+
@adj[node].values.map(&:length).sum
|
160
167
|
end
|
161
168
|
|
162
169
|
# Returns number of edges
|
@@ -164,7 +171,7 @@ module NetworkX
|
|
164
171
|
# @example
|
165
172
|
# graph.number_of_edges
|
166
173
|
def number_of_edges
|
167
|
-
@adj.values.flat_map(&:values).map(&:length).
|
174
|
+
@adj.values.flat_map(&:values).map(&:length).sum
|
168
175
|
end
|
169
176
|
|
170
177
|
# Returns the size of the graph
|
@@ -174,19 +181,17 @@ module NetworkX
|
|
174
181
|
#
|
175
182
|
# @param is_weighted [Bool] if true, method returns sum of weights of all edges
|
176
183
|
# else returns number of edges
|
177
|
-
def size(is_weighted=false)
|
184
|
+
def size(is_weighted = false)
|
178
185
|
if is_weighted
|
179
186
|
graph_size = 0
|
180
187
|
@adj.each do |_, hash_val|
|
181
|
-
hash_val.each { |_, v| v.each { |_, attrs| graph_size += attrs[:weight] if attrs.
|
188
|
+
hash_val.each { |_, v| v.each { |_, attrs| graph_size += attrs[:weight] if attrs.has_key?(:weight) } }
|
182
189
|
end
|
183
190
|
return graph_size
|
184
191
|
end
|
185
192
|
number_of_edges
|
186
193
|
end
|
187
194
|
|
188
|
-
# TODO: Reduce method length and method complexity
|
189
|
-
|
190
195
|
# Returns subgraph consisting of given array of nodes
|
191
196
|
#
|
192
197
|
# @example
|
@@ -196,23 +201,22 @@ module NetworkX
|
|
196
201
|
def subgraph(nodes)
|
197
202
|
case nodes
|
198
203
|
when Array, Set
|
199
|
-
sub_graph = NetworkX::MultiDiGraph.new(
|
204
|
+
sub_graph = NetworkX::MultiDiGraph.new(**@graph)
|
200
205
|
nodes.each do |u, _|
|
201
|
-
raise KeyError, "#{u} does not exist in the current graph!" unless @nodes.
|
202
|
-
|
206
|
+
raise KeyError, "#{u} does not exist in the current graph!" unless @nodes.has_key?(u)
|
207
|
+
|
208
|
+
sub_graph.add_node(u, **@nodes[u])
|
203
209
|
@adj[u].each do |v, edge_val|
|
204
|
-
edge_val.each { |_, keyval| sub_graph.add_edge(u, v, keyval) if @adj[u].
|
210
|
+
edge_val.each { |_, keyval| sub_graph.add_edge(u, v, **keyval) if @adj[u].has_key?(v) && nodes.include?(v) }
|
205
211
|
end
|
206
|
-
return sub_graph
|
207
212
|
end
|
213
|
+
sub_graph
|
208
214
|
else
|
209
|
-
raise ArgumentError, 'Expected Argument to be Array or Set of nodes, '\
|
215
|
+
raise ArgumentError, 'Expected Argument to be Array or Set of nodes, ' \
|
210
216
|
"received #{nodes.class.name} instead."
|
211
217
|
end
|
212
218
|
end
|
213
219
|
|
214
|
-
# TODO: Reduce method length and method complexity
|
215
|
-
|
216
220
|
# Returns subgraph conisting of given edges
|
217
221
|
#
|
218
222
|
# @example
|
@@ -222,19 +226,24 @@ module NetworkX
|
|
222
226
|
def edge_subgraph(edges)
|
223
227
|
case edges
|
224
228
|
when Array, Set
|
225
|
-
sub_graph = NetworkX::MultiDiGraph.new(
|
229
|
+
sub_graph = NetworkX::MultiDiGraph.new(**@graph)
|
226
230
|
edges.each do |u, v|
|
227
|
-
raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.
|
228
|
-
&& @adj[u].
|
229
|
-
|
230
|
-
sub_graph.add_node(
|
231
|
-
|
231
|
+
raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.has_key?(u) \
|
232
|
+
&& @adj[u].has_key?(v)
|
233
|
+
|
234
|
+
sub_graph.add_node(u, **@nodes[u])
|
235
|
+
sub_graph.add_node(v, **@nodes[v])
|
236
|
+
@adj[u][v].each { |_, keyval| sub_graph.add_edge(u, v, **keyval) }
|
232
237
|
end
|
233
|
-
|
238
|
+
sub_graph
|
234
239
|
else
|
235
|
-
raise ArgumentError, 'Expected Argument to be Array or Set of edges, '\
|
236
|
-
|
240
|
+
raise ArgumentError, 'Expected Argument to be Array or Set of edges, ' \
|
241
|
+
"received #{edges.class.name} instead."
|
237
242
|
end
|
238
243
|
end
|
244
|
+
|
245
|
+
def multigraph?
|
246
|
+
true
|
247
|
+
end
|
239
248
|
end
|
240
249
|
end
|
data/lib/networkx/multigraph.rb
CHANGED
@@ -8,12 +8,13 @@ module NetworkX
|
|
8
8
|
class MultiGraph < Graph
|
9
9
|
# Returns a new key
|
10
10
|
#
|
11
|
-
# @param
|
12
|
-
# @param
|
13
|
-
def new_edge_key(
|
14
|
-
return 0 if @adj[
|
15
|
-
|
16
|
-
key
|
11
|
+
# @param node1 [Object] the first node of a given edge
|
12
|
+
# @param node2 [Object] the second node of a given edge
|
13
|
+
def new_edge_key(node1, node2)
|
14
|
+
return 0 if @adj[node1][node2].nil?
|
15
|
+
|
16
|
+
key = @adj[node1][node2].length
|
17
|
+
key += 1 while @adj[node1][node2].has_key?(key)
|
17
18
|
key
|
18
19
|
end
|
19
20
|
|
@@ -25,39 +26,39 @@ module NetworkX
|
|
25
26
|
# @example Add an edge with no attribute
|
26
27
|
# graph.add_edge("Bangalore", "Chennai")
|
27
28
|
#
|
28
|
-
# @param
|
29
|
-
# @param
|
29
|
+
# @param node1 [Object] the first node of the edge
|
30
|
+
# @param node2 [Object] the second node of the edge
|
30
31
|
# @param edge_attrs [Hash{ Object => Object }] the hash of the edge attributes
|
31
|
-
def add_edge(
|
32
|
-
add_node(
|
33
|
-
add_node(
|
34
|
-
key = new_edge_key(
|
35
|
-
all_edge_attrs = @adj[
|
32
|
+
def add_edge(node1, node2, **edge_attrs)
|
33
|
+
add_node(node1)
|
34
|
+
add_node(node2)
|
35
|
+
key = new_edge_key(node1, node2)
|
36
|
+
all_edge_attrs = @adj[node1][node2] || {}
|
36
37
|
all_edge_attrs[key] = edge_attrs
|
37
|
-
@adj[
|
38
|
-
@adj[
|
38
|
+
@adj[node1][node2] = all_edge_attrs
|
39
|
+
@adj[node2][node1] = all_edge_attrs
|
39
40
|
end
|
40
41
|
|
41
|
-
# TODO: Reduce method complexity
|
42
|
-
|
43
42
|
# Removes edge from the graph
|
44
43
|
#
|
45
44
|
# @example
|
46
45
|
# graph.remove_edge('Noida', 'Bangalore')
|
47
46
|
#
|
48
|
-
# @param
|
49
|
-
# @param
|
50
|
-
def remove_edge(
|
51
|
-
if key.nil?
|
52
|
-
|
53
|
-
|
47
|
+
# @param node1 [Object] the first node of the edge
|
48
|
+
# @param node2 [Object] the second node of the edge
|
49
|
+
def remove_edge(node1, node2, key = nil)
|
50
|
+
return super(node1, node2) if key.nil?
|
51
|
+
|
52
|
+
raise KeyError, "#{node1} is not a valid node." unless @nodes.has_key?(node1)
|
53
|
+
raise KeyError, "#{node2} is not a valid node" unless @nodes.has_key?(node2)
|
54
|
+
raise KeyError, 'The given edge is not a valid one.' unless @adj[node1].has_key?(node2)
|
55
|
+
|
56
|
+
if @adj[node1][node2].none? { |_index, data| data[:key] == key }
|
57
|
+
raise KeyError, 'The given edge is not a valid one'
|
54
58
|
end
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
raise KeyError, 'The given edge is not a valid one.' unless @adj[node_1][node_2].key?(key)
|
59
|
-
@adj[node_1][node_2].delete(key)
|
60
|
-
@adj[node_2][node_1].delete(key)
|
59
|
+
|
60
|
+
@adj[node1][node2].delete_if { |_indx, data| data[:key] == key }
|
61
|
+
@adj[node2][node1].delete_if { |_indx, data| data[:key] == key }
|
61
62
|
end
|
62
63
|
|
63
64
|
# Returns the size of the graph
|
@@ -67,11 +68,11 @@ module NetworkX
|
|
67
68
|
#
|
68
69
|
# @param is_weighted [Bool] if true, method returns sum of weights of all edges
|
69
70
|
# else returns number of edges
|
70
|
-
def size(is_weighted=false)
|
71
|
+
def size(is_weighted = false)
|
71
72
|
if is_weighted
|
72
73
|
graph_size = 0
|
73
74
|
@adj.each do |_, hash_val|
|
74
|
-
hash_val.each { |_, v| v.each { |_, attrs| graph_size += attrs[:weight] if attrs.
|
75
|
+
hash_val.each { |_, v| v.each { |_, attrs| graph_size += attrs[:weight] if attrs.has_key?(:weight) } }
|
75
76
|
end
|
76
77
|
return graph_size / 2
|
77
78
|
end
|
@@ -83,20 +84,43 @@ module NetworkX
|
|
83
84
|
# @example
|
84
85
|
# graph.number_of_edges
|
85
86
|
def number_of_edges
|
86
|
-
@adj.values.flat_map(&:values).map(&:length).
|
87
|
+
@adj.values.flat_map(&:values).map(&:length).sum / 2
|
87
88
|
end
|
88
89
|
|
89
90
|
# Checks if the the edge consisting of two nodes is present in the graph
|
90
91
|
#
|
91
92
|
# @example
|
92
|
-
# graph.edge?(
|
93
|
+
# graph.edge?(node1, node2)
|
93
94
|
#
|
94
|
-
# @param
|
95
|
-
# @param
|
95
|
+
# @param node1 [Object] the first node of the edge to be checked
|
96
|
+
# @param node2 [Object] the second node of the edge to be checked
|
96
97
|
# @param key [Integer] the key of the given edge
|
97
|
-
def edge?(
|
98
|
-
super(
|
99
|
-
|
98
|
+
def edge?(node1, node2, key = nil)
|
99
|
+
return super(node1, node2) if key.nil?
|
100
|
+
|
101
|
+
node?(node1) && @adj[node1].has_key?(node2) && @adj[node1][node2].has_key?(key)
|
102
|
+
end
|
103
|
+
|
104
|
+
def has_edge?(node1, node2, key = nil)
|
105
|
+
return super(node1, node2) if key.nil?
|
106
|
+
|
107
|
+
return false unless node?(node1) && @adj[node1].has_key?(node2)
|
108
|
+
|
109
|
+
@adj[node1][node2].any? { |_index, data| data[:key] == key }
|
110
|
+
end
|
111
|
+
|
112
|
+
def each_edge(data: false)
|
113
|
+
return enum_for(:each_edge, data: data) unless block_given?
|
114
|
+
|
115
|
+
@adj.each do |v, ws|
|
116
|
+
ws.each do |w, key_and_info|
|
117
|
+
next if v > w
|
118
|
+
|
119
|
+
key_and_info.each do |key, info|
|
120
|
+
data ? yield(v, w, key, info) : yield(v, w, key)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
100
124
|
end
|
101
125
|
|
102
126
|
# Returns the undirected version of the graph
|
@@ -104,20 +128,18 @@ module NetworkX
|
|
104
128
|
# @example
|
105
129
|
# graph.to_undirected
|
106
130
|
def to_undirected
|
107
|
-
graph = NetworkX::Graph.new(
|
108
|
-
@nodes.each { |node, node_attr| graph.add_node(node, node_attr) }
|
109
|
-
@adj.each do |
|
110
|
-
|
131
|
+
graph = NetworkX::Graph.new(**@graph)
|
132
|
+
@nodes.each { |node, node_attr| graph.add_node(node, **node_attr) }
|
133
|
+
@adj.each do |node1, node1_edges|
|
134
|
+
node1_edges.each do |node2, node1_node2|
|
111
135
|
edge_attrs = {}
|
112
|
-
|
113
|
-
graph.add_edge(
|
136
|
+
node1_node2.each { |_key, attrs| edge_attrs.merge!(attrs) }
|
137
|
+
graph.add_edge(node1, node2, **edge_attrs)
|
114
138
|
end
|
115
139
|
end
|
116
140
|
graph
|
117
141
|
end
|
118
142
|
|
119
|
-
# TODO: Reduce method complexity and method length
|
120
|
-
|
121
143
|
# Returns subgraph consisting of given array of nodes
|
122
144
|
#
|
123
145
|
# @example
|
@@ -127,23 +149,24 @@ module NetworkX
|
|
127
149
|
def subgraph(nodes)
|
128
150
|
case nodes
|
129
151
|
when Array, Set
|
130
|
-
sub_graph = NetworkX::MultiGraph.new(
|
152
|
+
sub_graph = NetworkX::MultiGraph.new(**@graph)
|
131
153
|
nodes.each do |u, _|
|
132
|
-
raise KeyError, "#{u} does not exist in the current graph!" unless @nodes.
|
133
|
-
|
154
|
+
raise KeyError, "#{u} does not exist in the current graph!" unless @nodes.has_key?(u)
|
155
|
+
|
156
|
+
sub_graph.add_node(u, **@nodes[u])
|
134
157
|
@adj[u].each do |v, edge_val|
|
135
|
-
|
158
|
+
next if u > v
|
159
|
+
|
160
|
+
edge_val.each { |_, keyval| sub_graph.add_edge(u, v, **keyval) if @adj[u].has_key?(v) && nodes.include?(v) }
|
136
161
|
end
|
137
|
-
return sub_graph
|
138
162
|
end
|
163
|
+
sub_graph
|
139
164
|
else
|
140
|
-
raise ArgumentError, 'Expected Argument to be Array or Set of nodes, '\
|
165
|
+
raise ArgumentError, 'Expected Argument to be Array or Set of nodes, ' \
|
141
166
|
"received #{nodes.class.name} instead."
|
142
167
|
end
|
143
168
|
end
|
144
169
|
|
145
|
-
# TODO: Reduce method complexity and method length
|
146
|
-
|
147
170
|
# Returns subgraph conisting of given edges
|
148
171
|
#
|
149
172
|
# @example
|
@@ -153,19 +176,24 @@ module NetworkX
|
|
153
176
|
def edge_subgraph(edges)
|
154
177
|
case edges
|
155
178
|
when Array, Set
|
156
|
-
sub_graph = NetworkX::MultiGraph.new(
|
179
|
+
sub_graph = NetworkX::MultiGraph.new(**@graph)
|
157
180
|
edges.each do |u, v|
|
158
|
-
raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.
|
159
|
-
&& @adj[u].
|
160
|
-
|
161
|
-
sub_graph.add_node(
|
162
|
-
|
181
|
+
raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.has_key?(u) \
|
182
|
+
&& @adj[u].has_key?(v)
|
183
|
+
|
184
|
+
sub_graph.add_node(u, **@nodes[u])
|
185
|
+
sub_graph.add_node(v, **@nodes[v])
|
186
|
+
@adj[u][v].each { |_, keyval| sub_graph.add_edge(u, v, **keyval) }
|
163
187
|
end
|
164
|
-
|
188
|
+
sub_graph
|
165
189
|
else
|
166
|
-
raise ArgumentError, 'Expected Argument to be Array or Set of edges, '\
|
167
|
-
|
190
|
+
raise ArgumentError, 'Expected Argument to be Array or Set of edges, ' \
|
191
|
+
"received #{edges.class.name} instead."
|
168
192
|
end
|
169
193
|
end
|
194
|
+
|
195
|
+
def multigraph?
|
196
|
+
true
|
197
|
+
end
|
170
198
|
end
|
171
199
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module NetworkX
|
2
2
|
# Performs the union of many graphs
|
3
3
|
#
|
4
|
-
# @param [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
4
|
+
# @param graphs [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
5
5
|
#
|
6
6
|
# @return [Graph, DiGraph, MultiGraph, MultiDiGraph] union of all the graphs
|
7
7
|
def self.union_all(graphs)
|
8
8
|
raise ArgumentError, 'Argument array is empty' if graphs.empty?
|
9
|
+
|
9
10
|
result = graphs.shift
|
10
11
|
|
11
12
|
graphs.each do |graph|
|
@@ -16,11 +17,12 @@ module NetworkX
|
|
16
17
|
|
17
18
|
# Performs the disjoint union of many graphs
|
18
19
|
#
|
19
|
-
# @param [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
20
|
+
# @param graphs [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
20
21
|
#
|
21
22
|
# @return [Graph, DiGraph, MultiGraph, MultiDiGraph] disjoint union of all the graphs
|
22
23
|
def self.disjoint_union_all(graphs)
|
23
24
|
raise ArgumentError, 'Argument array is empty' if graphs.empty?
|
25
|
+
|
24
26
|
result = graphs.shift
|
25
27
|
|
26
28
|
graphs.each do |graph|
|
@@ -31,11 +33,12 @@ module NetworkX
|
|
31
33
|
|
32
34
|
# Performs the intersection of many graphs
|
33
35
|
#
|
34
|
-
# @param [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
36
|
+
# @param graphs [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
35
37
|
#
|
36
38
|
# @return [Graph, DiGraph, MultiGraph, MultiDiGraph] intersection of all the graphs
|
37
39
|
def self.intersection_all(graphs)
|
38
40
|
raise ArgumentError, 'Argument array is empty' if graphs.empty?
|
41
|
+
|
39
42
|
result = graphs.shift
|
40
43
|
|
41
44
|
graphs.each do |graph|
|
@@ -46,11 +49,12 @@ module NetworkX
|
|
46
49
|
|
47
50
|
# Performs the composition of many graphs
|
48
51
|
#
|
49
|
-
# @param [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
52
|
+
# @param graphs [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
50
53
|
#
|
51
54
|
# @return [Graph, DiGraph, MultiGraph, MultiDiGraph] composition of all the graphs
|
52
55
|
def self.compose_all(graphs)
|
53
56
|
raise ArgumentError, 'Argument array is empty' if graphs.empty?
|
57
|
+
|
54
58
|
result = graphs.shift
|
55
59
|
|
56
60
|
graphs.each do |graph|
|