networkx 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +5 -5
  2. data/{CODE_OF_CONDUCT.md → .github/CODE_OF_CONDUCT.md} +0 -0
  3. data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +21 -11
  4. data/.github/ISSUE_TEMPLATE.md +15 -0
  5. data/.github/PULL_REQUEST_TEMPLATE.md +10 -0
  6. data/.github/workflows/ci.yml +17 -0
  7. data/.github/workflows/doc.yml +23 -0
  8. data/.github/workflows/gem-push.yml +45 -0
  9. data/.rspec +0 -1
  10. data/.rubocop.yml +56 -63
  11. data/.yardopts +0 -1
  12. data/README.md +27 -27
  13. data/Rakefile +2 -3
  14. data/lib/networkx/auxillary_functions/cliques.rb +62 -0
  15. data/lib/networkx/auxillary_functions/cycles.rb +114 -0
  16. data/lib/networkx/auxillary_functions/dag.rb +59 -0
  17. data/lib/networkx/auxillary_functions/eccentricity.rb +37 -0
  18. data/lib/networkx/auxillary_functions/mis.rb +23 -0
  19. data/lib/networkx/auxillary_functions/mst.rb +33 -0
  20. data/lib/networkx/auxillary_functions/union_find.rb +104 -0
  21. data/lib/networkx/auxillary_functions/vitality.rb +13 -0
  22. data/lib/networkx/auxillary_functions/wiener.rb +13 -0
  23. data/lib/networkx/converters/to_csv.rb +45 -0
  24. data/lib/networkx/converters/to_json.rb +37 -0
  25. data/lib/networkx/digraph.rb +234 -0
  26. data/lib/networkx/flow/capacityscaling.rb +249 -0
  27. data/lib/networkx/flow/edmondskarp.rb +115 -0
  28. data/lib/networkx/flow/preflowpush.rb +249 -0
  29. data/lib/networkx/flow/shortestaugmentingpath.rb +154 -0
  30. data/lib/networkx/flow/utils.rb +139 -0
  31. data/lib/networkx/graph.rb +448 -0
  32. data/lib/networkx/link_analysis/hits.rb +59 -0
  33. data/lib/networkx/link_analysis/pagerank.rb +89 -0
  34. data/lib/networkx/multidigraph.rb +249 -0
  35. data/lib/networkx/multigraph.rb +199 -0
  36. data/lib/networkx/operators/all.rb +65 -0
  37. data/lib/networkx/operators/binary.rb +222 -0
  38. data/lib/networkx/operators/product.rb +201 -0
  39. data/lib/networkx/operators/unary.rb +17 -0
  40. data/lib/networkx/others/bridges.rb +30 -0
  41. data/lib/networkx/others/generators.rb +237 -0
  42. data/lib/networkx/others/grid_2d_graph.rb +38 -0
  43. data/lib/networkx/others/info.rb +11 -0
  44. data/lib/networkx/others/number_connected_components.rb +17 -0
  45. data/lib/networkx/others/reads.rb +52 -0
  46. data/lib/networkx/shortest_path/astar.rb +73 -0
  47. data/lib/networkx/shortest_path/dense.rb +29 -0
  48. data/lib/networkx/shortest_path/unweighted.rb +136 -0
  49. data/lib/networkx/shortest_path/weighted.rb +417 -0
  50. data/lib/networkx/to_matrix.rb +51 -0
  51. data/lib/networkx/traversals/bfs.rb +110 -0
  52. data/lib/networkx/traversals/dfs.rb +135 -0
  53. data/lib/networkx/traversals/edge_dfs.rb +114 -0
  54. data/lib/networkx/version.rb +1 -1
  55. data/lib/networkx.rb +43 -1
  56. data/networkx.gemspec +14 -12
  57. metadata +118 -62
  58. data/.rspec_formatter.rb +0 -24
  59. data/.travis.yml +0 -18
  60. data/Guardfile +0 -7
@@ -0,0 +1,222 @@
1
+ module NetworkX
2
+ # Returns the edges of the graph in an array
3
+ def self.get_edges(graph)
4
+ edges = []
5
+ if graph.is_a?(MultiGraph)
6
+ graph.adj.each do |u, v_keys|
7
+ v_keys.each do |v, key_attrs|
8
+ next if u > v
9
+
10
+ key_attrs.each do |_key, attributes|
11
+ edges << [u, v, attributes]
12
+ end
13
+ end
14
+ end
15
+ else
16
+ graph.adj.each do |u, u_attrs|
17
+ u_attrs.each do |v, uv_attrs|
18
+ edges << [u, v, uv_attrs]
19
+ end
20
+ end
21
+ end
22
+ edges
23
+ end
24
+
25
+ # Transforms the labels of the nodes of the graphs
26
+ # so that they are disjoint.
27
+ def self.convert_to_distinct_labels(graph, starting_int = -1)
28
+ new_graph = graph.class.new
29
+
30
+ idx_dict = graph.nodes.keys.to_h do |v|
31
+ starting_int += 1
32
+ [v, starting_int]
33
+ end
34
+
35
+ graph.nodes.each do |u, attrs|
36
+ new_graph.add_node(u.to_s + idx_dict[u].to_s, **attrs)
37
+ end
38
+
39
+ graph.adj.each do |u, u_edges|
40
+ u_edges.each do |v, uv_attrs|
41
+ if graph.multigraph?
42
+ uv_attrs.each do |_k, attrs|
43
+ new_graph.add_edge(u.to_s + idx_dict[u].to_s, v.to_s + idx_dict[v].to_s, **attrs)
44
+ end
45
+ else
46
+ new_graph.add_edge(u.to_s + idx_dict[u].to_s, v.to_s + idx_dict[v].to_s, **uv_attrs)
47
+ end
48
+ end
49
+ end
50
+ new_graph
51
+ end
52
+
53
+ # Performs the intersection of two graphs
54
+ #
55
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
56
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
57
+ #
58
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the intersection of the two graphs
59
+ def self.intersection(g1, g2)
60
+ result = g1.class.new
61
+
62
+ raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
63
+ raise ArgumentError, 'Node sets must be equal!' unless (g1.nodes.keys - g2.nodes.keys).empty?
64
+
65
+ g1.nodes.each { |u, attrs| result.add_node(u, **attrs) }
66
+
67
+ g1, g2 = g2, g1 if g1.number_of_edges > g2.number_of_edges
68
+ g1.adj.each do |u, u_edges|
69
+ u_edges.each do |v, uv_attrs|
70
+ if g1.multigraph?
71
+ next if u > v && g1.instance_of?(MultiGraph)
72
+
73
+ uv_attrs.each do |k, attrs|
74
+ result.add_edge(u, v, **attrs) if g2.edge?(u, v, k)
75
+ end
76
+ elsif g2.edge?(u, v)
77
+ result.add_edge(u, v, **uv_attrs)
78
+ end
79
+ end
80
+ end
81
+ result
82
+ end
83
+
84
+ # Performs the difference of two graphs
85
+ #
86
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
87
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
88
+ #
89
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the difference of the two graphs
90
+ def self.difference(g1, g2)
91
+ result = g1.class.new
92
+
93
+ raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
94
+ raise ArgumentError, 'Node sets must be equal!' unless (g1.nodes.keys - g2.nodes.keys).empty?
95
+
96
+ g1.nodes.each { |u, attrs| result.add_node(u, **attrs) }
97
+
98
+ g1.adj.each do |u, u_edges|
99
+ u_edges.each do |v, uv_attrs|
100
+ if g1.multigraph?
101
+ next if u > v && g1.instance_of?(MultiGraph)
102
+
103
+ uv_attrs.each do |k, attrs|
104
+ result.add_edge(u, v, **attrs) unless g2.edge?(u, v, k)
105
+ end
106
+ else
107
+ result.add_edge(u, v, **uv_attrs) unless g2.edge?(u, v)
108
+ end
109
+ end
110
+ end
111
+ result
112
+ end
113
+
114
+ # Performs the symmetric difference of two graphs
115
+ #
116
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
117
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
118
+ #
119
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the symmetric difference of the two graphs
120
+ def self.symmetric_difference(g1, g2)
121
+ result = g1.class.new
122
+
123
+ raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
124
+ raise ArgumentError, 'Node sets must be equal!' unless (g1.nodes.keys - g2.nodes.keys).empty?
125
+
126
+ g1.nodes.each { |u, attrs| result.add_node(u, **attrs) }
127
+
128
+ g1.adj.each do |u, u_edges|
129
+ u_edges.each do |v, uv_attrs|
130
+ if g1.multigraph?
131
+ next if u > v && g1.instance_of?(MultiGraph)
132
+
133
+ uv_attrs.each do |k, attrs|
134
+ result.add_edge(u, v, **attrs) unless g2.edge?(u, v, k)
135
+ end
136
+ else
137
+ result.add_edge(u, v, **uv_attrs) unless g2.edge?(u, v)
138
+ end
139
+ end
140
+ end
141
+
142
+ g2.adj.each do |u, u_edges|
143
+ u_edges.each do |v, uv_attrs|
144
+ next if u > v && g1.instance_of?(MultiGraph)
145
+
146
+ if g2.multigraph?
147
+ uv_attrs.each do |k, attrs|
148
+ result.add_edge(u, v, **attrs) unless g1.edge?(u, v, k)
149
+ end
150
+ else
151
+ result.add_edge(u, v, **uv_attrs) unless g1.edge?(u, v)
152
+ end
153
+ end
154
+ end
155
+ result
156
+ end
157
+
158
+ # Performs the composition of two graphs
159
+ #
160
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
161
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
162
+ #
163
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the composition of the two graphs
164
+ def self.compose(g1, g2)
165
+ result = g1.class.new
166
+
167
+ raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
168
+
169
+ result.add_nodes(g1.nodes.map { |u, attrs| [u, attrs] })
170
+ result.add_nodes(g2.nodes.map { |u, attrs| [u, attrs] })
171
+
172
+ if g1.multigraph?
173
+ g1.adj.each { |u, e| e.each { |v, uv_edges| uv_edges.each_value { |attrs| result.add_edge(u, v, **attrs) } } }
174
+ g2.adj.each { |u, e| e.each { |v, uv_edges| uv_edges.each_value { |attrs| result.add_edge(u, v, **attrs) } } }
175
+ else
176
+ g1.adj.each { |u, u_edges| u_edges.each { |v, attrs| result.add_edge(u, v, **attrs) } }
177
+ g2.adj.each { |u, u_edges| u_edges.each { |v, attrs| result.add_edge(u, v, **attrs) } }
178
+ end
179
+ result
180
+ end
181
+
182
+ # Performs the union of two graphs
183
+ #
184
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
185
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
186
+ #
187
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the union of the two graphs
188
+ def self.union(g1, g2)
189
+ raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
190
+
191
+ new_graph = g1.class.new
192
+ new_graph.graph.merge!(g1.graph)
193
+ new_graph.graph.merge!(g2.graph)
194
+
195
+ raise ArgumentError, 'Graphs must be disjoint!' unless (g1.nodes.keys & g2.nodes.keys).empty?
196
+
197
+ g1_edges = get_edges(g1)
198
+ g2_edges = get_edges(g2)
199
+
200
+ new_graph.add_nodes(g1.nodes.keys)
201
+ new_graph.add_edges(g1_edges)
202
+ new_graph.add_nodes(g2.nodes.keys)
203
+ new_graph.add_edges(g2_edges)
204
+
205
+ new_graph
206
+ end
207
+
208
+ # Performs the disjoint union of two graphs
209
+ #
210
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
211
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
212
+ #
213
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the disjoint union of the two graphs
214
+ def self.disjoint_union(g1, g2)
215
+ new_g1 = convert_to_distinct_labels(g1)
216
+ new_g2 = convert_to_distinct_labels(g2)
217
+ result = union(new_g1, new_g2)
218
+ result.graph.merge!(g1.graph)
219
+ result.graph.merge!(g2.graph)
220
+ result
221
+ end
222
+ end
@@ -0,0 +1,201 @@
1
+ module NetworkX
2
+ # Returns the edges of the graph in an array
3
+ def self.edges_in_array(graph)
4
+ edge_array = []
5
+ if graph.multigraph?
6
+ graph.adj.each do |u, u_edges|
7
+ u_edges.each do |v, uv_edges|
8
+ uv_edges.each do |_k, attrs|
9
+ edge_array << [u, v, attrs]
10
+ end
11
+ end
12
+ end
13
+ else
14
+ graph.adj.each do |u, u_edges|
15
+ u_edges.each do |v, attrs|
16
+ edge_array << [u, v, attrs]
17
+ end
18
+ end
19
+ end
20
+ edge_array
21
+ end
22
+
23
+ # Returns the hash product of two hashes
24
+ def self.hash_product(hash1, hash2)
25
+ (hash1.keys | hash2.keys).to_h { |n| [n, [hash1[n], hash2[n]]] }
26
+ end
27
+
28
+ # Returns the node product of nodes of two graphs
29
+ def self.node_product(g1, g2)
30
+ n_product = []
31
+ g1.nodes.each do |k1, attrs1|
32
+ g2.nodes.each do |k2, attrs2|
33
+ n_product << [[k1, k2], hash_product(attrs1, attrs2)]
34
+ end
35
+ end
36
+ n_product
37
+ end
38
+
39
+ # Returns the product of directed edges with edges
40
+ def self.directed_edges_cross_edges(g1, g2)
41
+ result = []
42
+ edges_in_array(g1).each do |u, v, c|
43
+ edges_in_array(g2).each do |x, y, d|
44
+ result << [[u, x], [v, y], hash_product(c, d)]
45
+ end
46
+ end
47
+ result
48
+ end
49
+
50
+ # Returns the product of undirected edges with edges
51
+ def self.undirected_edges_cross_edges(g1, g2)
52
+ result = []
53
+ edges_in_array(g1).each do |u, v, c|
54
+ edges_in_array(g2).each do |x, y, d|
55
+ result << [[v, x], [u, y], hash_product(c, d)]
56
+ end
57
+ end
58
+ result
59
+ end
60
+
61
+ # Returns the product of edges with edges
62
+ def self.edges_cross_nodes(g1, g2)
63
+ result = []
64
+ edges_in_array(g1).each do |u, v, d|
65
+ g2.nodes.each_key do |x|
66
+ result << [[u, x], [v, x], d]
67
+ end
68
+ end
69
+ result
70
+ end
71
+
72
+ # Returns the product of directed nodes with edges
73
+ def self.nodes_cross_edges(g1, g2)
74
+ result = []
75
+ g1.nodes.each_key do |x|
76
+ edges_in_array(g2).each do |u, v, d|
77
+ result << [[x, u], [x, v], d]
78
+ end
79
+ end
80
+ result
81
+ end
82
+
83
+ # Returns the product of edges with pairs of nodes
84
+ def self.edges_cross_nodes_and_nodes(g1, g2)
85
+ result = []
86
+ edges_in_array(g1).each do |u, v, d|
87
+ g2.nodes.each_key do |x|
88
+ g2.nodes.each_key do |y|
89
+ result << [[u, x], [v, y], d]
90
+ end
91
+ end
92
+ end
93
+ result
94
+ end
95
+
96
+ # Initializes the product graph
97
+ def self.init_product_graph(g1, g2)
98
+ raise ArgumentError, 'Arguments must be both directed or undirected!' unless g1.directed? == g2.directed?
99
+
100
+ g = if g1.multigraph? || g2.multigraph?
101
+ NetworkX::MultiGraph.new
102
+ else
103
+ NetworkX::Graph.new
104
+ end
105
+ g = g.to_directed if g.directed?
106
+ g
107
+ end
108
+
109
+ # Returns the tensor product of two graphs
110
+ #
111
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
112
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
113
+ #
114
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the tensor product of the two graphs
115
+ def self.tensor_product(g1, g2)
116
+ g = init_product_graph(g1, g2)
117
+ g.add_nodes(node_product(g1, g2))
118
+ g.add_edges(directed_edges_cross_edges(g1, g2))
119
+ g.add_edges(undirected_edges_cross_edges(g1, g2)) unless g.directed?
120
+ g
121
+ end
122
+
123
+ # Returns the cartesian product of two graphs
124
+ #
125
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
126
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
127
+ #
128
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the cartesian product of the two graphs
129
+ def self.cartesian_product(g1, g2)
130
+ g = init_product_graph(g1, g2)
131
+ g.add_nodes(node_product(g1, g2))
132
+ g.add_edges(edges_cross_nodes(g1, g2))
133
+ g.add_edges(nodes_cross_edges(g1, g2))
134
+ g
135
+ end
136
+
137
+ # Returns the lexicographic product of two graphs
138
+ #
139
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
140
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
141
+ #
142
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the lexicographic product of the two graphs
143
+ def self.lexicographic_product(g1, g2)
144
+ g = init_product_graph(g1, g2)
145
+ g.add_nodes(node_product(g1, g2))
146
+ g.add_edges(edges_cross_nodes_and_nodes(g1, g2))
147
+ g.add_edges(nodes_cross_edges(g1, g2))
148
+ g
149
+ end
150
+
151
+ # Returns the strong product of two graphs
152
+ #
153
+ # @param g1 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
154
+ # @param g2 [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.2
155
+ #
156
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the strong product of the two graphs
157
+ def self.strong_product(g1, g2)
158
+ g = init_product_graph(g1, g2)
159
+ g.add_nodes(node_product(g1, g2))
160
+ g.add_edges(nodes_cross_edges(g1, g2))
161
+ g.add_edges(edges_cross_nodes(g1, g2))
162
+ g.add_edges(directed_edges_cross_edges(g1, g2))
163
+ g.add_edges(undirected_edges_cross_edges(g1, g2)) unless g.directed?
164
+ g
165
+ end
166
+
167
+ # Returns the specified power of the graph
168
+ #
169
+ # @param graph [Graph, DiGraph, MultiGraph, MultiDiGraph] graph no.1
170
+ # @param pow [Numeric] the power to which to raise the graph to
171
+ #
172
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the power of the graph
173
+ def self.power(graph, pow)
174
+ raise ArgumentError, 'Power must be a positive quantity!' if pow <= 0
175
+
176
+ result = NetworkX::Graph.new
177
+ result.add_nodes(graph.nodes.map { |n, attrs| [n, attrs] })
178
+ graph.nodes.each do |n, _attrs|
179
+ seen = {}
180
+ level = 1
181
+ next_level = graph.adj[n]
182
+ until next_level.empty?
183
+ this_level = next_level
184
+ next_level = {}
185
+ this_level.each do |v, _attrs|
186
+ next if v == n
187
+
188
+ unless seen.has_key?(v)
189
+ seen[v] = level
190
+ next_level.merge!(graph.adj[v])
191
+ end
192
+ end
193
+ break if pow <= level
194
+
195
+ level += 1
196
+ end
197
+ result.add_edges(seen.map { |v, _| [n, v] })
198
+ end
199
+ result
200
+ end
201
+ end
@@ -0,0 +1,17 @@
1
+ module NetworkX
2
+ # Performs the complement operation on the graph
3
+ #
4
+ # @param [Graph, DiGraph, MultiGraph, MultiDiGraph] graph
5
+ #
6
+ # @return [Graph, DiGraph, MultiGraph, MultiDiGraph] the complement of the graph
7
+ def self.complement(graph)
8
+ result = Marshal.load(Marshal.dump(graph))
9
+ result.clear
10
+
11
+ result.add_nodes(graph.nodes.map { |u, attrs| [u, attrs] })
12
+ graph.adj.each do |u, u_edges|
13
+ graph.nodes.each { |v, attrs| result.add_edge(u, v, **attrs) if !u_edges.has_key?(v) && u != v }
14
+ end
15
+ result
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ require_relative '../auxillary_functions/union_find'
2
+
3
+ module NetworkX
4
+ # @return [[Object, Object]] bridges
5
+ #
6
+ # @param graph [Graph] Graph
7
+ def self.bridges(graph)
8
+ each_bridge(graph).to_a
9
+ end
10
+
11
+ # @param graph [Graph] Graph
12
+ def self.each_bridge(graph)
13
+ return enum_for(:each_bridge, graph) unless block_given?
14
+
15
+ graph.each_edge.with_index do |(s_i, t_i), i|
16
+ uf = UnionFind.new(1..graph.number_of_nodes)
17
+ graph.each_edge.with_index do |(s_j, t_j), j|
18
+ uf.unite(s_j, t_j) if i != j
19
+ end
20
+ yield [s_i, t_i] unless uf.same?(s_i, t_i)
21
+ end
22
+ end
23
+
24
+ # @return [Integer] the number of bridges
25
+ #
26
+ # @param graph [Graph] Graph
27
+ def self.number_of_bridges(graph)
28
+ bridges(graph).size
29
+ end
30
+ end
@@ -0,0 +1,237 @@
1
+ require_relative '../../networkx'
2
+
3
+ module NetworkX
4
+ class Graph
5
+ # private class method
6
+ def self.complete_edges(n)
7
+ n = (0...n) if n.is_a?(Integer)
8
+
9
+ edges = []
10
+ n.each do |i|
11
+ n.each do |j|
12
+ edges << [i, j] if i < j
13
+ end
14
+ end
15
+ edges
16
+ end
17
+
18
+ def self.balanced_tree(r, h)
19
+ edges = []
20
+ q = [0]
21
+ i = 0
22
+ h.times do
23
+ t = q.dup
24
+ q.clear
25
+ t.each do |v|
26
+ r.times do
27
+ i += 1
28
+ edges << [v, i]
29
+ q << i
30
+ end
31
+ end
32
+ end
33
+ graph = new(name: "balanced_tree(#{r}, #{h})")
34
+ graph.add_edges(edges)
35
+ graph
36
+ end
37
+
38
+ def self.barbell_graph(m1, m2)
39
+ edges = complete_edges(m1)
40
+ edges.concat((m1..m2 + m1).map { |k| [k - 1, k] })
41
+ edges.concat complete_edges(m1 + m2...m1 + m2 + m1)
42
+
43
+ graph = new(name: "barbell_graph(#{m1}, #{m2})")
44
+ graph.add_edges(edges)
45
+ graph
46
+ end
47
+
48
+ def self.complete_graph(n)
49
+ n = (0...n) if n.is_a?(Integer)
50
+
51
+ edges = []
52
+ n.each do |i|
53
+ n.each do |j|
54
+ edges << [i, j] if i < j
55
+ end
56
+ end
57
+
58
+ graph = new(name: "complete_graph(#{n})")
59
+ graph.add_edges(edges)
60
+ graph
61
+ end
62
+
63
+ def self.circular_ladder_graph(n)
64
+ edges = (0...n - 1).map { |v| [v, v + 1] }
65
+ edges << [n - 1, 0]
66
+ edges.concat((n...2 * n - 1).map { |v| [v, v + 1] })
67
+ edges << [2 * n - 1, n]
68
+ edges.concat((0...n).map { |v| [v, v + n] })
69
+
70
+ graph = new(name: "circular_ladder_graph(#{n})")
71
+ graph.add_edges(edges)
72
+ graph
73
+ end
74
+
75
+ def self.cycle_graph(n)
76
+ edges = (0...n - 1).map { |v| [v, v + 1] }
77
+ edges << [n - 1, 0]
78
+
79
+ graph = new(name: "cycle_graph(#{n})")
80
+ graph.add_edges(edges)
81
+ graph
82
+ end
83
+
84
+ def self.empty_graph(number_of_nodes)
85
+ empty_graph = new(name: "empty_graph#{number_of_nodes}")
86
+ empty_graph.add_nodes_from(0...number_of_nodes)
87
+ empty_graph
88
+ end
89
+
90
+ def self.ladder_graph(n)
91
+ edges = (0...n - 1).map { |k| [k, k + 1] }
92
+ edges.concat((n...2 * n - 1).map { |k| [k, k + 1] })
93
+ edges.concat((0...n).map { |k| [k, k + n] })
94
+
95
+ graph = new(name: "ladder_graph(#{n})")
96
+ graph.add_edges(edges)
97
+ graph
98
+ end
99
+
100
+ def self.lollipop_graph(m, n)
101
+ edges = complete_edges(m)
102
+ edges.concat((m - 1...m - 1 + n).map { |v| [v, v + 1] })
103
+
104
+ graph = new(name: "lollipop_graph(#{m}, #{n})")
105
+ graph.add_edges(edges)
106
+ graph
107
+ end
108
+
109
+ def self.null_graph
110
+ new(name: 'null_graph')
111
+ end
112
+
113
+ def self.path_graph(n)
114
+ edges = (0...n - 1).map { |v| [v, v + 1] }
115
+
116
+ graph = new(name: "path_graph(#{n})")
117
+ graph.add_edges(edges)
118
+ graph
119
+ end
120
+
121
+ def self.star_graph(n)
122
+ edges = (1..n).map { |i| [0, i] }
123
+
124
+ graph = new(name: "star_graph(#{n})")
125
+ graph.add_edges(edges)
126
+ graph
127
+ end
128
+
129
+ def self.trivial_graph
130
+ trivial_graph = new(name: 'trivial_grpph')
131
+ trivial_graph.add_node(0)
132
+ trivial_graph
133
+ end
134
+
135
+ def self.wheel_graph(n)
136
+ edges = (1..n - 1).map { |i| [0, i] }
137
+ edges.concat((1...n - 1).map { |i| [i, i + 1] })
138
+ edges << [1, n - 1]
139
+
140
+ graph = new(name: "wheel_graph(#{n})")
141
+ graph.add_edges(edges)
142
+ graph
143
+ end
144
+
145
+ def self.bull_graph
146
+ edges = [[0, 1], [1, 2], [2, 0], [1, 3], [2, 4]]
147
+ graph = new(name: 'bull_graph')
148
+ graph.add_edges(edges)
149
+ graph
150
+ end
151
+
152
+ def self.cubical_graph
153
+ graph = circular_ladder_graph(4)
154
+ graph.graph[:name] = 'cubical_graph'
155
+ graph
156
+ end
157
+
158
+ def self.diamond_graph
159
+ edges = [[0, 1], [0, 2], [1, 2], [1, 3], [2, 3]]
160
+ graph = new(name: 'diamond_graph')
161
+ graph.add_edges(edges)
162
+ graph
163
+ end
164
+
165
+ # 12
166
+ def self.dodecahedral_graph
167
+ edges = (0...19).map { |k| [k, k + 1] }
168
+ edges.concat [[0, 19], [0, 10], [1, 8], [2, 6], [3, 19], [4, 17], [5, 15], [7, 14], [9, 13], [11, 18], [12, 16]]
169
+ graph = new(name: 'dodecahedral_graph')
170
+ graph.add_edges(edges)
171
+ graph
172
+ end
173
+
174
+ def self.heawood_graph
175
+ edges = (0...13).map { |k| [k, k + 1] }
176
+ edges << [13, 0]
177
+ edges.concat [[0, 5], [1, 10], [2, 7], [3, 12], [4, 9], [6, 11], [8, 13]]
178
+ graph = new(name: 'heawood_graph')
179
+ graph.add_edges(edges)
180
+ graph
181
+ end
182
+
183
+ def self.house_graph
184
+ edges = [[0, 1], [0, 2], [1, 3], [2, 3], [2, 4], [3, 4]]
185
+ graph = new(name: 'house_graph')
186
+ graph.add_edges(edges)
187
+ graph
188
+ end
189
+
190
+ def self.house_x_graph
191
+ edges = (0...4).map { |k| [k, k + 1] }
192
+ edges.concat [[0, 2], [0, 3], [1, 3], [2, 4], [3, 4]]
193
+ graph = new(name: 'house_x_graph')
194
+ graph.add_edges(edges)
195
+ graph
196
+ end
197
+
198
+ def self.moebius_kantor_graph
199
+ edges = (0...15).map { |k| [k, k + 1] }
200
+ edges << [15, 0]
201
+ edges.concat [[0, 5], [1, 12], [2, 7], [4, 9], [3, 14], [6, 11], [8, 13], [10, 15]]
202
+ graph = new(name: 'moebius_kantor_graph')
203
+ graph.add_edges(edges)
204
+ graph
205
+ end
206
+
207
+ # 8: 6 nodes, 12 edges
208
+ def self.octahedral_graph
209
+ edges = []
210
+ 6.times do |i|
211
+ 6.times do |j|
212
+ edges << [i, j] if i != j && i + j != 5
213
+ end
214
+ end
215
+ graph = new(name: 'octahedral_graph')
216
+ graph.add_edges(edges)
217
+ graph
218
+ end
219
+
220
+ def self.tetrahedral_graph
221
+ graph = complete_graph(4)
222
+ graph.graph[:name] = 'tetrahedral_graph'
223
+ graph
224
+ end
225
+
226
+ # Experimental For debug.
227
+ #
228
+ # @return data for https://hello-world-494ec.firebaseapp.com/
229
+ def put_graph_x2
230
+ output = <<~"OUTPUT"
231
+ #{number_of_nodes} #{number_of_edges}
232
+ #{edges.map { |edge| edge.join(' ') }.join("\n")}
233
+ OUTPUT
234
+ puts output
235
+ end
236
+ end
237
+ end