networkx 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) 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/.github/workflows/gem-push.yml +45 -0
  9. data/.rspec +0 -1
  10. data/.rubocop.yml +57 -71
  11. data/.yardopts +0 -1
  12. data/README.md +27 -27
  13. data/Rakefile +2 -3
  14. data/lib/networkx/auxillary_functions/cliques.rb +9 -12
  15. data/lib/networkx/auxillary_functions/cycles.rb +17 -7
  16. data/lib/networkx/auxillary_functions/dag.rb +10 -5
  17. data/lib/networkx/auxillary_functions/eccentricity.rb +2 -1
  18. data/lib/networkx/auxillary_functions/mis.rb +2 -2
  19. data/lib/networkx/auxillary_functions/mst.rb +1 -3
  20. data/lib/networkx/auxillary_functions/union_find.rb +92 -12
  21. data/lib/networkx/auxillary_functions/wiener.rb +1 -1
  22. data/lib/networkx/converters/to_csv.rb +1 -3
  23. data/lib/networkx/converters/to_json.rb +0 -2
  24. data/lib/networkx/digraph.rb +55 -49
  25. data/lib/networkx/flow/capacityscaling.rb +29 -35
  26. data/lib/networkx/flow/edmondskarp.rb +17 -15
  27. data/lib/networkx/flow/preflowpush.rb +29 -32
  28. data/lib/networkx/flow/shortestaugmentingpath.rb +17 -20
  29. data/lib/networkx/flow/utils.rb +6 -27
  30. data/lib/networkx/graph.rb +179 -72
  31. data/lib/networkx/link_analysis/hits.rb +9 -9
  32. data/lib/networkx/link_analysis/pagerank.rb +48 -6
  33. data/lib/networkx/multidigraph.rb +90 -81
  34. data/lib/networkx/multigraph.rb +91 -63
  35. data/lib/networkx/operators/all.rb +8 -4
  36. data/lib/networkx/operators/binary.rb +106 -128
  37. data/lib/networkx/operators/product.rb +61 -64
  38. data/lib/networkx/operators/unary.rb +1 -1
  39. data/lib/networkx/others/bridges.rb +30 -0
  40. data/lib/networkx/others/generators.rb +237 -0
  41. data/lib/networkx/others/grid_2d_graph.rb +38 -0
  42. data/lib/networkx/others/info.rb +11 -0
  43. data/lib/networkx/others/number_connected_components.rb +17 -0
  44. data/lib/networkx/others/reads.rb +52 -0
  45. data/lib/networkx/shortest_path/astar.rb +10 -8
  46. data/lib/networkx/shortest_path/dense.rb +1 -3
  47. data/lib/networkx/shortest_path/unweighted.rb +13 -16
  48. data/lib/networkx/shortest_path/weighted.rb +51 -42
  49. data/lib/networkx/to_matrix.rb +2 -3
  50. data/lib/networkx/traversals/bfs.rb +54 -2
  51. data/lib/networkx/traversals/dfs.rb +62 -6
  52. data/lib/networkx/traversals/edge_dfs.rb +36 -12
  53. data/lib/networkx/version.rb +1 -1
  54. data/lib/networkx.rb +7 -1
  55. data/networkx.gemspec +12 -13
  56. metadata +71 -81
  57. data/.rspec_formatter.rb +0 -24
  58. data/.travis.yml +0 -18
  59. data/Guardfile +0 -7
  60. data/RELEASE_POLICY.md +0 -20
@@ -1,227 +1,205 @@
1
- # TODO: Reduce module length
2
-
3
1
  module NetworkX
4
2
  # Returns the edges of the graph in an array
5
3
  def self.get_edges(graph)
6
4
  edges = []
7
- graph.adj.each do |u, u_attrs|
8
- u_attrs.each do |v, uv_attrs|
9
- edges << [u, v, uv_attrs]
5
+ if graph.is_a?(MultiGraph)
6
+ graph.adj.each do |u, v_keys|
7
+ v_keys.each do |v, key_attrs|
8
+ next if u > v
9
+
10
+ key_attrs.each do |_key, attributes|
11
+ edges << [u, v, attributes]
12
+ end
13
+ end
14
+ end
15
+ else
16
+ graph.adj.each do |u, u_attrs|
17
+ u_attrs.each do |v, uv_attrs|
18
+ edges << [u, v, uv_attrs]
19
+ end
10
20
  end
11
21
  end
12
22
  edges
13
23
  end
14
24
 
15
- # TODO: Reduce method complexity and method length
16
-
17
25
  # Transforms the labels of the nodes of the graphs
18
26
  # so that they are disjoint.
19
- def self.convert_to_distinct_labels(graph, starting_int=-1)
20
- new_graph = Marshal.load(Marshal.dump(graph))
21
- new_graph.clear
27
+ def self.convert_to_distinct_labels(graph, starting_int = -1)
28
+ new_graph = graph.class.new
22
29
 
23
- idx_dict = Hash[graph.nodes.keys.map do |v|
30
+ idx_dict = graph.nodes.keys.to_h do |v|
24
31
  starting_int += 1
25
32
  [v, starting_int]
26
- end]
33
+ end
27
34
 
28
35
  graph.nodes.each do |u, attrs|
29
- new_graph.add_node(u.to_s + idx_dict[u].to_s, attrs)
36
+ new_graph.add_node(u.to_s + idx_dict[u].to_s, **attrs)
30
37
  end
31
38
 
32
39
  graph.adj.each do |u, u_edges|
33
40
  u_edges.each do |v, uv_attrs|
34
41
  if graph.multigraph?
35
42
  uv_attrs.each do |_k, attrs|
36
- new_graph.add_edge(u.to_s + idx_dict[u].to_s, v.to_s + idx_dict[v].to_s, attrs)
43
+ new_graph.add_edge(u.to_s + idx_dict[u].to_s, v.to_s + idx_dict[v].to_s, **attrs)
37
44
  end
38
45
  else
39
- new_graph.add_edge(u.to_s + idx_dict[u].to_s, v.to_s + idx_dict[v].to_s, uv_attrs)
46
+ new_graph.add_edge(u.to_s + idx_dict[u].to_s, v.to_s + idx_dict[v].to_s, **uv_attrs)
40
47
  end
41
48
  end
42
49
  end
43
50
  new_graph
44
51
  end
45
52
 
46
- # TODO: Reduce method complexity and method length
47
-
48
53
  # Performs the intersection of two graphs
49
54
  #
50
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
51
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
55
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
56
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
52
57
  #
53
58
  # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the intersection of the two graphs
54
- def self.intersection(g_1, g_2)
55
- result = Marshal.load(Marshal.dump(g_1))
56
- result.clear
57
-
58
- raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g_1.multigraph? == g_2.multigraph?
59
- raise ArgumentError, 'Node sets must be equal!' unless (g_1.nodes.keys - g_2.nodes.keys).empty?
60
-
61
- g_1.nodes.each { |u, attrs| result.add_node(u, attrs) }
62
-
63
- if g_1.number_of_edges <= g_2.number_of_edges
64
- g_1.adj.each do |u, u_edges|
65
- u_edges.each do |v, uv_attrs|
66
- if g_1.multigraph?
67
- uv_attrs.each do |k, attrs|
68
- result.add_edge(u, v, attrs) if g_2.edge?(u, v, k)
69
- end
70
- elsif g_2.edge?(u, v)
71
- result.add_edge(u, v, uv_attrs)
72
- end
73
- end
74
- end
75
- else
76
- g_2.adj.each do |u, u_edges|
77
- u_edges.each do |v, uv_attrs|
78
- if g_2.multigraph?
79
- uv_attrs.each do |k, attrs|
80
- result.add_edge(u, v, attrs) if g_1.edge?(u, v, k)
81
- end
82
- elsif g_1.edge?(u, v)
83
- result.add_edge(u, v, uv_attrs)
59
+ def self.intersection(g1, g2)
60
+ result = g1.class.new
61
+
62
+ raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
63
+ raise ArgumentError, 'Node sets must be equal!' unless (g1.nodes.keys - g2.nodes.keys).empty?
64
+
65
+ g1.nodes.each { |u, attrs| result.add_node(u, **attrs) }
66
+
67
+ g1, g2 = g2, g1 if g1.number_of_edges > g2.number_of_edges
68
+ g1.adj.each do |u, u_edges|
69
+ u_edges.each do |v, uv_attrs|
70
+ if g1.multigraph?
71
+ next if u > v && g1.instance_of?(MultiGraph)
72
+
73
+ uv_attrs.each do |k, attrs|
74
+ result.add_edge(u, v, **attrs) if g2.edge?(u, v, k)
84
75
  end
76
+ elsif g2.edge?(u, v)
77
+ result.add_edge(u, v, **uv_attrs)
85
78
  end
86
79
  end
87
80
  end
88
81
  result
89
82
  end
90
83
 
91
- # TODO: Reduce method complexity and method length
92
-
93
84
  # Performs the difference of two graphs
94
85
  #
95
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
96
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
86
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
87
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
97
88
  #
98
89
  # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the difference of the two graphs
99
- def self.difference(g_1, g_2)
100
- result = Marshal.load(Marshal.dump(g_1))
101
- result.clear
90
+ def self.difference(g1, g2)
91
+ result = g1.class.new
102
92
 
103
- raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g_1.multigraph? == g_2.multigraph?
104
- raise ArgumentError, 'Node sets must be equal!' unless (g_1.nodes.keys - g_2.nodes.keys).empty?
93
+ raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
94
+ raise ArgumentError, 'Node sets must be equal!' unless (g1.nodes.keys - g2.nodes.keys).empty?
105
95
 
106
- g_1.nodes.each { |u, attrs| result.add_node(u, attrs) }
96
+ g1.nodes.each { |u, attrs| result.add_node(u, **attrs) }
107
97
 
108
- g_1.adj.each do |u, u_edges|
98
+ g1.adj.each do |u, u_edges|
109
99
  u_edges.each do |v, uv_attrs|
110
- if g_1.multigraph?
100
+ if g1.multigraph?
101
+ next if u > v && g1.instance_of?(MultiGraph)
102
+
111
103
  uv_attrs.each do |k, attrs|
112
- result.add_edge(u, v, attrs) unless g_2.edge?(u, v, k)
104
+ result.add_edge(u, v, **attrs) unless g2.edge?(u, v, k)
113
105
  end
114
106
  else
115
- result.add_edge(u, v, uv_attrs) unless g_2.edge?(u, v)
107
+ result.add_edge(u, v, **uv_attrs) unless g2.edge?(u, v)
116
108
  end
117
109
  end
118
110
  end
119
111
  result
120
112
  end
121
113
 
122
- # TODO: Reduce method complexity and method length
123
-
124
114
  # Performs the symmetric difference of two graphs
125
115
  #
126
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
127
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
116
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
117
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
128
118
  #
129
119
  # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the symmetric difference of the two graphs
130
- def self.symmetric_difference(g_1, g_2)
131
- result = Marshal.load(Marshal.dump(g_1))
132
- result.clear
120
+ def self.symmetric_difference(g1, g2)
121
+ result = g1.class.new
133
122
 
134
- raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g_1.multigraph? == g_2.multigraph?
135
- raise ArgumentError, 'Node sets must be equal!' unless (g_1.nodes.keys - g_2.nodes.keys).empty?
123
+ raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
124
+ raise ArgumentError, 'Node sets must be equal!' unless (g1.nodes.keys - g2.nodes.keys).empty?
136
125
 
137
- g_1.nodes.each { |u, attrs| result.add_node(u, attrs) }
126
+ g1.nodes.each { |u, attrs| result.add_node(u, **attrs) }
138
127
 
139
- g_1.adj.each do |u, u_edges|
128
+ g1.adj.each do |u, u_edges|
140
129
  u_edges.each do |v, uv_attrs|
141
- if g_1.multigraph?
130
+ if g1.multigraph?
131
+ next if u > v && g1.instance_of?(MultiGraph)
132
+
142
133
  uv_attrs.each do |k, attrs|
143
- result.add_edge(u, v, attrs) unless g_2.edge?(u, v, k)
134
+ result.add_edge(u, v, **attrs) unless g2.edge?(u, v, k)
144
135
  end
145
136
  else
146
- result.add_edge(u, v, uv_attrs) unless g_2.edge?(u, v)
137
+ result.add_edge(u, v, **uv_attrs) unless g2.edge?(u, v)
147
138
  end
148
139
  end
149
140
  end
150
141
 
151
- g_2.adj.each do |u, u_edges|
142
+ g2.adj.each do |u, u_edges|
152
143
  u_edges.each do |v, uv_attrs|
153
- if g_2.multigraph?
144
+ next if u > v && g1.instance_of?(MultiGraph)
145
+
146
+ if g2.multigraph?
154
147
  uv_attrs.each do |k, attrs|
155
- result.add_edge(u, v, attrs) unless g_1.edge?(u, v, k)
148
+ result.add_edge(u, v, **attrs) unless g1.edge?(u, v, k)
156
149
  end
157
150
  else
158
- result.add_edge(u, v, uv_attrs) unless g_1.edge?(u, v)
151
+ result.add_edge(u, v, **uv_attrs) unless g1.edge?(u, v)
159
152
  end
160
153
  end
161
154
  end
162
155
  result
163
156
  end
164
157
 
165
- # TODO: Reduce method complexity and method length
166
-
167
158
  # Performs the composition of two graphs
168
159
  #
169
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
170
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
160
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
161
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
171
162
  #
172
163
  # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the composition of the two graphs
173
- def self.compose(g_1, g_2)
174
- result = Marshal.load(Marshal.dump(g_1))
175
- result.clear
164
+ def self.compose(g1, g2)
165
+ result = g1.class.new
176
166
 
177
- raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g_1.multigraph? == g_2.multigraph?
167
+ raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
178
168
 
179
- result.add_nodes(g_1.nodes.map { |u, attrs| [u, attrs] })
180
- result.add_nodes(g_2.nodes.map { |u, attrs| [u, attrs] })
169
+ result.add_nodes(g1.nodes.map { |u, attrs| [u, attrs] })
170
+ result.add_nodes(g2.nodes.map { |u, attrs| [u, attrs] })
181
171
 
182
- if g_1.multigraph?
183
- g_1.adj.each { |u, e| e.each { |v, uv_edges| uv_edges.each_value { |attrs| result.add_edge(u, v, attrs) } } }
184
- g_2.adj.each { |u, e| e.each { |v, uv_edges| uv_edges.each_value { |attrs| result.add_edge(u, v, attrs) } } }
172
+ if g1.multigraph?
173
+ g1.adj.each { |u, e| e.each { |v, uv_edges| uv_edges.each_value { |attrs| result.add_edge(u, v, **attrs) } } }
174
+ g2.adj.each { |u, e| e.each { |v, uv_edges| uv_edges.each_value { |attrs| result.add_edge(u, v, **attrs) } } }
185
175
  else
186
- g_1.adj.each { |u, u_edges| u_edges.each { |v, attrs| result.add_edge(u, v, attrs) } }
187
- g_2.adj.each { |u, u_edges| u_edges.each { |v, attrs| result.add_edge(u, v, attrs) } }
176
+ g1.adj.each { |u, u_edges| u_edges.each { |v, attrs| result.add_edge(u, v, **attrs) } }
177
+ g2.adj.each { |u, u_edges| u_edges.each { |v, attrs| result.add_edge(u, v, **attrs) } }
188
178
  end
189
179
  result
190
180
  end
191
181
 
192
- # TODO: Reduce method complexity and method length
193
-
194
182
  # Performs the union of two graphs
195
183
  #
196
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
197
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
184
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
185
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
198
186
  #
199
187
  # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the union of the two graphs
200
- def self.union(g_1, g_2)
201
- raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g_1.multigraph? == g_2.multigraph?
202
-
203
- case g_1
204
- when NetworkX::MultiGraph
205
- new_graph = NetworkX::MultiGraph.new
206
- when NetworkX::MultiDiGraph
207
- new_graph = NetworkX::MultiDiGraph.new
208
- when NetworkX::Graph
209
- new_graph = NetworkX::Graph.new
210
- when NetworkX::DiGraph
211
- new_graph = NetworkX::DiGraph.new
212
- end
188
+ def self.union(g1, g2)
189
+ raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
213
190
 
214
- new_graph.graph.merge!(g_1.graph)
215
- new_graph.graph.merge!(g_2.graph)
191
+ new_graph = g1.class.new
192
+ new_graph.graph.merge!(g1.graph)
193
+ new_graph.graph.merge!(g2.graph)
216
194
 
217
- raise ArgumentError, 'Graphs must be disjoint!' unless (g_1.nodes.keys & g_2.nodes.keys).empty?
195
+ raise ArgumentError, 'Graphs must be disjoint!' unless (g1.nodes.keys & g2.nodes.keys).empty?
218
196
 
219
- g1_edges = get_edges(g_1)
220
- g2_edges = get_edges(g_2)
197
+ g1_edges = get_edges(g1)
198
+ g2_edges = get_edges(g2)
221
199
 
222
- new_graph.add_nodes(g_1.nodes.keys)
200
+ new_graph.add_nodes(g1.nodes.keys)
223
201
  new_graph.add_edges(g1_edges)
224
- new_graph.add_nodes(g_2.nodes.keys)
202
+ new_graph.add_nodes(g2.nodes.keys)
225
203
  new_graph.add_edges(g2_edges)
226
204
 
227
205
  new_graph
@@ -229,16 +207,16 @@ module NetworkX
229
207
 
230
208
  # Performs the disjoint union of two graphs
231
209
  #
232
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
233
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
210
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
211
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
234
212
  #
235
213
  # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the disjoint union of the two graphs
236
- def self.disjoint_union(g_1, g_2)
237
- new_g_1 = convert_to_distinct_labels(g_1)
238
- new_g_2 = convert_to_distinct_labels(g_2)
239
- result = union(new_g_1, new_g_2)
240
- result.graph.merge!(g_1.graph)
241
- result.graph.merge!(g_2.graph)
214
+ def self.disjoint_union(g1, g2)
215
+ new_g1 = convert_to_distinct_labels(g1)
216
+ new_g2 = convert_to_distinct_labels(g2)
217
+ result = union(new_g1, new_g2)
218
+ result.graph.merge!(g1.graph)
219
+ result.graph.merge!(g2.graph)
242
220
  result
243
221
  end
244
222
  end
@@ -1,8 +1,4 @@
1
- # TODO: Reduce module length
2
-
3
1
  module NetworkX
4
- # TODO: Reduce method length
5
-
6
2
  # Returns the edges of the graph in an array
7
3
  def self.edges_in_array(graph)
8
4
  edge_array = []
@@ -25,26 +21,26 @@ module NetworkX
25
21
  end
26
22
 
27
23
  # Returns the hash product of two hashes
28
- def self.hash_product(hash_1, hash_2)
29
- Hash[(hash_1.keys | hash_2.keys).map { |n| [n, [hash_1[n], hash_2[n]]] }]
24
+ def self.hash_product(hash1, hash2)
25
+ (hash1.keys | hash2.keys).to_h { |n| [n, [hash1[n], hash2[n]]] }
30
26
  end
31
27
 
32
28
  # Returns the node product of nodes of two graphs
33
- def self.node_product(g_1, g_2)
29
+ def self.node_product(g1, g2)
34
30
  n_product = []
35
- g_1.nodes.each do |k_1, attrs_1|
36
- g_2.nodes.each do |k_2, attrs_2|
37
- n_product << [[k_1, k_2], hash_product(attrs_1, attrs_2)]
31
+ g1.nodes.each do |k1, attrs1|
32
+ g2.nodes.each do |k2, attrs2|
33
+ n_product << [[k1, k2], hash_product(attrs1, attrs2)]
38
34
  end
39
35
  end
40
36
  n_product
41
37
  end
42
38
 
43
39
  # Returns the product of directed edges with edges
44
- def self.directed_edges_cross_edges(g_1, g_2)
40
+ def self.directed_edges_cross_edges(g1, g2)
45
41
  result = []
46
- edges_in_array(g_1).each do |u, v, c|
47
- edges_in_array(g_2) do |x, y, d|
42
+ edges_in_array(g1).each do |u, v, c|
43
+ edges_in_array(g2).each do |x, y, d|
48
44
  result << [[u, x], [v, y], hash_product(c, d)]
49
45
  end
50
46
  end
@@ -52,10 +48,10 @@ module NetworkX
52
48
  end
53
49
 
54
50
  # Returns the product of undirected edges with edges
55
- def self.undirected_edges_cross_edges(g_1, g_2)
51
+ def self.undirected_edges_cross_edges(g1, g2)
56
52
  result = []
57
- edges_in_array(g_1).each do |u, v, c|
58
- edges_in_array(g_2).each do |x, y, d|
53
+ edges_in_array(g1).each do |u, v, c|
54
+ edges_in_array(g2).each do |x, y, d|
59
55
  result << [[v, x], [u, y], hash_product(c, d)]
60
56
  end
61
57
  end
@@ -63,10 +59,10 @@ module NetworkX
63
59
  end
64
60
 
65
61
  # Returns the product of edges with edges
66
- def self.edges_cross_nodes(g_1, g_2)
62
+ def self.edges_cross_nodes(g1, g2)
67
63
  result = []
68
- edges_in_array(g_1).each do |u, v, d|
69
- g_2.nodes.keys.each do |x|
64
+ edges_in_array(g1).each do |u, v, d|
65
+ g2.nodes.each_key do |x|
70
66
  result << [[u, x], [v, x], d]
71
67
  end
72
68
  end
@@ -74,10 +70,10 @@ module NetworkX
74
70
  end
75
71
 
76
72
  # Returns the product of directed nodes with edges
77
- def self.nodes_cross_edges(g_1, g_2)
73
+ def self.nodes_cross_edges(g1, g2)
78
74
  result = []
79
- g_1.nodes.keys.each do |x|
80
- edges_in_array(g_2).each do |u, v, d|
75
+ g1.nodes.each_key do |x|
76
+ edges_in_array(g2).each do |u, v, d|
81
77
  result << [[x, u], [x, v], d]
82
78
  end
83
79
  end
@@ -85,11 +81,11 @@ module NetworkX
85
81
  end
86
82
 
87
83
  # Returns the product of edges with pairs of nodes
88
- def self.edges_cross_nodes_and_nodes(g_1, g_2)
84
+ def self.edges_cross_nodes_and_nodes(g1, g2)
89
85
  result = []
90
- edges_in_array(g_1).each do |u, v, d|
91
- g_2.nodes.keys.each do |x|
92
- g_2.nodes.keys.each do |y|
86
+ edges_in_array(g1).each do |u, v, d|
87
+ g2.nodes.each_key do |x|
88
+ g2.nodes.each_key do |y|
93
89
  result << [[u, x], [v, y], d]
94
90
  end
95
91
  end
@@ -98,10 +94,10 @@ module NetworkX
98
94
  end
99
95
 
100
96
  # Initializes the product graph
101
- def self.init_product_graph(g_1, g_2)
102
- raise ArgumentError, 'Arguments must be both directed or undirected!' unless g_1.directed? == g_2.directed?
97
+ def self.init_product_graph(g1, g2)
98
+ raise ArgumentError, 'Arguments must be both directed or undirected!' unless g1.directed? == g2.directed?
103
99
 
104
- g = if g_1.multigraph? || g_2.multigraph?
100
+ g = if g1.multigraph? || g2.multigraph?
105
101
  NetworkX::MultiGraph.new
106
102
  else
107
103
  NetworkX::Graph.new
@@ -112,72 +108,71 @@ module NetworkX
112
108
 
113
109
  # Returns the tensor product of two graphs
114
110
  #
115
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
116
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
111
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
112
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
117
113
  #
118
114
  # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the tensor product of the two graphs
119
- def self.tensor_product(g_1, g_2)
120
- g = init_product_graph(g_1, g_2)
121
- g.add_nodes(node_product(g_1, g_2))
122
- g.add_edges(directed_edges_cross_edges(g_1, g_2))
123
- g.add_edges(undirected_edges_cross_edges(g_1, g_2)) unless g.directed?
115
+ def self.tensor_product(g1, g2)
116
+ g = init_product_graph(g1, g2)
117
+ g.add_nodes(node_product(g1, g2))
118
+ g.add_edges(directed_edges_cross_edges(g1, g2))
119
+ g.add_edges(undirected_edges_cross_edges(g1, g2)) unless g.directed?
124
120
  g
125
121
  end
126
122
 
127
123
  # Returns the cartesian product of two graphs
128
124
  #
129
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
130
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
125
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
126
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
131
127
  #
132
128
  # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the cartesian product of the two graphs
133
- def self.cartesian_product(g_1, g_2)
134
- g = init_product_graph(g_1, g_2)
135
- g.add_nodes(node_product(g_1, g_2))
136
- g.add_edges(edges_cross_nodes(g_1, g_2))
137
- g.add_edges(nodes_cross_edges(g_1, g_2))
129
+ def self.cartesian_product(g1, g2)
130
+ g = init_product_graph(g1, g2)
131
+ g.add_nodes(node_product(g1, g2))
132
+ g.add_edges(edges_cross_nodes(g1, g2))
133
+ g.add_edges(nodes_cross_edges(g1, g2))
138
134
  g
139
135
  end
140
136
 
141
137
  # Returns the lexicographic product of two graphs
142
138
  #
143
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
144
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
139
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
140
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
145
141
  #
146
142
  # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the lexicographic product of the two graphs
147
- def self.lexicographic_product(g_1, g_2)
148
- g = init_product_graph(g_1, g_2)
149
- g.add_nodes(node_product(g_1, g_2))
150
- g.add_edges(edges_cross_nodes_and_nodes(g_1, g_2))
151
- g.add_edges(nodes_cross_edges(g_1, g_2))
143
+ def self.lexicographic_product(g1, g2)
144
+ g = init_product_graph(g1, g2)
145
+ g.add_nodes(node_product(g1, g2))
146
+ g.add_edges(edges_cross_nodes_and_nodes(g1, g2))
147
+ g.add_edges(nodes_cross_edges(g1, g2))
152
148
  g
153
149
  end
154
150
 
155
151
  # Returns the strong product of two graphs
156
152
  #
157
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
158
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
153
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
154
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
159
155
  #
160
156
  # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the strong product of the two graphs
161
- def self.strong_product(g_1, g_2)
162
- g = init_product_graph(g_1, g_2)
163
- g.add_nodes(node_product(g_1, g_2))
164
- g.add_edges(nodes_cross_edges(g_1, g_2))
165
- g.add_edges(edges_cross_nodes(g_1, g_2))
166
- g.add_edges(directed_edges_cross_edges(g_1, g_2))
167
- g.add_edges(undirected_edges_cross_edges(g_1, g_2)) unless g.directed?
157
+ def self.strong_product(g1, g2)
158
+ g = init_product_graph(g1, g2)
159
+ g.add_nodes(node_product(g1, g2))
160
+ g.add_edges(nodes_cross_edges(g1, g2))
161
+ g.add_edges(edges_cross_nodes(g1, g2))
162
+ g.add_edges(directed_edges_cross_edges(g1, g2))
163
+ g.add_edges(undirected_edges_cross_edges(g1, g2)) unless g.directed?
168
164
  g
169
165
  end
170
166
 
171
- # TODO: Reduce method complexity and method length
172
-
173
167
  # Returns the specified power of the graph
174
168
  #
175
- # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
176
- # @param [Numeric] the power to which to raise the graph to
169
+ # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
170
+ # @param pow [Numeric] the power to which to raise the graph to
177
171
  #
178
172
  # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the power of the graph
179
173
  def self.power(graph, pow)
180
174
  raise ArgumentError, 'Power must be a positive quantity!' if pow <= 0
175
+
181
176
  result = NetworkX::Graph.new
182
177
  result.add_nodes(graph.nodes.map { |n, attrs| [n, attrs] })
183
178
  graph.nodes.each do |n, _attrs|
@@ -189,12 +184,14 @@ module NetworkX
189
184
  next_level = {}
190
185
  this_level.each do |v, _attrs|
191
186
  next if v == n
192
- unless seen.key?(v)
187
+
188
+ unless seen.has_key?(v)
193
189
  seen[v] = level
194
190
  next_level.merge!(graph.adj[v])
195
191
  end
196
192
  end
197
193
  break if pow <= level
194
+
198
195
  level += 1
199
196
  end
200
197
  result.add_edges(seen.map { |v, _| [n, v] })
@@ -10,7 +10,7 @@ module NetworkX
10
10
 
11
11
  result.add_nodes(graph.nodes.map { |u, attrs| [u, attrs] })
12
12
  graph.adj.each do |u, u_edges|
13
- graph.nodes.each { |v, attrs| result.add_edge(u, v, attrs) if !u_edges.key?(v) && u != v }
13
+ graph.nodes.each { |v, attrs| result.add_edge(u, v, **attrs) if !u_edges.has_key?(v) && u != v }
14
14
  end
15
15
  result
16
16
  end
@@ -0,0 +1,30 @@
1
+ require_relative '../auxillary_functions/union_find'
2
+
3
+ module NetworkX
4
+ # @return [[Object, Object]] bridges
5
+ #
6
+ # @param graph [Graph] Graph
7
+ def self.bridges(graph)
8
+ each_bridge(graph).to_a
9
+ end
10
+
11
+ # @param graph [Graph] Graph
12
+ def self.each_bridge(graph)
13
+ return enum_for(:each_bridge, graph) unless block_given?
14
+
15
+ graph.each_edge.with_index do |(s_i, t_i), i|
16
+ uf = UnionFind.new(1..graph.number_of_nodes)
17
+ graph.each_edge.with_index do |(s_j, t_j), j|
18
+ uf.unite(s_j, t_j) if i != j
19
+ end
20
+ yield [s_i, t_i] unless uf.same?(s_i, t_i)
21
+ end
22
+ end
23
+
24
+ # @return [Integer] the number of bridges
25
+ #
26
+ # @param graph [Graph] Graph
27
+ def self.number_of_bridges(graph)
28
+ bridges(graph).size
29
+ end
30
+ end