networkx 0.1.1 → 0.2.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 (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