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