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.
Files changed (59) hide show
  1. checksums.yaml +5 -5
  2. data/{CODE_OF_CONDUCT.md → .github/CODE_OF_CONDUCT.md} +0 -0
  3. data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +20 -10
  4. data/{ISSUE_TEMPLATE.md → .github/ISSUE_TEMPLATE.md} +1 -1
  5. data/{PULL_REQUEST_TEMPLATE.md → .github/PULL_REQUEST_TEMPLATE.md} +2 -4
  6. data/.github/workflows/ci.yml +17 -0
  7. data/.github/workflows/doc.yml +23 -0
  8. data/.rspec +0 -1
  9. data/.rubocop.yml +57 -71
  10. data/.yardopts +0 -1
  11. data/README.md +32 -34
  12. data/Rakefile +2 -3
  13. data/lib/networkx/auxillary_functions/cliques.rb +9 -12
  14. data/lib/networkx/auxillary_functions/cycles.rb +17 -7
  15. data/lib/networkx/auxillary_functions/dag.rb +10 -5
  16. data/lib/networkx/auxillary_functions/eccentricity.rb +2 -1
  17. data/lib/networkx/auxillary_functions/mis.rb +2 -2
  18. data/lib/networkx/auxillary_functions/mst.rb +1 -3
  19. data/lib/networkx/auxillary_functions/union_find.rb +92 -12
  20. data/lib/networkx/auxillary_functions/wiener.rb +1 -1
  21. data/lib/networkx/converters/to_csv.rb +1 -3
  22. data/lib/networkx/converters/to_json.rb +0 -2
  23. data/lib/networkx/digraph.rb +55 -49
  24. data/lib/networkx/flow/capacityscaling.rb +29 -35
  25. data/lib/networkx/flow/edmondskarp.rb +17 -15
  26. data/lib/networkx/flow/preflowpush.rb +29 -32
  27. data/lib/networkx/flow/shortestaugmentingpath.rb +17 -20
  28. data/lib/networkx/flow/utils.rb +6 -27
  29. data/lib/networkx/graph.rb +179 -72
  30. data/lib/networkx/link_analysis/hits.rb +9 -9
  31. data/lib/networkx/link_analysis/pagerank.rb +29 -31
  32. data/lib/networkx/multidigraph.rb +90 -81
  33. data/lib/networkx/multigraph.rb +91 -63
  34. data/lib/networkx/operators/all.rb +8 -4
  35. data/lib/networkx/operators/binary.rb +106 -128
  36. data/lib/networkx/operators/product.rb +61 -64
  37. data/lib/networkx/operators/unary.rb +1 -1
  38. data/lib/networkx/others/bridges.rb +30 -0
  39. data/lib/networkx/others/generators.rb +237 -0
  40. data/lib/networkx/others/grid_2d_graph.rb +38 -0
  41. data/lib/networkx/others/info.rb +11 -0
  42. data/lib/networkx/others/number_connected_components.rb +17 -0
  43. data/lib/networkx/others/reads.rb +52 -0
  44. data/lib/networkx/shortest_path/astar.rb +10 -8
  45. data/lib/networkx/shortest_path/dense.rb +1 -3
  46. data/lib/networkx/shortest_path/unweighted.rb +13 -16
  47. data/lib/networkx/shortest_path/weighted.rb +51 -42
  48. data/lib/networkx/to_matrix.rb +2 -3
  49. data/lib/networkx/traversals/bfs.rb +54 -2
  50. data/lib/networkx/traversals/dfs.rb +62 -6
  51. data/lib/networkx/traversals/edge_dfs.rb +36 -12
  52. data/lib/networkx/version.rb +1 -1
  53. data/lib/networkx.rb +7 -1
  54. data/networkx.gemspec +17 -14
  55. metadata +74 -84
  56. data/.rspec_formatter.rb +0 -24
  57. data/.travis.yml +0 -18
  58. data/Guardfile +0 -7
  59. 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 node_1 [Object] the first node of a given edge
14
- # @param node_2 [Object] the second node of a given edge
15
- def new_edge_key(node_1, node_2)
16
- return 0 if @adj[node_1][node_2].nil?
17
- key = @adj[node_1][node_2].length
18
- key += 1 while @adj[node_1][node_2].key?(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 node_1 [Object] the first node of the edge
31
- # @param node_2 [Object] the second node of the edge
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(node_1, node_2, **edge_attrs)
34
- add_node(node_1)
35
- add_node(node_2)
36
- key = new_edge_key(node_1, node_2)
37
- all_edge_attrs = @adj[node_1][node_2] || {}
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[node_1][node_2] = all_edge_attrs
40
- @pred[node_2][node_1] = all_edge_attrs
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 node_1 [Object] the first node of the edge
51
- # @param node_2 [Object] the second node of the edge
52
- def remove_edge(node_1, node_2, key=nil)
53
- if key.nil?
54
- super(node_1, node_2)
55
- return
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
- raise KeyError, "#{node_1} is not a valid node." unless @nodes.key?(node_1)
58
- raise KeyError, "#{node_2} is not a valid node" unless @nodes.key?(node_2)
59
- raise KeyError, 'The given edge is not a valid one.' unless @adj[node_1].key?(node_2)
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?(node_1, node_2)
68
+ # graph.edge?(node1, node2)
69
69
  #
70
- # @param node_1 [Object] the first node of the edge to be checked
71
- # @param node_2 [Object] the second node of the edge to be checked
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?(node_1, node_2, key=nil)
74
- super(node_1, node_2) if key.nil?
75
- node?(node_1) && @adj[node_1].key?(node_2) && @adj[node_1][node_2].key?(key)
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(@graph)
84
- @nodes.each { |node, node_attr| graph.add_node(node, node_attr) }
85
- @adj.each do |node_1, node_1_edges|
86
- node_1_edges.each do |node_2, node_1_node_2|
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
- node_1_node_2.each { |_key, attrs| edge_attrs.merge!(attrs) }
89
- graph.add_edge(node_1, node_2, edge_attrs)
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(@graph)
101
- @nodes.each { |node, node_attr| graph.add_node(node, node_attr) }
102
- @adj.each do |node_1, node_1_edges|
103
- node_1_edges.each do |node_2, node_1_node_2|
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
- node_1_node_2.each { |_key, attrs| edge_attrs.merge!(attrs) }
106
- graph.add_edge(node_1, node_2, edge_attrs)
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(@graph)
118
- @nodes.each { |node, node_attr| graph.add_node(node, node_attr) }
119
- @adj.each do |node_1, node_1_edges|
120
- node_1_edges.each_key do |node_2, node_1_node_2|
121
- edge_attrs = {}
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(@graph)
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(:length).inject(:+)
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(:length).inject(:+)
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).inject(:+)
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.key?(:weight) } }
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(@graph)
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.key?(u)
202
- sub_graph.add_node(u, @nodes[u])
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].key?(v) && nodes.include?(v) }
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(@graph)
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.key?(u)\
228
- && @adj[u].key?(v)
229
- sub_graph.add_node(u, @nodes[u])
230
- sub_graph.add_node(v, @nodes[v])
231
- @adj[u][v].each { |_, keyval| sub_graph.add_edge(u, v, keyval) }
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
- return sub_graph
238
+ sub_graph
234
239
  else
235
- raise ArgumentError, 'Expected Argument to be Array or Set of edges, '\
236
- "received #{edges.class.name} instead."
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
@@ -8,12 +8,13 @@ module NetworkX
8
8
  class MultiGraph < Graph
9
9
  # Returns a new key
10
10
  #
11
- # @param node_1 [Object] the first node of a given edge
12
- # @param node_2 [Object] the second node of a given edge
13
- def new_edge_key(node_1, node_2)
14
- return 0 if @adj[node_1][node_2].nil?
15
- key = @adj[node_1][node_2].length
16
- key += 1 while @adj[node_1][node_2].key?(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 node_1 [Object] the first node of the edge
29
- # @param node_2 [Object] the second node of the edge
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(node_1, node_2, **edge_attrs)
32
- add_node(node_1)
33
- add_node(node_2)
34
- key = new_edge_key(node_1, node_2)
35
- all_edge_attrs = @adj[node_1][node_2] || {}
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[node_1][node_2] = all_edge_attrs
38
- @adj[node_2][node_1] = all_edge_attrs
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 node_1 [Object] the first node of the edge
49
- # @param node_2 [Object] the second node of the edge
50
- def remove_edge(node_1, node_2, key=nil)
51
- if key.nil?
52
- super(node_1, node_2)
53
- return
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
- raise KeyError, "#{node_1} is not a valid node." unless @nodes.key?(node_1)
56
- raise KeyError, "#{node_2} is not a valid node" unless @nodes.key?(node_2)
57
- raise KeyError, 'The given edge is not a valid one.' unless @adj[node_1].key?(node_2)
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.key?(:weight) } }
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).inject(:+) / 2
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?(node_1, node_2)
93
+ # graph.edge?(node1, node2)
93
94
  #
94
- # @param node_1 [Object] the first node of the edge to be checked
95
- # @param node_2 [Object] the second node of the edge to be checked
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?(node_1, node_2, key=nil)
98
- super(node_1, node_2) if key.nil?
99
- node?(node_1) && @adj[node_1].key?(node_2) && @adj[node_1][node_2].key?(key)
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(@graph)
108
- @nodes.each { |node, node_attr| graph.add_node(node, node_attr) }
109
- @adj.each do |node_1, node_1_edges|
110
- node_1_edges.each do |node_2, node_1_node_2|
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
- node_1_node_2.each { |_key, attrs| edge_attrs.merge!(attrs) }
113
- graph.add_edge(node_1, node_2, edge_attrs)
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(@graph)
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.key?(u)
133
- sub_graph.add_node(u, @nodes[u])
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
- edge_val.each { |_, keyval| sub_graph.add_edge(u, v, keyval) if @adj[u].key?(v) && nodes.include?(v) }
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(@graph)
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.key?(u)\
159
- && @adj[u].key?(v)
160
- sub_graph.add_node(u, @nodes[u])
161
- sub_graph.add_node(v, @nodes[v])
162
- @adj[u][v].each { |_, keyval| sub_graph.add_edge(u, v, keyval) }
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
- return sub_graph
188
+ sub_graph
165
189
  else
166
- raise ArgumentError, 'Expected Argument to be Array or Set of edges, '\
167
- "received #{edges.class.name} instead."
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|