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.
- 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/.github/workflows/gem-push.yml +45 -0
- data/.rspec +0 -1
- data/.rubocop.yml +57 -71
- data/.yardopts +0 -1
- data/README.md +27 -27
- 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 +48 -6
- 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 +12 -13
- metadata +71 -81
- data/.rspec_formatter.rb +0 -24
- data/.travis.yml +0 -18
- data/Guardfile +0 -7
- 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,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.
|
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.
|
41
|
+
next if explored.has_key?(u)
|
42
|
+
|
42
43
|
ncost = dist + (attrs[:weight] || 1)
|
43
|
-
if enqueued.
|
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.
|
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
|
-
|
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.
|
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.
|
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.
|
123
|
+
if !seen.has_key?(v)
|
127
124
|
pred[v] = [u]
|
128
125
|
seen[v] = level
|
129
126
|
nextlevel << v
|