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
@@ -1,24 +1,104 @@
1
1
  module NetworkX
2
+ # Union Find Tree
3
+ #
4
+ # Reference
5
+ # - [ac-library-rb DSU (CC0)](https://github.com/universato/ac-library-rb/blob/main/lib/dsu.rb)
6
+ # - [Python NetworkX UnionFind](https://networkx.org/documentation/stable/_modules/networkx/utils/union_find.html)
7
+ #
8
+ #
9
+ # @attr_reader parents [Hash{ Object => Object }] Return parent of each element
10
+ # @attr_reader weights [Hash{ Object => Integer }] Return weight of each element
2
11
  class UnionFind
3
- def initialize(nodes)
4
- @unions = {}
5
- nodes.each_with_index do |node, index|
6
- @unions[node] = index
12
+ attr_accessor :parents, :weights
13
+
14
+ # Constructor for initializing Union Find Tree
15
+ #
16
+ # @param nodes [?Array[Object]] nodes
17
+ #
18
+ # @return [UnionFind] Union Find Tree
19
+ def initialize(nodes = nil)
20
+ @weights = {}
21
+ @parents = {}
22
+ nodes&.each do |node|
23
+ @weights[node] = 1
24
+ @parents[node] = node
25
+ end
26
+ end
27
+
28
+ # Return the root of node
29
+ #
30
+ # @param node [Object] node
31
+ #
32
+ # @return [Object] root of node, leader of node
33
+ def [](node)
34
+ if @parents.has_key?(node)
35
+ @parents[node] == node ? node : (@parents[node] = self[@parents[node]])
36
+ else
37
+ @weights[node] = 1
38
+ @parents[node] = node
7
39
  end
8
40
  end
9
41
 
10
- def connected?(node_1, node_2)
11
- @unions[node_1] == @unions[node_2]
42
+ # Return the root of node
43
+ #
44
+ # @param node [Object] node
45
+ #
46
+ # @return [Object] root of node, leader of node
47
+ def root(node)
48
+ @parents.has_key?(node) or raise ArgumentError.new, "#{node} is not a node"
49
+
50
+ @parents[node] == node ? node : (@parents[node] = root(@parents[node]))
51
+ end
52
+
53
+ def each(&block)
54
+ @parents.each_key(&block)
12
55
  end
13
56
 
14
- def union(node_1, node_2)
15
- return if connected?(node_1, node_2)
16
- node1_id = @unions[node_1]
17
- node2_id = @unions[node_2]
57
+ def to_sets
58
+ each.group_by { |node| root(node) }.values
59
+ end
60
+ alias groups to_sets
18
61
 
19
- @unions.each do |node, id|
20
- @unions[node] = node1_id if id == node2_id
62
+ # Is each root of two nodes the same?
63
+ #
64
+ # @param node1 [Object] node
65
+ # @param node2 [Object] node
66
+ #
67
+ # @return [bool] Is each root of node1 and nodes_2 the same?
68
+ def connected?(node1, node2)
69
+ root(node1) == root(node2)
70
+ end
71
+ alias same? connected?
72
+
73
+ # Unite nodes.
74
+ #
75
+ # @param nodes [Array[Object]] nodes
76
+ #
77
+ # @return [Object | nil] root of united nodes
78
+ def union(*nodes)
79
+ return merge(*nodes) if nodes.size == 2
80
+
81
+ roots = nodes.map { |node| self[node] }.uniq
82
+ return if roots.size == 1
83
+
84
+ roots.sort_by! { |root| @weights[root] }
85
+ root = roots[-1]
86
+ roots[0...-1].each do |r|
87
+ @weights[root] += @weights[r]
88
+ @parents[r] = root
21
89
  end
90
+ root
91
+ end
92
+ alias unite union
93
+
94
+ def merge(node1, node2)
95
+ x = self[node1]
96
+ y = self[node2]
97
+ return if x == y
98
+
99
+ x, y = y, x if @weights[x] < @weights[y]
100
+ @weights[x] += @weights[y]
101
+ @parents[y] = x
22
102
  end
23
103
  end
24
104
  end
@@ -7,7 +7,7 @@ module NetworkX
7
7
  def self.wiener_index(graph)
8
8
  total = all_pairs_shortest_path_length(graph)
9
9
  wiener_ind = 0
10
- Hash[total].each { |_, distances| Hash[distances].each { |_, val| wiener_ind += val } }
10
+ total.to_h.each { |_, distances| distances.to_h.each { |_, val| wiener_ind += val } }
11
11
  graph.directed? ? wiener_ind : wiener_ind / 2
12
12
  end
13
13
  end
@@ -1,11 +1,9 @@
1
1
  module NetworkX
2
- # TODO: Reduce method length and method complexity
3
-
4
2
  # Saves the graph in a csv file
5
3
  #
6
4
  # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph
7
5
  # @param filename [String] filename of the graph
8
- def self.graph_to_csv(graph, filename='graph.csv')
6
+ def self.graph_to_csv(graph, filename = 'graph.csv')
9
7
  CSV.open(filename, 'wb') do |csv|
10
8
  csv << [graph.class.name]
11
9
  csv << ['graph_values']
@@ -13,8 +13,6 @@ module NetworkX
13
13
  json_hash.to_json
14
14
  end
15
15
 
16
- # TODO: Reduce method length
17
-
18
16
  # Returns a graph from the json encoded graph
19
17
  #
20
18
  # @param json_str [JSON] json encoded string
@@ -8,7 +8,7 @@ module NetworkX
8
8
  # @attr_reader nodes [Hash{ Object => Hash{ Object => Object } }] Stores the nodes and their attributes
9
9
  # @attr_reader graph [Hash{ Object => Object }] Stores the attributes of the graph
10
10
  class DiGraph < Graph
11
- attr_reader :adj, :nodes, :graph, :pred
11
+ attr_reader :adj, :graph, :pred
12
12
 
13
13
  # Constructor for initializing graph
14
14
  #
@@ -17,7 +17,7 @@ module NetworkX
17
17
  #
18
18
  # @param graph_attrs [Hash{ Object => Object }] the graph attributes in a hash format
19
19
  def initialize(**graph_attrs)
20
- super(graph_attrs)
20
+ super(**graph_attrs)
21
21
 
22
22
  @pred = {}
23
23
  end
@@ -30,16 +30,16 @@ module NetworkX
30
30
  # @example Add an edge with no attribute
31
31
  # graph.add_edge("Bangalore", "Chennai")
32
32
  #
33
- # @param node_1 [Object] the first node of the edge
34
- # @param node_2 [Object] the second node of the edge
33
+ # @param node1 [Object] the first node of the edge
34
+ # @param node2 [Object] the second node of the edge
35
35
  # @param edge_attrs [Hash{ Object => Object }] the hash of the edge attributes
36
- def add_edge(node_1, node_2, **edge_attrs)
37
- add_node(node_1)
38
- add_node(node_2)
36
+ def add_edge(node1, node2, **edge_attrs)
37
+ add_node(node1)
38
+ add_node(node2)
39
39
 
40
- edge_attrs = (@adj[node_1][node_2] || {}).merge(edge_attrs)
41
- @adj[node_1][node_2] = edge_attrs
42
- @pred[node_2][node_1] = edge_attrs
40
+ edge_attrs = (@adj[node1][node2] || {}).merge(edge_attrs)
41
+ @adj[node1][node2] = edge_attrs
42
+ @pred[node2][node1] = edge_attrs
43
43
  end
44
44
 
45
45
  # Adds a node and its attributes to the graph
@@ -50,9 +50,13 @@ module NetworkX
50
50
  # @param node [Object] the node object
51
51
  # @param node_attrs [Hash{ Object => Object }] the hash of the attributes of the node
52
52
  def add_node(node, **node_attrs)
53
- super(node, node_attrs)
53
+ super(node, **node_attrs)
54
54
 
55
- @pred[node] = {} unless @pred.key?(node)
55
+ @pred[node] = {} unless @pred.has_key?(node)
56
+ end
57
+
58
+ def nodes(data: true)
59
+ data ? @nodes : @nodes.keys
56
60
  end
57
61
 
58
62
  # Removes node from the graph
@@ -62,7 +66,7 @@ module NetworkX
62
66
  #
63
67
  # @param node [Object] the node to be removed
64
68
  def remove_node(node)
65
- raise KeyError, "Error in deleting node #{node} from Graph." unless @nodes.key?(node)
69
+ raise KeyError, "Error in deleting node #{node} from Graph." unless @nodes.has_key?(node)
66
70
 
67
71
  neighbours = @adj[node]
68
72
  neighbours.each_key { |k| @pred[k].delete(node) }
@@ -80,15 +84,15 @@ module NetworkX
80
84
  # @example
81
85
  # graph.remove_edge('Noida', 'Bangalore')
82
86
  #
83
- # @param node_1 [Object] the first node of the edge
84
- # @param node_2 [Object] the second node of the edge
85
- def remove_edge(node_1, node_2)
86
- raise KeyError, "#{node_1} is not a valid node." unless @nodes.key?(node_1)
87
- raise KeyError, "#{node_2} is not a valid node" unless @nodes.key?(node_2)
88
- raise KeyError, 'The given edge is not a valid one.' unless @adj[node_1].key?(node_2)
87
+ # @param node1 [Object] the first node of the edge
88
+ # @param node2 [Object] the second node of the edge
89
+ def remove_edge(node1, node2)
90
+ raise KeyError, "#{node1} is not a valid node." unless @nodes.has_key?(node1)
91
+ raise KeyError, "#{node2} is not a valid node" unless @nodes.has_key?(node2)
92
+ raise KeyError, 'The given edge is not a valid one.' unless @adj[node1].has_key?(node2)
89
93
 
90
- @adj[node_1].delete(node_2)
91
- @pred[node_2].delete(node_1)
94
+ @adj[node1].delete(node2)
95
+ @pred[node2].delete(node1)
92
96
  end
93
97
 
94
98
  # Clears the graph
@@ -106,7 +110,7 @@ module NetworkX
106
110
  # @example
107
111
  # graph.number_of_edges
108
112
  def number_of_edges
109
- @adj.values.map(&:length).inject(:+)
113
+ @adj.values.map(&:length).sum
110
114
  end
111
115
 
112
116
  # Returns the size of graph
@@ -116,11 +120,11 @@ module NetworkX
116
120
  #
117
121
  # @param is_weighted [Bool] if true, method returns sum of weights of all edges
118
122
  # else returns number of edges
119
- def size(is_weighted=false)
123
+ def size(is_weighted = false)
120
124
  if is_weighted
121
125
  graph_size = 0
122
126
  @adj.each do |_, hash_val|
123
- hash_val.each { |_, v| graph_size += v[:weight] if v.key?(:weight) }
127
+ hash_val.each { |_, v| graph_size += v[:weight] if v.has_key?(:weight) }
124
128
  end
125
129
  return graph_size
126
130
  end
@@ -152,10 +156,10 @@ module NetworkX
152
156
  # @example
153
157
  # graph.reverse
154
158
  def reverse
155
- new_graph = NetworkX::DiGraph.new(@graph)
156
- @nodes.each { |u, attrs| new_graph.add_node(u, attrs) }
159
+ new_graph = NetworkX::DiGraph.new(**@graph)
160
+ @nodes.each { |u, attrs| new_graph.add_node(u, **attrs) }
157
161
  @adj.each do |u, edges|
158
- edges.each { |v, attrs| new_graph.add_edge(v, u, attrs) }
162
+ edges.each { |v, attrs| new_graph.add_edge(v, u, **attrs) }
159
163
  end
160
164
  new_graph
161
165
  end
@@ -165,16 +169,14 @@ module NetworkX
165
169
  # @example
166
170
  # graph.to_undirected
167
171
  def to_undirected
168
- new_graph = NetworkX::Graph.new(@graph)
169
- @nodes.each { |u, attrs| new_graph.add_node(u, attrs) }
172
+ new_graph = NetworkX::Graph.new(**@graph)
173
+ @nodes.each { |u, attrs| new_graph.add_node(u, **attrs) }
170
174
  @adj.each do |u, edges|
171
- edges.each { |v, attrs| new_graph.add_edge(u, v, attrs) }
175
+ edges.each { |v, attrs| new_graph.add_edge(u, v, **attrs) }
172
176
  end
173
177
  new_graph
174
178
  end
175
179
 
176
- # TODO: Reduce method complexity and method length
177
-
178
180
  # Returns subgraph consisting of given array of nodes
179
181
  #
180
182
  # @example
@@ -184,23 +186,22 @@ module NetworkX
184
186
  def subgraph(nodes)
185
187
  case nodes
186
188
  when Array, Set
187
- sub_graph = NetworkX::DiGraph.new(@graph)
189
+ sub_graph = NetworkX::DiGraph.new(**@graph)
188
190
  nodes.each do |u|
189
191
  raise KeyError, "#{u} does not exist in the current graph!" unless node?(u)
190
- sub_graph.add_node(u, @nodes[u])
192
+
193
+ sub_graph.add_node(u, **@nodes[u])
191
194
  @adj[u].each do |v, uv_attrs|
192
- sub_graph.add_edge(u, v, uv_attrs) if @adj[u].key?(v) && nodes.include?(v)
195
+ sub_graph.add_edge(u, v, **uv_attrs) if @adj[u].has_key?(v) && nodes.include?(v)
193
196
  end
194
- return sub_graph
195
197
  end
198
+ sub_graph
196
199
  else
197
- raise ArgumentError, 'Expected Argument to be Array or Set of nodes, '\
198
- "received #{nodes.class.name} instead."
200
+ raise ArgumentError, 'Expected Argument to be Array or Set of nodes, ' \
201
+ "received #{nodes.class.name} instead."
199
202
  end
200
203
  end
201
204
 
202
- # TODO: Reduce method complexity and method length
203
-
204
205
  # Returns subgraph consisting of given edges
205
206
  #
206
207
  # @example
@@ -210,19 +211,24 @@ module NetworkX
210
211
  def edge_subgraph(edges)
211
212
  case edges
212
213
  when Array, Set
213
- sub_graph = NetworkX::DiGraph.new(@graph)
214
+ sub_graph = NetworkX::DiGraph.new(**@graph)
214
215
  edges.each do |u, v|
215
- raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.key?(u)\
216
- && @adj[u].key?(v)
217
- sub_graph.add_node(u, @nodes[u])
218
- sub_graph.add_node(v, @nodes[v])
219
- sub_graph.add_edge(u, v, @adj[u][v])
216
+ raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.has_key?(u) \
217
+ && @adj[u].has_key?(v)
218
+
219
+ sub_graph.add_node(u, **@nodes[u])
220
+ sub_graph.add_node(v, **@nodes[v])
221
+ sub_graph.add_edge(u, v, **@adj[u][v])
220
222
  end
221
- return sub_graph
223
+ sub_graph
222
224
  else
223
- raise ArgumentError, 'Expected Argument to be Array or Set of edges, '\
224
- "received #{edges.class.name} instead."
225
+ raise ArgumentError, 'Expected Argument to be Array or Set of edges, ' \
226
+ "received #{edges.class.name} instead."
225
227
  end
226
228
  end
229
+
230
+ def directed?
231
+ true
232
+ end
227
233
  end
228
234
  end
@@ -1,5 +1,3 @@
1
- # TODO: Reduce module length
2
-
3
1
  module NetworkX
4
2
  # Returns a label for unique node
5
3
  def self.generate_unique_node
@@ -24,8 +22,6 @@ module NetworkX
24
22
  false
25
23
  end
26
24
 
27
- # TODO: Reduce method complexity and method length
28
-
29
25
  # Detects the unboundedness in the residual graph
30
26
  def self._detect_unboundedness(residual)
31
27
  g = NetworkX::DiGraph.new
@@ -42,14 +38,13 @@ module NetworkX
42
38
  raise ArgumentError, 'Negative cost cycle of infinite capacity found!' if negative_edge_cycle(g)
43
39
  end
44
40
 
45
- # TODO: Reduce method complexity and method length
46
-
47
41
  # Returns the residual graph of the given graph
48
42
  def self._build_residual_network(graph)
49
- raise ArgumentError, 'Sum of demands should be 0!' unless\
43
+ raise ArgumentError, 'Sum of demands should be 0!' unless \
50
44
  graph.nodes.values.map { |attr| attr[:demand] || 0 }.inject(0, :+).zero?
45
+
51
46
  residual = NetworkX::MultiDiGraph.new(inf: 0)
52
- residual.add_nodes(graph.nodes.map { |u, attr| [u, excess: (attr[:demand] || 0) * -1, potential: 0] })
47
+ residual.add_nodes(graph.nodes.map { |u, attr| [u, {excess: (attr[:demand] || 0) * -1, potential: 0}] })
53
48
  inf = Float::INFINITY
54
49
  edge_list = []
55
50
 
@@ -59,20 +54,20 @@ module NetworkX
59
54
  graph.adj.each do |u, u_edges|
60
55
  u_edges.each do |v, uv_edges|
61
56
  uv_edges.each do |k, attrs|
62
- edge_list << [u, v, k, e] if u != v && (attrs[:capacity] || inf) > 0
57
+ edge_list << [u, v, k, e] if u != v && (attrs[:capacity] || inf).positive?
63
58
  end
64
59
  end
65
60
  end
66
61
  else
67
62
  graph.adj.each do |u, u_edges|
68
63
  u_edges.each do |v, attrs|
69
- edge_list << [u, v, 0, attrs] if u != v && (attrs[:capacity] || inf) > 0
64
+ edge_list << [u, v, 0, attrs] if u != v && (attrs[:capacity] || inf).positive?
70
65
  end
71
66
  end
72
67
  end
73
68
 
74
69
  temp_inf = [residual.nodes.map { |_u, attrs| attrs[:excess].abs }.inject(0, :+), edge_list.map do |_, _, _, e|
75
- (e.key?(:capacity) && e[:capacity] != inf ? e[:capacity] : 0)
70
+ (e.has_key?(:capacity) && e[:capacity] != inf ? e[:capacity] : 0)
76
71
  end.inject(0, :+) * 2].max
77
72
  inf = temp_inf.zero? ? 1 : temp_inf
78
73
 
@@ -87,8 +82,6 @@ module NetworkX
87
82
  residual
88
83
  end
89
84
 
90
- # TODO: Reduce method complexity and method length
91
-
92
85
  # Returns the flowdict of the graph
93
86
  def self._build_flow_dict(graph, residual)
94
87
  flow_dict = {}
@@ -98,22 +91,24 @@ module NetworkX
98
91
  graph.nodes.each_key do |u|
99
92
  flow_dict[u] = {}
100
93
  graph.adj[u].each do |v, uv_edges|
101
- flow_dict[u][v] = Hash[uv_edges.map do |k, e|
102
- [k, u != v || (e[:capacity] || inf) <= 0 || (e[:weight] || 0) >= 0 ? 0 : e[:capacity]]
103
- end]
94
+ flow_dict[u][v] = uv_edges.transform_values do |e|
95
+ u != v || (e[:capacity] || inf) <= 0 || (e[:weight] || 0) >= 0 ? 0 : e[:capacity]
96
+ end
104
97
  end
105
98
  residual.adj[u].each do |v, uv_edges|
106
- flow_dict[u][v].merge!(Hash[uv_edges.map { |_, val| [val[:temp_key][0], val[:flow]] if val[:flow] > 0 }])
99
+ flow_dict[u][v].merge!(uv_edges.to_h do |_, val|
100
+ [val[:temp_key][0], val[:flow]] if (val[:flow]).positive?
101
+ end)
107
102
  end
108
103
  end
109
104
  else
110
105
  graph.nodes.each_key do |u|
111
- flow_dict[u] = Hash[graph.adj[u].map do |v, e|
106
+ flow_dict[u] = graph.adj[u].to_h do |v, e|
112
107
  [v, u != v || (e[:capacity] || inf) <= 0 || (e[:weight] || 0) >= 0 ? 0 : e[:capacity]]
113
- end]
108
+ end
114
109
  merge_dict = {}
115
110
  residual.adj[u].each do |v, uv_edges|
116
- uv_edges.each_value { |attrs| merge_dict[v] = attrs[:flow] if attrs[:flow] > 0 }
111
+ uv_edges.each_value { |attrs| merge_dict[v] = attrs[:flow] if (attrs[:flow]).positive? }
117
112
  end
118
113
  flow_dict[u].merge!(merge_dict)
119
114
  end
@@ -121,15 +116,6 @@ module NetworkX
121
116
  flow_dict
122
117
  end
123
118
 
124
- # Counter for the algorithm
125
- @itr = 0
126
- def self.count
127
- @itr += 1
128
- @itr
129
- end
130
-
131
- # TODO: Reduce method complexity and method length
132
-
133
119
  # Computes max flow using capacity scaling algorithm
134
120
  #
135
121
  # @param graph [DiGraph, MultiDiGraph] a graph
@@ -148,19 +134,22 @@ module NetworkX
148
134
  end).max
149
135
 
150
136
  return flow_cost, _build_flow_dict(graph, residual) if wmax == -inf
137
+
151
138
  r_nodes = residual.nodes
152
139
  r_adj = residual.adj
153
140
 
154
- delta = 2 ** Math.log2(wmax).floor
141
+ delta = 2**Math.log2(wmax).floor
155
142
  while delta >= 1
156
143
  r_nodes.each do |u, u_attrs|
157
144
  p_u = u_attrs[:potential]
158
145
  r_adj[u].each do |v, uv_edges|
159
146
  uv_edges.each do |_k, e|
160
147
  flow = e[:capacity]
161
- next unless e[:weight] - p_u + r_nodes[v][:potential] < 0
148
+ next unless (e[:weight] - p_u + r_nodes[v][:potential]).negative?
149
+
162
150
  flow = e[:capacity] - e[:flow]
163
151
  next unless flow >= delta
152
+
164
153
  e[:flow] += flow
165
154
  r_adj[v][u].each_key do |val|
166
155
  val[:flow] += val[:temp_key][0] == e[:temp_key][0] && val[:temp_key][1] != e[:temp_key][1] ? -flow : 0
@@ -201,24 +190,31 @@ module NetworkX
201
190
  end
202
191
  p_u = r_nodes[u][:potential]
203
192
  r_adj[u].each do |v, uv_edges|
204
- next if d.key?(v)
193
+ next if d.has_key?(v)
194
+
205
195
  wmin = inf
206
196
  uv_edges.each_value do |e|
207
197
  next unless e[:capacity] - e[:flow] >= delta
198
+
208
199
  w = e[:weight]
209
200
  next unless w < wmin
201
+
210
202
  wmin = w
211
203
  end
212
204
  next if wmin == inf
205
+
213
206
  d_v = d_u + wmin - p_u + r_nodes[v][:potential]
214
207
  next unless h_dict[v] > d_v
208
+
215
209
  h << [d_v, count, v]
216
210
  h_dict[v] = d_v
217
211
  pred[v] = [u, kmin, emin]
218
212
  end
219
213
  end
220
214
 
221
- if !t.nil?
215
+ if t.nil?
216
+ s_set.delete(s)
217
+ else
222
218
  while u != s
223
219
  v = u
224
220
  u, k, e = pred[v]
@@ -233,8 +229,6 @@ module NetworkX
233
229
  t_set.delete(t) if r_nodes[t][:excess] > -delta
234
230
  d_t = d[t]
235
231
  d.each { |node, d_u_node| r_nodes[node][:potential] -= (d_u_node - d_t) }
236
- else
237
- s_set.delete(s)
238
232
  end
239
233
  end
240
234
  delta = (delta / 2).floor
@@ -1,6 +1,4 @@
1
1
  module NetworkX
2
- # TODO: Reduce method complexity and method length
3
-
4
2
  # Helper function to augment the flow in a residual graph
5
3
  def self.augment(residual, inf, path)
6
4
  flow = inf
@@ -11,6 +9,7 @@ module NetworkX
11
9
  u = v
12
10
  end
13
11
  raise ArgumentError, 'Infinite capacity path!' if flow * 2 > inf
12
+
14
13
  u = path_first_elem
15
14
  path.each do |v|
16
15
  residual.adj[u][v][:flow] += flow
@@ -20,8 +19,6 @@ module NetworkX
20
19
  flow
21
20
  end
22
21
 
23
- # TODO: Reduce method complexity and method length
24
-
25
22
  # Helper function for the bidirectional bfs
26
23
  def self.bidirectional_bfs(residual, source, target)
27
24
  pred, succ = {source => nil}, {target => nil}
@@ -32,29 +29,34 @@ module NetworkX
32
29
  q_s.each do |u|
33
30
  residual.adj[u].each do |v, uv_attrs|
34
31
  next unless !pred.include?(v) && (uv_attrs[:flow] < uv_attrs[:capacity])
32
+
35
33
  pred[v] = u
36
- return [v, pred, succ] if succ.key?(v)
34
+ return [v, pred, succ] if succ.has_key?(v)
35
+
37
36
  q << v
38
37
  end
39
38
  end
40
39
  return [nil, nil, nil] if q.empty?
40
+
41
+ q_s = q
41
42
  else
42
43
  q_t.each do |u|
43
44
  residual.pred[u].each do |v, uv_attrs|
44
- next unless !succ.key?(v) && uv_attrs[:flow] < uv_attrs[:capacity]
45
+ next unless !succ.has_key?(v) && uv_attrs[:flow] < uv_attrs[:capacity]
46
+
45
47
  succ[v] = u
46
- return [v, pred, succ] if pred.key?(v)
48
+ return [v, pred, succ] if pred.has_key?(v)
49
+
47
50
  q << v
48
51
  end
49
52
  end
50
53
  return [nil, nil, nil] if q.empty?
54
+
51
55
  q_t = q
52
56
  end
53
57
  end
54
58
  end
55
59
 
56
- # TODO: Reduce method complexity and method length
57
-
58
60
  # Core helper function for the EdmondsKarp algorithm
59
61
  def self.edmondskarp_core(residual, source, target, cutoff)
60
62
  inf = residual.graph[:inf]
@@ -62,6 +64,7 @@ module NetworkX
62
64
  while flow_val < cutoff
63
65
  v, pred, succ = bidirectional_bfs(residual, source, target)
64
66
  break if pred.nil?
67
+
65
68
  path = [v]
66
69
  u = v
67
70
  while u != source
@@ -79,13 +82,12 @@ module NetworkX
79
82
  flow_val
80
83
  end
81
84
 
82
- # TODO: Reduce method complexity and method length
83
-
84
85
  # Helper function for the edmondskarp function
85
86
  def self.edmondskarp_impl(graph, source, target, residual, cutoff)
86
- raise ArgumentError, 'Source not in graph!' unless graph.nodes.key?(source)
87
- raise ArgumentError, 'Target not in graph!' unless graph.nodes.key?(target)
87
+ raise ArgumentError, 'Source not in graph!' unless graph.nodes.has_key?(source)
88
+ raise ArgumentError, 'Target not in graph!' unless graph.nodes.has_key?(target)
88
89
  raise ArgumentError, 'Source and target are same node!' if source == target
90
+
89
91
  res_graph = residual.nil? ? build_residual_network(graph) : residual.clone
90
92
  res_graph.adj.each do |u, u_edges|
91
93
  u_edges.each do |v, _attrs|
@@ -94,7 +96,7 @@ module NetworkX
94
96
  end
95
97
  end
96
98
  cutoff = Float::INFINITY if cutoff.nil?
97
- res_graph.graph[:flow_val] = edmondskarp_core(res_graph, source, target, cutoff)
99
+ res_graph.graph[:flow_value] = edmondskarp_core(res_graph, source, target, cutoff)
98
100
  res_graph
99
101
  end
100
102
 
@@ -107,7 +109,7 @@ module NetworkX
107
109
  # @param cutoff [Numeric] cutoff for the algorithm
108
110
  #
109
111
  # @return [DiGraph] a residual graph containing the flow values
110
- def self.edmondskarp(graph, source, target, residual=nil, cutoff=nil)
112
+ def self.edmondskarp(graph, source, target, residual = nil, cutoff = nil)
111
113
  edmondskarp_impl(graph, source, target, residual, cutoff)
112
114
  end
113
115
  end