Class: Array + + + +
+-
+
- Inherits: +
-
+ Object
+
+
-
+
- Object + +
- Array + +
+
-
+
- Includes: +
- Comparable +
-
+
- Defined in: +
- lib/networkx/others/grid_2d_graph.rb +
diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md deleted file mode 100644 index 6841be1..0000000 --- a/.github/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,46 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at athityakumar@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index 7c85a23..0000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,53 +0,0 @@ -# Contribution guidelines - -First of all, thanks for thinking of contributing to this project. :smile: - -# Developing the gem - -1. Fork this repository and clone it and install all the required gem dependencies. - - ```sh - git clone https://github.com/`your_github_user_id`/networkx.rb.git - cd networkx.rb - gem install bundler - bundle install - ``` - -2. Checkout to a different git branch (say, `adds-new-feature`). - -3. Add code (, test, and YARD documentation). - -4. Run the rspec test-suite. - ```sh - # Runs test suite for all files - bundle exec rspec - - # Runs test-suite only for a particular file - bundle exec rspec spec/networkx/filename_spec.rb - ``` - -5. Run the rubocop for static code quality comments. - - ```sh - # Runs rubocop test for all files - bundle exec rubocop - - # Runs rubocop test only for a particular file - bundle exec rubocop lib/networkx/filename.rb - ``` - -6. Send a Pull Request back to this repository. :tada: - -# Note: YARD Document - -You can create YARD documentation - -1. Create Document for `doc` directory with `yard` command -2. Create server via `yard server` command -3. open Browser with `open http://0.0.0.0:8808` e.t.c. - -``` -$ yard -$ yard server -$ open http://0.0.0.0:8808 -``` diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 279d6a4..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -name: Bug Report -about: Report an issue with gem you've discovered. ---- - -## Steps to reproduce the problem - -```ruby -``` - -## Actual behavior - -``` -``` - -## Expected behavior - -``` -``` - -## Version - -Include the versions of Ruby & NetworkX - -```ruby -p ['RUBY_VERSION: ', RUBY_VERSION] -p ['NetworkX: ' NetworkX::VERSION] -``` diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 8163b71..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: Feature Request -about: Suggest new NetworkX features or improvements to existing features. ---- - -## Is your feature request related to a problem? Please describe. - -## Describe the solution you'd like diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index aa0d752..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,12 +0,0 @@ -**Relevant Issues and PRs** -- (optional) - - -**Type of Change** -which type? - -- New feature -- Bug fix for existing feature -- Code quality improvement -- Addition or Improvement of tests -- Addition or Improvement of documentation diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 34e0996..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: test -on: [push, pull_request] -jobs: - build: - name: ${{ matrix.os }} Ruby ${{ matrix.ruby }} - runs-on: ${{ matrix.os }}-latest - strategy: - matrix: - os: [ 'ubuntu', 'macos' ] - ruby: [ '2.7', '3.0', '3.1', '3.2' ] - steps: - - uses: actions/checkout@v3 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby }} - bundler-cache: true - - run: bundle exec rspec diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml deleted file mode 100644 index c67fb6f..0000000 --- a/.github/workflows/doc.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: doc - -on: - push: - branches: - - main - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ruby - - name: Generate document - run: gem install -N yard && yard doc - - name: Publish Documentation on GitHub Pages - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./doc diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 5ac0efd..0000000 --- a/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -*.gem -.bundle/ -.yardoc/ -Gemfile.lock -/_yardoc/ -*.DS_store -.rspec_status -coverage/ -dump.rdb -doc/ -docs/ diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/.rspec b/.rspec deleted file mode 100644 index c99d2e7..0000000 --- a/.rspec +++ /dev/null @@ -1 +0,0 @@ ---require spec_helper diff --git a/.rubocop.yml b/.rubocop.yml deleted file mode 100644 index 18d0993..0000000 --- a/.rubocop.yml +++ /dev/null @@ -1,102 +0,0 @@ -AllCops: - NewCops: enable - TargetRubyVersion: 2.7 - Include: - - 'lib/**/*' - - 'spec/**/*_spec.rb' - - 'Gemfile' - - 'Rakefile' - - '*.gemspec' - DisplayCopNames: true - -require: - - rubocop-rspec - - rubocop-rake - -### Layouts ------------------------------------------------------------ - -Lint/AmbiguousOperatorPrecedence: - Enabled: false - -Layout/SpaceBeforeBlockBraces: - Enabled: false - -Layout/SpaceInsideBlockBraces: - Enabled: false - -Layout/SpaceInsideHashLiteralBraces: - EnforcedStyle: no_space - -### Metrics ------------------------------------------------------------ - -Metrics: - Enabled: false - -### Naming ------------------------------------------------------------- - -Naming/MethodParameterName: - Enabled: false - -Naming/PredicateName: - Enabled: false - -### Styles ------------------------------------------------------------- - -Style/CombinableLoops: - Enabled: false # there is case that it can't combined loop. - -Style/Documentation: - Enabled: false - -Style/FrozenStringLiteralComment: - Enabled: false - -Style/NumericPredicate: - Enabled: false # it is easier to read `size > 0` than `size.positive?` - -Style/OptionalBooleanParameter: - Enabled: false # it is necessary to change distructively. - -Style/ParallelAssignment: - Enabled: false # one line style is compact. - -Style/PreferredHashMethods: - Enabled: false - -Style/SymbolArray: - Enabled: false # general array literal is easy to read. no problem. - -Style/ZeroLengthPredicate: - Enabled: false # it is so easy to read `a.size > 0` as `!a.empty?` - -### RSpec -------------------------------------------------------------- - -RSpec/MessageSpies: - EnforcedStyle: receive - -RSpec/DescribedClass: - Enabled: false - -RSpec/ExampleLength: - Max: 25 - -RSpec/FilePath: - Enabled: false # too many offense - -RSpec/ImplicitSubject: - Enabled: false # too many offenses - -RSpec/MultipleExpectations: - Max: 15 - -RSpec/NestedGroups: - Max: 5 - -RSpec/PredicateMatcher: - Enabled: false - -RSpec/RepeatedExampleGroupBody: - Enabled: false - -RSpec/RepeatedExampleGroupDescription: - Enabled: false # too many offenses diff --git a/.yardopts b/.yardopts deleted file mode 100644 index 29c933b..0000000 --- a/.yardopts +++ /dev/null @@ -1 +0,0 @@ ---markup markdown diff --git a/Array.html b/Array.html new file mode 100644 index 0000000..ac6d1f8 --- /dev/null +++ b/Array.html @@ -0,0 +1,127 @@ + + +
+ + ++ + + + + Classes: CurrentEdge, DiGraph, GlobalRelabelThreshold, Graph, Level, MultiDiGraph, MultiGraph, UnionFind + + +
+ + +'0.4.0'.freeze
Returns the flowdict of the graph.
+Returns the residual graph of the given graph.
+Detects the unboundedness in the residual graph.
+Helper function to move a node from inactive set to active set.
+Finds shortest weighted paths and lengths between all nodes.
+Finds shortest weighted paths between all nodes.
+Finds shortest weighted path length between all nodes.
+Computes shortest paths to all nodes from all nodes.
+Computes shortest path values to all nodes from all nodes.
+Shortest paths between all nodes using Bellman Ford algorithm.
+Shortest path lengths between all nodes using Bellman Ford algorithm.
+Returns the ancestors of a given node.
+Helper function to return an arbitrary element from an iterable object.
+Returns path using astar algorithm between source and target.
+Returns astar path length b/w source and target.
+Helper function to augment the flow in a residual graph.
+Computes authority matrix for the graph.
+Shortest path from source to target using Bellman Ford algorithm.
+Length of shortest path from source to target using Bellman Ford algorithm.
+Finds shortest weighted path lengths and predecessors on shortest paths.
+Returns edges of the graph travelled in breadth first fashion.
+Returns predecessor child pair of the graph travelled in breadth first fashion.
+Returns parent successor pair of the graph travelled in breadth first fashion.
+Helper function for the bidirectional bfs.
+Bridges.
+Build flow dictionary of a graph from its residual graph.
+Builds a residual graph from a constituent graph.
+Computes max flow using capacity scaling algorithm.
+Returns the cartesian product of two graphs.
+Returns the closeness vitality of a node.
+Performs the complement operation on the graph.
+Performs the composition of two graphs.
+Performs the composition of many graphs.
+Transforms the labels of the nodes of the graphs so that they are disjoint.
+Returns whether the given undirected cycle has cycle.
+Returns all basis cycles in graph.
+Returns the descendants of a given node.
+Detects unboundedness in a graph, raises exception when infinite capacity flow is found.
+Returns edges of the graph travelled in depth first fashion.
+Returns predecessor child pair of the graph travelled in depth first fashion.
+Returns parent successor pair of the graph travelled in depth first fashion.
+Returns dfs tree of the graph.
+Returns the diameter of a graph.
+Performs the difference of two graphs.
+Computes shortest path to target from the given node.
+Computes shortest path length to target from the given node.
+Computes weighted shortest path length and predecessors.
+Returns the product of directed edges with edges.
+Helper function for discharging a node.
+Performs the disjoint union of two graphs.
+Performs the disjoint union of many graphs.
+Helper function to get distances.
+Returns the eccentricity of a particular node or all nodes.
+Performs edge dfs on the graph Orientation :ignore, directed edges can be travelled in both fashions Orientation reverse, directed edges can be travelled in reverse fashion Orientation :nil, the graph is not meddled with.
+Helper function of edge_dfs.
+Returns the product of edges with edges.
+Returns the product of edges with pairs of nodes.
+Returns the edges of the graph in an array.
+Computes max flow using edmonds karp algorithm.
+Core helper function for the EdmondsKarp algorithm.
+Helper function for the edmondskarp function.
+Returns all cliques in the graph.
+Returns the cycle containing the given node.
+Returns the all pair distance between all the nodes.
+Helper function for applying gap heuristic.
+Returns a label for unique node.
+Returns the edges of the graph in an array.
+Helper function for the minimum spanning tree.
+Helper function to get sources.
+Helper function to extract weight from a adjecency hash.
+Helper function for global relabel heuristic.
+Saves the graph in a csv file.
+Returns a JSON object of the given graph.
+Returns the hash product of two hashes.
+Helper function for bellman ford.
+Helper function for single source dijkstra.
+Helper function for multisource dijkstra.
+Helper function for finding single source shortest path.
+Helper function for single source shortest path length.
+Computes hits and authority scores for all the graphs.
+Computes hub matrix for the graph.
+Initializes the product graph.
+Performs the intersection of two graphs.
+Performs the intersection of many graphs.
+Returns shortest path between all pairs of nodes.
+Returns a graph from the json encoded graph.
+Returns the lexicographic product of two graphs.
+Returns the maximal independent set of a graph.
+Returns the minimum spanning tree of a graph.
+Computes shortest paths and path lengths to a target from one of the nodes.
+Computes shortest paths to any from the given nodes.
+Computes shortest path lengths to any from the given nodes.
+Finds if there is a negative edge cycle in the graph.
+Returns the node product of nodes of two graphs.
+Returns the product of directed nodes with edges.
+The number of connected components on graph.
+The number of bridges.
+Returns the number of cliques in a graph containing a node.
+Helper function for edge_dfs.
+Computes pagerank values for the graph.
+Returns the specified power of the graph.
+Computes shortest paths to all nodes from all nodes.
+Computes max flow using preflow push algorithm.
+Helper function to apply the preflow push algorithm.
+Helper function for augmenting flow.
+Returns the radius of a graph.
+Helper function to relable a node to create a permissible edge.
+Helper function for reverse bfs.
+Helper function to set path lengths for Johnson algorithm.
+Computes max flow using shortest augmenting path algorithm.
+Helper function for running the shortest augmenting path algorithm.
+Computes single source shortest path from a node to every other node.
+Computes shortest path values to all nodes from a given node.
+Shortest path from source to all nodes using Bellman Ford algorithm.
+Shortest path length from source to all nodes using Bellman Ford algorithm.
+Computes shortest paths and path distances to all nodes/target from the given node.
+Computes shortest paths to all nodes from the given node.
+Computes shortest path lengths to all nodes from the given node.
+Returns the strong product of two graphs.
+Performs the symmetric difference of two graphs.
+Returns the tensor product of two graphs.
+Returns the nodes arranged in the topologically sorted fashion.
+Returns the product of undirected edges with edges.
+Performs the union of two graphs.
+Performs the union of many graphs.
+Returns the wiener index of the graph.
+Helper function for augmenting flow.
+Returns the flowdict of the graph
+ + +
+ + + +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119+ |
+
+ # File 'lib/networkx/flow/capacityscaling.rb', line 88 + +def self._build_flow_dict(graph, residual) + flow_dict = {} + inf = Float::INFINITY + + if graph.multigraph? + graph.nodes(data: true).each_key do |u| + flow_dict[u] = {} + graph.adj[u].each do |v, uv_edges| + flow_dict[u][v] = uv_edges.transform_values do |e| + u != v || (e[:capacity] || inf) <= 0 || (e[:weight] || 0) >= 0 ? 0 : e[:capacity] + end + end + residual.adj[u].each do |v, uv_edges| + flow_dict[u][v].merge!(uv_edges.to_h do |_, val| + [val[:temp_key][0], val[:flow]] if (val[:flow]).positive? + end) + end + end + else + graph.nodes(data: true).each_key do |u| + flow_dict[u] = graph.adj[u].to_h do |v, e| + [v, u != v || (e[:capacity] || inf) <= 0 || (e[:weight] || 0) >= 0 ? 0 : e[:capacity]] + end + merge_dict = {} + residual.adj[u].each do |v, uv_edges| + uv_edges.each_value { |attrs| merge_dict[v] = attrs[:flow] if (attrs[:flow]).positive? } + end + flow_dict[u].merge!(merge_dict) + end + end + flow_dict +end+ |
+
Returns the residual graph of the given graph
+ + +
+ + + +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85+ |
+
+ # File 'lib/networkx/flow/capacityscaling.rb', line 42 + +def self._build_residual_network(graph) + raise ArgumentError, 'Sum of demands should be 0!' \ + unless graph.nodes(data: true).values.map { |attr| attr[:demand] || 0 }.sum.zero? + + residual = NetworkX::MultiDiGraph.new(inf: 0) + residual.add_nodes(graph.nodes(data: true).map { |u, attr| [u, {excess: (attr[:demand] || 0) * -1, potential: 0}] }) + inf = Float::INFINITY + edge_list = [] + + # TODO: Selfloop edges check + + if graph.multigraph? + graph.adj.each do |u, u_edges| + u_edges.each do |v, uv_edges| + uv_edges.each do |k, attrs| + edge_list << [u, v, k, e] if u != v && (attrs[:capacity] || inf).positive? + end + end + end + else + graph.adj.each do |u, u_edges| + u_edges.each do |v, attrs| + edge_list << [u, v, 0, attrs] if u != v && (attrs[:capacity] || inf).positive? + end + end + end + + temp_inf = [ + residual.nodes(data: true).map { |_u, attrs| attrs[:excess].abs }.sum, + edge_list.map {|_, _, _, e| (e.has_key?(:capacity) && e[:capacity] != inf ? e[:capacity] : 0) }.sum * 2 + ].max + + inf = temp_inf.zero? ? 1 : temp_inf + + edge_list.each do |u, v, k, e| + r = [e[:capacity] || inf, inf].min + w = e[:weight] || 0 + residual.add_edge(u, v, temp_key: [k, true], capacity: r, weight: w, flow: 0) + residual.add_edge(v, u, temp_key: [k, false], capacity: 0, weight: -w, flow: 0) + end + residual.graph[:inf] = inf + _detect_unboundedness(residual) + residual +end+ |
+
Detects the unboundedness in the residual graph
+ + +
+ + + +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39+ |
+
+ # File 'lib/networkx/flow/capacityscaling.rb', line 26 + +def self._detect_unboundedness(residual) + g = NetworkX::DiGraph.new + g.add_nodes(residual.nodes(data: true).keys.zip(residual.nodes(data: true).values)) + inf = residual.graph[:inf] + + residual.nodes(data: true).each do |u, _attr| + residual.adj[u].each do |v, uv_attrs| + w = inf + uv_attrs.each { |_key, edge_attrs| w = [w, edge_attrs[:weight]].min if edge_attrs[:capacity] == inf } + g.add_edge(u, v, weight: w) unless w == inf + end + end + raise ArgumentError, 'Negative cost cycle of infinite capacity found!' if negative_edge_cycle(g) +end+ |
+
Helper function to move a node from inactive set to active set
+ + +
+ + + +119 +120 +121 +122 +123 +124 +125 +126+ |
+
+ # File 'lib/networkx/flow/preflowpush.rb', line 119 + +def self.activate(node, source, target, levels, residual_nodes) + return if node == source || node == target + return unless level.inactive.include?(node) + + level = levels[residual_nodes[node][:height]] + level.inactive.delete(node) + level.active.add(node) +end+ |
+
Finds shortest weighted paths and lengths between all nodes
+ + +
+ + + +189 +190 +191 +192 +193+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 189 + +def self.all_pairs_dijkstra(graph, cutoff = nil) + path = [] + graph.nodes(data: true).each_key { |n| path << [n, singlesource_dijkstra(graph, n, nil, cutoff)] } + path +end+ |
+
Finds shortest weighted paths between all nodes
+ + +
+ + + +213 +214 +215 +216 +217+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 213 + +def self.all_pairs_dijkstra_path(graph, cutoff = nil) + paths = [] + graph.nodes(data: true).each_key { |n| paths << singlesource_dijkstra_path(graph, n, cutoff) } + paths +end+ |
+
Finds shortest weighted path length between all nodes
+ + +
+ + + +201 +202 +203 +204 +205+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 201 + +def self.all_pairs_dijkstra_path_length(graph, cutoff = nil) + path_lengths = [] + graph.nodes(data: true).each_key { |n| path_lengths << [n, singlesource_dijkstra_path_length(graph, n, cutoff)] } + path_lengths +end+ |
+
Computes shortest paths to all nodes from all nodes
+ + +
+ + + +94 +95 +96 +97 +98+ |
+
+ # File 'lib/networkx/shortest_path/unweighted.rb', line 94 + +def self.all_pairs_shortest_path(graph, cutoff = nil) + shortest_paths = [] + graph.nodes(data: true).each_key { |n| shortest_paths << [n, single_source_shortest_path(graph, n, cutoff)] } + shortest_paths +end+ |
+
Computes shortest path values to all nodes from all nodes
+ + +
+ + + +46 +47 +48 +49 +50+ |
+
+ # File 'lib/networkx/shortest_path/unweighted.rb', line 46 + +def self.all_pairs_shortest_path_length(graph, cutoff = nil) + shortest_paths = [] + graph.nodes(data: true).each_key { |n| shortest_paths << [n, single_source_shortest_path_length(graph, n, cutoff)] } + shortest_paths +end+ |
+
Shortest paths between all nodes using Bellman Ford algorithm
+ + +
+ + + +373 +374 +375 +376 +377+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 373 + +def self.allpairs_bellmanford_path(graph, cutoff = nil) + paths = [] + graph.nodes(data: true).each_key { |n| paths << [n, singlesource_bellmanford_path(graph, n, cutoff)] } + paths +end+ |
+
Shortest path lengths between all nodes using Bellman Ford algorithm
+ + +
+ + + +361 +362 +363 +364 +365+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 361 + +def self.allpairs_bellmanford_path_length(graph, cutoff = nil) + path_lengths = [] + graph.nodes(data: true).each_key { |n| path_lengths << [n, singlesource_bellmanford_path_length(graph, n, cutoff)] } + path_lengths +end+ |
+
Returns the ancestors of a given node
+ + +
+ + + +21 +22 +23 +24 +25 +26+ |
+
+ # File 'lib/networkx/auxillary_functions/dag.rb', line 21 + +def self.ancestors(graph, source) + raise ArgumentError, 'Source is not present in the graph!' unless graph.node?(source) + + anc = single_source_shortest_path_length(graph.reverse, source).map { |u, _| u }.uniq + anc - [source] +end+ |
+
Helper function to return an arbitrary element from an iterable object
+ + +
+ + + +3 +4 +5 +6 +7 +8 +9 +10 +11+ |
+
+ # File 'lib/networkx/flow/preflowpush.rb', line 3 + +def self.arbitrary_element(iterable) + if iterable.is_a?(Hash) + iterable.first[0] + elsif iterable.respond_to?(:first) + iterable.first + elsif iterable.respond_to?(:[]) + iterable[0] + end +end+ |
+
Returns path using astar algorithm between source and target
+ + +
+ + + +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55+ |
+
+ # File 'lib/networkx/shortest_path/astar.rb', line 11 + +def self.astar_path(graph, source, target, heuristic = nil) + warn 'A* is not implemented for MultiGraph and MultiDiGraph' if graph.is_a?(MultiGraph) || graph.is_a?(MultiDiGraph) + + raise ArgumentError, 'Either source or target is not in graph' unless graph.node?(source) && graph.node?(target) + + count = ->(i) { i + 1 } + i = -1 + heuristic ||= (->(_u, _v) { 0 }) + heap = Heap.new { |x, y| x[0] < y[0] || (x[0] == y[0] && x[1] < y[1]) } + heap << [0, count.call(i), source, 0, nil] + enqueued, explored = {}, {} + + until heap.empty? + _, _, curnode, dist, parent = heap.pop + if curnode == target + path = [curnode] + node = parent + until node.nil? + path << node + node = explored[node] + end + path.reverse + return path + end + + next if explored.has_key?(curnode) + + explored[curnode] = parent + + graph.adj[curnode].each do |u, attrs| + next if explored.has_key?(u) + + ncost = dist + (attrs[:weight] || 1) + if enqueued.has_key?(u) + qcost, = enqueued[u] + next if qcost <= ncost + else + h = heuristic.call(u, target) + enqueued[u] = ncost, h + heap << [ncost + h, count.call(i), u, ncost, curnode] + end + end + end + raise ArgumentError, 'Target not reachable!' +end+ |
+
Returns astar path length b/w source and target
+ + +
+ + + +65 +66 +67 +68 +69 +70 +71 +72+ |
+
+ # File 'lib/networkx/shortest_path/astar.rb', line 65 + +def self.astar_path_length(graph, source, target, heuristic = nil) + raise ArgumentError, 'Either source or target is not in graph' unless graph.node?(source) && graph.node?(target) + + path = astar_path(graph, source, target, heuristic) + path_length = 0 + (1..(path.length - 1)).each { |i| path_length += (graph.adj[path[i - 1]][path[i]][:weight] || 1) } + path_length +end+ |
+
Helper function to augment the flow in a residual graph
+ + +
+ + + +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20+ |
+
+ # File 'lib/networkx/flow/edmondskarp.rb', line 3 + +def self.augment(residual, inf, path) + flow = inf + path_first_elem = path.shift + u = path_first_elem + path.each do |v| + flow = [flow, residual.adj[u][v][:capacity] - residual.adj[u][v][:flow]].min + u = v + end + raise ArgumentError, 'Infinite capacity path!' if flow * 2 > inf + + u = path_first_elem + path.each do |v| + residual.adj[u][v][:flow] += flow + residual.adj[v][u][:flow] -= flow + u = v + end + flow +end+ |
+
Computes authority matrix for the graph
+ + +
+ + + +45 +46 +47 +48+ |
+
+ # File 'lib/networkx/link_analysis/hits.rb', line 45 + +def self.(graph) + matrix, = to_matrix(graph, 0) + matrix.transpose * matrix +end+ |
+
Shortest path from source to target using Bellman Ford algorithm
+ + +
+ + + +326 +327 +328 +329+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 326 + +def self.bellmanford_path(graph, source, target) + _, path = singlesource_bellmanford(graph, source, target) + path +end+ |
+
Length of shortest path from source to target using Bellman Ford algorithm
+ + +
+ + + +309 +310 +311 +312 +313 +314 +315 +316 +317+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 309 + +def self.bellmanford_path_length(graph, source, target) + return 0 if source == target + + weight = get_weight(graph) + length = help_bellman_ford(graph, [source], weight, nil, nil, nil, nil, target) + raise ArgumentError, 'Node not reachable!' unless length.has_key?(target) + + length[target] +end+ |
+
Finds shortest weighted path lengths and predecessors on shortest paths
+ + +
+ + + +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 277 + +def self.bellmanford_predecesor_distance(graph, source, target = nil, cutoff = nil) + raise ArgumentError, 'Node not found!' unless graph.node?(source) + + weight = get_weight(graph) + # TODO: Detection of selfloop edges + dist = {source => 0} + pred = {source => []} + return [pred, dist] if graph.nodes(data: true).length == 1 + + dist = help_bellman_ford(graph, [source], weight, pred, nil, dist, cutoff, target) + [pred, dist] +end+ |
+
Returns edges of the graph travelled in breadth first fashion
+ + +
+ + + +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26+ |
+
+ # File 'lib/networkx/traversals/bfs.rb', line 9 + +def self.bfs_edges(graph, source) + raise KeyError, "There exists no node names #{source} in the given graph." unless graph.node?(source) + + bfs_edges = [] + visited = [source] + queue = Queue.new.push([source, graph.neighbours(source)]) + until queue.empty? + parent, children = queue.pop + children.each_key do |child| + next if visited.include?(child) + + bfs_edges << [parent, child] + visited << child + queue.push([child, graph.neighbours(child)]) + end + end + bfs_edges +end+ |
+
Returns predecessor child pair of the graph travelled in breadth first fashion
+ + +
+ + + +52 +53 +54 +55 +56 +57+ |
+
+ # File 'lib/networkx/traversals/bfs.rb', line 52 + +def self.bfs_predecessors(graph, source) + bfs_edges = bfs_edges(graph, source) + predecessors = {} + bfs_edges.each { |u, v| predecessors[v] = u } + predecessors +end+ |
+
Returns parent successor pair of the graph travelled in breadth first fashion
+ + +
+ + + +35 +36 +37 +38 +39 +40 +41 +42 +43+ |
+
+ # File 'lib/networkx/traversals/bfs.rb', line 35 + +def self.bfs_successors(graph, source) + bfs_edges = bfs_edges(graph, source) + successors = {} + bfs_edges.each do |u, v| + successors[u] = [] if successors[u].nil? + successors[u] << v + end + successors +end+ |
+
Helper function for the bidirectional bfs
+ + +
+ + + +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58+ |
+
+ # File 'lib/networkx/flow/edmondskarp.rb', line 23 + +def self.bidirectional_bfs(residual, source, target) + pred, succ = {source => nil}, {target => nil} + q_s, q_t = [source], [target] + loop do + q = [] + if q_s.length <= q_t.length + q_s.each do |u| + residual.adj[u].each do |v, uv_attrs| + next unless !pred.include?(v) && (uv_attrs[:flow] < uv_attrs[:capacity]) + + pred[v] = u + return [v, pred, succ] if succ.has_key?(v) + + q << v + end + end + return [nil, nil, nil] if q.empty? + + q_s = q + else + q_t.each do |u| + residual.pred[u].each do |v, uv_attrs| + next unless !succ.has_key?(v) && uv_attrs[:flow] < uv_attrs[:capacity] + + succ[v] = u + return [v, pred, succ] if pred.has_key?(v) + + q << v + end + end + return [nil, nil, nil] if q.empty? + + q_t = q + end + end +end+ |
+
Returns bridges.
+ + +
+ + + +7 +8 +9+ |
+
+ # File 'lib/networkx/others/bridges.rb', line 7 + +def self.bridges(graph) + each_bridge(graph).to_a +end+ |
+
Build flow dictionary of a graph from its residual graph
+ + +
+ + + +130 +131 +132 +133 +134 +135 +136 +137 +138+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 130 + +def self.build_flow_dict(graph, residual) + flow_dict = {} + graph.edges.each do |u, u_edges| + flow_dict[u] = {} + u_edges.each_key { |v| flow_dict[u][v] = 0 } + u_edges.each_key { |v| flow_dict[u][v] = residual[u][v][:flow] if (residual[u][v][:flow]).positive? } + end + flow_dict +end+ |
+
Builds a residual graph from a constituent graph
+ + +
+ + + +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 61 + +def self.build_residual_network(graph) + raise NotImplementedError, 'MultiGraph and MultiDiGraph not supported!' if graph.multigraph? + + r_network = NetworkX::DiGraph.new(inf: 0, flow_value: 0) + r_network.add_nodes(graph.nodes(data: true).keys) + inf = Float::INFINITY + edge_list = [] + + graph.adj.each do |u, u_edges| + u_edges.each do |v, uv_attrs| + edge_list << [u, v, uv_attrs] if (uv_attrs[:capacity] || inf).positive? && u != v + end + end + + inf_chk = 3 * edge_list.inject(0) do |result, arr| + arr[2].has_key?(:capacity) && arr[2][:capacity] != inf ? (result + arr[2][:capacity]) : result + end + inf = inf_chk.zero? ? 1 : inf_chk + + if graph.directed? + edge_list.each do |u, v, attrs| + r = [attrs[:capacity] || inf, inf].min + if r_network.adj[u][v].nil? + r_network.add_edge(u, v, capacity: r) + r_network.add_edge(v, u, capacity: 0) + else + r_network[u][v][:capacity] = r + end + end + else + edge_list.each do |u, v, attrs| + r = [attrs[:capacity] || inf, inf].min + r_network.add_edge(u, v, capacity: r) + r_network.add_edge(v, u, capacity: r) + end + end + r_network.graph[:inf] = inf + r_network +end+ |
+
Computes max flow using capacity scaling algorithm
+ + +
+ + + +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250+ |
+
+ # File 'lib/networkx/flow/capacityscaling.rb', line 127 + +def self.capacity_scaling(graph) + residual = _build_residual_network(graph) + inf = Float::INFINITY + flow_cost = 0 + + # TODO: Account cost of self-loof edges + + wmax = ([-inf] + residual.adj.each_with_object([]) do |u, arr| + u[1].each { |_, key_attrs| key_attrs.each { |_, attrs| arr << attrs[:capacity] } } + end).max + + return flow_cost, _build_flow_dict(graph, residual) if wmax == -inf + + r_nodes = residual.nodes + r_adj = residual.adj + + delta = 2**Math.log2(wmax).floor + while delta >= 1 + r_nodes.each do |u, u_attrs| + p_u = u_attrs[:potential] + r_adj[u].each do |v, uv_edges| + uv_edges.each do |_k, e| + flow = e[:capacity] + next unless (e[:weight] - p_u + r_nodes[v][:potential]).negative? + + flow = e[:capacity] - e[:flow] + next unless flow >= delta + + e[:flow] += flow + r_adj[v][u].each_key do |val| + val[:flow] += val[:temp_key][0] == e[:temp_key][0] && val[:temp_key][1] != e[:temp_key][1] ? -flow : 0 + end + r_nodes[u][:excess] -= flow + r_nodes[v][:excess] += flow + end + end + end + + s_set = Set.new + t_set = Set.new + + residual.nodes(data: true).each do |u, _attrs| + excess = r_nodes[u][:excess] + if excess >= delta + s_set.add(u) + elsif excess <= -delta + t_set.add(u) + end + end + + while !s_set.empty? && !t_set.empty? + s = arbitrary_element + t = nil + d = {} + pred = {s => nil} + h = Heap.new { |x, y| x[0] < y[0] || (x[0] == y[0] && x[1] < y[1]) } + h_dict = {s => 0} + h << [0, count, s] + until h.empty? + d_u, _, u = h.pop + h_dict.delete(u) + d[u] = d_u + if t_set.include?(u) + t = u + break + end + p_u = r_nodes[u][:potential] + r_adj[u].each do |v, uv_edges| + next if d.has_key?(v) + + wmin = inf + uv_edges.each_value do |e| + next unless e[:capacity] - e[:flow] >= delta + + w = e[:weight] + next unless w < wmin + + wmin = w + end + next if wmin == inf + + d_v = d_u + wmin - p_u + r_nodes[v][:potential] + next unless h_dict[v] > d_v + + h << [d_v, count, v] + h_dict[v] = d_v + pred[v] = [u, kmin, emin] + end + end + + if t.nil? + s_set.delete(s) + else + while u != s + v = u + u, k, e = pred[v] + e[:flow] += delta + r_adj[v][u].each_key do |val| + val[:flow] += val[:temp_key][0] == k[0] && val[:temp_key][1] != k[1] ? -delta : 0 + end + end + r_nodes[s][:excess] -= delta + r_nodes[t][:excess] += delta + s_set.delete(s) if r_nodes[s][:excess] < delta + t_set.delete(t) if r_nodes[t][:excess] > -delta + d_t = d[t] + d.each { |node, d_u_node| r_nodes[node][:potential] -= (d_u_node - d_t) } + end + end + delta = (delta / 2).floor + end + + r_nodes.each_value { |attrs| raise ArgumentError, 'No flow satisfying all demands!' if attrs[:excess] != 0 } + + residual.nodes(data: true).each_key do |node| + residual.adj[node].each_value do |uv_edges| + uv_edges.each_value do |k_attrs| + flow = k_attrs[:flow] + flow_cost += (flow * k_attrs[:weight]) + end + end + end + [flow_cost, _build_flow_dict(graph, residual)] +end+ |
+
Returns the cartesian product of two graphs
+ + +
+ + + +129 +130 +131 +132 +133 +134 +135+ |
+
+ # File 'lib/networkx/operators/product.rb', line 129 + +def self.cartesian_product(g1, g2) + g = init_product_graph(g1, g2) + g.add_nodes(node_product(g1, g2)) + g.add_edges(edges_cross_nodes(g1, g2)) + g.add_edges(nodes_cross_edges(g1, g2)) + g +end+ |
+
Returns the closeness vitality of a node
+ + +
+ + + +8 +9 +10 +11 +12+ |
+
+ # File 'lib/networkx/auxillary_functions/vitality.rb', line 8 + +def self.closeness_vitality(graph, node) + before = wiener_index(graph) + after = wiener_index(graph.subgraph(graph.nodes(data: true).keys - [node])) + before - after +end+ |
+
Performs the complement operation on the graph
+ + +
+ + + +7 +8 +9 +10 +11 +12 +13 +14 +15 +16+ |
+
+ # File 'lib/networkx/operators/unary.rb', line 7 + +def self.complement(graph) + result = Marshal.load(Marshal.dump(graph)) + result.clear + + result.add_nodes(graph.nodes(data: true).map { |u, attrs| [u, attrs] }) + graph.adj.each do |u, u_edges| + graph.nodes(data: true).each { |v, attrs| result.add_edge(u, v, **attrs) if !u_edges.has_key?(v) && u != v } + end + result +end+ |
+
Performs the composition of two graphs
+ + +
+ + + +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189+ |
+
+ # File 'lib/networkx/operators/binary.rb', line 173 + +def self.compose(g1, g2) + result = g1.class.new + + raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph? + + result.add_nodes(g1.nodes(data: true).map { |u, attrs| [u, attrs] }) + result.add_nodes(g2.nodes(data: true).map { |u, attrs| [u, attrs] }) + + if g1.multigraph? + g1.adj.each { |u, e| e.each { |v, uv_edges| uv_edges.each_value { |attrs| result.add_edge(u, v, **attrs) } } } + g2.adj.each { |u, e| e.each { |v, uv_edges| uv_edges.each_value { |attrs| result.add_edge(u, v, **attrs) } } } + else + g1.adj.each { |u, u_edges| u_edges.each { |v, attrs| result.add_edge(u, v, **attrs) } } + g2.adj.each { |u, u_edges| u_edges.each { |v, attrs| result.add_edge(u, v, **attrs) } } + end + result +end+ |
+
Performs the composition of many graphs
+ + +
+ + + +55 +56 +57 +58 +59 +60 +61 +62 +63 +64+ |
+
+ # File 'lib/networkx/operators/all.rb', line 55 + +def self.compose_all(graphs) + raise ArgumentError, 'Argument array is empty' if graphs.empty? + + result = graphs.shift + + graphs.each do |graph| + result = NetworkX.compose(result, graph) + end + result +end+ |
+
Transforms the labels of the nodes of the graphs so that they are disjoint.
+ + +
+ + + +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51+ |
+
+ # File 'lib/networkx/operators/binary.rb', line 27 + +def self.convert_to_distinct_labels(graph, starting_int = -1) + new_graph = graph.class.new + + idx_dict = graph.nodes(data: true).keys.to_h do |v| + starting_int += 1 + [v, starting_int] + end + + graph.nodes(data: true).each do |u, attrs| + new_graph.add_node(u.to_s + idx_dict[u].to_s, **attrs) + end + + graph.adj.each do |u, u_edges| + u_edges.each do |v, uv_attrs| + if graph.multigraph? + uv_attrs.each do |_k, attrs| + new_graph.add_edge(u.to_s + idx_dict[u].to_s, v.to_s + idx_dict[v].to_s, **attrs) + end + else + new_graph.add_edge(u.to_s + idx_dict[u].to_s, v.to_s + idx_dict[v].to_s, **uv_attrs) + end + end + end + new_graph +end+ |
+
Returns whether the given undirected cycle has cycle.
+ + +
+ + + +107 +108 +109 +110 +111 +112 +113+ |
+
+ # File 'lib/networkx/auxillary_functions/cycles.rb', line 107 + +def self.cycle?(undirected_graph) + uf = NetworkX::UnionFind.new + undirected_graph.edges.each do |x, y| + uf[x] == uf[y] ? (return [x, y]) : uf.unite(x, y) + end + false +end+ |
+
Returns all basis cycles in graph
+ + +
+ + + +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45+ |
+
+ # File 'lib/networkx/auxillary_functions/cycles.rb', line 8 + +def self.cycle_basis(graph, root = nil) + gnodes = graph.nodes(data: true).keys + cycles = [] + until gnodes.empty? + root = gnodes.shift if root.nil? + stack = [root] + pred = {root => root} + used = {root => []} + until stack.empty? + z = stack.shift + zused = used[z] + graph.adj[z].each_key do |u| + if !used.has_key?(u) + pred[u] = z + stack << u + used[u] = [z] + elsif u == z + cycles << [z] + elsif !zused.include?(u) + pn = used[u] + cycle = [u, z] + p = pred[z] + until pn.include?(p) + cycle << p + p = pred[p] + end + cycle << p + cycles << cycle + used[u] << z + used[u] = used[u].uniq + end + end + end + gnodes -= pred.keys + root = nil + end + cycles +end+ |
+
Returns the descendants of a given node
+ + +
+ + + +8 +9 +10 +11 +12 +13+ |
+
+ # File 'lib/networkx/auxillary_functions/dag.rb', line 8 + +def self.descendants(graph, source) + raise ArgumentError, 'Source is not present in the graph!' unless graph.node?(source) + + des = single_source_shortest_path_length(graph, source).map { |u, _| u }.uniq + des - [source] +end+ |
+
Detects unboundedness in a graph, raises exception when infinite capacity flow is found
+ + +
+ + + +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 107 + +def self.detect_unboundedness(r_network, source, target) + q = [source] + seen = Set.new([source]) + inf = r_network.graph[:inf] + until q.empty? + u = q.shift + r_network.adj[u].each do |v, uv_attrs| + next unless uv_attrs[:capacity] == inf && !seen.include?(v) + raise ArgumentError, 'Infinite capacity flow!' if v == target + + seen << v + q << v + end + end +end+ |
+
Returns edges of the graph travelled in depth first fashion
+ + +
+ + + +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30+ |
+
+ # File 'lib/networkx/traversals/dfs.rb', line 10 + +def self.dfs_edges(graph, source, depth_limit = nil) + raise KeyError, "There exists no node names #{source} in the given graph." unless graph.node?(source) + + depth_limit += 1 if depth_limit + depth_limit = graph.nodes(data: true).length if depth_limit.nil? + dfs_edges = [] + visited = [source] + stack = [[-1, source, depth_limit, graph.neighbours(source)]] + until stack.empty? + earlier_node, parent, depth_now, children = stack.pop + dfs_edges << [earlier_node, parent] + children.each_key do |child| + unless visited.include?(child) + visited << child + stack.push([parent, child, depth_now - 1, graph.neighbours(child)]) if depth_now > 1 + end + end + end + dfs_edges.shift + dfs_edges +end+ |
+
Returns predecessor child pair of the graph travelled in depth first fashion
+ + +
+ + + +73 +74 +75 +76 +77 +78+ |
+
+ # File 'lib/networkx/traversals/dfs.rb', line 73 + +def self.dfs_predecessors(graph, source, depth_limit = nil) + dfs_edges = dfs_edges(graph, source, depth_limit) + predecessors = {} + dfs_edges.each { |u, v| predecessors[v] = u } + predecessors +end+ |
+
Returns parent successor pair of the graph travelled in depth first fashion
+ + +
+ + + +55 +56 +57 +58 +59 +60 +61 +62 +63+ |
+
+ # File 'lib/networkx/traversals/dfs.rb', line 55 + +def self.dfs_successors(graph, source, depth_limit = nil) + dfs_edges = dfs_edges(graph, source, depth_limit) + successors = {} + dfs_edges.each do |u, v| + successors[u] = [] if successors[u].nil? + successors[u] << v + end + successors +end+ |
+
Returns dfs tree of the graph
+ + +
+ + + +40 +41 +42 +43 +44 +45+ |
+
+ # File 'lib/networkx/traversals/dfs.rb', line 40 + +def self.dfs_tree(graph, source, depth_limit = nil) + t = NetworkX::DiGraph.new + t.add_node(source) + t.add_edges_from(dfs_edges(graph, source, depth_limit)) + t +end+ |
+
Returns the diameter of a graph
+ + +
+ + + +25 +26 +27+ |
+
+ # File 'lib/networkx/auxillary_functions/eccentricity.rb', line 25 + +def self.diameter(graph) + eccentricity(graph).values.max +end+ |
+
Performs the difference of two graphs
+ + +
+ + + +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118+ |
+
+ # File 'lib/networkx/operators/binary.rb', line 93 + +def self.difference(g1, g2) + result = g1.class.new + + raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph? + + unless (g1.nodes(data: true).keys - g2.nodes(data: true).keys).empty? + raise ArgumentError, 'Node sets must be equal!' + end + + g1.nodes(data: true).each { |u, attrs| result.add_node(u, **attrs) } + + g1.adj.each do |u, u_edges| + u_edges.each do |v, uv_attrs| + if g1.multigraph? + next if u > v && g1.instance_of?(MultiGraph) + + uv_attrs.each do |k, attrs| + result.add_edge(u, v, **attrs) unless g2.edge?(u, v, k) + end + else + result.add_edge(u, v, **uv_attrs) unless g2.edge?(u, v) + end + end + end + result +end+ |
+
Computes shortest path to target from the given node
+ + +
+ + + +163 +164 +165 +166+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 163 + +def self.dijkstra_path(graph, source, target) + _, path = singlesource_dijkstra(graph, source, target) + path +end+ |
+
Computes shortest path length to target from the given node
+ + +
+ + + +146 +147 +148 +149 +150 +151 +152 +153 +154+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 146 + +def self.dijkstra_path_length(graph, source, target) + return 0 if source == target + + weight = get_weight(graph) + length = help_dijkstra(graph, source, weight, nil, nil, nil, target) + raise KeyError, 'Node not reachable!' unless length.has_key?(target) + + length[target] +end+ |
+
Computes weighted shortest path length and predecessors
+ + +
+ + + +176 +177 +178 +179 +180+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 176 + +def self.dijkstra_predecessor_distance(graph, source, cutoff = nil) + weight = get_weight(graph) + pred = {source => []} + [pred, help_dijkstra(graph, source, weight, pred, nil, cutoff)] +end+ |
+
Returns the product of directed edges with edges
+ + +
+ + + +40 +41 +42 +43 +44 +45 +46 +47 +48+ |
+
+ # File 'lib/networkx/operators/product.rb', line 40 + +def self.directed_edges_cross_edges(g1, g2) + result = [] + edges_in_array(g1).each do |u, v, c| + edges_in_array(g2).each do |x, y, d| + result << [[u, x], [v, y], hash_product(c, d)] + end + end + result +end+ |
+
Helper function for discharging a node
+ + +
+ + + +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165+ |
+
+ # File 'lib/networkx/flow/preflowpush.rb', line 135 + +def self.discharge(u_node, is_phase1, residual_nodes, residual_adj, height, levels, grt, source, target) + height_val = residual_nodes[u_node][:height] + curr_edge = residual_nodes[u_node][:curr_edge] + next_height = height_val + levels[height_val].active.delete(u_node) + + loop do + v, attr = curr_edge.get + if height_val == residual_nodes[v][:height] + 1 && attr[:flow] < attr[:capacity] + flow = [residual_nodes[u_node][:excess], attr[:capacity] - attr[:flow]].min + push(u_node, v, flow, residual_nodes, residual_adj) + activate(v, source, target, levels, residual_nodes) + if residual_nodes[u_node][:excess].zero? + levels[height_val].inactive.add(u_node) + break + end + end + begin + curr_edge.move_to_next + rescue StopIteration + height_val = relabel(u_node, grt, residual_adj, residual_nodes, source, target, levels) + if is_phase1 && height_val >= n - 1 + levels[height].active.add(u_node) + break + end + next_height = height_val + end + end + residual_nodes[u_node][:height] = height_val + next_height +end+ |
+
Performs the disjoint union of two graphs
+ + +
+ + + +225 +226 +227 +228 +229 +230 +231 +232+ |
+
+ # File 'lib/networkx/operators/binary.rb', line 225 + +def self.disjoint_union(g1, g2) + new_g1 = convert_to_distinct_labels(g1) + new_g2 = convert_to_distinct_labels(g2) + result = union(new_g1, new_g2) + result.graph.merge!(g1.graph) + result.graph.merge!(g2.graph) + result +end+ |
+
Performs the disjoint union of many graphs
+ + +
+ + + +23 +24 +25 +26 +27 +28 +29 +30 +31 +32+ |
+
+ # File 'lib/networkx/operators/all.rb', line 23 + +def self.disjoint_union_all(graphs) + raise ArgumentError, 'Argument array is empty' if graphs.empty? + + result = graphs.shift + + graphs.each do |graph| + result = NetworkX.disjoint_union(result, graph) + end + result +end+ |
+
Helper function to get distances
+ + +
+ + + +385 +386 +387 +388 +389 +390 +391+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 385 + +def self.dist_path_lambda(_graph, _new_weight) + lambda do |graph, v, new_weight| + paths = {v => [v]} + _ = help_dijkstra(graph, v, new_weight, nil, paths) + paths + end +end+ |
+
+ + + +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22+ |
+
+ # File 'lib/networkx/others/bridges.rb', line 12 + +def self.each_bridge(graph) + return enum_for(:each_bridge, graph) unless block_given? + + graph.each_edge.with_index do |(s_i, t_i), i| + uf = UnionFind.new(1..graph.number_of_nodes) + graph.each_edge.with_index do |(s_j, t_j), j| + uf.unite(s_j, t_j) if i != j + end + yield [s_i, t_i] unless uf.same?(s_i, t_i) + end +end+ |
+
Returns the eccentricity of a particular node or all nodes
+ + +
+ + + +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18+ |
+
+ # File 'lib/networkx/auxillary_functions/eccentricity.rb', line 8 + +def self.eccentricity(graph, node = nil) + e = {} + graph.nodes(data: true).each do |u, _| + length = single_source_shortest_path_length(graph, u) + l = length.length + raise ArgumentError, 'Found infinite path length!' unless l == graph.nodes(data: true).length + + e[u] = length.max_by { |a| a[1] }[1] + end + node.nil? ? e : e[node] +end+ |
+
Performs edge dfs on the graph Orientation :ignore, directed edges can be travelled in both fashions Orientation reverse, directed edges can be travelled in reverse fashion Orientation :nil, the graph is not meddled with
+ + +
+ + + +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86+ |
+
+ # File 'lib/networkx/traversals/edge_dfs.rb', line 51 + +def self.edge_dfs(graph, start, orientation = nil) + case orientation + when :reverse + graph = graph.reverse if graph.instance_of?(::NetworkX::DiGraph) || graph.instance_of?(::NetworkX::MultiDiGraph) + when :ignore + graph = graph.to_undirected if graph.instance_of?(::NetworkX::DiGraph) + graph = graph.to_multigraph if graph.instance_of?(::NetworkX::MultiDiGraph) + end + + visited_edges = [] + visited_nodes = [] + stack = [start] + current_edges = {} + + e = Enumerator.new do |yield_var| + until stack.empty? + current = stack.last + unless visited_nodes.include?(current) + current_edges[current] = out_edges(graph, current) + visited_nodes << current + end + + edge = current_edges[current].shift + if edge.nil? + stack.pop + else + unless visited_edges.include?(edge_id(graph, edge)) + visited_edges << edge_id(graph, edge) + stack << edge[1] + yield_var.yield edge + end + end + end + end + e.take(graph.number_of_edges) +end+ |
+
Helper function of edge_dfs
+ + +
+ + + +31 +32 +33 +34 +35 +36+ |
+
+ # File 'lib/networkx/traversals/edge_dfs.rb', line 31 + +def self.edge_id(graph, edge) + return edge if graph.directed? + return Set.new([edge, (edge[0..1].reverse << edge[2])]) if graph.multigraph? + + Set.new([edge, edge.reverse]) +end+ |
+
Returns the product of edges with edges
+ + +
+ + + +62 +63 +64 +65 +66 +67 +68 +69 +70+ |
+
+ # File 'lib/networkx/operators/product.rb', line 62 + +def self.edges_cross_nodes(g1, g2) + result = [] + edges_in_array(g1).each do |u, v, d| + g2.nodes(data: true).each_key do |x| + result << [[u, x], [v, x], d] + end + end + result +end+ |
+
Returns the product of edges with pairs of nodes
+ + +
+ + + +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94+ |
+
+ # File 'lib/networkx/operators/product.rb', line 84 + +def self.edges_cross_nodes_and_nodes(g1, g2) + result = [] + edges_in_array(g1).each do |u, v, d| + g2.nodes(data: true).each_key do |x| + g2.nodes(data: true).each_key do |y| + result << [[u, x], [v, y], d] + end + end + end + result +end+ |
+
Returns the edges of the graph in an array
+ + +
+ + + +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21+ |
+
+ # File 'lib/networkx/operators/product.rb', line 3 + +def self.edges_in_array(graph) + edge_array = [] + if graph.multigraph? + graph.adj.each do |u, u_edges| + u_edges.each do |v, uv_edges| + uv_edges.each do |_k, attrs| + edge_array << [u, v, attrs] + end + end + end + else + graph.adj.each do |u, u_edges| + u_edges.each do |v, attrs| + edge_array << [u, v, attrs] + end + end + end + edge_array +end+ |
+
Computes max flow using edmonds karp algorithm
+ + +
+ + + +112 +113 +114+ |
+
+ # File 'lib/networkx/flow/edmondskarp.rb', line 112 + +def self.edmondskarp(graph, source, target, residual = nil, cutoff = nil) + edmondskarp_impl(graph, source, target, residual, cutoff) +end+ |
+
Core helper function for the EdmondsKarp algorithm
+ + +
+ + + +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83+ |
+
+ # File 'lib/networkx/flow/edmondskarp.rb', line 61 + +def self.edmondskarp_core(residual, source, target, cutoff) + inf = residual.graph[:inf] + flow_val = 0 + while flow_val < cutoff + v, pred, succ = bidirectional_bfs(residual, source, target) + break if pred.nil? + + path = [v] + u = v + while u != source + u = pred[u] + path << u + end + path.reverse! + u = v + while u != target + u = succ[u] + path << u + end + flow_val += augment(residual, inf, path) + end + flow_val +end+ |
+
Helper function for the edmondskarp function
+ + +
+ + + +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101+ |
+
+ # File 'lib/networkx/flow/edmondskarp.rb', line 86 + +def self.edmondskarp_impl(graph, source, target, residual, cutoff) + raise ArgumentError, 'Source not in graph!' unless graph.nodes(data: true).has_key?(source) + raise ArgumentError, 'Target not in graph!' unless graph.nodes(data: true).has_key?(target) + raise ArgumentError, 'Source and target are same node!' if source == target + + res_graph = residual.nil? ? build_residual_network(graph) : residual.clone + res_graph.adj.each do |u, u_edges| + u_edges.each do |v, _attrs| + res_graph.adj[u][v][:flow] = 0 + res_graph.pred[v][u][:flow] = 0 + end + end + cutoff = Float::INFINITY if cutoff.nil? + res_graph.graph[:flow_value] = edmondskarp_core(res_graph, source, target, cutoff) + res_graph +end+ |
+
Returns all cliques in the graph
+ + +
+ + + +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50+ |
+
+ # File 'lib/networkx/auxillary_functions/cliques.rb', line 7 + +def self.find_cliques(graph) + return nil if graph.nodes(data: true).empty? + + q = [nil] + adj = {} + graph.nodes(data: true).each_key { |u| adj[u] = [] } + graph.adj.each { |u, u_edges| u_edges.each_key { |v| adj[u] << v if u != v } } + + subg = graph.nodes(data: true).keys + cand = graph.nodes(data: true).keys + u = subg.max { |n1, n2| (cand & adj[n1]).length <=> (cand & adj[n2]).length } + ext_u = cand - adj[u] + stack = [] + cliques = [] + begin + loop do + if ext_u.empty? + q.pop + subg, cand, ext_u = stack.pop + else + q_elem = ext_u.pop + cand.delete(q_elem) + q[-1] = q_elem + adj_q = adj[q_elem] + subg_q = subg & adj_q + if subg_q.empty? + cliques << q[0..(q.length - 1)] + else + cand_q = cand & adj_q + unless cand_q.empty? + stack << [subg, cand, ext_u] + q << nil + subg = subg_q + cand = cand_q + u = subg.max { |n1, n2| (cand & adj[n1]).length <=> (cand & adj[n2]).length } + ext_u = cand - adj[u] + end + end + end + end + rescue NoMethodError + cliques + end +end+ |
+
Returns the cycle containing the given node
+ + +
+ + + +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100+ |
+
+ # File 'lib/networkx/auxillary_functions/cycles.rb', line 53 + +def self.find_cycle(graph, node) + explored = Set.new + cycle = [] + final_node = nil + unless explored.include?(node) + edges = [] + seen = [node] + active_nodes = [node] + previous_head = nil + + edge_dfs(graph, node).each do |edge| + tail, head = edge + next if explored.include?(head) + + if !previous_head.nil? && tail != previous_head + loop do + popped_edge = edges.pop + if popped_edge.nil? + edges = [] + active_nodes = [tail] + break + else + popped_head = popped_edge[1] + active_nodes.delete(popped_head) + end + + unless edges.empty? + last_head = edges[-1][1] + break if tail == last_head + end + end + end + edges << edge + + if active_nodes.include?(head) + cycle += edges + final_node = head + break + else + seen << head + active_nodes << head + previous_head = head + end + end + cycle.each_with_index { |edge, i| return cycle[i..(cycle.length - 1)] if final_node == edge[0] } + end + raise ArgumentError, 'No cycle found!' if cycle.empty? +end+ |
+
Returns the all pair distance between all the nodes
+ + +
+ + + +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28+ |
+
+ # File 'lib/networkx/shortest_path/dense.rb', line 8 + +def self.floyd_warshall(graph) + a, index = to_matrix(graph, Float::INFINITY, 'min') + nodelen = graph.nodes(data: true).length + (0..(nodelen - 1)).each { |i| a[i, i] = 0 } + (0..(nodelen - 1)).each do |k| + (0..(nodelen - 1)).each do |i| + (0..(nodelen - 1)).each do |j| + a[i, j] = [a[i, j], a[i, k] + a[k, j]].min + end + end + end + + as_hash = {} + (0..(nodelen - 1)).each do |i| + (0..(nodelen - 1)).each do |j| + as_hash[index[i]] = {} unless as_hash.has_key?(index[i]) + as_hash[index[i]][index[j]] = a[i, j] + end + end + as_hash +end+ |
+
Helper function for applying gap heuristic
+ + +
+ + + +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178+ |
+
+ # File 'lib/networkx/flow/preflowpush.rb', line 168 + +def self.gap_heuristic(height, levels, residual_nodes) + ((height + 1)..(max_height)).each do |idx| + level = levels[idx] + level.active.each { |u| residual_nodes[u][:height] = n + 1 } + level.inactive.each { |u| residual_nodes[u][:height] = n + 1 } + levels[n + 1].active.merge!(level.active) + level.active.clear + levels[n + 1].inactive.merge!(level.inactive) + level.inactive.clear + end +end+ |
+
Returns a label for unique node
+ + +
+ + + +3 +4 +5+ |
+
+ # File 'lib/networkx/flow/capacityscaling.rb', line 3 + +def self.generate_unique_node + SecureRandom.uuid +end+ |
+
Returns the edges of the graph in an array
+ + +
+ + + +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23+ |
+
+ # File 'lib/networkx/operators/binary.rb', line 3 + +def self.get_edges(graph) + edges = [] + if graph.is_a?(MultiGraph) + graph.adj.each do |u, v_keys| + v_keys.each do |v, key_attrs| + next if u > v + + key_attrs.each do |_key, attributes| + edges << [u, v, attributes] + end + end + end + else + graph.adj.each do |u, u_attrs| + u_attrs.each do |v, uv_attrs| + edges << [u, v, uv_attrs] + end + end + end + edges +end+ |
+
Helper function for the minimum spanning tree
+ + +
+ + + +4 +5 +6 +7 +8 +9 +10 +11 +12+ |
+
+ # File 'lib/networkx/auxillary_functions/mst.rb', line 4 + +def self.get_edges_weights(graph) + edges = [] + graph.adj.each do |u, u_edges| + u_edges.each do |v, uv_attrs| + edges << [[u, v], uv_attrs[:weight] || Float::INFINITY] + end + end + edges +end+ |
+
Helper function to get sources
+ + +
+ + + +380 +381 +382+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 380 + +def self.get_sources(graph) + graph.nodes(data: true).collect { |k, _v| k } +end+ |
+
Helper function to extract weight from a adjecency hash
+ + +
+ + + +3 +4 +5 +6 +7 +8 +9+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 3 + +def self.get_weight(graph) + lambda do |_, _, attrs| + return attrs[:weight] || 1 unless graph.multigraph? + + attrs.group_by { |_k, vals| vals[:weight] || 1 }.keys.max + end +end+ |
+
Helper function for global relabel heuristic
+ + +
+ + + +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207+ |
+
+ # File 'lib/networkx/flow/preflowpush.rb', line 181 + +def self.global_relabel(from_sink, source, target, residual_nodes, num, levels, residual_pred) + src = from_sink ? target : source + heights = reverse_bfs(src, residual_pred) + heights.delete(target) unless from_sink + max_height = heights.values.max + if from_sink + residual_nodes.each { |u, attr| heights[u] = num + 1 if !heights.has_key?(u) && attr[:height] < num } + else + heights.each_key { |u| heights[u] += num } + max_height += num + end + heights.delete(src) + heights.each do |u, new_height| + old_height = residual_nodes[u][:height] + next unless new_height != old_height + + if levels[old_height].active.include?(u) + levels[old_height].active.delete(u) + levels[new_height].active.add(u) + else + levels[old_height].inactive.delete(u) + levels[new_height].inactive.add(u) + end + residual_nodes[u][:height] = new_height + end + max_height +end+ |
+
Saves the graph in a csv file
+ + +
+ + + +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44+ |
+
+ # File 'lib/networkx/converters/to_csv.rb', line 6 + +def self.graph_to_csv(graph, filename = 'graph.csv') + CSV.open(filename, 'wb') do |csv| + csv << [graph.class.name] + csv << ['graph_values'] + csv << graph.graph.keys + csv << graph.graph.values + csv << ['graph_nodes'] + graph.nodes(data: true).each do |u, attrs| + node_attrs = [u] + attrs.each do |k, v| + node_attrs << k + node_attrs << v + end + csv << node_attrs + end + csv << ['graph_edges'] + graph.adj.each do |u, u_edges| + u_edges.each do |v, uv_attrs| + if graph.multigraph? + uv_attrs.each do |key, attrs| + node_attrs = [u, v, key] + attrs.each do |k, k_attrs| + node_attrs << k + node_attrs << k_attrs + end + csv << node_attrs + end + else + node_attrs = [u, v] + uv_attrs.each do |k, vals| + node_attrs << k + node_attrs << vals + end + csv << node_attrs + end + end + end + end +end+ |
+
Returns a JSON object of the given graph
+ + +
+ + + +7 +8 +9 +10 +11 +12 +13 +14+ |
+
+ # File 'lib/networkx/converters/to_json.rb', line 7 + +def self.graph_to_json(graph) + json_hash = {} + json_hash[:class] = graph.class.name + json_hash[:graph] = graph.graph + json_hash[:nodes] = graph.nodes + json_hash[:adj] = graph.adj + json_hash.to_json +end+ |
+
+ + + +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37+ |
+
+ # File 'lib/networkx/others/grid_2d_graph.rb', line 12 + +def self.grid_2d_graph(m, n, periodic: false, create_using: NetworkX::Graph) + warn('sorry, periodic is not done yet') if periodic + + m.is_a?(Integer) or raise(ArgumentError, "[NetworkX] argument m: Integer, not #{m.class}") + n.is_a?(Integer) or raise(ArgumentError, "[NetworkX] argument n: Integer, not #{n.class}") + create_using.is_a?(Class) \ + or raise(ArgumentError, "[NetworkX] argument create_using: `Graph` class or children, not #{create_using.class}") + + g = create_using.new + + a = [] + m.times { |i| n.times { |j| a << [i, j] } } + g.add_nodes_from(a) + + e1 = [] + (m - 1).times { |i| n.times { |j| e1 << [[i, j], [i + 1, j]] } } + g.add_edges_from(e1) + + e2 = [] + m.times { |i| (n - 1).times { |j| e2 << [[i, j], [i, j + 1]] } } + g.add_edges_from(e2) + + g.add_edges_from(g.edges.map { |i, j| [j, i] }) if g.directed? + + g +end+ |
+
Returns the hash product of two hashes
+ + +
+ + + +24 +25 +26+ |
+
+ # File 'lib/networkx/operators/product.rb', line 24 + +def self.hash_product(hash1, hash2) + (hash1.keys | hash2.keys).to_h { |n| [n, [hash1[n], hash2[n]]] } +end+ |
+
Helper function for bellman ford
+ + +
+ + + +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 220 + +def self.help_bellman_ford(graph, sources, weight, pred = nil, paths = nil, dist = nil, cutoff = nil, target = nil) + pred = sources.product([[]]).to_h if pred.nil? + dist = sources.product([0]).to_h if dist.nil? + + inf, n, count, q, in_q = Float::INFINITY, graph.nodes(data: true).length, {}, sources.clone, Set.new(sources) + until q.empty? + u = q.shift + in_q.delete(u) + skip = false + pred[u].each { |k| skip = true if in_q.include?(k) } + next if skip + + dist_u = dist[u] + graph.adj[u].each do |v, e| + dist_v = dist_u + weight.call(u, v, e) + next if !cutoff.nil? && dist_v > cutoff + next if !target.nil? && dist_v > (dist[target] || inf) + + if dist_v < (dist[v] || inf) + unless in_q.include?(v) + q << v + in_q.add(v) + count_v = (count[v] || 0) + 1 + raise ArgumentError, 'Negative edge cycle detected!' if count_v == n + + count[v] = count_v + end + dist[v] = dist_v + pred[v] = [u] + elsif dist.has_key?(v) && dist_v == dist[v] + pred[v] << u + end + end + end + unless paths.nil? + dsts = pred + dsts.each_key do |dst| + path, cur = [dst], dst + until pred[cur][0].nil? + cur = pred[cur][0] + path << cur + end + path.reverse + paths[dst] = path + end + end + dist +end+ |
+
Helper function for single source dijkstra
+ + +
+ + + +53 +54 +55+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 53 + +def self.help_dijkstra(graph, source, weight, pred = nil, paths = nil, cutoff = nil, target = nil) + help_multisource_dijkstra(graph, [source], weight, pred, paths, cutoff, target) +end+ |
+
Helper function for multisource dijkstra
+ + +
+ + + +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 12 + +def self.help_multisource_dijkstra(graph, sources, weight, pred = nil, paths = nil, cutoff = nil, target = nil) + count = ->(i) { i + 1 } + i = -1 + dist = {} + seen = {} + fringe = Heap.new { |x, y| x[0] < y[0] || (x[0] == y[0] && x[1] < y[1]) } + sources.each do |s| + seen[s] = 0 + fringe << [0, count.call(i), s] + end + + until fringe.empty? + d, _, v = fringe.pop + next if dist.has_key?(v) + + dist[v] = d + break if v == target + + graph.adj[v].each do |u, attrs| + cost = weight.call(v, u, attrs) + next if cost.nil? + + vu_dist = dist[v] + cost + next if !cutoff.nil? && vu_dist > cutoff + + if dist.has_key?(u) + raise ValueError, 'Contradictory weights found!' if vu_dist < dist[u] + elsif !seen.has_key?(u) || vu_dist < seen[u] + seen[u] = vu_dist + fringe << [vu_dist, count.call(i), u] + paths[u] = paths[v] + [u] unless paths.nil? + pred[u] = [v] unless pred.nil? + elsif vu_dist == seen[u] + pred[u] << v unless pred.nil? + end + end + end + dist +end+ |
+
Helper function for finding single source shortest path
+ + +
+ + + +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70+ |
+
+ # File 'lib/networkx/shortest_path/unweighted.rb', line 53 + +def self.help_single_shortest_path(adj, firstlevel, paths, cutoff) + level = 0 + nextlevel = firstlevel + while !nextlevel.empty? && cutoff > level + thislevel = nextlevel + nextlevel = {} + thislevel.each_key do |u| + adj[u].each_key do |v| + unless paths.has_key?(v) + paths[v] = paths[u] + [v] + nextlevel[v] = 1 + end + end + end + level += 1 + end + paths +end+ |
+
Helper function for single source shortest path length
+ + +
+ + + +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23+ |
+
+ # File 'lib/networkx/shortest_path/unweighted.rb', line 3 + +def self.help_single_shortest_path_length(adj, firstlevel, cutoff) + Enumerator.new do |e| + seen = {} + level = 0 + nextlevel = firstlevel + + while !nextlevel.empty? && cutoff >= level + thislevel = nextlevel + nextlevel = {} + thislevel.each do |u, _attrs| + next if seen.has_key?(u) + + seen[u] = level + nextlevel.merge!(adj[u]) + e.yield [u, level] + end + level += 1 + end + seen.clear + end +end+ |
+
Computes hits and authority scores for all the graphs
+ + +
+ + + +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38+ |
+
+ # File 'lib/networkx/link_analysis/hits.rb', line 10 + +def self.hits(graph, max_iter = 100, tol = 1e-8, nstart) + return [{}, {}] if graph.nodes(data: true).empty? + + h = nstart + sum = h.values.sum + h.each_key { |k| h[k] /= (sum * 1.0) } + i = 0 + a = {} + + loop do + hlast = Marshal.load(Marshal.dump(h)) + h, a = {}, {} + hlast.each do |k, _v| + h[k] = 0 + a[k] = 0 + end + h.each_key { |k| graph.adj[k].each { |nbr, attrs| a[k] += hlast[nbr] * (attrs[:weight] || 1) } } + h.each_key { |k| graph.adj[k].each { |nbr, attrs| h[k] += a[nbr] * (attrs[:weight] || 1) } } + smax = h.values.max + h.each_key { |k| h[k] /= smax } + smax = a.values.max + a.each_key { |k| a[k] /= smax } + break if h.keys.map { |k| (h[k] - hlast[k]).abs }.sum < tol + raise ArgumentError, 'Power Iteration failed to converge!' if i > max_iter + + i += 1 + end + [h, a] +end+ |
+
Computes hub matrix for the graph
+ + +
+ + + +55 +56 +57 +58+ |
+
+ # File 'lib/networkx/link_analysis/hits.rb', line 55 + +def self.hub_matrix(graph) + matrix, = to_matrix(graph, 0) + matrix * matrix.transpose +end+ |
+
+ + + +4 +5 +6 +7 +8 +9 +10+ |
+
+ # File 'lib/networkx/others/info.rb', line 4 + +def self.info(graph) + info = '' + info << "Type: #{graph.class}\n" + info << "Number of nodes: #{graph.number_of_nodes}\n" + info << "Number of edges: #{graph.number_of_edges}\n" + info +end+ |
+
Initializes the product graph
+ + +
+ + + +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107+ |
+
+ # File 'lib/networkx/operators/product.rb', line 97 + +def self.init_product_graph(g1, g2) + raise ArgumentError, 'Arguments must be both directed or undirected!' unless g1.directed? == g2.directed? + + g = if g1.multigraph? || g2.multigraph? + NetworkX::MultiGraph.new + else + NetworkX::Graph.new + end + g = g.to_directed if g.directed? + g +end+ |
+
Performs the intersection of two graphs
+ + +
+ + + +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85+ |
+
+ # File 'lib/networkx/operators/binary.rb', line 59 + +def self.intersection(g1, g2) + result = g1.class.new + + raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph? + + unless (g1.nodes(data: true).keys - g2.nodes(data: true).keys).empty? + raise ArgumentError, 'Node sets must be equal!' + end + + g1.nodes(data: true).each { |u, attrs| result.add_node(u, **attrs) } + + g1, g2 = g2, g1 if g1.number_of_edges > g2.number_of_edges + g1.adj.each do |u, u_edges| + u_edges.each do |v, uv_attrs| + if g1.multigraph? + next if u > v && g1.instance_of?(MultiGraph) + + uv_attrs.each do |k, attrs| + result.add_edge(u, v, **attrs) if g2.edge?(u, v, k) + end + elsif g2.edge?(u, v) + result.add_edge(u, v, **uv_attrs) + end + end + end + result +end+ |
+
Performs the intersection of many graphs
+ + +
+ + + +39 +40 +41 +42 +43 +44 +45 +46 +47 +48+ |
+
+ # File 'lib/networkx/operators/all.rb', line 39 + +def self.intersection_all(graphs) + raise ArgumentError, 'Argument array is empty' if graphs.empty? + + result = graphs.shift + + graphs.each do |graph| + result = NetworkX.intersection(result, graph) + end + result +end+ |
+
Returns shortest path between all pairs of nodes
+ + +
+ + + +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 405 + +def self.johnson(graph) + dist, pred = {}, {} + sources = get_sources(graph) + graph.nodes(data: true).each_key do |n| + dist[n], pred[n] = 0, [] + end + weight = get_weight(graph) + dist_bellman = help_bellman_ford(graph, sources, weight, pred, nil, dist) + new_weight = ->(u, v, d) { weight.call(u, v, d) + dist_bellman[u] - dist_bellman[v] } + dist_path = dist_path_lambda(graph, new_weight) + set_path_lengths_johnson(graph, dist_path, new_weight) +end+ |
+
Returns a graph from the json encoded graph
+ + +
+ + + +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36+ |
+
+ # File 'lib/networkx/converters/to_json.rb', line 21 + +def self.json_to_graph(json_str) + graph_hash = JSON.parse(json_str) + case json_str['class'] + when 'NetworkX::Graph' + graph = NetworkX::Graph.new(graph_hash.graph) + when 'NetworkX::MultiGraph' + graph = NetworkX::MultiGraph.new(graph_hash.graph) + when 'NetworkX::DiGraph' + graph = NetworkX::DiGraph.new(graph_hash.graph) + when 'NetworkX::MultiDiGraph' + graph = NetworkX::MultiDiGraph.new(graph_hash.graph) + end + graph.adj = graph_hash['adj'] + graph.nodes = graph_hash['nodes'] + graph +end+ |
+
Returns the lexicographic product of two graphs
+ + +
+ + + +143 +144 +145 +146 +147 +148 +149+ |
+
+ # File 'lib/networkx/operators/product.rb', line 143 + +def self.lexicographic_product(g1, g2) + g = init_product_graph(g1, g2) + g.add_nodes(node_product(g1, g2)) + g.add_edges(edges_cross_nodes_and_nodes(g1, g2)) + g.add_edges(nodes_cross_edges(g1, g2)) + g +end+ |
+
Returns the maximal independent set of a graph
+ + +
+ + + +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24+ |
+
+ # File 'lib/networkx/auxillary_functions/mis.rb', line 8 + +def self.maximal_independent_set(graph, nodes) + if (graph.nodes(data: true).keys - nodes).empty? + raise 'The array containing the nodes should be a subset of the graph!' + end + + neighbours = [] + nodes.each { |u| graph.adj[u].each { |v, _| neighbours |= [v] } } + raise 'Nodes is not an independent set of graph!' if (neighbours - nodes).empty? + + available_nodes = graph.nodes(data: true).keys - (neighbours | nodes) + until available_nodes.empty? + node = available_nodes.sample + nodes << node + available_nodes -= (graph.adj[node].keys + [node]) + end + nodes +end+ |
+
Returns the minimum spanning tree of a graph
+ + +
+ + + +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32+ |
+
+ # File 'lib/networkx/auxillary_functions/mst.rb', line 19 + +def self.minimum_spanning_tree(graph) + mst = Marshal.load(Marshal.dump(graph)) + mst.clear + edges = get_edges_weights(graph).sort_by { |a| a[1] } + union_find = UnionFind.new(graph.nodes(data: true).keys) + while edges.any? && mst.nodes(data: true).length <= graph.nodes(data: true).length + edge = edges.shift + unless union_find.connected?(edge[0][0], edge[0][1]) + union_find.union(edge[0][0], edge[0][1]) + mst.add_edge(edge[0][0], edge[0][1], **graph.adj[edge[0][0]][edge[0][1]]) + end + end + mst +end+ |
+
Computes shortest paths and path lengths to a target from one of the nodes
+ + +
+ + + +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 65 + +def self.multisource_dijkstra(graph, sources, target = nil, cutoff = nil) + raise ValueError, 'Sources cannot be empty' if sources.empty? + return [0, [target]] if sources.include?(target) + + paths = {} + weight = get_weight(graph) + sources.each { |source| paths[source] = [source] } + dist = help_multisource_dijkstra(graph, sources, weight, nil, paths, cutoff, target) + return [dist, paths] if target.nil? + raise KeyError, "No path to #{target}!" unless dist.has_key?(target) + + [dist[target], paths[target]] +end+ |
+
Computes shortest paths to any from the given nodes
+ + +
+ + + +100 +101 +102 +103+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 100 + +def self.multisource_dijkstra_path(graph, sources, cutoff = nil) + _, path = multisource_dijkstra(graph, sources, nil, cutoff) + path +end+ |
+
Computes shortest path lengths to any from the given nodes
+ + +
+ + + +86 +87 +88 +89 +90 +91+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 86 + +def self.multisource_dijkstra_path_length(graph, sources, cutoff = nil) + raise ValueError, 'Sources cannot be empty' if sources.empty? + + weight = get_weight(graph) + help_multisource_dijkstra(graph, sources, weight, nil, nil, cutoff) +end+ |
+
Finds if there is a negative edge cycle in the graph
+ + +
+ + + +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23+ |
+
+ # File 'lib/networkx/flow/capacityscaling.rb', line 12 + +def self.negative_edge_cycle(graph) + newnode = generate_unique_node + graph.add_edges(graph.nodes(data: true).keys.map { |n| [newnode, n] }) + begin + bellmanford_predecesor_distance(graph, newnode) + rescue ArgumentError + return true + ensure + graph.remove_node(newnode) + end + false +end+ |
+
Returns the node product of nodes of two graphs
+ + +
+ + + +29 +30 +31 +32 +33 +34 +35 +36 +37+ |
+
+ # File 'lib/networkx/operators/product.rb', line 29 + +def self.node_product(g1, g2) + n_product = [] + g1.nodes(data: true).each do |k1, attrs1| + g2.nodes(data: true).each do |k2, attrs2| + n_product << [[k1, k2], hash_product(attrs1, attrs2)] + end + end + n_product +end+ |
+
Returns the product of directed nodes with edges
+ + +
+ + + +73 +74 +75 +76 +77 +78 +79 +80 +81+ |
+
+ # File 'lib/networkx/operators/product.rb', line 73 + +def self.nodes_cross_edges(g1, g2) + result = [] + g1.nodes(data: true).each_key do |x| + edges_in_array(g2).each do |u, v, d| + result << [[x, u], [x, v], d] + end + end + result +end+ |
+
Returns the number of connected components on graph.
+ + +
+ + + +8 +9 +10 +11 +12+ |
+
+ # File 'lib/networkx/others/number_connected_components.rb', line 8 + +def self.number_connected_components(graph) + uf = NetworkX::UnionFind.new(graph.nodes(data: false)) + graph.each_edge { |x, y| uf.unite(x, y) } + uf.groups.size +end+ |
+
Returns the number of bridges.
+ + +
+ + + +27 +28 +29+ |
+
+ # File 'lib/networkx/others/bridges.rb', line 27 + +def self.number_of_bridges(graph) + bridges(graph).size +end+ |
+
Returns the number of cliques in a graph containing a node
+ + +
+ + + +58 +59 +60 +61+ |
+
+ # File 'lib/networkx/auxillary_functions/cliques.rb', line 58 + +def self.number_of_cliques(graph, node) + cliques = find_cliques(graph) + cliques.count { |c| c.include?(node) } +end+ |
+
Helper function for edge_dfs
+ + +
+ + + +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28+ |
+
+ # File 'lib/networkx/traversals/edge_dfs.rb', line 6 + +def self.out_edges(graph, node) + edges = [] + visited = {} + case graph.class.name + when 'NetworkX::Graph', 'NetworkX::DiGraph' + graph.adj[node].each do |v, _| + if graph.instance_of?(::NetworkX::DiGraph) || visited[[v, node]].nil? + visited[[node, v]] = true + edges << [node, v] + end + end + else + graph.adj[node].each do |v, uv_keys| + uv_keys.each_key do |k| + if graph.instance_of?(::NetworkX::MultiDiGraph) || visited[[v, node, k]].nil? + visited[[node, v, k]] = true + edges << [node, v, k] + end + end + end + end + edges +end+ |
+
Computes pagerank values for the graph
+ + +
+ + + +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44+ |
+
+ # File 'lib/networkx/link_analysis/pagerank.rb', line 10 + +def self.pagerank(graph, alpha: 0.85, personalization: nil, eps: 1e-6, max_iter: 100) + n = graph.number_of_nodes + + matrix, index_to_node = NetworkX.to_matrix(graph, 0) + + index_from_node = index_to_node.invert + + probabilities = Array.new(n) do |i| + total = matrix.row(i).sum + (matrix.row(i) / total.to_f).to_a + end + + curr = personalization + unless curr + curr = Array.new(n) + graph.each_node{|node| curr[index_from_node[node]] = 1.0 / n } + end + + max_iter.times do + prev = curr.clone + + n.times do |i| + ip = 0.0 + n.times do |j| + ip += probabilities[j][i] * prev[j] + end + curr[i] = (alpha * ip) + ((1.0 - alpha) / n * 1.0) + end + + err = (0...n).map{|i| (prev[i] - curr[i]).abs }.sum + return (0...n).map{|i| [index_to_node[i], curr[i]] }.sort.to_h if err < eps + end + warn "pagerank() failed within #{max_iter} iterations. Please inclease max_iter: or loosen eps:" + (0...n).map{|i| [index_to_node[i], curr[i]] }.sort.to_h +end+ |
+
Returns the specified power of the graph
+ + +
+ + + +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200+ |
+
+ # File 'lib/networkx/operators/product.rb', line 173 + +def self.power(graph, pow) + raise ArgumentError, 'Power must be a positive quantity!' if pow <= 0 + + result = NetworkX::Graph.new + result.add_nodes(graph.nodes(data: true).map { |n, attrs| [n, attrs] }) + graph.nodes(data: true).each do |n, _attrs| + seen = {} + level = 1 + next_level = graph.adj[n] + until next_level.empty? + this_level = next_level + next_level = {} + this_level.each do |v, _attrs| + next if v == n + + unless seen.has_key?(v) + seen[v] = level + next_level.merge!(graph.adj[v]) + end + end + break if pow <= level + + level += 1 + end + result.add_edges(seen.map { |v, _| [n, v] }) + end + result +end+ |
+
Computes shortest paths to all nodes from all nodes
+ + +
+ + + +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135+ |
+
+ # File 'lib/networkx/shortest_path/unweighted.rb', line 110 + +def self.predecessor(graph, source, cutoff = nil, return_seen = false) + raise ArgumentError, 'Source not found in the Graph!' unless graph.node?(source) + + level = 0 + nextlevel = [source] + seen = {source => level} + pred = {source => []} + until nextlevel.empty? + level += 1 + thislevel = nextlevel + nextlevel = [] + thislevel.each do |u| + graph.adj[u].each_key do |v| + if !seen.has_key?(v) + pred[v] = [u] + seen[v] = level + nextlevel << v + elsif seen[v] == level + pred[v] << u + end + end + end + break if cutoff.nil? && cutoff <= level + end + return_seen ? [pred, seen] : pred +end+ |
+
Computes max flow using preflow push algorithm
+ + +
+ + + +246 +247 +248+ |
+
+ # File 'lib/networkx/flow/preflowpush.rb', line 246 + +def self.preflowpush(graph, source, target, residual = nil, globalrelabel_freq = 1, value_only = false) + preflowpush_impl(graph, source, target, residual, globalrelabel_freq, value_only) +end+ |
+
Helper function to apply the preflow push algorithm
+ + +
+ + + +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116+ |
+
+ # File 'lib/networkx/flow/preflowpush.rb', line 14 + +def self.preflowpush_impl(graph, source, target, residual, globalrelabel_freq, value_only) + raise ArgumentError, 'Source not in graph!' unless graph.nodes(data: true).has_key?(source) + raise ArgumentError, 'Target not in graph!' unless graph.nodes(data: true).has_key?(target) + raise ArgumentError, 'Source and Target are same!' if source == target + + globalrelabel_freq = 0 if globalrelabel_freq.nil? + raise ArgumentError, 'Global Relabel Freq must be nonnegative!' if globalrelabel_freq.negative? + + r_network = residual.nil? ? build_residual_network(graph) : residual + detect_unboundedness(r_network, source, target) + + residual_nodes = r_network.nodes + residual_adj = r_network.adj + residual_pred = r_network.pred + + residual_nodes.each do |u, u_attrs| + u_attrs[:excess] = 0 + residual_adj[u].each { |_v, attrs| attrs[:flow] = 0 } + end + + heights = reverse_bfs(target, residual_pred) + + unless heights.has_key?(source) + r_network.graph[:flow_value] = 0 + return r_network + end + + n = r_network.nodes(data: true).length + max_height = heights.map { |u, h| u == source ? -1 : h }.max + heights[source] = n + + grt = GlobalRelabelThreshold.new(n, r_network.size, globalrelabel_freq) + + residual_nodes.each do |u, u_attrs| + u_attrs[:height] = heights.has_key?(u) ? heights[u] : (n + 1) + u_attrs[:curr_edge] = CurrentEdge.new(residual_adj[u]) + end + + residual_adj[source].each do |u, attr| + flow = attr[:capacity] + push(source, u, flow, residual_nodes, residual_adj) if flow.positive? + end + + levels = (0..((2 * n) - 1)).map { |_| Level.new } + residual_nodes.each do |u, attr| + if u != source && u != target + level = levels[attr[:height]] + (residual_nodes[u][:excess]).positive? ? level.active.add(u) : level.inactive.add(u) + end + end + + height = max_height + while height.positive? + loop do + level = levels[height] + if level.active.empty? + height -= 1 + break + end + old_height = height + old_level = level + u = arbitrary_element(level.active) + height = discharge(u, true, residual_nodes, residual_adj, height, levels, grt, source, target) + if grt.reached? + height = global_relabel(true, source, target, residual_nodes, n, levels, residual_pred) + max_height = height + grt.clear_work + elsif old_level.active.empty? && old_level.inactive.empty? + gap_heuristic(old_height, levels, residual_nodes) + height = old_height - 1 + max_height = height + else + max_height = [max_height, height].max + end + end + end + + if value_only + r_network.graph[:flow_value] = residual_nodes[target][:excess] + return r_network + end + + height = global_relabel(false, source, target, residual_nodes, n, levels, residual_pred) + grt.clear_work + + while height > n + loop do + level = levels[height] + if level.active.empty? + height -= 1 + break + end + u = arbitrary_element(level.active) + height = discharge(u, false, residual_nodes, residual_adj, height, levels, grt, source, target) + if grt.reached? + height = global_relabel(false, source, target, residual_nodes, n, levels, residual_pred) + grt.clear_work + end + end + end + r_network.graph[:flow_value] = residual_nodes[target][:excess] + r_network +end+ |
+
Helper function for augmenting flow
+ + +
+ + + +210 +211 +212 +213 +214 +215+ |
+
+ # File 'lib/networkx/flow/preflowpush.rb', line 210 + +def self.push(node1, node2, flow, residual_nodes, residual_adj) + residual_adj[node1][node2][:flow] += flow + residual_adj[node2][node1][:flow] -= flow + residual_nodes[node1][:excess] -= flow + residual_nodes[node2][:excess] += flow +end+ |
+
Returns the radius of a graph
+ + +
+ + + +34 +35 +36+ |
+
+ # File 'lib/networkx/auxillary_functions/eccentricity.rb', line 34 + +def self.radius(graph) + eccentricity(graph).values.min +end+ |
+
Helper function to relable a node to create a permissible edge
+ + +
+ + + +129 +130 +131 +132+ |
+
+ # File 'lib/networkx/flow/preflowpush.rb', line 129 + +def self.relabel(u_node, grt, r_adj, _r_nodes, _source, _target, _levels) + grt.add_work(r_adj[u_node].length) + r_adj[u_node].map { |v, attr| attr[:flow] < (attr[:capacity] + 1) ? _nodes[v][:height] : Float::INFINITY }.min +end+ |
+
Helper function for reverse bfs
+ + +
+ + + +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233+ |
+
+ # File 'lib/networkx/flow/preflowpush.rb', line 218 + +def self.reverse_bfs(src, residual_pred) + heights = {src => 0} + q = [[src, 0]] + + until q.empty? + u, height = q.shift + height += 1 + residual_pred[u].each do |v, attr| + if !heights.has_key?(v) && attr[:flow] < attr[:capacity] + heights[v] = height + q << [v, height] + end + end + end + heights +end+ |
+
Helper function to set path lengths for Johnson algorithm
+ + +
+ + + +394 +395 +396 +397 +398+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 394 + +def self.set_path_lengths_johnson(graph, dist_path, new_weight) + path_lengths = [] + graph.nodes(data: true).each_key { |n| path_lengths << [n, dist_path.call(graph, n, new_weight)] } + path_lengths +end+ |
+
Computes max flow using shortest augmenting path algorithm
+ + +
+ + + +149 +150 +151 +152 +153+ |
+
+ # File 'lib/networkx/flow/shortestaugmentingpath.rb', line 149 + +def self.shortest_augmenting_path(graph, source, target, residual = nil, \ + _value_only = false, two_phase = false, cutoff = nil) + + shortest_augmenting_path_impl(graph, source, target, residual, two_phase, cutoff) +end+ |
+
Helper function for running the shortest augmenting path algorithm
+ + +
+ + + +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105+ |
+
+ # File 'lib/networkx/flow/shortestaugmentingpath.rb', line 3 + +def self.shortest_augmenting_path_impl(graph, source, target, residual, two_phase, cutoff) + raise ArgumentError, 'Source is not in the graph!' unless graph.nodes(data: true).has_key?(source) + raise ArgumentError, 'Target is not in the graph!' unless graph.nodes(data: true).has_key?(target) + raise ArgumentError, 'Source and Target are the same!' if source == target + + residual = residual.nil? ? build_residual_network(graph) : residual + r_nodes = residual.nodes + r_pred = residual.pred + r_adj = residual.adj + + r_adj.each_value do |u_edges| + u_edges.each_value do |attrs| + attrs[:flow] = 0 + end + end + + heights = {target => 0} + q = [[target, 0]] + + until q.empty? + u, height = q.shift + height += 1 + r_pred[u].each do |v, attrs| + if !heights.has_key?(v) && attrs[:flow] < attrs[:capacity] + heights[v] = height + q << [v, height] + end + end + end + + unless heights.has_key?(source) + residual.graph[:flow_value] = 0 + return residual + end + + n = graph.nodes(data: true).length + m = residual.size / 2 + + r_nodes.each do |node, attrs| + attrs[:height] = heights.has_key?(node) ? heights[node] : n + attrs[:curr_edge] = CurrentEdge.new(r_adj[node]) + end + + counts = [0] * (2 * n - 1) + r_nodes.each_value { |attrs| counts[attrs[:height]] += 1 } + inf = graph.graph[:inf] + + cutoff = Float::INFINITY if cutoff.nil? + flow_value = 0 + path = [source] + u = source + d = two_phase ? n : [m**0.5, 2 * (n**(2./ 3))].min.floor + done = r_nodes[source][:height] >= d + + until done + height = r_nodes[u][:height] + curr_edge = r_nodes[u][:curr_edge] + + loop do + v, attr = curr_edge.get + if height == r_nodes[v][:height] + 1 && attr[:flow] < attr[:capacity] + path << v + u = v + break + end + begin + curr_edge.move_to_next + rescue StopIteration + if counts[height].zero? + residual.graph[:flow_value] = flow_value + return residual + end + height = relabel(u, n, r_adj, r_nodes) + if u == source && height >= d + if two_phase + done = true + break + else + residual.graph[:flow_value] = flow_value + return residual + end + end + counts[height] += 1 + r_nodes[u][:height] = height + unless u == source + path.pop + u = path[-1] + break + end + end + end + next unless u == target + + flow_value += augment(path, inf, r_adj) + if flow_value >= cutoff + residual.graph[:flow_value] = flow_value + return residual + end + end + flow_value += edmondskarp_core(residual, source, target, cutoff - flow_value) + residual.graph[:flow_value] = flow_value + residual +end+ |
+
Computes single source shortest path from a node to every other node
+ + +
+ + + +79 +80 +81 +82 +83 +84 +85 +86+ |
+
+ # File 'lib/networkx/shortest_path/unweighted.rb', line 79 + +def self.single_source_shortest_path(graph, source, cutoff = nil) + raise ArgumentError, 'Source not found in the Graph!' unless graph.node?(source) + + cutoff = Float::INFINITY if cutoff.nil? + nextlevel = {source => 1} + paths = {source => [source]} + help_single_shortest_path(graph.adj, nextlevel, paths, cutoff) +end+ |
+
Computes shortest path values to all nodes from a given node
+ + +
+ + + +32 +33 +34 +35 +36 +37 +38+ |
+
+ # File 'lib/networkx/shortest_path/unweighted.rb', line 32 + +def self.single_source_shortest_path_length(graph, source, cutoff = nil) + raise ArgumentError, 'Source not found in the Graph!' unless graph.node?(source) + + cutoff = Float::INFINITY if cutoff.nil? + nextlevel = {source => 1} + help_single_shortest_path_length(graph.adj, nextlevel, cutoff).take(graph.nodes(data: true).length) +end+ |
+
+ + + +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 290 + +def self.singlesource_bellmanford(graph, source, target = nil, cutoff = nil) + return [0, [source]] if source == target + + weight = get_weight(graph) + paths = {source => [source]} + dist = help_bellman_ford(graph, [source], weight, nil, paths, nil, cutoff, target) + return [dist, paths] if target.nil? + raise ArgumentError, 'Node not reachable!' unless dist.has_key?(target) + + [dist[target], paths[target]] +end+ |
+
Shortest path from source to all nodes using Bellman Ford algorithm
+ + +
+ + + +338 +339 +340 +341+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 338 + +def self.singlesource_bellmanford_path(graph, source, cutoff = nil) + _, path = singlesource_bellmanford(graph, source, cutoff) + path +end+ |
+
Shortest path length from source to all nodes using Bellman Ford algorithm
+ + +
+ + + +350 +351 +352 +353+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 350 + +def self.singlesource_bellmanford_path_length(graph, source, cutoff = nil) + weight = get_weight(graph) + help_bellman_ford(graph, [source], weight, nil, nil, nil, cutoff) +end+ |
+
Computes shortest paths and path distances to all nodes/target from the given node
+ + +
+ + + +113 +114 +115+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 113 + +def self.singlesource_dijkstra(graph, source, target = nil, cutoff = nil) + multisource_dijkstra(graph, [source], target, cutoff) +end+ |
+
Computes shortest paths to all nodes from the given node
+ + +
+ + + +135 +136 +137+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 135 + +def self.singlesource_dijkstra_path(graph, source, cutoff = nil) + multisource_dijkstra_path(graph, [source], cutoff) +end+ |
+
Computes shortest path lengths to all nodes from the given node
+ + +
+ + + +124 +125 +126+ |
+
+ # File 'lib/networkx/shortest_path/weighted.rb', line 124 + +def self.singlesource_dijkstra_path_length(graph, source, cutoff = nil) + multisource_dijkstra_path_length(graph, [source], cutoff) +end+ |
+
Returns the strong product of two graphs
+ + +
+ + + +157 +158 +159 +160 +161 +162 +163 +164 +165+ |
+
+ # File 'lib/networkx/operators/product.rb', line 157 + +def self.strong_product(g1, g2) + g = init_product_graph(g1, g2) + g.add_nodes(node_product(g1, g2)) + g.add_edges(nodes_cross_edges(g1, g2)) + g.add_edges(edges_cross_nodes(g1, g2)) + g.add_edges(directed_edges_cross_edges(g1, g2)) + g.add_edges(undirected_edges_cross_edges(g1, g2)) unless g.directed? + g +end+ |
+
Performs the symmetric difference of two graphs
+ + +
+ + + +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165+ |
+
+ # File 'lib/networkx/operators/binary.rb', line 126 + +def self.symmetric_difference(g1, g2) + result = g1.class.new + + raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph? + + unless (g1.nodes(data: true).keys - g2.nodes(data: true).keys).empty? + raise ArgumentError, 'Node sets must be equal!' + end + + g1.nodes(data: true).each { |u, attrs| result.add_node(u, **attrs) } + + g1.adj.each do |u, u_edges| + u_edges.each do |v, uv_attrs| + if g1.multigraph? + next if u > v && g1.instance_of?(MultiGraph) + + uv_attrs.each do |k, attrs| + result.add_edge(u, v, **attrs) unless g2.edge?(u, v, k) + end + else + result.add_edge(u, v, **uv_attrs) unless g2.edge?(u, v) + end + end + end + + g2.adj.each do |u, u_edges| + u_edges.each do |v, uv_attrs| + next if u > v && g1.instance_of?(MultiGraph) + + if g2.multigraph? + uv_attrs.each do |k, attrs| + result.add_edge(u, v, **attrs) unless g1.edge?(u, v, k) + end + else + result.add_edge(u, v, **uv_attrs) unless g1.edge?(u, v) + end + end + end + result +end+ |
+
Returns the tensor product of two graphs
+ + +
+ + + +115 +116 +117 +118 +119 +120 +121+ |
+
+ # File 'lib/networkx/operators/product.rb', line 115 + +def self.tensor_product(g1, g2) + g = init_product_graph(g1, g2) + g.add_nodes(node_product(g1, g2)) + g.add_edges(directed_edges_cross_edges(g1, g2)) + g.add_edges(undirected_edges_cross_edges(g1, g2)) unless g.directed? + g +end+ |
+
+ + + +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50+ |
+
+ # File 'lib/networkx/to_matrix.rb', line 2 + +def self.to_matrix(graph, val, multigraph_weight = 'sum') + is_undirected = !graph.directed? + is_multigraph = graph.multigraph? + nodelen = graph.nodes(data: true).length + + m = Matrix.build(nodelen) { val } + index = {} + inv_index = {} + ind = 0 + + graph.nodes(data: true).each do |u, _| + index[u] = ind + inv_index[ind] = u + ind += 1 + end + + if is_multigraph + graph.adj.each do |u, edge_hash| + edge_hash.each do |v, keys| + all_weights = [] + keys.each do |_key, attrs| + all_weights << attrs[:weight] + end + + edge_attr = 0 + + case multigraph_weight + when 'sum' + edge_attr = all_weights.sum + when 'max' + edge_attr = all_weights.max + when 'min' + edge_attr = all_weights.min + end + + m[index[u], index[v]] = edge_attr + m[index[v], index[u]] = edge_attr || 1 if is_undirected + end + end + else + graph.adj.each do |u, edge_hash| + edge_hash.each do |v, attrs| + m[index[u], index[v]] = (attrs[:weight] || 1) + m[index[v], index[u]] = (attrs[:weight] || 1) if is_undirected + end + end + end + [m, inv_index] +end+ |
+
+ + + +42 +43 +44 +45 +46 +47 +48 +49 +50 +51+ |
+
+ # File 'lib/networkx/others/reads.rb', line 42 + +def self.to_number_if_possible(str) + case str + when /^[+-]?[0-9]+$/ + str.to_i + when /^([+-]?\d*\.\d*)|(\d*[eE][+-]?\d+)$/ + str.to_f + else + str + end +end+ |
+
Returns the nodes arranged in the topologically sorted fashion
+ + +
+ + + +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58+ |
+
+ # File 'lib/networkx/auxillary_functions/dag.rb', line 33 + +def self.topological_sort(graph) + raise ArgumentError, 'Topological Sort not defined on undirected graphs!' unless graph.directed? + + nodes = [] + indegree_map = graph.nodes(data: true).each_key.map do |u| + [u, graph.in_degree(u)] if graph.in_degree(u).positive? + end.compact.to_h + zero_indegree = graph.nodes(data: true).each_key.select { |u| graph.in_degree(u).zero? } + + until zero_indegree.empty? + node = zero_indegree.shift + raise ArgumentError, 'Graph changed during iteration!' unless graph.nodes(data: true).has_key?(node) + + graph.adj[node].each_key do |child| + indegree_map[child] -= 1 + if indegree_map[child].zero? + zero_indegree << child + indegree_map.delete(child) + end + end + nodes << node + end + raise ArgumentError, 'Graph contains cycle or graph changed during iteration!' unless indegree_map.empty? + + nodes +end+ |
+
Returns the product of undirected edges with edges
+ + +
+ + + +51 +52 +53 +54 +55 +56 +57 +58 +59+ |
+
+ # File 'lib/networkx/operators/product.rb', line 51 + +def self.undirected_edges_cross_edges(g1, g2) + result = [] + edges_in_array(g1).each do |u, v, c| + edges_in_array(g2).each do |x, y, d| + result << [[v, x], [u, y], hash_product(c, d)] + end + end + result +end+ |
+
Performs the union of two graphs
+ + +
+ + + +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217+ |
+
+ # File 'lib/networkx/operators/binary.rb', line 197 + +def self.union(g1, g2) + raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph? + + new_graph = g1.class.new + new_graph.graph.merge!(g1.graph) + new_graph.graph.merge!(g2.graph) + + unless (g1.nodes(data: true).keys & g2.nodes(data: true).keys).empty? + raise ArgumentError, 'Graphs must be disjoint!' + end + + g1_edges = get_edges(g1) + g2_edges = get_edges(g2) + + new_graph.add_nodes(g1.nodes(data: true).keys) + new_graph.add_edges(g1_edges) + new_graph.add_nodes(g2.nodes(data: true).keys) + new_graph.add_edges(g2_edges) + + new_graph +end+ |
+
Performs the union of many graphs
+ + +
+ + + +7 +8 +9 +10 +11 +12 +13 +14 +15 +16+ |
+
+ # File 'lib/networkx/operators/all.rb', line 7 + +def self.union_all(graphs) + raise ArgumentError, 'Argument array is empty' if graphs.empty? + + result = graphs.shift + + graphs.each do |graph| + result = NetworkX.union(result, graph) + end + result +end+ |
+
Returns the wiener index of the graph
+ + +
+ + + +7 +8 +9 +10 +11 +12+ |
+
+ # File 'lib/networkx/auxillary_functions/wiener.rb', line 7 + +def self.wiener_index(graph) + total = all_pairs_shortest_path_length(graph) + wiener_ind = 0 + total.to_h.each { |_, distances| distances.to_h.each { |_, val| wiener_ind += val } } + graph.directed? ? wiener_ind : wiener_ind / 2 +end+ |
+
Helper function for augmenting flow
+ + +
+ + + +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127+ |
+
+ # File 'lib/networkx/flow/shortestaugmentingpath.rb', line 108 + +def augment(path, inf, r_adj) + flow = inf + temp_path = path.clone + u = temp_path.shift + temp_path.each do |v| + attr = r_adj[u][v] + flow = [flow, attr[:capacity] - attr[:flow]].min + u = v + end + raise ArgumentError, 'Infinite capacity path!' if flow * 2 > inf + + temp_path = path.clone + u = temp_path.shift + temp_path.each do |v| + r_adj[u][v][:flow] += flow + r_adj[v][u][:flow] -= flow + u = v + end + flow +end+ |
+
Helper class for preflow push algorithm
+ + +Returns the value of attribute curr.
+Returns the value of attribute edges.
+A new instance of CurrentEdge.
+Returns a new instance of CurrentEdge.
+ + +
+ + + +6 +7 +8 +9 +10 +11 +12+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 6 + +def initialize(edges) + @edges = edges + @index = {} + @n = edges.length + @curr = 0 + edges.each_with_index { |(key, _value), idx| @index[idx] = key } +end+ |
+
Returns the value of attribute curr.
+ + +
+ + + +4 +5 +6+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 4 + +def curr + @curr +end+ |
+
Returns the value of attribute edges.
+ + +
+ + + +4 +5 +6+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 4 + +def edges + @edges +end+ |
+
+ + + +14 +15 +16+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 14 + +def get + [@index[@curr], @edges[@index[@curr]]] +end+ |
+
+ + + +18 +19 +20 +21 +22+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 18 + +def move_to_next + @temp = @curr + @curr = (@curr + 1) % @n + raise StopIteration if @temp == @n - 1 +end+ |
+
Describes the class for making Directed Graphs
+ + +Stores the edges and their attributes in an adjencency list form.
+Stores the attributes of the graph.
+Stores the nodes and their attributes.
+Stores the reverse edges and their attributes in an adjencency list form.
+Adds the respective edge.
+Adds a node and its attributes to the graph.
+Clears the graph.
+Returns subgraph consisting of given edges.
+Returns in-degree of a given node.
+Constructor for initializing graph.
+Returns number of edges.
+Returns out-degree of a given node.
+Removes edge from the graph.
+Removes node from the graph.
+Returns the reversed version of the graph.
+Returns the size of graph.
+Returns subgraph consisting of given array of nodes.
+Returns the undirected version of the graph.
+#add_edges, #add_edges_from, #add_nodes, #add_nodes_from, #add_path, #add_weighted_edge, #add_weighted_edges, #add_weighted_edges_from, balanced_tree, barbell_graph, #bfs_edges, #bfs_nodes, bull_graph, circular_ladder_graph, complete_edges, complete_graph, cubical_graph, cycle_graph, #degree, #dfs_edges, #dfs_postorder_nodes, #dfs_preorder_nodes, diamond_graph, dodecahedral_graph, #each_bfs_edge, #each_bfs_node, #each_dfs_edge, #each_dfs_postorder_node, #each_dfs_preorder_node, #each_edge, #each_node, #edge?, #edges, empty_graph, #get_edge_data, #get_node_data, heawood_graph, house_graph, house_x_graph, #info, ladder_graph, lollipop_graph, moebius_kantor_graph, #multigraph?, #neighbours, #node?, null_graph, #number_of_nodes, octahedral_graph, path_graph, #put_graph_x2, read_edgelist, read_weighted_edgelist, #remove_edges, #remove_nodes, star_graph, tetrahedral_graph, trivial_graph, wheel_graph
+Constructor for initializing graph
+ + +
+ + + +19 +20 +21 +22 +23+ |
+
+ # File 'lib/networkx/digraph.rb', line 19 + +def initialize(**graph_attrs) + super(**graph_attrs) + + @pred = {} +end+ |
+
Stores the edges and their attributes in an adjencency list form
+ + +
+ + + +10 +11 +12+ |
+
+ # File 'lib/networkx/digraph.rb', line 10 + +def adj + @adj +end+ |
+
Stores the attributes of the graph
+ + +
+ + + +10 +11 +12+ |
+
+ # File 'lib/networkx/digraph.rb', line 10 + +def graph + @graph +end+ |
+
Stores the nodes and their attributes
+ + +
+ + + +10 +11 +12+ |
+
+ # File 'lib/networkx/digraph.rb', line 10 + +def nodes + @nodes +end+ |
+
Stores the reverse edges and their attributes in an adjencency list form
+ + +
+ + + +10 +11 +12+ |
+
+ # File 'lib/networkx/digraph.rb', line 10 + +def pred + @pred +end+ |
+
Adds the respective edge
+ + +
+ + + +36 +37 +38 +39 +40 +41 +42 +43+ |
+
+ # File 'lib/networkx/digraph.rb', line 36 + +def add_edge(node1, node2, **edge_attrs) + add_node(node1) + add_node(node2) + + edge_attrs = (@adj[node1][node2] || {}).merge(edge_attrs) + @adj[node1][node2] = edge_attrs + @pred[node2][node1] = edge_attrs +end+ |
+
Adds a node and its attributes to the graph
+ + +
+ + + +52 +53 +54 +55 +56+ |
+
+ # File 'lib/networkx/digraph.rb', line 52 + +def add_node(node, **node_attrs) + super(node, **node_attrs) + + @pred[node] = {} unless @pred.has_key?(node) +end+ |
+
Clears the graph
+ + +
+ + + +102 +103 +104 +105 +106+ |
+
+ # File 'lib/networkx/digraph.rb', line 102 + +def clear + super + + @pred.clear +end+ |
+
+ + + +230 +231 +232+ |
+
+ # File 'lib/networkx/digraph.rb', line 230 + +def directed? + true +end+ |
+
Returns subgraph consisting of given edges
+ + +
+ + + +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228+ |
+
+ # File 'lib/networkx/digraph.rb', line 211 + +def edge_subgraph(edges) + case edges + when Array, Set + sub_graph = NetworkX::DiGraph.new(**@graph) + edges.each do |u, v| + raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.has_key?(u) \ + && @adj[u].has_key?(v) + + sub_graph.add_node(u, **@nodes[u]) + sub_graph.add_node(v, **@nodes[v]) + sub_graph.add_edge(u, v, **@adj[u][v]) + end + sub_graph + else + raise ArgumentError, 'Expected Argument to be Array or Set of edges, ' \ + "received #{edges.class.name} instead." + end +end+ |
+
Returns in-degree of a given node
+ + +
+ + + +140 +141 +142+ |
+
+ # File 'lib/networkx/digraph.rb', line 140 + +def in_degree(node) + @pred[node].length +end+ |
+
Returns number of edges
+ + +
+ + + +112 +113 +114+ |
+
+ # File 'lib/networkx/digraph.rb', line 112 + +def number_of_edges + @adj.values.map(&:length).sum +end+ |
+
Returns out-degree of a given node
+ + +
+ + + +150 +151 +152+ |
+
+ # File 'lib/networkx/digraph.rb', line 150 + +def out_degree(node) + @adj[node].length +end+ |
+
Removes edge from the graph
+ + +
+ + + +89 +90 +91 +92 +93 +94 +95 +96+ |
+
+ # File 'lib/networkx/digraph.rb', line 89 + +def remove_edge(node1, node2) + raise KeyError, "#{node1} is not a valid node." unless @nodes.has_key?(node1) + raise KeyError, "#{node2} is not a valid node" unless @nodes.has_key?(node2) + raise KeyError, 'The given edge is not a valid one.' unless @adj[node1].has_key?(node2) + + @adj[node1].delete(node2) + @pred[node2].delete(node1) +end+ |
+
Removes node from the graph
+ + +
+ + + +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80+ |
+
+ # File 'lib/networkx/digraph.rb', line 68 + +def remove_node(node) + raise KeyError, "Error in deleting node #{node} from Graph." unless @nodes.has_key?(node) + + neighbours = @adj[node] + neighbours.each_key { |k| @pred[k].delete(node) } + @pred[node].each_key do |k| + @adj[k].delete(node) + end + + @pred.delete(node) + @adj.delete(node) + @nodes.delete(node) +end+ |
+
Returns the reversed version of the graph
+ + +
+ + + +158 +159 +160 +161 +162 +163 +164 +165+ |
+
+ # File 'lib/networkx/digraph.rb', line 158 + +def reverse + new_graph = NetworkX::DiGraph.new(**@graph) + @nodes.each { |u, attrs| new_graph.add_node(u, **attrs) } + @adj.each do |u, edges| + edges.each { |v, attrs| new_graph.add_edge(v, u, **attrs) } + end + new_graph +end+ |
+
Returns the size of graph
+ + +
+ + + +123 +124 +125 +126 +127 +128 +129 +130 +131 +132+ |
+
+ # File 'lib/networkx/digraph.rb', line 123 + +def size(is_weighted = false) + if is_weighted + graph_size = 0 + @adj.each do |_, hash_val| + hash_val.each { |_, v| graph_size += v[:weight] if v.has_key?(:weight) } + end + return graph_size + end + number_of_edges +end+ |
+
Returns subgraph consisting of given array of nodes
+ + +
+ + + +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203+ |
+
+ # File 'lib/networkx/digraph.rb', line 186 + +def subgraph(nodes) + case nodes + when Array, Set + sub_graph = NetworkX::DiGraph.new(**@graph) + nodes.each do |u| + raise KeyError, "#{u} does not exist in the current graph!" unless node?(u) + + sub_graph.add_node(u, **@nodes[u]) + @adj[u].each do |v, uv_attrs| + sub_graph.add_edge(u, v, **uv_attrs) if @adj[u].has_key?(v) && nodes.include?(v) + end + end + sub_graph + else + raise ArgumentError, 'Expected Argument to be Array or Set of nodes, ' \ + "received #{nodes.class.name} instead." + end +end+ |
+
Returns the undirected version of the graph
+ + +
+ + + +171 +172 +173 +174 +175 +176 +177 +178+ |
+
+ # File 'lib/networkx/digraph.rb', line 171 + +def to_undirected + new_graph = NetworkX::Graph.new(**@graph) + @nodes.each { |u, attrs| new_graph.add_node(u, **attrs) } + @adj.each do |u, edges| + edges.each { |v, attrs| new_graph.add_edge(u, v, **attrs) } + end + new_graph +end+ |
+
Helper class for preflow push algorithm
+ + +A new instance of GlobalRelabelThreshold.
+Returns a new instance of GlobalRelabelThreshold.
+ + +
+ + + +37 +38 +39 +40 +41+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 37 + +def initialize(num1, num2, freq) + freq = freq.nil? ? Float::INFINITY : freq + @threshold = (num1 + num2) / freq + @work = 0 +end+ |
+
+ + + +43 +44 +45+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 43 + +def add_work(work) + @work += work +end+ |
+
+ + + +51 +52 +53+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 51 + +def clear_work + @work = 0 +end+ |
+
+ + + +47 +48 +49+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 47 + +def reached? + @work >= @threshold +end+ |
+
Describes the class for making Undirected Graphs
+ + +Stores the edges and their attributes in an adjencency list form.
+Stores the attributes of the graph.
+private class method.
+12.
+8: 6 nodes, 12 edges.
+Adds the respective edges.
+Adds multiple edges from an array.
+Adds a node and its attributes to the graph.
+Adds multiple nodes to the graph.
+[TODO].
+Adds weighted edge.
+Adds multiple weighted edges.
+[TODO].
+[EXPERIMENTAL].
+Clears the graph.
+[EXPERIMENTAL].
+[EXPERIMENTAL].
+[EXPERIMENTAL].
+[EXPERIMENTAL].
+[EXPERIMENTAL].
+[TODO].
+Checks if the the edge consisting of two nodes is present in the graph.
+Returns subgraph conisting of given edges.
+[TODO].
+Gets the edge data.
+Gets the node data.
+Constructor for initializing graph.
+Retus a hash of neighbours of a node.
+Checks if a node is present in the graph.
+Return nodes of graph.
+Returns number of edges.
+Returns number of nodes.
+Experimental For debug.
+Removes edge from the graph.
+Removes multiple edges from the graph.
+Removes node from the graph.
+Removes multiple nodes from the graph.
+Returns the size of the graph.
+Returns subgraph consisting of given array of nodes.
+Constructor for initializing graph
+ + +
+ + + +16 +17 +18 +19 +20+ |
+
+ # File 'lib/networkx/graph.rb', line 16 + +def initialize(**graph_attrs) + @nodes = {} + @adj = {} + @graph = graph_attrs +end+ |
+
Stores the edges and their attributes in an adjencency list form
+ + +
+ + + +7 +8 +9+ |
+
+ # File 'lib/networkx/graph.rb', line 7 + +def adj + @adj +end+ |
+
Stores the attributes of the graph
+ + +
+ + + +7 +8 +9+ |
+
+ # File 'lib/networkx/graph.rb', line 7 + +def graph + @graph +end+ |
+
+ + + +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36+ |
+
+ # File 'lib/networkx/others/generators.rb', line 18 + +def self.balanced_tree(r, h) + edges = [] + q = [0] + i = 0 + h.times do + t = q.dup + q.clear + t.each do |v| + r.times do + i += 1 + edges << [v, i] + q << i + end + end + end + graph = new(name: "balanced_tree(#{r}, #{h})") + graph.add_edges(edges) + graph +end+ |
+
+ + + +38 +39 +40 +41 +42 +43 +44 +45 +46+ |
+
+ # File 'lib/networkx/others/generators.rb', line 38 + +def self.(m1, m2) + edges = complete_edges(m1) + edges.concat((m1..m2 + m1).map { |k| [k - 1, k] }) + edges.concat complete_edges(m1 + m2...m1 + m2 + m1) + + graph = new(name: "barbell_graph(#{m1}, #{m2})") + graph.add_edges(edges) + graph +end+ |
+
+ + + +145 +146 +147 +148 +149 +150+ |
+
+ # File 'lib/networkx/others/generators.rb', line 145 + +def self.bull_graph + edges = [[0, 1], [1, 2], [2, 0], [1, 3], [2, 4]] + graph = new(name: 'bull_graph') + graph.add_edges(edges) + graph +end+ |
+
+ + + +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73+ |
+
+ # File 'lib/networkx/others/generators.rb', line 63 + +def self.circular_ladder_graph(n) + edges = (0...n - 1).map { |v| [v, v + 1] } + edges << [n - 1, 0] + edges.concat((n...2 * n - 1).map { |v| [v, v + 1] }) + edges << [2 * n - 1, n] + edges.concat((0...n).map { |v| [v, v + n] }) + + graph = new(name: "circular_ladder_graph(#{n})") + graph.add_edges(edges) + graph +end+ |
+
private class method
+ + +
+ + + +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16+ |
+
+ # File 'lib/networkx/others/generators.rb', line 6 + +def self.complete_edges(n) + n = (0...n) if n.is_a?(Integer) + + edges = [] + n.each do |i| + n.each do |j| + edges << [i, j] if i < j + end + end + edges +end+ |
+
+ + + +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61+ |
+
+ # File 'lib/networkx/others/generators.rb', line 48 + +def self.complete_graph(n) + n = (0...n) if n.is_a?(Integer) + + edges = [] + n.each do |i| + n.each do |j| + edges << [i, j] if i < j + end + end + + graph = new(name: "complete_graph(#{n})") + graph.add_edges(edges) + graph +end+ |
+
+ + + +152 +153 +154 +155 +156+ |
+
+ # File 'lib/networkx/others/generators.rb', line 152 + +def self.cubical_graph + graph = circular_ladder_graph(4) + graph.graph[:name] = 'cubical_graph' + graph +end+ |
+
+ + + +75 +76 +77 +78 +79 +80 +81 +82+ |
+
+ # File 'lib/networkx/others/generators.rb', line 75 + +def self.cycle_graph(n) + edges = (0...n - 1).map { |v| [v, v + 1] } + edges << [n - 1, 0] + + graph = new(name: "cycle_graph(#{n})") + graph.add_edges(edges) + graph +end+ |
+
+ + + +158 +159 +160 +161 +162 +163+ |
+
+ # File 'lib/networkx/others/generators.rb', line 158 + +def self.diamond_graph + edges = [[0, 1], [0, 2], [1, 2], [1, 3], [2, 3]] + graph = new(name: 'diamond_graph') + graph.add_edges(edges) + graph +end+ |
+
12
+ + +
+ + + +166 +167 +168 +169 +170 +171 +172+ |
+
+ # File 'lib/networkx/others/generators.rb', line 166 + +def self.dodecahedral_graph + edges = (0...19).map { |k| [k, k + 1] } + edges.concat [[0, 19], [0, 10], [1, 8], [2, 6], [3, 19], [4, 17], [5, 15], [7, 14], [9, 13], [11, 18], [12, 16]] + graph = new(name: 'dodecahedral_graph') + graph.add_edges(edges) + graph +end+ |
+
+ + + +84 +85 +86 +87 +88+ |
+
+ # File 'lib/networkx/others/generators.rb', line 84 + +def self.empty_graph(number_of_nodes) + empty_graph = new(name: "empty_graph#{number_of_nodes}") + empty_graph.add_nodes_from(0...number_of_nodes) + empty_graph +end+ |
+
+ + + +174 +175 +176 +177 +178 +179 +180 +181+ |
+
+ # File 'lib/networkx/others/generators.rb', line 174 + +def self.heawood_graph + edges = (0...13).map { |k| [k, k + 1] } + edges << [13, 0] + edges.concat [[0, 5], [1, 10], [2, 7], [3, 12], [4, 9], [6, 11], [8, 13]] + graph = new(name: 'heawood_graph') + graph.add_edges(edges) + graph +end+ |
+
+ + + +183 +184 +185 +186 +187 +188+ |
+
+ # File 'lib/networkx/others/generators.rb', line 183 + +def self.house_graph + edges = [[0, 1], [0, 2], [1, 3], [2, 3], [2, 4], [3, 4]] + graph = new(name: 'house_graph') + graph.add_edges(edges) + graph +end+ |
+
+ + + +190 +191 +192 +193 +194 +195 +196+ |
+
+ # File 'lib/networkx/others/generators.rb', line 190 + +def self.house_x_graph + edges = (0...4).map { |k| [k, k + 1] } + edges.concat [[0, 2], [0, 3], [1, 3], [2, 4], [3, 4]] + graph = new(name: 'house_x_graph') + graph.add_edges(edges) + graph +end+ |
+
+ + + +90 +91 +92 +93 +94 +95 +96 +97 +98+ |
+
+ # File 'lib/networkx/others/generators.rb', line 90 + +def self.ladder_graph(n) + edges = (0...n - 1).map { |k| [k, k + 1] } + edges.concat((n...2 * n - 1).map { |k| [k, k + 1] }) + edges.concat((0...n).map { |k| [k, k + n] }) + + graph = new(name: "ladder_graph(#{n})") + graph.add_edges(edges) + graph +end+ |
+
+ + + +100 +101 +102 +103 +104 +105 +106 +107+ |
+
+ # File 'lib/networkx/others/generators.rb', line 100 + +def self.lollipop_graph(m, n) + edges = complete_edges(m) + edges.concat((m - 1...m - 1 + n).map { |v| [v, v + 1] }) + + graph = new(name: "lollipop_graph(#{m}, #{n})") + graph.add_edges(edges) + graph +end+ |
+
+ + + +198 +199 +200 +201 +202 +203 +204 +205+ |
+
+ # File 'lib/networkx/others/generators.rb', line 198 + +def self.moebius_kantor_graph + edges = (0...15).map { |k| [k, k + 1] } + edges << [15, 0] + edges.concat [[0, 5], [1, 12], [2, 7], [4, 9], [3, 14], [6, 11], [8, 13], [10, 15]] + graph = new(name: 'moebius_kantor_graph') + graph.add_edges(edges) + graph +end+ |
+
+ + + +109 +110 +111+ |
+
+ # File 'lib/networkx/others/generators.rb', line 109 + +def self.null_graph + new(name: 'null_graph') +end+ |
+
8: 6 nodes, 12 edges
+ + +
+ + + +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218+ |
+
+ # File 'lib/networkx/others/generators.rb', line 208 + +def self.octahedral_graph + edges = [] + 6.times do |i| + 6.times do |j| + edges << [i, j] if i != j && i + j != 5 + end + end + graph = new(name: 'octahedral_graph') + graph.add_edges(edges) + graph +end+ |
+
+ + + +113 +114 +115 +116 +117 +118 +119+ |
+
+ # File 'lib/networkx/others/generators.rb', line 113 + +def self.path_graph(n) + edges = (0...n - 1).map { |v| [v, v + 1] } + + graph = new(name: "path_graph(#{n})") + graph.add_edges(edges) + graph +end+ |
+
+ + + +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17+ |
+
+ # File 'lib/networkx/others/reads.rb', line 6 + +def read_edgelist(path, comment: '#', delimiter: nil) + edges = File.readlines(path).filter_map do |line| + line.sub!(/#{comment}.+/, '') + line.strip.split(delimiter) if line.strip.size > 0 + end + + edges.each{|edge| edge.map!{|node| NetworkX.to_number_if_possible(node) } } + + graph = new + graph.add_edges(edges) + graph +end+ |
+
+ + + +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37+ |
+
+ # File 'lib/networkx/others/reads.rb', line 20 + +def read_weighted_edgelist(path, comment: '#', delimiter: nil) + edges = File.readlines(path).filter_map do |line| + line.sub!(/#{comment}.+/, '') + line.strip.split(delimiter) if line.strip.size > 0 + end + + edges.map! do |x, y, weight| + [ + NetworkX.to_number_if_possible(x), + NetworkX.to_number_if_possible(y), + {weight: NetworkX.to_number_if_possible(weight)} + ] + end + + graph = new + graph.add_edges(edges) + graph +end+ |
+
+ + + +121 +122 +123 +124 +125 +126 +127+ |
+
+ # File 'lib/networkx/others/generators.rb', line 121 + +def self.star_graph(n) + edges = (1..n).map { |i| [0, i] } + + graph = new(name: "star_graph(#{n})") + graph.add_edges(edges) + graph +end+ |
+
+ + + +220 +221 +222 +223 +224+ |
+
+ # File 'lib/networkx/others/generators.rb', line 220 + +def self.tetrahedral_graph + graph = complete_graph(4) + graph.graph[:name] = 'tetrahedral_graph' + graph +end+ |
+
+ + + +129 +130 +131 +132 +133+ |
+
+ # File 'lib/networkx/others/generators.rb', line 129 + +def self.trivial_graph + trivial_graph = new(name: 'trivial_grpph') + trivial_graph.add_node(0) + trivial_graph +end+ |
+
+ + + +135 +136 +137 +138 +139 +140 +141 +142 +143+ |
+
+ # File 'lib/networkx/others/generators.rb', line 135 + +def self.wheel_graph(n) + edges = (1..n - 1).map { |i| [0, i] } + edges.concat((1...n - 1).map { |i| [i, i + 1] }) + edges << [1, n - 1] + + graph = new(name: "wheel_graph(#{n})") + graph.add_edges(edges) + graph +end+ |
+
Adds the respective edges
+ + +
+ + + +33 +34 +35 +36 +37 +38 +39 +40+ |
+
+ # File 'lib/networkx/graph.rb', line 33 + +def add_edge(node1, node2, **edge_attrs) + add_node(node1) + add_node(node2) + + edge_attrs = (@adj[node1][node2] || {}).merge(edge_attrs) + @adj[node1][node2] = edge_attrs + @adj[node2][node1] = edge_attrs +end+ |
+
Adds multiple edges from an array
+ + +
+ + + +47 +48 +49 +50 +51 +52 +53 +54 +55+ |
+
+ # File 'lib/networkx/graph.rb', line 47 + +def add_edges(edges) + case edges + when Array + edges.each { |node1, node2, attrs| add_edge(node1, node2, **(attrs || {})) } + else + raise ArgumentError, 'Expected argument to be an Array of edges, ' \ + "received #{edges.class.name} instead." + end +end+ |
+
+ + + +57 +58 +59+ |
+
+ # File 'lib/networkx/graph.rb', line 57 + +def add_edges_from(rng) + rng.each { |node| add_edge(*node) } +end+ |
+
Adds a node and its attributes to the graph
+ + +
+ + + +68 +69 +70 +71 +72 +73 +74 +75+ |
+
+ # File 'lib/networkx/graph.rb', line 68 + +def add_node(node, **node_attrs) + if @nodes.has_key?(node) + @nodes[node].merge!(node_attrs) + else + @adj[node] = {} + @nodes[node] = node_attrs + end +end+ |
+
Adds multiple nodes to the graph
+ + +
+ + + +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93+ |
+
+ # File 'lib/networkx/graph.rb', line 83 + +def add_nodes(nodes) + case nodes + when Set, Array + nodes.each { |node, node_attrs| add_node(node, **(node_attrs || {})) } + when Range + nodes.each { |node| add_node(node) } + else + raise ArgumentError, 'Expected argument to be an Array/Set/Range of nodes, ' \ + "received #{nodes.class.name} instead." + end +end+ |
+
+ + + +98 +99 +100 +101 +102 +103 +104 +105+ |
+
+ # File 'lib/networkx/graph.rb', line 98 + +def add_nodes_from(nodes_for_adding) + case nodes_for_adding + when String + nodes_for_adding.each_char { |node| add_node(node) } + else + nodes_for_adding.each { |node| add_node(node) } + end +end+ |
+
+ + + +107 +108 +109+ |
+
+ # File 'lib/networkx/graph.rb', line 107 + +def add_path(paths) + paths.each_cons(2){|x, y| add_edge(x, y) } +end+ |
+
Adds weighted edge
+ + +
+ + + +183 +184 +185+ |
+
+ # File 'lib/networkx/graph.rb', line 183 + +def add_weighted_edge(node1, node2, weight) + add_edge(node1, node2, weight: weight) +end+ |
+
Adds multiple weighted edges
+ + +
+ + + +195 +196 +197 +198 +199 +200 +201 +202 +203 +204+ |
+
+ # File 'lib/networkx/graph.rb', line 195 + +def add_weighted_edges(edges, weights) + raise ArgumentError, 'edges and weights array must have equal number of elements.' \ + unless edges.size == weights.size + raise ArgumentError, 'edges and weight must be given in an Array.' \ + unless edges.is_a?(Array) && weights.is_a?(Array) + + (edges.transpose << weights).transpose.each do |node1, node2, weight| + add_weighted_edge(node1, node2, weight) + end +end+ |
+
+ + + +210 +211 +212 +213 +214+ |
+
+ # File 'lib/networkx/graph.rb', line 210 + +def add_weighted_edges_from(edges, weight: :weight) + edges.each do |s, t, w| + add_edge(s, t, **{weight => w}) + end +end+ |
+
[EXPERIMENTAL]
+ + +
+ + + +84 +85 +86+ |
+
+ # File 'lib/networkx/traversals/bfs.rb', line 84 + +def bfs_edges(node) + each_bfs_edge(node).to_a +end+ |
+
+ + + +60 +61 +62+ |
+
+ # File 'lib/networkx/traversals/bfs.rb', line 60 + +def bfs_nodes(root) + each_bfs_node(root).to_a +end+ |
+
Clears the graph
+ + +
+ + + +270 +271 +272 +273 +274+ |
+
+ # File 'lib/networkx/graph.rb', line 270 + +def clear + @adj.clear + @nodes.clear + @graph.clear +end+ |
+
[EXPERIMENTAL]
+ + +
+ + + +421 +422 +423 +424 +425 +426 +427 +428 +429+ |
+
+ # File 'lib/networkx/graph.rb', line 421 + +def degree(nodes = nil) + if nodes.nil? + @adj.transform_values(&:size) + else + res = {} + nodes.each { |node| res[node] = @adj[node].size } + res + end +end+ |
+
+ + + +89 +90 +91+ |
+
+ # File 'lib/networkx/traversals/edge_dfs.rb', line 89 + +def dfs_edges(node) + each_dfs_edge(node).to_a +end+ |
+
[EXPERIMENTAL]
+ + +
+ + + +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126+ |
+
+ # File 'lib/networkx/traversals/dfs.rb', line 115 + +def dfs_postorder_nodes(root, used = {root => true}) + res = [] + @adj[root].each do |v, _data| + next if used[v] + + used[v] = true + res.concat dfs_postorder_nodes(v, used) + end + + res << root + res +end+ |
+
[EXPERIMENTAL]
+ + +
+ + + +86 +87 +88+ |
+
+ # File 'lib/networkx/traversals/dfs.rb', line 86 + +def dfs_preorder_nodes(root) + each_dfs_preorder_node(root).to_a +end+ |
+
+ + + +443 +444 +445+ |
+
+ # File 'lib/networkx/graph.rb', line 443 + +def directed? + ['NetworkX::DiGraph', 'NetworkX::MultiDiGraph'].include?(self.class.name) +end+ |
+
[EXPERIMENTAL]
+ + +
+ + + +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108+ |
+
+ # File 'lib/networkx/traversals/bfs.rb', line 91 + +def each_bfs_edge(node) + return enum_for(:each_bfs_edge, node) unless block_given? + + que = [node] + used = {node => true} + while que[0] + node = que.shift + + @adj[node].each do |v, _data| + next if used[v] + + used[v] = true + + yield(node, v) + que << v + end + end +end+ |
+
+ + + +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79+ |
+
+ # File 'lib/networkx/traversals/bfs.rb', line 64 + +def each_bfs_node(root) + return enum_for(:each_bfs_node, root) unless block_given? + + queue = [root] + dist = {root => 0} + while (v = queue.shift) + yield v + d = dist[v] + @adj[v].each do |u, _data| + next if dist[u] + + dist[u] = d + 1 + queue << u + end + end +end+ |
+
+ + + +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112+ |
+
+ # File 'lib/networkx/traversals/edge_dfs.rb', line 93 + +def each_dfs_edge(node) + return enum_for(:each_dfs_edge, node) unless block_given? + + st = [node] + used = {} + parents = {} + while st[-1] + node = st.pop + + yield(parents[node], node) if parents[node] + + used[node] = true + @adj[node].reverse_each do |v, _data| + next if used[v] + + parents[v] = node + st << v unless used[v] + end + end +end+ |
+
+ + + +129 +130 +131 +132 +133+ |
+
+ # File 'lib/networkx/traversals/dfs.rb', line 129 + +def each_dfs_postorder_node(root, &block) + return enum_for(:each_dfs_postorder_node, root) unless block_given? + + dfs_postorder_nodes(root).each(&block) +end+ |
+
[EXPERIMENTAL]
+ + +
+ + + +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108+ |
+
+ # File 'lib/networkx/traversals/dfs.rb', line 93 + +def each_dfs_preorder_node(root) + return enum_for(:each_dfs_preorder_node, root) unless block_given? + + st = [root] + used = {root => true} + while st[-1] + node = st.pop + yield(node) + @adj[node].reverse_each do |v, _data| + next if used[v] + + used[v] = node + st << v + end + end +end+ |
+
+ + + +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264+ |
+
+ # File 'lib/networkx/graph.rb', line 248 + +def each_edge(data: false) + return enum_for(:each_edge, data: data) unless block_given? + + h = {} + @adj.each do |v, ws| + ws.each do |w, info| + next if v > w + + h[[v, w, info]] = true + end + end + if data + h.each { |(v, w, info), _true| yield(v, w, info) } + else + h.each { |(v, w, _info), _true| yield(v, w) } + end +end+ |
+
+ + + +230 +231 +232 +233 +234+ |
+
+ # File 'lib/networkx/graph.rb', line 230 + +def each_node(data: false, &block) + return enum_for(:each_node, data: data) unless block_given? + + data ? @nodes.each(&block) : @nodes.each_key(&block) +end+ |
+
Checks if the the edge consisting of two nodes is present in the graph
+ + +
+ + + +294 +295 +296+ |
+
+ # File 'lib/networkx/graph.rb', line 294 + +def edge?(node1, node2) + node?(node1) && @adj[node1].has_key?(node2) +end+ |
+
Returns subgraph conisting of given edges
+ + +
+ + + +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418+ |
+
+ # File 'lib/networkx/graph.rb', line 401 + +def edge_subgraph(edges) + case edges + when Array, Set + sub_graph = NetworkX::Graph.new(**@graph) + edges.each do |u, v| + raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.has_key?(u) \ + && @adj[u].has_key?(v) + + sub_graph.add_node(u, **@nodes[u]) + sub_graph.add_node(v, **@nodes[v]) + sub_graph.add_edge(u, v, **@adj[u][v]) + end + sub_graph + else + raise ArgumentError, 'Expected Argument to be Array or Set of edges, ' \ + "received #{edges.class.name} instead." + end +end+ |
+
+ + + +241 +242 +243+ |
+
+ # File 'lib/networkx/graph.rb', line 241 + +def edges(data: false) + each_edge(data: data).to_a +end+ |
+
Gets the edge data
+ + +
+ + + +318 +319 +320 +321 +322+ |
+
+ # File 'lib/networkx/graph.rb', line 318 + +def get_edge_data(node1, node2) + raise KeyError, 'No such edge exists!' unless node?(node1) && node?(node2) + + @adj[node1][node2] +end+ |
+
Gets the node data
+ + +
+ + + +305 +306 +307 +308 +309+ |
+
+ # File 'lib/networkx/graph.rb', line 305 + +def get_node_data(node) + raise ArgumentError, 'No such node exists!' unless node?(node) + + @nodes[node] +end+ |
+
+ + + +431 +432 +433 +434 +435 +436 +437+ |
+
+ # File 'lib/networkx/graph.rb', line 431 + +def info + info = '' + info << "Type: #{self.class}\n" + info << "Number of nodes: #{number_of_nodes}\n" + info << "Number of edges: #{number_of_edges}\n" + info +end+ |
+
+ + + +439 +440 +441+ |
+
+ # File 'lib/networkx/graph.rb', line 439 + +def multigraph? + ['NetworkX::MultiGraph', 'NetworkX::MultiDiGraph'].include?(self.class.name) +end+ |
+
Retus a hash of neighbours of a node
+ + +
+ + + +330 +331 +332 +333 +334+ |
+
+ # File 'lib/networkx/graph.rb', line 330 + +def neighbours(node) + raise KeyError, 'No such node exists!' unless node?(node) + + @adj[node] +end+ |
+
Checks if a node is present in the graph
+ + +
+ + + +282 +283 +284+ |
+
+ # File 'lib/networkx/graph.rb', line 282 + +def node?(node) + @nodes.has_key?(node) +end+ |
+
Return nodes of graph
+ + +
+ + + +222 +223 +224 +225 +226 +227 +228+ |
+
+ # File 'lib/networkx/graph.rb', line 222 + +def nodes(data: false) + if data + @nodes + else + @nodes.keys + end +end+ |
+
Returns number of edges
+ + +
+ + + +348 +349 +350+ |
+
+ # File 'lib/networkx/graph.rb', line 348 + +def number_of_edges + @adj.values.map(&:length).sum / 2 +end+ |
+
Returns number of nodes
+ + +
+ + + +340 +341 +342+ |
+
+ # File 'lib/networkx/graph.rb', line 340 + +def number_of_nodes + @nodes.length +end+ |
+
Experimental For debug.
+ + +
+ + + +229 +230 +231 +232 +233 +234 +235+ |
+
+ # File 'lib/networkx/others/generators.rb', line 229 + +def put_graph_x2 + output = <<~"OUTPUT" + #{number_of_nodes} #{number_of_edges} + #{edges.map { |edge| edge.join(' ') }.join("\n")} + OUTPUT + puts output +end+ |
+
Removes edge from the graph
+ + +
+ + + +149 +150 +151 +152 +153 +154 +155 +156+ |
+
+ # File 'lib/networkx/graph.rb', line 149 + +def remove_edge(node1, node2) + raise KeyError, "#{node1} is not a valid node." unless @nodes.has_key?(node1) + raise KeyError, "#{node2} is not a valid node" unless @nodes.has_key?(node2) + raise KeyError, 'The given edge is not a valid one.' unless @adj[node1].has_key?(node2) + + @adj[node1].delete(node2) + @adj[node2].delete(node1) if node1 != node2 +end+ |
+
Removes multiple edges from the graph
+ + +
+ + + +164 +165 +166 +167 +168 +169 +170 +171 +172+ |
+
+ # File 'lib/networkx/graph.rb', line 164 + +def remove_edges(edges) + case edges + when Array, Set + edges.each { |node1, node2| remove_edge(node1, node2) } + else + raise ArgumentError, 'Expected Arguement to be Array or Set of edges, ' \ + "received #{edges.class.name} instead." + end +end+ |
+
Removes node from the graph
+ + +
+ + + +117 +118 +119 +120 +121 +122 +123+ |
+
+ # File 'lib/networkx/graph.rb', line 117 + +def remove_node(node) + raise KeyError, "Error in deleting node #{node} from Graph." unless @nodes.has_key?(node) + + @adj[node].each_key { |k| @adj[k].delete(node) } + @adj.delete(node) + @nodes.delete(node) +end+ |
+
Removes multiple nodes from the graph
+ + +
+ + + +131 +132 +133 +134 +135 +136 +137 +138 +139+ |
+
+ # File 'lib/networkx/graph.rb', line 131 + +def remove_nodes(nodes) + case nodes + when Set, Array + nodes.each { |node| remove_node(node) } + else + raise ArgumentError, 'Expected argument to be an Array or Set of nodes, ' \ + "received #{nodes.class.name} instead." + end +end+ |
+
Returns the size of the graph
+ + +
+ + + +359 +360 +361 +362 +363 +364 +365 +366 +367 +368+ |
+
+ # File 'lib/networkx/graph.rb', line 359 + +def size(is_weighted = false) + if is_weighted + graph_size = 0 + @adj.each do |_, hash_val| + hash_val.each { |_, v| graph_size += v[:weight] if v.has_key?(:weight) } + end + return graph_size / 2 + end + number_of_edges +end+ |
+
Returns subgraph consisting of given array of nodes
+ + +
+ + + +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393+ |
+
+ # File 'lib/networkx/graph.rb', line 376 + +def subgraph(nodes) + case nodes + when Array, Set + sub_graph = NetworkX::Graph.new(**@graph) + nodes.each do |u, _| + raise KeyError, "#{u} does not exist in the current graph!" unless @nodes.has_key?(u) + + sub_graph.add_node(u, **@nodes[u]) + @adj[u].each do |v, edge_val| + sub_graph.add_edge(u, v, **edge_val) if @adj[u].has_key?(v) && nodes.include?(v) + end + end + sub_graph + else + raise ArgumentError, 'Expected Argument to be Array or Set of nodes, ' \ + "received #{nodes.class.name} instead." + end +end+ |
+
Helper class for preflow push algorithm
+ + +Returns the value of attribute active.
+Returns the value of attribute inactive.
+A new instance of Level.
+Returns a new instance of Level.
+ + +
+ + + +29 +30 +31 +32+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 29 + +def initialize + @inactive = Set.new + @active = Set.new +end+ |
+
Returns the value of attribute active.
+ + +
+ + + +27 +28 +29+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 27 + +def active + @active +end+ |
+
Returns the value of attribute inactive.
+ + +
+ + + +27 +28 +29+ |
+
+ # File 'lib/networkx/flow/utils.rb', line 27 + +def inactive + @inactive +end+ |
+
Describes the class for making MultiDiGraphs
+ + +Stores the edges and their attributes in an adjencency list form.
+Stores the attributes of the graph.
+Stores the nodes and their attributes.
+Stores the reverse edges and their attributes in an adjencency list form.
+Adds the respective edge.
+Checks if the the edge consisting of two nodes is present in the graph.
+Returns subgraph conisting of given edges.
+Returns in-degree of a given node.
+Returns a new key.
+Returns number of edges.
+Returns out-degree of a given node.
+Removes edge from the graph.
+Returns the reversed version of the graph.
+Returns the size of the graph.
+Returns subgraph consisting of given array of nodes.
+Returns the directed version of the graph.
+Returns the multigraph version of the graph.
+Returns the undirected version of the graph.
+#add_node, #clear, #directed?, #initialize, #remove_node
+ + + + + + + + + +#add_edges, #add_edges_from, #add_node, #add_nodes, #add_nodes_from, #add_path, #add_weighted_edge, #add_weighted_edges, #add_weighted_edges_from, balanced_tree, barbell_graph, #bfs_edges, #bfs_nodes, bull_graph, circular_ladder_graph, #clear, complete_edges, complete_graph, cubical_graph, cycle_graph, #degree, #dfs_edges, #dfs_postorder_nodes, #dfs_preorder_nodes, diamond_graph, #directed?, dodecahedral_graph, #each_bfs_edge, #each_bfs_node, #each_dfs_edge, #each_dfs_postorder_node, #each_dfs_preorder_node, #each_edge, #each_node, #edges, empty_graph, #get_edge_data, #get_node_data, heawood_graph, house_graph, house_x_graph, #info, #initialize, ladder_graph, lollipop_graph, moebius_kantor_graph, #neighbours, #node?, null_graph, #number_of_nodes, octahedral_graph, path_graph, #put_graph_x2, read_edgelist, read_weighted_edgelist, #remove_edges, #remove_node, #remove_nodes, star_graph, tetrahedral_graph, trivial_graph, wheel_graph
+This class inherits a constructor from NetworkX::DiGraph
+ +Stores the edges and their attributes in an adjencency list form
+ + +
+ + + +10 +11 +12+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 10 + +def adj + @adj +end+ |
+
Stores the attributes of the graph
+ + +
+ + + +10 +11 +12+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 10 + +def graph + @graph +end+ |
+
Stores the nodes and their attributes
+ + +
+ + + +10 +11 +12+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 10 + +def nodes + @nodes +end+ |
+
Stores the reverse edges and their attributes in an adjencency list form
+ + +
+ + + +10 +11 +12+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 10 + +def pred + @pred +end+ |
+
Adds the respective edge
+ + +
+ + + +34 +35 +36 +37 +38 +39 +40 +41 +42+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 34 + +def add_edge(node1, node2, **edge_attrs) + add_node(node1) + add_node(node2) + key = new_edge_key(node1, node2) + all_edge_attrs = @adj[node1][node2] || {} + all_edge_attrs[key] = edge_attrs + @adj[node1][node2] = all_edge_attrs + @pred[node2][node1] = all_edge_attrs +end+ |
+
Checks if the the edge consisting of two nodes is present in the graph
+ + +
+ + + +73 +74 +75 +76 +77+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 73 + +def edge?(node1, node2, key = nil) + return super(node1, node2) if key.nil? + + node?(node1) && @adj[node1].has_key?(node2) && @adj[node1][node2].has_key?(key) +end+ |
+
Returns subgraph conisting of given edges
+ + +
+ + + +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 226 + +def edge_subgraph(edges) + case edges + when Array, Set + sub_graph = NetworkX::MultiDiGraph.new(**@graph) + edges.each do |u, v| + raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.has_key?(u) \ + && @adj[u].has_key?(v) + + sub_graph.add_node(u, **@nodes[u]) + sub_graph.add_node(v, **@nodes[v]) + @adj[u][v].each { |_, keyval| sub_graph.add_edge(u, v, **keyval) } + end + sub_graph + else + raise ArgumentError, 'Expected Argument to be Array or Set of edges, ' \ + "received #{edges.class.name} instead." + end +end+ |
+
+ + + +79 +80 +81 +82 +83 +84 +85+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 79 + +def has_edge?(node1, node2, key = nil) + return super(node1, node2) if key.nil? + + return false unless node?(node1) && @adj[node1].has_key?(node2) + + @adj[node1][node2].any? { |_index, data| data[:key] == key } +end+ |
+
Returns in-degree of a given node
+ + +
+ + + +155 +156 +157+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 155 + +def in_degree(node) + @pred[node].values.map(&:length).sum +end+ |
+
+ + + +245 +246 +247+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 245 + +def multigraph? + true +end+ |
+
Returns a new key
+ + +
+ + + +15 +16 +17 +18 +19 +20 +21+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 15 + +def new_edge_key(node1, node2) + return 0 if @adj[node1][node2].nil? + + key = @adj[node1][node2].length + key += 1 while @adj[node1][node2].has_key?(key) + key +end+ |
+
Returns number of edges
+ + +
+ + + +173 +174 +175+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 173 + +def number_of_edges + @adj.values.flat_map(&:values).map(&:length).sum +end+ |
+
Returns out-degree of a given node
+ + +
+ + + +165 +166 +167+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 165 + +def out_degree(node) + @adj[node].values.map(&:length).sum +end+ |
+
Removes edge from the graph
+ + +
+ + + +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 51 + +def remove_edge(node1, node2, key = nil) + return super(node1, node2) if key.nil? + + raise KeyError, "#{node1} is not a valid node." unless @nodes.has_key?(node1) + raise KeyError, "#{node2} is not a valid node" unless @nodes.has_key?(node2) + raise KeyError, 'The given edge is not a valid one.' unless @adj[node1].has_key?(node2) + if @adj[node1][node2].none? { |_index, data| data[:key] == key } + raise KeyError, 'The given edge is not a valid one' + end + + @adj[node1][node2].delete_if { |_indx, data| data[:key] == key } + @pred[node2][node1].delete_if { |_indx, data| data[:key] == key } +end+ |
+
Returns the reversed version of the graph
+ + +
+ + + +140 +141 +142 +143 +144 +145 +146 +147+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 140 + +def reverse + new_graph = NetworkX::MultiDiGraph.new(**@graph) + @nodes.each { |node, attrs| new_graph.add_node(node, **attrs) } + @adj.each do |u, u_edges| + u_edges.each { |v, uv_attrs| uv_attrs.each { |_k, edge_attrs| new_graph.add_edge(v, u, **edge_attrs) } } + end + new_graph +end+ |
+
Returns the size of the graph
+ + +
+ + + +184 +185 +186 +187 +188 +189 +190 +191 +192 +193+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 184 + +def size(is_weighted = false) + if is_weighted + graph_size = 0 + @adj.each do |_, hash_val| + hash_val.each { |_, v| v.each { |_, attrs| graph_size += attrs[:weight] if attrs.has_key?(:weight) } } + end + return graph_size + end + number_of_edges +end+ |
+
Returns subgraph consisting of given array of nodes
+ + +
+ + + +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 201 + +def subgraph(nodes) + case nodes + when Array, Set + sub_graph = NetworkX::MultiDiGraph.new(**@graph) + nodes.each do |u, _| + raise KeyError, "#{u} does not exist in the current graph!" unless @nodes.has_key?(u) + + sub_graph.add_node(u, **@nodes[u]) + @adj[u].each do |v, edge_val| + edge_val.each { |_, keyval| sub_graph.add_edge(u, v, **keyval) if @adj[u].has_key?(v) && nodes.include?(v) } + end + end + sub_graph + else + raise ArgumentError, 'Expected Argument to be Array or Set of nodes, ' \ + "received #{nodes.class.name} instead." + end +end+ |
+
Returns the directed version of the graph
+ + +
+ + + +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 108 + +def to_directed + graph = NetworkX::DiGraph.new(**@graph) + @nodes.each { |node, node_attr| graph.add_node(node, **node_attr) } + @adj.each do |node1, node1_edges| + node1_edges.each do |node2, node1_node2| + edge_attrs = {} + node1_node2.each { |_key, attrs| edge_attrs.merge!(attrs) } + graph.add_edge(node1, node2, **edge_attrs) + end + end + graph +end+ |
+
Returns the multigraph version of the graph
+ + +
+ + + +125 +126 +127 +128 +129 +130 +131 +132 +133 +134+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 125 + +def to_multigraph + graph = NetworkX::MultiGraph.new(**@graph) + @nodes.each { |node, node_attr| graph.add_node(node, **node_attr) } + @adj.each do |node1, node2_edges| + node2_edges.each do |node2, edges| + edges.each { |_key, attrs| graph.add_edge(node1, node2, **attrs) } + end + end + graph +end+ |
+
Returns the undirected version of the graph
+ + +
+ + + +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102+ |
+
+ # File 'lib/networkx/multidigraph.rb', line 91 + +def to_undirected + graph = NetworkX::Graph.new(**@graph) + @nodes.each { |node, node_attr| graph.add_node(node, **node_attr) } + @adj.each do |node1, node1_edges| + node1_edges.each do |node2, node1_node2| + edge_attrs = {} + node1_node2.each { |_key, attrs| edge_attrs.merge!(attrs) } + graph.add_edge(node1, node2, **edge_attrs) + end + end + graph +end+ |
+
Describes the class for making MultiGraphs
+ + +Stores the edges and their attributes in an adjencency list form.
+Stores the attributes of the gra.
+Stores the nodes and their attributes.
+Adds the respective edge.
+Checks if the the edge consisting of two nodes is present in the graph.
+Returns subgraph conisting of given edges.
+Returns a new key.
+Returns number of edges.
+Removes edge from the graph.
+Returns the size of the graph.
+Returns subgraph consisting of given array of nodes.
+Returns the undirected version of the graph.
+#add_edges, #add_edges_from, #add_node, #add_nodes, #add_nodes_from, #add_path, #add_weighted_edge, #add_weighted_edges, #add_weighted_edges_from, balanced_tree, barbell_graph, #bfs_edges, #bfs_nodes, bull_graph, circular_ladder_graph, #clear, complete_edges, complete_graph, cubical_graph, cycle_graph, #degree, #dfs_edges, #dfs_postorder_nodes, #dfs_preorder_nodes, diamond_graph, #directed?, dodecahedral_graph, #each_bfs_edge, #each_bfs_node, #each_dfs_edge, #each_dfs_postorder_node, #each_dfs_preorder_node, #each_node, #edges, empty_graph, #get_edge_data, #get_node_data, heawood_graph, house_graph, house_x_graph, #info, #initialize, ladder_graph, lollipop_graph, moebius_kantor_graph, #neighbours, #node?, null_graph, #number_of_nodes, octahedral_graph, path_graph, #put_graph_x2, read_edgelist, read_weighted_edgelist, #remove_edges, #remove_node, #remove_nodes, star_graph, tetrahedral_graph, trivial_graph, wheel_graph
+This class inherits a constructor from NetworkX::Graph
+ +Stores the edges and their attributes in an adjencency list form
+ + +
+ + + +8 +9 +10+ |
+
+ # File 'lib/networkx/multigraph.rb', line 8 + +def adj + @adj +end+ |
+
Stores the attributes of the gra
+ + +
+ + + +8 +9 +10+ |
+
+ # File 'lib/networkx/multigraph.rb', line 8 + +def graph + @graph +end+ |
+
Stores the nodes and their attributes
+ + +
+ + + +8 +9 +10+ |
+
+ # File 'lib/networkx/multigraph.rb', line 8 + +def nodes + @nodes +end+ |
+
Adds the respective edge
+ + +
+ + + +32 +33 +34 +35 +36 +37 +38 +39 +40+ |
+
+ # File 'lib/networkx/multigraph.rb', line 32 + +def add_edge(node1, node2, **edge_attrs) + add_node(node1) + add_node(node2) + key = new_edge_key(node1, node2) + all_edge_attrs = @adj[node1][node2] || {} + all_edge_attrs[key] = edge_attrs + @adj[node1][node2] = all_edge_attrs + @adj[node2][node1] = all_edge_attrs +end+ |
+
+ + + +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124+ |
+
+ # File 'lib/networkx/multigraph.rb', line 112 + +def each_edge(data: false) + return enum_for(:each_edge, data: data) unless block_given? + + @adj.each do |v, ws| + ws.each do |w, key_and_info| + next if v > w + + key_and_info.each do |key, info| + data ? yield(v, w, key, info) : yield(v, w, key) + end + end + end +end+ |
+
Checks if the the edge consisting of two nodes is present in the graph
+ + +
+ + + +98 +99 +100 +101 +102+ |
+
+ # File 'lib/networkx/multigraph.rb', line 98 + +def edge?(node1, node2, key = nil) + return super(node1, node2) if key.nil? + + node?(node1) && @adj[node1].has_key?(node2) && @adj[node1][node2].has_key?(key) +end+ |
+
Returns subgraph conisting of given edges
+ + +
+ + + +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193+ |
+
+ # File 'lib/networkx/multigraph.rb', line 176 + +def edge_subgraph(edges) + case edges + when Array, Set + sub_graph = NetworkX::MultiGraph.new(**@graph) + edges.each do |u, v| + raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.has_key?(u) \ + && @adj[u].has_key?(v) + + sub_graph.add_node(u, **@nodes[u]) + sub_graph.add_node(v, **@nodes[v]) + @adj[u][v].each { |_, keyval| sub_graph.add_edge(u, v, **keyval) } + end + sub_graph + else + raise ArgumentError, 'Expected Argument to be Array or Set of edges, ' \ + "received #{edges.class.name} instead." + end +end+ |
+
+ + + +104 +105 +106 +107 +108 +109 +110+ |
+
+ # File 'lib/networkx/multigraph.rb', line 104 + +def has_edge?(node1, node2, key = nil) + return super(node1, node2) if key.nil? + + return false unless node?(node1) && @adj[node1].has_key?(node2) + + @adj[node1][node2].any? { |_index, data| data[:key] == key } +end+ |
+
+ + + +195 +196 +197+ |
+
+ # File 'lib/networkx/multigraph.rb', line 195 + +def multigraph? + true +end+ |
+
Returns a new key
+ + +
+ + + +13 +14 +15 +16 +17 +18 +19+ |
+
+ # File 'lib/networkx/multigraph.rb', line 13 + +def new_edge_key(node1, node2) + return 0 if @adj[node1][node2].nil? + + key = @adj[node1][node2].length + key += 1 while @adj[node1][node2].has_key?(key) + key +end+ |
+
Returns number of edges
+ + +
+ + + +86 +87 +88+ |
+
+ # File 'lib/networkx/multigraph.rb', line 86 + +def number_of_edges + @adj.values.flat_map(&:values).map(&:length).sum / 2 +end+ |
+
Removes edge from the graph
+ + +
+ + + +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62+ |
+
+ # File 'lib/networkx/multigraph.rb', line 49 + +def remove_edge(node1, node2, key = nil) + return super(node1, node2) if key.nil? + + raise KeyError, "#{node1} is not a valid node." unless @nodes.has_key?(node1) + raise KeyError, "#{node2} is not a valid node" unless @nodes.has_key?(node2) + raise KeyError, 'The given edge is not a valid one.' unless @adj[node1].has_key?(node2) + + if @adj[node1][node2].none? { |_index, data| data[:key] == key } + raise KeyError, 'The given edge is not a valid one' + end + + @adj[node1][node2].delete_if { |_indx, data| data[:key] == key } + @adj[node2][node1].delete_if { |_indx, data| data[:key] == key } +end+ |
+
Returns the size of the graph
+ + +
+ + + +71 +72 +73 +74 +75 +76 +77 +78 +79 +80+ |
+
+ # File 'lib/networkx/multigraph.rb', line 71 + +def size(is_weighted = false) + if is_weighted + graph_size = 0 + @adj.each do |_, hash_val| + hash_val.each { |_, v| v.each { |_, attrs| graph_size += attrs[:weight] if attrs.has_key?(:weight) } } + end + return graph_size / 2 + end + number_of_edges +end+ |
+
Returns subgraph consisting of given array of nodes
+ + +
+ + + +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168+ |
+
+ # File 'lib/networkx/multigraph.rb', line 149 + +def subgraph(nodes) + case nodes + when Array, Set + sub_graph = NetworkX::MultiGraph.new(**@graph) + nodes.each do |u, _| + raise KeyError, "#{u} does not exist in the current graph!" unless @nodes.has_key?(u) + + sub_graph.add_node(u, **@nodes[u]) + @adj[u].each do |v, edge_val| + next if u > v + + edge_val.each { |_, keyval| sub_graph.add_edge(u, v, **keyval) if @adj[u].has_key?(v) && nodes.include?(v) } + end + end + sub_graph + else + raise ArgumentError, 'Expected Argument to be Array or Set of nodes, ' \ + "received #{nodes.class.name} instead." + end +end+ |
+
Returns the undirected version of the graph
+ + +
+ + + +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141+ |
+
+ # File 'lib/networkx/multigraph.rb', line 130 + +def to_undirected + graph = NetworkX::Graph.new(**@graph) + @nodes.each { |node, node_attr| graph.add_node(node, **node_attr) } + @adj.each do |node1, node1_edges| + node1_edges.each do |node2, node1_node2| + edge_attrs = {} + node1_node2.each { |_key, attrs| edge_attrs.merge!(attrs) } + graph.add_edge(node1, node2, **edge_attrs) + end + end + graph +end+ |
+
Union Find Tree
+ +Reference - ac-library-rb DSU (CC0) - Python NetworkX UnionFind
+ + +Return parent of each element.
+Return weight of each element.
+Return the root of node.
+Is each root of two nodes the same?.
+Constructor for initializing Union Find Tree.
+Return the root of node.
+Unite nodes.
+Constructor for initializing Union Find Tree
+ + +
+ + + +19 +20 +21 +22 +23 +24 +25 +26+ |
+
+ # File 'lib/networkx/auxillary_functions/union_find.rb', line 19 + +def initialize(nodes = nil) + @weights = {} + @parents = {} + nodes&.each do |node| + @weights[node] = 1 + @parents[node] = node + end +end+ |
+
Return parent of each element
+ + +
+ + + +11 +12 +13+ |
+
+ # File 'lib/networkx/auxillary_functions/union_find.rb', line 11 + +def parents + @parents +end+ |
+
Return weight of each element
+ + +
+ + + +11 +12 +13+ |
+
+ # File 'lib/networkx/auxillary_functions/union_find.rb', line 11 + +def weights + @weights +end+ |
+
Return the root of node
+ + +
+ + + +33 +34 +35 +36 +37 +38 +39 +40+ |
+
+ # File 'lib/networkx/auxillary_functions/union_find.rb', line 33 + +def [](node) + if @parents.has_key?(node) + @parents[node] == node ? node : (@parents[node] = self[@parents[node]]) + else + @weights[node] = 1 + @parents[node] = node + end +end+ |
+
Is each root of two nodes the same?
+ + +
+ + + +68 +69 +70+ |
+
+ # File 'lib/networkx/auxillary_functions/union_find.rb', line 68 + +def connected?(node1, node2) + root(node1) == root(node2) +end+ |
+
+ + + +53 +54 +55+ |
+
+ # File 'lib/networkx/auxillary_functions/union_find.rb', line 53 + +def each(&block) + @parents.each_key(&block) +end+ |
+
+ + + +94 +95 +96 +97 +98 +99 +100 +101 +102+ |
+
+ # File 'lib/networkx/auxillary_functions/union_find.rb', line 94 + +def merge(node1, node2) + x = self[node1] + y = self[node2] + return if x == y + + x, y = y, x if @weights[x] < @weights[y] + @weights[x] += @weights[y] + @parents[y] = x +end+ |
+
Return the root of node
+ + +
+ + + +47 +48 +49 +50 +51+ |
+
+ # File 'lib/networkx/auxillary_functions/union_find.rb', line 47 + +def root(node) + @parents.has_key?(node) or raise ArgumentError.new, "#{node} is not a node" + + @parents[node] == node ? node : (@parents[node] = root(@parents[node])) +end+ |
+
+ + + +57 +58 +59+ |
+
+ # File 'lib/networkx/auxillary_functions/union_find.rb', line 57 + +def to_sets + each.group_by { |node| root(node) }.values +end+ |
+
Unite nodes.
+ + +
+ + + +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91+ |
+
+ # File 'lib/networkx/auxillary_functions/union_find.rb', line 78 + +def union(*nodes) + return merge(*nodes) if nodes.size == 2 + + roots = nodes.map { |node| self[node] }.uniq + return if roots.size == 1 + + roots.sort_by! { |root| @weights[root] } + root = roots[-1] + roots[0...-1].each do |r| + @weights[root] += @weights[r] + @parents[r] = root + end + root +end+ |
+
+
+
+
|
+
+
+
|
+
| t |