networkx 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) 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/.rspec +0 -1
  9. data/.rubocop.yml +57 -71
  10. data/.yardopts +0 -1
  11. data/README.md +32 -34
  12. data/Rakefile +2 -3
  13. data/lib/networkx/auxillary_functions/cliques.rb +9 -12
  14. data/lib/networkx/auxillary_functions/cycles.rb +17 -7
  15. data/lib/networkx/auxillary_functions/dag.rb +10 -5
  16. data/lib/networkx/auxillary_functions/eccentricity.rb +2 -1
  17. data/lib/networkx/auxillary_functions/mis.rb +2 -2
  18. data/lib/networkx/auxillary_functions/mst.rb +1 -3
  19. data/lib/networkx/auxillary_functions/union_find.rb +92 -12
  20. data/lib/networkx/auxillary_functions/wiener.rb +1 -1
  21. data/lib/networkx/converters/to_csv.rb +1 -3
  22. data/lib/networkx/converters/to_json.rb +0 -2
  23. data/lib/networkx/digraph.rb +55 -49
  24. data/lib/networkx/flow/capacityscaling.rb +29 -35
  25. data/lib/networkx/flow/edmondskarp.rb +17 -15
  26. data/lib/networkx/flow/preflowpush.rb +29 -32
  27. data/lib/networkx/flow/shortestaugmentingpath.rb +17 -20
  28. data/lib/networkx/flow/utils.rb +6 -27
  29. data/lib/networkx/graph.rb +179 -72
  30. data/lib/networkx/link_analysis/hits.rb +9 -9
  31. data/lib/networkx/link_analysis/pagerank.rb +29 -31
  32. data/lib/networkx/multidigraph.rb +90 -81
  33. data/lib/networkx/multigraph.rb +91 -63
  34. data/lib/networkx/operators/all.rb +8 -4
  35. data/lib/networkx/operators/binary.rb +106 -128
  36. data/lib/networkx/operators/product.rb +61 -64
  37. data/lib/networkx/operators/unary.rb +1 -1
  38. data/lib/networkx/others/bridges.rb +30 -0
  39. data/lib/networkx/others/generators.rb +237 -0
  40. data/lib/networkx/others/grid_2d_graph.rb +38 -0
  41. data/lib/networkx/others/info.rb +11 -0
  42. data/lib/networkx/others/number_connected_components.rb +17 -0
  43. data/lib/networkx/others/reads.rb +52 -0
  44. data/lib/networkx/shortest_path/astar.rb +10 -8
  45. data/lib/networkx/shortest_path/dense.rb +1 -3
  46. data/lib/networkx/shortest_path/unweighted.rb +13 -16
  47. data/lib/networkx/shortest_path/weighted.rb +51 -42
  48. data/lib/networkx/to_matrix.rb +2 -3
  49. data/lib/networkx/traversals/bfs.rb +54 -2
  50. data/lib/networkx/traversals/dfs.rb +62 -6
  51. data/lib/networkx/traversals/edge_dfs.rb +36 -12
  52. data/lib/networkx/version.rb +1 -1
  53. data/lib/networkx.rb +7 -1
  54. data/networkx.gemspec +17 -14
  55. metadata +74 -84
  56. data/.rspec_formatter.rb +0 -24
  57. data/.travis.yml +0 -18
  58. data/Guardfile +0 -7
  59. 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