Class: Rugraph
- Inherits:
-
Object
- Object
- Rugraph
- Defined in:
- lib/rugraph.rb
Overview
Rugraph class representing a Directed graph.
Class Method Summary collapse
-
.betweenness_centrality(graph) ⇒ Hash
Calculates the betweenness centrality for each node.
-
.closeness_centrality(graph) ⇒ Object
Calculate the closeness centrality for each node.
-
.degree_centrality(graph) ⇒ Object
Calculate the degree centrality for each node.
-
.load_centrality(graph) ⇒ Object
Calculate the load centrality for each node.
-
.new_from_edges_array(edges_array) ⇒ Rugraph
Creates graph from describing array.
-
.new_from_vertices_hash(vertices_hash) ⇒ Rugraph
Creates graph from describing hash.
Instance Method Summary collapse
-
#<<(node) ⇒ Rugraph
Equivalent to ##add_vertex.
-
#[](node) ⇒ Array?
Equivalent to #neighbors_of.
-
#[]=(node, node_array) ⇒ Object
Sets the edges coming out of a node.
-
#add_edge(edge) ⇒ Rugraph
Adds an edge to the graph.
-
#add_node(node) ⇒ Rugraph
Adds a vertex to the graph.
-
#add_vertex(node) ⇒ Rugraph
Adds a vertex to the graph.
-
#degree(node) ⇒ Integer
Computes the degree of a node.
-
#degrees ⇒ Enumerator
Computes the degree of each node.
-
#edges ⇒ Array
Returns the list of all the edges in the graph.
-
#edges_from(node) ⇒ Array
Returns the edges coming out of a node.
-
#edges_of(node) ⇒ Array
Returns the edges around a node.
-
#edges_to(node) ⇒ Array
Returns the edges coming from a node.
-
#in_degree(node) ⇒ Integer
Computes the incoming degree of a node.
-
#initialize ⇒ Rugraph
constructor
An empty graph.
-
#load_from_edges_array(edges_array) ⇒ Rugraph
Adds vertices and edges to the graph from an array [Array] formatted as such [[source_node, destination] [source_node2, destination2], …].
-
#load_from_vertices_hash(vertices_hash) ⇒ Rugraph
Adds vertices and edges to the graph from a hash [Hash] formatted as such { node1 => neighboring_nodes_array, node2 => … }.
-
#neighbors_of(node) ⇒ Array?
Method returning the neighbors of a node.
-
#nodes ⇒ Array
Returns the nodes in the graph.
-
#order ⇒ Integer
Computes the order (number of nodes) of the graph.
-
#out_degree(node) ⇒ Integer
Computes the outcoming degree of a node.
-
#shortest_path_lengths(source) ⇒ Hash
Computes the shortest path lengths from a node to all other accessible nodes.
-
#shortest_paths(source) ⇒ Array
Computes the shortest path a node.
-
#vertices ⇒ Array
Returns the nodes in the graph.
Constructor Details
#initialize ⇒ Rugraph
Returns an empty graph.
5 6 7 |
# File 'lib/rugraph.rb', line 5 def initialize @structure = {} end |
Class Method Details
.betweenness_centrality(graph) ⇒ Hash
Calculates the betweenness centrality for each node.
Based on Brandes algorithm : algo.uni-konstanz.de/publications/b-fabc-01.pdf
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/rugraph.rb', line 255 def self.betweenness_centrality(graph) cb = graph.vertices.map { |v| [v, 0] }.to_h graph.vertices.each do |source| stack = [] path = Hash.new { [] } sig = Hash.new(0) sig[source] = 1.0 distance = {} distance[source] = 0 queue = [] queue << source until queue.empty? v = queue.shift stack << v graph.neighbors_of(v).each do |w| unless distance.keys.include? w queue << w distance[w] = distance[v] + 1 end if distance[w] == distance[v] + 1 sig[w] += sig[v] path[w] += [v] end end end delta = Hash.new(0) until stack.empty? w = stack.pop coeff = (1.0 + delta[w]) / sig[w].to_f path[w].each do |n| delta[n] += sig[n] * coeff end cb[w] += delta[w] if w != source end end cb end |
.closeness_centrality(graph) ⇒ Object
Calculate the closeness centrality for each node.
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/rugraph.rb', line 301 def self.closeness_centrality(graph) closeness_centrality = {} graph.vertices.each do |n| shortest_paths = graph.shortest_path_lengths(n) sum = shortest_paths.values.reduce(&:+) closeness_centrality[n] = 0.0 next unless (sum > 0) && (graph.order > 1) closeness_centrality[n] = (shortest_paths.length - 1) / sum.to_f s = (shortest_paths.length - 1).to_f / (graph.order - 1) closeness_centrality[n] *= s end closeness_centrality end |
.degree_centrality(graph) ⇒ Object
Calculate the degree centrality for each node.
321 322 323 324 325 326 |
# File 'lib/rugraph.rb', line 321 def self.degree_centrality(graph) s = 1.0 / (graph.order - 1) graph.degrees .map { |n, d| [n, d * s] } .to_h end |
.load_centrality(graph) ⇒ Object
Calculate the load centrality for each node.
Based on NetworkX’s Python implementation.
334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/rugraph.rb', line 334 def self.load_centrality(graph) betweenness = graph.vertices .map { |n| [n, 0.0] } .to_h betweenness.each do |source, _| ubetween = _node_betweenness(graph, source) betweenness.merge(ubetween) do |key, v1, v2| betweenness[key] = v1 + v2 end end end |
.new_from_edges_array(edges_array) ⇒ Rugraph
Creates graph from describing array. See #load_from_edges_array
21 22 23 |
# File 'lib/rugraph.rb', line 21 def self.new_from_edges_array(edges_array) new.load_from_edges_array(edges_array) end |
.new_from_vertices_hash(vertices_hash) ⇒ Rugraph
Creates graph from describing hash. See #load_from_vertices_hash
13 14 15 |
# File 'lib/rugraph.rb', line 13 def self.new_from_vertices_hash(vertices_hash) new.load_from_vertices_hash(vertices_hash) end |
Instance Method Details
#<<(node) ⇒ Rugraph
Equivalent to ##add_vertex.
243 244 245 |
# File 'lib/rugraph.rb', line 243 def <<(node) add_vertex(node) end |
#[](node) ⇒ Array?
Equivalent to #neighbors_of
226 227 228 |
# File 'lib/rugraph.rb', line 226 def [](node) neighbors_of(node) end |
#[]=(node, node_array) ⇒ Object
Sets the edges coming out of a node.
235 236 237 |
# File 'lib/rugraph.rb', line 235 def []=(node, node_array) @structure[node] = node_array end |
#add_edge(edge) ⇒ Rugraph
Adds an edge to the graph. If the vertex already exists, do nothing.
68 69 70 71 |
# File 'lib/rugraph.rb', line 68 def add_edge(edge) edge.each { |node| add_vertex(node) } @structure[edge[0]] << edge[1] end |
#add_node(node) ⇒ Rugraph
Adds a vertex to the graph. If the vertex already exists, do nothing.
60 61 62 |
# File 'lib/rugraph.rb', line 60 def add_node(node) add_vertex(node) end |
#add_vertex(node) ⇒ Rugraph
Adds a vertex to the graph. If the vertex already exists, do nothing.
55 56 57 |
# File 'lib/rugraph.rb', line 55 def add_vertex(node) @structure[node] ||= [] end |
#degree(node) ⇒ Integer
Computes the degree of a node.
175 176 177 |
# File 'lib/rugraph.rb', line 175 def degree(node) in_degree(node) + out_degree(node) end |
#degrees ⇒ Enumerator
Computes the degree of each node.
163 164 165 166 167 168 169 |
# File 'lib/rugraph.rb', line 163 def degrees Enumerator.new(@structure.length) do |y| nodes.each do |node| y << [node, degree(node)] end end end |
#edges ⇒ Array
Returns the list of all the edges in the graph.
217 218 219 220 221 |
# File 'lib/rugraph.rb', line 217 def edges @structure.reduce([]) do |acc, node| acc + node[1].map { |dest| [node[0], dest] } end end |
#edges_from(node) ⇒ Array
Returns the edges coming out of a node.
148 149 150 |
# File 'lib/rugraph.rb', line 148 def edges_from(node) self[node].map { |n| [node, n] } end |
#edges_of(node) ⇒ Array
Returns the edges around a node.
140 141 142 |
# File 'lib/rugraph.rb', line 140 def edges_of(node) edges_from(node) | edges_to(node) end |
#edges_to(node) ⇒ Array
Returns the edges coming from a node.
156 157 158 |
# File 'lib/rugraph.rb', line 156 def edges_to(node) edges.select { |edge| edge.last == node } end |
#in_degree(node) ⇒ Integer
Computes the incoming degree of a node.
183 184 185 |
# File 'lib/rugraph.rb', line 183 def in_degree(node) self[node].length end |
#load_from_edges_array(edges_array) ⇒ Rugraph
Adds vertices and edges to the graph from an array [Array] formatted as such
[[source_node, destination] [source_node2, destination2], ...]
42 43 44 45 46 47 48 49 |
# File 'lib/rugraph.rb', line 42 def load_from_edges_array(edges_array) @structure = edges_array .each_with_object({}) do |edge, nodes| nodes[edge[0]] = [] unless nodes.keys.include? edge[0] nodes[edge[0]] << edge[1] end self end |
#load_from_vertices_hash(vertices_hash) ⇒ Rugraph
Adds vertices and edges to the graph from a hash [Hash] formatted as such
{ node1 => neighboring_nodes_array, node2 => ... }
31 32 33 34 |
# File 'lib/rugraph.rb', line 31 def load_from_vertices_hash(vertices_hash) @structure = vertices_hash self end |
#neighbors_of(node) ⇒ Array?
Method returning the neighbors of a node.
78 79 80 81 |
# File 'lib/rugraph.rb', line 78 def neighbors_of(node) return nil unless nodes.include?(node) @structure[node] || [] end |
#nodes ⇒ Array
Returns the nodes in the graph
210 211 212 |
# File 'lib/rugraph.rb', line 210 def nodes vertices end |
#order ⇒ Integer
Computes the order (number of nodes) of the graph.
198 199 200 |
# File 'lib/rugraph.rb', line 198 def order nodes.length end |
#out_degree(node) ⇒ Integer
Computes the outcoming degree of a node.
191 192 193 |
# File 'lib/rugraph.rb', line 191 def out_degree(node) @structure.count { |_source, dest| dest.include? node } end |
#shortest_path_lengths(source) ⇒ Hash
Computes the shortest path lengths from a node to all other accessible nodes.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/rugraph.rb', line 88 def shortest_path_lengths(source) seen = {} level = 0 nextlevel = { source => 1 } until nextlevel.empty? thislevel = nextlevel nextlevel = {} thislevel.each do |v, _| if seen[v].nil? seen[v] = level nextlevel.update(neighbors_of(v).map { |w| [w, nil] }.to_h) end end level += 1 end seen end |
#shortest_paths(source) ⇒ Array
Computes the shortest path a node.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/rugraph.rb', line 112 def shortest_paths(source) level = 0 nextlevel = [source] seen = { source => level } pred = { source => [] } until nextlevel.empty? level += 1 thislevel = nextlevel nextlevel = [] thislevel.each do |v| neighbors_of(v).each do |w| next if (seen.keys.include? w) && (seen[w] != level) unless seen.keys.include? w pred[w] = [] seen[w] = level nextlevel << w end pred[w] << v end end end [pred, seen] end |
#vertices ⇒ Array
Returns the nodes in the graph
205 206 207 |
# File 'lib/rugraph.rb', line 205 def vertices (@structure.keys | @structure.values).flatten.uniq end |