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,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
- weight_get = lambda do |_, _, attrs|
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.key?(v)
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
- if dist.key?(u)
36
+
37
+ if dist.has_key?(u)
38
38
  raise ValueError, 'Contradictory weights found!' if vu_dist < dist[u]
39
- elsif !seen.key?(u) || vu_dist < seen[u]
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.key?(target)
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.key?(target)
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.key?(v) && dist_v == dist[v]
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 = target.nil? ? pred : [target]
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.key?(target)
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=target)
303
- raise ArgumentError, 'Node not reachable!' unless length.key?(target)
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=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
- path_lengths = set_path_lengths_johnson(graph, dist_path, new_weight)
406
- path_lengths
415
+ set_path_lengths_johnson(graph, dist_path, new_weight)
407
416
  end
408
417
  end
@@ -1,11 +1,10 @@
1
1
  module NetworkX
2
- # TODO: Reduce condition branches and method length
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 = NMatrix.new(nodelen, val)
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.class.name == 'NetworkX::DiGraph' || visited[[v, node]].nil?
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.class.name == 'NetworkX::MultiDiGraph' || visited[[v, node, k]].nil?
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 + edge[2])]) if graph.multigraph?
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 source [Object] node to start dfs from
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.class.name == 'NetworkX::DiGraph' || graph.class.name == 'NetworkX::MultiDiGraph'
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.class.name == 'NetworkX::DiGraph'
60
- graph = graph.to_multigraph if graph.class.name == 'NetworkX::MultiDiGraph'
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
@@ -1,3 +1,3 @@
1
1
  module NetworkX
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
data/lib/networkx.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'set'
2
- require 'nmatrix'
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
@@ -20,19 +20,18 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ['lib']
22
22
 
23
- spec.add_development_dependency 'bundler', '~> 1.15'
24
- spec.add_development_dependency 'rake', '~> 10.0'
25
- spec.add_development_dependency 'redcarpet'
23
+ spec.add_development_dependency 'bundler', '~> 2.0'
24
+ spec.add_development_dependency 'rake', '~> 13.0'
26
25
  spec.add_development_dependency 'rspec', '~> 3.0'
27
- spec.add_development_dependency 'rspec-its'
28
- spec.add_development_dependency 'rubocop', '>= 0.40.0'
29
- spec.add_development_dependency 'rubocop-rspec'
30
- spec.add_development_dependency 'rubygems-tasks'
31
- spec.add_development_dependency 'saharspec'
32
- spec.add_development_dependency 'simplecov'
33
- spec.add_development_dependency 'yard'
34
- spec.add_runtime_dependency 'nmatrix'
35
- spec.add_runtime_dependency 'rb_heap'
26
+ spec.add_development_dependency 'rspec-its', '~> 1.0'
27
+ spec.add_development_dependency 'rubocop', '~> 1.0'
28
+ spec.add_development_dependency 'rubocop-rake', '~> 0.6'
29
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.0'
30
+ spec.add_development_dependency 'rubygems-tasks', '~> 0.2'
31
+ spec.add_development_dependency 'saharspec', '~> 0.0'
32
+ spec.add_development_dependency 'simplecov', '~> 0.21'
33
+ spec.add_development_dependency 'yard', '~> 0.9'
36
34
 
37
- spec.add_development_dependency 'guard-rspec' if RUBY_VERSION >= '2.2.5'
35
+ spec.add_runtime_dependency 'matrix', '~> 0.4'
36
+ spec.add_runtime_dependency 'rb_heap', '~> 1.0'
38
37
  end