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,21 +1,24 @@
|
|
1
|
-
# TODO: Reduce module length
|
2
|
-
|
3
1
|
module NetworkX
|
4
2
|
# Helper function to return an arbitrary element from an iterable object
|
5
3
|
def self.arbitrary_element(iterable)
|
6
|
-
iterable.
|
4
|
+
if iterable.is_a?(Hash)
|
5
|
+
iterable.first[0]
|
6
|
+
elsif iterable.respond_to?(:first)
|
7
|
+
iterable.first
|
8
|
+
elsif iterable.respond_to?(:[])
|
9
|
+
iterable[0]
|
10
|
+
end
|
7
11
|
end
|
8
12
|
|
9
|
-
# TODO: Reduce method complexity and method length
|
10
|
-
|
11
13
|
# Helper function to apply the preflow push algorithm
|
12
14
|
def self.preflowpush_impl(graph, source, target, residual, globalrelabel_freq, value_only)
|
13
|
-
raise ArgumentError, 'Source not in graph!' unless graph.nodes.
|
14
|
-
raise ArgumentError, 'Target not in graph!' unless graph.nodes.
|
15
|
+
raise ArgumentError, 'Source not in graph!' unless graph.nodes.has_key?(source)
|
16
|
+
raise ArgumentError, 'Target not in graph!' unless graph.nodes.has_key?(target)
|
15
17
|
raise ArgumentError, 'Source and Target are same!' if source == target
|
16
18
|
|
17
19
|
globalrelabel_freq = 0 if globalrelabel_freq.nil?
|
18
|
-
raise ArgumentError, 'Global Relabel Freq must be nonnegative!' if globalrelabel_freq
|
20
|
+
raise ArgumentError, 'Global Relabel Freq must be nonnegative!' if globalrelabel_freq.negative?
|
21
|
+
|
19
22
|
r_network = residual.nil? ? build_residual_network(graph) : residual
|
20
23
|
detect_unboundedness(r_network, source, target)
|
21
24
|
|
@@ -30,7 +33,7 @@ module NetworkX
|
|
30
33
|
|
31
34
|
heights = reverse_bfs(target, residual_pred)
|
32
35
|
|
33
|
-
unless heights.
|
36
|
+
unless heights.has_key?(source)
|
34
37
|
r_network.graph[:flow_value] = 0
|
35
38
|
return r_network
|
36
39
|
end
|
@@ -42,25 +45,25 @@ module NetworkX
|
|
42
45
|
grt = GlobalRelabelThreshold.new(n, r_network.size, globalrelabel_freq)
|
43
46
|
|
44
47
|
residual_nodes.each do |u, u_attrs|
|
45
|
-
u_attrs[:height] = heights.
|
48
|
+
u_attrs[:height] = heights.has_key?(u) ? heights[u] : (n + 1)
|
46
49
|
u_attrs[:curr_edge] = CurrentEdge.new(residual_adj[u])
|
47
50
|
end
|
48
51
|
|
49
52
|
residual_adj[source].each do |u, attr|
|
50
53
|
flow = attr[:capacity]
|
51
|
-
push(source, u, flow, residual_nodes, residual_adj) if flow
|
54
|
+
push(source, u, flow, residual_nodes, residual_adj) if flow.positive?
|
52
55
|
end
|
53
56
|
|
54
|
-
levels = (0..(2 * n - 1)).map { |_| Level.new }
|
57
|
+
levels = (0..((2 * n) - 1)).map { |_| Level.new }
|
55
58
|
residual_nodes.each do |u, attr|
|
56
59
|
if u != source && u != target
|
57
60
|
level = levels[attr[:height]]
|
58
|
-
residual_nodes[u][:excess]
|
61
|
+
(residual_nodes[u][:excess]).positive? ? level.active.add(u) : level.inactive.add(u)
|
59
62
|
end
|
60
63
|
end
|
61
64
|
|
62
65
|
height = max_height
|
63
|
-
while height
|
66
|
+
while height.positive?
|
64
67
|
loop do
|
65
68
|
level = levels[height]
|
66
69
|
if level.active.empty?
|
@@ -116,6 +119,7 @@ module NetworkX
|
|
116
119
|
def self.activate(node, source, target, levels, residual_nodes)
|
117
120
|
return if node == source || node == target
|
118
121
|
return unless level.inactive.include?(node)
|
122
|
+
|
119
123
|
level = levels[residual_nodes[node][:height]]
|
120
124
|
level.inactive.delete(node)
|
121
125
|
level.active.add(node)
|
@@ -127,10 +131,8 @@ module NetworkX
|
|
127
131
|
r_adj[u_node].map { |v, attr| attr[:flow] < (attr[:capacity] + 1) ? _nodes[v][:height] : Float::INFINITY }.min
|
128
132
|
end
|
129
133
|
|
130
|
-
# TODO: Reduce method complexity and method length
|
131
|
-
|
132
134
|
# Helper function for discharging a node
|
133
|
-
def self.discharge(u_node,
|
135
|
+
def self.discharge(u_node, is_phase1, residual_nodes, residual_adj, height, levels, grt, source, target)
|
134
136
|
height_val = residual_nodes[u_node][:height]
|
135
137
|
curr_edge = residual_nodes[u_node][:curr_edge]
|
136
138
|
next_height = height_val
|
@@ -151,7 +153,7 @@ module NetworkX
|
|
151
153
|
curr_edge.move_to_next
|
152
154
|
rescue StopIteration
|
153
155
|
height_val = relabel(u_node, grt, residual_adj, residual_nodes, source, target, levels)
|
154
|
-
if
|
156
|
+
if is_phase1 && height_val >= n - 1
|
155
157
|
levels[height].active.add(u_node)
|
156
158
|
break
|
157
159
|
end
|
@@ -162,8 +164,6 @@ module NetworkX
|
|
162
164
|
next_height
|
163
165
|
end
|
164
166
|
|
165
|
-
# TODO: Reduce method complexity
|
166
|
-
|
167
167
|
# Helper function for applying gap heuristic
|
168
168
|
def self.gap_heuristic(height, levels, residual_nodes)
|
169
169
|
((height + 1)..(max_height)).each do |idx|
|
@@ -177,8 +177,6 @@ module NetworkX
|
|
177
177
|
end
|
178
178
|
end
|
179
179
|
|
180
|
-
# TODO: Reduce method complexity and method length
|
181
|
-
|
182
180
|
# Helper function for global relabel heuristic
|
183
181
|
def self.global_relabel(from_sink, source, target, residual_nodes, num, levels, residual_pred)
|
184
182
|
src = from_sink ? target : source
|
@@ -186,7 +184,7 @@ module NetworkX
|
|
186
184
|
heights.delete(target) unless from_sink
|
187
185
|
max_height = heights.values.max
|
188
186
|
if from_sink
|
189
|
-
residual_nodes.each { |u, attr| heights[u] = num + 1 if !heights.
|
187
|
+
residual_nodes.each { |u, attr| heights[u] = num + 1 if !heights.has_key?(u) && attr[:height] < num }
|
190
188
|
else
|
191
189
|
heights.each_key { |u| heights[u] += num }
|
192
190
|
max_height += num
|
@@ -195,6 +193,7 @@ module NetworkX
|
|
195
193
|
heights.each do |u, new_height|
|
196
194
|
old_height = residual_nodes[u][:height]
|
197
195
|
next unless new_height != old_height
|
196
|
+
|
198
197
|
if levels[old_height].active.include?(u)
|
199
198
|
levels[old_height].active.delete(u)
|
200
199
|
levels[new_height].active.add(u)
|
@@ -208,15 +207,13 @@ module NetworkX
|
|
208
207
|
end
|
209
208
|
|
210
209
|
# Helper function for augmenting flow
|
211
|
-
def self.push(
|
212
|
-
residual_adj[
|
213
|
-
residual_adj[
|
214
|
-
residual_nodes[
|
215
|
-
residual_nodes[
|
210
|
+
def self.push(node1, node2, flow, residual_nodes, residual_adj)
|
211
|
+
residual_adj[node1][node2][:flow] += flow
|
212
|
+
residual_adj[node2][node1][:flow] -= flow
|
213
|
+
residual_nodes[node1][:excess] -= flow
|
214
|
+
residual_nodes[node2][:excess] += flow
|
216
215
|
end
|
217
216
|
|
218
|
-
# TODO: Reduce method length
|
219
|
-
|
220
217
|
# Helper function for reverse bfs
|
221
218
|
def self.reverse_bfs(src, residual_pred)
|
222
219
|
heights = {src => 0}
|
@@ -226,7 +223,7 @@ module NetworkX
|
|
226
223
|
u, height = q.shift
|
227
224
|
height += 1
|
228
225
|
residual_pred[u].each do |v, attr|
|
229
|
-
if !heights.
|
226
|
+
if !heights.has_key?(v) && attr[:flow] < attr[:capacity]
|
230
227
|
heights[v] = height
|
231
228
|
q << [v, height]
|
232
229
|
end
|
@@ -246,7 +243,7 @@ module NetworkX
|
|
246
243
|
# maximum preflow
|
247
244
|
#
|
248
245
|
# @return [DiGraph] a residual graph containing the flow values
|
249
|
-
def self.preflowpush(graph, source, target, residual=nil, globalrelabel_freq=1, value_only=false)
|
246
|
+
def self.preflowpush(graph, source, target, residual = nil, globalrelabel_freq = 1, value_only = false)
|
250
247
|
preflowpush_impl(graph, source, target, residual, globalrelabel_freq, value_only)
|
251
248
|
end
|
252
249
|
end
|
@@ -1,12 +1,8 @@
|
|
1
|
-
# TODO: Reduce module length
|
2
|
-
|
3
1
|
module NetworkX
|
4
|
-
# TODO: Reduce method complexity and method length
|
5
|
-
|
6
2
|
# Helper function for running the shortest augmenting path algorithm
|
7
3
|
def self.shortest_augmenting_path_impl(graph, source, target, residual, two_phase, cutoff)
|
8
|
-
raise ArgumentError, 'Source is not in the graph!' unless graph.nodes.
|
9
|
-
raise ArgumentError, 'Target is not in the graph!' unless graph.nodes.
|
4
|
+
raise ArgumentError, 'Source is not in the graph!' unless graph.nodes.has_key?(source)
|
5
|
+
raise ArgumentError, 'Target is not in the graph!' unless graph.nodes.has_key?(target)
|
10
6
|
raise ArgumentError, 'Source and Target are the same!' if source == target
|
11
7
|
|
12
8
|
residual = residual.nil? ? build_residual_network(graph) : residual
|
@@ -27,14 +23,14 @@ module NetworkX
|
|
27
23
|
u, height = q.shift
|
28
24
|
height += 1
|
29
25
|
r_pred[u].each do |v, attrs|
|
30
|
-
if !heights.
|
26
|
+
if !heights.has_key?(v) && attrs[:flow] < attrs[:capacity]
|
31
27
|
heights[v] = height
|
32
28
|
q << [v, height]
|
33
29
|
end
|
34
30
|
end
|
35
31
|
end
|
36
32
|
|
37
|
-
unless heights.
|
33
|
+
unless heights.has_key?(source)
|
38
34
|
residual.graph[:flow_value] = 0
|
39
35
|
return residual
|
40
36
|
end
|
@@ -43,12 +39,11 @@ module NetworkX
|
|
43
39
|
m = residual.size / 2
|
44
40
|
|
45
41
|
r_nodes.each do |node, attrs|
|
46
|
-
attrs[:height] = heights.
|
42
|
+
attrs[:height] = heights.has_key?(node) ? heights[node] : n
|
47
43
|
attrs[:curr_edge] = CurrentEdge.new(r_adj[node])
|
48
44
|
end
|
49
45
|
|
50
|
-
counts =
|
51
|
-
counts.fill(0)
|
46
|
+
counts = [0] * (2 * n - 1)
|
52
47
|
r_nodes.each_value { |attrs| counts[attrs[:height]] += 1 }
|
53
48
|
inf = graph.graph[:inf]
|
54
49
|
|
@@ -56,7 +51,7 @@ module NetworkX
|
|
56
51
|
flow_value = 0
|
57
52
|
path = [source]
|
58
53
|
u = source
|
59
|
-
d = two_phase ? n : [m
|
54
|
+
d = two_phase ? n : [m**0.5, 2 * (n**(2./ 3))].min.floor
|
60
55
|
done = r_nodes[source][:height] >= d
|
61
56
|
|
62
57
|
until done
|
@@ -79,12 +74,12 @@ module NetworkX
|
|
79
74
|
end
|
80
75
|
height = relabel(u, n, r_adj, r_nodes)
|
81
76
|
if u == source && height >= d
|
82
|
-
if
|
83
|
-
residual.graph[:flow_value] = flow_value
|
84
|
-
return residual
|
85
|
-
else
|
77
|
+
if two_phase
|
86
78
|
done = true
|
87
79
|
break
|
80
|
+
else
|
81
|
+
residual.graph[:flow_value] = flow_value
|
82
|
+
return residual
|
88
83
|
end
|
89
84
|
end
|
90
85
|
counts[height] += 1
|
@@ -97,6 +92,7 @@ module NetworkX
|
|
97
92
|
end
|
98
93
|
end
|
99
94
|
next unless u == target
|
95
|
+
|
100
96
|
flow_value += augment(path, inf, r_adj)
|
101
97
|
if flow_value >= cutoff
|
102
98
|
residual.graph[:flow_value] = flow_value
|
@@ -108,8 +104,6 @@ module NetworkX
|
|
108
104
|
residual
|
109
105
|
end
|
110
106
|
|
111
|
-
# TODO: Reduce method complexity and method length
|
112
|
-
|
113
107
|
# Helper function for augmenting flow
|
114
108
|
def augment(path, inf, r_adj)
|
115
109
|
flow = inf
|
@@ -121,6 +115,7 @@ module NetworkX
|
|
121
115
|
u = v
|
122
116
|
end
|
123
117
|
raise ArgumentError, 'Infinite capacity path!' if flow * 2 > inf
|
118
|
+
|
124
119
|
temp_path = path.clone
|
125
120
|
u = temp_path.shift
|
126
121
|
temp_path.each do |v|
|
@@ -146,12 +141,14 @@ module NetworkX
|
|
146
141
|
# @param source [Object] source node
|
147
142
|
# @param target [Object] target node
|
148
143
|
# @param residual [DiGraph, nil] residual graph
|
149
|
-
# @param
|
144
|
+
# @param _value_only [Boolean] if true, compute only the maximum flow value
|
150
145
|
# @param two_phase [Boolean] if true, two phase variant is used
|
151
146
|
# @param cutoff [Numeric] cutoff value for the algorithm
|
152
147
|
#
|
153
148
|
# @return [DiGraph] a residual graph containing the flow values
|
154
|
-
def self.shortest_augmenting_path(graph, source, target, residual
|
149
|
+
def self.shortest_augmenting_path(graph, source, target, residual = nil, \
|
150
|
+
_value_only = false, two_phase = false, cutoff = nil)
|
151
|
+
|
155
152
|
shortest_augmenting_path_impl(graph, source, target, residual, two_phase, cutoff)
|
156
153
|
end
|
157
154
|
end
|
data/lib/networkx/flow/utils.rb
CHANGED
@@ -34,9 +34,9 @@ module NetworkX
|
|
34
34
|
|
35
35
|
# Helper class for preflow push algorithm
|
36
36
|
class GlobalRelabelThreshold
|
37
|
-
def initialize(
|
37
|
+
def initialize(num1, num2, freq)
|
38
38
|
freq = freq.nil? ? Float::INFINITY : freq
|
39
|
-
@threshold = (
|
39
|
+
@threshold = (num1 + num2) / freq
|
40
40
|
@work = 0
|
41
41
|
end
|
42
42
|
|
@@ -53,8 +53,6 @@ module NetworkX
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
# TODO: Reduce method complexity and method length
|
57
|
-
|
58
56
|
# Builds a residual graph from a constituent graph
|
59
57
|
#
|
60
58
|
# @param graph [DiGraph] a graph
|
@@ -69,31 +67,13 @@ module NetworkX
|
|
69
67
|
edge_list = []
|
70
68
|
|
71
69
|
graph.adj.each do |u, u_edges|
|
72
|
-
require 'spec_helper'
|
73
|
-
RSpec.describe NetworkX::DiGraph do
|
74
|
-
subject { graph }
|
75
|
-
|
76
|
-
let(:graph) { described_class.new }
|
77
|
-
|
78
|
-
before do
|
79
|
-
graph.add_edge(1, 2)
|
80
|
-
graph.add_edge(2, 4)
|
81
|
-
end
|
82
|
-
|
83
|
-
context 'when capacity_scaling is called' do
|
84
|
-
subject { NetworkX.capacity_scaling(graph) }
|
85
|
-
|
86
|
-
it { is_expected.to eq([0, {1=>{2=>0}, 2=>{4=>0}, 4=>{}}]) }
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
70
|
u_edges.each do |v, uv_attrs|
|
91
|
-
edge_list << [u, v, uv_attrs] if (uv_attrs[:capacity] || inf)
|
71
|
+
edge_list << [u, v, uv_attrs] if (uv_attrs[:capacity] || inf).positive? && u != v
|
92
72
|
end
|
93
73
|
end
|
94
74
|
|
95
75
|
inf_chk = 3 * edge_list.inject(0) do |result, arr|
|
96
|
-
arr[2].
|
76
|
+
arr[2].has_key?(:capacity) && arr[2][:capacity] != inf ? (result + arr[2][:capacity]) : result
|
97
77
|
end
|
98
78
|
inf = inf_chk.zero? ? 1 : inf_chk
|
99
79
|
|
@@ -118,8 +98,6 @@ module NetworkX
|
|
118
98
|
r_network
|
119
99
|
end
|
120
100
|
|
121
|
-
# TODO: Reduce method complexity and method length
|
122
|
-
|
123
101
|
# Detects unboundedness in a graph, raises exception when
|
124
102
|
# infinite capacity flow is found
|
125
103
|
#
|
@@ -135,6 +113,7 @@ module NetworkX
|
|
135
113
|
r_network.adj[u].each do |v, uv_attrs|
|
136
114
|
next unless uv_attrs[:capacity] == inf && !seen.include?(v)
|
137
115
|
raise ArgumentError, 'Infinite capacity flow!' if v == target
|
116
|
+
|
138
117
|
seen << v
|
139
118
|
q << v
|
140
119
|
end
|
@@ -153,7 +132,7 @@ module NetworkX
|
|
153
132
|
graph.edges.each do |u, u_edges|
|
154
133
|
flow_dict[u] = {}
|
155
134
|
u_edges.each_key { |v| flow_dict[u][v] = 0 }
|
156
|
-
u_edges.each_key { |v| flow_dict[u][v] = residual[u][v][:flow] if residual[u][v][:flow]
|
135
|
+
u_edges.each_key { |v| flow_dict[u][v] = residual[u][v][:flow] if (residual[u][v][:flow]).positive? }
|
157
136
|
end
|
158
137
|
flow_dict
|
159
138
|
end
|