Mercurial > repos > petrn > repeatexplorer
comparison louvain/community.cpp @ 0:f6ebec6e235e draft
Uploaded
| author | petrn |
|---|---|
| date | Thu, 19 Dec 2019 13:46:43 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:f6ebec6e235e |
|---|---|
| 1 // File: community.h | |
| 2 // -- community detection source file | |
| 3 //----------------------------------------------------------------------------- | |
| 4 // Community detection | |
| 5 // Based on the article "Fast unfolding of community hierarchies in large networks" | |
| 6 // Copyright (C) 2008 V. Blondel, J.-L. Guillaume, R. Lambiotte, E. Lefebvre | |
| 7 // | |
| 8 // This program must not be distributed without agreement of the above mentionned authors. | |
| 9 //----------------------------------------------------------------------------- | |
| 10 // Author : E. Lefebvre, adapted by J.-L. Guillaume | |
| 11 // Email : jean-loup.guillaume@lip6.fr | |
| 12 // Location : Paris, France | |
| 13 // Time : February 2008 | |
| 14 //----------------------------------------------------------------------------- | |
| 15 // see readme.txt for more details | |
| 16 | |
| 17 #include "community.h" | |
| 18 | |
| 19 using namespace std; | |
| 20 | |
| 21 Community::Community(char * filename, char * filename_w, int type, int nbp, double minm) { | |
| 22 g = Graph(filename, filename_w, type); | |
| 23 size = g.nb_nodes; | |
| 24 | |
| 25 neigh_weight.resize(size,-1); | |
| 26 neigh_pos.resize(size); | |
| 27 neigh_last=0; | |
| 28 | |
| 29 n2c.resize(size); | |
| 30 in.resize(size); | |
| 31 tot.resize(size); | |
| 32 | |
| 33 for (int i=0 ; i<size ; i++) { | |
| 34 n2c[i] = i; | |
| 35 tot[i] = g.weighted_degree(i); | |
| 36 in[i] = g.nb_selfloops(i); | |
| 37 } | |
| 38 | |
| 39 nb_pass = nbp; | |
| 40 min_modularity = minm; | |
| 41 } | |
| 42 | |
| 43 Community::Community(Graph gc, int nbp, double minm) { | |
| 44 g = gc; | |
| 45 size = g.nb_nodes; | |
| 46 | |
| 47 neigh_weight.resize(size,-1); | |
| 48 neigh_pos.resize(size); | |
| 49 neigh_last=0; | |
| 50 | |
| 51 n2c.resize(size); | |
| 52 in.resize(size); | |
| 53 tot.resize(size); | |
| 54 | |
| 55 for (int i=0 ; i<size ; i++) { | |
| 56 n2c[i] = i; | |
| 57 in[i] = g.nb_selfloops(i); | |
| 58 tot[i] = g.weighted_degree(i); | |
| 59 } | |
| 60 | |
| 61 nb_pass = nbp; | |
| 62 min_modularity = minm; | |
| 63 } | |
| 64 | |
| 65 void | |
| 66 Community::init_partition(char * filename) { | |
| 67 ifstream finput; | |
| 68 finput.open(filename,fstream::in); | |
| 69 | |
| 70 // read partition | |
| 71 while (!finput.eof()) { | |
| 72 unsigned int node, comm; | |
| 73 finput >> node >> comm; | |
| 74 | |
| 75 if (finput) { | |
| 76 int old_comm = n2c[node]; | |
| 77 neigh_comm(node); | |
| 78 | |
| 79 remove(node, old_comm, neigh_weight[old_comm]); | |
| 80 | |
| 81 unsigned int i=0; | |
| 82 for ( i=0 ; i<neigh_last ; i++) { | |
| 83 unsigned int best_comm = neigh_pos[i]; | |
| 84 float best_nblinks = neigh_weight[neigh_pos[i]]; | |
| 85 if (best_comm==comm) { | |
| 86 insert(node, best_comm, best_nblinks); | |
| 87 break; | |
| 88 } | |
| 89 } | |
| 90 if (i==neigh_last) | |
| 91 insert(node, comm, 0); | |
| 92 } | |
| 93 } | |
| 94 finput.close(); | |
| 95 } | |
| 96 | |
| 97 // inline void | |
| 98 // Community::remove(int node, int comm, double dnodecomm) { | |
| 99 // assert(node>=0 && node<size); | |
| 100 | |
| 101 // tot[comm] -= g.weighted_degree(node); | |
| 102 // in[comm] -= 2*dnodecomm + g.nb_selfloops(node); | |
| 103 // n2c[node] = -1; | |
| 104 // } | |
| 105 | |
| 106 // inline void | |
| 107 // Community::insert(int node, int comm, double dnodecomm) { | |
| 108 // assert(node>=0 && node<size); | |
| 109 | |
| 110 // tot[comm] += g.weighted_degree(node); | |
| 111 // in[comm] += 2*dnodecomm + g.nb_selfloops(node); | |
| 112 // n2c[node]=comm; | |
| 113 // } | |
| 114 | |
| 115 void | |
| 116 Community::display() { | |
| 117 for (int i=0 ; i<size ; i++) | |
| 118 cerr << " " << i << "/" << n2c[i] << "/" << in[i] << "/" << tot[i] ; | |
| 119 cerr << endl; | |
| 120 } | |
| 121 | |
| 122 | |
| 123 double | |
| 124 Community::modularity() { | |
| 125 double q = 0.; | |
| 126 double m2 = (double)g.total_weight; | |
| 127 | |
| 128 for (int i=0 ; i<size ; i++) { | |
| 129 if (tot[i]>0) | |
| 130 q += (double)in[i]/m2 - ((double)tot[i]/m2)*((double)tot[i]/m2); | |
| 131 } | |
| 132 | |
| 133 return q; | |
| 134 } | |
| 135 | |
| 136 void | |
| 137 Community::neigh_comm(unsigned int node) { | |
| 138 for (unsigned int i=0 ; i<neigh_last ; i++) | |
| 139 neigh_weight[neigh_pos[i]]=-1; | |
| 140 neigh_last=0; | |
| 141 | |
| 142 pair<vector<unsigned int>::iterator, vector<float>::iterator> p = g.neighbors(node); | |
| 143 | |
| 144 unsigned int deg = g.nb_neighbors(node); | |
| 145 | |
| 146 neigh_pos[0]=n2c[node]; | |
| 147 neigh_weight[neigh_pos[0]]=0; | |
| 148 neigh_last=1; | |
| 149 | |
| 150 for (unsigned int i=0 ; i<deg ; i++) { | |
| 151 unsigned int neigh = *(p.first+i); | |
| 152 unsigned int neigh_comm = n2c[neigh]; | |
| 153 double neigh_w = (g.weights.size()==0)?1.:*(p.second+i); | |
| 154 | |
| 155 if (neigh!=node) { | |
| 156 if (neigh_weight[neigh_comm]==-1) { | |
| 157 neigh_weight[neigh_comm]=0.; | |
| 158 neigh_pos[neigh_last++]=neigh_comm; | |
| 159 } | |
| 160 neigh_weight[neigh_comm]+=neigh_w; | |
| 161 } | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 void | |
| 166 Community::partition2graph() { | |
| 167 vector<int> renumber(size, -1); | |
| 168 for (int node=0 ; node<size ; node++) { | |
| 169 renumber[n2c[node]]++; | |
| 170 } | |
| 171 | |
| 172 int final=0; | |
| 173 for (int i=0 ; i<size ; i++) | |
| 174 if (renumber[i]!=-1) | |
| 175 renumber[i]=final++; | |
| 176 | |
| 177 | |
| 178 for (int i=0 ; i<size ; i++) { | |
| 179 pair<vector<unsigned int>::iterator, vector<float>::iterator> p = g.neighbors(i); | |
| 180 | |
| 181 int deg = g.nb_neighbors(i); | |
| 182 for (int j=0 ; j<deg ; j++) { | |
| 183 int neigh = *(p.first+j); | |
| 184 cout << renumber[n2c[i]] << " " << renumber[n2c[neigh]] << endl; | |
| 185 } | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 void | |
| 190 Community::display_partition() { | |
| 191 vector<int> renumber(size, -1); | |
| 192 for (int node=0 ; node<size ; node++) { | |
| 193 renumber[n2c[node]]++; | |
| 194 } | |
| 195 | |
| 196 int final=0; | |
| 197 for (int i=0 ; i<size ; i++) | |
| 198 if (renumber[i]!=-1) | |
| 199 renumber[i]=final++; | |
| 200 | |
| 201 for (int i=0 ; i<size ; i++) | |
| 202 cout << i << " " << renumber[n2c[i]] << endl; | |
| 203 } | |
| 204 | |
| 205 | |
| 206 Graph | |
| 207 Community::partition2graph_binary() { | |
| 208 // Renumber communities | |
| 209 vector<int> renumber(size, -1); | |
| 210 for (int node=0 ; node<size ; node++) { | |
| 211 renumber[n2c[node]]++; | |
| 212 } | |
| 213 | |
| 214 int final=0; | |
| 215 for (int i=0 ; i<size ; i++) | |
| 216 if (renumber[i]!=-1) | |
| 217 renumber[i]=final++; | |
| 218 | |
| 219 // Compute communities | |
| 220 vector<vector<int> > comm_nodes(final); | |
| 221 for (int node=0 ; node<size ; node++) { | |
| 222 comm_nodes[renumber[n2c[node]]].push_back(node); | |
| 223 } | |
| 224 | |
| 225 // Compute weighted graph | |
| 226 Graph g2; | |
| 227 g2.nb_nodes = comm_nodes.size(); | |
| 228 g2.degrees.resize(comm_nodes.size()); | |
| 229 | |
| 230 int comm_deg = comm_nodes.size(); | |
| 231 for (int comm=0 ; comm<comm_deg ; comm++) { | |
| 232 map<int,float> m; | |
| 233 map<int,float>::iterator it; | |
| 234 | |
| 235 int comm_size = comm_nodes[comm].size(); | |
| 236 for (int node=0 ; node<comm_size ; node++) { | |
| 237 pair<vector<unsigned int>::iterator, vector<float>::iterator> p = g.neighbors(comm_nodes[comm][node]); | |
| 238 int deg = g.nb_neighbors(comm_nodes[comm][node]); | |
| 239 for (int i=0 ; i<deg ; i++) { | |
| 240 int neigh = *(p.first+i); | |
| 241 int neigh_comm = renumber[n2c[neigh]]; | |
| 242 double neigh_weight = (g.weights.size()==0)?1.:*(p.second+i); | |
| 243 | |
| 244 it = m.find(neigh_comm); | |
| 245 if (it==m.end()) | |
| 246 m.insert(make_pair(neigh_comm, neigh_weight)); | |
| 247 else | |
| 248 it->second+=neigh_weight; | |
| 249 } | |
| 250 } | |
| 251 g2.degrees[comm]=(comm==0)?m.size():g2.degrees[comm-1]+m.size(); | |
| 252 g2.nb_links+=m.size(); | |
| 253 | |
| 254 | |
| 255 for (it = m.begin() ; it!=m.end() ; it++) { | |
| 256 g2.total_weight += it->second; | |
| 257 g2.links.push_back(it->first); | |
| 258 g2.weights.push_back(it->second); | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 return g2; | |
| 263 } | |
| 264 | |
| 265 | |
| 266 bool | |
| 267 Community::one_level() { | |
| 268 bool improvement=false ; | |
| 269 int nb_moves; | |
| 270 int nb_pass_done = 0; | |
| 271 double new_mod = modularity(); | |
| 272 double cur_mod = new_mod; | |
| 273 | |
| 274 vector<int> random_order(size); | |
| 275 for (int i=0 ; i<size ; i++) | |
| 276 random_order[i]=i; | |
| 277 for (int i=0 ; i<size-1 ; i++) { | |
| 278 int rand_pos = rand()%(size-i)+i; | |
| 279 int tmp = random_order[i]; | |
| 280 random_order[i] = random_order[rand_pos]; | |
| 281 random_order[rand_pos] = tmp; | |
| 282 } | |
| 283 | |
| 284 // repeat while | |
| 285 // there is an improvement of modularity | |
| 286 // or there is an improvement of modularity greater than a given epsilon | |
| 287 // or a predefined number of pass have been done | |
| 288 do { | |
| 289 cur_mod = new_mod; | |
| 290 nb_moves = 0; | |
| 291 nb_pass_done++; | |
| 292 | |
| 293 // for each node: remove the node from its community and insert it in the best community | |
| 294 for (int node_tmp=0 ; node_tmp<size ; node_tmp++) { | |
| 295 // int node = node_tmp; | |
| 296 int node = random_order[node_tmp]; | |
| 297 int node_comm = n2c[node]; | |
| 298 double w_degree = g.weighted_degree(node); | |
| 299 | |
| 300 // computation of all neighboring communities of current node | |
| 301 neigh_comm(node); | |
| 302 // remove node from its current community | |
| 303 remove(node, node_comm, neigh_weight[node_comm]); | |
| 304 | |
| 305 // compute the nearest community for node | |
| 306 // default choice for future insertion is the former community | |
| 307 int best_comm = node_comm; | |
| 308 double best_nblinks = 0.; | |
| 309 double best_increase = 0.; | |
| 310 for (unsigned int i=0 ; i<neigh_last ; i++) { | |
| 311 double increase = modularity_gain(node, neigh_pos[i], neigh_weight[neigh_pos[i]], w_degree); | |
| 312 if (increase>best_increase) { | |
| 313 best_comm = neigh_pos[i]; | |
| 314 best_nblinks = neigh_weight[neigh_pos[i]]; | |
| 315 best_increase = increase; | |
| 316 } | |
| 317 } | |
| 318 | |
| 319 // insert node in the nearest community | |
| 320 insert(node, best_comm, best_nblinks); | |
| 321 | |
| 322 if (best_comm!=node_comm) | |
| 323 nb_moves++; | |
| 324 } | |
| 325 | |
| 326 double total_tot=0; | |
| 327 double total_in=0; | |
| 328 for (unsigned int i=0 ; i<tot.size() ;i++) { | |
| 329 total_tot+=tot[i]; | |
| 330 total_in+=in[i]; | |
| 331 } | |
| 332 | |
| 333 new_mod = modularity(); | |
| 334 if (nb_moves>0) | |
| 335 improvement=true; | |
| 336 | |
| 337 } while (nb_moves>0 && new_mod-cur_mod>min_modularity); | |
| 338 | |
| 339 return improvement; | |
| 340 } | |
| 341 |
