louvian_ruby 0.0.3 → 0.0.4
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.
- data/lib/louvian/graph.rb +159 -0
- data/lib/louvian.rb +1 -1
- metadata +2 -1
@@ -0,0 +1,159 @@
|
|
1
|
+
class Louvian::Graph
|
2
|
+
|
3
|
+
attr_accessor :adj_list, :nodes, :communities, :directed, :n2c, :total_weight
|
4
|
+
def initialize edges_list, directed, level
|
5
|
+
# Adjacency list
|
6
|
+
@adj_list = Louvian::Graph.make_adj edges_list, directed
|
7
|
+
|
8
|
+
# List of all nodes
|
9
|
+
# TODO remove sort
|
10
|
+
@nodes = @adj_list.keys.sort
|
11
|
+
|
12
|
+
# List of all communities (meta_nodes)
|
13
|
+
@communities = []
|
14
|
+
|
15
|
+
# whether the graph is diercted or not
|
16
|
+
@directed = false
|
17
|
+
|
18
|
+
# node_id => community_id
|
19
|
+
@n2c = {}
|
20
|
+
|
21
|
+
@level = level
|
22
|
+
# TODO remove sort
|
23
|
+
@adj_list.sort.each do |k, v|
|
24
|
+
@communities << Louvian::Community.new({k => v}, @level)
|
25
|
+
@n2c[k] = @communities.last.id
|
26
|
+
end
|
27
|
+
|
28
|
+
# Sum of all links half edges (double the number of edges)
|
29
|
+
@total_weight = @adj_list.inject(0) {|r,(k,v)| r+v.count}
|
30
|
+
end
|
31
|
+
|
32
|
+
# This method builds the adjacency list from list of edges
|
33
|
+
# @param list [Array] in the form of [src dest] (edge per cell)
|
34
|
+
# @param directed, whether the edge list is directed or not
|
35
|
+
def self.make_adj edges_list, directed
|
36
|
+
adj = {}
|
37
|
+
edges_list.each do |edge|
|
38
|
+
adj[edge[0]] ||= []
|
39
|
+
adj[edge[1]] ||= []
|
40
|
+
|
41
|
+
adj[edge[0]] << edge[1]
|
42
|
+
if not directed
|
43
|
+
adj[edge[1]] << edge[0]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
adj
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_neighbour_nodes node
|
50
|
+
neighbours = adj_list[node]
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_neighbour_comms node
|
54
|
+
node_to_comms_links = get_node_to_comms_links node
|
55
|
+
|
56
|
+
neighbour_communities = @communities.find_all {|comm| node_to_comms_links.include? comm.id}
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_community node
|
60
|
+
@communities.find {|comm| comm.id == @n2c[node]}
|
61
|
+
end
|
62
|
+
|
63
|
+
# This method gets all neighbour communities and the number of links from node
|
64
|
+
# to all neighbou communities
|
65
|
+
# @param node to be considered
|
66
|
+
# @return node_to_comms_links [Hash] {community => number_of_links from node
|
67
|
+
# to community}
|
68
|
+
def get_node_to_comms_links node
|
69
|
+
neighbour_nodes = get_neighbour_nodes node
|
70
|
+
node_to_comms_links = {}
|
71
|
+
neighbour_nodes.each do |n|
|
72
|
+
node_to_comms_links[@n2c[n]] = (node_to_comms_links[@n2c[n]] || 0) + 1
|
73
|
+
end
|
74
|
+
node_to_comms_links[@n2c[node]] ||= 0
|
75
|
+
return node_to_comms_links
|
76
|
+
end
|
77
|
+
|
78
|
+
# OPTIMIZE
|
79
|
+
def get_number_of_links from_node, to_comm
|
80
|
+
get_node_to_comms_links(from_node)[to_comm.id]
|
81
|
+
end
|
82
|
+
|
83
|
+
# This method calcualtes the current modularity of the communities
|
84
|
+
# @returns q [Float] which is the modularity
|
85
|
+
def modularity
|
86
|
+
q = 0.0
|
87
|
+
m2 = @total_weight
|
88
|
+
|
89
|
+
@communities.each do |m_node|
|
90
|
+
q += m_node.in.to_f/m2 - (m_node.tot.to_f/m2 * m_node.tot.to_f/m2)
|
91
|
+
end
|
92
|
+
q
|
93
|
+
end
|
94
|
+
|
95
|
+
# This method calcualtes the modularity gain for moving +node+ to community
|
96
|
+
# @param node this is the node to be moved
|
97
|
+
# @param community this is the destination community
|
98
|
+
# @param nb_links_to_comm is the number of links from +node+ to community
|
99
|
+
# @returns delta_q (the gain of modularity)
|
100
|
+
def modularity_gain node, community
|
101
|
+
nb_links_to_comm = get_number_of_links node, community
|
102
|
+
tot = community.tot
|
103
|
+
deg = @adj_list[node].count
|
104
|
+
m2 = @total_weight
|
105
|
+
|
106
|
+
#puts "\t\t\tcomm #{community.id} #{[tot, deg, m2, nb_links_to_comm]}"
|
107
|
+
# what makes sense
|
108
|
+
#return (nb_links_to_comm.to_f/m2) - (tot * deg.to_f/m2**2/2)
|
109
|
+
|
110
|
+
# copied from the cpp code
|
111
|
+
return nb_links_to_comm.to_f - tot*deg.to_f/m2
|
112
|
+
end
|
113
|
+
|
114
|
+
# This method outputs information about communities
|
115
|
+
def display_communities
|
116
|
+
@communities.each do |m|
|
117
|
+
puts "#{m.id} => #{m.nodes_ids} in=#{m.in} tot=#{m.tot}"
|
118
|
+
end
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
|
122
|
+
def insert_node node, comm
|
123
|
+
comm.insert node, @adj_list[node]
|
124
|
+
@n2c[node] = comm.id
|
125
|
+
end
|
126
|
+
|
127
|
+
def remove_node node, comm
|
128
|
+
comm.remove node, @adj_list[node]
|
129
|
+
@n2c[node] = -1
|
130
|
+
end
|
131
|
+
|
132
|
+
def garbage_collect community
|
133
|
+
if community.nodes_ids.empty?
|
134
|
+
@communities.delete community
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def build_graph_from_comms
|
139
|
+
|
140
|
+
comm_edges = []
|
141
|
+
|
142
|
+
count = @communities.count
|
143
|
+
if not directed # iterate only on one half of communities
|
144
|
+
count % 2 == 0 ? count : count + 1
|
145
|
+
count /=2
|
146
|
+
end
|
147
|
+
|
148
|
+
@communities[0,count].each do |comm|
|
149
|
+
comm.nodes_ids.each do |node|
|
150
|
+
@adj_list[node].each do |linked_node|
|
151
|
+
if not comm.nodes_ids.include? linked_node
|
152
|
+
comm_edges << [comm.id, @n2c[linked_node]]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
return Louvian::Graph.new comm_edges, directed, @level+1
|
158
|
+
end
|
159
|
+
end
|
data/lib/louvian.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: louvian_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -19,6 +19,7 @@ extra_rdoc_files: []
|
|
19
19
|
files:
|
20
20
|
- lib/louvian.rb
|
21
21
|
- lib/louvian/community.rb
|
22
|
+
- lib/louvian/graph.rb
|
22
23
|
homepage: http://rubygems.org/gems/louvian_ruby
|
23
24
|
licenses: []
|
24
25
|
post_install_message:
|