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
@@ -0,0 +1,237 @@
1
+ require_relative '../../networkx'
2
+
3
+ module NetworkX
4
+ class Graph
5
+ # private class method
6
+ def self.complete_edges(n)
7
+ n = (0...n) if n.is_a?(Integer)
8
+
9
+ edges = []
10
+ n.each do |i|
11
+ n.each do |j|
12
+ edges << [i, j] if i < j
13
+ end
14
+ end
15
+ edges
16
+ end
17
+
18
+ def self.balanced_tree(r, h)
19
+ edges = []
20
+ q = [0]
21
+ i = 0
22
+ h.times do
23
+ t = q.dup
24
+ q.clear
25
+ t.each do |v|
26
+ r.times do
27
+ i += 1
28
+ edges << [v, i]
29
+ q << i
30
+ end
31
+ end
32
+ end
33
+ graph = new(name: "balanced_tree(#{r}, #{h})")
34
+ graph.add_edges(edges)
35
+ graph
36
+ end
37
+
38
+ def self.barbell_graph(m1, m2)
39
+ edges = complete_edges(m1)
40
+ edges.concat((m1..m2 + m1).map { |k| [k - 1, k] })
41
+ edges.concat complete_edges(m1 + m2...m1 + m2 + m1)
42
+
43
+ graph = new(name: "barbell_graph(#{m1}, #{m2})")
44
+ graph.add_edges(edges)
45
+ graph
46
+ end
47
+
48
+ def self.complete_graph(n)
49
+ n = (0...n) if n.is_a?(Integer)
50
+
51
+ edges = []
52
+ n.each do |i|
53
+ n.each do |j|
54
+ edges << [i, j] if i < j
55
+ end
56
+ end
57
+
58
+ graph = new(name: "complete_graph(#{n})")
59
+ graph.add_edges(edges)
60
+ graph
61
+ end
62
+
63
+ def self.circular_ladder_graph(n)
64
+ edges = (0...n - 1).map { |v| [v, v + 1] }
65
+ edges << [n - 1, 0]
66
+ edges.concat((n...2 * n - 1).map { |v| [v, v + 1] })
67
+ edges << [2 * n - 1, n]
68
+ edges.concat((0...n).map { |v| [v, v + n] })
69
+
70
+ graph = new(name: "circular_ladder_graph(#{n})")
71
+ graph.add_edges(edges)
72
+ graph
73
+ end
74
+
75
+ def self.cycle_graph(n)
76
+ edges = (0...n - 1).map { |v| [v, v + 1] }
77
+ edges << [n - 1, 0]
78
+
79
+ graph = new(name: "cycle_graph(#{n})")
80
+ graph.add_edges(edges)
81
+ graph
82
+ end
83
+
84
+ def self.empty_graph(number_of_nodes)
85
+ empty_graph = new(name: "empty_graph#{number_of_nodes}")
86
+ empty_graph.add_nodes_from(0...number_of_nodes)
87
+ empty_graph
88
+ end
89
+
90
+ def self.ladder_graph(n)
91
+ edges = (0...n - 1).map { |k| [k, k + 1] }
92
+ edges.concat((n...2 * n - 1).map { |k| [k, k + 1] })
93
+ edges.concat((0...n).map { |k| [k, k + n] })
94
+
95
+ graph = new(name: "ladder_graph(#{n})")
96
+ graph.add_edges(edges)
97
+ graph
98
+ end
99
+
100
+ def self.lollipop_graph(m, n)
101
+ edges = complete_edges(m)
102
+ edges.concat((m - 1...m - 1 + n).map { |v| [v, v + 1] })
103
+
104
+ graph = new(name: "lollipop_graph(#{m}, #{n})")
105
+ graph.add_edges(edges)
106
+ graph
107
+ end
108
+
109
+ def self.null_graph
110
+ new(name: 'null_graph')
111
+ end
112
+
113
+ def self.path_graph(n)
114
+ edges = (0...n - 1).map { |v| [v, v + 1] }
115
+
116
+ graph = new(name: "path_graph(#{n})")
117
+ graph.add_edges(edges)
118
+ graph
119
+ end
120
+
121
+ def self.star_graph(n)
122
+ edges = (1..n).map { |i| [0, i] }
123
+
124
+ graph = new(name: "star_graph(#{n})")
125
+ graph.add_edges(edges)
126
+ graph
127
+ end
128
+
129
+ def self.trivial_graph
130
+ trivial_graph = new(name: 'trivial_grpph')
131
+ trivial_graph.add_node(0)
132
+ trivial_graph
133
+ end
134
+
135
+ def self.wheel_graph(n)
136
+ edges = (1..n - 1).map { |i| [0, i] }
137
+ edges.concat((1...n - 1).map { |i| [i, i + 1] })
138
+ edges << [1, n - 1]
139
+
140
+ graph = new(name: "wheel_graph(#{n})")
141
+ graph.add_edges(edges)
142
+ graph
143
+ end
144
+
145
+ def self.bull_graph
146
+ edges = [[0, 1], [1, 2], [2, 0], [1, 3], [2, 4]]
147
+ graph = new(name: 'bull_graph')
148
+ graph.add_edges(edges)
149
+ graph
150
+ end
151
+
152
+ def self.cubical_graph
153
+ graph = circular_ladder_graph(4)
154
+ graph.graph[:name] = 'cubical_graph'
155
+ graph
156
+ end
157
+
158
+ def self.diamond_graph
159
+ edges = [[0, 1], [0, 2], [1, 2], [1, 3], [2, 3]]
160
+ graph = new(name: 'diamond_graph')
161
+ graph.add_edges(edges)
162
+ graph
163
+ end
164
+
165
+ # 12
166
+ def self.dodecahedral_graph
167
+ edges = (0...19).map { |k| [k, k + 1] }
168
+ edges.concat [[0, 19], [0, 10], [1, 8], [2, 6], [3, 19], [4, 17], [5, 15], [7, 14], [9, 13], [11, 18], [12, 16]]
169
+ graph = new(name: 'dodecahedral_graph')
170
+ graph.add_edges(edges)
171
+ graph
172
+ end
173
+
174
+ def self.heawood_graph
175
+ edges = (0...13).map { |k| [k, k + 1] }
176
+ edges << [13, 0]
177
+ edges.concat [[0, 5], [1, 10], [2, 7], [3, 12], [4, 9], [6, 11], [8, 13]]
178
+ graph = new(name: 'heawood_graph')
179
+ graph.add_edges(edges)
180
+ graph
181
+ end
182
+
183
+ def self.house_graph
184
+ edges = [[0, 1], [0, 2], [1, 3], [2, 3], [2, 4], [3, 4]]
185
+ graph = new(name: 'house_graph')
186
+ graph.add_edges(edges)
187
+ graph
188
+ end
189
+
190
+ def self.house_x_graph
191
+ edges = (0...4).map { |k| [k, k + 1] }
192
+ edges.concat [[0, 2], [0, 3], [1, 3], [2, 4], [3, 4]]
193
+ graph = new(name: 'house_x_graph')
194
+ graph.add_edges(edges)
195
+ graph
196
+ end
197
+
198
+ def self.moebius_kantor_graph
199
+ edges = (0...15).map { |k| [k, k + 1] }
200
+ edges << [15, 0]
201
+ edges.concat [[0, 5], [1, 12], [2, 7], [4, 9], [3, 14], [6, 11], [8, 13], [10, 15]]
202
+ graph = new(name: 'moebius_kantor_graph')
203
+ graph.add_edges(edges)
204
+ graph
205
+ end
206
+
207
+ # 8: 6 nodes, 12 edges
208
+ def self.octahedral_graph
209
+ edges = []
210
+ 6.times do |i|
211
+ 6.times do |j|
212
+ edges << [i, j] if i != j && i + j != 5
213
+ end
214
+ end
215
+ graph = new(name: 'octahedral_graph')
216
+ graph.add_edges(edges)
217
+ graph
218
+ end
219
+
220
+ def self.tetrahedral_graph
221
+ graph = complete_graph(4)
222
+ graph.graph[:name] = 'tetrahedral_graph'
223
+ graph
224
+ end
225
+
226
+ # Experimental For debug.
227
+ #
228
+ # @return data for https://hello-world-494ec.firebaseapp.com/
229
+ def put_graph_x2
230
+ output = <<~"OUTPUT"
231
+ #{number_of_nodes} #{number_of_edges}
232
+ #{edges.map { |edge| edge.join(' ') }.join("\n")}
233
+ OUTPUT
234
+ puts output
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,38 @@
1
+ require_relative '../graph'
2
+
3
+ class Array
4
+ include Comparable
5
+ end
6
+
7
+ # Reference: https://networkx.org/documentation/stable/_modules/networkx/generators/lattice.html#grid_2d_graph
8
+ module NetworkX
9
+ # @param m [Integer] the number of rows
10
+ # @param n [Integer] the number of columns
11
+ # @param create_using [Class] graph class. this is optional. default is `NetworkX::Graph`.
12
+ def self.grid_2d_graph(m, n, periodic: false, create_using: NetworkX::Graph)
13
+ warn('sorry, periodic is not done yet') if periodic
14
+
15
+ m.is_a?(Integer) or raise(ArgumentError, "[NetworkX] argument m: Integer, not #{m.class}")
16
+ n.is_a?(Integer) or raise(ArgumentError, "[NetworkX] argument n: Integer, not #{n.class}")
17
+ create_using.is_a?(Class) \
18
+ or raise(ArgumentError, "[NetworkX] argument create_using: `Graph` class or children, not #{create_using.class}")
19
+
20
+ g = create_using.new
21
+
22
+ a = []
23
+ m.times { |i| n.times { |j| a << [i, j] } }
24
+ g.add_nodes_from(a)
25
+
26
+ e1 = []
27
+ (m - 1).times { |i| n.times { |j| e1 << [[i, j], [i + 1, j]] } }
28
+ g.add_edges_from(e1)
29
+
30
+ e2 = []
31
+ m.times { |i| (n - 1).times { |j| e2 << [[i, j], [i, j + 1]] } }
32
+ g.add_edges_from(e2)
33
+
34
+ g.add_edges_from(g.edges.map { |i, j| [j, i] }) if g.directed?
35
+
36
+ g
37
+ end
38
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../graph'
2
+
3
+ module NetworkX
4
+ def self.info(graph)
5
+ info = ''
6
+ info << "Type: #{graph.class}\n"
7
+ info << "Number of nodes: #{graph.number_of_nodes}\n"
8
+ info << "Number of edges: #{graph.number_of_edges}\n"
9
+ info
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ require_relative '../graph'
2
+ require_relative '../auxillary_functions/union_find'
3
+
4
+ module NetworkX
5
+ # @param [NetworkX::Graph] graph
6
+ #
7
+ # @return [Integer] the number of connected components on graph
8
+ def self.number_connected_components(graph)
9
+ uf = NetworkX::UnionFind.new(graph.nodes(data: false))
10
+ graph.each_edge { |x, y| uf.unite(x, y) }
11
+ uf.groups.size
12
+ end
13
+
14
+ class << self
15
+ alias number_of_connected_components number_connected_components
16
+ end
17
+ end
@@ -0,0 +1,52 @@
1
+ require_relative '../../networkx'
2
+
3
+ module NetworkX
4
+ class Graph
5
+ class << self
6
+ def read_edgelist(path, comment: '#', delimiter: nil)
7
+ edges = File.readlines(path).filter_map do |line|
8
+ line.sub!(/#{comment}.+/, '')
9
+ line.strip.split(delimiter) if line.strip.size > 0
10
+ end
11
+
12
+ edges.each{|edge| edge.map!{|node| NetworkX.to_number_if_possible(node) } }
13
+
14
+ graph = new
15
+ graph.add_edges(edges)
16
+ graph
17
+ end
18
+ alias read_edges read_edgelist
19
+
20
+ def read_weighted_edgelist(path, comment: '#', delimiter: nil)
21
+ edges = File.readlines(path).filter_map do |line|
22
+ line.sub!(/#{comment}.+/, '')
23
+ line.strip.split(delimiter) if line.strip.size > 0
24
+ end
25
+
26
+ edges.map! do |x, y, weight|
27
+ [
28
+ NetworkX.to_number_if_possible(x),
29
+ NetworkX.to_number_if_possible(y),
30
+ {weight: NetworkX.to_number_if_possible(weight)}
31
+ ]
32
+ end
33
+
34
+ graph = new
35
+ graph.add_edges(edges)
36
+ graph
37
+ end
38
+ alias read_weighted_edges read_weighted_edgelist
39
+ end
40
+ end
41
+
42
+ def self.to_number_if_possible(str)
43
+ case str
44
+ when /^[+-]?[0-9]+$/
45
+ str.to_i
46
+ when /^([+-]?\d*\.\d*)|(\d*[eE][+-]?\d+)$/
47
+ str.to_f
48
+ else
49
+ str
50
+ end
51
+ end
52
+ end
@@ -1,6 +1,4 @@
1
1
  module NetworkX
2
- # TODO: Reduce method complexity and method length
3
-
4
2
  # Returns path using astar algorithm between source and target
5
3
  #
6
4
  # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph
@@ -10,9 +8,11 @@ module NetworkX
10
8
  #
11
9
  # @return [Array<Object>] an array of nodes forming a path between source
12
10
  # and target
13
- def self.astar_path(graph, source, target, heuristic=nil)
14
- warn 'A* is not implemented for MultiGraph and MultiDiGraph'
11
+ def self.astar_path(graph, source, target, heuristic = nil)
12
+ warn 'A* is not implemented for MultiGraph and MultiDiGraph' if graph.is_a?(MultiGraph) || graph.is_a?(MultiDiGraph)
13
+
15
14
  raise ArgumentError, 'Either source or target is not in graph' unless graph.node?(source) && graph.node?(target)
15
+
16
16
  count = ->(i) { i + 1 }
17
17
  i = -1
18
18
  heuristic ||= (->(_u, _v) { 0 })
@@ -33,14 +33,15 @@ module NetworkX
33
33
  return path
34
34
  end
35
35
 
36
- next if explored.key?(curnode)
36
+ next if explored.has_key?(curnode)
37
37
 
38
38
  explored[curnode] = parent
39
39
 
40
40
  graph.adj[curnode].each do |u, attrs|
41
- next if explored.key?(u)
41
+ next if explored.has_key?(u)
42
+
42
43
  ncost = dist + (attrs[:weight] || 1)
43
- if enqueued.key?(u)
44
+ if enqueued.has_key?(u)
44
45
  qcost, = enqueued[u]
45
46
  next if qcost <= ncost
46
47
  else
@@ -61,8 +62,9 @@ module NetworkX
61
62
  # @param heuristic [] a lambda to compute heuristic b/w two nodes
62
63
  #
63
64
  # @return [Numeric] the length of the path
64
- def self.astar_path_length(graph, source, target, heuristic=nil)
65
+ def self.astar_path_length(graph, source, target, heuristic = nil)
65
66
  raise ArgumentError, 'Either source or target is not in graph' unless graph.node?(source) && graph.node?(target)
67
+
66
68
  path = astar_path(graph, source, target, heuristic)
67
69
  path_length = 0
68
70
  (1..(path.length - 1)).each { |i| path_length += (graph.adj[path[i - 1]][path[i]][:weight] || 1) }
@@ -1,6 +1,4 @@
1
1
  module NetworkX
2
- # TODO: Reduce method length and method complexity
3
-
4
2
  # Returns the all pair distance between all the nodes
5
3
  #
6
4
  # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph
@@ -22,7 +20,7 @@ module NetworkX
22
20
  as_hash = {}
23
21
  (0..(nodelen - 1)).each do |i|
24
22
  (0..(nodelen - 1)).each do |j|
25
- as_hash[index[i]] = {} unless as_hash.key?(index[i])
23
+ as_hash[index[i]] = {} unless as_hash.has_key?(index[i])
26
24
  as_hash[index[i]][index[j]] = a[i, j]
27
25
  end
28
26
  end
@@ -1,9 +1,7 @@
1
1
  module NetworkX
2
- # TODO: Reduce method length
3
-
4
2
  # Helper function for single source shortest path length
5
3
  def self.help_single_shortest_path_length(adj, firstlevel, cutoff)
6
- iterator = Enumerator.new do |e|
4
+ Enumerator.new do |e|
7
5
  seen = {}
8
6
  level = 0
9
7
  nextlevel = firstlevel
@@ -12,7 +10,8 @@ module NetworkX
12
10
  thislevel = nextlevel
13
11
  nextlevel = {}
14
12
  thislevel.each do |u, _attrs|
15
- next if seen.key?(u)
13
+ next if seen.has_key?(u)
14
+
16
15
  seen[u] = level
17
16
  nextlevel.merge!(adj[u])
18
17
  e.yield [u, level]
@@ -21,7 +20,6 @@ module NetworkX
21
20
  end
22
21
  seen.clear
23
22
  end
24
- iterator
25
23
  end
26
24
 
27
25
  # Computes shortest path values to all nodes from a given node
@@ -31,8 +29,9 @@ module NetworkX
31
29
  # @param cutoff [Numeric, nil] cutoff for the shortest path algorithm
32
30
  #
33
31
  # @return [Array<Object, Numeric>] path lengths for all nodes
34
- def self.single_source_shortest_path_length(graph, source, cutoff=nil)
32
+ def self.single_source_shortest_path_length(graph, source, cutoff = nil)
35
33
  raise ArgumentError, 'Source not found in the Graph!' unless graph.node?(source)
34
+
36
35
  cutoff = Float::INFINITY if cutoff.nil?
37
36
  nextlevel = {source => 1}
38
37
  help_single_shortest_path_length(graph.adj, nextlevel, cutoff).take(graph.nodes.length)
@@ -44,14 +43,12 @@ module NetworkX
44
43
  # @param cutoff [Numeric, nil] cutoff for the shortest path algorithm
45
44
  #
46
45
  # @return [Array<Object, Array<Object, Numeric>>] path lengths for all nodes from all nodes
47
- def self.all_pairs_shortest_path_length(graph, cutoff=nil)
46
+ def self.all_pairs_shortest_path_length(graph, cutoff = nil)
48
47
  shortest_paths = []
49
48
  graph.nodes.each_key { |n| shortest_paths << [n, single_source_shortest_path_length(graph, n, cutoff)] }
50
49
  shortest_paths
51
50
  end
52
51
 
53
- # TODO: Reduce method length
54
-
55
52
  # Helper function for finding single source shortest path
56
53
  def self.help_single_shortest_path(adj, firstlevel, paths, cutoff)
57
54
  level = 0
@@ -61,7 +58,7 @@ module NetworkX
61
58
  nextlevel = {}
62
59
  thislevel.each_key do |u|
63
60
  adj[u].each_key do |v|
64
- unless paths.key?(v)
61
+ unless paths.has_key?(v)
65
62
  paths[v] = paths[u] + [v]
66
63
  nextlevel[v] = 1
67
64
  end
@@ -79,8 +76,9 @@ module NetworkX
79
76
  # @param cutoff [Numeric, nil] cutoff for the shortest path algorithm
80
77
  #
81
78
  # @return [Array<Object, Array<Object, Array<Object>>>] path lengths for all nodes from all nodes
82
- def self.single_source_shortest_path(graph, source, cutoff=nil)
79
+ def self.single_source_shortest_path(graph, source, cutoff = nil)
83
80
  raise ArgumentError, 'Source not found in the Graph!' unless graph.node?(source)
81
+
84
82
  cutoff = Float::INFINITY if cutoff.nil?
85
83
  nextlevel = {source => 1}
86
84
  paths = {source => [source]}
@@ -93,14 +91,12 @@ module NetworkX
93
91
  # @param cutoff [Numeric, nil] cutoff for the shortest path algorithm
94
92
  #
95
93
  # @return [Array<Object, Hash {Object => Array<Object> }>] paths for all nodes from all nodes
96
- def self.all_pairs_shortest_path(graph, cutoff=nil)
94
+ def self.all_pairs_shortest_path(graph, cutoff = nil)
97
95
  shortest_paths = []
98
96
  graph.nodes.each_key { |n| shortest_paths << [n, single_source_shortest_path(graph, n, cutoff)] }
99
97
  shortest_paths
100
98
  end
101
99
 
102
- # TODO: Reduce method length and method complexity
103
-
104
100
  # Computes shortest paths to all nodes from all nodes
105
101
  #
106
102
  # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph
@@ -111,8 +107,9 @@ module NetworkX
111
107
  # @return [Array<Hash{ Object => Array<Object> }, Hash{ Object => Numeric }>,
112
108
  # Hash{ Object => Array<Object> }]
113
109
  # predecessors of a given node and/or seen dict
114
- def self.predecessor(graph, source, cutoff=nil, return_seen=false)
110
+ def self.predecessor(graph, source, cutoff = nil, return_seen = false)
115
111
  raise ArgumentError, 'Source not found in the Graph!' unless graph.node?(source)
112
+
116
113
  level = 0
117
114
  nextlevel = [source]
118
115
  seen = {source => level}
@@ -123,7 +120,7 @@ module NetworkX
123
120
  nextlevel = []
124
121
  thislevel.each do |u|
125
122
  graph.adj[u].each_key do |v|
126
- if !seen.key?(v)
123
+ if !seen.has_key?(v)
127
124
  pred[v] = [u]
128
125
  seen[v] = level
129
126
  nextlevel << v