networkx 0.1.1 → 0.3.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/.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,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 | 
            -
                 | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 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 | 
            -
                 | 
| 11 | 
            -
             | 
| 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  | 
| 15 | 
            -
                   | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 57 | 
            +
                def to_sets
         | 
| 58 | 
            +
                  each.group_by { |node| root(node) }.values
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
                alias groups to_sets
         | 
| 18 61 |  | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 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 | 
            -
                 | 
| 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']
         | 
    
        data/lib/networkx/digraph.rb
    CHANGED
    
    | @@ -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, : | 
| 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  | 
| 34 | 
            -
                # @param  | 
| 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( | 
| 37 | 
            -
                  add_node( | 
| 38 | 
            -
                  add_node( | 
| 36 | 
            +
                def add_edge(node1, node2, **edge_attrs)
         | 
| 37 | 
            +
                  add_node(node1)
         | 
| 38 | 
            +
                  add_node(node2)
         | 
| 39 39 |  | 
| 40 | 
            -
                  edge_attrs = (@adj[ | 
| 41 | 
            -
                  @adj[ | 
| 42 | 
            -
                  @pred[ | 
| 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. | 
| 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. | 
| 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  | 
| 84 | 
            -
                # @param  | 
| 85 | 
            -
                def remove_edge( | 
| 86 | 
            -
                  raise KeyError, "#{ | 
| 87 | 
            -
                  raise KeyError, "#{ | 
| 88 | 
            -
                  raise KeyError, 'The given edge is not a valid one.' unless @adj[ | 
| 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[ | 
| 91 | 
            -
                  @pred[ | 
| 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). | 
| 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. | 
| 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( | 
| 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( | 
| 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( | 
| 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 | 
            -
             | 
| 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]. | 
| 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 | 
            -
             | 
| 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( | 
| 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. | 
| 216 | 
            -
                                                                                                && @adj[u]. | 
| 217 | 
            -
             | 
| 218 | 
            -
                      sub_graph.add_node( | 
| 219 | 
            -
                      sub_graph. | 
| 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 | 
            -
                     | 
| 223 | 
            +
                    sub_graph
         | 
| 222 224 | 
             
                  else
         | 
| 223 | 
            -
                    raise ArgumentError, 'Expected Argument to be Array or Set of edges, '\
         | 
| 224 | 
            -
             | 
| 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) | 
| 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) | 
| 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. | 
| 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] =  | 
| 102 | 
            -
                         | 
| 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!( | 
| 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] =  | 
| 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]  | 
| 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 | 
| 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] | 
| 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. | 
| 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  | 
| 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. | 
| 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. | 
| 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. | 
| 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. | 
| 87 | 
            -
                raise ArgumentError, 'Target not in graph!' unless graph.nodes. | 
| 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[: | 
| 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
         |