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 @@ + + + + + + + Class: Array + + — Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Array + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + +
+
Includes:
+
Comparable
+
+ + + + + + +
+
Defined in:
+
lib/networkx/others/grid_2d_graph.rb
+
+ +
+ + + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 851fabc..0000000 --- a/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source 'https://rubygems.org' -gemspec diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index 8be2421..0000000 --- a/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 [Athitya Kumar](https://github.com/athityakumar/). - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/NetworkX.html b/NetworkX.html new file mode 100644 index 0000000..cd36b4c --- /dev/null +++ b/NetworkX.html @@ -0,0 +1,17806 @@ + + + + + + + Module: NetworkX + + — Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: NetworkX + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
lib/networkx/others/grid_2d_graph.rb,
+ lib/networkx/graph.rb,
lib/networkx/digraph.rb,
lib/networkx/version.rb,
lib/networkx/to_matrix.rb,
lib/networkx/flow/utils.rb,
lib/networkx/multigraph.rb,
lib/networkx/others/info.rb,
lib/networkx/multidigraph.rb,
lib/networkx/others/reads.rb,
lib/networkx/operators/all.rb,
lib/networkx/others/bridges.rb,
lib/networkx/traversals/bfs.rb,
lib/networkx/traversals/dfs.rb,
lib/networkx/operators/unary.rb,
lib/networkx/flow/edmondskarp.rb,
lib/networkx/flow/preflowpush.rb,
lib/networkx/operators/binary.rb,
lib/networkx/converters/to_csv.rb,
lib/networkx/operators/product.rb,
lib/networkx/others/generators.rb,
lib/networkx/converters/to_json.rb,
lib/networkx/link_analysis/hits.rb,
lib/networkx/shortest_path/astar.rb,
lib/networkx/shortest_path/dense.rb,
lib/networkx/traversals/edge_dfs.rb,
lib/networkx/flow/capacityscaling.rb,
lib/networkx/link_analysis/pagerank.rb,
lib/networkx/shortest_path/weighted.rb,
lib/networkx/auxillary_functions/dag.rb,
lib/networkx/auxillary_functions/mis.rb,
lib/networkx/auxillary_functions/mst.rb,
lib/networkx/shortest_path/unweighted.rb,
lib/networkx/auxillary_functions/cycles.rb,
lib/networkx/auxillary_functions/wiener.rb,
lib/networkx/auxillary_functions/cliques.rb,
lib/networkx/flow/shortestaugmentingpath.rb,
lib/networkx/auxillary_functions/vitality.rb,
lib/networkx/auxillary_functions/union_find.rb,
lib/networkx/auxillary_functions/eccentricity.rb,
lib/networkx/others/number_connected_components.rb
+
+
+ +
+ +

Overview

+
+ + +

Defined Under Namespace

+

+ + + + + Classes: CurrentEdge, DiGraph, GlobalRelabelThreshold, Graph, Level, MultiDiGraph, MultiGraph, UnionFind + + +

+ + +

+ Constant Summary + collapse +

+ +
+ +
VERSION = + +
+
'0.4.0'.freeze
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + ._build_flow_dict(graph, residual) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + ._build_residual_network(graph) ⇒ Object + + + + + +

+
+ +

Returns the residual graph of the given graph

+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + ._detect_unboundedness(residual) ⇒ Object + + + + + +

+
+ +

Detects the unboundedness in the residual graph

+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .activate(node, source, target, levels, residual_nodes) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .all_pairs_dijkstra(graph, cutoff = nil) ⇒ Array<Object, Array<Hash{ Object => Numeric }, Hash{ Object => Array<Object> }>> + + + + + +

+
+ +

Finds shortest weighted paths and lengths between all nodes

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGrhelp_dijkaph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the dijkstra algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object, Array<Hash{ Object => Numeric }, Hash{ Object => Array<Object> }>>) + + + + — +
    +

    paths and path 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
+
+
+ +
+

+ + .all_pairs_dijkstra_path(graph, cutoff = nil) ⇒ Array<Object, Hash{ Object => Array<Object> }> + + + + + +

+
+ +

Finds shortest weighted paths between all nodes

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the dijkstra algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object, Hash{ Object => Array<Object> }>) + + + + — +
    +

    path lengths 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
+
+
+ +
+

+ + .all_pairs_dijkstra_path_length(graph, cutoff = nil) ⇒ Array<Object, Hash{ Object => Numeric }> + + + + + +

+
+ +

Finds shortest weighted path length between all nodes

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the dijkstra algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object, Hash{ Object => Numeric }>) + + + + — +
    +

    path lengths 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
+
+
+ +
+

+ + .all_pairs_shortest_path(graph, cutoff = nil) ⇒ Array<Object, Hash {Object => Array<Object> }> + + + + + +

+
+ +

Computes shortest paths to all nodes from all nodes

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the shortest path algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object, Hash {Object => Array<Object> }>) + + + + — +
    +

    paths for 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
+
+
+ +
+

+ + .all_pairs_shortest_path_length(graph, cutoff = nil) ⇒ Array<Object, Array<Object, Numeric>> + + + + + +

+
+ +

Computes shortest path values to all nodes from all nodes

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the shortest path algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object, Array<Object, Numeric>>) + + + + — +
    +

    path lengths for 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
+
+
+ +
+

+ + .allpairs_bellmanford_path(graph, cutoff = nil) ⇒ Array<Object, Hash{ Object => Array<Object> }> + + + + + +

+
+ +

Shortest paths between all nodes using Bellman Ford algorithm

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for Bellman Ford algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object, Hash{ Object => Array<Object> }>) + + + + — +
    +

    path lengths from source to all nodes

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .allpairs_bellmanford_path_length(graph, cutoff = nil) ⇒ Array<Object, Hash{ Object => Numeric }> + + + + + +

+
+ +

Shortest path lengths between all nodes using Bellman Ford algorithm

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for Bellman Ford algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object, Hash{ Object => Numeric }>) + + + + — +
    +

    path lengths from source to all nodes

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .ancestors(graph, source) ⇒ Array<Object> + + + + + +

+
+ +

Returns the ancestors of a given node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    node to find ancestors of

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object>) + + + + — +
    +

    Array of the ancestors

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .arbitrary_element(iterable) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .astar_path(graph, source, target, heuristic = nil) ⇒ Array<Object> + + + + + +

+
+ +

Returns path using astar algorithm between source and target

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    a node to start astar from

    +
    + +
  • + +
  • + + target + + + (Object) + + + + — +
    +

    a node to end astar

    +
    + +
  • + +
  • + + heuristic + + + + + + (defaults to: nil) + + + — +
    +

    [] a lambda to compute heuristic b/w two nodes

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object>) + + + + — +
    +

    an array of nodes forming a path between source and target

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .astar_path_length(graph, source, target, heuristic = nil) ⇒ Numeric + + + + + +

+
+ +

Returns astar path length b/w source and target

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    a node to start astar from

    +
    + +
  • + +
  • + + target + + + (Object) + + + + — +
    +

    a node to end astar

    +
    + +
  • + +
  • + + heuristic + + + + + + (defaults to: nil) + + + — +
    +

    [] a lambda to compute heuristic b/w two nodes

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Numeric) + + + + — +
    +

    the length of the path

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .augment(residual, inf, path) ⇒ Object + + + + + +

+
+ +

Helper function to augment the flow in a residual graph

+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .authority_matrix(graph) ⇒ Matrix + + + + + +

+
+ +

Computes authority matrix for the graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Matrix) + + + + — +
    +

    authority matrix for the graph

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+45
+46
+47
+48
+
+
# File 'lib/networkx/link_analysis/hits.rb', line 45
+
+def self.authority_matrix(graph)
+  matrix, = to_matrix(graph, 0)
+  matrix.transpose * matrix
+end
+
+
+ +
+

+ + .bellmanford_path(graph, source, target) ⇒ Array<Object> + + + + + +

+
+ +

Shortest path from source to target using Bellman Ford algorithm

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source

    +
    + +
  • + +
  • + + target + + + (Object) + + + + — +
    +

    target

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object>) + + + + — +
    +

    path from source to target

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .bellmanford_path_length(graph, source, target) ⇒ Numeric + + + + + +

+
+ +

Length of shortest path from source to target using Bellman Ford algorithm

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source

    +
    + +
  • + +
  • + + target + + + (Object) + + + + — +
    +

    target

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Numeric) + + + + — +
    +

    distance between source and target

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .bellmanford_predecesor_distance(graph, source, target = nil, cutoff = nil) ⇒ Array<Hash{ Object => Array<Object> }, Hash{ Object => Numeric }> + + + + + +

+
+ +

Finds shortest weighted path lengths and predecessors on shortest paths

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source

    +
    + +
  • + +
  • + + target + + + (Object, nil) + + + (defaults to: nil) + + + — +
    +

    target

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the dijkstra algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Hash{ Object => Array<Object> }, Hash{ Object => Numeric }>) + + + + — +
    +

    predecessors and distances

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .bfs_edges(graph, source) ⇒ Object + + + + + +

+
+ +

Returns edges of the graph travelled in breadth first fashion

+ + +
+
+
+ +
+

Examples:

+ + +
NetworkX.bfs_edges(graph, source)
+ +
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    node to start bfs from

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (KeyError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .bfs_predecessors(graph, source) ⇒ Object + + + + + +

+
+ +

Returns predecessor child pair of the graph travelled in breadth first fashion

+ + +
+
+
+ +
+

Examples:

+ + +
NetworkX.bfs_predecessors(graph, source)
+ +
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    node to start bfs from

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .bfs_successors(graph, source) ⇒ Object + + + + + +

+
+ +

Returns parent successor pair of the graph travelled in breadth first fashion

+ + +
+
+
+ +
+

Examples:

+ + +
NetworkX.bfs_successors(graph, source)
+ +
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    node to start bfs from

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .bidirectional_bfs(residual, source, target) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .bridges(graph) ⇒ [Object, Object] + + + + + +

+
+ +

Returns bridges.

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph) + + + + — +
    +

    Graph

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + ([Object, Object]) + + + + — +
    +

    bridges

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/networkx/others/bridges.rb', line 7
+
+def self.bridges(graph)
+  each_bridge(graph).to_a
+end
+
+
+ +
+

+ + .build_flow_dict(graph, residual) ⇒ Hash{ Object => Hash{ Object => Numeric }] flowdict containing all +the flow values in the edges + + + + + +

+
+ +

Build flow dictionary of a graph from its residual graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + residual + + + (DiGraph) + + + + — +
    +

    residual graph

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Hash{ Object => Numeric }] flowdict containing all +the flow values in the edges) + + + + — +
    +

    Hash{ Object => Hash{ Object => Numeric }] flowdict containing all the flow values in the edges

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .build_residual_network(graph) ⇒ DiGraph + + + + + +

+
+ +

Builds a residual graph from a constituent graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (DiGraph) + + + + — +
    +

    residual graph

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (NotImplementedError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .capacity_scaling(graph) ⇒ Array<Numeric, Hash{ Object => Hash{ Object => Numeric } }> + + + + + +

+
+ +

Computes max flow using capacity scaling algorithm

+ + +
+
+
+

Parameters:

+ + +

Returns:

+
    + +
  • + + + (Array<Numeric, Hash{ Object => Hash{ Object => Numeric } }>) + + + + — +
    +

    flow cost and flowdict containing all the flow values in the edges

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .cartesian_product(g1, g2) ⇒ Graph, ... + + + + + +

+
+ +

Returns the cartesian product of two graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .closeness_vitality(graph, node) ⇒ Numeric + + + + + +

+
+ +

Returns the closeness vitality of a node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + node + + + (Object) + + + + — +
    +

    node to compute closeness vitality of

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Numeric) + + + + — +
    +

    closeness vitality of the given 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
+
+
+ +
+

+ + .complement(graph) ⇒ Graph, ... + + + + + +

+
+ +

Performs the complement operation on the graph

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .compose(g1, g2) ⇒ Graph, ... + + + + + +

+
+ +

Performs the composition of two graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .compose_all(graphs) ⇒ Graph, ... + + + + + +

+
+ +

Performs the composition of many graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .convert_to_distinct_labels(graph, starting_int = -1)) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .cycle?(undirected_graph) ⇒ book + + + + + +

+
+ +

Returns whether the given undirected cycle has cycle.

+ + +
+
+
+

Parameters:

+
    + +
  • + + undirected_graph + + + (Graph) + + + + — +
    +

    an undirected graph

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (book) + + + + — +
    +

    true if the given graph has cycle. otherwise, false.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .cycle_basis(graph, root = nil) ⇒ Array<Array<Object>> + + + + + +

+
+ +

Returns all basis cycles in graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + root + + + (Object, Nil) + + + (defaults to: nil) + + + — +
    +

    root for the graph cycles

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Array<Object>>) + + + + — +
    +

    Arrays of nodes in the cycles

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .descendants(graph, source) ⇒ Array<Object> + + + + + +

+
+ +

Returns the descendants of a given node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    node to find descendents of

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object>) + + + + — +
    +

    Array of the descendants

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .detect_unboundedness(r_network, source, target) ⇒ Object + + + + + +

+
+ +

Detects unboundedness in a graph, raises exception when infinite capacity flow is found

+ + +
+
+
+

Parameters:

+
    + +
  • + + r_network + + + (DiGraph) + + + + — +
    +

    a residual graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source node

    +
    + +
  • + +
  • + + target + + + (Object) + + + + — +
    +

    target node

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .dfs_edges(graph, source, depth_limit = nil) ⇒ Object + + + + + +

+
+ +

Returns edges of the graph travelled in depth first fashion

+ + +
+
+
+ +
+

Examples:

+ + +
NetworkX.dfs_edges(graph, source)
+ +
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    node to start dfs from

    +
    + +
  • + +
  • + + depth_limit + + + (Integer, nil) + + + (defaults to: nil) + + + — +
    +

    the depth limit of dfs

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (KeyError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .dfs_predecessors(graph, source, depth_limit = nil) ⇒ Object + + + + + +

+
+ +

Returns predecessor child pair of the graph travelled in depth first fashion

+ + +
+
+
+ +
+

Examples:

+ + +
NetworkX.dfs_predecessors(graph, source)
+ +
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    node to start dfs from

    +
    + +
  • + +
  • + + depth_limit + + + (Integer, nil) + + + (defaults to: nil) + + + — +
    +

    the depth limit of dfs

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .dfs_successors(graph, source, depth_limit = nil) ⇒ Object + + + + + +

+
+ +

Returns parent successor pair of the graph travelled in depth first fashion

+ + +
+
+
+ +
+

Examples:

+ + +
NetworkX.dfs_successors(graph, source)
+ +
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    node to start dfs from

    +
    + +
  • + +
  • + + depth_limit + + + (Integer, nil) + + + (defaults to: nil) + + + — +
    +

    the depth limit of dfs

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .dfs_tree(graph, source, depth_limit = nil) ⇒ Object + + + + + +

+
+ +

Returns dfs tree of the graph

+ + +
+
+
+ +
+

Examples:

+ + +
NetworkX.dfs_tree(graph, source)
+ +
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    node to start dfs from

    +
    + +
  • + +
  • + + depth_limit + + + (Integer, nil) + + + (defaults to: nil) + + + — +
    +

    the depth limit of dfs

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .diameter(graph) ⇒ Numeric + + + + + +

+
+ +

Returns the diameter of a graph

+ + +
+
+
+

Parameters:

+ + +

Returns:

+
    + +
  • + + + (Numeric) + + + + — +
    +

    diameter of the graph

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+25
+26
+27
+
+
# File 'lib/networkx/auxillary_functions/eccentricity.rb', line 25
+
+def self.diameter(graph)
+  eccentricity(graph).values.max
+end
+
+
+ +
+

+ + .difference(g1, g2) ⇒ Graph, ... + + + + + +

+
+ +

Performs the difference of two graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .dijkstra_path(graph, source, target) ⇒ Numeric + + + + + +

+
+ +

Computes shortest path to target from the given node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source

    +
    + +
  • + +
  • + + target + + + (Object) + + + + — +
    +

    target

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Numeric) + + + + — +
    +

    path for target node from 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
+
+
+ +
+

+ + .dijkstra_path_length(graph, source, target) ⇒ Numeric + + + + + +

+
+ +

Computes shortest path length to target from the given node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source

    +
    + +
  • + +
  • + + target + + + (Object) + + + + — +
    +

    target

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Numeric) + + + + — +
    +

    path length for target node from given node

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (KeyError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .dijkstra_predecessor_distance(graph, source, cutoff = nil) ⇒ <Array<Hash{ Object => Array<Object> }, Hash{ Object => Numeric }>] +predcessor hash and distance hash + + + + + +

+
+ +

Computes weighted shortest path length and predecessors

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the dijkstra algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (<Array<Hash{ Object => Array<Object> }, Hash{ Object => Numeric }>] +predcessor hash and distance hash) + + + + — +
    +

    <Array<Hash{ Object => Array<Object> }, Hash{ Object => Numeric }>] predcessor hash and distance hash

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .directed_edges_cross_edges(g1, g2) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .discharge(u_node, is_phase1, residual_nodes, residual_adj, height, levels, grt, source, target) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .disjoint_union(g1, g2) ⇒ Graph, ... + + + + + +

+
+ +

Performs the disjoint union of two graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .disjoint_union_all(graphs) ⇒ Graph, ... + + + + + +

+
+ +

Performs the disjoint union of many graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .dist_path_lambda(_graph, _new_weight) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .each_bridge(graph) ⇒ Object + + + + + +

+
+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph) + + + + — +
    +

    Graph

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .eccentricity(graph, node = nil) ⇒ Array<Numeric>, Numeric + + + + + +

+
+ +

Returns the eccentricity of a particular node or all nodes

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + node + + + (Object) + + + (defaults to: nil) + + + — +
    +

    node to find the eccentricity of

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Numeric>, Numeric) + + + + — +
    +

    eccentricity/eccentricites of 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
+
+
+ +
+

+ + .edge_dfs(graph, start, orientation = nil) ⇒ Object + + + + + +

+
+ +

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

+ + +
+
+
+ +
+

Examples:

+ + +
NetworkX.edge_dfs(graph, source, 'ignore')
+ +
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + start + + + (Object) + + + + — +
    +

    node to start dfs from

    +
    + +
  • + +
  • + + orientation + + + (:ignore, :reverse', nil) + + + (defaults to: nil) + + + — +
    +

    the orientation of edges of graph

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .edge_id(graph, edge) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .edges_cross_nodes(g1, g2) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .edges_cross_nodes_and_nodes(g1, g2) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .edges_in_array(graph) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .edmondskarp(graph, source, target, residual = nil, cutoff = nil) ⇒ DiGraph + + + + + +

+
+ +

Computes max flow using edmonds karp algorithm

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source node

    +
    + +
  • + +
  • + + target + + + (Object) + + + + — +
    +

    target node

    +
    + +
  • + +
  • + + residual + + + (DiGraph, nil) + + + (defaults to: nil) + + + — +
    +

    residual graph

    +
    + +
  • + +
  • + + cutoff + + + (Numeric) + + + (defaults to: nil) + + + — +
    +

    cutoff for the algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (DiGraph) + + + + — +
    +

    a residual graph containing the flow values

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .edmondskarp_core(residual, source, target, cutoff) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .edmondskarp_impl(graph, source, target, residual, cutoff) ⇒ Object + + + + + +

+
+ +

Helper function for the edmondskarp function

+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .find_cliques(graph) ⇒ Array<Array<Object>> + + + + + +

+
+ +

Returns all cliques in the graph

+ + +
+
+
+

Parameters:

+ + +

Returns:

+
    + +
  • + + + (Array<Array<Object>>) + + + + — +
    +

    Arrays of nodes in the cliques

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .find_cycle(graph, node) ⇒ Array<Array<Object>> + + + + + +

+
+ +

Returns the cycle containing the given node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + node + + + (Object) + + + + — +
    +

    node to be included in the cycle

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Array<Object>>) + + + + — +
    +

    Arrays of nodes in the cycle

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .floyd_warshall(graph) ⇒ Hash{ Object => { Object => { Numeric }}} + + + + + +

+
+ +

Returns the all pair distance between all the nodes

+ + +
+
+
+

Parameters:

+ + +

Returns:

+
    + +
  • + + + (Hash{ Object => { Object => { Numeric }}}) + + + + — +
    +

    a hash containing distances b/w all pairs of 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
+
+
+ +
+

+ + .gap_heuristic(height, levels, residual_nodes) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .generate_unique_nodeObject + + + + + +

+
+ +

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
+
+
+ +
+

+ + .get_edges(graph) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .get_edges_weights(graph) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .get_sources(graph) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .get_weight(graph) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .global_relabel(from_sink, source, target, residual_nodes, num, levels, residual_pred) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .graph_to_csv(graph, filename = 'graph.csv') ⇒ Object + + + + + +

+
+ +

Saves the graph in a csv file

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + filename + + + (String) + + + (defaults to: 'graph.csv') + + + — +
    +

    filename of the graph

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .graph_to_json(graph) ⇒ JSON + + + + + +

+
+ +

Returns a JSON object of the given graph

+ + +
+
+
+

Parameters:

+ + +

Returns:

+
    + +
  • + + + (JSON) + + + + — +
    +

    json encoded 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
+
+
+ +
+

+ + .grid_2d_graph(m, n, periodic: false, create_using: NetworkX::Graph) ⇒ Object + + + + + +

+
+ + +
+
+
+

Parameters:

+
    + +
  • + + m + + + (Integer) + + + + — +
    +

    the number of rows

    +
    + +
  • + +
  • + + n + + + (Integer) + + + + — +
    +

    the number of columns

    +
    + +
  • + +
  • + + create_using + + + (Class) + + + (defaults to: NetworkX::Graph) + + + — +
    +

    graph class. this is optional. default is NetworkX::Graph.

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .hash_product(hash1, hash2) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .help_bellman_ford(graph, sources, weight, pred = nil, paths = nil, dist = nil, cutoff = nil, target = nil) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .help_dijkstra(graph, source, weight, pred = nil, paths = nil, cutoff = nil, target = nil) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .help_multisource_dijkstra(graph, sources, weight, pred = nil, paths = nil, cutoff = nil, target = nil) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .help_single_shortest_path(adj, firstlevel, paths, cutoff) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .help_single_shortest_path_length(adj, firstlevel, cutoff) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .hits(graph, max_iter = 100, tol = 1e-8, nstart) ⇒ Array<Numeric, Numeric> + + + + + +

+
+ +

Computes hits and authority scores for all the graphs

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + max_iter + + + (Integer) + + + (defaults to: 100) + + + — +
    +

    max iterations to run the hits algorithm

    +
    + +
  • + +
  • + + tol + + + (Numeric) + + + (defaults to: 1e-8) + + + — +
    +

    tolerences to cut off the loop

    +
    + +
  • + +
  • + + nstart + + + (Array<Numeric>) + + + + — +
    +

    starting hub values for the nodes

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Numeric, Numeric>) + + + + — +
    +

    hits and authority scores

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .hub_matrix(graph) ⇒ Matrix + + + + + +

+
+ +

Computes hub matrix for the graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Matrix) + + + + — +
    +

    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
+
+
+ +
+

+ + .info(graph) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .init_product_graph(g1, g2) ⇒ Object + + + + + +

+
+ +

Initializes the product graph

+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .intersection(g1, g2) ⇒ Graph, ... + + + + + +

+
+ +

Performs the intersection of two graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .intersection_all(graphs) ⇒ Graph, ... + + + + + +

+
+ +

Performs the intersection of many graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .johnson(graph) ⇒ Array<Object, Hash { Object => Array<Object> }] shortest paths between all pairs of nodes + + + + + +

+
+ +

Returns shortest path between all pairs of nodes

+ + +
+
+
+

Parameters:

+ + +

Returns:

+
    + +
  • + + + (Array<Object, Hash { Object => Array<Object> }] shortest paths between all pairs of nodes) + + + + — +
    +

    Array<Object, Hash { Object => Array<Object> }] shortest paths 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
+
+
+ +
+

+ + .json_to_graph(json_str) ⇒ Graph, ... + + + + + +

+
+ +

Returns a graph from the json encoded graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + json_str + + + (JSON) + + + + — +
    +

    json encoded string

    +
    + +
  • + +
+ +

Returns:

+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .lexicographic_product(g1, g2) ⇒ Graph, ... + + + + + +

+
+ +

Returns the lexicographic product of two graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .maximal_independent_set(graph, nodes) ⇒ Numeric + + + + + +

+
+ +

Returns the maximal independent set of a graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + nodes + + + (Object) + + + + — +
    +

    nodes to be considered in the MIS

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Numeric) + + + + — +
    +

    radius of the 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
+
+
+ +
+

+ + .minimum_spanning_tree(graph) ⇒ DiGraph, Graph + + + + + +

+
+ +

Returns the minimum spanning tree of a graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (DiGraph, Graph) + + + + — +
    +

    a minimum spanning tree of the 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
+
+
+ +
+

+ + .multisource_dijkstra(graph, sources, target = nil, cutoff = nil) ⇒ Numeric, Array<Object> + + + + + +

+
+ +

Computes shortest paths and path lengths to a target from one of the nodes

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + sources + + + (Array<Object>) + + + + — +
    +

    Array of sources

    +
    + +
  • + +
  • + + target + + + (Object, nil) + + + (defaults to: nil) + + + — +
    +

    target node for the dijkstra algorithm

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the dijkstra algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Numeric, Array<Object>) + + + + — +
    +

    path lengths for all nodes

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ValueError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .multisource_dijkstra_path(graph, sources, cutoff = nil) ⇒ Hash{ Object => Array<Object> } + + + + + +

+
+ +

Computes shortest paths to any from the given nodes

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + sources + + + (Array<Object>) + + + + — +
    +

    Array of sources

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the dijkstra algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Array<Object> }) + + + + — +
    +

    paths for any nodes from 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
+
+
+ +
+

+ + .multisource_dijkstra_path_length(graph, sources, cutoff = nil) ⇒ Hash{ Object => Numeric } + + + + + +

+
+ +

Computes shortest path lengths to any from the given nodes

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + sources + + + (Array<Object>) + + + + — +
    +

    Array of sources

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the dijkstra algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Numeric }) + + + + — +
    +

    path lengths for any nodes from given nodes

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ValueError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .negative_edge_cycle(graph) ⇒ Boolean + + + + + +

+
+ +

Finds if there is a negative edge cycle in the graph

+ + +
+
+
+

Parameters:

+ + +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +
    +

    whether there exists a negative cycle in 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
+
+
+ +
+

+ + .node_product(g1, g2) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .nodes_cross_edges(g1, g2) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .number_connected_components(graph) ⇒ Integer + + + + Also known as: + number_of_connected_components + + + + +

+
+ +

Returns the number of connected components on graph.

+ + +
+
+
+

Parameters:

+ + +

Returns:

+
    + +
  • + + + (Integer) + + + + — +
    +

    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
+
+
+ +
+

+ + .number_of_bridges(graph) ⇒ Integer + + + + + +

+
+ +

Returns the number of bridges.

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph) + + + + — +
    +

    Graph

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Integer) + + + + — +
    +

    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
+
+
+ +
+

+ + .number_of_cliques(graph, node) ⇒ Numeric + + + + + +

+
+ +

Returns the number of cliques in a graph containing a node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, MultiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + node + + + (Object) + + + + — +
    +

    a node

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Numeric) + + + + — +
    +

    Number of cliques containing the given 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
+
+
+ +
+

+ + .out_edges(graph, node) ⇒ Object + + + + + +

+
+ +

Helper function for edge_dfs

+ + +
+
+
+

Parameters:

+ + + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .pagerank(graph, alpha: 0.85, personalization: nil, eps: 1e-6, max_iter: 100) ⇒ Hash of Object => Float + + + + + +

+
+ +

Computes pagerank values for the graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + alpha + + + (Numeric) + + + (defaults to: 0.85) + + + — +
    +

    the alpha value to compute the pagerank

    +
    + +
  • + +
  • + + eps + + + (Numeric) + + + (defaults to: 1e-6) + + + — +
    +

    tolerence to check for convergence

    +
    + +
  • + +
  • + + max_iter + + + (Integer) + + + (defaults to: 100) + + + — +
    +

    max iterations for the pagerank algorithm to run

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash of Object => Float) + + + + — +
    +

    pagerank values of 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
+
+
+ +
+

+ + .power(graph, pow) ⇒ Graph, ... + + + + + +

+
+ +

Returns the specified power of the graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    graph no.1

    +
    + +
  • + +
  • + + pow + + + (Numeric) + + + + — +
    +

    the power to which to raise the graph to

    +
    + +
  • + +
+ +

Returns:

+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .predecessor(graph, source, cutoff = nil, return_seen = false) ⇒ Array<Hash{ Object => Array<Object> }, Hash{ Object => Numeric }>, Hash{ Object => Array<Object> } + + + + + +

+
+ +

Computes shortest paths to all nodes from all nodes

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source for which predecessors are needed

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for finding predecessor

    +
    + +
  • + +
  • + + return_seen + + + (Boolean) + + + (defaults to: false) + + + — +
    +

    if true, returns seen dict

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Hash{ Object => Array<Object> }, Hash{ Object => Numeric }>, Hash{ Object => Array<Object> }) + + + + — +
    +

    predecessors of a given node and/or seen dict

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .preflowpush(graph, source, target, residual = nil, globalrelabel_freq = 1, value_only = false) ⇒ DiGraph + + + + + +

+
+ +

Computes max flow using preflow push algorithm

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source node

    +
    + +
  • + +
  • + + target + + + (Object) + + + + — +
    +

    target node

    +
    + +
  • + +
  • + + residual + + + (DiGraph, nil) + + + (defaults to: nil) + + + — +
    +

    residual graph

    +
    + +
  • + +
  • + + globalrelabel_freq + + + (Numeric) + + + (defaults to: 1) + + + — +
    +

    global relabel freq

    +
    + +
  • + +
  • + + value_only + + + (Boolean) + + + (defaults to: false) + + + — +
    +

    if false, compute maximum flow else maximum preflow

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (DiGraph) + + + + — +
    +

    a residual graph containing the flow values

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .preflowpush_impl(graph, source, target, residual, globalrelabel_freq, value_only) ⇒ Object + + + + + +

+
+ +

Helper function to apply the preflow push algorithm

+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .push(node1, node2, flow, residual_nodes, residual_adj) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .radius(graph) ⇒ Numeric + + + + + +

+
+ +

Returns the radius of a graph

+ + +
+
+
+

Parameters:

+ + +

Returns:

+
    + +
  • + + + (Numeric) + + + + — +
    +

    radius of the graph

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+34
+35
+36
+
+
# File 'lib/networkx/auxillary_functions/eccentricity.rb', line 34
+
+def self.radius(graph)
+  eccentricity(graph).values.min
+end
+
+
+ +
+

+ + .relabel(node, num, r_adj, r_nodes) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .reverse_bfs(src, residual_pred) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .set_path_lengths_johnson(graph, dist_path, new_weight) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .shortest_augmenting_path(graph, source, target, residual = nil, _value_only = false, two_phase = false, cutoff = nil) ⇒ DiGraph + + + + + +

+
+ +

Computes max flow using shortest augmenting path algorithm

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source node

    +
    + +
  • + +
  • + + target + + + (Object) + + + + — +
    +

    target node

    +
    + +
  • + +
  • + + residual + + + (DiGraph, nil) + + + (defaults to: nil) + + + — +
    +

    residual graph

    +
    + +
  • + +
  • + + _value_only + + + (Boolean) + + + (defaults to: false) + + + — +
    +

    if true, compute only the maximum flow value

    +
    + +
  • + +
  • + + two_phase + + + (Boolean) + + + (defaults to: false) + + + — +
    +

    if true, two phase variant is used

    +
    + +
  • + +
  • + + cutoff + + + (Numeric) + + + (defaults to: nil) + + + — +
    +

    cutoff value for the algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (DiGraph) + + + + — +
    +

    a residual graph containing the flow values

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .shortest_augmenting_path_impl(graph, source, target, residual, two_phase, cutoff) ⇒ Object + + + + + +

+
+ +

Helper function for running the shortest augmenting path algorithm

+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .single_source_shortest_path(graph, source, cutoff = nil) ⇒ Array<Object, Array<Object, Array<Object>>> + + + + + +

+
+ +

Computes single source shortest path from a node to every other node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source from which shortest paths are needed

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the shortest path algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object, Array<Object, Array<Object>>>) + + + + — +
    +

    path lengths for all nodes from all nodes

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .single_source_shortest_path_length(graph, source, cutoff = nil) ⇒ Array<Object, Numeric> + + + + + +

+
+ +

Computes shortest path values to all nodes from a given node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source to compute path length from

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the shortest path algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object, Numeric>) + + + + — +
    +

    path lengths for all nodes

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .singlesource_bellmanford(graph, source, target = nil, cutoff = nil) ⇒ Object + + + + + +

+
+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .singlesource_bellmanford_path(graph, source, cutoff = nil) ⇒ Hash{ Object => Array<Object> } + + + + + +

+
+ +

Shortest path from source to all nodes using Bellman Ford algorithm

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for Bellman Ford algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Array<Object> }) + + + + — +
    +

    path from source to all nodes

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .singlesource_bellmanford_path_length(graph, source, cutoff = nil) ⇒ Hash{ Object => Numeric } + + + + + +

+
+ +

Shortest path length from source to all nodes using Bellman Ford algorithm

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for Bellman Ford algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Numeric }) + + + + — +
    +

    path lengths from source to all nodes

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .singlesource_dijkstra(graph, source, target = nil, cutoff = nil) ⇒ Hash{ Object => Array<Object> }, Array<Object> + + + + + +

+
+ +

Computes shortest paths and path distances to all nodes/target from the given node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source

    +
    + +
  • + +
  • + + target + + + (Object) + + + (defaults to: nil) + + + — +
    +

    target

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the dijkstra algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Array<Object> }, Array<Object>) + + + + — +
    +

    paths for all nodes/target node from 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
+
+
+ +
+

+ + .singlesource_dijkstra_path(graph, source, cutoff = nil) ⇒ Hash{ Object => Array<Object> } + + + + + +

+
+ +

Computes shortest paths to all nodes from the given node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the dijkstra algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Array<Object> }) + + + + — +
    +

    paths for all nodes from 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
+
+
+ +
+

+ + .singlesource_dijkstra_path_length(graph, source, cutoff = nil) ⇒ Hash{ Object => Numeric } + + + + + +

+
+ +

Computes shortest path lengths to all nodes from the given node

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph, MultiGraph, MultiDiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
  • + + source + + + (Object) + + + + — +
    +

    source

    +
    + +
  • + +
  • + + cutoff + + + (Numeric, nil) + + + (defaults to: nil) + + + — +
    +

    cutoff for the dijkstra algorithm

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Numeric }) + + + + — +
    +

    path lengths for all nodes from 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
+
+
+ +
+

+ + .strong_product(g1, g2) ⇒ Graph, ... + + + + + +

+
+ +

Returns the strong product of two graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .symmetric_difference(g1, g2) ⇒ Graph, ... + + + + + +

+
+ +

Performs the symmetric difference of two graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .tensor_product(g1, g2) ⇒ Graph, ... + + + + + +

+
+ +

Returns the tensor product of two graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .to_matrix(graph, val, multigraph_weight = 'sum') ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .to_number_if_possible(str) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .topological_sort(graph) ⇒ Array<Object> + + + + + +

+
+ +

Returns the nodes arranged in the topologically sorted fashion

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array<Object>) + + + + — +
    +

    Array of the nodes

    +
    + +
  • + +
+

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .undirected_edges_cross_edges(g1, g2) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .union(g1, g2) ⇒ Graph, ... + + + + + +

+
+ +

Performs the union of two graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .union_all(graphs) ⇒ Graph, ... + + + + + +

+
+ +

Performs the union of many graphs

+ + +
+
+
+

Parameters:

+ + +

Returns:

+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .wiener_index(graph) ⇒ Numeric + + + + + +

+
+ +

Returns the wiener index of the graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + graph + + + (Graph, DiGraph) + + + + — +
    +

    a graph

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Numeric) + + + + — +
    +

    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
+
+
+ +
+ +
+

Instance Method Details

+ + +
+

+ + #augment(path, inf, r_adj) ⇒ Object + + + + + +

+
+ +

Helper function for augmenting flow

+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/NetworkX/CurrentEdge.html b/NetworkX/CurrentEdge.html new file mode 100644 index 0000000..e942cd0 --- /dev/null +++ b/NetworkX/CurrentEdge.html @@ -0,0 +1,512 @@ + + + + + + + Class: NetworkX::CurrentEdge + + — Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: NetworkX::CurrentEdge + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/networkx/flow/utils.rb
+
+ +
+ +

Overview

+
+ +

Helper class for preflow push algorithm

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(edges) ⇒ 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
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #currObject (readonly) + + + + + +

+
+ +

Returns the value of attribute curr.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+4
+5
+6
+
+
# File 'lib/networkx/flow/utils.rb', line 4
+
+def curr
+  @curr
+end
+
+
+ + + +
+

+ + #edgesObject (readonly) + + + + + +

+
+ +

Returns the value of attribute edges.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+4
+5
+6
+
+
# File 'lib/networkx/flow/utils.rb', line 4
+
+def edges
+  @edges
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #getObject + + + + + +

+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/networkx/flow/utils.rb', line 14
+
+def get
+  [@index[@curr], @edges[@index[@curr]]]
+end
+
+
+ +
+

+ + #move_to_nextObject + + + + + +

+
+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (StopIteration) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/NetworkX/DiGraph.html b/NetworkX/DiGraph.html new file mode 100644 index 0000000..568374b --- /dev/null +++ b/NetworkX/DiGraph.html @@ -0,0 +1,2095 @@ + + + + + + + Class: NetworkX::DiGraph + + — Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: NetworkX::DiGraph + + + +

+
+ +
+
Inherits:
+
+ Graph + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/networkx/digraph.rb
+
+ +
+ +

Overview

+
+ +

Describes the class for making Directed Graphs

+ + +
+
+
+ + +
+

Direct Known Subclasses

+

MultiDiGraph

+
+ + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods inherited from 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 Details

+ +
+

+ + #initialize(**graph_attrs) ⇒ DiGraph + + + + + +

+
+ +

Constructor for initializing graph

+ + +
+
+
+ +
+

Examples:

+ + +

+

Initialize a graph with attributes ‘type’ and ‘name’

+

+ +
graph = NetworkX::Graph.new(name: "Social Network", type: "undirected")
+ +
+

Parameters:

+
    + +
  • + + graph_attrs + + + (Hash{ Object => Object }) + + + + — +
    +

    the graph attributes in a hash format

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+19
+20
+21
+22
+23
+
+
# File 'lib/networkx/digraph.rb', line 19
+
+def initialize(**graph_attrs)
+  super(**graph_attrs)
+
+  @pred = {}
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #adjHash{ Object => Hash{ Object => Hash{ Object => Object } } } (readonly) + + + + + +

+
+ +

Stores the edges and their attributes in an adjencency list form

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Hash{ Object => Hash{ Object => Object } } }) + + + + — +
    +

    the current value of adj

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+10
+11
+12
+
+
# File 'lib/networkx/digraph.rb', line 10
+
+def adj
+  @adj
+end
+
+
+ + + +
+

+ + #graphHash{ Object => Object } (readonly) + + + + + +

+
+ +

Stores the attributes of the graph

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Object }) + + + + — +
    +

    the current value of graph

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+10
+11
+12
+
+
# File 'lib/networkx/digraph.rb', line 10
+
+def graph
+  @graph
+end
+
+
+ + + +
+

+ + #nodes(data: true) ⇒ Hash{ Object => Hash{ Object => Object } } (readonly) + + + + + +

+
+ +

Stores the nodes and their attributes

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Hash{ Object => Object } }) + + + + — +
    +

    the current value of nodes

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+10
+11
+12
+
+
# File 'lib/networkx/digraph.rb', line 10
+
+def nodes
+  @nodes
+end
+
+
+ + + +
+

+ + #predHash{ Object => Hash{ Object => Hash{ Object => Object } } } (readonly) + + + + + +

+
+ +

Stores the reverse edges and their attributes in an adjencency list form

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Hash{ Object => Hash{ Object => Object } } }) + + + + — +
    +

    the current value of pred

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+10
+11
+12
+
+
# File 'lib/networkx/digraph.rb', line 10
+
+def pred
+  @pred
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #add_edge(node1, node2, **edge_attrs) ⇒ Object + + + + + +

+
+ +

Adds the respective edge

+ + +
+
+
+ +
+

Examples:

+ + +

+

Add an edge with attribute name

+

+ +
graph.add_edge(node1, node2, name: "Edge1")
+ + +

+

Add an edge with no attribute

+

+ +
graph.add_edge("Bangalore", "Chennai")
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge

    +
    + +
  • + +
  • + + edge_attrs + + + (Hash{ Object => Object }) + + + + — +
    +

    the hash of the edge attributes

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #add_node(node, **node_attrs) ⇒ Object + + + + + +

+
+ +

Adds a node and its attributes to the graph

+ + +
+
+
+ +
+

Examples:

+ + +

+

Add a node with attribute ‘type’

+

+ +
graph.add_node("Noida", type: "city")
+ +
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    the node object

    +
    + +
  • + +
  • + + node_attrs + + + (Hash{ Object => Object }) + + + + — +
    +

    the hash of the attributes of the node

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #clearObject + + + + + +

+
+ +

Clears the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.clear
+ +
+ + +
+ + + + +
+
+
+
+102
+103
+104
+105
+106
+
+
# File 'lib/networkx/digraph.rb', line 102
+
+def clear
+  super
+
+  @pred.clear
+end
+
+
+ +
+

+ + #directed?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+230
+231
+232
+
+
# File 'lib/networkx/digraph.rb', line 230
+
+def directed?
+  true
+end
+
+
+ +
+

+ + #edge_subgraph(edges) ⇒ Object + + + + + +

+
+ +

Returns subgraph consisting of given edges

+ + +
+
+
+ +
+

Examples:

+ + +
graph.edge_subgraph([%w[Nagpur Wardha], %w[Nagpur Mumbai]])
+ +
+

Parameters:

+
    + +
  • + + edges + + + (Array<Object, Object>) + + + + — +
    +

    the edges to be included in the subraph

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #in_degree(node) ⇒ Object + + + + + +

+
+ +

Returns in-degree of a given node

+ + +
+
+
+ +
+

Examples:

+ + +
graph.in_degree(node)
+ +
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    the node whose in degree is to be calculated

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+140
+141
+142
+
+
# File 'lib/networkx/digraph.rb', line 140
+
+def in_degree(node)
+  @pred[node].length
+end
+
+
+ +
+

+ + #number_of_edgesObject + + + + + +

+
+ +

Returns number of edges

+ + +
+
+
+ +
+

Examples:

+ + +
graph.number_of_edges
+ +
+ + +
+ + + + +
+
+
+
+112
+113
+114
+
+
# File 'lib/networkx/digraph.rb', line 112
+
+def number_of_edges
+  @adj.values.map(&:length).sum
+end
+
+
+ +
+

+ + #out_degree(node) ⇒ Object + + + + + +

+
+ +

Returns out-degree of a given node

+ + +
+
+
+ +
+

Examples:

+ + +
graph.out_degree(node)
+ +
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    the node whose out degree is to be calculated

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+150
+151
+152
+
+
# File 'lib/networkx/digraph.rb', line 150
+
+def out_degree(node)
+  @adj[node].length
+end
+
+
+ +
+

+ + #remove_edge(node1, node2) ⇒ Object + + + + + +

+
+ +

Removes edge from the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.remove_edge('Noida', 'Bangalore')
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (KeyError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #remove_node(node) ⇒ Object + + + + + +

+
+ +

Removes node from the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.remove_node("Noida")
+ +
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    the node to be removed

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (KeyError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #reverseObject + + + + + +

+
+ +

Returns the reversed version of the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.reverse
+ +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #size(is_weighted = false) ⇒ Object + + + + + +

+
+ +

Returns the size of graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.size(true)
+ +
+

Parameters:

+
    + +
  • + + is_weighted + + + (Bool) + + + (defaults to: false) + + + — +
    +

    if true, method returns sum of weights of all edges else returns number of edges

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #subgraph(nodes) ⇒ Object + + + + + +

+
+ +

Returns subgraph consisting of given array of nodes

+ + +
+
+
+ +
+

Examples:

+ + +
graph.subgraph(%w[Mumbai Nagpur])
+ +
+

Parameters:

+
    + +
  • + + nodes + + + (Array<Object>) + + + + — +
    +

    the nodes to be included in the subgraph

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #to_undirectedObject + + + + + +

+
+ +

Returns the undirected version of the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.to_undirected
+ +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/NetworkX/GlobalRelabelThreshold.html b/NetworkX/GlobalRelabelThreshold.html new file mode 100644 index 0000000..3d5f2df --- /dev/null +++ b/NetworkX/GlobalRelabelThreshold.html @@ -0,0 +1,402 @@ + + + + + + + Class: NetworkX::GlobalRelabelThreshold + + — Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: NetworkX::GlobalRelabelThreshold + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/networkx/flow/utils.rb
+
+ +
+ +

Overview

+
+ +

Helper class for preflow push algorithm

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(num1, num2, freq) ⇒ 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
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #add_work(work) ⇒ Object + + + + + +

+ + + + +
+
+
+
+43
+44
+45
+
+
# File 'lib/networkx/flow/utils.rb', line 43
+
+def add_work(work)
+  @work += work
+end
+
+
+ +
+

+ + #clear_workObject + + + + + +

+ + + + +
+
+
+
+51
+52
+53
+
+
# File 'lib/networkx/flow/utils.rb', line 51
+
+def clear_work
+  @work = 0
+end
+
+
+ +
+

+ + #reached?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+47
+48
+49
+
+
# File 'lib/networkx/flow/utils.rb', line 47
+
+def reached?
+  @work >= @threshold
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/NetworkX/Graph.html b/NetworkX/Graph.html new file mode 100644 index 0000000..3283eaa --- /dev/null +++ b/NetworkX/Graph.html @@ -0,0 +1,6501 @@ + + + + + + + Class: NetworkX::Graph + + — Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: NetworkX::Graph + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/networkx/graph.rb,
+ lib/networkx/others/reads.rb,
lib/networkx/traversals/bfs.rb,
lib/networkx/traversals/dfs.rb,
lib/networkx/others/generators.rb,
lib/networkx/traversals/edge_dfs.rb
+
+
+ +
+ +

Overview

+
+ +

Describes the class for making Undirected Graphs

+ + +
+
+
+ + +
+

Direct Known Subclasses

+

DiGraph, MultiGraph

+
+ + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Class Method Summary + collapse +

+ + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(**graph_attrs) ⇒ Graph + + + + + +

+
+ +

Constructor for initializing graph

+ + +
+
+
+ +
+

Examples:

+ + +

+

Initialize a graph with attributes ‘type’ and ‘name’

+

+ +
graph = NetworkX::Graph.new(name: "Social Network", type: "undirected")
+ +
+

Parameters:

+
    + +
  • + + graph_attrs + + + (Hash{ Object => Object }) + + + + — +
    +

    the graph attributes in a hash format

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+16
+17
+18
+19
+20
+
+
# File 'lib/networkx/graph.rb', line 16
+
+def initialize(**graph_attrs)
+  @nodes = {}
+  @adj = {}
+  @graph = graph_attrs
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #adjHash{ Object => Hash{ Object => Hash{ Object => Object } } } (readonly) + + + + + +

+
+ +

Stores the edges and their attributes in an adjencency list form

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Hash{ Object => Hash{ Object => Object } } }) + + + + — +
    +

    the current value of adj

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/networkx/graph.rb', line 7
+
+def adj
+  @adj
+end
+
+
+ + + +
+

+ + #graphHash{ Object => Object } (readonly) + + + + + +

+
+ +

Stores the attributes of the graph

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Object }) + + + + — +
    +

    the current value of graph

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/networkx/graph.rb', line 7
+
+def graph
+  @graph
+end
+
+
+ +
+ + +
+

Class Method Details

+ + +
+

+ + .balanced_tree(r, h) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .barbell_graph(m1, m2) ⇒ Object + + + + + +

+ + + + +
+
+
+
+38
+39
+40
+41
+42
+43
+44
+45
+46
+
+
# File 'lib/networkx/others/generators.rb', line 38
+
+def self.barbell_graph(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
+
+
+ +
+

+ + .bull_graphObject + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .circular_ladder_graph(n) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .complete_edges(n) ⇒ Object + + + + + +

+
+ +

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
+
+
+ +
+

+ + .complete_graph(n) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .cubical_graphObject + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .cycle_graph(n) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .diamond_graphObject + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .dodecahedral_graphObject + + + + + +

+
+ +

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
+
+
+ +
+

+ + .empty_graph(number_of_nodes) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .heawood_graphObject + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .house_graphObject + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .house_x_graphObject + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .ladder_graph(n) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .lollipop_graph(m, n) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .moebius_kantor_graphObject + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .null_graphObject + + + + + +

+ + + + +
+
+
+
+109
+110
+111
+
+
# File 'lib/networkx/others/generators.rb', line 109
+
+def self.null_graph
+  new(name: 'null_graph')
+end
+
+
+ +
+

+ + .octahedral_graphObject + + + + + +

+
+ +

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
+
+
+ +
+

+ + .path_graph(n) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .read_edgelist(path, comment: '#', delimiter: nil) ⇒ Object + + + + Also known as: + read_edges + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .read_weighted_edgelist(path, comment: '#', delimiter: nil) ⇒ Object + + + + Also known as: + read_weighted_edges + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .star_graph(n) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .tetrahedral_graphObject + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .trivial_graphObject + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + .wheel_graph(n) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+ +
+

Instance Method Details

+ + +
+

+ + #add_edge(node1, node2, **edge_attrs) ⇒ Object + + + + + +

+
+ +

Adds the respective edges

+ + +
+
+
+ +
+

Examples:

+ + +

+

Add an edge with attribute name

+

+ +
graph.add_edge(node1, node2, name: "Edge1")
+ + +

+

Add an edge with no attribute

+

+ +
graph.add_edge("Bangalore", "Chennai")
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge

    +
    + +
  • + +
  • + + edge_attrs + + + (Hash{ Object => Object }) + + + + — +
    +

    the hash of the edge attributes

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #add_edges(edges) ⇒ Object + + + + + +

+
+ +

Adds multiple edges from an array

+ + +
+
+
+ +
+

Examples:

+ + +

+

Add multiple edges without any attributes

+

+ +
graph.add_edges([['Nagpur', 'Kgp'], ['Noida', 'Kgp']])
+ +
+

Parameters:

+
    + +
  • + + edges + + + (Array<Object, Object>) + + + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #add_edges_from(rng) ⇒ Object + + + + + +

+ + + + +
+
+
+
+57
+58
+59
+
+
# File 'lib/networkx/graph.rb', line 57
+
+def add_edges_from(rng)
+  rng.each { |node| add_edge(*node) }
+end
+
+
+ +
+

+ + #add_node(node, **node_attrs) ⇒ Object + + + + + +

+
+ +

Adds a node and its attributes to the graph

+ + +
+
+
+ +
+

Examples:

+ + +

+

Add a node with attribute ‘type’

+

+ +
graph.add_node("Noida", type: "city")
+ +
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    the node object

    +
    + +
  • + +
  • + + node_attrs + + + (Hash{ Object => Object }) + + + + — +
    +

    the hash of the attributes of the node

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #add_nodes(nodes) ⇒ Object + + + + + +

+
+ +

Adds multiple nodes to the graph

+ + +
+
+
+ +
+

Examples:

+ + +

+

Adds multiple nodes with attribute ‘type’

+

+ +
graph.add_nodes([["Noida", type: "city"], ["Kgp", type: "town"]])
+ +
+

Parameters:

+
    + +
  • + + nodes + + + (Array<Object, Hash{ Object => Object }>) + + + + — +
    +

    the Array of pair containing nodes and its attributes

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #add_nodes_from(nodes_for_adding) ⇒ Object + + + + + +

+
+ +

[TODO]

+ + +
+
+
+

Parameters:

+
    + +
  • + + nodes_for_adding + + + (Array | Range | String) + + + + — +
    +

    nodes

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #add_path(paths) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #add_weighted_edge(node1, node2, weight) ⇒ Object + + + + + +

+
+ +

Adds weighted edge

+ + +
+
+
+ +
+

Examples:

+ + +
graph.add_weighted_edge('Noida', 'Bangalore', 1000)
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge

    +
    + +
  • + +
  • + + weight + + + (Integer) + + + + — +
    +

    the weight value

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+183
+184
+185
+
+
# File 'lib/networkx/graph.rb', line 183
+
+def add_weighted_edge(node1, node2, weight)
+  add_edge(node1, node2, weight: weight)
+end
+
+
+ +
+

+ + #add_weighted_edges(edges, weights) ⇒ Object + + + + + +

+
+ +

Adds multiple weighted edges

+ + +
+
+
+ +
+

Examples:

+ + +
graph.add_weighted_edges([['Noida', 'Bangalore'],
+                          ['Noida', 'Nagpur']], [1000, 2000])
+ +
+

Parameters:

+
    + +
  • + + edges + + + (Array<Object, Object>) + + + + — +
    +

    the array of edges

    +
    + +
  • + +
  • + + weights + + + (Array<Integer>) + + + + — +
    +

    the array of weights

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #add_weighted_edges_from(edges, weight: :weight) ⇒ Object + + + + + +

+
+ +

[TODO]

+ + +
+
+
+

Parameters:

+
    + +
  • + + edges + + + ([Object, Object, Integer|Float]) + + + + — +
    +

    the weight of edge

    +
    + +
  • + +
  • + + weight + + + (Symbol) + + + (defaults to: :weight) + + + — +
    +

    weight name key. default key is ‘:weight“

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #bfs_edges(node) ⇒ Object + + + + + +

+
+ +

[EXPERIMENTAL]

+ + +
+
+
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    which is root, start ,source

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+84
+85
+86
+
+
# File 'lib/networkx/traversals/bfs.rb', line 84
+
+def bfs_edges(node)
+  each_bfs_edge(node).to_a
+end
+
+
+ +
+

+ + #bfs_nodes(root) ⇒ Object + + + + + +

+ + + + +
+
+
+
+60
+61
+62
+
+
# File 'lib/networkx/traversals/bfs.rb', line 60
+
+def bfs_nodes(root)
+  each_bfs_node(root).to_a
+end
+
+
+ +
+

+ + #clearObject + + + + + +

+
+ +

Clears the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.clear
+ +
+ + +
+ + + + +
+
+
+
+270
+271
+272
+273
+274
+
+
# File 'lib/networkx/graph.rb', line 270
+
+def clear
+  @adj.clear
+  @nodes.clear
+  @graph.clear
+end
+
+
+ +
+

+ + #degree(nodes = nil) ⇒ Object + + + + + +

+
+ +

[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
+
+
+ +
+

+ + #dfs_edges(node) ⇒ Object + + + + + +

+ + + + +
+
+
+
+89
+90
+91
+
+
# File 'lib/networkx/traversals/edge_dfs.rb', line 89
+
+def dfs_edges(node)
+  each_dfs_edge(node).to_a
+end
+
+
+ +
+

+ + #dfs_postorder_nodes(root, used = {root => true}) ⇒ Array[Object] + + + + + +

+
+ +

[EXPERIMENTAL]

+ + +
+
+
+

Parameters:

+
    + +
  • + + root + + + (Object) + + + + — +
    +

    node which is root, start, source

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array[Object]) + + + + — +
    +

    array of dfs postorder nodes

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #dfs_preorder_nodes(root) ⇒ Array[Object] + + + + + +

+
+ +

[EXPERIMENTAL]

+ + +
+
+
+

Parameters:

+
    + +
  • + + root + + + (Object) + + + + — +
    +

    node which is root, start, source

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array[Object]) + + + + — +
    +

    nodes

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+86
+87
+88
+
+
# File 'lib/networkx/traversals/dfs.rb', line 86
+
+def dfs_preorder_nodes(root)
+  each_dfs_preorder_node(root).to_a
+end
+
+
+ +
+

+ + #directed?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+443
+444
+445
+
+
# File 'lib/networkx/graph.rb', line 443
+
+def directed?
+  ['NetworkX::DiGraph', 'NetworkX::MultiDiGraph'].include?(self.class.name)
+end
+
+
+ +
+

+ + #each_bfs_edge(node) ⇒ Object + + + + + +

+
+ +

[EXPERIMENTAL]

+ + +
+
+
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    which is root, start ,source

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #each_bfs_node(root) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #each_dfs_edge(node) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #each_dfs_postorder_node(root, &block) ⇒ Object + + + + + +

+
+ + +
+
+
+

Parameters:

+
    + +
  • + + root + + + (Object) + + + + — +
    +

    node which is root, start, source

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #each_dfs_preorder_node(root) ⇒ Object + + + + + +

+
+ +

[EXPERIMENTAL]

+ + +
+
+
+

Parameters:

+
    + +
  • + + root + + + (Object) + + + + — +
    +

    node which is root, start, source

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #each_edge(data: false) ⇒ Object + + + + + +

+
+ +

[TODO]

+ + +
+
+
+

Parameters:

+
    + +
  • + + data + + + (bool) + + + (defaults to: false) + + + — +
    +

    true if you want data of each edge

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #each_node(data: false, &block) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #edge?(node1, node2) ⇒ Boolean + + + + Also known as: + has_edge? + + + + +

+
+ +

Checks if the the edge consisting of two nodes is present in the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.edge?(node1, node2)
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge to be checked

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge to be checked

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+294
+295
+296
+
+
# File 'lib/networkx/graph.rb', line 294
+
+def edge?(node1, node2)
+  node?(node1) && @adj[node1].has_key?(node2)
+end
+
+
+ +
+

+ + #edge_subgraph(edges) ⇒ Object + + + + + +

+
+ +

Returns subgraph conisting of given edges

+ + +
+
+
+ +
+

Examples:

+ + +
graph.edge_subgraph([%w[Nagpur Wardha], %w[Nagpur Mumbai]])
+ +
+

Parameters:

+
    + +
  • + + edges + + + (Array<Object, Object>) + + + + — +
    +

    the edges to be included in the subraph

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #edges(data: false) ⇒ Array[[Object, Object]] + + + + + +

+
+ +

[TODO]

+ + +
+
+
+

Parameters:

+
    + +
  • + + data + + + (bool) + + + (defaults to: false) + + + — +
    +

    true if you want data of each edge

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Array[[Object, Object]]) + + + + — +
    +

    edges array

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+241
+242
+243
+
+
# File 'lib/networkx/graph.rb', line 241
+
+def edges(data: false)
+  each_edge(data: data).to_a
+end
+
+
+ +
+

+ + #get_edge_data(node1, node2) ⇒ Object + + + + + +

+
+ +

Gets the edge data

+ + +
+
+
+ +
+

Examples:

+ + +
graph.get_edge_data(node1, node2)
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (KeyError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #get_node_data(node) ⇒ Object + + + + + +

+
+ +

Gets the node data

+ + +
+
+
+ +
+

Examples:

+ + +
graph.get_node_data(node)
+ +
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    the node whose data is to be fetched

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #infoObject + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #multigraph?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+439
+440
+441
+
+
# File 'lib/networkx/graph.rb', line 439
+
+def multigraph?
+  ['NetworkX::MultiGraph', 'NetworkX::MultiDiGraph'].include?(self.class.name)
+end
+
+
+ +
+

+ + #neighbours(node) ⇒ Object + + + + + +

+
+ +

Retus a hash of neighbours of a node

+ + +
+
+
+ +
+

Examples:

+ + +
graph.neighbours(node)
+ +
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    the node whose neighbours are to be fetched

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (KeyError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #node?(node) ⇒ Boolean + + + + Also known as: + has_node? + + + + +

+
+ +

Checks if a node is present in the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.node?(node1)
+ +
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    the node to be checked

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+282
+283
+284
+
+
# File 'lib/networkx/graph.rb', line 282
+
+def node?(node)
+  @nodes.has_key?(node)
+end
+
+
+ +
+

+ + #nodes(data: false) ⇒ Hash | Array + + + + + +

+
+ +

Return nodes of graph

+ + +
+
+
+

Parameters:

+
    + +
  • + + data + + + (bool) + + + (defaults to: false) + + + — +
    +

    true if you want data of each edge

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Hash | Array) + + + + — +
    +

    if data is true, it returns hash including data. otherwise, simple nodes array.

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #number_of_edgesObject + + + + + +

+
+ +

Returns number of edges

+ + +
+
+
+ +
+

Examples:

+ + +
graph.number_of_edges
+ +
+ + +
+ + + + +
+
+
+
+348
+349
+350
+
+
# File 'lib/networkx/graph.rb', line 348
+
+def number_of_edges
+  @adj.values.map(&:length).sum / 2
+end
+
+
+ +
+

+ + #number_of_nodesObject + + + + + +

+
+ +

Returns number of nodes

+ + +
+
+
+ +
+

Examples:

+ + +
graph.number_of_nodes
+ +
+ + +
+ + + + +
+
+
+
+340
+341
+342
+
+
# File 'lib/networkx/graph.rb', line 340
+
+def number_of_nodes
+  @nodes.length
+end
+
+
+ +
+

+ + #put_graph_x2Object + + + + + +

+
+ +

Experimental For debug.

+ + +
+
+
+ +

Returns:

+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #remove_edge(node1, node2) ⇒ Object + + + + + +

+
+ +

Removes edge from the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.remove_edge('Noida', 'Bangalore')
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (KeyError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #remove_edges(edges) ⇒ Object + + + + Also known as: + remove_edges_from + + + + +

+
+ +

Removes multiple edges from the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.remove_edges([%w[Noida Bangalore], %w[Bangalore Chennai]])
+ +
+

Parameters:

+
    + +
  • + + edges + + + (Array<Object>) + + + + — +
    +

    the array of edges to be removed

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #remove_node(node) ⇒ Object + + + + + +

+
+ +

Removes node from the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.remove_node("Noida")
+ +
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    the node to be removed

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (KeyError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #remove_nodes(nodes) ⇒ Object + + + + Also known as: + remove_nodes_from + + + + +

+
+ +

Removes multiple nodes from the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.remove_nodes(["Noida", "Bangalore"])
+ +
+

Parameters:

+
    + +
  • + + nodes + + + (Array<Object>) + + + + — +
    +

    the array of nodes to be removed

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #size(is_weighted = false) ⇒ Object + + + + + +

+
+ +

Returns the size of the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.size(true)
+ +
+

Parameters:

+
    + +
  • + + is_weighted + + + (Bool) + + + (defaults to: false) + + + — +
    +

    if true, method returns sum of weights of all edges else returns number of edges

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #subgraph(nodes) ⇒ Object + + + + + +

+
+ +

Returns subgraph consisting of given array of nodes

+ + +
+
+
+ +
+

Examples:

+ + +
graph.subgraph(%w[Mumbai Nagpur])
+ +
+

Parameters:

+
    + +
  • + + nodes + + + (Array<Object>) + + + + — +
    +

    the nodes to be included in the subgraph

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/NetworkX/Level.html b/NetworkX/Level.html new file mode 100644 index 0000000..bd574a2 --- /dev/null +++ b/NetworkX/Level.html @@ -0,0 +1,370 @@ + + + + + + + Class: NetworkX::Level + + — Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: NetworkX::Level + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/networkx/flow/utils.rb
+
+ +
+ +

Overview

+
+ +

Helper class for preflow push algorithm

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initializeLevel + + + + + +

+
+ +

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
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #activeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute active.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+27
+28
+29
+
+
# File 'lib/networkx/flow/utils.rb', line 27
+
+def active
+  @active
+end
+
+
+ + + +
+

+ + #inactiveObject (readonly) + + + + + +

+
+ +

Returns the value of attribute inactive.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+27
+28
+29
+
+
# File 'lib/networkx/flow/utils.rb', line 27
+
+def inactive
+  @inactive
+end
+
+
+ +
+ + +
+ + + +
+ + \ No newline at end of file diff --git a/NetworkX/MultiDiGraph.html b/NetworkX/MultiDiGraph.html new file mode 100644 index 0000000..80767ca --- /dev/null +++ b/NetworkX/MultiDiGraph.html @@ -0,0 +1,2216 @@ + + + + + + + Class: NetworkX::MultiDiGraph + + — Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: NetworkX::MultiDiGraph + + + +

+
+ +
+
Inherits:
+
+ DiGraph + +
    +
  • Object
  • + + + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/networkx/multidigraph.rb
+
+ +
+ +

Overview

+
+ +

Describes the class for making MultiDiGraphs

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods inherited from DiGraph

+

#add_node, #clear, #directed?, #initialize, #remove_node

+ + + + + + + + + +

Methods inherited from 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_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

+
+

Constructor Details

+ +

This class inherits a constructor from NetworkX::DiGraph

+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #adjHash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } } (readonly) + + + + + +

+
+ +

Stores the edges and their attributes in an adjencency list form

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } }) + + + + — +
    +

    the current value of adj

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+10
+11
+12
+
+
# File 'lib/networkx/multidigraph.rb', line 10
+
+def adj
+  @adj
+end
+
+
+ + + +
+

+ + #graphHash{ Object => Object } (readonly) + + + + + +

+
+ +

Stores the attributes of the graph

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Object }) + + + + — +
    +

    the current value of graph

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+10
+11
+12
+
+
# File 'lib/networkx/multidigraph.rb', line 10
+
+def graph
+  @graph
+end
+
+
+ + + +
+

+ + #nodesHash{ Object => Hash{ Object => Object } } (readonly) + + + + + +

+
+ +

Stores the nodes and their attributes

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Hash{ Object => Object } }) + + + + — +
    +

    the current value of nodes

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+10
+11
+12
+
+
# File 'lib/networkx/multidigraph.rb', line 10
+
+def nodes
+  @nodes
+end
+
+
+ + + +
+

+ + #predHash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } } (readonly) + + + + + +

+
+ +

Stores the reverse edges and their attributes in an adjencency list form

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } }) + + + + — +
    +

    the current value of pred

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+10
+11
+12
+
+
# File 'lib/networkx/multidigraph.rb', line 10
+
+def pred
+  @pred
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #add_edge(node1, node2, **edge_attrs) ⇒ Object + + + + + +

+
+ +

Adds the respective edge

+ + +
+
+
+ +
+

Examples:

+ + +

+

Add an edge with attribute name

+

+ +
graph.add_edge(node1, node2, name: "Edge1")
+ + +

+

Add an edge with no attribute

+

+ +
graph.add_edge("Bangalore", "Chennai")
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge

    +
    + +
  • + +
  • + + edge_attrs + + + (Hash{ Object => Object }) + + + + — +
    +

    the hash of the edge attributes

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #edge?(node1, node2, key = nil) ⇒ Boolean + + + + + +

+
+ +

Checks if the the edge consisting of two nodes is present in the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.edge?(node1, node2)
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge to be checked

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge to be checked

    +
    + +
  • + +
  • + + key + + + (Integer) + + + (defaults to: nil) + + + — +
    +

    the key of the given edge

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #edge_subgraph(edges) ⇒ Object + + + + + +

+
+ +

Returns subgraph conisting of given edges

+ + +
+
+
+ +
+

Examples:

+ + +
graph.edge_subgraph([%w[Nagpur Wardha], %w[Nagpur Mumbai]])
+ +
+

Parameters:

+
    + +
  • + + edges + + + (Array<Object, Object>) + + + + — +
    +

    the edges to be included in the subraph

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #has_edge?(node1, node2, key = nil) ⇒ Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #in_degree(node) ⇒ Object + + + + + +

+
+ +

Returns in-degree of a given node

+ + +
+
+
+ +
+

Examples:

+ + +
graph.in_degree(node)
+ +
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    the node whose in degree is to be calculated

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+155
+156
+157
+
+
# File 'lib/networkx/multidigraph.rb', line 155
+
+def in_degree(node)
+  @pred[node].values.map(&:length).sum
+end
+
+
+ +
+

+ + #multigraph?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+245
+246
+247
+
+
# File 'lib/networkx/multidigraph.rb', line 245
+
+def multigraph?
+  true
+end
+
+
+ +
+

+ + #new_edge_key(node1, node2) ⇒ Object + + + + + +

+
+ +

Returns a new key

+ + +
+
+
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of a given edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of a given edge

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #number_of_edgesObject + + + + + +

+
+ +

Returns number of edges

+ + +
+
+
+ +
+

Examples:

+ + +
graph.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
+
+
+ +
+

+ + #out_degree(node) ⇒ Object + + + + + +

+
+ +

Returns out-degree of a given node

+ + +
+
+
+ +
+

Examples:

+ + +
graph.out_degree(node)
+ +
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    the node whose out degree is to be calculated

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+165
+166
+167
+
+
# File 'lib/networkx/multidigraph.rb', line 165
+
+def out_degree(node)
+  @adj[node].values.map(&:length).sum
+end
+
+
+ +
+

+ + #remove_edge(node1, node2, key = nil) ⇒ Object + + + + + +

+
+ +

Removes edge from the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.remove_edge('Noida', 'Bangalore')
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (KeyError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #reverseObject + + + + + +

+
+ +

Returns the reversed version of the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.reverse
+ +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #size(is_weighted = false) ⇒ Object + + + + + +

+
+ +

Returns the size of the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.size(true)
+ +
+

Parameters:

+
    + +
  • + + is_weighted + + + (Bool) + + + (defaults to: false) + + + — +
    +

    if true, method returns sum of weights of all edges else returns number of edges

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #subgraph(nodes) ⇒ Object + + + + + +

+
+ +

Returns subgraph consisting of given array of nodes

+ + +
+
+
+ +
+

Examples:

+ + +
graph.subgraph(%w[Mumbai Nagpur])
+ +
+

Parameters:

+
    + +
  • + + nodes + + + (Array<Object>) + + + + — +
    +

    the nodes to be included in the subgraph

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #to_directedObject + + + + + +

+
+ +

Returns the directed version of the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.to_directed
+ +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #to_multigraphObject + + + + + +

+
+ +

Returns the multigraph version of the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.to_multigraph
+ +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #to_undirectedObject + + + + + +

+
+ +

Returns the undirected version of the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.to_undirected
+ +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/NetworkX/MultiGraph.html b/NetworkX/MultiGraph.html new file mode 100644 index 0000000..b49cb79 --- /dev/null +++ b/NetworkX/MultiGraph.html @@ -0,0 +1,1744 @@ + + + + + + + Class: NetworkX::MultiGraph + + — Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: NetworkX::MultiGraph + + + +

+
+ +
+
Inherits:
+
+ Graph + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/networkx/multigraph.rb
+
+ +
+ +

Overview

+
+ +

Describes the class for making MultiGraphs

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods inherited from 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

+
+

Constructor Details

+ +

This class inherits a constructor from NetworkX::Graph

+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #adjHash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } } (readonly) + + + + + +

+
+ +

Stores the edges and their attributes in an adjencency list form

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } }) + + + + — +
    +

    the current value of adj

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+8
+9
+10
+
+
# File 'lib/networkx/multigraph.rb', line 8
+
+def adj
+  @adj
+end
+
+
+ + + +
+

+ + #graphHash{ Object => Object } (readonly) + + + + + +

+
+ +

Stores the attributes of the gra

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Object }) + + + + — +
    +

    the current value of graph

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+8
+9
+10
+
+
# File 'lib/networkx/multigraph.rb', line 8
+
+def graph
+  @graph
+end
+
+
+ + + +
+

+ + #nodesHash{ Object => Hash{ Object => Object } } (readonly) + + + + + +

+
+ +

Stores the nodes and their attributes

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Hash{ Object => Object } }) + + + + — +
    +

    the current value of nodes

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+8
+9
+10
+
+
# File 'lib/networkx/multigraph.rb', line 8
+
+def nodes
+  @nodes
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #add_edge(node1, node2, **edge_attrs) ⇒ Object + + + + + +

+
+ +

Adds the respective edge

+ + +
+
+
+ +
+

Examples:

+ + +

+

Add an edge with attribute name

+

+ +
graph.add_edge(node1, node2, name: "Edge1")
+ + +

+

Add an edge with no attribute

+

+ +
graph.add_edge("Bangalore", "Chennai")
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge

    +
    + +
  • + +
  • + + edge_attrs + + + (Hash{ Object => Object }) + + + + — +
    +

    the hash of the edge attributes

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #each_edge(data: false) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #edge?(node1, node2, key = nil) ⇒ Boolean + + + + + +

+
+ +

Checks if the the edge consisting of two nodes is present in the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.edge?(node1, node2)
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge to be checked

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge to be checked

    +
    + +
  • + +
  • + + key + + + (Integer) + + + (defaults to: nil) + + + — +
    +

    the key of the given edge

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #edge_subgraph(edges) ⇒ Object + + + + + +

+
+ +

Returns subgraph conisting of given edges

+ + +
+
+
+ +
+

Examples:

+ + +
graph.edge_subgraph([%w[Nagpur Wardha], %w[Nagpur Mumbai]])
+ +
+

Parameters:

+
    + +
  • + + edges + + + (Array<Object, Object>) + + + + — +
    +

    the edges to be included in the subraph

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #has_edge?(node1, node2, key = nil) ⇒ Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #multigraph?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+195
+196
+197
+
+
# File 'lib/networkx/multigraph.rb', line 195
+
+def multigraph?
+  true
+end
+
+
+ +
+

+ + #new_edge_key(node1, node2) ⇒ Object + + + + + +

+
+ +

Returns a new key

+ + +
+
+
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of a given edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of a given edge

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #number_of_edgesObject + + + + + +

+
+ +

Returns number of edges

+ + +
+
+
+ +
+

Examples:

+ + +
graph.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
+
+
+ +
+

+ + #remove_edge(node1, node2, key = nil) ⇒ Object + + + + + +

+
+ +

Removes edge from the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.remove_edge('Noida', 'Bangalore')
+ +
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    the first node of the edge

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    the second node of the edge

    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (KeyError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #size(is_weighted = false) ⇒ Object + + + + + +

+
+ +

Returns the size of the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.size(true)
+ +
+

Parameters:

+
    + +
  • + + is_weighted + + + (Bool) + + + (defaults to: false) + + + — +
    +

    if true, method returns sum of weights of all edges else returns number of edges

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #subgraph(nodes) ⇒ Object + + + + + +

+
+ +

Returns subgraph consisting of given array of nodes

+ + +
+
+
+ +
+

Examples:

+ + +
graph.subgraph(%w[Mumbai Nagpur])
+ +
+

Parameters:

+
    + +
  • + + nodes + + + (Array<Object>) + + + + — +
    +

    the nodes to be included in the subgraph

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #to_undirectedObject + + + + + +

+
+ +

Returns the undirected version of the graph

+ + +
+
+
+ +
+

Examples:

+ + +
graph.to_undirected
+ +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/NetworkX/UnionFind.html b/NetworkX/UnionFind.html new file mode 100644 index 0000000..f3dcdab --- /dev/null +++ b/NetworkX/UnionFind.html @@ -0,0 +1,1090 @@ + + + + + + + Class: NetworkX::UnionFind + + — Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: NetworkX::UnionFind + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/networkx/auxillary_functions/union_find.rb
+
+ +
+ +

Overview

+
+ +

Union Find Tree

+ +

Reference - ac-library-rb DSU (CC0) - Python NetworkX UnionFind

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(nodes = nil) ⇒ UnionFind + + + + + +

+
+ +

Constructor for initializing Union Find Tree

+ + +
+
+
+

Parameters:

+
    + +
  • + + nodes + + + (?Array[Object]) + + + (defaults to: nil) + + + — +
    +

    nodes

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+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
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #parentsHash{ Object => Object } + + + + + +

+
+ +

Return parent of each element

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Object }) + + + + — +
    +

    the current value of parents

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+11
+12
+13
+
+
# File 'lib/networkx/auxillary_functions/union_find.rb', line 11
+
+def parents
+  @parents
+end
+
+
+ + + +
+

+ + #weightsHash{ Object => Integer } + + + + + +

+
+ +

Return weight of each element

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash{ Object => Integer }) + + + + — +
    +

    the current value of weights

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+11
+12
+13
+
+
# File 'lib/networkx/auxillary_functions/union_find.rb', line 11
+
+def weights
+  @weights
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #[](node) ⇒ Object + + + + + +

+
+ +

Return the root of node

+ + +
+
+
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    node

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Object) + + + + — +
    +

    root of node, leader 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
+
+
+ +
+

+ + #connected?(node1, node2) ⇒ bool + + + + Also known as: + same? + + + + +

+
+ +

Is each root of two nodes the same?

+ + +
+
+
+

Parameters:

+
    + +
  • + + node1 + + + (Object) + + + + — +
    +

    node

    +
    + +
  • + +
  • + + node2 + + + (Object) + + + + — +
    +

    node

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (bool) + + + + — +
    +

    Is each root of node1 and nodes_2 the same?

    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+68
+69
+70
+
+
# File 'lib/networkx/auxillary_functions/union_find.rb', line 68
+
+def connected?(node1, node2)
+  root(node1) == root(node2)
+end
+
+
+ +
+

+ + #each(&block) ⇒ Object + + + + + +

+ + + + +
+
+
+
+53
+54
+55
+
+
# File 'lib/networkx/auxillary_functions/union_find.rb', line 53
+
+def each(&block)
+  @parents.each_key(&block)
+end
+
+
+ +
+

+ + #merge(node1, node2) ⇒ Object + + + + + +

+ + + + +
+
+
+
+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
+
+
+ +
+

+ + #root(node) ⇒ Object + + + + + +

+
+ +

Return the root of node

+ + +
+
+
+

Parameters:

+
    + +
  • + + node + + + (Object) + + + + — +
    +

    node

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Object) + + + + — +
    +

    root of node, leader 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
+
+
+ +
+

+ + #to_setsObject + + + + Also known as: + groups + + + + +

+ + + + +
+
+
+
+57
+58
+59
+
+
# File 'lib/networkx/auxillary_functions/union_find.rb', line 57
+
+def to_sets
+  each.group_by { |node| root(node) }.values
+end
+
+
+ +
+

+ + #union(*nodes) ⇒ Object | nil + + + + Also known as: + unite + + + + +

+
+ +

Unite nodes.

+ + +
+
+
+

Parameters:

+
    + +
  • + + nodes + + + (Array[Object]) + + + + — +
    +

    nodes

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Object | nil) + + + + — +
    +

    root of united 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
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 384e309..0000000 --- a/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# NetworkX.rb - -[![Gem Version](https://badge.fury.io/rb/networkx.svg)](https://badge.fury.io/rb/networkx) - -[NetworkX](https://networkx.github.io/) is a very popular Python library, that handles various use-cases of the Graph Data Structure. -This project intends to provide a working alternative to the Ruby community, by closely mimicing as many features as possible. - -## List of contents - -- [Installing](#installing) -- [Usage](#Usage) -- [Document](#document) -- [Contributing](#contributing) -- [License](#license) - -## Installing - -- install it yourself as: -```console -$ gem install networkx -``` - - -- Or use Bundler & Gemfile - 1. add this line to your application's Gemfile: - ```ruby - gem 'networkx' - ``` - 2. And then execute: - ```console - $ bundle install - ``` - -## Usage - -```ruby -require 'networkx' - -g = NetworkX::Graph.new -g.add_edge('start', 'stop') -``` - -## Document - -You can read [Document](https://SciRuby.github.io/networkx.rb/) for this library. - -## Contributing - -Your contributions are always welcome! -Please have a look at the [contribution guidelines](.github/CONTRIBUTING.md) first. :tada: - -## License - -The MIT License 2017 - [Athitya Kumar](https://github.com/athityakumar). -Please have a look at the [LICENSE.md](LICENSE.md) for more details. diff --git a/Rakefile b/Rakefile deleted file mode 100644 index acd631d..0000000 --- a/Rakefile +++ /dev/null @@ -1,11 +0,0 @@ -require 'bundler/gem_tasks' - -require 'bundler/setup' - -require 'rspec/core/rake_task' -RSpec::Core::RakeTask.new - -require 'rubocop/rake_task' -RuboCop::RakeTask.new - -task default: %w[spec rubocop] diff --git a/_index.html b/_index.html new file mode 100644 index 0000000..fe1bc1d --- /dev/null +++ b/_index.html @@ -0,0 +1,227 @@ + + + + + + + Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Documentation by YARD 0.9.28

+
+

Alphabetic Index

+ +

File Listing

+ + +
+

Namespace Listing A-Z

+ + + + + + + + +
+ + +
    +
  • A
  • + +
+ + + + + +
    +
  • D
  • +
      + +
    • + DiGraph + + (NetworkX) + +
    • + +
    +
+ + + + + +
    +
  • L
  • +
      + +
    • + Level + + (NetworkX) + +
    • + +
    +
+ + + + + + + + +
+ + +
    +
  • U
  • + +
+ +
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/class_list.html b/class_list.html new file mode 100644 index 0000000..2281271 --- /dev/null +++ b/class_list.html @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + Class List + + + +
+
+

Class List

+ + + +
+ + +
+ + diff --git a/css/common.css b/css/common.css new file mode 100644 index 0000000..cf25c45 --- /dev/null +++ b/css/common.css @@ -0,0 +1 @@ +/* Override this file with custom rules */ \ No newline at end of file diff --git a/css/full_list.css b/css/full_list.css new file mode 100644 index 0000000..fa35982 --- /dev/null +++ b/css/full_list.css @@ -0,0 +1,58 @@ +body { + margin: 0; + font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; + font-size: 13px; + height: 101%; + overflow-x: hidden; + background: #fafafa; +} + +h1 { padding: 12px 10px; padding-bottom: 0; margin: 0; font-size: 1.4em; } +.clear { clear: both; } +.fixed_header { position: fixed; background: #fff; width: 100%; padding-bottom: 10px; margin-top: 0; top: 0; z-index: 9999; height: 70px; } +#search { position: absolute; right: 5px; top: 9px; padding-left: 24px; } +#content.insearch #search, #content.insearch #noresults { background: url(data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAAPr6+pKSkoiIiO7u7sjIyNjY2J6engAAAI6OjsbGxjIyMlJSUuzs7KamppSUlPLy8oKCghwcHLKysqSkpJqamvT09Pj4+KioqM7OzkRERAwMDGBgYN7e3ujo6Ly8vCoqKjY2NkZGRtTU1MTExDw8PE5OTj4+PkhISNDQ0MrKylpaWrS0tOrq6nBwcKysrLi4uLq6ul5eXlxcXGJiYoaGhuDg4H5+fvz8/KKiohgYGCwsLFZWVgQEBFBQUMzMzDg4OFhYWBoaGvDw8NbW1pycnOLi4ubm5kBAQKqqqiQkJCAgIK6urnJyckpKSjQ0NGpqatLS0sDAwCYmJnx8fEJCQlRUVAoKCggICLCwsOTk5ExMTPb29ra2tmZmZmhoaNzc3KCgoBISEiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCAAAACwAAAAAEAAQAAAHaIAAgoMgIiYlg4kACxIaACEJCSiKggYMCRselwkpghGJBJEcFgsjJyoAGBmfggcNEx0flBiKDhQFlIoCCA+5lAORFb4AJIihCRbDxQAFChAXw9HSqb60iREZ1omqrIPdJCTe0SWI09GBACH5BAkIAAAALAAAAAAQABAAAAdrgACCgwc0NTeDiYozCQkvOTo9GTmDKy8aFy+NOBA7CTswgywJDTIuEjYFIY0JNYMtKTEFiRU8Pjwygy4ws4owPyCKwsMAJSTEgiQlgsbIAMrO0dKDGMTViREZ14kYGRGK38nHguHEJcvTyIEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDAggPg4iJAAMJCRUAJRIqiRGCBI0WQEEJJkWDERkYAAUKEBc4Po1GiKKJHkJDNEeKig4URLS0ICImJZAkuQAhjSi/wQyNKcGDCyMnk8u5rYrTgqDVghgZlYjcACTA1sslvtHRgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCQARAtOUoQRGRiFD0kJUYWZhUhKT1OLhR8wBaaFBzQ1NwAlkIszCQkvsbOHL7Y4q4IuEjaqq0ZQD5+GEEsJTDCMmIUhtgk1lo6QFUwJVDKLiYJNUd6/hoEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4uen4ICCA+IkIsDCQkVACWmhwSpFqAABQoQF6ALTkWFnYMrVlhWvIKTlSAiJiVVPqlGhJkhqShHV1lCW4cMqSkAR1ofiwsjJyqGgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCSMhREZGIYYGY2ElYebi56fhyWQniSKAKKfpaCLFlAPhl0gXYNGEwkhGYREUywag1wJwSkHNDU3D0kJYIMZQwk8MjPBLx9eXwuETVEyAC/BOKsuEjYFhoEAIfkECQgAAAAsAAAAABAAEAAAB2eAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4ueICImip6CIQkJKJ4kigynKaqKCyMnKqSEK05StgAGQRxPYZaENqccFgIID4KXmQBhXFkzDgOnFYLNgltaSAAEpxa7BQoQF4aBACH5BAkIAAAALAAAAAAQABAAAAdogACCg4SFggJiPUqCJSWGgkZjCUwZACQkgxGEXAmdT4UYGZqCGWQ+IjKGGIUwPzGPhAc0NTewhDOdL7Ykji+dOLuOLhI2BbaFETICx4MlQitdqoUsCQ2vhKGjglNfU0SWmILaj43M5oEAOwAAAAAAAAAAAA==) no-repeat center left; } +#full_list { padding: 0; list-style: none; margin-left: 0; margin-top: 80px; font-size: 1.1em; } +#full_list ul { padding: 0; } +#full_list li { padding: 0; margin: 0; list-style: none; } +#full_list li .item { padding: 5px 5px 5px 12px; } +#noresults { padding: 7px 12px; background: #fff; } +#content.insearch #noresults { margin-left: 7px; } +li.collapsed ul { display: none; } +li a.toggle { cursor: default; position: relative; left: -5px; top: 4px; text-indent: -999px; width: 10px; height: 9px; margin-left: -10px; display: block; float: left; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left; } +li.collapsed a.toggle { opacity: 0.5; cursor: default; background-position: top left; } +li { color: #888; cursor: pointer; } +li.deprecated { text-decoration: line-through; font-style: italic; } +li.odd { background: #f0f0f0; } +li.even { background: #fafafa; } +.item:hover { background: #ddd; } +li small:before { content: "("; } +li small:after { content: ")"; } +li small.search_info { display: none; } +a, a:visited { text-decoration: none; color: #05a; } +li.clicked > .item { background: #05a; color: #ccc; } +li.clicked > .item a, li.clicked > .item a:visited { color: #eee; } +li.clicked > .item a.toggle { opacity: 0.5; background-position: bottom right; } +li.collapsed.clicked a.toggle { background-position: top right; } +#search input { border: 1px solid #bbb; border-radius: 3px; } +#full_list_nav { margin-left: 10px; font-size: 0.9em; display: block; color: #aaa; } +#full_list_nav a, #nav a:visited { color: #358; } +#full_list_nav a:hover { background: transparent; color: #5af; } +#full_list_nav span:after { content: ' | '; } +#full_list_nav span:last-child:after { content: ''; } + +#content h1 { margin-top: 0; } +li { white-space: nowrap; cursor: normal; } +li small { display: block; font-size: 0.8em; } +li small:before { content: ""; } +li small:after { content: ""; } +li small.search_info { display: none; } +#search { width: 170px; position: static; margin: 3px; margin-left: 10px; font-size: 0.9em; color: #888; padding-left: 0; padding-right: 24px; } +#content.insearch #search { background-position: center right; } +#search input { width: 110px; } + +#full_list.insearch ul { display: block; } +#full_list.insearch .item { display: none; } +#full_list.insearch .found { display: block; padding-left: 11px !important; } +#full_list.insearch li a.toggle { display: none; } +#full_list.insearch li small.search_info { display: block; } diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..eb0dbc8 --- /dev/null +++ b/css/style.css @@ -0,0 +1,497 @@ +html { + width: 100%; + height: 100%; +} +body { + font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; + font-size: 13px; + width: 100%; + margin: 0; + padding: 0; + display: flex; + display: -webkit-flex; + display: -ms-flexbox; +} + +#nav { + position: relative; + width: 100%; + height: 100%; + border: 0; + border-right: 1px dotted #eee; + overflow: auto; +} +.nav_wrap { + margin: 0; + padding: 0; + width: 20%; + height: 100%; + position: relative; + display: flex; + display: -webkit-flex; + display: -ms-flexbox; + flex-shrink: 0; + -webkit-flex-shrink: 0; + -ms-flex: 1 0; +} +#resizer { + position: absolute; + right: -5px; + top: 0; + width: 10px; + height: 100%; + cursor: col-resize; + z-index: 9999; +} +#main { + flex: 5 1; + -webkit-flex: 5 1; + -ms-flex: 5 1; + outline: none; + position: relative; + background: #fff; + padding: 1.2em; + padding-top: 0.2em; + box-sizing: border-box; +} + +@media (max-width: 920px) { + .nav_wrap { width: 100%; top: 0; right: 0; overflow: visible; position: absolute; } + #resizer { display: none; } + #nav { + z-index: 9999; + background: #fff; + display: none; + position: absolute; + top: 40px; + right: 12px; + width: 500px; + max-width: 80%; + height: 80%; + overflow-y: scroll; + border: 1px solid #999; + border-collapse: collapse; + box-shadow: -7px 5px 25px #aaa; + border-radius: 2px; + } +} + +@media (min-width: 920px) { + body { height: 100%; overflow: hidden; } + #main { height: 100%; overflow: auto; } + #search { display: none; } +} + +#main img { max-width: 100%; } +h1 { font-size: 25px; margin: 1em 0 0.5em; padding-top: 4px; border-top: 1px dotted #d5d5d5; } +h1.noborder { border-top: 0px; margin-top: 0; padding-top: 4px; } +h1.title { margin-bottom: 10px; } +h1.alphaindex { margin-top: 0; font-size: 22px; } +h2 { + padding: 0; + padding-bottom: 3px; + border-bottom: 1px #aaa solid; + font-size: 1.4em; + margin: 1.8em 0 0.5em; + position: relative; +} +h2 small { font-weight: normal; font-size: 0.7em; display: inline; position: absolute; right: 0; } +h2 small a { + display: block; + height: 20px; + border: 1px solid #aaa; + border-bottom: 0; + border-top-left-radius: 5px; + background: #f8f8f8; + position: relative; + padding: 2px 7px; +} +.clear { clear: both; } +.inline { display: inline; } +.inline p:first-child { display: inline; } +.docstring, .tags, #filecontents { font-size: 15px; line-height: 1.5145em; } +.docstring p > code, .docstring p > tt, .tags p > code, .tags p > tt { + color: #c7254e; background: #f9f2f4; padding: 2px 4px; font-size: 1em; + border-radius: 4px; +} +.docstring h1, .docstring h2, .docstring h3, .docstring h4 { padding: 0; border: 0; border-bottom: 1px dotted #bbb; } +.docstring h1 { font-size: 1.2em; } +.docstring h2 { font-size: 1.1em; } +.docstring h3, .docstring h4 { font-size: 1em; border-bottom: 0; padding-top: 10px; } +.summary_desc .object_link a, .docstring .object_link a { + font-family: monospace; font-size: 1.05em; + color: #05a; background: #EDF4FA; padding: 2px 4px; font-size: 1em; + border-radius: 4px; +} +.rdoc-term { padding-right: 25px; font-weight: bold; } +.rdoc-list p { margin: 0; padding: 0; margin-bottom: 4px; } +.summary_desc pre.code .object_link a, .docstring pre.code .object_link a { + padding: 0px; background: inherit; color: inherit; border-radius: inherit; +} + +/* style for */ +#filecontents table, .docstring table { border-collapse: collapse; } +#filecontents table th, #filecontents table td, +.docstring table th, .docstring table td { border: 1px solid #ccc; padding: 8px; padding-right: 17px; } +#filecontents table tr:nth-child(odd), +.docstring table tr:nth-child(odd) { background: #eee; } +#filecontents table tr:nth-child(even), +.docstring table tr:nth-child(even) { background: #fff; } +#filecontents table th, .docstring table th { background: #fff; } + +/* style for
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/lib/networkx.rb b/lib/networkx.rb deleted file mode 100644 index 142f31d..0000000 --- a/lib/networkx.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'set' -require 'matrix' -require 'rb_heap' -require 'securerandom' -require_relative 'networkx/version' -require_relative 'networkx/graph' -require_relative 'networkx/digraph' -require_relative 'networkx/multigraph' -require_relative 'networkx/multidigraph' -require_relative 'networkx/traversals/bfs' -require_relative 'networkx/traversals/dfs' -require_relative 'networkx/traversals/edge_dfs' -require_relative 'networkx/shortest_path/unweighted' -require_relative 'networkx/to_matrix' -require_relative 'networkx/shortest_path/dense' -require_relative 'networkx/shortest_path/weighted' -require_relative 'networkx/shortest_path/astar' -require_relative 'networkx/operators/product' -require_relative 'networkx/operators/binary' -require_relative 'networkx/operators/unary' -require_relative 'networkx/operators/all' -require_relative 'networkx/flow/utils' -require_relative 'networkx/flow/edmondskarp' -require_relative 'networkx/flow/shortestaugmentingpath' -require_relative 'networkx/flow/capacityscaling' -require_relative 'networkx/flow/preflowpush' -require_relative 'networkx/auxillary_functions/cliques' -require_relative 'networkx/auxillary_functions/dag' -require_relative 'networkx/auxillary_functions/eccentricity' -require_relative 'networkx/auxillary_functions/mis' -require_relative 'networkx/auxillary_functions/mst' -require_relative 'networkx/auxillary_functions/union_find' -require_relative 'networkx/auxillary_functions/vitality' -require_relative 'networkx/auxillary_functions/wiener' -require_relative 'networkx/auxillary_functions/cycles' -require_relative 'networkx/link_analysis/hits' -require_relative 'networkx/link_analysis/pagerank' -require_relative 'networkx/others/bridges' -require_relative 'networkx/others/generators' -require_relative 'networkx/others/grid_2d_graph' -require_relative 'networkx/others/info' -require_relative 'networkx/others/number_connected_components' -require_relative 'networkx/others/reads' diff --git a/lib/networkx/auxillary_functions/cliques.rb b/lib/networkx/auxillary_functions/cliques.rb deleted file mode 100644 index 3c60448..0000000 --- a/lib/networkx/auxillary_functions/cliques.rb +++ /dev/null @@ -1,62 +0,0 @@ -module NetworkX - # Returns all cliques in the graph - # - # @param graph [Graph, MultiGraph] a graph - # - # @return [Array>] Arrays of nodes in the cliques - 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 number of cliques in a graph containing a node - # - # @param graph [Graph, MultiGraph] a graph - # @param node [Object] a node - # - # @return [Numeric] Number of cliques containing the given node - def self.number_of_cliques(graph, node) - cliques = find_cliques(graph) - cliques.count { |c| c.include?(node) } - end -end diff --git a/lib/networkx/auxillary_functions/cycles.rb b/lib/networkx/auxillary_functions/cycles.rb deleted file mode 100644 index f378682..0000000 --- a/lib/networkx/auxillary_functions/cycles.rb +++ /dev/null @@ -1,114 +0,0 @@ -module NetworkX - # Returns all basis cycles in graph - # - # @param graph [Graph] a graph - # @param root [Object, Nil] root for the graph cycles - # - # @return [Array>] Arrays of nodes in the cycles - 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 cycle containing the given node - # - # @param graph [Graph, DiGraph] a graph - # @param node [Object] node to be included in the cycle - # - # @return [Array>] Arrays of nodes in the cycle - 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 whether the given undirected cycle has cycle. - # - # @param undirected_graph [Graph] an undirected graph - # - # @return [book] true if the given graph has cycle. otherwise, false. - 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 -end diff --git a/lib/networkx/auxillary_functions/dag.rb b/lib/networkx/auxillary_functions/dag.rb deleted file mode 100644 index e3d4b87..0000000 --- a/lib/networkx/auxillary_functions/dag.rb +++ /dev/null @@ -1,59 +0,0 @@ -module NetworkX - # Returns the descendants of a given node - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] node to find descendents of - # - # @return [Array] Array of the descendants - 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 - - # Returns the ancestors of a given node - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] node to find ancestors of - # - # @return [Array] Array of the ancestors - 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 - - # Returns the nodes arranged in the topologically sorted fashion - # - # @param graph [DiGraph] a graph - # - # @return [Array] Array of the nodes - 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 -end diff --git a/lib/networkx/auxillary_functions/eccentricity.rb b/lib/networkx/auxillary_functions/eccentricity.rb deleted file mode 100644 index e78b190..0000000 --- a/lib/networkx/auxillary_functions/eccentricity.rb +++ /dev/null @@ -1,37 +0,0 @@ -module NetworkX - # Returns the eccentricity of a particular node or all nodes - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param node [Object] node to find the eccentricity of - # - # @return [Array, Numeric] eccentricity/eccentricites of all nodes - 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 - - # Returns the diameter of a graph - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # - # @return [Numeric] diameter of the graph - def self.diameter(graph) - eccentricity(graph).values.max - end - - # Returns the radius of a graph - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # - # @return [Numeric] radius of the graph - def self.radius(graph) - eccentricity(graph).values.min - end -end diff --git a/lib/networkx/auxillary_functions/mis.rb b/lib/networkx/auxillary_functions/mis.rb deleted file mode 100644 index 11b8e4d..0000000 --- a/lib/networkx/auxillary_functions/mis.rb +++ /dev/null @@ -1,25 +0,0 @@ -module NetworkX - # Returns the maximal independent set of a graph - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param nodes [Object] nodes to be considered in the MIS - # - # @return [Numeric] radius of the graph - 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 -end diff --git a/lib/networkx/auxillary_functions/mst.rb b/lib/networkx/auxillary_functions/mst.rb deleted file mode 100644 index ad0a11f..0000000 --- a/lib/networkx/auxillary_functions/mst.rb +++ /dev/null @@ -1,33 +0,0 @@ -module NetworkX - # Helper function for the minimum spanning tree - # - 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 - - # Returns the minimum spanning tree of a graph - # - # @param graph [Graph, DiGraph] a graph - # - # @return [DiGraph, Graph] a minimum spanning tree of the graph - 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 -end diff --git a/lib/networkx/auxillary_functions/union_find.rb b/lib/networkx/auxillary_functions/union_find.rb deleted file mode 100644 index db8e761..0000000 --- a/lib/networkx/auxillary_functions/union_find.rb +++ /dev/null @@ -1,104 +0,0 @@ -module NetworkX - # Union Find Tree - # - # Reference - # - [ac-library-rb DSU (CC0)](https://github.com/universato/ac-library-rb/blob/main/lib/dsu.rb) - # - [Python NetworkX UnionFind](https://networkx.org/documentation/stable/_modules/networkx/utils/union_find.html) - # - # - # @attr_reader parents [Hash{ Object => Object }] Return parent of each element - # @attr_reader weights [Hash{ Object => Integer }] Return weight of each element - class UnionFind - attr_accessor :parents, :weights - - # Constructor for initializing Union Find Tree - # - # @param nodes [?Array[Object]] nodes - # - # @return [UnionFind] Union Find Tree - def initialize(nodes = nil) - @weights = {} - @parents = {} - nodes&.each do |node| - @weights[node] = 1 - @parents[node] = node - end - end - - # Return the root of node - # - # @param node [Object] node - # - # @return [Object] root of node, leader of node - 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 - - # Return the root of node - # - # @param node [Object] node - # - # @return [Object] root of node, leader of node - 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 - - def each(&block) - @parents.each_key(&block) - end - - def to_sets - each.group_by { |node| root(node) }.values - end - alias groups to_sets - - # Is each root of two nodes the same? - # - # @param node1 [Object] node - # @param node2 [Object] node - # - # @return [bool] Is each root of node1 and nodes_2 the same? - def connected?(node1, node2) - root(node1) == root(node2) - end - alias same? connected? - - # Unite nodes. - # - # @param nodes [Array[Object]] nodes - # - # @return [Object | nil] root of united nodes - 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 - alias unite union - - 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 - end -end diff --git a/lib/networkx/auxillary_functions/vitality.rb b/lib/networkx/auxillary_functions/vitality.rb deleted file mode 100644 index fcde5fa..0000000 --- a/lib/networkx/auxillary_functions/vitality.rb +++ /dev/null @@ -1,13 +0,0 @@ -module NetworkX - # Returns the closeness vitality of a node - # - # @param graph [Graph, DiGraph] a graph - # @param node [Object] node to compute closeness vitality of - # - # @return [Numeric] closeness vitality of the given node - def self.closeness_vitality(graph, node) - before = wiener_index(graph) - after = wiener_index(graph.subgraph(graph.nodes(data: true).keys - [node])) - before - after - end -end diff --git a/lib/networkx/auxillary_functions/wiener.rb b/lib/networkx/auxillary_functions/wiener.rb deleted file mode 100644 index 9cedeb6..0000000 --- a/lib/networkx/auxillary_functions/wiener.rb +++ /dev/null @@ -1,13 +0,0 @@ -module NetworkX - # Returns the wiener index of the graph - # - # @param graph [Graph, DiGraph] a graph - # - # @return [Numeric] wiener index of the graph - 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 -end diff --git a/lib/networkx/converters/to_csv.rb b/lib/networkx/converters/to_csv.rb deleted file mode 100644 index 9a511af..0000000 --- a/lib/networkx/converters/to_csv.rb +++ /dev/null @@ -1,45 +0,0 @@ -module NetworkX - # Saves the graph in a csv file - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param filename [String] filename of the graph - 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 -end diff --git a/lib/networkx/converters/to_json.rb b/lib/networkx/converters/to_json.rb deleted file mode 100644 index 79d78c2..0000000 --- a/lib/networkx/converters/to_json.rb +++ /dev/null @@ -1,37 +0,0 @@ -module NetworkX - # Returns a JSON object of the given graph - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # - # @return [JSON] json encoded graph - 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 - - # Returns a graph from the json encoded graph - # - # @param json_str [JSON] json encoded string - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] a decoded graph - 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 -end diff --git a/lib/networkx/digraph.rb b/lib/networkx/digraph.rb deleted file mode 100644 index 42e55a1..0000000 --- a/lib/networkx/digraph.rb +++ /dev/null @@ -1,234 +0,0 @@ -module NetworkX - # Describes the class for making Directed Graphs - # - # @attr_reader adj [Hash{ Object => Hash{ Object => Hash{ Object => Object } } }] - # Stores the edges and their attributes in an adjencency list form - # @attr_reader pred [Hash{ Object => Hash{ Object => Hash{ Object => Object } } }] - # Stores the reverse edges and their attributes in an adjencency list form - # @attr_reader nodes [Hash{ Object => Hash{ Object => Object } }] Stores the nodes and their attributes - # @attr_reader graph [Hash{ Object => Object }] Stores the attributes of the graph - class DiGraph < Graph - attr_reader :adj, :graph, :pred - - # Constructor for initializing graph - # - # @example Initialize a graph with attributes 'type' and 'name' - # graph = NetworkX::Graph.new(name: "Social Network", type: "undirected") - # - # @param graph_attrs [Hash{ Object => Object }] the graph attributes in a hash format - def initialize(**graph_attrs) - super(**graph_attrs) - - @pred = {} - end - - # Adds the respective edge - # - # @example Add an edge with attribute name - # graph.add_edge(node1, node2, name: "Edge1") - # - # @example Add an edge with no attribute - # graph.add_edge("Bangalore", "Chennai") - # - # @param node1 [Object] the first node of the edge - # @param node2 [Object] the second node of the edge - # @param edge_attrs [Hash{ Object => Object }] the hash of the edge attributes - 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 - # - # @example Add a node with attribute 'type' - # graph.add_node("Noida", type: "city") - # - # @param node [Object] the node object - # @param node_attrs [Hash{ Object => Object }] the hash of the attributes of the node - def add_node(node, **node_attrs) - super(node, **node_attrs) - - @pred[node] = {} unless @pred.has_key?(node) - end - - def nodes(data: true) - data ? @nodes : @nodes.keys - end - - # Removes node from the graph - # - # @example - # graph.remove_node("Noida") - # - # @param node [Object] the node to be removed - 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 - - # Removes edge from the graph - # - # @example - # graph.remove_edge('Noida', 'Bangalore') - # - # @param node1 [Object] the first node of the edge - # @param node2 [Object] the second node of the edge - 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 - - # Clears the graph - # - # @example - # graph.clear - def clear - super - - @pred.clear - end - - # Returns number of edges - # - # @example - # graph.number_of_edges - def number_of_edges - @adj.values.map(&:length).sum - end - - # Returns the size of graph - # - # @example - # graph.size(true) - # - # @param is_weighted [Bool] if true, method returns sum of weights of all edges - # else returns number of edges - 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 in-degree of a given node - # - # @example - # graph.in_degree(node) - # - # @param node [Object] the node whose in degree is to be calculated - def in_degree(node) - @pred[node].length - end - - # Returns out-degree of a given node - # - # @example - # graph.out_degree(node) - # - # @param node [Object] the node whose out degree is to be calculated - def out_degree(node) - @adj[node].length - end - - # Returns the reversed version of the graph - # - # @example - # graph.reverse - 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 undirected version of the graph - # - # @example - # graph.to_undirected - 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 - - # Returns subgraph consisting of given array of nodes - # - # @example - # graph.subgraph(%w[Mumbai Nagpur]) - # - # @param nodes [Array] the nodes to be included in the subgraph - 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 subgraph consisting of given edges - # - # @example - # graph.edge_subgraph([%w[Nagpur Wardha], %w[Nagpur Mumbai]]) - # - # @param edges [Array] the edges to be included in the subraph - 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 - - def directed? - true - end - end -end diff --git a/lib/networkx/flow/capacityscaling.rb b/lib/networkx/flow/capacityscaling.rb deleted file mode 100644 index c9ab5ea..0000000 --- a/lib/networkx/flow/capacityscaling.rb +++ /dev/null @@ -1,251 +0,0 @@ -module NetworkX - # Returns a label for unique node - def self.generate_unique_node - SecureRandom.uuid - end - - # Finds if there is a negative edge cycle in the graph - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # - # @return [Boolean] whether there exists a negative cycle in graph - 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 - - # Detects the unboundedness in the residual graph - 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 - - # Returns the residual graph of the given graph - 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 - - # Returns the flowdict of the graph - 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 - - # Computes max flow using capacity scaling algorithm - # - # @param graph [DiGraph, MultiDiGraph] a graph - # - # @return [Array Hash{ Object => Numeric } }>] - # flow cost and flowdict containing all the flow values in the edges - 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 -end diff --git a/lib/networkx/flow/edmondskarp.rb b/lib/networkx/flow/edmondskarp.rb deleted file mode 100644 index a4776fa..0000000 --- a/lib/networkx/flow/edmondskarp.rb +++ /dev/null @@ -1,115 +0,0 @@ -module NetworkX - # Helper function to augment the flow in a residual graph - 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 - - # Helper function for the bidirectional bfs - 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 - - # Core helper function for the EdmondsKarp algorithm - 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 - 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 - - # Computes max flow using edmonds karp algorithm - # - # @param graph [Graph, DiGraph] a graph - # @param source [Object] source node - # @param target [Object] target node - # @param residual [DiGraph, nil] residual graph - # @param cutoff [Numeric] cutoff for the algorithm - # - # @return [DiGraph] a residual graph containing the flow values - def self.edmondskarp(graph, source, target, residual = nil, cutoff = nil) - edmondskarp_impl(graph, source, target, residual, cutoff) - end -end diff --git a/lib/networkx/flow/preflowpush.rb b/lib/networkx/flow/preflowpush.rb deleted file mode 100644 index 7d34b96..0000000 --- a/lib/networkx/flow/preflowpush.rb +++ /dev/null @@ -1,249 +0,0 @@ -module NetworkX - # Helper function to return an arbitrary element from an iterable object - 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 - - # Helper function to apply the preflow push algorithm - 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 to move a node from inactive set to active set - 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 - - # Helper function to relable a node to create a permissible edge - 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 discharging a node - 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 - - # Helper function for applying gap heuristic - 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 - - # Helper function for global relabel heuristic - 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 - - # Helper function for augmenting flow - 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 - - # Helper function for reverse bfs - 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 - - # Computes max flow using preflow push algorithm - # - # @param graph [DiGraph] a graph - # @param source [Object] source node - # @param target [Object] target node - # @param residual [DiGraph, nil] residual graph - # @param globalrelabel_freq [Numeric] global relabel freq - # @param value_only [Boolean] if false, compute maximum flow else - # maximum preflow - # - # @return [DiGraph] a residual graph containing the flow values - 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 -end diff --git a/lib/networkx/flow/shortestaugmentingpath.rb b/lib/networkx/flow/shortestaugmentingpath.rb deleted file mode 100644 index 113c310..0000000 --- a/lib/networkx/flow/shortestaugmentingpath.rb +++ /dev/null @@ -1,154 +0,0 @@ -module NetworkX - # Helper function for running the shortest augmenting path algorithm - 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 - - # Helper function for augmenting flow - 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 function to relable a node to create a permissible edge - def self.relabel(node, num, r_adj, r_nodes) - height = num - 1 - r_adj[node].each do |v, attrs| - height = [height, r_nodes[v][:height]].min if attrs[:flow] < attrs[:capacity] - end - height + 1 - end - - # Computes max flow using shortest augmenting path algorithm - # - # @param graph [DiGraph] a graph - # @param source [Object] source node - # @param target [Object] target node - # @param residual [DiGraph, nil] residual graph - # @param _value_only [Boolean] if true, compute only the maximum flow value - # @param two_phase [Boolean] if true, two phase variant is used - # @param cutoff [Numeric] cutoff value for the algorithm - # - # @return [DiGraph] a residual graph containing the flow values - 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 -end diff --git a/lib/networkx/flow/utils.rb b/lib/networkx/flow/utils.rb deleted file mode 100644 index 2702e59..0000000 --- a/lib/networkx/flow/utils.rb +++ /dev/null @@ -1,139 +0,0 @@ -module NetworkX - # Helper class for preflow push algorithm - class CurrentEdge - attr_reader :curr, :edges - - def initialize(edges) - @edges = edges - @index = {} - @n = edges.length - @curr = 0 - edges.each_with_index { |(key, _value), idx| @index[idx] = key } - end - - def get - [@index[@curr], @edges[@index[@curr]]] - end - - def move_to_next - @temp = @curr - @curr = (@curr + 1) % @n - raise StopIteration if @temp == @n - 1 - end - end - - # Helper class for preflow push algorithm - class Level - attr_reader :inactive, :active - - def initialize - @inactive = Set.new - @active = Set.new - end - end - - # Helper class for preflow push algorithm - class GlobalRelabelThreshold - def initialize(num1, num2, freq) - freq = freq.nil? ? Float::INFINITY : freq - @threshold = (num1 + num2) / freq - @work = 0 - end - - def add_work(work) - @work += work - end - - def reached? - @work >= @threshold - end - - def clear_work - @work = 0 - end - end - - # Builds a residual graph from a constituent graph - # - # @param graph [DiGraph] a graph - # - # @return [DiGraph] residual graph - 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 - - # Detects unboundedness in a graph, raises exception when - # infinite capacity flow is found - # - # @param r_network [DiGraph] a residual graph - # @param source [Object] source node - # @param target [Object] target node - 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 - - # Build flow dictionary of a graph from its residual graph - # - # @param graph [DiGraph] a graph - # @param residual [DiGraph] residual graph - # - # @return [Hash{ Object => Hash{ Object => Numeric }] flowdict containing all - # the flow values in the edges - 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 -end diff --git a/lib/networkx/graph.rb b/lib/networkx/graph.rb deleted file mode 100644 index cc0873f..0000000 --- a/lib/networkx/graph.rb +++ /dev/null @@ -1,447 +0,0 @@ -module NetworkX - # Describes the class for making Undirected Graphs - # - # @attr_reader adj [Hash{ Object => Hash{ Object => Hash{ Object => Object } } }] - # Stores the edges and their attributes in an adjencency list form - # @attr_reader graph [Hash{ Object => Object }] Stores the attributes of the graph - class Graph - attr_reader :adj, :graph - - # Constructor for initializing graph - # - # @example Initialize a graph with attributes 'type' and 'name' - # graph = NetworkX::Graph.new(name: "Social Network", type: "undirected") - # - # @param graph_attrs [Hash{ Object => Object }] the graph attributes in a hash format - def initialize(**graph_attrs) - @nodes = {} - @adj = {} - @graph = graph_attrs - end - - # Adds the respective edges - # - # @example Add an edge with attribute name - # graph.add_edge(node1, node2, name: "Edge1") - # - # @example Add an edge with no attribute - # graph.add_edge("Bangalore", "Chennai") - # - # @param node1 [Object] the first node of the edge - # @param node2 [Object] the second node of the edge - # @param edge_attrs [Hash{ Object => Object }] the hash of the edge attributes - 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 - # - # @example Add multiple edges without any attributes - # graph.add_edges([['Nagpur', 'Kgp'], ['Noida', 'Kgp']]) - # @param edges [Array] - 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 - - def add_edges_from(rng) - rng.each { |node| add_edge(*node) } - end - - # Adds a node and its attributes to the graph - # - # @example Add a node with attribute 'type' - # graph.add_node("Noida", type: "city") - # - # @param node [Object] the node object - # @param node_attrs [Hash{ Object => Object }] the hash of the attributes of the node - 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 - # - # @example Adds multiple nodes with attribute 'type' - # graph.add_nodes([["Noida", type: "city"], ["Kgp", type: "town"]]) - # - # @param nodes [Array Object }>] the Array of pair containing nodes and its attributes - 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 - - # [TODO][EXPERIMENTAL] - # - # @param nodes_for_adding [Array | Range | String] nodes - 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 - - def add_path(paths) - paths.each_cons(2){|x, y| add_edge(x, y) } - end - - # Removes node from the graph - # - # @example - # graph.remove_node("Noida") - # - # @param node [Object] the node to be removed - 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 - # - # @example - # graph.remove_nodes(["Noida", "Bangalore"]) - # - # @param nodes [Array] the array of nodes to be removed - 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 - alias remove_nodes_from remove_nodes - - # Removes edge from the graph - # - # @example - # graph.remove_edge('Noida', 'Bangalore') - # - # @param node1 [Object] the first node of the edge - # @param node2 [Object] the second node of the edge - 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 - # - # @example - # graph.remove_edges([%w[Noida Bangalore], %w[Bangalore Chennai]]) - # - # @param edges [Array] the array of edges to be removed - 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 - alias remove_edges_from remove_edges - - # Adds weighted edge - # - # @example - # graph.add_weighted_edge('Noida', 'Bangalore', 1000) - # - # @param node1 [Object] the first node of the edge - # @param node2 [Object] the second node of the edge - # @param weight [Integer] the weight value - def add_weighted_edge(node1, node2, weight) - add_edge(node1, node2, weight: weight) - end - - # Adds multiple weighted edges - # - # @example - # graph.add_weighted_edges([['Noida', 'Bangalore'], - # ['Noida', 'Nagpur']], [1000, 2000]) - # - # @param edges [Array] the array of edges - # @param weights [Array] the array of weights - 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 - - # [TODO][EXPERIMENTAL] - # - # @param edges [[Object, Object, Integer|Float]] the weight of edge - # @param weight [Symbol] weight name key. default key is `:weight`` - def add_weighted_edges_from(edges, weight: :weight) - edges.each do |s, t, w| - add_edge(s, t, **{weight => w}) - end - end - - # Return nodes of graph - # - # @param data [bool] true if you want data of each edge - # - # @return [Hash | Array] if data is true, it returns hash including data. - # otherwise, simple nodes array. - def nodes(data: false) - if data - @nodes - else - @nodes.keys - end - end - - 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 - - # [TODO][EXPERIMENTAL] - # - # @param data [bool] true if you want data of each edge - # - # @return [Array[[Object, Object]]] edges array - def edges(data: false) - each_edge(data: data).to_a - end - - # [TODO][EXPERIMENTAL] - # - # @param data [bool] true if you want data of each edge - 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 - - # Clears the graph - # - # @example - # graph.clear - def clear - @adj.clear - @nodes.clear - @graph.clear - end - - # Checks if a node is present in the graph - # - # @example - # graph.node?(node1) - # - # @param node [Object] the node to be checked - def node?(node) - @nodes.has_key?(node) - end - alias has_node? node? - - # Checks if the the edge consisting of two nodes is present in the graph - # - # @example - # graph.edge?(node1, node2) - # - # @param node1 [Object] the first node of the edge to be checked - # @param node2 [Object] the second node of the edge to be checked - def edge?(node1, node2) - node?(node1) && @adj[node1].has_key?(node2) - end - alias has_edge? edge? - - # Gets the node data - # - # @example - # graph.get_node_data(node) - # - # @param node [Object] the node whose data is to be fetched - def get_node_data(node) - raise ArgumentError, 'No such node exists!' unless node?(node) - - @nodes[node] - end - - # Gets the edge data - # - # @example - # graph.get_edge_data(node1, node2) - # - # @param node1 [Object] the first node of the edge - # @param node2 [Object] the second node of the edge - def get_edge_data(node1, node2) - raise KeyError, 'No such edge exists!' unless node?(node1) && node?(node2) - - @adj[node1][node2] - end - - # Retus a hash of neighbours of a node - # - # @example - # graph.neighbours(node) - # - # @param node [Object] the node whose neighbours are to be fetched - def neighbours(node) - raise KeyError, 'No such node exists!' unless node?(node) - - @adj[node] - end - - # Returns number of nodes - # - # @example - # graph.number_of_nodes - def number_of_nodes - @nodes.length - end - - # Returns number of edges - # - # @example - # graph.number_of_edges - def number_of_edges - @adj.values.map(&:length).sum / 2 - end - - # Returns the size of the graph - # - # @example - # graph.size(true) - # - # @param is_weighted [Bool] if true, method returns sum of weights of all edges - # else returns number of edges - 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 - # - # @example - # graph.subgraph(%w[Mumbai Nagpur]) - # - # @param nodes [Array] the nodes to be included in the subgraph - 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 - - # Returns subgraph conisting of given edges - # - # @example - # graph.edge_subgraph([%w[Nagpur Wardha], %w[Nagpur Mumbai]]) - # - # @param edges [Array] the edges to be included in the subraph - 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 - - # [EXPERIMENTAL] - def degree(nodes = nil) - if nodes.nil? - @adj.transform_values(&:size) - else - res = {} - nodes.each { |node| res[node] = @adj[node].size } - res - end - end - - 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 - - def multigraph? - ['NetworkX::MultiGraph', 'NetworkX::MultiDiGraph'].include?(self.class.name) - end - - def directed? - ['NetworkX::DiGraph', 'NetworkX::MultiDiGraph'].include?(self.class.name) - end - end -end diff --git a/lib/networkx/link_analysis/hits.rb b/lib/networkx/link_analysis/hits.rb deleted file mode 100644 index 5f5a245..0000000 --- a/lib/networkx/link_analysis/hits.rb +++ /dev/null @@ -1,59 +0,0 @@ -module NetworkX - # Computes hits and authority scores for all the graphs - # - # @param graph [Graph, DiGraph] a graph - # @param max_iter [Integer] max iterations to run the hits algorithm - # @param tol [Numeric] tolerences to cut off the loop - # @param nstart [Array] starting hub values for the nodes - # - # @return [Array] hits and authority scores - 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 authority matrix for the graph - # - # @param graph [Graph, DiGraph] a graph - # - # @return [Matrix] authority matrix for the graph - def self.authority_matrix(graph) - matrix, = to_matrix(graph, 0) - matrix.transpose * matrix - end - - # Computes hub matrix for the graph - # - # @param graph [Graph, DiGraph] a graph - # - # @return [Matrix] hub matrix for the graph - def self.hub_matrix(graph) - matrix, = to_matrix(graph, 0) - matrix * matrix.transpose - end -end diff --git a/lib/networkx/link_analysis/pagerank.rb b/lib/networkx/link_analysis/pagerank.rb deleted file mode 100644 index a995ab7..0000000 --- a/lib/networkx/link_analysis/pagerank.rb +++ /dev/null @@ -1,45 +0,0 @@ -module NetworkX - # Computes pagerank values for the graph - # - # @param graph [Graph] a graph - # @param alpha [Numeric] the alpha value to compute the pagerank - # @param eps [Numeric] tolerence to check for convergence - # @param max_iter [Integer] max iterations for the pagerank algorithm to run - # - # @return [Hash of Object => Float] pagerank values of the graph - 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 -end diff --git a/lib/networkx/multidigraph.rb b/lib/networkx/multidigraph.rb deleted file mode 100644 index 7c936e9..0000000 --- a/lib/networkx/multidigraph.rb +++ /dev/null @@ -1,249 +0,0 @@ -module NetworkX - # Describes the class for making MultiDiGraphs - # - # @attr_reader adj [Hash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } }] - # Stores the edges and their attributes in an adjencency list form - # @attr_reader pred [Hash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } }] - # Stores the reverse edges and their attributes in an adjencency list form - # @attr_reader nodes [Hash{ Object => Hash{ Object => Object } }] Stores the nodes and their attributes - # @attr_reader graph [Hash{ Object => Object }] Stores the attributes of the graph - class MultiDiGraph < DiGraph - # Returns a new key - # - # @param node1 [Object] the first node of a given edge - # @param node2 [Object] the second node of a given edge - 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 - - # Adds the respective edge - # - # @example Add an edge with attribute name - # graph.add_edge(node1, node2, name: "Edge1") - # - # @example Add an edge with no attribute - # graph.add_edge("Bangalore", "Chennai") - # - # @param node1 [Object] the first node of the edge - # @param node2 [Object] the second node of the edge - # @param edge_attrs [Hash{ Object => Object }] the hash of the edge attributes - 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 - - # Removes edge from the graph - # - # @example - # graph.remove_edge('Noida', 'Bangalore') - # - # @param node1 [Object] the first node of the edge - # @param node2 [Object] the second node of the edge - 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 - - # Checks if the the edge consisting of two nodes is present in the graph - # - # @example - # graph.edge?(node1, node2) - # - # @param node1 [Object] the first node of the edge to be checked - # @param node2 [Object] the second node of the edge to be checked - # @param key [Integer] the key of the given edge - 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 - - 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 the undirected version of the graph - # - # @example - # graph.to_undirected - 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 - - # Returns the directed version of the graph - # - # @example - # graph.to_directed - 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 - # - # @example - # graph.to_multigraph - 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 reversed version of the graph - # - # @example - # graph.reverse - 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 in-degree of a given node - # - # @example - # graph.in_degree(node) - # - # @param node [Object] the node whose in degree is to be calculated - def in_degree(node) - @pred[node].values.map(&:length).sum - end - - # Returns out-degree of a given node - # - # @example - # graph.out_degree(node) - # - # @param node [Object] the node whose out degree is to be calculated - def out_degree(node) - @adj[node].values.map(&:length).sum - end - - # Returns number of edges - # - # @example - # graph.number_of_edges - def number_of_edges - @adj.values.flat_map(&:values).map(&:length).sum - end - - # Returns the size of the graph - # - # @example - # graph.size(true) - # - # @param is_weighted [Bool] if true, method returns sum of weights of all edges - # else returns number of edges - 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 - # - # @example - # graph.subgraph(%w[Mumbai Nagpur]) - # - # @param nodes [Array] the nodes to be included in the subgraph - 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 subgraph conisting of given edges - # - # @example - # graph.edge_subgraph([%w[Nagpur Wardha], %w[Nagpur Mumbai]]) - # - # @param edges [Array] the edges to be included in the subraph - 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 - - def multigraph? - true - end - end -end diff --git a/lib/networkx/multigraph.rb b/lib/networkx/multigraph.rb deleted file mode 100644 index 8a82c7b..0000000 --- a/lib/networkx/multigraph.rb +++ /dev/null @@ -1,199 +0,0 @@ -module NetworkX - # Describes the class for making MultiGraphs - # - # @attr_reader adj [Hash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } }] - # Stores the edges and their attributes in an adjencency list form - # @attr_reader nodes [Hash{ Object => Hash{ Object => Object } }] Stores the nodes and their attributes - # @attr_reader graph [Hash{ Object => Object }] Stores the attributes of the gra - class MultiGraph < Graph - # Returns a new key - # - # @param node1 [Object] the first node of a given edge - # @param node2 [Object] the second node of a given edge - 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 - - # Adds the respective edge - # - # @example Add an edge with attribute name - # graph.add_edge(node1, node2, name: "Edge1") - # - # @example Add an edge with no attribute - # graph.add_edge("Bangalore", "Chennai") - # - # @param node1 [Object] the first node of the edge - # @param node2 [Object] the second node of the edge - # @param edge_attrs [Hash{ Object => Object }] the hash of the edge attributes - 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 - - # Removes edge from the graph - # - # @example - # graph.remove_edge('Noida', 'Bangalore') - # - # @param node1 [Object] the first node of the edge - # @param node2 [Object] the second node of the edge - 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 - # - # @example - # graph.size(true) - # - # @param is_weighted [Bool] if true, method returns sum of weights of all edges - # else returns number of edges - 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 number of edges - # - # @example - # graph.number_of_edges - def number_of_edges - @adj.values.flat_map(&:values).map(&:length).sum / 2 - end - - # Checks if the the edge consisting of two nodes is present in the graph - # - # @example - # graph.edge?(node1, node2) - # - # @param node1 [Object] the first node of the edge to be checked - # @param node2 [Object] the second node of the edge to be checked - # @param key [Integer] the key of the given edge - 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 - - 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 - - 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 - - # Returns the undirected version of the graph - # - # @example - # graph.to_undirected - 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 - - # Returns subgraph consisting of given array of nodes - # - # @example - # graph.subgraph(%w[Mumbai Nagpur]) - # - # @param nodes [Array] the nodes to be included in the subgraph - 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 subgraph conisting of given edges - # - # @example - # graph.edge_subgraph([%w[Nagpur Wardha], %w[Nagpur Mumbai]]) - # - # @param edges [Array] the edges to be included in the subraph - 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 - - def multigraph? - true - end - end -end diff --git a/lib/networkx/operators/all.rb b/lib/networkx/operators/all.rb deleted file mode 100644 index 63a55dc..0000000 --- a/lib/networkx/operators/all.rb +++ /dev/null @@ -1,65 +0,0 @@ -module NetworkX - # Performs the union of many graphs - # - # @param graphs [Array, Array, Array, Array] Array of graphs - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] union of all the graphs - 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 - - # Performs the disjoint union of many graphs - # - # @param graphs [Array, Array, Array, Array] Array of graphs - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] disjoint union of all the graphs - 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 - - # Performs the intersection of many graphs - # - # @param graphs [Array, Array, Array, Array] Array of graphs - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] intersection of all the graphs - 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 - - # Performs the composition of many graphs - # - # @param graphs [Array, Array, Array, Array] Array of graphs - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] composition of all the graphs - 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 -end diff --git a/lib/networkx/operators/binary.rb b/lib/networkx/operators/binary.rb deleted file mode 100644 index e4996f4..0000000 --- a/lib/networkx/operators/binary.rb +++ /dev/null @@ -1,233 +0,0 @@ -module NetworkX - # Returns the edges of the graph in an array - 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 - - # Transforms the labels of the nodes of the graphs - # so that they are disjoint. - 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 - - # Performs the intersection of two graphs - # - # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1 - # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2 - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the intersection of the two graphs - 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 difference of two graphs - # - # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1 - # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2 - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the difference of the two graphs - 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 - - # Performs the symmetric difference of two graphs - # - # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1 - # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2 - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the symmetric difference of the two graphs - 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 - - # Performs the composition of two graphs - # - # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1 - # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2 - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the composition of the two graphs - 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 union of two graphs - # - # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1 - # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2 - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the union of the two graphs - 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 disjoint union of two graphs - # - # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1 - # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2 - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the disjoint union of the two graphs - 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 -end diff --git a/lib/networkx/operators/product.rb b/lib/networkx/operators/product.rb deleted file mode 100644 index 89bfdb9..0000000 --- a/lib/networkx/operators/product.rb +++ /dev/null @@ -1,201 +0,0 @@ -module NetworkX - # Returns the edges of the graph in an array - 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 - - # Returns the hash product of two hashes - def self.hash_product(hash1, hash2) - (hash1.keys | hash2.keys).to_h { |n| [n, [hash1[n], hash2[n]]] } - end - - # Returns the node product of nodes of two graphs - 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 edges with edges - 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 - - # Returns the product of undirected edges with edges - 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 - - # Returns the product of edges with edges - 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 directed nodes with edges - 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 product of edges with pairs of nodes - 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 - - # Initializes the product graph - 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 - - # Returns the tensor product of two graphs - # - # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1 - # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2 - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the tensor product of the two graphs - 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 - - # Returns the cartesian product of two graphs - # - # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1 - # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2 - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the cartesian product of the two graphs - 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 lexicographic product of two graphs - # - # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1 - # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2 - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the lexicographic product of the two graphs - 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 strong product of two graphs - # - # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1 - # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2 - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the strong product of the two graphs - 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 - - # Returns the specified power of the graph - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1 - # @param pow [Numeric] the power to which to raise the graph to - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the power of the graph - 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 -end diff --git a/lib/networkx/operators/unary.rb b/lib/networkx/operators/unary.rb deleted file mode 100644 index a0fe098..0000000 --- a/lib/networkx/operators/unary.rb +++ /dev/null @@ -1,17 +0,0 @@ -module NetworkX - # Performs the complement operation on the graph - # - # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph - # - # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the complement of the graph - 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 -end diff --git a/lib/networkx/others/bridges.rb b/lib/networkx/others/bridges.rb deleted file mode 100644 index c616c59..0000000 --- a/lib/networkx/others/bridges.rb +++ /dev/null @@ -1,30 +0,0 @@ -require_relative '../auxillary_functions/union_find' - -module NetworkX - # @return [[Object, Object]] bridges - # - # @param graph [Graph] Graph - def self.bridges(graph) - each_bridge(graph).to_a - end - - # @param graph [Graph] Graph - 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 - - # @return [Integer] the number of bridges - # - # @param graph [Graph] Graph - def self.number_of_bridges(graph) - bridges(graph).size - end -end diff --git a/lib/networkx/others/generators.rb b/lib/networkx/others/generators.rb deleted file mode 100644 index d15991b..0000000 --- a/lib/networkx/others/generators.rb +++ /dev/null @@ -1,237 +0,0 @@ -require_relative '../../networkx' - -module NetworkX - class Graph - # private class method - 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 - - 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 - - def self.barbell_graph(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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - def self.null_graph - new(name: 'null_graph') - end - - 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 - - def self.star_graph(n) - edges = (1..n).map { |i| [0, i] } - - graph = new(name: "star_graph(#{n})") - graph.add_edges(edges) - graph - end - - def self.trivial_graph - trivial_graph = new(name: 'trivial_grpph') - trivial_graph.add_node(0) - trivial_graph - end - - 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 - - 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 - - def self.cubical_graph - graph = circular_ladder_graph(4) - graph.graph[:name] = 'cubical_graph' - graph - end - - 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 - 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 - - 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 - - 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 - - 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 - - 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 - - # 8: 6 nodes, 12 edges - 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 - - def self.tetrahedral_graph - graph = complete_graph(4) - graph.graph[:name] = 'tetrahedral_graph' - graph - end - - # Experimental For debug. - # - # @return data for https://hello-world-494ec.firebaseapp.com/ - def put_graph_x2 - output = <<~"OUTPUT" - #{number_of_nodes} #{number_of_edges} - #{edges.map { |edge| edge.join(' ') }.join("\n")} - OUTPUT - puts output - end - end -end diff --git a/lib/networkx/others/grid_2d_graph.rb b/lib/networkx/others/grid_2d_graph.rb deleted file mode 100644 index 292d98f..0000000 --- a/lib/networkx/others/grid_2d_graph.rb +++ /dev/null @@ -1,38 +0,0 @@ -require_relative '../graph' - -class Array - include Comparable -end - -# Reference: https://networkx.org/documentation/stable/_modules/networkx/generators/lattice.html#grid_2d_graph -module NetworkX - # @param m [Integer] the number of rows - # @param n [Integer] the number of columns - # @param create_using [Class] graph class. this is optional. default is `NetworkX::Graph`. - 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 -end diff --git a/lib/networkx/others/info.rb b/lib/networkx/others/info.rb deleted file mode 100644 index babfb1c..0000000 --- a/lib/networkx/others/info.rb +++ /dev/null @@ -1,11 +0,0 @@ -require_relative '../graph' - -module NetworkX - 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 -end diff --git a/lib/networkx/others/number_connected_components.rb b/lib/networkx/others/number_connected_components.rb deleted file mode 100644 index c03ce98..0000000 --- a/lib/networkx/others/number_connected_components.rb +++ /dev/null @@ -1,17 +0,0 @@ -require_relative '../graph' -require_relative '../auxillary_functions/union_find' - -module NetworkX - # @param [NetworkX::Graph] graph - # - # @return [Integer] the number of connected components on graph - 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 - - class << self - alias number_of_connected_components number_connected_components - end -end diff --git a/lib/networkx/others/reads.rb b/lib/networkx/others/reads.rb deleted file mode 100644 index 1b128bb..0000000 --- a/lib/networkx/others/reads.rb +++ /dev/null @@ -1,52 +0,0 @@ -require_relative '../../networkx' - -module NetworkX - class Graph - class << self - 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 - alias read_edges read_edgelist - - 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 - alias read_weighted_edges read_weighted_edgelist - end - end - - 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 -end diff --git a/lib/networkx/shortest_path/astar.rb b/lib/networkx/shortest_path/astar.rb deleted file mode 100644 index 24305a1..0000000 --- a/lib/networkx/shortest_path/astar.rb +++ /dev/null @@ -1,73 +0,0 @@ -module NetworkX - # Returns path using astar algorithm between source and target - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] a node to start astar from - # @param target [Object] a node to end astar - # @param heuristic [] a lambda to compute heuristic b/w two nodes - # - # @return [Array] an array of nodes forming a path between source - # and target - 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 - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] a node to start astar from - # @param target [Object] a node to end astar - # @param heuristic [] a lambda to compute heuristic b/w two nodes - # - # @return [Numeric] the length of the path - 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 -end diff --git a/lib/networkx/shortest_path/dense.rb b/lib/networkx/shortest_path/dense.rb deleted file mode 100644 index 5af37cf..0000000 --- a/lib/networkx/shortest_path/dense.rb +++ /dev/null @@ -1,29 +0,0 @@ -module NetworkX - # Returns the all pair distance between all the nodes - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # - # @return [Hash{ Object => { Object => { Numeric }}}] a hash containing distances - # b/w all pairs of nodes - 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 -end diff --git a/lib/networkx/shortest_path/unweighted.rb b/lib/networkx/shortest_path/unweighted.rb deleted file mode 100644 index 11c14a8..0000000 --- a/lib/networkx/shortest_path/unweighted.rb +++ /dev/null @@ -1,136 +0,0 @@ -module NetworkX - # Helper function for single source shortest path length - 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 shortest path values to all nodes from a given node - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source to compute path length from - # @param cutoff [Numeric, nil] cutoff for the shortest path algorithm - # - # @return [Array] path lengths for all nodes - 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 - - # Computes shortest path values to all nodes from all nodes - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param cutoff [Numeric, nil] cutoff for the shortest path algorithm - # - # @return [Array>] path lengths for all nodes from all nodes - 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 - - # Helper function for finding single source shortest path - 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 - - # Computes single source shortest path from a node to every other node - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source from which shortest paths are needed - # @param cutoff [Numeric, nil] cutoff for the shortest path algorithm - # - # @return [Array>>] path lengths for all nodes from all nodes - 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 paths to all nodes from all nodes - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param cutoff [Numeric, nil] cutoff for the shortest path algorithm - # - # @return [Array Array }>] paths for all nodes from all nodes - 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 paths to all nodes from all nodes - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source for which predecessors are needed - # @param cutoff [Numeric, nil] cutoff for finding predecessor - # @param return_seen [Boolean] if true, returns seen dict - # - # @return [Array Array }, Hash{ Object => Numeric }>, - # Hash{ Object => Array }] - # predecessors of a given node and/or seen dict - 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 -end diff --git a/lib/networkx/shortest_path/weighted.rb b/lib/networkx/shortest_path/weighted.rb deleted file mode 100644 index fe42680..0000000 --- a/lib/networkx/shortest_path/weighted.rb +++ /dev/null @@ -1,417 +0,0 @@ -module NetworkX - # Helper function to extract weight from a adjecency hash - 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 multisource dijkstra - 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 single source dijkstra - 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 - - # Computes shortest paths and path lengths to a target from one of the nodes - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param sources [Array] Array of sources - # @param target [Object, nil] target node for the dijkstra algorithm - # @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm - # - # @return [Numeric, Array] path lengths for all nodes - 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 path lengths to any from the given nodes - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param sources [Array] Array of sources - # @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm - # - # @return [Hash{ Object => Numeric }] path lengths for any nodes from given nodes - 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 - - # Computes shortest paths to any from the given nodes - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param sources [Array] Array of sources - # @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm - # - # @return [Hash{ Object => Array }] paths for any nodes from given nodes - def self.multisource_dijkstra_path(graph, sources, cutoff = nil) - _, path = multisource_dijkstra(graph, sources, nil, cutoff) - path - end - - # Computes shortest paths and path distances to all nodes/target from the given node - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source - # @param target [Object] target - # @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm - # - # @return [Hash{ Object => Array }, Array] paths for all nodes/target node from given node - def self.singlesource_dijkstra(graph, source, target = nil, cutoff = nil) - multisource_dijkstra(graph, [source], target, cutoff) - end - - # Computes shortest path lengths to all nodes from the given node - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source - # @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm - # - # @return [Hash{ Object => Numeric }] path lengths for all nodes from given node - def self.singlesource_dijkstra_path_length(graph, source, cutoff = nil) - multisource_dijkstra_path_length(graph, [source], cutoff) - end - - # Computes shortest paths to all nodes from the given node - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source - # @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm - # - # @return [Hash{ Object => Array }] paths for all nodes from given node - def self.singlesource_dijkstra_path(graph, source, cutoff = nil) - multisource_dijkstra_path(graph, [source], cutoff) - end - - # Computes shortest path length to target from the given node - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source - # @param target [Object] target - # - # @return [Numeric] path length for target node from given node - 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 shortest path to target from the given node - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source - # @param target [Object] target - # - # @return [Numeric] path for target node from given node - def self.dijkstra_path(graph, source, target) - _, path = singlesource_dijkstra(graph, source, target) - path - end - - # Computes weighted shortest path length and predecessors - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source - # @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm - # - # @return [ Array }, Hash{ Object => Numeric }>] - # predcessor hash and distance hash - 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 - - # Finds shortest weighted paths and lengths between all nodes - # - # @param graph [Graph, DiGrhelp_dijkaph, MultiGraph, MultiDiGraph] a graph - # @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm - # - # @return [Array Numeric }, Hash{ Object => Array }>>] - # paths and path lengths between all nodes - 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 path length between all nodes - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm - # - # @return [Array Numeric }>] path lengths between all nodes - 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 - - # Finds shortest weighted paths between all nodes - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm - # - # @return [Array Array }>] path lengths between all nodes - 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 - - # Helper function for bellman ford - 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 - - # Finds shortest weighted path lengths and predecessors on shortest paths - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source - # @param target [Object, nil] target - # @param cutoff [Numeric, nil] cutoff for the dijkstra algorithm - # - # @return [Array Array }, Hash{ Object => Numeric }>] predecessors and distances - 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 - - 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 - - # Length of shortest path from source to target using Bellman Ford algorithm - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source - # @param target [Object] target - # - # @return [Numeric] distance between source and target - 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 - - # Shortest path from source to target using Bellman Ford algorithm - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source - # @param target [Object] target - # - # @return [Array] path from source to target - def self.bellmanford_path(graph, source, target) - _, path = singlesource_bellmanford(graph, source, target) - path - end - - # Shortest path from source to all nodes using Bellman Ford algorithm - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source - # @param cutoff [Numeric, nil] cutoff for Bellman Ford algorithm - # - # @return [Hash{ Object => Array }] path from source to all nodes - 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 - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] source - # @param cutoff [Numeric, nil] cutoff for Bellman Ford algorithm - # - # @return [Hash{ Object => Numeric }] path lengths from source to all nodes - 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 - - # Shortest path lengths between all nodes using Bellman Ford algorithm - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param cutoff [Numeric, nil] cutoff for Bellman Ford algorithm - # - # @return [Array Numeric }>] path lengths from source to all nodes - 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 - - # Shortest paths between all nodes using Bellman Ford algorithm - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param cutoff [Numeric, nil] cutoff for Bellman Ford algorithm - # - # @return [Array Array }>] path lengths from source to all nodes - 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 - - # Helper function to get sources - def self.get_sources(graph) - graph.nodes(data: true).collect { |k, _v| k } - end - - # Helper function to get distances - 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 - - # Helper function to set path lengths for Johnson algorithm - 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 - - # Returns shortest path between all pairs of nodes - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # - # @return [Array Array }] shortest paths between all pairs of nodes - 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 -end diff --git a/lib/networkx/to_matrix.rb b/lib/networkx/to_matrix.rb deleted file mode 100644 index 4a55f1d..0000000 --- a/lib/networkx/to_matrix.rb +++ /dev/null @@ -1,51 +0,0 @@ -module NetworkX - 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 -end diff --git a/lib/networkx/traversals/bfs.rb b/lib/networkx/traversals/bfs.rb deleted file mode 100644 index 949b7b1..0000000 --- a/lib/networkx/traversals/bfs.rb +++ /dev/null @@ -1,110 +0,0 @@ -module NetworkX - # Returns edges of the graph travelled in breadth first fashion - # - # @example - # NetworkX.bfs_edges(graph, source) - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] node to start bfs from - 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 parent successor pair of the graph travelled in breadth first fashion - # - # @example - # NetworkX.bfs_successors(graph, source) - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] node to start bfs from - 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 - - # Returns predecessor child pair of the graph travelled in breadth first fashion - # - # @example - # NetworkX.bfs_predecessors(graph, source) - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] node to start bfs from - def self.bfs_predecessors(graph, source) - bfs_edges = bfs_edges(graph, source) - predecessors = {} - bfs_edges.each { |u, v| predecessors[v] = u } - predecessors - end - - class Graph - def bfs_nodes(root) - each_bfs_node(root).to_a - end - - 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 - - # [EXPERIMENTAL] - # - # @param [Object] node which is root, start ,source - def bfs_edges(node) - each_bfs_edge(node).to_a - end - - # [EXPERIMENTAL] - # - # @param [Object] node which is root, start ,source - 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 - end -end diff --git a/lib/networkx/traversals/dfs.rb b/lib/networkx/traversals/dfs.rb deleted file mode 100644 index 853a1e4..0000000 --- a/lib/networkx/traversals/dfs.rb +++ /dev/null @@ -1,135 +0,0 @@ -module NetworkX - # Returns edges of the graph travelled in depth first fashion - # - # @example - # NetworkX.dfs_edges(graph, source) - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] node to start dfs from - # @param depth_limit [Integer, nil] the depth limit of dfs - 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 dfs tree of the graph - # - # @example - # NetworkX.dfs_tree(graph, source) - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] node to start dfs from - # @param depth_limit [Integer, nil] the depth limit of dfs - 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 parent successor pair of the graph travelled in depth first fashion - # - # @example - # NetworkX.dfs_successors(graph, source) - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] node to start dfs from - # @param depth_limit [Integer, nil] the depth limit of dfs - 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 predecessor child pair of the graph travelled in depth first fashion - # - # @example - # NetworkX.dfs_predecessors(graph, source) - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param source [Object] node to start dfs from - # @param depth_limit [Integer, nil] the depth limit of dfs - 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 - - class Graph - # [EXPERIMENTAL] - # - # @param root [Object] node which is root, start, source - # - # @return [Array[Object]] nodes - def dfs_preorder_nodes(root) - each_dfs_preorder_node(root).to_a - end - - # [EXPERIMENTAL] - # - # @param root [Object] node which is root, start, source - 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 - - # [EXPERIMENTAL] - # - # @param root [Object] node which is root, start, source - # - # @return [Array[Object]] array of dfs postorder nodes - 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 - - # @param root [Object] node which is root, start, source - 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 - end -end diff --git a/lib/networkx/traversals/edge_dfs.rb b/lib/networkx/traversals/edge_dfs.rb deleted file mode 100644 index 6c174c7..0000000 --- a/lib/networkx/traversals/edge_dfs.rb +++ /dev/null @@ -1,114 +0,0 @@ -module NetworkX - # Helper function for edge_dfs - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param node [Object] a node in the graph - 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 - - # Helper function of edge_dfs - 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 - - # 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 - # - # @example - # NetworkX.edge_dfs(graph, source, 'ignore') - # - # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] a graph - # @param start [Object] node to start dfs from - # @param orientation [:ignore, :reverse', nil] the orientation of edges of graph - 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 - - class Graph - def dfs_edges(node) - each_dfs_edge(node).to_a - end - - 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 - end -end diff --git a/lib/networkx/version.rb b/lib/networkx/version.rb deleted file mode 100644 index 48dbb27..0000000 --- a/lib/networkx/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module NetworkX - VERSION = '0.4.0'.freeze -end diff --git a/method_list.html b/method_list.html new file mode 100644 index 0000000..844cd99 --- /dev/null +++ b/method_list.html @@ -0,0 +1,2307 @@ + + + + + + + + + + + + + + + + + + Method List + + + +
+
+

Method List

+ + + +
+ + +
+ + diff --git a/networkx.gemspec b/networkx.gemspec deleted file mode 100644 index 5467ad8..0000000 --- a/networkx.gemspec +++ /dev/null @@ -1,41 +0,0 @@ -lib = File.expand_path('lib', __dir__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'networkx/version' - -NetworkX::DESCRIPTION = <= 2.0' - spec.add_development_dependency 'rake', '>= 13.0' - spec.add_development_dependency 'rspec', '>= 3.0' - spec.add_development_dependency 'rspec-its', '>= 1.0' - spec.add_development_dependency 'rubocop', '>= 1.0' - spec.add_development_dependency 'rubocop-rake', '>= 0.6' - spec.add_development_dependency 'rubocop-rspec', '>= 2.0' - spec.add_development_dependency 'rubygems-tasks', '>= 0.2' - spec.add_development_dependency 'saharspec', '>= 0.0' - spec.add_development_dependency 'simplecov', '>= 0.21' - spec.add_development_dependency 'yard', '>= 0.9' - - spec.add_runtime_dependency 'matrix', '>= 0.4' - spec.add_runtime_dependency 'rb_heap', '>= 1.0' - - spec.metadata['rubygems_mfa_required'] = 'true' -end diff --git a/spec/network_x/auxillary_functions/digraph_dag_spec.rb b/spec/network_x/auxillary_functions/digraph_dag_spec.rb deleted file mode 100644 index 120a377..0000000 --- a/spec/network_x/auxillary_functions/digraph_dag_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -RSpec.describe NetworkX::DiGraph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2) - graph.add_edge(2, 4) - graph.add_edge(1, 4) - graph.add_edge(5, 6) - graph.add_edge(7, 6) - graph.add_edge(5, 7) - end - - context 'when ancestors is called' do - subject { NetworkX.ancestors(graph, 4) } - - it { is_expected.to eq([1, 2]) } - end - - context 'when descendants is called' do - subject { NetworkX.descendants(graph, 1) } - - it { is_expected.to eq([2, 4]) } - end - - context 'when topological_sort is called' do - subject { NetworkX.topological_sort(graph) } - - it { is_expected.to eq([1, 5, 2, 7, 4, 6]) } - end -end diff --git a/spec/network_x/auxillary_functions/graph_cliques_spec.rb b/spec/network_x/auxillary_functions/graph_cliques_spec.rb deleted file mode 100644 index 0d66539..0000000 --- a/spec/network_x/auxillary_functions/graph_cliques_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2) - graph.add_edge(2, 4) - graph.add_edge(1, 4) - graph.add_edge(5, 6) - graph.add_edge(7, 6) - graph.add_edge(5, 7) - end - - context 'when cliques is called' do - subject { NetworkX.find_cliques(graph) } - - it { is_expected.to eq([[7, 5, 6], [1, 2, 4]]) } - end - - it 'number of cliques' do - graph = NetworkX::Graph.new - graph.add_edges([[1, 2], [1, 5], [2, 3], [2, 5], [3, 4], [4, 5], [4, 6]]) - expect(NetworkX.number_of_cliques(graph, 1)).to be 1 - expect(NetworkX.number_of_cliques(graph, 2)).to be 2 - expect(NetworkX.number_of_cliques(graph, 3)).to be 2 - expect(NetworkX.number_of_cliques(graph, 4)).to be 3 - expect(NetworkX.number_of_cliques(graph, 5)).to be 2 - expect(NetworkX.number_of_cliques(graph, 6)).to be 1 - end -end diff --git a/spec/network_x/auxillary_functions/graph_cycles_spec.rb b/spec/network_x/auxillary_functions/graph_cycles_spec.rb deleted file mode 100644 index 670cecb..0000000 --- a/spec/network_x/auxillary_functions/graph_cycles_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2) - graph.add_edge(2, 4) - graph.add_edge(4, 1) - graph.add_edge(1, 3) - graph.add_edge(3, 10) - graph.add_edge(1, 10) - graph.add_edge(5, 6) - graph.add_edge(6, 7) - graph.add_edge(7, 5) - end - - context 'when cycle_basis is called' do - subject { NetworkX.cycle_basis(graph, 1) } - - it { is_expected.to eq([[4, 2, 1], [10, 3, 1], [7, 6, 5]]) } - end - - context 'when find_cycle is called' do - subject { NetworkX.find_cycle(graph, 1) } - - it { is_expected.to eq([[1, 2], [2, 4], [4, 1]]) } - end - - it 'when find_cycle occures ArgumentError' do - empty_graph = NetworkX::Graph.empty_graph(3) - expect{ NetworkX.find_cycle(empty_graph, 0) }.to raise_error(ArgumentError) - - null_graph = NetworkX::Graph.null_graph - expect{ NetworkX.find_cycle(null_graph, 0) }.to raise_error(ArgumentError) - - tree = NetworkX::Graph.balanced_tree(3, 2) - expect{ NetworkX.find_cycle(tree, 0) }.to raise_error(ArgumentError) - end - - it 'cycle? only for Undirected Graph' do - undirected_graph = NetworkX::Graph.new - expect(NetworkX.cycle?(undirected_graph)).to be false - - undirected_graph.add_edge(0, 1) - expect(NetworkX.cycle?(undirected_graph)).to be false - - undirected_graph.add_edge(1, 2) - expect(NetworkX.cycle?(undirected_graph)).to be false - - undirected_graph.add_edge(2, 0) - expect(NetworkX.cycle?(undirected_graph)).to be_truthy - end -end diff --git a/spec/network_x/auxillary_functions/graph_eccentricity_spec.rb b/spec/network_x/auxillary_functions/graph_eccentricity_spec.rb deleted file mode 100644 index 6b21b78..0000000 --- a/spec/network_x/auxillary_functions/graph_eccentricity_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2) - graph.add_edge(2, 4) - end - - context 'when eccentricity is called' do - subject { NetworkX.eccentricity(graph, 1) } - - it { is_expected.to eq(2) } - end - - context 'when diameter is called' do - subject { NetworkX.diameter(graph) } - - it { is_expected.to eq(2) } - end - - context 'when radius is called' do - subject { NetworkX.radius(graph) } - - it { is_expected.to eq(1) } - end -end diff --git a/spec/network_x/auxillary_functions/graph_mis_spec.rb b/spec/network_x/auxillary_functions/graph_mis_spec.rb deleted file mode 100644 index 72b2a22..0000000 --- a/spec/network_x/auxillary_functions/graph_mis_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2) - graph.add_edge(2, 4) - graph.add_edge(1, 4) - graph.add_edge(5, 2) - end - - context 'when mis is called' do - subject { NetworkX.maximal_independent_set(graph, [1]) } - - it { is_expected.to eq([1, 5]) } - end -end diff --git a/spec/network_x/auxillary_functions/graph_mst_spec.rb b/spec/network_x/auxillary_functions/graph_mst_spec.rb deleted file mode 100644 index f5ca8c0..0000000 --- a/spec/network_x/auxillary_functions/graph_mst_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2) - graph.add_edge(2, 4) - graph.add_edge(1, 4) - graph.add_edge(5, 2) - end - - context 'when mst is called' do - subject { NetworkX.minimum_spanning_tree(graph) } - - its('adj') { is_expected.to eq(1 => {2 => {}, 4 => {}}, 2 => {1 => {}, 5 => {}}, 4 => {1 => {}}, 5 => {2 => {}}) } - end -end diff --git a/spec/network_x/auxillary_functions/graph_vitality_spec.rb b/spec/network_x/auxillary_functions/graph_vitality_spec.rb deleted file mode 100644 index a67f16a..0000000 --- a/spec/network_x/auxillary_functions/graph_vitality_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2) - graph.add_edge(2, 4) - graph.add_edge(1, 4) - graph.add_edge(5, 2) - end - - context 'when vitality is called' do - subject { NetworkX.closeness_vitality(graph, 1) } - - it { is_expected.to eq(4) } - end -end diff --git a/spec/network_x/auxillary_functions/graph_wiener_spec.rb b/spec/network_x/auxillary_functions/graph_wiener_spec.rb deleted file mode 100644 index 8740c72..0000000 --- a/spec/network_x/auxillary_functions/graph_wiener_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2) - graph.add_edge(2, 4) - graph.add_edge(1, 4) - graph.add_edge(5, 2) - end - - context 'when wiener_index is called' do - subject { NetworkX.wiener_index(graph) } - - it { is_expected.to eq(8) } - end -end diff --git a/spec/network_x/auxillary_functions/union_find_spec.rb b/spec/network_x/auxillary_functions/union_find_spec.rb deleted file mode 100644 index 7f567d1..0000000 --- a/spec/network_x/auxillary_functions/union_find_spec.rb +++ /dev/null @@ -1,81 +0,0 @@ -RSpec.describe NetworkX::Graph do - it 'test empty' do - uf = NetworkX::UnionFind.new - expect(uf.parents).to eq({}) - expect(uf.weights).to eq({}) - end - - it 'test simple' do - uf = NetworkX::UnionFind.new([0, 1]) - expect(uf.connected?(0, 1)).to be false - - uf.union(0, 1) - expect(uf.connected?(0, 1)).to be true - end - - it 'test []' do - uf = NetworkX::UnionFind.new([0, 1]) - expect(uf[0] == uf[1]).to be false - expect(uf[3] == uf[0]).to be false - - uf.union(0, 1) - uf.union(3, 1) - expect(uf[0] == uf[1]).to be true - expect(uf[3] == uf[0]).to be true - expect(uf[5] == uf[3]).to be false - end - - it 'test each' do - uf = NetworkX::UnionFind.new(('a'..'e')) - uf.union('a', 'd') - uf.union('d', 'c') - expect(uf.each.to_a).to eq ('a'..'e').to_a - end - - it 'test groups' do - uf = NetworkX::UnionFind.new((0...4)) - groups = uf.groups.map(&:sort).sort - expect(groups.size).to eq 4 - expect(groups).to eq [[0], [1], [2], [3]] - - uf.union(0, 1) - uf.union(2, 3) - groups = uf.groups.map(&:sort).sort - expect(groups.size).to eq 2 - expect(groups[0]).to eq [0, 1] - expect(groups[1]).to eq [2, 3] - - uf.union(0, 2) - groups = uf.groups.map(&:sort).sort - expect(groups.size).to eq 1 - expect(groups[0]).to eq [0, 1, 2, 3] - end - - it 'test groups (symbol case)' do - uf = NetworkX::UnionFind.new([:a, :b, :c, :d, :e, :f]) - expect(uf.groups.size).to eq 6 - - uf.unite(:a, :b) - expect(uf.groups.size).to eq 5 - - uf.unite(:b, :d, :e) - expect(uf.groups.size).to eq 3 - end - - it 'test multiple unite' do - uf = NetworkX::UnionFind.new((6..15)) - expect(uf[11] == uf[9]).to be false - expect(uf[9] == uf[10]).to be false - expect(uf[7] == uf[15]).to be false - uf.union(9, 6, 15, 10, 8) - expect(uf[9] == uf[10]).to be true - uf.union(7, 6, 8) - expect(uf[7] == uf[15]).to be true - expect(uf[11] == uf[9]).to be false - end - - it 'test UnionFind Error node' do - uf = NetworkX::UnionFind.new(%w[a b c]) - expect { uf.root('x') }.to raise_error(ArgumentError, 'x is not a node') - end -end diff --git a/spec/network_x/di_graph_spec.rb b/spec/network_x/di_graph_spec.rb deleted file mode 100644 index 6586693..0000000 --- a/spec/network_x/di_graph_spec.rb +++ /dev/null @@ -1,232 +0,0 @@ -RSpec.describe NetworkX::DiGraph do - subject { graph } - - let(:graph) { described_class.new(name: 'Cities', type: 'directed') } - - before do - graph.add_nodes(%w[Nagpur Mumbai]) - graph.add_edge('Nagpur', 'Mumbai') - graph.add_edges([%w[Nagpur Chennai], %w[Chennai Bangalore]]) - graph.add_node('Kolkata') - end - - context 'when graph has been assigned attributes' do - its('graph') { is_expected.to eq(name: 'Cities', type: 'directed') } - end - - context 'when a new node/s has/have been created' do - its('nodes') do - is_expected.to eq('Kolkata' => {}, - 'Nagpur' => {}, - 'Mumbai' => {}, - 'Chennai' => {}, - 'Bangalore' => {}) - end - end - - context 'when a new edge/s has/have been added' do - its('adj') do - is_expected.to eq('Nagpur' => {'Mumbai' => {}, 'Chennai' => {}}, - 'Bangalore' => {}, - 'Chennai' => {'Bangalore' => {}}, - 'Mumbai' => {}, 'Kolkata' => {}) - end - - its('pred') do - is_expected.to eq('Nagpur' => {}, - 'Bangalore' => {'Chennai' => {}}, - 'Chennai' => {'Nagpur' => {}}, - 'Mumbai' => {'Nagpur' => {}}, 'Kolkata' => {}) - end - end - - it 'node' do - graph = NetworkX::DiGraph.new - graph.add_edges([[1, 2], [5, 6]]) - graph.add_node(10, name: 'ten') - expect(graph.nodes(data: false).sort).to eq([1, 2, 5, 6, 10]) - expect(graph.nodes(data: true)).to eq({1 => {}, 2 => {}, 5 => {}, 6 => {}, 10 => {name: 'ten'}}) - end - - context 'when node/s is/are removed' do - before do - graph.remove_node('Nagpur') - graph.remove_nodes(%w[Chennai Mumbai]) - end - - its('nodes') { is_expected.to eq('Kolkata' => {}, 'Bangalore' => {}) } - its('adj') { is_expected.to eq('Kolkata' => {}, 'Bangalore' => {}) } - end - - context 'when edge/s is/are removed' do - before do - graph.remove_edge('Nagpur', 'Mumbai') - graph.remove_edges([%w[Nagpur Chennai], %w[Chennai Bangalore]]) - end - - its('adj') do - is_expected.to eq('Kolkata' => {}, 'Bangalore' => {}, \ - 'Nagpur' => {}, 'Chennai' => {}, 'Mumbai' => {}) - end - end - - it 'tests DiGraph#clear' do - graph = NetworkX::DiGraph.new(name: 'test') - graph.add_edge(:x, :y, key: 'first') - graph.add_edge(:x, :y, key: 'second') - graph.clear - expect(graph.number_of_edges).to be 0 - expect(graph.number_of_nodes).to be 0 - expect(graph.graph).to eq({}) - expect(graph.adj).to eq({}) - end - - context 'when weighted edge/s is/are added' do - before do - graph.add_weighted_edge('Nagpur', 'Mumbai', 15) - graph.add_weighted_edges([%w[Nagpur Kolkata]], [10]) - end - - its('adj') do - is_expected.to eq('Bangalore' => {}, - 'Chennai' => {'Bangalore' => {}}, - 'Kolkata' => {}, - 'Mumbai' => {}, - 'Nagpur' => {'Mumbai' => {weight: 15}, 'Chennai' => {}, 'Kolkata' => {weight: 10}}) - end - end - - context 'when number of edges are calculated' do - its('number_of_edges') do - is_expected.to eq 3 - end - end - - it 'test number_of_edges of empty graph returns 0' do - empty_graph = NetworkX::DiGraph.new - expect(empty_graph.number_of_edges).to be 0 - end - - it 'test indegree & out_degree of MultiDiGraph with no edge' do - graph = NetworkX::DiGraph.new - graph.add_node(0) - graph.add_node(1) - - expect(graph.in_degree(0)).to be 0 - expect(graph.in_degree(1)).to be 0 - expect(graph.out_degree(0)).to be 0 - expect(graph.out_degree(1)).to be 0 - end - - it 'test indegree & out_degree of simple MultiDiGraph' do - graph = NetworkX::DiGraph.new - graph.add_edges([[0, 1], [1, 2], [2, 3], [3, 4]]) - - expect(graph.in_degree(0)).to be 0 - expect(graph.in_degree(1)).to be 1 - expect(graph.in_degree(2)).to be 1 - expect(graph.in_degree(3)).to be 1 - expect(graph.in_degree(4)).to be 1 - - expect(graph.out_degree(0)).to be 1 - expect(graph.out_degree(1)).to be 1 - expect(graph.out_degree(2)).to be 1 - expect(graph.out_degree(3)).to be 1 - expect(graph.out_degree(4)).to be 0 - end - - context 'when size is called' do - subject { graph.size(true) } - - before do - graph.add_weighted_edge('Nagpur', 'Mumbai', 15) - end - - it do - is_expected.to eq 15 - end - end - - it 'test size' do - graph = NetworkX::DiGraph.new - expect(graph.size).to be 0 - expect(graph.size(true)).to be 0 - - graph.add_edge(:s, :t, weight: 10) - expect(graph.size).to be 1 - expect(graph.size(true)).to be 10 - end - - context 'when subgraph is called' do - subject { graph.subgraph(%w[Nagpur Mumbai]) } - - its('nodes') do - is_expected.to eq('Nagpur' => {}, 'Mumbai' => {}) - end - - its('adj') do - is_expected.to eq('Nagpur' => {'Mumbai' => {}}, 'Mumbai' => {}) - end - end - - it 'test `subgraph` method' do - g = NetworkX::DiGraph.new - g.add_nodes_from(0...4) - g.add_edges([[0, 1], [1, 2], [1, 3]]) - - h = g.subgraph([0, 1, 2]) - - expect(h.number_of_nodes).to eq 3 - expect(h.edges).to eq [[0, 1], [1, 2]] - end - - context 'when edges_subgraph is called' do - subject { graph.edge_subgraph([%w[Nagpur Mumbai], %w[Nagpur Chennai]]) } - - its('nodes') do - is_expected.to eq('Nagpur' => {}, 'Mumbai' => {}, 'Chennai' => {}) - end - - its('adj') do - is_expected.to eq('Nagpur' => {'Chennai' => {}, 'Mumbai' => {}}, 'Mumbai' => {}, 'Chennai' => {}) - end - end - - it 'tests error of subgraph & edge_subgraph' do - g = NetworkX::DiGraph.new - expect { g.subgraph(nil) }.to raise_error(ArgumentError) - expect { g.edge_subgraph(nil) }.to raise_error(ArgumentError) - end - - context 'when reverse is called' do - subject { graph.reverse } - - its('adj') do - is_expected.to eq('Nagpur' => {}, - 'Bangalore' => {'Chennai' => {}}, - 'Chennai' => {'Nagpur' => {}}, - 'Mumbai' => {'Nagpur' => {}}, 'Kolkata' => {}) - end - end - - it 'to_undirected' do - directed_graph = NetworkX::DiGraph.new(name: 'Di') - directed_graph.add_edges([[:a, :b], [:c, :d]]) - - undirected_graph = directed_graph.to_undirected - expect(undirected_graph.class).to eq NetworkX::Graph - expect(undirected_graph.graph[:name]).to eq 'Di' - expect(undirected_graph.number_of_edges).to be 2 - expect(undirected_graph.number_of_nodes).to be 4 - end - - it 'directed?' do - directed_graph = NetworkX::DiGraph.new - expect(directed_graph.directed?).to be true - end - - it 'multigraph?' do - directed_graph = NetworkX::DiGraph.new - expect(directed_graph.multigraph?).to be false - end -end diff --git a/spec/network_x/flow/digraph_capacityscaling_spec.rb b/spec/network_x/flow/digraph_capacityscaling_spec.rb deleted file mode 100644 index 3ae395f..0000000 --- a/spec/network_x/flow/digraph_capacityscaling_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -RSpec.describe NetworkX::DiGraph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2) - graph.add_edge(2, 4) - end - - context 'when capacity_scaling is called' do - subject { NetworkX.capacity_scaling(graph) } - - it { is_expected.to eq([0, {1 => {2 => 0}, 2 => {4 => 0}, 4 => {}}]) } - end - - it 'negative_edge_cycle when Argument Error in this method' do - graph = NetworkX::Graph.new - graph.add_weighted_edges([[:a, :b], [:b, :a]], [9, -10]) - - expect(NetworkX.negative_edge_cycle(graph)).to be_truthy - end -end diff --git a/spec/network_x/flow/digraph_edmondskarp_spec.rb b/spec/network_x/flow/digraph_edmondskarp_spec.rb deleted file mode 100644 index 6621b4e..0000000 --- a/spec/network_x/flow/digraph_edmondskarp_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -RSpec.describe NetworkX::DiGraph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2, capacity: 1) - graph.add_edge(2, 4, capacity: 1) - end - - context 'when edmondskarp is called' do - subject { NetworkX.edmondskarp(graph, 1, 4) } - - its('adj') do - is_expected.to eq(1 => {2 => {capacity: 1, flow: 1}}, - 2 => {1 => {capacity: 0, flow: -1}, - 4 => {capacity: 1, flow: 1}}, - 4 => {2 => {capacity: 0, flow: -1}}) - end - end - - it 'when edmondskarp is called for DiGraph with no capacity' do - graph = NetworkX::DiGraph.new - graph.add_edge(1, 2) - graph.add_edge(2, 4) - expect{ NetworkX.edmondskarp(graph, 1, 4) }.to raise_error(ArgumentError) - end - - it 'when edmondskarp is called for simple DiGraph' do - graph = NetworkX::DiGraph.new - graph.add_edge(1, 2, capacity: 1) - graph.add_edge(2, 4, capacity: 1) - r = NetworkX.edmondskarp(graph, 1, 4) - expect(r.graph[:flow_value]).to be 1 - end - - it 'edmond_carp' do - g = NetworkX::DiGraph.new - g.add_edge('x', 'a', capacity: 3.0) - g.add_edge('x', 'b', capacity: 1.0) - g.add_edge('a', 'c', capacity: 3.0) - g.add_edge('b', 'c', capacity: 5.0) - g.add_edge('b', 'd', capacity: 4.0) - g.add_edge('d', 'e', capacity: 2.0) - g.add_edge('c', 'y', capacity: 2.0) - g.add_edge('e', 'y', capacity: 3.0) - r = NetworkX.edmondskarp(g, 'x', 'y') - expect(r.graph[:flow_value]).to be 3.0 - end -end diff --git a/spec/network_x/flow/digraph_preflowpush_spec.rb b/spec/network_x/flow/digraph_preflowpush_spec.rb deleted file mode 100644 index dad7a3d..0000000 --- a/spec/network_x/flow/digraph_preflowpush_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -RSpec.describe NetworkX::DiGraph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2, capacity: 1) - graph.add_edge(2, 4, capacity: 3) - end - - context 'when preflowpush is called' do - subject { NetworkX.preflowpush(graph, 1, 4) } - - its('adj') do - is_expected.to eq(1 => {2 => {capacity: 1, flow: 1}}, - 2 => {1 => {capacity: 0, flow: -1}, 4 => {capacity: 3, flow: 1}}, - 4 => {2 => {capacity: 0, flow: -1}}) - end - end -end diff --git a/spec/network_x/flow/digraph_shortestaugmentingpath_spec.rb b/spec/network_x/flow/digraph_shortestaugmentingpath_spec.rb deleted file mode 100644 index 9617d69..0000000 --- a/spec/network_x/flow/digraph_shortestaugmentingpath_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -RSpec.describe NetworkX::DiGraph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2, capacity: 1) - graph.add_edge(2, 4, capacity: 1) - end - - context 'when shortest_augmenting_path is called' do - subject { NetworkX.shortest_augmenting_path(graph, 1, 4) } - - its('adj') do - is_expected.to eq(1 => {2 => {capacity: 1, flow: 1}}, - 2 => {1 => {capacity: 0, flow: -1}, - 4 => {capacity: 1, flow: 1}}, - 4 => {2 => {capacity: 0, flow: -1}}) - end - end - - it 'shortest_augmenting_path for DiGraph with no capacity' do - graph = NetworkX::DiGraph.new - graph.add_edge(1, 2) - graph.add_edge(2, 4) - expect{ NetworkX.shortest_augmenting_path(graph, 1, 4) }.to raise_error(ArgumentError) - end - - it 'shortes augmeting path' do - g = NetworkX::DiGraph.new - g.add_edge('x', 'a', capacity: 3.0) - g.add_edge('x', 'b', capacity: 1.0) - g.add_edge('a', 'c', capacity: 3.0) - g.add_edge('b', 'c', capacity: 5.0) - g.add_edge('b', 'd', capacity: 4.0) - g.add_edge('d', 'e', capacity: 2.0) - g.add_edge('c', 'y', capacity: 2.0) - g.add_edge('e', 'y', capacity: 3.0) - r = NetworkX.shortest_augmenting_path(g, 'x', 'y') - expect(r.graph[:flow_value]).to be 3.0 - end -end diff --git a/spec/network_x/flow/others_spec.rb b/spec/network_x/flow/others_spec.rb deleted file mode 100644 index ecdb81c..0000000 --- a/spec/network_x/flow/others_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -RSpec.describe NetworkX do - it 'test arbitrary_element method' do - expect(NetworkX.arbitrary_element(Set[-1, -2, -3])).to eq(-1) - expect(NetworkX.arbitrary_element([10, 20, 30])).to eq 10 - expect(NetworkX.arbitrary_element('xyz')).to eq 'x' - expect(NetworkX.arbitrary_element({s: 99, t: 100})).to eq :s - expect(NetworkX.arbitrary_element(80..90)).to eq 80 - end -end diff --git a/spec/network_x/graph_spec.rb b/spec/network_x/graph_spec.rb deleted file mode 100644 index 19db6d1..0000000 --- a/spec/network_x/graph_spec.rb +++ /dev/null @@ -1,277 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new(name: 'Cities', type: 'undirected') } - - before do - graph.add_nodes(%w[Nagpur Mumbai]) - graph.add_edge('Nagpur', 'Mumbai') - graph.add_edges([%w[Nagpur Chennai], %w[Chennai Bangalore]]) - graph.add_node('Kolkata') - end - - context 'when graph has been assigned attributes' do - its('graph') { is_expected.to eq(name: 'Cities', type: 'undirected') } - end - - context 'when a new node/s has/have been created' do - its('nodes') do - is_expected.to eq(%w[Nagpur Mumbai Chennai Bangalore Kolkata]) - end - end - - context 'when a new edge/s has/have been added' do - its('adj') do - is_expected.to eq('Nagpur' => {'Mumbai' => {}, 'Chennai' => {}}, - 'Bangalore' => {'Chennai' => {}}, - 'Chennai' => {'Nagpur' => {}, 'Bangalore' => {}}, - 'Mumbai' => {'Nagpur' => {}}, 'Kolkata' => {}) - end - end - - it 'nodes' do - graph = NetworkX::Graph.new - graph.add_edges([[:x, :y], [:y, :z]]) - expect(graph.nodes(data: false).sort).to eq([:x, :y, :z]) - expect(graph.nodes(data: true)).to eq({x: {}, y: {}, z: {}}) - end - - it 'each_node' do - graph = NetworkX::Graph.new - graph.add_edges([[:x, :y], [:y, :z]]) - expect(graph.each_node.to_a).to eq([:x, :y, :z]) - expect(graph.each_node(data: true).to_a).to eq([[:x, {}], [:y, {}], [:z, {}]]) - end - - it 'add_path' do - graph = NetworkX::Graph.new - graph.add_path(%i[a b c]) - expect(graph.number_of_nodes).to be 3 - expect(graph.number_of_edges).to be 2 - expect(graph.edges).to eq [[:a, :b], [:b, :c]] - end - - context 'when node/s is/are removed' do - before do - graph.remove_node('Nagpur') - graph.remove_nodes(%w[Chennai Mumbai]) - end - - its('nodes') { is_expected.to eq(%w[Bangalore Kolkata]) } - its('adj') { is_expected.to eq('Kolkata' => {}, 'Bangalore' => {}) } - end - - context 'when edge/s is/are removed' do - before do - graph.remove_edge('Nagpur', 'Mumbai') - graph.remove_edges([%w[Nagpur Chennai], %w[Chennai Bangalore]]) - end - - its('adj') do - is_expected.to eq('Kolkata' => {}, 'Bangalore' => {}, \ - 'Nagpur' => {}, 'Chennai' => {}, 'Mumbai' => {}) - end - end - - context 'when weighted edge/s is/are added' do - before do - graph.add_weighted_edge('Nagpur', 'Mumbai', 15) - graph.add_weighted_edges([%w[Nagpur Kolkata]], [10]) - end - - its('adj') do - is_expected.to eq('Bangalore' => {'Chennai' => {}}, - 'Chennai' => {'Nagpur' => {}, 'Bangalore' => {}}, - 'Kolkata' => {'Nagpur' => {weight: 10}}, - 'Mumbai' => {'Nagpur' => {weight: 15}}, - 'Nagpur' => {'Mumbai' => {weight: 15}, 'Chennai' => {}, 'Kolkata' => {weight: 10}}) - end - end - - context 'when number of edges are calculated' do - its('number_of_edges') do - is_expected.to eq 3 - end - end - - it 'test number_of_edges of empty graph returns 0' do - empty_graph = NetworkX::Graph.new - expect(empty_graph.number_of_edges).to be 0 - end - - it 'when size is called' do - graph.add_weighted_edge('Nagpur', 'Mumbai', 15) - expect(graph.size).to be 3 - expect(graph.size(true)).to eq 15 - end - - context 'when subgraph is called' do - subject { graph.subgraph(%w[Nagpur Mumbai]) } - - its('nodes') do - is_expected.to eq(%w[Nagpur Mumbai]) - end - - its('adj') do - is_expected.to eq('Nagpur' => {'Mumbai' => {}}, 'Mumbai' => {'Nagpur' => {}}) - end - end - - context 'when edges_subgraph is called' do - subject { graph.edge_subgraph([%w[Nagpur Mumbai], %w[Nagpur Chennai]]) } - - its('nodes') do - is_expected.to eq(%w[Nagpur Mumbai Chennai]) - end - - its('adj') do - is_expected.to eq('Nagpur' => {'Chennai' => {}, 'Mumbai' => {}}, \ - 'Mumbai' => {'Nagpur' => {}}, 'Chennai' => {'Nagpur' => {}}) - end - end - - it 'test `subgraph` method' do - g = NetworkX::Graph.new - g.add_nodes_from(0...4) - g.add_edges([[0, 1], [1, 2], [1, 3]]) - - h = g.subgraph([0, 1, 2]) - - expect(h.nodes(data: false)).to eq [0, 1, 2] - expect(h.edges).to eq [[0, 1], [1, 2]] - end - - it 'test errors' do - g = NetworkX::Graph.new - expect { g.add_edges('abc') }.to raise_error(ArgumentError) - expect { g.add_nodes(nil) }.to raise_error(ArgumentError) - expect { g.remove_nodes('wwww') }.to raise_error(ArgumentError) - expect { g.remove_edges('css') }.to raise_error(ArgumentError) - expect { g.get_edge_data('yes', 'no') }.to raise_error(KeyError, 'No such edge exists!') - expect { g.subgraph('xxx') }.to raise_error(ArgumentError) - expect { g.edge_subgraph('xxx') }.to raise_error(ArgumentError) - end - - it 'test get_node_data' do - g = NetworkX::Graph.new - g.add_node('Tokyo', country: 'Japan') - expect(g.get_node_data('Tokyo')).to eq({country: 'Japan'}) - end - - it 'test get_edge_data' do - g = NetworkX::Graph.new - g.add_edge('New York', 'Tokyo', time_diff: 14) - expect(g.get_edge_data('New York', 'Tokyo')).to eq({time_diff: 14}) - end - - # [EXPERIMENTAL] - it 'test `add_edges_from`' do - g = NetworkX::Graph.new - g.add_nodes_from(0...10) - g.add_edges_from([[0, 1], [1, 2], [3, 2], [5, 3], [6, 9], [7, 1]]) - expect(g.number_of_nodes).to be 10 - expect(g.number_of_edges).to be 6 - end - - it 'test add_nodes(Range)' do - g = NetworkX::Graph.new - g.add_nodes(0...10) - expect(g.number_of_nodes).to be 10 - end - - # test experimental methods: `add_nodes_from` - it 'test add_nodes_from(String)' do - g = NetworkX::Graph.new - g.add_nodes_from('Hello') - expect(g.number_of_nodes).to be 4 - expect(g.node?('l')).to be true - expect(g.node?('h')).to be false - expect(g.node?('o')).to be true - expect(g.node?('x')).to be false - end - - it 'test degree' do - graph = NetworkX::Graph.new - graph.add_edges([[0, 1], [1, 2], [2, 3]]) - expect(graph.degree[0]).to be 1 - expect(graph.degree[1]).to be 2 - expect(graph.degree[2]).to be 2 - expect(graph.degree[3]).to be 1 - - expect(graph.degree([1, 3, 2])).to eq({1 => 2, 3 => 1, 2 => 2}) - end - - # test experimental methods: `add_nodes_from`, `add_weighted_edges_from`, `each_edge`, `edges` - # https://atcoder.jp/contests/abc051/tasks/abc051_d - it 'ABC051 D: example 1' do - n, _m = 3, 3 - edges = [[1, 2, 1], [1, 3, 1], [2, 3, 3]] - - g = NetworkX::Graph.new - g.add_nodes_from(1..n) - g.add_weighted_edges_from(edges) - - expect(g.number_of_nodes).to be 3 - expect(g.number_of_edges).to be 3 - expect(g.adj[1][2][:weight]).to be 1 - expect(g.adj[3][1][:weight]).to be 1 - expect(g.adj[2][3][:weight]).to be 3 - - expect(g.edges).to eq [[1, 2], [1, 3], [2, 3]] - - fw = NetworkX.floyd_warshall(g) - expect(fw[1][2]).to be 1 - expect(fw[1][3]).to be 1 - expect(fw[2][1]).to be 1 - expect(fw[2][3]).to be 2 - expect(fw[3][1]).to be 1 - expect(fw[3][2]).to be 2 - end - - # test experimental methods: `add_nodes_from`, `add_weighted_edges_from`, `each_edge`, `edges` - # https://atcoder.jp/contests/abc051/tasks/abc051_d - it 'ABC051 D: example 2' do - n, _m = 3, 2 - edges = [[1, 2, 1], [2, 3, 1]] - - g = NetworkX::Graph.new - g.add_nodes_from(1..n) - g.add_weighted_edges_from(edges) - - expect(g.number_of_nodes).to be 3 - expect(g.number_of_edges).to be 2 - expect(g.adj[1][2][:weight]).to be 1 - expect(g.adj[3][2][:weight]).to be 1 - - expect(g.edges).to eq [[1, 2], [2, 3]] - expect(g.edges(data: true)).to eq [[1, 2, {weight: 1}], [2, 3, {weight: 1}]] - - fw = NetworkX.floyd_warshall(g) - expect(fw[1][2]).to be 1 - expect(fw[1][3]).to be 2 - expect(fw[2][1]).to be 1 - expect(fw[2][3]).to be 1 - expect(fw[3][1]).to be 2 - expect(fw[3][2]).to be 1 - end - - it 'test info method' do - output = <<~'OUTPUT' - Type: NetworkX::Graph - Number of nodes: 0 - Number of edges: 0 - OUTPUT - graph = NetworkX::Graph.new - expect(graph.info).to eq(output) - end - - it 'directed?' do - directed_graph = NetworkX::Graph.new - expect(directed_graph.directed?).to be false - end - - it 'multigraph?' do - directed_graph = NetworkX::Graph.new - expect(directed_graph.multigraph?).to be false - end -end diff --git a/spec/network_x/link_analysis/graph_hits_spec.rb b/spec/network_x/link_analysis/graph_hits_spec.rb deleted file mode 100644 index b25dbc0..0000000 --- a/spec/network_x/link_analysis/graph_hits_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new } - - before do - graph.add_edge(1, 2) - graph.add_edge(2, 4) - end - - context 'when hits is called' do - subject { NetworkX.hits(graph, 1 => 0.333, 2 => 0.333, 4 => 0.333) } - - it { is_expected.to eq([{1 => 1.0, 2 => 1.0, 4 => 1.0}, {1 => 0.5, 2 => 1.0, 4 => 0.5}]) } - end - - context 'when authority_matrix is called' do - subject { NetworkX.authority_matrix(graph) } - - it { is_expected.to eq(Matrix[[1, 0, 1], [0, 2, 0], [1, 0, 1]]) } - end - - context 'when hub_matrix is called' do - subject { NetworkX.hub_matrix(graph) } - - it { is_expected.to eq(Matrix[[1, 0, 1], [0, 2, 0], [1, 0, 1]]) } - end -end diff --git a/spec/network_x/link_analysis/graph_pagerank_spec.rb b/spec/network_x/link_analysis/graph_pagerank_spec.rb deleted file mode 100644 index a072a64..0000000 --- a/spec/network_x/link_analysis/graph_pagerank_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -RSpec.describe NetworkX::Graph do - it 'Digraph#pagerank' do - graph = NetworkX::DiGraph.new - graph.add_edges([[1, 2], [1, 3], [2, 4], [3, 4], [3, 5], [4, 5], [5, 1]]) - pagerank = NetworkX.pagerank(graph, alpha: 0.95, max_iter: 1000) - expect(pagerank[1]).to be_within(1e-6).of(0.26261029498162486) - expect(pagerank[2]).to be_within(1e-6).of(0.13473989208216358) - expect(pagerank[3]).to be_within(1e-6).of(0.13473989208216358) - expect(pagerank[4]).to be_within(1e-6).of(0.20200434638512804) - expect(pagerank[5]).to be_within(1e-6).of(0.2659055744689199) - end - - it 'pagerank' do - graph = NetworkX::Graph.new - graph.add_edges([[1, 2], [2, 4]]) - pagerank = NetworkX.pagerank(graph) - expect(pagerank[1]).to be_within(1e-6).of(0.25675675672536513) - expect(pagerank[2]).to be_within(1e-6).of(0.4864864865492695) - expect(pagerank[4]).to be_within(1e-6).of(0.25675675672536513) - end - - it 'pagerank(alpha: 0)' do - graph = NetworkX::Graph.new - graph.add_edges([[:a, :b], [:b, :c], [:c, :d], [:d, :a]]) - pagerank = NetworkX.pagerank(graph, alpha: 0) - expect(pagerank).to eq({a: 0.25, b: 0.25, c: 0.25, d: 0.25}) - end -end diff --git a/spec/network_x/multi_di_graph_spec.rb b/spec/network_x/multi_di_graph_spec.rb deleted file mode 100644 index 12d6b58..0000000 --- a/spec/network_x/multi_di_graph_spec.rb +++ /dev/null @@ -1,277 +0,0 @@ -RSpec.describe NetworkX::MultiDiGraph do - subject { graph } - - let(:graph) { described_class.new(name: 'Cities', type: 'directed') } - - before do - graph.add_nodes(%w[Nagpur Mumbai]) - graph.add_edge('Nagpur', 'Mumbai') - graph.add_edges([%w[Nagpur Chennai], %w[Chennai Bangalore]]) - graph.add_node('Kolkata') - end - - context 'when graph has been assigned attributes' do - its('graph') { is_expected.to eq(name: 'Cities', type: 'directed') } - end - - context 'when a new node/s has/have been created' do - its('nodes') do - is_expected.to eq('Kolkata' => {}, - 'Nagpur' => {}, - 'Mumbai' => {}, - 'Chennai' => {}, - 'Bangalore' => {}) - end - end - - context 'when a new edge/s has/have been added' do - its('adj') do - is_expected.to eq('Nagpur' => {'Mumbai' => {0 => {}}, 'Chennai' => {0 => {}}}, - 'Bangalore' => {}, - 'Chennai' => {'Bangalore' => {0 => {}}}, - 'Mumbai' => {}, 'Kolkata' => {}) - end - - its('pred') do - is_expected.to eq('Nagpur' => {}, - 'Bangalore' => {'Chennai' => {0 => {}}}, - 'Chennai' => {'Nagpur' => {0 => {}}}, - 'Mumbai' => {'Nagpur' => {0 => {}}}, 'Kolkata' => {}) - end - end - - context 'when node/s is/are removed' do - before do - graph.remove_node('Nagpur') - graph.remove_nodes(%w[Chennai Mumbai]) - end - - its('nodes') { is_expected.to eq('Kolkata' => {}, 'Bangalore' => {}) } - its('adj') { is_expected.to eq('Kolkata' => {}, 'Bangalore' => {}) } - end - - context 'when edge/s is/are removed' do - before do - graph.remove_edge('Nagpur', 'Mumbai') - graph.remove_edges([%w[Nagpur Chennai], %w[Chennai Bangalore]]) - end - - its('adj') do - is_expected.to eq('Kolkata' => {}, 'Bangalore' => {}, \ - 'Nagpur' => {}, 'Chennai' => {}, 'Mumbai' => {}) - end - end - - it 'test remove_edge' do - graph = NetworkX::MultiDiGraph.new - graph.add_edge(:s, :t, key: 'first') - graph.add_edge(:s, :t, key: 'second') - graph.add_edge(:s, :t, key: 'third') - expect(graph.number_of_edges).to be 3 - - graph.remove_edge(:s, :t, 'second') - expect(graph.number_of_edges).to be 2 - - expect { graph.remove_edge(:s, :t, '1st') }.to raise_error(KeyError) - end - - context 'when weighted edge/s is/are added' do - before do - graph.remove_nodes(%w[Chennai Bangalore]) - graph.add_weighted_edge('Nagpur', 'Mumbai', 15) - graph.add_weighted_edges([%w[Nagpur Kolkata]], [10]) - end - - its('adj') do - is_expected.to eq('Kolkata' => {}, - 'Mumbai' => {}, - 'Nagpur' => {'Mumbai' => {0 => {}, 1 => {weight: 15}}, - 'Kolkata' => {0 => {weight: 10}}}) - end - end - - context 'when number of edges are calculated' do - its('number_of_edges') do - is_expected.to eq 3 - end - end - - it 'test number_of_edges of empty graph returns 0' do - empty_graph = NetworkX::MultiDiGraph.new - expect(empty_graph.number_of_edges).to be 0 - end - - it 'test indegree & out_degree of MultiDiGraph with no edge' do - graph = NetworkX::MultiDiGraph.new - graph.add_node(0) - graph.add_node(1) - - expect(graph.in_degree(0)).to be 0 - expect(graph.in_degree(1)).to be 0 - expect(graph.out_degree(0)).to be 0 - expect(graph.out_degree(1)).to be 0 - end - - it 'test indegree & out_degree of simple MultiDiGraph' do - graph = NetworkX::MultiDiGraph.new - graph.add_edges([[0, 1], [1, 2], [2, 3], [3, 4]]) - - expect(graph.in_degree(0)).to be 0 - expect(graph.in_degree(1)).to be 1 - expect(graph.in_degree(2)).to be 1 - expect(graph.in_degree(3)).to be 1 - expect(graph.in_degree(4)).to be 1 - - expect(graph.out_degree(0)).to be 1 - expect(graph.out_degree(1)).to be 1 - expect(graph.out_degree(2)).to be 1 - expect(graph.out_degree(3)).to be 1 - expect(graph.out_degree(4)).to be 0 - end - - it 'tests edge?' do - graph = NetworkX::MultiDiGraph.new - expect(graph.has_edge?(:x, :y)).to be_falsy - - graph.add_edge(:x, :y) - expect(graph.has_edge?(:x, :y)).to be_truthy - expect(graph.has_edge?(:y, :x)).to be_falsy - end - - it 'tests edge? with key' do - graph = NetworkX::MultiDiGraph.new - expect(graph.has_edge?(:x, :y, 'first')).to be_falsy - - graph.add_edge(:x, :y, key: 'first') - expect(graph.has_edge?(:x, :y, 'first')).to be_truthy - expect(graph.has_edge?(:x, :y, 'second')).to be_falsy - end - - context 'when size is called' do - subject { graph.size(true) } - - before do - graph.add_weighted_edge('Nagpur', 'Mumbai', 15) - end - - it do - is_expected.to eq 15 - end - end - - it 'test size' do - graph = NetworkX::MultiDiGraph.new - expect(graph.size).to be 0 - expect(graph.size(true)).to be 0 - - graph.add_edge(:s, :t, weight: 10) - expect(graph.size).to be 1 - expect(graph.size(true)).to be 10 - end - - context 'when subgraph is called' do - subject { graph.subgraph(%w[Nagpur Mumbai]) } - - its('nodes') do - is_expected.to eq('Nagpur' => {}, 'Mumbai' => {}) - end - - its('adj') do - is_expected.to eq('Nagpur' => {'Mumbai' => {0 => {}}}, 'Mumbai' => {}) - end - end - - it 'test `subgraph` method' do - g = NetworkX::MultiDiGraph.new - g.add_nodes_from(0...4) - g.add_edges([[0, 1], [1, 2], [1, 3]]) - - h = g.subgraph([0, 1, 2]) - - expect(h.number_of_nodes).to eq 3 - expect(h.edges).to eq [[0, 1], [1, 2]] - end - - context 'when edges_subgraph is called' do - subject { graph.edge_subgraph([%w[Nagpur Mumbai], %w[Nagpur Chennai]]) } - - its('nodes') do - is_expected.to eq('Nagpur' => {}, 'Mumbai' => {}, 'Chennai' => {}) - end - - its('adj') do - is_expected.to eq('Nagpur' => {'Chennai' => {0 => {}}, 'Mumbai' => {0 => {}}}, 'Mumbai' => {}, 'Chennai' => {}) - end - end - - it 'tests error from subgraph and edge_subgraph' do - g = NetworkX::MultiDiGraph.new - expect { g.subgraph(nil) }.to raise_error(ArgumentError) - expect { g.edge_subgraph(nil) }.to raise_error(ArgumentError) - end - - it 'nodes' do - graph = NetworkX::MultiDiGraph.new - graph.add_edges([[:x, :y], [:y, :z]]) - expect(graph.nodes(data: false)).to eq([:x, :y, :z]) - expect(graph.nodes(data: true)).to eq({x: {}, y: {}, z: {}}) - end - - context 'when reverse is called' do - subject { graph.reverse } - - its('adj') do - is_expected.to eq('Nagpur' => {}, - 'Bangalore' => {'Chennai' => {0 => {}}}, - 'Chennai' => {'Nagpur' => {0 => {}}}, - 'Mumbai' => {'Nagpur' => {0 => {}}}, 'Kolkata' => {}) - end - end - - it 'to_undirected' do - multi_directed_graph = NetworkX::MultiDiGraph.new(name: 'MultiDi') - multi_directed_graph.add_edges([[:a, :b], [:c, :d]]) - - undirected_graph = multi_directed_graph.to_undirected - expect(undirected_graph.class).to eq NetworkX::Graph - expect(undirected_graph.graph[:name]).to eq 'MultiDi' - expect(undirected_graph.number_of_edges).to be 2 - expect(undirected_graph.number_of_nodes).to be 4 - end - - it 'to_directed' do - multi_directed_graph = NetworkX::MultiDiGraph.new(name: 'MultiDi') - multi_directed_graph.add_edges([[:a, :b], [:a, :b]]) - expect(multi_directed_graph.number_of_edges).to be 2 - expect(multi_directed_graph.number_of_nodes).to be 2 - - undirected_graph = multi_directed_graph.to_directed - expect(undirected_graph.class).to eq NetworkX::DiGraph - expect(undirected_graph.graph[:name]).to eq 'MultiDi' - expect(undirected_graph.number_of_edges).to be 1 - expect(undirected_graph.number_of_nodes).to be 2 - end - - it 'to_multidirected' do - multi_directed_graph = NetworkX::MultiDiGraph.new(name: 'MultiDi') - multi_directed_graph.add_edges([[:a, :b], [:a, :b]]) - expect(multi_directed_graph.number_of_edges).to be 2 - expect(multi_directed_graph.number_of_nodes).to be 2 - - multi_graph = multi_directed_graph.to_multigraph - expect(multi_graph.class).to eq NetworkX::MultiGraph - expect(multi_graph.graph[:name]).to eq 'MultiDi' - expect(multi_graph.number_of_edges).to be 2 - expect(multi_graph.number_of_nodes).to be 2 - end - - it 'directed?' do - directed_graph = NetworkX::MultiDiGraph.new - expect(directed_graph.directed?).to be true - end - - it 'multigraph?' do - directed_graph = NetworkX::MultiDiGraph.new - expect(directed_graph.multigraph?).to be true - end -end diff --git a/spec/network_x/multi_graph_spec.rb b/spec/network_x/multi_graph_spec.rb deleted file mode 100644 index f3ba2b0..0000000 --- a/spec/network_x/multi_graph_spec.rb +++ /dev/null @@ -1,218 +0,0 @@ -RSpec.describe NetworkX::MultiGraph do - subject { graph } - - let(:graph) { described_class.new(name: 'Cities', type: 'undirected') } - - before do - graph.add_nodes(%w[Nagpur Mumbai]) - graph.add_edge('Nagpur', 'Mumbai') - graph.add_edges([%w[Nagpur Chennai], %w[Chennai Bangalore]]) - graph.add_node('Kolkata') - end - - context 'when graph has been assigned attributes' do - its('graph') { is_expected.to eq(name: 'Cities', type: 'undirected') } - end - - context 'when a new node/s has/have been created' do - its('nodes') do - is_expected.to eq(%w[Nagpur Mumbai Chennai Bangalore Kolkata]) - end - end - - context 'when a new edge/s has/have been added' do - its('adj') do - is_expected.to eq('Nagpur' => {'Mumbai' => {0 => {}}, 'Chennai' => {0 => {}}}, - 'Bangalore' => {'Chennai' => {0 => {}}}, - 'Chennai' => {'Nagpur' => {0 => {}}, 'Bangalore' => {0 => {}}}, - 'Mumbai' => {'Nagpur' => {0 => {}}}, 'Kolkata' => {}) - end - end - - it 'nodes' do - graph = NetworkX::MultiGraph.new - graph.add_edges([[:x, :y], [:y, :z]]) - expect(graph.nodes(data: false).sort).to eq([:x, :y, :z]) - expect(graph.nodes(data: true)).to eq({x: {}, y: {}, z: {}}) - end - - context 'when node/s is/are removed' do - before do - graph.remove_node('Nagpur') - graph.remove_nodes(%w[Chennai Mumbai]) - end - - its('nodes') { is_expected.to eq(%w[Bangalore Kolkata]) } - its('adj') { is_expected.to eq('Kolkata' => {}, 'Bangalore' => {}) } - end - - context 'when edge/s is/are removed' do - before do - graph.remove_edge('Nagpur', 'Mumbai') - graph.remove_edges([%w[Nagpur Chennai], %w[Chennai Bangalore]]) - end - - its('adj') do - is_expected.to eq('Kolkata' => {}, 'Bangalore' => {}, \ - 'Nagpur' => {}, 'Chennai' => {}, 'Mumbai' => {}) - end - end - - it 'tests `remove_edge` with key' do - graph = NetworkX::MultiGraph.new - graph.add_edge(:a, :b, key: 'first') - graph.add_edge(:a, :b, key: 'second') - expect(graph.number_of_nodes).to be 2 - expect(graph.number_of_edges).to be 2 - - graph.remove_edge(:a, :b, 'first') - expect(graph.number_of_nodes).to be 2 - expect(graph.number_of_edges).to be 1 - - expect { graph.remove_edge(:a, :b, 'third') }.to raise_error(KeyError) - end - - context 'when weighted edge/s is/are added' do - before do - graph.remove_nodes(%w[Chennai Bangalore]) - graph.add_weighted_edge('Nagpur', 'Mumbai', 15) - graph.add_weighted_edges([%w[Nagpur Kolkata]], [10]) - end - - its('adj') do - is_expected.to eq('Kolkata' => {'Nagpur' => {0 => {weight: 10}}}, - 'Mumbai' => {'Nagpur' => {1 => {weight: 15}, 0 => {}}}, - 'Nagpur' => {'Mumbai' => {1 => {weight: 15}, 0 => {}}, - 'Kolkata' => {0 => {weight: 10}}}) - end - end - - context 'when number of edges are calculated' do - before do - graph.add_edge('Nagpur', 'Mumbai') - end - - its('number_of_edges') do - is_expected.to eq 4 - end - end - - it 'test number_of_edges of empty graph returns 0' do - empty_graph = NetworkX::MultiGraph.new - expect(empty_graph.number_of_edges).to be 0 - end - - it 'tests edge?' do - graph = NetworkX::MultiGraph.new - expect(graph.has_edge?(:x, :y)).to be_falsy - expect(graph.has_edge?(:y, :x)).to be_falsy - - graph.add_edge(:x, :y) - expect(graph.has_edge?(:x, :y)).to be_truthy - expect(graph.has_edge?(:y, :x)).to be_truthy - end - - it 'tests edge? with key' do - graph = NetworkX::MultiGraph.new - expect(graph.has_edge?(:x, :y, 'first')).to be_falsy - - graph.add_edge(:x, :y, key: 'first') - expect(graph.has_edge?(:x, :y, 'first')).to be_truthy - expect(graph.has_edge?(:y, :x, 'first')).to be_truthy - expect(graph.has_edge?(:y, :x, 'second')).to be_falsy - end - - it 'each_edges' do - graph = NetworkX::MultiGraph.new - graph.add_edge(1, 2, key: 'first') - graph.add_edge(1, 2, key: 'second') - expect(graph.each_edge.to_a).to eq [[1, 2, 0], [1, 2, 1]] - end - - context 'when size is called' do - subject { graph.size(true) } - - before do - graph.add_weighted_edge('Nagpur', 'Mumbai', 15) - end - - it do - is_expected.to eq 15 - end - end - - it 'test size' do - graph = NetworkX::MultiGraph.new - expect(graph.size).to be 0 - expect(graph.size(true)).to be 0 - - graph.add_edge(:s, :t, weight: 10) - expect(graph.size).to be 1 - expect(graph.size(true)).to be 10 - end - - context 'when subgraph is called' do - subject { graph.subgraph(%w[Nagpur Mumbai]) } - - its('nodes') do - is_expected.to eq(%w[Nagpur Mumbai]) - end - - its('adj') do - is_expected.to eq('Nagpur' => {'Mumbai' => {0 => {}}}, 'Mumbai' => {'Nagpur' => {0 => {}}}) - end - end - - it 'test `subgraph` method' do - g = NetworkX::MultiGraph.new - g.add_nodes_from(0...4) - g.add_edges([[0, 1], [1, 2], [1, 2], [1, 3]]) - - h = g.subgraph([0, 1, 2]) - - expect(h.number_of_nodes).to eq 3 - expect(h.number_of_edges).to eq 3 - expect(h.edges(data: true)).to eq [[0, 1, 0, {}], [1, 2, 0, {}], [1, 2, 1, {}]] - end - - it 'tests error from subgraph and edge_subgraph' do - g = NetworkX::MultiGraph.new - expect { g.subgraph(nil) }.to raise_error(ArgumentError) - expect { g.edge_subgraph(nil) }.to raise_error(ArgumentError) - end - - context 'when edges_subgraph is called' do - subject { graph.edge_subgraph([%w[Nagpur Mumbai], %w[Nagpur Chennai]]) } - - its('nodes') do - is_expected.to eq(%w[Nagpur Mumbai Chennai]) - end - - its('adj') do - is_expected.to eq('Nagpur' => {'Chennai' => {0 => {}}, 'Mumbai' => {0 => {}}}, - 'Mumbai' => {'Nagpur' => {0 => {}}}, - 'Chennai' => {'Nagpur' => {0 => {}}}) - end - end - - context 'when to_undirected is called' do - subject { graph.to_undirected } - - its('adj') do - is_expected.to eq('Nagpur' => {'Mumbai' => {}, 'Chennai' => {}}, - 'Bangalore' => {'Chennai' => {}}, - 'Chennai' => {'Nagpur' => {}, 'Bangalore' => {}}, - 'Mumbai' => {'Nagpur' => {}}, 'Kolkata' => {}) - end - end - - it 'directed?' do - directed_graph = NetworkX::MultiGraph.new - expect(directed_graph.directed?).to be false - end - - it 'multigraph?' do - directed_graph = NetworkX::MultiGraph.new - expect(directed_graph.multigraph?).to be true - end -end diff --git a/spec/network_x/operators/graph_all_spec.rb b/spec/network_x/operators/graph_all_spec.rb deleted file mode 100644 index f058560..0000000 --- a/spec/network_x/operators/graph_all_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graphs1) { [] } - let(:graphs2) { [] } - - before do - graphs1 << described_class.new - graphs1 << described_class.new - graphs1[0].add_edge(1, 2) - graphs1[1].add_edge(3, 4) - - graphs2 << described_class.new - graphs2 << described_class.new - graphs2[0].add_edge(1, 2) - graphs2[1].add_node(1) - graphs2[1].add_node(2) - end - - context 'when union_all is called' do - subject { NetworkX.union_all(graphs1) } - - its('adj') { is_expected.to eq(1 => {2 => {}}, 2 => {1 => {}}, 3 => {4 => {}}, 4 => {3 => {}}) } - end - - context 'when disjoint_union_all is called' do - subject { NetworkX.disjoint_union_all(graphs1) } - - its('adj') do - is_expected.to eq('10' => {'21' => {}}, - '21' => {'10' => {}}, - '30' => {'41' => {}}, - '41' => {'30' => {}}) - end - end - - context 'when intersection_all is called' do - subject { NetworkX.intersection_all(graphs2) } - - its('adj') { is_expected.to eq(1 => {}, 2 => {}) } - end - - context 'when compose_all is called' do - subject { NetworkX.compose_all(graphs1) } - - its('adj') { is_expected.to eq(1 => {2 => {}}, 2 => {1 => {}}, 3 => {4 => {}}, 4 => {3 => {}}) } - end -end diff --git a/spec/network_x/operators/graph_binary_spec.rb b/spec/network_x/operators/graph_binary_spec.rb deleted file mode 100644 index 3d45f62..0000000 --- a/spec/network_x/operators/graph_binary_spec.rb +++ /dev/null @@ -1,336 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph1) { described_class.new(type: 'undirected') } - let(:graph2) { described_class.new(type: 'undirected') } - - before do - graph1.add_edge(1, 2) - graph2.add_edge(5, 6) - end - - context 'when union is called' do - subject { NetworkX.union(graph1, graph2) } - - its('adj') do - is_expected.to eq(1 => {2 => {}}, - 2 => {1 => {}}, - 5 => {6 => {}}, - 6 => {5 => {}}) - end - end - - it 'unite DiGraph' do - graph1 = NetworkX::DiGraph.new - graph2 = NetworkX::DiGraph.new - graph1.add_edge(1, 2) - graph1.add_edge(2, 3) - graph2.add_edge(5, 6) - - graph3 = NetworkX.union(graph1, graph2) - expect(graph3.class).to be NetworkX::DiGraph - expect(graph3.number_of_nodes).to be 5 - expect(graph3.number_of_edges).to be 3 - expect(graph3.has_node?(2)).to be true - expect(graph3.has_node?(5)).to be true - expect(graph3.has_edge?(5, 6)).to be true - end - - it 'unite Graph' do - graph1 = NetworkX::Graph.new - graph2 = NetworkX::Graph.new - graph1.add_edge(:a, :b) - graph1.add_edge(:b, :c) - graph2.add_edge(:e, :f) - - graph3 = NetworkX.union(graph1, graph2) - expect(graph3.class).to be NetworkX::Graph - expect(graph3.number_of_nodes).to be 5 - expect(graph3.number_of_edges).to be 3 - expect(graph3.has_node?(:b)).to be true - expect(graph3.has_node?(:e)).to be true - expect(graph3.has_edge?(:e, :f)).to be true - end - - it 'unite MultiGraph' do - graph1 = NetworkX::MultiGraph.new - graph2 = NetworkX::MultiGraph.new - graph1.add_edge(1, 2) - graph1.add_edge(2, 3) - graph2.add_edge(5, 6) - - graph3 = NetworkX.union(graph1, graph2) - expect(graph3.class).to be NetworkX::MultiGraph - expect(graph3.number_of_nodes).to be 5 - expect(graph3.number_of_edges).to be 3 - expect(graph3.has_node?(2)).to be true - expect(graph3.has_node?(5)).to be true - expect(graph3.has_edge?(5, 6)).to be true - end - - it 'unite MultiDiGraph' do - graph1 = NetworkX::MultiDiGraph.new - graph2 = NetworkX::MultiDiGraph.new - graph1.add_edge(1, 2) - graph1.add_edge(2, 3) - graph2.add_edge(5, 6) - - graph3 = NetworkX.union(graph1, graph2) - expect(graph3.class).to be NetworkX::MultiDiGraph - expect(graph3.number_of_nodes).to be 5 - expect(graph3.number_of_edges).to be 3 - expect(graph3.has_node?(2)).to be true - expect(graph3.has_node?(5)).to be true - expect(graph3.has_edge?(5, 6)).to be true - end - - context 'when disjoint_union is called' do - subject { NetworkX.disjoint_union(graph1, graph2) } - - its('adj') do - is_expected.to eq('10' => {'21' => {}}, - '21' => {'10' => {}}, - '50' => {'61' => {}}, - '61' => {'50' => {}}) - end - end - - context 'when compose is called' do - subject { NetworkX.compose(graph1, graph2) } - - its('adj') do - is_expected.to eq(1 => {2 => {}}, - 2 => {1 => {}}, - 5 => {6 => {}}, - 6 => {5 => {}}) - end - end - - it 'compose multiple graphs' do - graph1 = NetworkX::MultiDiGraph.new(name: 'first') - graph2 = NetworkX::MultiDiGraph.new(name: 'second') - graph1.add_nodes_from(0...5) - graph2.add_nodes_from(2...6) - - graph1.add_edge(0, 1) - graph1.add_edge(1, 2) - graph2.add_edge(0, 1) - graph2.add_edge(4, 5) - graph2.add_edge(4, 5) - - graph3 = NetworkX.compose(graph1, graph2) - expect(graph3.class).to be NetworkX::MultiDiGraph - expect(graph3.number_of_nodes).to be 6 - expect(graph3.number_of_edges).to be 5 - end - - context 'when symmetric_difference is called' do - subject { NetworkX.symmetric_difference(graph1, graph2) } - - before do - graph2.clear - graph2.add_node(1) - graph2.add_node(2) - end - - its('adj') { is_expected.to eq(1 => {2 => {}}, 2 => {1 => {}}) } - end - - it 'intersection for Graph' do - g = NetworkX::Graph.new - h = NetworkX::Graph.new - g.add_edges_from([[0, 1], [0, 2], [1, 2], [1, 3]]) - h.add_edges_from([[0, 1], [1, 2], [0, 3]]) - new_graph = NetworkX.intersection(g, h) - expect(new_graph.nodes(data: true)).to eq({0 => {}, 1 => {}, 2 => {}, 3 => {}}) - expect(new_graph.number_of_nodes).to be 4 - expect(new_graph.number_of_edges).to be 2 - expect(new_graph.adj).to eq({ - 0 => {1 => {}}, - 1 => {0 => {}, 2 => {}}, - 2 => {1 => {}}, - 3 => {} - }) - end - - it 'intersection for MultiGraph' do - g = NetworkX::MultiGraph.new - h = NetworkX::MultiGraph.new - g.add_edges_from([[0, 1], [0, 2], [1, 2], [1, 3]]) - h.add_edges_from([[0, 1], [1, 2], [0, 3]]) - new_graph = NetworkX.intersection(g, h) - expect(new_graph.nodes(data: true)).to eq({0 => {}, 1 => {}, 2 => {}, 3 => {}}) - expect(new_graph.number_of_nodes).to be 4 - expect(new_graph.number_of_edges).to be 2 - expect(new_graph.adj).to eq({ - 0 => {1 => {0 => {}}}, - 1 => {0 => {0 => {}}, 2 => {0 => {}}}, - 2 => {1 => {0 => {}}}, - 3 => {} - }) - end - - it 'intersection for MultiDiGraph' do - g = NetworkX::MultiDiGraph.new - h = NetworkX::MultiDiGraph.new - g.add_edges_from([[0, 1], [0, 2], [1, 2], [1, 3]]) - h.add_edges_from([[0, 1], [1, 2], [0, 3]]) - new_graph = NetworkX.intersection(g, h) - expect(new_graph.nodes(data: true)).to eq({0 => {}, 1 => {}, 2 => {}, 3 => {}}) - expect(new_graph.number_of_nodes).to be 4 - expect(new_graph.number_of_edges).to be 2 - expect(new_graph.adj).to eq({ - 0 => {1 => {0 => {}}}, - 1 => {2 => {0 => {}}}, - 2 => {}, - 3 => {} - }) - end - - it 'difference for Graph' do - g = NetworkX::Graph.new - h = NetworkX::Graph.new - g.add_edges_from([[0, 1], [0, 2], [1, 2], [1, 3]]) - h.add_edges_from([[0, 1], [1, 2], [0, 3]]) - new_graph = NetworkX.difference(g, h) - expect(new_graph.nodes(data: true)).to eq({0 => {}, 1 => {}, 2 => {}, 3 => {}}) - expect(new_graph.number_of_nodes).to be 4 - expect(new_graph.number_of_edges).to be 2 - expect(new_graph.adj).to eq({ - 0 => {2 => {}}, - 1 => {3 => {}}, - 2 => {0 => {}}, - 3 => {1 => {}} - }) - end - - it 'difference for DiGraph' do - g = NetworkX::DiGraph.new - h = NetworkX::DiGraph.new - g.add_edges_from([[0, 1], [0, 2], [1, 2], [1, 3]]) - h.add_edges_from([[0, 1], [1, 2], [0, 3]]) - new_graph = NetworkX.difference(g, h) - expect(new_graph.nodes(data: true)).to eq({0 => {}, 1 => {}, 2 => {}, 3 => {}}) - expect(new_graph.number_of_nodes).to be 4 - expect(new_graph.number_of_edges).to be 2 - expect(new_graph.adj).to eq({ - 0 => {2 => {}}, - 1 => {3 => {}}, - 2 => {}, - 3 => {} - }) - end - - it 'difference for MultiGraph' do - g = NetworkX::MultiGraph.new - h = NetworkX::MultiGraph.new - g.add_edges_from([[0, 1], [0, 2], [1, 2], [1, 3]]) - h.add_edges_from([[0, 1], [1, 2], [0, 3]]) - - new_graph = NetworkX.difference(g, h) - expect(new_graph.nodes(data: true)).to eq({0 => {}, 1 => {}, 2 => {}, 3 => {}}) - expect(new_graph.number_of_nodes).to be 4 - expect(new_graph.number_of_edges).to be 2 - expect(new_graph.adj).to eq({ - 0 => {2 => {0 => {}}}, - 1 => {3 => {0 => {}}}, - 2 => {0 => {0 => {}}}, - 3 => {1 => {0 => {}}} - }) - end - - it 'difference for MultiDiGraph' do - g = NetworkX::MultiDiGraph.new - h = NetworkX::MultiDiGraph.new - g.add_edges_from([[0, 1], [0, 2], [1, 2], [1, 3]]) - h.add_edges_from([[0, 1], [1, 2], [0, 3]]) - new_graph = NetworkX.difference(g, h) - expect(new_graph.nodes(data: true)).to eq({0 => {}, 1 => {}, 2 => {}, 3 => {}}) - expect(new_graph.number_of_nodes).to be 4 - expect(new_graph.number_of_edges).to be 2 - expect(new_graph.adj).to eq({0 => {2 => {0 => {}}}, 1 => {3 => {0 => {}}}, 2 => {}, 3 => {}}) - end - - it 'symmetric_difference for Graph' do - g = NetworkX::Graph.new - h = NetworkX::Graph.new - g.add_edges_from([[0, 1], [0, 2], [1, 2], [1, 3]]) - h.add_edges_from([[0, 1], [1, 2], [0, 3]]) - new_graph = NetworkX.symmetric_difference(g, h) - expect(new_graph.nodes(data: true)).to eq({0 => {}, 1 => {}, 2 => {}, 3 => {}}) - expect(new_graph.number_of_nodes).to be 4 - expect(new_graph.number_of_edges).to be 3 - expect(new_graph.adj).to eq({ - 0 => {2 => {}, 3 => {}}, - 1 => {3 => {}}, - 2 => {0 => {}}, - 3 => {1 => {}, 0 => {}} - }) - end - - it 'symmetric_difference for DiGraph' do - g = NetworkX::DiGraph.new - h = NetworkX::DiGraph.new - g.add_edges_from([[0, 1], [0, 2], [1, 2], [1, 3]]) - h.add_edges_from([[0, 1], [1, 2], [0, 3]]) - new_graph = NetworkX.symmetric_difference(g, h) - expect(new_graph.number_of_nodes).to be 4 - expect(new_graph.number_of_edges).to be 3 - expect(new_graph.nodes(data: true)).to eq({0 => {}, 1 => {}, 2 => {}, 3 => {}}) - expect(new_graph.adj).to eq({0 => {2 => {}, 3 => {}}, 1 => {3 => {}}, 2 => {}, 3 => {}}) - end - - it 'symmetric_difference for MultiGraph' do - g = NetworkX::MultiGraph.new - h = NetworkX::MultiGraph.new - g.add_edges_from([[0, 1], [0, 2], [1, 2], [1, 3]]) - h.add_edges_from([[0, 1], [1, 2], [0, 3]]) - - new_graph = NetworkX.symmetric_difference(g, h) - expect(new_graph.nodes(data: true)).to eq({0 => {}, 1 => {}, 2 => {}, 3 => {}}) - expect(new_graph.number_of_nodes).to be 4 - expect(new_graph.number_of_edges).to be 3 - expect(new_graph.adj).to eq({ - 0 => {2 => {0 => {}}, 3 => {0 => {}}}, - 1 => {3 => {0 => {}}}, - 2 => {0 => {0 => {}}}, - 3 => {1 => {0 => {}}, 0 => {0 => {}}} - }) - end - - it 'symmetric_difference for MultiDiGraph' do - g = NetworkX::MultiDiGraph.new - h = NetworkX::MultiDiGraph.new - g.add_edges_from([[0, 1], [0, 2], [1, 2], [1, 3]]) - h.add_edges_from([[0, 1], [1, 2], [0, 3]]) - - new_graph = NetworkX.symmetric_difference(g, h) - expect(new_graph.nodes(data: true)).to eq({0 => {}, 1 => {}, 2 => {}, 3 => {}}) - expect(new_graph.number_of_nodes).to be 4 - expect(new_graph.number_of_edges).to be 3 - expect(new_graph.adj).to eq({ - 0 => {2 => {0 => {}}, 3 => {0 => {}}}, - 1 => {3 => {0 => {}}}, - 2 => {}, - 3 => {} - }) - end - - context 'when difference is called' do - subject { NetworkX.difference(graph1, graph2) } - - before do - graph2.clear - graph2.add_node(1) - graph2.add_node(2) - end - - its('adj') { is_expected.to eq(1 => {2 => {}}, 2 => {1 => {}}) } - end - - context 'when intersection is called' do - subject { NetworkX.intersection(graph1, graph1) } - - its('adj') { is_expected.to eq(1 => {2 => {}}, 2 => {1 => {}}) } - end -end diff --git a/spec/network_x/operators/graph_product_spec.rb b/spec/network_x/operators/graph_product_spec.rb deleted file mode 100644 index ede1425..0000000 --- a/spec/network_x/operators/graph_product_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph1) { described_class.new(type: 'undirected') } - let(:graph2) { described_class.new(type: 'undirected') } - - before do - graph1.add_edge(1, 2) - graph2.add_edge(5, 6) - end - - context 'when tensor_product is called' do - subject { NetworkX.tensor_product(graph1, graph2) } - - its('adj') do - is_expected.to eq([1, 5] => {[2, 6] => {}}, - [1, 6] => {[2, 5] => {}}, - [2, 5] => {[1, 6] => {}}, - [2, 6] => {[1, 5] => {}}) - end - end - - context 'when lexicographic_product is called' do - subject { NetworkX.lexicographic_product(graph1, graph2) } - - its('adj') do - is_expected.to eq([1, 5] => {[2, 5] => {}, [2, 6] => {}, [1, 6] => {}}, - [1, 6] => {[2, 5] => {}, [2, 6] => {}, [1, 5] => {}}, - [2, 5] => {[1, 5] => {}, [1, 6] => {}, [2, 6] => {}}, - [2, 6] => {[1, 5] => {}, [1, 6] => {}, [2, 5] => {}}) - end - end - - context 'when cartesian_product is called' do - subject { NetworkX.cartesian_product(graph1, graph2) } - - its('adj') do - is_expected.to eq([1, 5] => {[2, 5] => {}, [1, 6] => {}}, - [1, 6] => {[2, 6] => {}, [1, 5] => {}}, - [2, 5] => {[1, 5] => {}, [2, 6] => {}}, - [2, 6] => {[1, 6] => {}, [2, 5] => {}}) - end - end - - context 'when strong_product is called' do - subject { NetworkX.strong_product(graph1, graph2) } - - its('adj') do - is_expected.to eq([1, 5] => {[1, 6] => {}, [2, 5] => {}, [2, 6] => {}}, - [1, 6] => {[1, 5] => {}, [2, 6] => {}, [2, 5] => {}}, - [2, 5] => {[2, 6] => {}, [1, 5] => {}, [1, 6] => {}}, - [2, 6] => {[2, 5] => {}, [1, 6] => {}, [1, 5] => {}}) - end - end - - context 'when power is called' do - subject { NetworkX.power(graph1, 2) } - - its('adj') { is_expected.to eq(1 => {2 => {}}, 2 => {1 => {}}) } - end - - it 'edges_in_array' do - graph = NetworkX::MultiDiGraph.new - expect(NetworkX.edges_in_array(graph)).to eq [] - - graph.add_nodes_from([:a, :b]) - expect(NetworkX.edges_in_array(graph)).to eq [] - - graph.add_edge(:a, :b) - expect(NetworkX.edges_in_array(graph)).to eq [[:a, :b, {}]] - - graph.add_edge(:a, :b) - expect(NetworkX.edges_in_array(graph)).to eq [[:a, :b, {}], [:a, :b, {}]] - end -end diff --git a/spec/network_x/operators/graph_unary_spec.rb b/spec/network_x/operators/graph_unary_spec.rb deleted file mode 100644 index df1b114..0000000 --- a/spec/network_x/operators/graph_unary_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph1) { described_class.new(type: 'undirected') } - let(:graph2) { described_class.new(type: 'undirected') } - - before do - graph1.add_edge(1, 2) - graph1.add_edge(5, 6) - end - - context 'when union is called' do - subject { NetworkX.complement(graph1) } - - its('adj') do - is_expected.to eq(1 => {5 => {}, 6 => {}}, - 2 => {5 => {}, 6 => {}}, - 5 => {1 => {}, 2 => {}}, - 6 => {1 => {}, 2 => {}}) - end - end -end diff --git a/spec/network_x/others/bridges_spec.rb b/spec/network_x/others/bridges_spec.rb deleted file mode 100644 index af7716a..0000000 --- a/spec/network_x/others/bridges_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -RSpec.describe NetworkX do - it 'test empty graph has no bridge' do - graph = NetworkX::Graph.new - - expect(NetworkX.bridges(graph)).to eq [] - expect(NetworkX.number_of_bridges(graph)).to be 0 - end - - it 'test simple graph' do - graph = NetworkX::Graph.new - graph.add_nodes_from(1..3) - graph.add_edge(1, 2) - graph.add_edge(2, 3) - - expect(NetworkX.bridges(graph)).to eq [[1, 2], [2, 3]] - expect(NetworkX.number_of_bridges(graph)).to be 2 - end - - # refer to: https://atcoder.jp/contests/abc075/tasks/abc075_c - it 'test brudges to answer ABC075_C sample#1' do - n, _m = 7, 7 - edges = [[1, 3], [2, 7], [3, 4], [4, 5], [4, 6], [5, 6], [6, 7]] - graph = NetworkX::Graph.new - graph.add_nodes_from(1..n) - graph.add_edges(edges) - - expect(NetworkX.bridges(graph).size).to be 4 - expect(NetworkX.number_of_bridges(graph)).to be 4 - end - - it 'test brudges to answer ABC075_C sample#2' do - n, _m = 3, 3 - edges = [[1, 2], [1, 3], [2, 3]] - graph = NetworkX::Graph.new - graph.add_nodes_from(1..n) - graph.add_edges(edges) - - expect(NetworkX.bridges(graph).size).to be 0 - end - - it 'test brudges to answer ABC075_C sample#3' do - n, _m = 6, 5 - edges = [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]] - graph = NetworkX::Graph.new - graph.add_nodes_from(1..n) - graph.add_edges(edges) - - expect(NetworkX.bridges(graph).size).to be 5 - end -end diff --git a/spec/network_x/others/generator_spec.rb b/spec/network_x/others/generator_spec.rb deleted file mode 100644 index a28ec0b..0000000 --- a/spec/network_x/others/generator_spec.rb +++ /dev/null @@ -1,150 +0,0 @@ -RSpec.describe NetworkX do - it 'balanced_tree' do - balanced_tree = NetworkX::Graph.balanced_tree(3, 2) - expect(balanced_tree.number_of_nodes).to be 13 - expect(balanced_tree.number_of_edges).to be 12 - end - - it 'barbell_graph' do - barbell_graph = NetworkX::Graph.barbell_graph(5, 2) - expect(barbell_graph.number_of_nodes).to be 12 # 5 * 2 + 2 - expect(barbell_graph.number_of_edges).to be 23 # (5 * (5 - 1) / 2 * 2) + 2 + 1 - end - - it 'complete_graph' do - complete_graph = NetworkX::Graph.complete_graph(6) - expect(complete_graph.number_of_nodes).to be 6 # 6 - expect(complete_graph.number_of_edges).to be 15 # 6 * (6 - 1) / 2 - end - - it 'circular_ladder_graph' do - circular_ladder_graph = NetworkX::Graph.circular_ladder_graph(10) - expect(circular_ladder_graph.number_of_nodes).to be 20 # 10 * 2 - expect(circular_ladder_graph.number_of_edges).to be 30 # 10 * 3 - end - - it 'cycle_graph' do - cycle_graph = NetworkX::Graph.cycle_graph(10) - expect(cycle_graph.number_of_nodes).to be 10 # 10 - expect(cycle_graph.number_of_edges).to be 10 # 10 - end - - it 'empty_graph' do - empty_graph = NetworkX::Graph.empty_graph(10) - expect(empty_graph.number_of_nodes).to be 10 # 10 - expect(empty_graph.number_of_edges).to be 0 # 10 - end - - it 'ladder_graph' do - ladder_graph = NetworkX::Graph.ladder_graph(7) - expect(ladder_graph.number_of_nodes).to be 14 # 7 * 2 - expect(ladder_graph.number_of_edges).to be 19 # 7 * 3 - 2 - end - - it 'lollipop_graph' do - lollipop_graph = NetworkX::Graph.lollipop_graph(6, 3) - expect(lollipop_graph.number_of_nodes).to be 9 # 6 + 3 - expect(lollipop_graph.number_of_edges).to be 18 # 6 * 5 / 2 + 3 - end - - it 'null_graph' do - null_graph = NetworkX::Graph.null_graph - expect(null_graph.number_of_nodes).to be 0 - expect(null_graph.number_of_edges).to be 0 - end - - it 'path_graph' do - path_graph = NetworkX::Graph.path_graph(5) - expect(path_graph.number_of_nodes).to be 5 - expect(path_graph.number_of_edges).to be 4 - end - - it 'star_graph' do - star_graph = NetworkX::Graph.star_graph(5) - expect(star_graph.number_of_nodes).to be 6 # 5 + 1 - expect(star_graph.number_of_edges).to be 5 # 5 - end - - it 'trivial_graph' do - trivial_graph = NetworkX::Graph.trivial_graph - expect(trivial_graph.number_of_nodes).to be 1 - expect(trivial_graph.number_of_edges).to be 0 - end - - it 'wheel_graph' do - wheel_graph = NetworkX::Graph.wheel_graph(10) - expect(wheel_graph.number_of_nodes).to be 10 - expect(wheel_graph.number_of_edges).to be 18 - end - - it 'bull_graph' do - bull_graph = NetworkX::Graph.bull_graph - expect(bull_graph.number_of_nodes).to be 5 - expect(bull_graph.number_of_edges).to be 5 - end - - it 'cubical_graph' do - cubical_graph = NetworkX::Graph.cubical_graph - expect(cubical_graph.number_of_nodes).to be 8 - expect(cubical_graph.number_of_edges).to be 12 - end - - it 'diamond_graph' do - diamond_graph = NetworkX::Graph.diamond_graph - expect(diamond_graph.number_of_nodes).to be 4 - expect(diamond_graph.number_of_edges).to be 5 - end - - it 'dodecahedral_graph' do - dodecahedral_graph = NetworkX::Graph.dodecahedral_graph - expect(dodecahedral_graph.number_of_nodes).to be 20 - expect(dodecahedral_graph.number_of_edges).to be 30 - end - - it 'heawood_graph' do - heawood_graph = NetworkX::Graph.heawood_graph - expect(heawood_graph.number_of_nodes).to be 14 - expect(heawood_graph.number_of_edges).to be 21 - end - - it 'house_graph' do - house_graph = NetworkX::Graph.house_graph - expect(house_graph.number_of_nodes).to be 5 - expect(house_graph.number_of_edges).to be 6 - end - - it 'house_x_graph' do - house_x_graph = NetworkX::Graph.house_x_graph - expect(house_x_graph.number_of_nodes).to be 5 - expect(house_x_graph.number_of_edges).to be 8 - end - - it 'moebius_kantor_graph' do - moebius_kantor_graph = NetworkX::Graph.moebius_kantor_graph - expect(moebius_kantor_graph.number_of_nodes).to be 16 - expect(moebius_kantor_graph.number_of_edges).to be 24 - end - - it 'octahedral_graph' do - octahedral_graph = NetworkX::Graph.octahedral_graph - expect(octahedral_graph.number_of_nodes).to be 6 - expect(octahedral_graph.number_of_edges).to be 12 - end - - it 'tetrahedral_graph_graph' do - tetrahedral_graph = NetworkX::Graph.tetrahedral_graph - expect(tetrahedral_graph.number_of_nodes).to be 4 - expect(tetrahedral_graph.number_of_edges).to be 6 - end - - it 'puts_graph_x2' do - path_graph = NetworkX::Graph.path_graph(4) - output = <<~'OUTPUT' - 4 3 - 0 1 - 1 2 - 2 3 - OUTPUT - expect { path_graph.put_graph_x2 }.to output(output).to_stdout - end -end diff --git a/spec/network_x/others/grid_2d_graph_spec.rb b/spec/network_x/others/grid_2d_graph_spec.rb deleted file mode 100644 index 3392761..0000000 --- a/spec/network_x/others/grid_2d_graph_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -RSpec.describe NetworkX do - it 'test grid_2d_graph for simple square Graph' do - grid_graph = NetworkX.grid_2d_graph(2, 2) - expect(grid_graph.number_of_nodes).to be 4 - expect(grid_graph.number_of_edges).to be 4 - end - - it 'test grid_2d_graph for simple Graph' do - grid_graph = NetworkX.grid_2d_graph(3, 6) - expect(grid_graph.number_of_nodes).to be 3 * 6 - expect(grid_graph.number_of_edges).to be (3 - 1) * 6 + 3 * (6 - 1) - expect(grid_graph.number_of_edges).to be(3 * 6 * 2 - 3 - 6) - end - - it 'test grid_2d_graph for DiGraph' do - grid_di_graph = NetworkX.grid_2d_graph(5, 4, create_using: NetworkX::DiGraph) - expect(grid_di_graph.number_of_nodes).to be 5 * 4 - expect(grid_di_graph.number_of_edges).to be (5 * 4 * 2 - 5 - 4) * 2 - end - - it 'test grid_2d_graph for simple MultiGraph' do - grid_graph = NetworkX.grid_2d_graph(3, 6, create_using: NetworkX::MultiGraph) - expect(grid_graph.number_of_nodes).to be 3 * 6 - expect(grid_graph.number_of_edges).to be (3 - 1) * 6 + 3 * (6 - 1) - expect(grid_graph.number_of_edges).to be(3 * 6 * 2 - 3 - 6) - end - - it 'test grid_2d_graph for MultiDiGraph' do - grid_di_graph = NetworkX.grid_2d_graph(5, 4, create_using: NetworkX::MultiDiGraph) - expect(grid_di_graph.number_of_nodes).to be 5 * 4 - expect(grid_di_graph.number_of_edges).to be (5 * 4 * 2 - 5 - 4) * 2 - end -end diff --git a/spec/network_x/others/info_spec.rb b/spec/network_x/others/info_spec.rb deleted file mode 100644 index 3bc2215..0000000 --- a/spec/network_x/others/info_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -RSpec.describe NetworkX do - it 'test info method' do - output = <<~'OUTPUT' - Type: NetworkX::Graph - Number of nodes: 0 - Number of edges: 0 - OUTPUT - - graph = NetworkX::Graph.new - expect(NetworkX.info(graph)).to eq(output) - end -end diff --git a/spec/network_x/others/inputs/edges.txt b/spec/network_x/others/inputs/edges.txt deleted file mode 100644 index 301ff3b..0000000 --- a/spec/network_x/others/inputs/edges.txt +++ /dev/null @@ -1,7 +0,0 @@ -# node1 node2 -a c -b c -c d -d e -e f -d f diff --git a/spec/network_x/others/inputs/weighted_edges.txt b/spec/network_x/others/inputs/weighted_edges.txt deleted file mode 100644 index 7446561..0000000 --- a/spec/network_x/others/inputs/weighted_edges.txt +++ /dev/null @@ -1,7 +0,0 @@ -# node1 node2 weight -1 3 5.0 -2 3 1.0e3 -3 4 -5.0 -4 5 25 -5 6 4.0 -4 6 5.0 diff --git a/spec/network_x/others/number_connected_components_spec.rb b/spec/network_x/others/number_connected_components_spec.rb deleted file mode 100644 index e4c5588..0000000 --- a/spec/network_x/others/number_connected_components_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -RSpec.describe NetworkX do - it 'test number_connected methods' do - graph = NetworkX::Graph.new - graph.add_nodes_from('a'..'z') - - expect(NetworkX.number_of_connected_components(graph)).to be 26 - - graph.add_edge('a', 'j') - graph.add_edge('j', 't') - expect(NetworkX.number_of_connected_components(graph)).to be 24 - end -end diff --git a/spec/network_x/others/reads_spec.rb b/spec/network_x/others/reads_spec.rb deleted file mode 100644 index 03193d5..0000000 --- a/spec/network_x/others/reads_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -RSpec.describe NetworkX do - it 'Graph#read_edgelist' do - graph = NetworkX::Graph.read_edges('spec/network_x/others/inputs/edges.txt') - expect(graph.number_of_nodes).to be 6 - expect(graph.number_of_edges).to be 6 - end - - it 'Graph#read_weighted_edges' do - graph = NetworkX::Graph.read_weighted_edges('spec/network_x/others/inputs/weighted_edges.txt') - expect(graph.number_of_nodes).to be 6 - expect(graph.number_of_edges).to be 6 - expect(graph.get_edge_data(1, 3)).to eq({weight: 5}) - end - - it 'to_number_if_possible' do - expect(NetworkX.to_number_if_possible('10')).to be 10 - - expect(NetworkX.to_number_if_possible('11.0')).to be 11.0 - expect(NetworkX.to_number_if_possible('1e2')).to be 100.0 - expect(NetworkX.to_number_if_possible('-25e-2')).to be(-0.25) - - expect(NetworkX.to_number_if_possible('e')).to eq 'e' - expect(NetworkX.to_number_if_possible('E')).to eq 'E' - end -end diff --git a/spec/network_x/shortest_path/astar_spec.rb b/spec/network_x/shortest_path/astar_spec.rb deleted file mode 100644 index 99af466..0000000 --- a/spec/network_x/shortest_path/astar_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new(type: 'undirected') } - - before do - graph.add_nodes(%w[A B]) - graph.add_edge('A', 'B') - graph.add_edges([%w[A C], %w[C D]]) - graph.add_node('E') - end - - context 'when astar_path is called' do - subject { NetworkX.astar_path(graph, 'B', 'D') } - - it do - is_expected.to eq(%w[D C A B]) - end - end - - context 'when astar_path_length is called' do - subject { NetworkX.astar_path_length(graph, 'B', 'D') } - - it do - is_expected.to eq(3) - end - end - - it 'not reachable' do - graph = NetworkX::Graph.new - graph.add_node(:a) - graph.add_node(:b) - - expect{ NetworkX.astar_path(graph, :a, :b) }.to raise_error(ArgumentError) - end -end diff --git a/spec/network_x/shortest_path/dense_spec.rb b/spec/network_x/shortest_path/dense_spec.rb deleted file mode 100644 index 319a550..0000000 --- a/spec/network_x/shortest_path/dense_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new(type: 'undirected') } - - before do - graph.add_nodes(%w[A B]) - graph.add_edge('A', 'B', weight: 1) - graph.add_weighted_edges([%w[A C], %w[C D]], [5, 1]) - graph.add_node('E') - end - - context 'when floyd_warshall is called' do - subject { NetworkX.floyd_warshall(graph) } - - it do - inf = Float::INFINITY - is_expected.to eq('A' => {'A' => 0.0, 'B' => 1.0, 'C' => 5.0, 'D' => 6.0, 'E' => inf}, - 'B' => {'A' => 1.0, 'B' => 0.0, 'C' => 6.0, 'D' => 7.0, 'E' => inf}, - 'C' => {'A' => 5.0, 'B' => 6.0, 'C' => 0.0, 'D' => 1.0, 'E' => inf}, - 'D' => {'A' => 6.0, 'B' => 7.0, 'C' => 1.0, 'D' => 0.0, 'E' => inf}, - 'E' => {'A' => inf, 'B' => inf, 'C' => inf, 'D' => inf, 'E' => 0.0}) - end - end -end diff --git a/spec/network_x/shortest_path/unweighted_spec.rb b/spec/network_x/shortest_path/unweighted_spec.rb deleted file mode 100644 index 80549db..0000000 --- a/spec/network_x/shortest_path/unweighted_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new(type: 'undirected') } - - before do - graph.add_nodes(%w[A B]) - graph.add_edge('A', 'B') - graph.add_edges([%w[A C], %w[C D]]) - graph.add_node('E') - end - - context 'when single_source_shortest_path_length is called' do - subject { NetworkX.single_source_shortest_path_length(graph, 'A') } - - it do - is_expected.to eq([['A', 0], ['B', 1], ['C', 1], ['D', 2]]) - end - end - - context 'when all_pairs_shortest_path_length is called' do - subject { NetworkX.all_pairs_shortest_path_length(graph) } - - it do - is_expected.to eq([['A', [['A', 0], ['B', 1], ['C', 1], ['D', 2]]], - ['B', [['B', 0], ['A', 1], ['C', 2], ['D', 3]]], - ['C', [['C', 0], ['A', 1], ['D', 1], ['B', 2]]], - ['D', [['D', 0], ['C', 1], ['A', 2], ['B', 3]]], - ['E', [['E', 0]]]]) - end - end - - context 'when single_source_shortest_path is called' do - subject { NetworkX.single_source_shortest_path(graph, 'A') } - - it do - is_expected.to eq('A' => ['A'], 'B' => %w[A B], 'C' => %w[A C], 'D' => %w[A C D]) - end - end - - context 'when all_pairs_shortest_path is called' do - subject { NetworkX.all_pairs_shortest_path(graph) } - - it do - is_expected.to eq([['A', {'A' => ['A'], 'B' => %w[A B], 'C' => %w[A C], 'D' => %w[A C D]}], - ['B', {'B' => ['B'], 'A' => %w[B A], 'C' => %w[B A C], 'D' => %w[B A C D]}], - ['C', {'C' => ['C'], 'A' => %w[C A], 'D' => %w[C D], 'B' => %w[C A B]}], - ['D', {'D' => ['D'], 'C' => %w[D C], 'A' => %w[D C A], 'B' => %w[D C A B]}], - ['E', {'E' => ['E']}]]) - end - end - - context 'when predecessor is called' do - subject { NetworkX.predecessor(graph, 'A', true) } - - it do - is_expected.to eq('A' => [], 'B' => ['A'], 'C' => ['A'], 'D' => ['C']) - end - end -end diff --git a/spec/network_x/shortest_path/weighted_spec.rb b/spec/network_x/shortest_path/weighted_spec.rb deleted file mode 100644 index 45c0949..0000000 --- a/spec/network_x/shortest_path/weighted_spec.rb +++ /dev/null @@ -1,236 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new(type: 'undirected') } - - before do - graph.add_nodes(%w[A B]) - graph.add_edge('A', 'B', weight: 5) - graph.add_weighted_edges([%w[A C], %w[C D]], [2, 3]) - graph.add_node('E') - end - - it 'simple single source dijkstra' do - n, _m = 2, 2 - weighted_edges = [[1, 2, 2], [2, 1, 1]] - - g = NetworkX::DiGraph.new - g.add_nodes_from(1..n) - g.add_weighted_edges_from(weighted_edges) - - expect(NetworkX.singlesource_dijkstra_path_length(g, 1)).to eq({1 => 0, 2 => 2}) - expect(NetworkX.dijkstra_path(g, 1, 2)).to eq([1, 2]) - expect(NetworkX.singlesource_dijkstra_path(g, 1)).to eq({1 => [1], 2 => [1, 2]}) - end - - it 'single source dijkstra' do - # https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_1_A&lang=ja - n, _m, r = 4, 5, 0 - weighted_edges = [[0, 1, 1], [0, 2, 4], [1, 2, 2], [2, 3, 1], [1, 3, 5]] - - g = NetworkX::DiGraph.new - g.add_nodes_from(0...n) - g.add_weighted_edges_from(weighted_edges) - - expect(NetworkX.dijkstra_path_length(g, r, 3)).to be 4 - expect(NetworkX.singlesource_dijkstra_path(g, r)).to eq({0 => [0], 1 => [0, 1], 2 => [0, 1, 2], 3 => [0, 1, 2, 3]}) - end - - it 'all pair dijkstra' do - n, _m = 4, 5 - weighted_edges = [[0, 1, 5], [0, 2, -1], [1, 3, 3], [2, 3, 1], [3, 2, 4]] - - g = NetworkX::DiGraph.new - g.add_nodes_from(0...n) - g.add_weighted_edges_from(weighted_edges) - - expect(NetworkX.all_pairs_dijkstra_path_length(g)).to eq [[0, {0 => 0, 1 => 5, 2 => -1, 3 => 0}], - [1, {1 => 0, 2 => 7, 3 => 3}], - [2, {2 => 0, 3 => 1}], - [3, {2 => 4, 3 => 0}]] - expect(NetworkX.all_pairs_dijkstra_path(g)).to eq [ - {0 => [0], 1 => [0, 1], 2 => [0, 2], 3 => [0, 2, 3]}, - {1 => [1], 3 => [1, 3], 2 => [1, 3, 2]}, - {2 => [2], 3 => [2, 3]}, - {3 => [3], 2 => [3, 2]} - ] - end - - context 'when multisource_dijkstra is called' do - subject { NetworkX.multisource_dijkstra(graph, %w[B A], 'D') } - - it do - is_expected.to eq([5, %w[A C D]]) - end - end - - context 'when multisource_dijkstra_path_length is called' do - subject { NetworkX.multisource_dijkstra_path_length(graph, %w[B A]) } - - it do - is_expected.to eq('B' => 0, 'A' => 0, 'C' => 2, 'D' => 5) - end - end - - context 'when multisource_dijkstra_path is called' do - subject { NetworkX.multisource_dijkstra_path(graph, %w[B A]) } - - it do - is_expected.to eq('B' => ['B'], 'A' => ['A'], 'C' => %w[A C], 'D' => %w[A C D]) - end - end - - context 'when multisource_dijkstra_path is called' do - subject { NetworkX.multisource_dijkstra_path(graph, %w[B A]) } - - it do - is_expected.to eq('B' => ['B'], 'A' => ['A'], 'C' => %w[A C], 'D' => %w[A C D]) - end - end - - context 'when dijkstra_predecessor_distance is called' do - subject { NetworkX.dijkstra_predecessor_distance(graph, 'A') } - - it do - is_expected.to eq([{'A' => [], 'B' => ['A'], 'C' => ['A'], 'D' => ['C']}, - {'A' => 0, 'C' => 2, 'B' => 5, 'D' => 5}]) - end - end - - context 'when self.all_pairs_dijkstra is called' do - subject { NetworkX.all_pairs_dijkstra(graph) } - - it do - is_expected.to eq([['A', - [{'A' => 0, 'C' => 2, 'B' => 5, 'D' => 5}, - {'A' => ['A'], - 'B' => %w[A B], - 'C' => %w[A C], - 'D' => %w[A C D]}]], - ['B', - [{'B' => 0, 'A' => 5, 'C' => 7, 'D' => 10}, - {'B' => ['B'], - 'A' => %w[B A], - 'C' => %w[B A C], - 'D' => %w[B A C D]}]], - ['C', - [{'C' => 0, 'A' => 2, 'D' => 3, 'B' => 7}, - {'C' => ['C'], - 'A' => %w[C A], - 'D' => %w[C D], - 'B' => %w[C A B]}]], - ['D', - [{'D' => 0, 'C' => 3, 'A' => 5, 'B' => 10}, - {'D' => ['D'], - 'C' => %w[D C], - 'A' => %w[D C A], - 'B' => %w[D C A B]}]], - ['E', [{'E' => 0}, {'E' => ['E']}]]]) - end - end - - context 'when dijkstra_predecessor_distance is called' do - subject { NetworkX.dijkstra_predecessor_distance(graph, 'A') } - - it do - is_expected.to eq([{'A' => [], 'B' => ['A'], 'C' => ['A'], 'D' => ['C']}, - {'A' => 0, 'C' => 2, 'B' => 5, 'D' => 5}]) - end - end - - it 'dijksttra for simple MultiGraph' do - graph = NetworkX::MultiGraph.new - graph.add_edges_from([[:a, :b], [:a, :b], [:b, :a], [:a, :c], [:c, :d], [:a, :d], [:c, :e]]) - expect(NetworkX.dijkstra_path_length(graph, :a, :a)).to be 0 - expect(NetworkX.dijkstra_path_length(graph, :a, :b)).to be 1 - expect(NetworkX.dijkstra_path_length(graph, :a, :c)).to be 1 - expect(NetworkX.dijkstra_path_length(graph, :a, :d)).to be 1 - expect(NetworkX.dijkstra_path_length(graph, :a, :e)).to be 2 - end - - it 'dijksttra for MultiGraph' do - graph = NetworkX::MultiGraph.new - graph.add_weighted_edges_from([[:a, :b, 20], [:a, :b, 5], [:a, :b, 10]]) - expect(graph.edges).to eq [[:a, :b, 0], [:a, :b, 1], [:a, :b, 2]] - expect(NetworkX.dijkstra_path_length(graph, :a, :a)).to be 0 - # expect(NetworkX.dijkstra_path_length(graph, :a, :b)).to be 5 # [TODO] - end - - it 'allpairs_bellmanford_path for MultiGraph' do - graph = NetworkX::MultiGraph.new - graph.add_edges_from([[:a, :b], [:a, :b], [:b, :c], [:a, :c]]) - - expect(NetworkX.allpairs_bellmanford_path_length(graph)).to eq [ - [:a, {a: 0, b: 1, c: 1}], - [:b, {a: 1, b: 0, c: 1}], - [:c, {a: 1, b: 1, c: 0}] - ] - expect(NetworkX.allpairs_bellmanford_path(graph)).to eq [ - [:a, {a: [:a], b: [:b, :a], c: [:c, :a]}], - [:b, {a: [:a, :b], b: [:b], c: [:c, :b]}], - [:c, {a: [:a, :c], b: [:b, :c], c: [:c]}] - ] - end - - it 'raise ArgumentError in singlesource_bellmanford' do - graph = NetworkX::DiGraph.new - graph.add_node(:a) - graph.add_node(:x) - expect{ NetworkX.singlesource_bellmanford(graph, :a, :x) }.to raise_error(ArgumentError) - end - - it 'bellmanford_path' do - graph = NetworkX::DiGraph.new - graph.add_edges_from([[:a, :b], [:b, :c], [:c, :d], [:d, :x], [:c, :x]]) - graph.add_node(:x) - - expect(NetworkX.bellmanford_path(graph, :a, :x)).to eq [:x, :c, :b, :a] - # [TODO] [:a, :b, :c, :x] ? - end - - context 'when bellmanford_predecesor_distance is called' do - subject { NetworkX.bellmanford_predecesor_distance(graph, 'A') } - - it do - is_expected.to eq([{'A' => [], 'B' => ['A'], 'C' => ['A'], 'D' => ['C']}, - {'A' => 0, 'C' => 2, 'B' => 5, 'D' => 5}]) - end - end - - context 'when singlesource_bellmanford is called' do - subject { NetworkX.singlesource_bellmanford(graph, 'A') } - - it do - is_expected.to eq([{'A' => 0, 'B' => 5, 'C' => 2, 'D' => 5}, - {'A' => ['A'], 'B' => %w[B A], 'C' => %w[C A], 'D' => %w[D C A]}]) - end - end - - context 'when bellmanford_path_length is called' do - subject { NetworkX.bellmanford_path_length(graph, 'A', 'D') } - - it do - is_expected.to eq(5) - end - end - - context 'when bellmanford_path_length is called' do - subject { NetworkX.bellmanford_path_length(graph, 'A', 'D') } - - it do - is_expected.to eq(5) - end - end - - context 'when johnson is called' do - subject { NetworkX.johnson(graph) } - - it do - is_expected.to eq([['A', {'A' => ['A'], 'B' => %w[A B], 'C' => %w[A C], 'D' => %w[A C D]}], - ['B', {'B' => ['B'], 'A' => %w[B A], 'C' => %w[B A C], 'D' => %w[B A C D]}], - ['C', {'C' => ['C'], 'A' => %w[C A], 'D' => %w[C D], 'B' => %w[C A B]}], - ['D', {'D' => ['D'], 'C' => %w[D C], 'A' => %w[D C A], 'B' => %w[D C A B]}], - ['E', {'E' => ['E']}]]) - end - end -end diff --git a/spec/network_x/to_matrix_spec.rb b/spec/network_x/to_matrix_spec.rb deleted file mode 100644 index 4fa9619..0000000 --- a/spec/network_x/to_matrix_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -RSpec.describe NetworkX do - it 'to_matrix(multi graph, val, sum)' do - graph = NetworkX::MultiGraph.new - - graph.add_edge(:a, :b, weight: 10) - graph.add_edge(:b, :a, weight: 9) - - m, indexes = NetworkX.to_matrix(graph, 0) - expect(m).to eq Matrix[[0, 19], [19, 0]] - expect(indexes).to eq({0 => :a, 1 => :b}) - end - - it 'to_matrix(multi graph, val, max)' do - graph = NetworkX::MultiGraph.new - - graph.add_edge(:x, :y, weight: 10) - graph.add_edge(:y, :x, weight: 5) - - m, index = NetworkX.to_matrix(graph, 0, 'max') - expect(m).to eq Matrix[[0, 10], [10, 0]] - expect(index).to eq({0 => :x, 1 => :y}) - end - - it 'to_matrix(multi graph, val, min)' do - graph = NetworkX::MultiGraph.new - - graph.add_edge(:v, :w, weight: 10) - graph.add_edge(:w, :v, weight: 5) - - m, index = NetworkX.to_matrix(graph, 0, 'min') - expect(m).to eq Matrix[[0, 5], [5, 0]] - expect(index).to eq({0 => :v, 1 => :w}) - end -end diff --git a/spec/network_x/traversals/bfs_spec.rb b/spec/network_x/traversals/bfs_spec.rb deleted file mode 100644 index 9ec9fb7..0000000 --- a/spec/network_x/traversals/bfs_spec.rb +++ /dev/null @@ -1,76 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new(type: 'undirected') } - - before do - graph.add_nodes(%w[A B]) - graph.add_edge('A', 'B') - graph.add_edges([%w[A C], %w[C D]]) - graph.add_node('E') - end - - context 'when bfs_edges is called' do - subject { NetworkX.bfs_edges(graph, 'A') } - - it do - is_expected.to eq([%w[A B], %w[A C], %w[C D]]) - end - end - - context 'when bfs_successors is called' do - subject { NetworkX.bfs_successors(graph, 'A') } - - it do - is_expected.to eq('A' => %w[B C], 'C' => ['D']) - end - end - - context 'when bfs_predecessors is called' do - subject { NetworkX.bfs_predecessors(graph, 'A') } - - it do - is_expected.to eq('B' => 'A', 'C' => 'A', 'D' => 'C') - end - end - - it 'bfs_nodes' do - tree = NetworkX::Graph.new - tree.add_nodes('a'..'o') - tree.add_edges([%w[a b], %w[b c], %w[c h], %w[c i], %w[b d], %w[a e], %w[e f], %w[f j], %w[e g], %w[g k]]) - - expect(tree.bfs_nodes('a')).to eq %w[a b e c d f g h i j k] - end - - it 'test bfs_edge' do - edges = [[1, 2], [1, 3], [2, 4], [2, 5], [3, 6], [3, 7]] - - g = NetworkX::Graph.new - g.add_nodes_from(1..7) - g.add_edges_from(edges) - expect(g.bfs_edges(1)).to eq(edges) - end - - it 'test bfs_edge (ABC051 D - Maze Master many paths)' do - # https://atcoder.jp/contests/abc151/submissions/36396660 - def bfs(sy, sx, graph) - dist = {} - dist[[sy, sx]] = 0 - graph.each_bfs_edge([sy, sx]) do |from, to| - dist[to] = dist[from] + 1 - end - dist.values.max - end - - h, w = 12, 12 - grid_graph = NetworkX.grid_2d_graph(h, w) - ans = 0 - h.times do |y| - w.times do |x| - tmp = bfs(y, x, grid_graph) - ans = tmp if ans < tmp - end - end - expect(ans).to be 22 - end -end diff --git a/spec/network_x/traversals/dfs_spec.rb b/spec/network_x/traversals/dfs_spec.rb deleted file mode 100644 index 8a4284c..0000000 --- a/spec/network_x/traversals/dfs_spec.rb +++ /dev/null @@ -1,109 +0,0 @@ -RSpec.describe NetworkX::Graph do - subject { graph } - - let(:graph) { described_class.new(type: 'undirected') } - - before do - graph.add_nodes(%w[A B]) - graph.add_edge('A', 'B') - graph.add_edges([%w[A C], %w[B D]]) - graph.add_node('E') - end - - context 'when dfs_edges is called' do - subject { NetworkX.dfs_edges(graph, 'A') } - - it do - is_expected.to eq([%w[A C], %w[A B], %w[B D]]) - end - end - - it 'dfs_edges with limit' do - graph = NetworkX::Graph.new - graph.add_edges([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [4, 5]]) - edges = NetworkX.dfs_edges(graph, 0, 2) - expect(edges).to eq([[0, 1], [1, 2]]) - end - - it 'dfs_tree' do - graph = NetworkX::Graph.new - graph.add_edges([[0, 1], [1, 2], [1, 3], [2, 3], [1, 4], [4, 5], [5, 2], [5, 3], [4, 2]]) - tree = NetworkX.dfs_tree(graph, 0) - expect(tree.edges.sort).to eq([[0, 1], [1, 2], [1, 3], [1, 4], [4, 5]]) - end - - it 'dfs_tree with limit' do - graph = NetworkX::Graph.new - graph.add_edges([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [4, 5]]) - tree = NetworkX.dfs_tree(graph, 0, 2) - expect(tree.edges.sort).to eq([[0, 1], [1, 2]]) - end - - context 'when dfs_successors is called' do - subject { NetworkX.dfs_successors(graph, 'A') } - - it do - is_expected.to eq('A' => %w[C B], 'B' => ['D']) - end - end - - context 'when dfs_predecessors is called' do - subject { NetworkX.dfs_predecessors(graph, 'A') } - - it do - is_expected.to eq('B' => 'A', 'C' => 'A', 'D' => 'B') - end - end - - it 'test dfs_preorder_nodes for Graph' do - edges = [[1, 2], [1, 3], [2, 4], [2, 5], [3, 6], [3, 7]] - dfs_preorder_nodes = [1, 2, 4, 5, 3, 6, 7] - - g = NetworkX::Graph.new - g.add_nodes_from(1..7) - g.add_edges_from(edges) - expect(g.dfs_preorder_nodes(1)).to eq(dfs_preorder_nodes) - end - - it 'test dfs_preorder_nodes for Digraph' do - edges = [[1, 2], [1, 3], [2, 4], [2, 5], [3, 6], [3, 7]] - dfs_preorder_nodes = [1, 2, 4, 5, 3, 6, 7] - - g = NetworkX::DiGraph.new - g.add_nodes_from(1..7) - g.add_edges_from(edges) - expect(g.dfs_preorder_nodes(1)).to eq(dfs_preorder_nodes) - end - - it 'test each dfs nodes for Digraph' do - edges = [[2, 1], [2, 8], [8, 3], [3, 5], [5, 4], [5, 7], [7, 6], [8, 9]] - dfs_preorder_nodes = [2, 1, 8, 3, 5, 4, 7, 6, 9] - dfs_postorder_nodes = [1, 4, 6, 7, 5, 3, 9, 8, 2] - - g = NetworkX::DiGraph.new - g.add_nodes_from(1..9) - g.add_edges_from(edges) - expect(g.each_dfs_preorder_node(2).to_a).to eq(dfs_preorder_nodes) - expect(g.each_dfs_postorder_node(2).to_a).to eq(dfs_postorder_nodes) - end - - it 'test dfs nodes for Graph' do - tree = NetworkX::Graph.new - tree.add_nodes('a'..'o') - tree.add_edges([%w[a b], %w[b c], %w[c h], %w[c i], %w[b d], %w[a e], %w[e f], %w[f j], %w[e g], %w[g k]]) - - expect(tree.dfs_preorder_nodes('a')).to eq %w[a b c h i d e f j g k] - expect(tree.dfs_postorder_nodes('a')).to eq %w[h i c d b j f k g e a] - expect(tree.each_dfs_postorder_node('a').to_a).to eq %w[h i c d b j f k g e a] - end - - it 'test dfs nodes for DiGraph' do - tree = NetworkX::DiGraph.new - tree.add_nodes('a'..'o') - tree.add_edges([%w[a b], %w[b c], %w[c h], %w[c i], %w[b d], %w[a e], %w[e f], %w[f j], %w[e g], %w[g k]]) - - expect(tree.dfs_preorder_nodes('a')).to eq %w[a b c h i d e f j g k] - expect(tree.dfs_postorder_nodes('a')).to eq %w[h i c d b j f k g e a] - expect(tree.each_dfs_postorder_node('a').to_a).to eq %w[h i c d b j f k g e a] - end -end diff --git a/spec/network_x/traversals/edge_dfs_spec.rb b/spec/network_x/traversals/edge_dfs_spec.rb deleted file mode 100644 index 634483b..0000000 --- a/spec/network_x/traversals/edge_dfs_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -RSpec.describe NetworkX::DiGraph do - subject { graph } - - let(:graph) { described_class.new(type: 'directed') } - - before do - graph.add_nodes(%w[A B]) - graph.add_edge('A', 'B') - graph.add_edges([%w[B A], %w[B D]]) - graph.add_node('E') - end - - context 'when dfs_edges is called' do - subject { NetworkX.edge_dfs(graph, 'A') } - - it do - is_expected.to eq([%w[A B], %w[B A], %w[B D]]) - end - end - - it 'multigraph' do - graph = NetworkX::MultiDiGraph.new - graph.add_edge(:A, :B) - graph.add_edges([%i[B A], %i[B D]]) - - expect(NetworkX.edge_dfs(graph, :A)).to eq([[:A, :B, 0], [:B, :A, 0], [:B, :D, 0]]) - end - - it 'edges_dfes to digraph with option' do - graph = NetworkX::DiGraph.new - graph.add_edge(:A, :B) - graph.add_edges([%i[B C], %i[C D]]) - - expect(NetworkX.edge_dfs(graph, :A, :reverse)).to eq([]) - expect(NetworkX.edge_dfs(graph, :D, :ignore)).to eq([%i[D C], %i[C B], %i[B A]]) - expect(NetworkX.edge_dfs(graph, :D, :reverse)).to eq([%i[D C], %i[C B], %i[B A]]) - end - - it 'test bfs_edge (ABC051 D - Maze Master sample_01)' do - # # https://atcoder.jp/contests/abc151/submissions/36398103 - g = NetworkX::Graph.new - g.add_nodes_from(0...2) - g.add_edge(0, 1) - expect(g.bfs_edges(0)).to eq([[0, 1]]) - expect(g.bfs_edges(1)).to eq([[1, 0]]) - end - - it 'test dfs_edges' do - edges = [[1, 2], [1, 3], [2, 4], [2, 5], [3, 6], [3, 7]] - dfs_edges = [[1, 2], [2, 4], [2, 5], [1, 3], [3, 6], [3, 7]] - - g = NetworkX::Graph.new - g.add_nodes_from(1..7) - g.add_edges_from(edges) - expect(g.dfs_edges(1)).to eq(dfs_edges) - end - - it 'tes dfs_edges for object other than integert' do - tree = NetworkX::Graph.new - tree.add_nodes('a'..'o') - tree.add_edges([%w[a b], %w[b c], %w[c h], %w[c i], %w[b d], %w[a e], %w[e f], %w[f j], %w[e g], %w[g k]]) - - expect(tree.dfs_edges('a')).to eq [%w[a b], %w[b c], %w[c h], %w[c i], %w[b d], %w[a e], - %w[e f], %w[f j], %w[e g], %w[g k]] - end - - it 'test dfs_edges to line graph (ABC133 E sample1)' do - n, _k = 4, 3 - edges = [[1, 2], [2, 3], [3, 4]] - - g = NetworkX::Graph.new - g.add_nodes_from(1..n) - g.add_edges_from(edges) - expect(g.dfs_edges(1)).to eq([[1, 2], [2, 3], [3, 4]]) - end - - it 'test dfs_edges to line graph (ABC133 E sample2)' do - n, _k = 5, 4 - edges = [[1, 2], [1, 3], [1, 4], [4, 5]] - - g = NetworkX::Graph.new - g.add_nodes_from(1..n) - g.add_edges_from(edges) - expect(g.dfs_edges(1)).to eq([[1, 2], [1, 3], [1, 4], [4, 5]]) - end -end diff --git a/spec/network_x_spec.rb b/spec/network_x_spec.rb deleted file mode 100644 index bd2c39e..0000000 --- a/spec/network_x_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -RSpec.describe NetworkX do - context 'when has a version number' do - subject { described_class::VERSION } - - it { is_expected.not_to be_nil } - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb deleted file mode 100644 index d3d0e6d..0000000 --- a/spec/spec_helper.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'bundler/setup' - -require 'simplecov' -SimpleCov.start { add_filter 'spec' } - -require 'rspec' -require 'rspec/its' -require 'saharspec/its/call' - -require 'networkx' - -RSpec::Expectations.configuration.warn_about_potential_false_positives = false - -RSpec.configure do |config| - # Enable flags like --only-failures and --next-failure - config.example_status_persistence_file_path = 'spec/.rspec_status' -end diff --git a/top-level-namespace.html b/top-level-namespace.html new file mode 100644 index 0000000..b8c591a --- /dev/null +++ b/top-level-namespace.html @@ -0,0 +1,112 @@ + + + + + + + Top Level Namespace + + — Documentation by YARD 0.9.28 + + + + + + + + + + + + + + + + + + + +
+ + +

Top Level Namespace + + + +

+
+ + + + + + + + + + + +
+ +

Defined Under Namespace

+

+ + + Modules: NetworkX + + + + Classes: Array + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file