lib/rgraph/graph.rb in rgraph-0.0.9 vs lib/rgraph/graph.rb in rgraph-0.0.10
- old
+ new
@@ -4,28 +4,36 @@
require_relative '../../lib/rgraph/node'
class Graph
attr_accessor :nodes, :links, :infinity
+ def self.new_from_string(string)
+ csv = CSV.new(string, headers: true)
+ new(csv)
+ end
+
def initialize(csv)
@nodes = []
@links = []
@distance = nil
@infinity = 100_000
- raise Exception.new("the file must be a .csv") unless File.extname(csv) == ".csv"
- CSV.foreach(csv, headers: true) do |row|
+ csv = CSV.new(File.open(csv), headers: true) if csv.is_a?(String)
+
+ csv.each do |row|
#last because CSV#delete returns [column,value]
source_id = row.delete('source').last
target_id = row.delete('target').last
+ type = row.delete('type').last || 'undirected'
+ weight = row.delete('weight').last || 1
source = get_node_by_id(source_id) || Node.new(id: source_id)
target = get_node_by_id(target_id) || Node.new(id: target_id)
maybe_add_to_nodes(source, target)
- @links << Link.new(source: source, target: target, weight: row['weight'], year: row['year'])
+ @links << Link.new(source: source, target: target, weight: weight, type: type)
end
end
def each_node(&block)
@nodes.each(&block)
@@ -82,10 +90,17 @@
end
end
@distance
end
+ def mdistance
+ distances unless @distance
+
+ fdistance = @distance.flatten.select{|d| d != @infinity}
+ fdistance.inject(:+) / fdistance.count.to_f
+ end
+
def shortest_paths
tmp = []
distances unless @my_shortest_paths
@@ -125,11 +140,11 @@
n / m
end
def betweenness(args = {})
cumulative = args[:cumulative] || false
-
+
#If we ask cumulative, normalized must be true
normalized = args[:normalized] || cumulative || false
bts = 0.upto(@nodes.size - 1).map { |i| between(i) }
@@ -151,17 +166,64 @@
distances unless @distance
(distances.flatten - [@infinity]).max
end
+ def single_clustering(node)
+ possible = possible_connections(node)
+ return 0 if possible == 0
+
+ existent = node.neighbours.combination(2).select{ |t| t[0].neighbours.include?(t[1]) }.count
+ existent / possible.to_f
+ end
+
+ def clustering
+ nodes.map{ |node| single_clustering(node) }.inject(:+) / nodes.size.to_f
+ end
+
+ def page_rank(d = 0.85, e = 0.01)
+ n = @nodes.count
+
+ #Initial values
+ @page_rank = Array.new(n, 1 / n.to_f)
+
+ while true
+ return @page_rank if @page_rank.inject(:+) - step_page_rank(d, e).inject(:+) < e
+ end
+ end
+
private
+ def step_page_rank(d = 0.85, e = 0.01)
+ n = @nodes.count
+ tmp = Array.new(n, 0)
+
+ @nodes.each_with_index do |node,i|
+ #How much 'node' will give to its neighbours
+ to_neighbours = @page_rank[i] / node.neighbours.count
+
+ #Give 'to_neighbours' to each neighbour
+ node.neighbours.each do |ne|
+ j = @nodes.index(ne)
+ tmp[j] += to_neighbours
+ end
+ end
+
+ #Calculates the final value
+ @page_rank = tmp.map{|t| ((1 - d) / n) + t * d}
+ end
+
def get_node_by_id(node_id)
@nodes.select{|n| n.id == node_id}.first
end
def maybe_add_to_nodes(*nodes)
nodes.each do |node|
@nodes << node unless get_node_by_id(node.id)
end
+ end
+
+ def possible_connections(node)
+ total = node.neighbours.count
+ total * (total - 1) / 2
end
end