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.
- checksums.yaml +5 -5
- data/{CODE_OF_CONDUCT.md → .github/CODE_OF_CONDUCT.md} +0 -0
- data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +21 -11
- data/.github/ISSUE_TEMPLATE.md +15 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +10 -0
- data/.github/workflows/ci.yml +17 -0
- data/.github/workflows/doc.yml +23 -0
- data/.github/workflows/gem-push.yml +45 -0
- data/.rspec +0 -1
- data/.rubocop.yml +56 -63
- data/.yardopts +0 -1
- data/README.md +27 -27
- data/Rakefile +2 -3
- data/lib/networkx/auxillary_functions/cliques.rb +62 -0
- data/lib/networkx/auxillary_functions/cycles.rb +114 -0
- data/lib/networkx/auxillary_functions/dag.rb +59 -0
- data/lib/networkx/auxillary_functions/eccentricity.rb +37 -0
- data/lib/networkx/auxillary_functions/mis.rb +23 -0
- data/lib/networkx/auxillary_functions/mst.rb +33 -0
- data/lib/networkx/auxillary_functions/union_find.rb +104 -0
- data/lib/networkx/auxillary_functions/vitality.rb +13 -0
- data/lib/networkx/auxillary_functions/wiener.rb +13 -0
- data/lib/networkx/converters/to_csv.rb +45 -0
- data/lib/networkx/converters/to_json.rb +37 -0
- data/lib/networkx/digraph.rb +234 -0
- data/lib/networkx/flow/capacityscaling.rb +249 -0
- data/lib/networkx/flow/edmondskarp.rb +115 -0
- data/lib/networkx/flow/preflowpush.rb +249 -0
- data/lib/networkx/flow/shortestaugmentingpath.rb +154 -0
- data/lib/networkx/flow/utils.rb +139 -0
- data/lib/networkx/graph.rb +448 -0
- data/lib/networkx/link_analysis/hits.rb +59 -0
- data/lib/networkx/link_analysis/pagerank.rb +89 -0
- data/lib/networkx/multidigraph.rb +249 -0
- data/lib/networkx/multigraph.rb +199 -0
- data/lib/networkx/operators/all.rb +65 -0
- data/lib/networkx/operators/binary.rb +222 -0
- data/lib/networkx/operators/product.rb +201 -0
- data/lib/networkx/operators/unary.rb +17 -0
- data/lib/networkx/others/bridges.rb +30 -0
- data/lib/networkx/others/generators.rb +237 -0
- data/lib/networkx/others/grid_2d_graph.rb +38 -0
- data/lib/networkx/others/info.rb +11 -0
- data/lib/networkx/others/number_connected_components.rb +17 -0
- data/lib/networkx/others/reads.rb +52 -0
- data/lib/networkx/shortest_path/astar.rb +73 -0
- data/lib/networkx/shortest_path/dense.rb +29 -0
- data/lib/networkx/shortest_path/unweighted.rb +136 -0
- data/lib/networkx/shortest_path/weighted.rb +417 -0
- data/lib/networkx/to_matrix.rb +51 -0
- data/lib/networkx/traversals/bfs.rb +110 -0
- data/lib/networkx/traversals/dfs.rb +135 -0
- data/lib/networkx/traversals/edge_dfs.rb +114 -0
- data/lib/networkx/version.rb +1 -1
- data/lib/networkx.rb +43 -1
- data/networkx.gemspec +14 -12
- metadata +118 -62
- data/.rspec_formatter.rb +0 -24
- data/.travis.yml +0 -18
- data/Guardfile +0 -7
@@ -0,0 +1,249 @@
|
|
1
|
+
module NetworkX
|
2
|
+
# Describes the class for making MultiDiGraphs
|
3
|
+
#
|
4
|
+
# @attr_reader adj [Hash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } }]
|
5
|
+
# Stores the edges and their attributes in an adjencency list form
|
6
|
+
# @attr_reader pred [Hash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } }]
|
7
|
+
# Stores the reverse edges and their attributes in an adjencency list form
|
8
|
+
# @attr_reader nodes [Hash{ Object => Hash{ Object => Object } }] Stores the nodes and their attributes
|
9
|
+
# @attr_reader graph [Hash{ Object => Object }] Stores the attributes of the graph
|
10
|
+
class MultiDiGraph < DiGraph
|
11
|
+
# Returns a new key
|
12
|
+
#
|
13
|
+
# @param node1 [Object] the first node of a given edge
|
14
|
+
# @param node2 [Object] the second node of a given edge
|
15
|
+
def new_edge_key(node1, node2)
|
16
|
+
return 0 if @adj[node1][node2].nil?
|
17
|
+
|
18
|
+
key = @adj[node1][node2].length
|
19
|
+
key += 1 while @adj[node1][node2].has_key?(key)
|
20
|
+
key
|
21
|
+
end
|
22
|
+
|
23
|
+
# Adds the respective edge
|
24
|
+
#
|
25
|
+
# @example Add an edge with attribute name
|
26
|
+
# graph.add_edge(node1, node2, name: "Edge1")
|
27
|
+
#
|
28
|
+
# @example Add an edge with no attribute
|
29
|
+
# graph.add_edge("Bangalore", "Chennai")
|
30
|
+
#
|
31
|
+
# @param node1 [Object] the first node of the edge
|
32
|
+
# @param node2 [Object] the second node of the edge
|
33
|
+
# @param edge_attrs [Hash{ Object => Object }] the hash of the edge attributes
|
34
|
+
def add_edge(node1, node2, **edge_attrs)
|
35
|
+
add_node(node1)
|
36
|
+
add_node(node2)
|
37
|
+
key = new_edge_key(node1, node2)
|
38
|
+
all_edge_attrs = @adj[node1][node2] || {}
|
39
|
+
all_edge_attrs[key] = edge_attrs
|
40
|
+
@adj[node1][node2] = all_edge_attrs
|
41
|
+
@pred[node2][node1] = all_edge_attrs
|
42
|
+
end
|
43
|
+
|
44
|
+
# Removes edge from the graph
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# graph.remove_edge('Noida', 'Bangalore')
|
48
|
+
#
|
49
|
+
# @param node1 [Object] the first node of the edge
|
50
|
+
# @param node2 [Object] the second node of the edge
|
51
|
+
def remove_edge(node1, node2, key = nil)
|
52
|
+
return super(node1, node2) if key.nil?
|
53
|
+
|
54
|
+
raise KeyError, "#{node1} is not a valid node." unless @nodes.has_key?(node1)
|
55
|
+
raise KeyError, "#{node2} is not a valid node" unless @nodes.has_key?(node2)
|
56
|
+
raise KeyError, 'The given edge is not a valid one.' unless @adj[node1].has_key?(node2)
|
57
|
+
if @adj[node1][node2].none? { |_index, data| data[:key] == key }
|
58
|
+
raise KeyError, 'The given edge is not a valid one'
|
59
|
+
end
|
60
|
+
|
61
|
+
@adj[node1][node2].delete_if { |_indx, data| data[:key] == key }
|
62
|
+
@pred[node2][node1].delete_if { |_indx, data| data[:key] == key }
|
63
|
+
end
|
64
|
+
|
65
|
+
# Checks if the the edge consisting of two nodes is present in the graph
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
# graph.edge?(node1, node2)
|
69
|
+
#
|
70
|
+
# @param node1 [Object] the first node of the edge to be checked
|
71
|
+
# @param node2 [Object] the second node of the edge to be checked
|
72
|
+
# @param key [Integer] the key of the given edge
|
73
|
+
def edge?(node1, node2, key = nil)
|
74
|
+
return super(node1, node2) if key.nil?
|
75
|
+
|
76
|
+
node?(node1) && @adj[node1].has_key?(node2) && @adj[node1][node2].has_key?(key)
|
77
|
+
end
|
78
|
+
|
79
|
+
def has_edge?(node1, node2, key = nil)
|
80
|
+
return super(node1, node2) if key.nil?
|
81
|
+
|
82
|
+
return false unless node?(node1) && @adj[node1].has_key?(node2)
|
83
|
+
|
84
|
+
@adj[node1][node2].any? { |_index, data| data[:key] == key }
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns the undirected version of the graph
|
88
|
+
#
|
89
|
+
# @example
|
90
|
+
# graph.to_undirected
|
91
|
+
def to_undirected
|
92
|
+
graph = NetworkX::Graph.new(**@graph)
|
93
|
+
@nodes.each { |node, node_attr| graph.add_node(node, **node_attr) }
|
94
|
+
@adj.each do |node1, node1_edges|
|
95
|
+
node1_edges.each do |node2, node1_node2|
|
96
|
+
edge_attrs = {}
|
97
|
+
node1_node2.each { |_key, attrs| edge_attrs.merge!(attrs) }
|
98
|
+
graph.add_edge(node1, node2, **edge_attrs)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
graph
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns the directed version of the graph
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# graph.to_directed
|
108
|
+
def to_directed
|
109
|
+
graph = NetworkX::DiGraph.new(**@graph)
|
110
|
+
@nodes.each { |node, node_attr| graph.add_node(node, **node_attr) }
|
111
|
+
@adj.each do |node1, node1_edges|
|
112
|
+
node1_edges.each do |node2, node1_node2|
|
113
|
+
edge_attrs = {}
|
114
|
+
node1_node2.each { |_key, attrs| edge_attrs.merge!(attrs) }
|
115
|
+
graph.add_edge(node1, node2, **edge_attrs)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
graph
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns the multigraph version of the graph
|
122
|
+
#
|
123
|
+
# @example
|
124
|
+
# graph.to_multigraph
|
125
|
+
def to_multigraph
|
126
|
+
graph = NetworkX::MultiGraph.new(**@graph)
|
127
|
+
@nodes.each { |node, node_attr| graph.add_node(node, **node_attr) }
|
128
|
+
@adj.each do |node1, node2_edges|
|
129
|
+
node2_edges.each do |node2, edges|
|
130
|
+
edges.each { |_key, attrs| graph.add_edge(node1, node2, **attrs) }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
graph
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns the reversed version of the graph
|
137
|
+
#
|
138
|
+
# @example
|
139
|
+
# graph.reverse
|
140
|
+
def reverse
|
141
|
+
new_graph = NetworkX::MultiDiGraph.new(**@graph)
|
142
|
+
@nodes.each { |node, attrs| new_graph.add_node(node, **attrs) }
|
143
|
+
@adj.each do |u, u_edges|
|
144
|
+
u_edges.each { |v, uv_attrs| uv_attrs.each { |_k, edge_attrs| new_graph.add_edge(v, u, **edge_attrs) } }
|
145
|
+
end
|
146
|
+
new_graph
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns in-degree of a given node
|
150
|
+
#
|
151
|
+
# @example
|
152
|
+
# graph.in_degree(node)
|
153
|
+
#
|
154
|
+
# @param node [Object] the node whose in degree is to be calculated
|
155
|
+
def in_degree(node)
|
156
|
+
@pred[node].values.map(&:length).sum
|
157
|
+
end
|
158
|
+
|
159
|
+
# Returns out-degree of a given node
|
160
|
+
#
|
161
|
+
# @example
|
162
|
+
# graph.out_degree(node)
|
163
|
+
#
|
164
|
+
# @param node [Object] the node whose out degree is to be calculated
|
165
|
+
def out_degree(node)
|
166
|
+
@adj[node].values.map(&:length).sum
|
167
|
+
end
|
168
|
+
|
169
|
+
# Returns number of edges
|
170
|
+
#
|
171
|
+
# @example
|
172
|
+
# graph.number_of_edges
|
173
|
+
def number_of_edges
|
174
|
+
@adj.values.flat_map(&:values).map(&:length).sum
|
175
|
+
end
|
176
|
+
|
177
|
+
# Returns the size of the graph
|
178
|
+
#
|
179
|
+
# @example
|
180
|
+
# graph.size(true)
|
181
|
+
#
|
182
|
+
# @param is_weighted [Bool] if true, method returns sum of weights of all edges
|
183
|
+
# else returns number of edges
|
184
|
+
def size(is_weighted = false)
|
185
|
+
if is_weighted
|
186
|
+
graph_size = 0
|
187
|
+
@adj.each do |_, hash_val|
|
188
|
+
hash_val.each { |_, v| v.each { |_, attrs| graph_size += attrs[:weight] if attrs.has_key?(:weight) } }
|
189
|
+
end
|
190
|
+
return graph_size
|
191
|
+
end
|
192
|
+
number_of_edges
|
193
|
+
end
|
194
|
+
|
195
|
+
# Returns subgraph consisting of given array of nodes
|
196
|
+
#
|
197
|
+
# @example
|
198
|
+
# graph.subgraph(%w[Mumbai Nagpur])
|
199
|
+
#
|
200
|
+
# @param nodes [Array<Object>] the nodes to be included in the subgraph
|
201
|
+
def subgraph(nodes)
|
202
|
+
case nodes
|
203
|
+
when Array, Set
|
204
|
+
sub_graph = NetworkX::MultiDiGraph.new(**@graph)
|
205
|
+
nodes.each do |u, _|
|
206
|
+
raise KeyError, "#{u} does not exist in the current graph!" unless @nodes.has_key?(u)
|
207
|
+
|
208
|
+
sub_graph.add_node(u, **@nodes[u])
|
209
|
+
@adj[u].each do |v, edge_val|
|
210
|
+
edge_val.each { |_, keyval| sub_graph.add_edge(u, v, **keyval) if @adj[u].has_key?(v) && nodes.include?(v) }
|
211
|
+
end
|
212
|
+
end
|
213
|
+
sub_graph
|
214
|
+
else
|
215
|
+
raise ArgumentError, 'Expected Argument to be Array or Set of nodes, ' \
|
216
|
+
"received #{nodes.class.name} instead."
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Returns subgraph conisting of given edges
|
221
|
+
#
|
222
|
+
# @example
|
223
|
+
# graph.edge_subgraph([%w[Nagpur Wardha], %w[Nagpur Mumbai]])
|
224
|
+
#
|
225
|
+
# @param edges [Array<Object, Object>] the edges to be included in the subraph
|
226
|
+
def edge_subgraph(edges)
|
227
|
+
case edges
|
228
|
+
when Array, Set
|
229
|
+
sub_graph = NetworkX::MultiDiGraph.new(**@graph)
|
230
|
+
edges.each do |u, v|
|
231
|
+
raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.has_key?(u) \
|
232
|
+
&& @adj[u].has_key?(v)
|
233
|
+
|
234
|
+
sub_graph.add_node(u, **@nodes[u])
|
235
|
+
sub_graph.add_node(v, **@nodes[v])
|
236
|
+
@adj[u][v].each { |_, keyval| sub_graph.add_edge(u, v, **keyval) }
|
237
|
+
end
|
238
|
+
sub_graph
|
239
|
+
else
|
240
|
+
raise ArgumentError, 'Expected Argument to be Array or Set of edges, ' \
|
241
|
+
"received #{edges.class.name} instead."
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def multigraph?
|
246
|
+
true
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
module NetworkX
|
2
|
+
# Describes the class for making MultiGraphs
|
3
|
+
#
|
4
|
+
# @attr_reader adj [Hash{ Object => Hash{ Object => Hash{ Integer => Hash{ Object => Object } } } }]
|
5
|
+
# Stores the edges and their attributes in an adjencency list form
|
6
|
+
# @attr_reader nodes [Hash{ Object => Hash{ Object => Object } }] Stores the nodes and their attributes
|
7
|
+
# @attr_reader graph [Hash{ Object => Object }] Stores the attributes of the gra
|
8
|
+
class MultiGraph < Graph
|
9
|
+
# Returns a new key
|
10
|
+
#
|
11
|
+
# @param node1 [Object] the first node of a given edge
|
12
|
+
# @param node2 [Object] the second node of a given edge
|
13
|
+
def new_edge_key(node1, node2)
|
14
|
+
return 0 if @adj[node1][node2].nil?
|
15
|
+
|
16
|
+
key = @adj[node1][node2].length
|
17
|
+
key += 1 while @adj[node1][node2].has_key?(key)
|
18
|
+
key
|
19
|
+
end
|
20
|
+
|
21
|
+
# Adds the respective edge
|
22
|
+
#
|
23
|
+
# @example Add an edge with attribute name
|
24
|
+
# graph.add_edge(node1, node2, name: "Edge1")
|
25
|
+
#
|
26
|
+
# @example Add an edge with no attribute
|
27
|
+
# graph.add_edge("Bangalore", "Chennai")
|
28
|
+
#
|
29
|
+
# @param node1 [Object] the first node of the edge
|
30
|
+
# @param node2 [Object] the second node of the edge
|
31
|
+
# @param edge_attrs [Hash{ Object => Object }] the hash of the edge attributes
|
32
|
+
def add_edge(node1, node2, **edge_attrs)
|
33
|
+
add_node(node1)
|
34
|
+
add_node(node2)
|
35
|
+
key = new_edge_key(node1, node2)
|
36
|
+
all_edge_attrs = @adj[node1][node2] || {}
|
37
|
+
all_edge_attrs[key] = edge_attrs
|
38
|
+
@adj[node1][node2] = all_edge_attrs
|
39
|
+
@adj[node2][node1] = all_edge_attrs
|
40
|
+
end
|
41
|
+
|
42
|
+
# Removes edge from the graph
|
43
|
+
#
|
44
|
+
# @example
|
45
|
+
# graph.remove_edge('Noida', 'Bangalore')
|
46
|
+
#
|
47
|
+
# @param node1 [Object] the first node of the edge
|
48
|
+
# @param node2 [Object] the second node of the edge
|
49
|
+
def remove_edge(node1, node2, key = nil)
|
50
|
+
return super(node1, node2) if key.nil?
|
51
|
+
|
52
|
+
raise KeyError, "#{node1} is not a valid node." unless @nodes.has_key?(node1)
|
53
|
+
raise KeyError, "#{node2} is not a valid node" unless @nodes.has_key?(node2)
|
54
|
+
raise KeyError, 'The given edge is not a valid one.' unless @adj[node1].has_key?(node2)
|
55
|
+
|
56
|
+
if @adj[node1][node2].none? { |_index, data| data[:key] == key }
|
57
|
+
raise KeyError, 'The given edge is not a valid one'
|
58
|
+
end
|
59
|
+
|
60
|
+
@adj[node1][node2].delete_if { |_indx, data| data[:key] == key }
|
61
|
+
@adj[node2][node1].delete_if { |_indx, data| data[:key] == key }
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the size of the graph
|
65
|
+
#
|
66
|
+
# @example
|
67
|
+
# graph.size(true)
|
68
|
+
#
|
69
|
+
# @param is_weighted [Bool] if true, method returns sum of weights of all edges
|
70
|
+
# else returns number of edges
|
71
|
+
def size(is_weighted = false)
|
72
|
+
if is_weighted
|
73
|
+
graph_size = 0
|
74
|
+
@adj.each do |_, hash_val|
|
75
|
+
hash_val.each { |_, v| v.each { |_, attrs| graph_size += attrs[:weight] if attrs.has_key?(:weight) } }
|
76
|
+
end
|
77
|
+
return graph_size / 2
|
78
|
+
end
|
79
|
+
number_of_edges
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns number of edges
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
# graph.number_of_edges
|
86
|
+
def number_of_edges
|
87
|
+
@adj.values.flat_map(&:values).map(&:length).sum / 2
|
88
|
+
end
|
89
|
+
|
90
|
+
# Checks if the the edge consisting of two nodes is present in the graph
|
91
|
+
#
|
92
|
+
# @example
|
93
|
+
# graph.edge?(node1, node2)
|
94
|
+
#
|
95
|
+
# @param node1 [Object] the first node of the edge to be checked
|
96
|
+
# @param node2 [Object] the second node of the edge to be checked
|
97
|
+
# @param key [Integer] the key of the given edge
|
98
|
+
def edge?(node1, node2, key = nil)
|
99
|
+
return super(node1, node2) if key.nil?
|
100
|
+
|
101
|
+
node?(node1) && @adj[node1].has_key?(node2) && @adj[node1][node2].has_key?(key)
|
102
|
+
end
|
103
|
+
|
104
|
+
def has_edge?(node1, node2, key = nil)
|
105
|
+
return super(node1, node2) if key.nil?
|
106
|
+
|
107
|
+
return false unless node?(node1) && @adj[node1].has_key?(node2)
|
108
|
+
|
109
|
+
@adj[node1][node2].any? { |_index, data| data[:key] == key }
|
110
|
+
end
|
111
|
+
|
112
|
+
def each_edge(data: false)
|
113
|
+
return enum_for(:each_edge, data: data) unless block_given?
|
114
|
+
|
115
|
+
@adj.each do |v, ws|
|
116
|
+
ws.each do |w, key_and_info|
|
117
|
+
next if v > w
|
118
|
+
|
119
|
+
key_and_info.each do |key, info|
|
120
|
+
data ? yield(v, w, key, info) : yield(v, w, key)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns the undirected version of the graph
|
127
|
+
#
|
128
|
+
# @example
|
129
|
+
# graph.to_undirected
|
130
|
+
def to_undirected
|
131
|
+
graph = NetworkX::Graph.new(**@graph)
|
132
|
+
@nodes.each { |node, node_attr| graph.add_node(node, **node_attr) }
|
133
|
+
@adj.each do |node1, node1_edges|
|
134
|
+
node1_edges.each do |node2, node1_node2|
|
135
|
+
edge_attrs = {}
|
136
|
+
node1_node2.each { |_key, attrs| edge_attrs.merge!(attrs) }
|
137
|
+
graph.add_edge(node1, node2, **edge_attrs)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
graph
|
141
|
+
end
|
142
|
+
|
143
|
+
# Returns subgraph consisting of given array of nodes
|
144
|
+
#
|
145
|
+
# @example
|
146
|
+
# graph.subgraph(%w[Mumbai Nagpur])
|
147
|
+
#
|
148
|
+
# @param nodes [Array<Object>] the nodes to be included in the subgraph
|
149
|
+
def subgraph(nodes)
|
150
|
+
case nodes
|
151
|
+
when Array, Set
|
152
|
+
sub_graph = NetworkX::MultiGraph.new(**@graph)
|
153
|
+
nodes.each do |u, _|
|
154
|
+
raise KeyError, "#{u} does not exist in the current graph!" unless @nodes.has_key?(u)
|
155
|
+
|
156
|
+
sub_graph.add_node(u, **@nodes[u])
|
157
|
+
@adj[u].each do |v, edge_val|
|
158
|
+
next if u > v
|
159
|
+
|
160
|
+
edge_val.each { |_, keyval| sub_graph.add_edge(u, v, **keyval) if @adj[u].has_key?(v) && nodes.include?(v) }
|
161
|
+
end
|
162
|
+
end
|
163
|
+
sub_graph
|
164
|
+
else
|
165
|
+
raise ArgumentError, 'Expected Argument to be Array or Set of nodes, ' \
|
166
|
+
"received #{nodes.class.name} instead."
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns subgraph conisting of given edges
|
171
|
+
#
|
172
|
+
# @example
|
173
|
+
# graph.edge_subgraph([%w[Nagpur Wardha], %w[Nagpur Mumbai]])
|
174
|
+
#
|
175
|
+
# @param edges [Array<Object, Object>] the edges to be included in the subraph
|
176
|
+
def edge_subgraph(edges)
|
177
|
+
case edges
|
178
|
+
when Array, Set
|
179
|
+
sub_graph = NetworkX::MultiGraph.new(**@graph)
|
180
|
+
edges.each do |u, v|
|
181
|
+
raise KeyError, "Edge between #{u} and #{v} does not exist in the graph!" unless @nodes.has_key?(u) \
|
182
|
+
&& @adj[u].has_key?(v)
|
183
|
+
|
184
|
+
sub_graph.add_node(u, **@nodes[u])
|
185
|
+
sub_graph.add_node(v, **@nodes[v])
|
186
|
+
@adj[u][v].each { |_, keyval| sub_graph.add_edge(u, v, **keyval) }
|
187
|
+
end
|
188
|
+
sub_graph
|
189
|
+
else
|
190
|
+
raise ArgumentError, 'Expected Argument to be Array or Set of edges, ' \
|
191
|
+
"received #{edges.class.name} instead."
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def multigraph?
|
196
|
+
true
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module NetworkX
|
2
|
+
# Performs the union of many graphs
|
3
|
+
#
|
4
|
+
# @param graphs [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
5
|
+
#
|
6
|
+
# @return [Graph, DiGraph, MultiGraph, MultiDiGraph] union of all the graphs
|
7
|
+
def self.union_all(graphs)
|
8
|
+
raise ArgumentError, 'Argument array is empty' if graphs.empty?
|
9
|
+
|
10
|
+
result = graphs.shift
|
11
|
+
|
12
|
+
graphs.each do |graph|
|
13
|
+
result = NetworkX.union(result, graph)
|
14
|
+
end
|
15
|
+
result
|
16
|
+
end
|
17
|
+
|
18
|
+
# Performs the disjoint union of many graphs
|
19
|
+
#
|
20
|
+
# @param graphs [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
21
|
+
#
|
22
|
+
# @return [Graph, DiGraph, MultiGraph, MultiDiGraph] disjoint union of all the graphs
|
23
|
+
def self.disjoint_union_all(graphs)
|
24
|
+
raise ArgumentError, 'Argument array is empty' if graphs.empty?
|
25
|
+
|
26
|
+
result = graphs.shift
|
27
|
+
|
28
|
+
graphs.each do |graph|
|
29
|
+
result = NetworkX.disjoint_union(result, graph)
|
30
|
+
end
|
31
|
+
result
|
32
|
+
end
|
33
|
+
|
34
|
+
# Performs the intersection of many graphs
|
35
|
+
#
|
36
|
+
# @param graphs [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
37
|
+
#
|
38
|
+
# @return [Graph, DiGraph, MultiGraph, MultiDiGraph] intersection of all the graphs
|
39
|
+
def self.intersection_all(graphs)
|
40
|
+
raise ArgumentError, 'Argument array is empty' if graphs.empty?
|
41
|
+
|
42
|
+
result = graphs.shift
|
43
|
+
|
44
|
+
graphs.each do |graph|
|
45
|
+
result = NetworkX.intersection(result, graph)
|
46
|
+
end
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
# Performs the composition of many graphs
|
51
|
+
#
|
52
|
+
# @param graphs [Array<Graph>, Array<DiGraph>, Array<MultiGraph>, Array<MultiDiGraph>] Array of graphs
|
53
|
+
#
|
54
|
+
# @return [Graph, DiGraph, MultiGraph, MultiDiGraph] composition of all the graphs
|
55
|
+
def self.compose_all(graphs)
|
56
|
+
raise ArgumentError, 'Argument array is empty' if graphs.empty?
|
57
|
+
|
58
|
+
result = graphs.shift
|
59
|
+
|
60
|
+
graphs.each do |graph|
|
61
|
+
result = NetworkX.compose(result, graph)
|
62
|
+
end
|
63
|
+
result
|
64
|
+
end
|
65
|
+
end
|