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,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.each { |u| return u }
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.key?(source)
14
- raise ArgumentError, 'Target not in graph!' unless graph.nodes.key?(target)
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 < 0
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.key?(source)
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.key?(u) ? heights[u] : (n + 1)
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 > 0
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] > 0 ? level.active.add(u) : level.inactive.add(u)
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 > 0
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, is_phase_1, residual_nodes, residual_adj, height, levels, grt, source, target)
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 is_phase_1 && height_val >= n - 1
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.key?(u) && attr[:height] < num }
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(node_1, node_2, flow, residual_nodes, residual_adj)
212
- residual_adj[node_1][node_2][:flow] += flow
213
- residual_adj[node_2][node_1][:flow] -= flow
214
- residual_nodes[node_1][:excess] -= flow
215
- residual_nodes[node_2][:excess] += flow
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.key?(v) && attr[:flow] < attr[:capacity]
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.key?(source)
9
- raise ArgumentError, 'Target is not in the graph!' unless graph.nodes.key?(target)
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.key?(v) && attrs[:flow] < attrs[:capacity]
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.key?(source)
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.key?(node) ? heights[node] : n
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 = Array.new(2 * n - 1, 0)
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 ** 0.5, 2 * n ** (2. / 3)].min.floor
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 !two_phase
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 value_only [Boolean] if true, compute only the maximum flow value
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=nil, _value_only=false, two_phase=false, cutoff=nil)
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
@@ -34,9 +34,9 @@ module NetworkX
34
34
 
35
35
  # Helper class for preflow push algorithm
36
36
  class GlobalRelabelThreshold
37
- def initialize(num_1, num_2, freq)
37
+ def initialize(num1, num2, freq)
38
38
  freq = freq.nil? ? Float::INFINITY : freq
39
- @threshold = (num_1 + num_2) / freq
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) > 0 && u != v
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].key?(:capacity) && arr[2][:capacity] != inf ? (result + arr[2][:capacity]) : result
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] > 0 }
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