louvian_ruby 0.0.5 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/louvian.rb +61 -52
- metadata +1 -1
data/lib/louvian.rb
CHANGED
@@ -1,92 +1,97 @@
|
|
1
|
-
|
1
|
+
class Louvian
|
2
2
|
require 'louvian/community'
|
3
3
|
require 'louvian/graph'
|
4
4
|
|
5
5
|
MIN_INCREASE = 0.000001
|
6
6
|
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
# This method sets up the whole environemnt for calculations
|
9
|
+
#
|
10
|
+
# @param string [String] in the form of src dest (one edge per line)
|
11
|
+
#
|
12
|
+
def initialize tuples, directed
|
13
|
+
#list = string.split("\n").map {|line| line.split.map{|n| n.to_i}}
|
14
|
+
@graph = Graph.new tuples, directed, 0
|
15
|
+
@levels = [] # List of Graphs
|
10
16
|
end
|
11
17
|
|
12
|
-
def
|
13
|
-
|
18
|
+
def graph
|
19
|
+
@graph
|
14
20
|
end
|
15
21
|
|
16
|
-
def
|
17
|
-
|
22
|
+
def graph= value
|
23
|
+
@graph = value
|
18
24
|
end
|
19
25
|
|
20
|
-
def
|
21
|
-
|
26
|
+
def levels
|
27
|
+
@levels
|
22
28
|
end
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def self.init_env string, directed
|
27
|
-
list = string.split("\n").map {|line| line.split.map{|n| n.to_i}}
|
28
|
-
@@graph = Graph.new list, directed, 0
|
29
|
-
@@levels = [] # List of Graphs
|
30
|
-
nil
|
29
|
+
|
30
|
+
def levels= value
|
31
|
+
@levels = value
|
31
32
|
end
|
32
33
|
|
33
|
-
def
|
34
|
+
def run
|
34
35
|
l = 0
|
35
|
-
|
36
|
-
puts "Level #{l}: Comms #{@@graph.communities.size}"
|
36
|
+
puts "Level #{l}: Comms #{@graph.communities.size}"
|
37
37
|
l +=1
|
38
38
|
|
39
39
|
while self.one_level
|
40
|
-
puts "Level #{l}: Comms #{
|
41
|
-
|
42
|
-
|
40
|
+
puts "Level #{l}: Comms #{@graph.communities.size}"
|
41
|
+
@levels << @graph
|
42
|
+
@graph = @graph.build_graph_from_comms
|
43
|
+
|
43
44
|
l+=1
|
44
45
|
end
|
46
|
+
self
|
45
47
|
end
|
46
48
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
49
|
+
def unfold_levels!
|
50
|
+
return false if @levels.size < 2
|
51
|
+
puts "levels count #{@levels.size}"
|
52
|
+
@levels[(1..-1)].each_with_index do |graph, i|
|
53
|
+
graph.expand! @levels[i]
|
50
54
|
end
|
55
|
+
true
|
51
56
|
end
|
52
57
|
|
53
|
-
def
|
54
|
-
|
58
|
+
def display_hierarchy
|
59
|
+
@levels.each do |graph|
|
55
60
|
puts "level #{graph.level}: Nodes #{graph.communities.count}"
|
56
61
|
end
|
57
|
-
|
62
|
+
nil
|
58
63
|
end
|
59
64
|
|
60
65
|
# This method iterates over the graph to optimze the modularity. Iterations
|
61
66
|
# stops when there are no possible moves anymore.
|
62
67
|
# @returns improvement [Boolean] indicates whether there was improvment or no
|
63
|
-
def
|
68
|
+
def one_level
|
64
69
|
improvement = false
|
65
70
|
nb_passes = 0
|
66
|
-
cur_mod =
|
71
|
+
cur_mod = @graph.modularity
|
67
72
|
new_mod = cur_mod
|
68
73
|
begin
|
69
74
|
#puts "Iterating"
|
70
|
-
#puts "modularity is #{
|
75
|
+
#puts "modularity is #{@graph.modularity}"
|
71
76
|
cur_mod = new_mod
|
72
77
|
nb_moves = 0
|
73
78
|
nb_passes += 1
|
74
|
-
|
75
|
-
#puts "\t#{
|
79
|
+
@graph.nodes.shuffle.each do |node|
|
80
|
+
#puts "\t#{@graph.n2c}"
|
76
81
|
#puts "\tconsidering node #{node}"
|
77
|
-
orig_community =
|
82
|
+
orig_community = @graph.get_community node
|
78
83
|
|
79
|
-
neighbour_communities =
|
84
|
+
neighbour_communities = @graph.get_neighbour_comms node
|
80
85
|
|
81
86
|
#puts "\tneihbours#{neighbour_communities.map {|i| i.id}} origin #{orig_community.id}"
|
82
|
-
|
87
|
+
@graph.remove_node node, orig_community
|
83
88
|
|
84
89
|
|
85
90
|
best_community = orig_community
|
86
91
|
max_gain = 0.0
|
87
92
|
|
88
93
|
neighbour_communities.each do |comm|
|
89
|
-
mod_gain =
|
94
|
+
mod_gain = @graph.modularity_gain node, comm
|
90
95
|
#puts "\t\tfor comm #{comm.id} mod increase is #{mod_gain}"
|
91
96
|
if mod_gain > max_gain
|
92
97
|
max_gain = mod_gain
|
@@ -99,20 +104,19 @@ module Louvian
|
|
99
104
|
#puts "\t\tbest comm #{best_community.id}"
|
100
105
|
end
|
101
106
|
|
102
|
-
|
107
|
+
@graph.insert_node node, best_community
|
103
108
|
|
104
|
-
|
109
|
+
@graph.garbage_collect orig_community
|
105
110
|
|
106
111
|
end
|
107
|
-
new_mod =
|
112
|
+
new_mod = @graph.modularity
|
108
113
|
#puts "modularity was #{cur_mod} and now #{new_mod}, moves #{nb_moves}"
|
109
114
|
end while nb_moves > 0 and new_mod - cur_mod >= MIN_INCREASE
|
110
115
|
return improvement
|
111
116
|
end
|
112
117
|
|
113
|
-
|
114
|
-
|
115
|
-
s='0 1 1
|
118
|
+
def self.example s=nil
|
119
|
+
s ||='0 1 1
|
116
120
|
0 8 1
|
117
121
|
1 3 1
|
118
122
|
1 4 1
|
@@ -124,14 +128,19 @@ module Louvian
|
|
124
128
|
4 7 1
|
125
129
|
5 6 1
|
126
130
|
5 7 1'
|
131
|
+
list = self.make_list_from_string s
|
132
|
+
|
133
|
+
l = Louvian.new(list, false)
|
134
|
+
#l.one_level
|
135
|
+
#ng = l.graph.build_graph_from_comms
|
136
|
+
#l.levels << l.graph
|
137
|
+
#l.graph = ng
|
138
|
+
l.run
|
139
|
+
return l
|
140
|
+
end
|
127
141
|
|
128
|
-
|
129
|
-
|
130
|
-
ng = Louvian.graph.build_graph_from_comms
|
131
|
-
Louvian.levels << Louvian.graph
|
132
|
-
Louvian.graph = ng
|
133
|
-
#L = Louvian
|
134
|
-
#Louvian.run
|
135
|
-
nil
|
142
|
+
def self.make_list_from_string s
|
143
|
+
list = (s.split("\n").map {|line| line.split.map{|n| n.to_i}})
|
136
144
|
end
|
145
|
+
|
137
146
|
end
|