networkx 0.1.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,19 +1,15 @@
|
|
1
|
-
# TODO: Reduce module length
|
2
|
-
|
3
1
|
module NetworkX
|
4
2
|
# Helper function to extract weight from a adjecency hash
|
5
3
|
def self.get_weight(graph)
|
6
|
-
|
4
|
+
lambda do |_, _, attrs|
|
7
5
|
return attrs[:weight] || 1 unless graph.multigraph?
|
6
|
+
|
8
7
|
attrs.group_by { |_k, vals| vals[:weight] || 1 }.keys.max
|
9
8
|
end
|
10
|
-
weight_get
|
11
9
|
end
|
12
10
|
|
13
|
-
# TODO: Reduce method length and method complexity
|
14
|
-
|
15
11
|
# Helper function for multisource dijkstra
|
16
|
-
def self.help_multisource_dijkstra(graph, sources, weight, pred=nil, paths=nil, cutoff=nil, target=nil)
|
12
|
+
def self.help_multisource_dijkstra(graph, sources, weight, pred = nil, paths = nil, cutoff = nil, target = nil)
|
17
13
|
count = ->(i) { i + 1 }
|
18
14
|
i = -1
|
19
15
|
dist = {}
|
@@ -26,17 +22,21 @@ module NetworkX
|
|
26
22
|
|
27
23
|
until fringe.empty?
|
28
24
|
d, _, v = fringe.pop
|
29
|
-
next if dist.
|
25
|
+
next if dist.has_key?(v)
|
26
|
+
|
30
27
|
dist[v] = d
|
31
28
|
break if v == target
|
29
|
+
|
32
30
|
graph.adj[v].each do |u, attrs|
|
33
31
|
cost = weight.call(v, u, attrs)
|
34
32
|
next if cost.nil?
|
33
|
+
|
35
34
|
vu_dist = dist[v] + cost
|
36
35
|
next if !cutoff.nil? && vu_dist > cutoff
|
37
|
-
|
36
|
+
|
37
|
+
if dist.has_key?(u)
|
38
38
|
raise ValueError, 'Contradictory weights found!' if vu_dist < dist[u]
|
39
|
-
elsif !seen.
|
39
|
+
elsif !seen.has_key?(u) || vu_dist < seen[u]
|
40
40
|
seen[u] = vu_dist
|
41
41
|
fringe << [vu_dist, count.call(i), u]
|
42
42
|
paths[u] = paths[v] + [u] unless paths.nil?
|
@@ -50,7 +50,7 @@ module NetworkX
|
|
50
50
|
end
|
51
51
|
|
52
52
|
# Helper function for single source dijkstra
|
53
|
-
def self.help_dijkstra(graph, source, weight, pred=nil, paths=nil, cutoff=nil, target=nil)
|
53
|
+
def self.help_dijkstra(graph, source, weight, pred = nil, paths = nil, cutoff = nil, target = nil)
|
54
54
|
help_multisource_dijkstra(graph, [source], weight, pred, paths, cutoff, target)
|
55
55
|
end
|
56
56
|
|
@@ -62,15 +62,17 @@ module NetworkX
|
|
62
62
|
# @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm
|
63
63
|
#
|
64
64
|
# @return [Numeric, Array<Object>] path lengths for all nodes
|
65
|
-
def self.multisource_dijkstra(graph, sources, target=nil, cutoff=nil)
|
65
|
+
def self.multisource_dijkstra(graph, sources, target = nil, cutoff = nil)
|
66
66
|
raise ValueError, 'Sources cannot be empty' if sources.empty?
|
67
67
|
return [0, [target]] if sources.include?(target)
|
68
|
+
|
68
69
|
paths = {}
|
69
70
|
weight = get_weight(graph)
|
70
71
|
sources.each { |source| paths[source] = [source] }
|
71
72
|
dist = help_multisource_dijkstra(graph, sources, weight, nil, paths, cutoff, target)
|
72
73
|
return [dist, paths] if target.nil?
|
73
|
-
raise KeyError, "No path to #{target}!" unless dist.
|
74
|
+
raise KeyError, "No path to #{target}!" unless dist.has_key?(target)
|
75
|
+
|
74
76
|
[dist[target], paths[target]]
|
75
77
|
end
|
76
78
|
|
@@ -81,8 +83,9 @@ module NetworkX
|
|
81
83
|
# @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm
|
82
84
|
#
|
83
85
|
# @return [Hash{ Object => Numeric }] path lengths for any nodes from given nodes
|
84
|
-
def self.multisource_dijkstra_path_length(graph, sources, cutoff=nil)
|
86
|
+
def self.multisource_dijkstra_path_length(graph, sources, cutoff = nil)
|
85
87
|
raise ValueError, 'Sources cannot be empty' if sources.empty?
|
88
|
+
|
86
89
|
weight = get_weight(graph)
|
87
90
|
help_multisource_dijkstra(graph, sources, weight, nil, nil, cutoff)
|
88
91
|
end
|
@@ -94,7 +97,7 @@ module NetworkX
|
|
94
97
|
# @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm
|
95
98
|
#
|
96
99
|
# @return [Hash{ Object => Array<Object> }] paths for any nodes from given nodes
|
97
|
-
def self.multisource_dijkstra_path(graph, sources, cutoff=nil)
|
100
|
+
def self.multisource_dijkstra_path(graph, sources, cutoff = nil)
|
98
101
|
_, path = multisource_dijkstra(graph, sources, nil, cutoff)
|
99
102
|
path
|
100
103
|
end
|
@@ -107,7 +110,7 @@ module NetworkX
|
|
107
110
|
# @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm
|
108
111
|
#
|
109
112
|
# @return [Hash{ Object => Array<Object> }, Array<Object>] paths for all nodes/target node from given node
|
110
|
-
def self.singlesource_dijkstra(graph, source, target=nil, cutoff=nil)
|
113
|
+
def self.singlesource_dijkstra(graph, source, target = nil, cutoff = nil)
|
111
114
|
multisource_dijkstra(graph, [source], target, cutoff)
|
112
115
|
end
|
113
116
|
|
@@ -118,7 +121,7 @@ module NetworkX
|
|
118
121
|
# @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm
|
119
122
|
#
|
120
123
|
# @return [Hash{ Object => Numeric }] path lengths for all nodes from given node
|
121
|
-
def self.singlesource_dijkstra_path_length(graph, source, cutoff=nil)
|
124
|
+
def self.singlesource_dijkstra_path_length(graph, source, cutoff = nil)
|
122
125
|
multisource_dijkstra_path_length(graph, [source], cutoff)
|
123
126
|
end
|
124
127
|
|
@@ -129,7 +132,7 @@ module NetworkX
|
|
129
132
|
# @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm
|
130
133
|
#
|
131
134
|
# @return [Hash{ Object => Array<Object> }] paths for all nodes from given node
|
132
|
-
def self.singlesource_dijkstra_path(graph, source, cutoff=nil)
|
135
|
+
def self.singlesource_dijkstra_path(graph, source, cutoff = nil)
|
133
136
|
multisource_dijkstra_path(graph, [source], cutoff)
|
134
137
|
end
|
135
138
|
|
@@ -142,9 +145,11 @@ module NetworkX
|
|
142
145
|
# @return [Numeric] path length for target node from given node
|
143
146
|
def self.dijkstra_path_length(graph, source, target)
|
144
147
|
return 0 if source == target
|
148
|
+
|
145
149
|
weight = get_weight(graph)
|
146
150
|
length = help_dijkstra(graph, source, weight, nil, nil, nil, target)
|
147
|
-
raise KeyError, 'Node not reachable!' unless length.
|
151
|
+
raise KeyError, 'Node not reachable!' unless length.has_key?(target)
|
152
|
+
|
148
153
|
length[target]
|
149
154
|
end
|
150
155
|
|
@@ -168,7 +173,7 @@ module NetworkX
|
|
168
173
|
#
|
169
174
|
# @return [<Array<Hash{ Object => Array<Object> }, Hash{ Object => Numeric }>]
|
170
175
|
# predcessor hash and distance hash
|
171
|
-
def self.dijkstra_predecessor_distance(graph, source, cutoff=nil)
|
176
|
+
def self.dijkstra_predecessor_distance(graph, source, cutoff = nil)
|
172
177
|
weight = get_weight(graph)
|
173
178
|
pred = {source => []}
|
174
179
|
[pred, help_dijkstra(graph, source, weight, pred, nil, cutoff)]
|
@@ -181,7 +186,7 @@ module NetworkX
|
|
181
186
|
#
|
182
187
|
# @return [Array<Object, Array<Hash{ Object => Numeric }, Hash{ Object => Array<Object> }>>]
|
183
188
|
# paths and path lengths between all nodes
|
184
|
-
def self.all_pairs_dijkstra(graph, cutoff=nil)
|
189
|
+
def self.all_pairs_dijkstra(graph, cutoff = nil)
|
185
190
|
path = []
|
186
191
|
graph.nodes.each_key { |n| path << [n, singlesource_dijkstra(graph, n, nil, cutoff)] }
|
187
192
|
path
|
@@ -193,7 +198,7 @@ module NetworkX
|
|
193
198
|
# @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm
|
194
199
|
#
|
195
200
|
# @return [Array<Object, Hash{ Object => Numeric }>] path lengths between all nodes
|
196
|
-
def self.all_pairs_dijkstra_path_length(graph, cutoff=nil)
|
201
|
+
def self.all_pairs_dijkstra_path_length(graph, cutoff = nil)
|
197
202
|
path_lengths = []
|
198
203
|
graph.nodes.each_key { |n| path_lengths << [n, singlesource_dijkstra_path_length(graph, n, cutoff)] }
|
199
204
|
path_lengths
|
@@ -205,16 +210,14 @@ module NetworkX
|
|
205
210
|
# @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm
|
206
211
|
#
|
207
212
|
# @return [Array<Object, Hash{ Object => Array<Object> }>] path lengths between all nodes
|
208
|
-
def self.all_pairs_dijkstra_path(graph, cutoff=nil)
|
213
|
+
def self.all_pairs_dijkstra_path(graph, cutoff = nil)
|
209
214
|
paths = []
|
210
215
|
graph.nodes.each_key { |n| paths << singlesource_dijkstra_path(graph, n, cutoff) }
|
211
216
|
paths
|
212
217
|
end
|
213
218
|
|
214
|
-
# TODO: Reduce method length and method complexity
|
215
|
-
|
216
219
|
# Helper function for bellman ford
|
217
|
-
def self.help_bellman_ford(graph, sources, weight, pred=nil, paths=nil, dist=nil, cutoff=nil, target=nil)
|
220
|
+
def self.help_bellman_ford(graph, sources, weight, pred = nil, paths = nil, dist = nil, cutoff = nil, target = nil)
|
218
221
|
pred = sources.product([[]]).to_h if pred.nil?
|
219
222
|
dist = sources.product([0]).to_h if dist.nil?
|
220
223
|
|
@@ -225,28 +228,31 @@ module NetworkX
|
|
225
228
|
skip = false
|
226
229
|
pred[u].each { |k| skip = true if in_q.include?(k) }
|
227
230
|
next if skip
|
231
|
+
|
228
232
|
dist_u = dist[u]
|
229
233
|
graph.adj[u].each do |v, e|
|
230
234
|
dist_v = dist_u + weight.call(u, v, e)
|
231
235
|
next if !cutoff.nil? && dist_v > cutoff
|
232
236
|
next if !target.nil? && dist_v > (dist[target] || inf)
|
237
|
+
|
233
238
|
if dist_v < (dist[v] || inf)
|
234
239
|
unless in_q.include?(v)
|
235
240
|
q << v
|
236
241
|
in_q.add(v)
|
237
242
|
count_v = (count[v] || 0) + 1
|
238
243
|
raise ArgumentError, 'Negative edge cycle detected!' if count_v == n
|
244
|
+
|
239
245
|
count[v] = count_v
|
240
246
|
end
|
241
247
|
dist[v] = dist_v
|
242
248
|
pred[v] = [u]
|
243
|
-
elsif dist.
|
249
|
+
elsif dist.has_key?(v) && dist_v == dist[v]
|
244
250
|
pred[v] << u
|
245
251
|
end
|
246
252
|
end
|
247
253
|
end
|
248
254
|
unless paths.nil?
|
249
|
-
dsts =
|
255
|
+
dsts = pred
|
250
256
|
dsts.each_key do |dst|
|
251
257
|
path, cur = [dst], dst
|
252
258
|
until pred[cur][0].nil?
|
@@ -268,24 +274,28 @@ module NetworkX
|
|
268
274
|
# @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm
|
269
275
|
#
|
270
276
|
# @return [Array<Hash{ Object => Array<Object> }, Hash{ Object => Numeric }>] predecessors and distances
|
271
|
-
def self.bellmanford_predecesor_distance(graph, source, target=nil, cutoff=nil)
|
277
|
+
def self.bellmanford_predecesor_distance(graph, source, target = nil, cutoff = nil)
|
272
278
|
raise ArgumentError, 'Node not found!' unless graph.node?(source)
|
279
|
+
|
273
280
|
weight = get_weight(graph)
|
274
281
|
# TODO: Detection of selfloop edges
|
275
282
|
dist = {source => 0}
|
276
283
|
pred = {source => []}
|
277
284
|
return [pred, dist] if graph.nodes.length == 1
|
285
|
+
|
278
286
|
dist = help_bellman_ford(graph, [source], weight, pred, nil, dist, cutoff, target)
|
279
287
|
[pred, dist]
|
280
288
|
end
|
281
289
|
|
282
|
-
def self.singlesource_bellmanford(graph, source, target=nil, cutoff=nil)
|
290
|
+
def self.singlesource_bellmanford(graph, source, target = nil, cutoff = nil)
|
283
291
|
return [0, [source]] if source == target
|
292
|
+
|
284
293
|
weight = get_weight(graph)
|
285
294
|
paths = {source => [source]}
|
286
295
|
dist = help_bellman_ford(graph, [source], weight, nil, paths, nil, cutoff, target)
|
287
296
|
return [dist, paths] if target.nil?
|
288
|
-
raise ArgumentError, 'Node not reachable!' unless dist.
|
297
|
+
raise ArgumentError, 'Node not reachable!' unless dist.has_key?(target)
|
298
|
+
|
289
299
|
[dist[target], paths[target]]
|
290
300
|
end
|
291
301
|
|
@@ -298,9 +308,11 @@ module NetworkX
|
|
298
308
|
# @return [Numeric] distance between source and target
|
299
309
|
def self.bellmanford_path_length(graph, source, target)
|
300
310
|
return 0 if source == target
|
311
|
+
|
301
312
|
weight = get_weight(graph)
|
302
|
-
length = help_bellman_ford(graph, [source], weight, nil, nil, nil, nil, target
|
303
|
-
raise ArgumentError, 'Node not reachable!' unless length.
|
313
|
+
length = help_bellman_ford(graph, [source], weight, nil, nil, nil, nil, target)
|
314
|
+
raise ArgumentError, 'Node not reachable!' unless length.has_key?(target)
|
315
|
+
|
304
316
|
length[target]
|
305
317
|
end
|
306
318
|
|
@@ -323,7 +335,7 @@ module NetworkX
|
|
323
335
|
# @param cutoff [Numeric, nil] cutoff for Bellman Ford algorithm
|
324
336
|
#
|
325
337
|
# @return [Hash{ Object => Array<Object> }] path from source to all nodes
|
326
|
-
def self.singlesource_bellmanford_path(graph, source, cutoff=nil)
|
338
|
+
def self.singlesource_bellmanford_path(graph, source, cutoff = nil)
|
327
339
|
_, path = singlesource_bellmanford(graph, source, cutoff)
|
328
340
|
path
|
329
341
|
end
|
@@ -335,7 +347,7 @@ module NetworkX
|
|
335
347
|
# @param cutoff [Numeric, nil] cutoff for Bellman Ford algorithm
|
336
348
|
#
|
337
349
|
# @return [Hash{ Object => Numeric }] path lengths from source to all nodes
|
338
|
-
def self.singlesource_bellmanford_path_length(graph, source, cutoff=nil)
|
350
|
+
def self.singlesource_bellmanford_path_length(graph, source, cutoff = nil)
|
339
351
|
weight = get_weight(graph)
|
340
352
|
help_bellman_ford(graph, [source], weight, nil, nil, nil, cutoff)
|
341
353
|
end
|
@@ -346,7 +358,7 @@ module NetworkX
|
|
346
358
|
# @param cutoff [Numeric, nil] cutoff for Bellman Ford algorithm
|
347
359
|
#
|
348
360
|
# @return [Array<Object, Hash{ Object => Numeric }>] path lengths from source to all nodes
|
349
|
-
def self.allpairs_bellmanford_path_length(graph, cutoff=nil)
|
361
|
+
def self.allpairs_bellmanford_path_length(graph, cutoff = nil)
|
350
362
|
path_lengths = []
|
351
363
|
graph.nodes.each_key { |n| path_lengths << [n, singlesource_bellmanford_path_length(graph, n, cutoff)] }
|
352
364
|
path_lengths
|
@@ -358,7 +370,7 @@ module NetworkX
|
|
358
370
|
# @param cutoff [Numeric, nil] cutoff for Bellman Ford algorithm
|
359
371
|
#
|
360
372
|
# @return [Array<Object, Hash{ Object => Array<Object> }>] path lengths from source to all nodes
|
361
|
-
def self.allpairs_bellmanford_path(graph, cutoff=nil)
|
373
|
+
def self.allpairs_bellmanford_path(graph, cutoff = nil)
|
362
374
|
paths = []
|
363
375
|
graph.nodes.each_key { |n| paths << [n, singlesource_bellmanford_path(graph, n, cutoff)] }
|
364
376
|
paths
|
@@ -385,8 +397,6 @@ module NetworkX
|
|
385
397
|
path_lengths
|
386
398
|
end
|
387
399
|
|
388
|
-
# TODO: Reduce method length and method complexity
|
389
|
-
|
390
400
|
# Returns shortest path between all pairs of nodes
|
391
401
|
#
|
392
402
|
# @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph
|
@@ -399,10 +409,9 @@ module NetworkX
|
|
399
409
|
dist[n], pred[n] = 0, []
|
400
410
|
end
|
401
411
|
weight = get_weight(graph)
|
402
|
-
dist_bellman = help_bellman_ford(graph, sources, weight, pred, nil, dist
|
412
|
+
dist_bellman = help_bellman_ford(graph, sources, weight, pred, nil, dist)
|
403
413
|
new_weight = ->(u, v, d) { weight.call(u, v, d) + dist_bellman[u] - dist_bellman[v] }
|
404
414
|
dist_path = dist_path_lambda(graph, new_weight)
|
405
|
-
|
406
|
-
path_lengths
|
415
|
+
set_path_lengths_johnson(graph, dist_path, new_weight)
|
407
416
|
end
|
408
417
|
end
|
data/lib/networkx/to_matrix.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
module NetworkX
|
2
|
-
|
3
|
-
def self.to_matrix(graph, val, multigraph_weight='sum')
|
2
|
+
def self.to_matrix(graph, val, multigraph_weight = 'sum')
|
4
3
|
is_undirected = !graph.directed?
|
5
4
|
is_multigraph = graph.multigraph?
|
6
5
|
nodelen = graph.nodes.length
|
7
6
|
|
8
|
-
m =
|
7
|
+
m = Matrix.build(nodelen) { val }
|
9
8
|
index = {}
|
10
9
|
inv_index = {}
|
11
10
|
ind = 0
|
@@ -1,6 +1,4 @@
|
|
1
1
|
module NetworkX
|
2
|
-
# TODO: Reduce method length
|
3
|
-
|
4
2
|
# Returns edges of the graph travelled in breadth first fashion
|
5
3
|
#
|
6
4
|
# @example
|
@@ -10,6 +8,7 @@ module NetworkX
|
|
10
8
|
# @param source [Object] node to start bfs from
|
11
9
|
def self.bfs_edges(graph, source)
|
12
10
|
raise KeyError, "There exists no node names #{source} in the given graph." unless graph.node?(source)
|
11
|
+
|
13
12
|
bfs_edges = []
|
14
13
|
visited = [source]
|
15
14
|
queue = Queue.new.push([source, graph.neighbours(source)])
|
@@ -17,6 +16,7 @@ module NetworkX
|
|
17
16
|
parent, children = queue.pop
|
18
17
|
children.each_key do |child|
|
19
18
|
next if visited.include?(child)
|
19
|
+
|
20
20
|
bfs_edges << [parent, child]
|
21
21
|
visited << child
|
22
22
|
queue.push([child, graph.neighbours(child)])
|
@@ -55,4 +55,56 @@ module NetworkX
|
|
55
55
|
bfs_edges.each { |u, v| predecessors[v] = u }
|
56
56
|
predecessors
|
57
57
|
end
|
58
|
+
|
59
|
+
class Graph
|
60
|
+
def bfs_nodes(root)
|
61
|
+
each_bfs_node(root).to_a
|
62
|
+
end
|
63
|
+
|
64
|
+
def each_bfs_node(root)
|
65
|
+
return enum_for(:each_bfs_node, root) unless block_given?
|
66
|
+
|
67
|
+
queue = [root]
|
68
|
+
dist = {root => 0}
|
69
|
+
while (v = queue.shift)
|
70
|
+
yield v
|
71
|
+
d = dist[v]
|
72
|
+
@adj[v].each do |u, _data|
|
73
|
+
next if dist[u]
|
74
|
+
|
75
|
+
dist[u] = d + 1
|
76
|
+
queue << u
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# [EXPERIMENTAL]
|
82
|
+
#
|
83
|
+
# @param [Object] node which is root, start ,source
|
84
|
+
def bfs_edges(node)
|
85
|
+
each_bfs_edge(node).to_a
|
86
|
+
end
|
87
|
+
|
88
|
+
# [EXPERIMENTAL]
|
89
|
+
#
|
90
|
+
# @param [Object] node which is root, start ,source
|
91
|
+
def each_bfs_edge(node)
|
92
|
+
return enum_for(:each_bfs_edge, node) unless block_given?
|
93
|
+
|
94
|
+
que = [node]
|
95
|
+
used = {node => true}
|
96
|
+
while que[0]
|
97
|
+
node = que.shift
|
98
|
+
|
99
|
+
@adj[node].each do |v, _data|
|
100
|
+
next if used[v]
|
101
|
+
|
102
|
+
used[v] = true
|
103
|
+
|
104
|
+
yield(node, v)
|
105
|
+
que << v
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
58
110
|
end
|
@@ -1,6 +1,4 @@
|
|
1
1
|
module NetworkX
|
2
|
-
# TODO: Reduce method complexity and method length
|
3
|
-
|
4
2
|
# Returns edges of the graph travelled in depth first fashion
|
5
3
|
#
|
6
4
|
# @example
|
@@ -9,8 +7,10 @@ module NetworkX
|
|
9
7
|
# @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph
|
10
8
|
# @param source [Object] node to start dfs from
|
11
9
|
# @param depth_limit [Integer, nil] the depth limit of dfs
|
12
|
-
def self.dfs_edges(graph, source, depth_limit=nil)
|
10
|
+
def self.dfs_edges(graph, source, depth_limit = nil)
|
13
11
|
raise KeyError, "There exists no node names #{source} in the given graph." unless graph.node?(source)
|
12
|
+
|
13
|
+
depth_limit += 1 if depth_limit
|
14
14
|
depth_limit = graph.nodes.length if depth_limit.nil?
|
15
15
|
dfs_edges = []
|
16
16
|
visited = [source]
|
@@ -37,7 +37,7 @@ module NetworkX
|
|
37
37
|
# @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph
|
38
38
|
# @param source [Object] node to start dfs from
|
39
39
|
# @param depth_limit [Integer, nil] the depth limit of dfs
|
40
|
-
def self.dfs_tree(graph, source, depth_limit=nil)
|
40
|
+
def self.dfs_tree(graph, source, depth_limit = nil)
|
41
41
|
t = NetworkX::DiGraph.new
|
42
42
|
t.add_node(source)
|
43
43
|
t.add_edges_from(dfs_edges(graph, source, depth_limit))
|
@@ -52,7 +52,7 @@ module NetworkX
|
|
52
52
|
# @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph
|
53
53
|
# @param source [Object] node to start dfs from
|
54
54
|
# @param depth_limit [Integer, nil] the depth limit of dfs
|
55
|
-
def self.dfs_successors(graph, source, depth_limit=nil)
|
55
|
+
def self.dfs_successors(graph, source, depth_limit = nil)
|
56
56
|
dfs_edges = dfs_edges(graph, source, depth_limit)
|
57
57
|
successors = {}
|
58
58
|
dfs_edges.each do |u, v|
|
@@ -70,10 +70,66 @@ module NetworkX
|
|
70
70
|
# @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph
|
71
71
|
# @param source [Object] node to start dfs from
|
72
72
|
# @param depth_limit [Integer, nil] the depth limit of dfs
|
73
|
-
def self.dfs_predecessors(graph, source, depth_limit=nil)
|
73
|
+
def self.dfs_predecessors(graph, source, depth_limit = nil)
|
74
74
|
dfs_edges = dfs_edges(graph, source, depth_limit)
|
75
75
|
predecessors = {}
|
76
76
|
dfs_edges.each { |u, v| predecessors[v] = u }
|
77
77
|
predecessors
|
78
78
|
end
|
79
|
+
|
80
|
+
class Graph
|
81
|
+
# [EXPERIMENTAL]
|
82
|
+
#
|
83
|
+
# @param root [Object] node which is root, start, source
|
84
|
+
#
|
85
|
+
# @return [Array[Object]] nodes
|
86
|
+
def dfs_preorder_nodes(root)
|
87
|
+
each_dfs_preorder_node(root).to_a
|
88
|
+
end
|
89
|
+
|
90
|
+
# [EXPERIMENTAL]
|
91
|
+
#
|
92
|
+
# @param root [Object] node which is root, start, source
|
93
|
+
def each_dfs_preorder_node(root)
|
94
|
+
return enum_for(:each_dfs_preorder_node, root) unless block_given?
|
95
|
+
|
96
|
+
st = [root]
|
97
|
+
used = {root => true}
|
98
|
+
while st[-1]
|
99
|
+
node = st.pop
|
100
|
+
yield(node)
|
101
|
+
@adj[node].reverse_each do |v, _data|
|
102
|
+
next if used[v]
|
103
|
+
|
104
|
+
used[v] = node
|
105
|
+
st << v
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# [EXPERIMENTAL]
|
111
|
+
#
|
112
|
+
# @param root [Object] node which is root, start, source
|
113
|
+
#
|
114
|
+
# @return [Array[Object]] array of dfs postorder nodes
|
115
|
+
def dfs_postorder_nodes(root, used = {root => true})
|
116
|
+
res = []
|
117
|
+
@adj[root].each do |v, _data|
|
118
|
+
next if used[v]
|
119
|
+
|
120
|
+
used[v] = true
|
121
|
+
res.concat dfs_postorder_nodes(v, used)
|
122
|
+
end
|
123
|
+
|
124
|
+
res << root
|
125
|
+
res
|
126
|
+
end
|
127
|
+
|
128
|
+
# @param root [Object] node which is root, start, source
|
129
|
+
def each_dfs_postorder_node(root, &block)
|
130
|
+
return enum_for(:each_dfs_postorder_node, root) unless block_given?
|
131
|
+
|
132
|
+
dfs_postorder_nodes(root).each(&block)
|
133
|
+
end
|
134
|
+
end
|
79
135
|
end
|
@@ -1,6 +1,4 @@
|
|
1
1
|
module NetworkX
|
2
|
-
# TODO: Reduce method complexity and method length
|
3
|
-
|
4
2
|
# Helper function for edge_dfs
|
5
3
|
#
|
6
4
|
# @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph
|
@@ -11,7 +9,7 @@ module NetworkX
|
|
11
9
|
case graph.class.name
|
12
10
|
when 'NetworkX::Graph', 'NetworkX::DiGraph'
|
13
11
|
graph.adj[node].each do |v, _|
|
14
|
-
if graph.
|
12
|
+
if graph.instance_of?(::NetworkX::DiGraph) || visited[[v, node]].nil?
|
15
13
|
visited[[node, v]] = true
|
16
14
|
edges << [node, v]
|
17
15
|
end
|
@@ -19,7 +17,7 @@ module NetworkX
|
|
19
17
|
else
|
20
18
|
graph.adj[node].each do |v, uv_keys|
|
21
19
|
uv_keys.each_key do |k|
|
22
|
-
if graph.
|
20
|
+
if graph.instance_of?(::NetworkX::MultiDiGraph) || visited[[v, node, k]].nil?
|
23
21
|
visited[[node, v, k]] = true
|
24
22
|
edges << [node, v, k]
|
25
23
|
end
|
@@ -32,12 +30,11 @@ module NetworkX
|
|
32
30
|
# Helper function of edge_dfs
|
33
31
|
def self.edge_id(graph, edge)
|
34
32
|
return edge if graph.directed?
|
35
|
-
return Set.new([edge, (edge[0..1].reverse
|
33
|
+
return Set.new([edge, (edge[0..1].reverse << edge[2])]) if graph.multigraph?
|
34
|
+
|
36
35
|
Set.new([edge, edge.reverse])
|
37
36
|
end
|
38
37
|
|
39
|
-
# TODO: Reduce method complexity and method length
|
40
|
-
|
41
38
|
# Performs edge dfs on the graph
|
42
39
|
# Orientation :ignore, directed edges can be
|
43
40
|
# travelled in both fashions
|
@@ -49,15 +46,15 @@ module NetworkX
|
|
49
46
|
# NetworkX.edge_dfs(graph, source, 'ignore')
|
50
47
|
#
|
51
48
|
# @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph
|
52
|
-
# @param
|
49
|
+
# @param start [Object] node to start dfs from
|
53
50
|
# @param orientation [:ignore, :reverse', nil] the orientation of edges of graph
|
54
|
-
def self.edge_dfs(graph, start, orientation=nil)
|
51
|
+
def self.edge_dfs(graph, start, orientation = nil)
|
55
52
|
case orientation
|
56
53
|
when :reverse
|
57
|
-
graph = graph.reverse if graph.
|
54
|
+
graph = graph.reverse if graph.instance_of?(::NetworkX::DiGraph) || graph.instance_of?(::NetworkX::MultiDiGraph)
|
58
55
|
when :ignore
|
59
|
-
graph = graph.to_undirected if graph.
|
60
|
-
graph = graph.to_multigraph if graph.
|
56
|
+
graph = graph.to_undirected if graph.instance_of?(::NetworkX::DiGraph)
|
57
|
+
graph = graph.to_multigraph if graph.instance_of?(::NetworkX::MultiDiGraph)
|
61
58
|
end
|
62
59
|
|
63
60
|
visited_edges = []
|
@@ -87,4 +84,31 @@ module NetworkX
|
|
87
84
|
end
|
88
85
|
e.take(graph.number_of_edges)
|
89
86
|
end
|
87
|
+
|
88
|
+
class Graph
|
89
|
+
def dfs_edges(node)
|
90
|
+
each_dfs_edge(node).to_a
|
91
|
+
end
|
92
|
+
|
93
|
+
def each_dfs_edge(node)
|
94
|
+
return enum_for(:each_dfs_edge, node) unless block_given?
|
95
|
+
|
96
|
+
st = [node]
|
97
|
+
used = {}
|
98
|
+
parents = {}
|
99
|
+
while st[-1]
|
100
|
+
node = st.pop
|
101
|
+
|
102
|
+
yield(parents[node], node) if parents[node]
|
103
|
+
|
104
|
+
used[node] = true
|
105
|
+
@adj[node].reverse_each do |v, _data|
|
106
|
+
next if used[v]
|
107
|
+
|
108
|
+
parents[v] = node
|
109
|
+
st << v unless used[v]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
90
114
|
end
|
data/lib/networkx/version.rb
CHANGED
data/lib/networkx.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'set'
|
2
|
-
require '
|
2
|
+
require 'matrix'
|
3
3
|
require 'rb_heap'
|
4
4
|
require 'securerandom'
|
5
5
|
require_relative 'networkx/version'
|
@@ -35,3 +35,9 @@ require_relative 'networkx/auxillary_functions/wiener'
|
|
35
35
|
require_relative 'networkx/auxillary_functions/cycles'
|
36
36
|
require_relative 'networkx/link_analysis/hits'
|
37
37
|
require_relative 'networkx/link_analysis/pagerank'
|
38
|
+
require_relative 'networkx/others/bridges'
|
39
|
+
require_relative 'networkx/others/generators'
|
40
|
+
require_relative 'networkx/others/grid_2d_graph'
|
41
|
+
require_relative 'networkx/others/info'
|
42
|
+
require_relative 'networkx/others/number_connected_components'
|
43
|
+
require_relative 'networkx/others/reads'
|
data/networkx.gemspec
CHANGED
@@ -13,26 +13,29 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.email = ['athityakumar@gmail.com']
|
14
14
|
spec.summary = 'A Ruby implemenation of the well-known graph library called networkx.'
|
15
15
|
spec.description = NetworkX::DESCRIPTION
|
16
|
-
spec.homepage = 'https://github.com/
|
16
|
+
spec.homepage = 'https://github.com/SciRuby/networkx.rb'
|
17
17
|
spec.license = 'MIT'
|
18
18
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
19
|
spec.bindir = 'bin'
|
20
20
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ['lib']
|
22
22
|
|
23
|
-
spec.
|
24
|
-
|
25
|
-
spec.add_development_dependency '
|
23
|
+
spec.required_ruby_version = '>= 2.7'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
26
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
26
27
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
27
|
-
spec.add_development_dependency 'rspec-its'
|
28
|
-
spec.add_development_dependency 'rubocop', '
|
29
|
-
spec.add_development_dependency 'rubocop-
|
30
|
-
spec.add_development_dependency '
|
31
|
-
spec.add_development_dependency '
|
32
|
-
spec.add_development_dependency '
|
33
|
-
spec.add_development_dependency '
|
34
|
-
spec.
|
35
|
-
|
28
|
+
spec.add_development_dependency 'rspec-its', '~> 1.0'
|
29
|
+
spec.add_development_dependency 'rubocop', '~> 1.0'
|
30
|
+
spec.add_development_dependency 'rubocop-rake', '~> 0.6'
|
31
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.0'
|
32
|
+
spec.add_development_dependency 'rubygems-tasks', '~> 0.2'
|
33
|
+
spec.add_development_dependency 'saharspec', '~> 0.0'
|
34
|
+
spec.add_development_dependency 'simplecov', '~> 0.21'
|
35
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
36
|
+
|
37
|
+
spec.add_runtime_dependency 'matrix', '~> 0.4'
|
38
|
+
spec.add_runtime_dependency 'rb_heap', '~> 1.0'
|
36
39
|
|
37
|
-
spec.
|
40
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
38
41
|
end
|