diff louvain/community.cpp @ 0:1d1b9e1b2e2f draft

Uploaded
author petr-novak
date Thu, 19 Dec 2019 10:24:45 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/louvain/community.cpp	Thu Dec 19 10:24:45 2019 -0500
@@ -0,0 +1,341 @@
+// File: community.h
+// -- community detection source file
+//-----------------------------------------------------------------------------
+// Community detection
+// Based on the article "Fast unfolding of community hierarchies in large networks"
+// Copyright (C) 2008 V. Blondel, J.-L. Guillaume, R. Lambiotte, E. Lefebvre
+//
+// This program must not be distributed without agreement of the above mentionned authors.
+//-----------------------------------------------------------------------------
+// Author   : E. Lefebvre, adapted by J.-L. Guillaume
+// Email    : jean-loup.guillaume@lip6.fr
+// Location : Paris, France
+// Time	    : February 2008
+//-----------------------------------------------------------------------------
+// see readme.txt for more details
+
+#include "community.h"
+
+using namespace std;
+
+Community::Community(char * filename, char * filename_w, int type, int nbp, double minm) {
+  g = Graph(filename, filename_w, type);
+  size = g.nb_nodes;
+
+  neigh_weight.resize(size,-1);
+  neigh_pos.resize(size);
+  neigh_last=0;
+
+  n2c.resize(size);
+  in.resize(size);
+  tot.resize(size);
+
+  for (int i=0 ; i<size ; i++) {
+    n2c[i] = i;
+    tot[i] = g.weighted_degree(i);
+    in[i]  = g.nb_selfloops(i);
+  }
+
+  nb_pass = nbp;
+  min_modularity = minm;
+}
+
+Community::Community(Graph gc, int nbp, double minm) {
+  g = gc;
+  size = g.nb_nodes;
+
+  neigh_weight.resize(size,-1);
+  neigh_pos.resize(size);
+  neigh_last=0;
+
+  n2c.resize(size);
+  in.resize(size);
+  tot.resize(size);
+
+  for (int i=0 ; i<size ; i++) {
+    n2c[i] = i;
+    in[i]  = g.nb_selfloops(i);
+    tot[i] = g.weighted_degree(i);
+  }
+
+  nb_pass = nbp;
+  min_modularity = minm;
+}
+
+void
+Community::init_partition(char * filename) {
+  ifstream finput;
+  finput.open(filename,fstream::in);
+
+  // read partition
+  while (!finput.eof()) {
+    unsigned int node, comm;
+    finput >> node >> comm;
+    
+    if (finput) {
+      int old_comm = n2c[node];
+      neigh_comm(node);
+
+      remove(node, old_comm, neigh_weight[old_comm]);
+
+      unsigned int i=0;
+      for ( i=0 ; i<neigh_last ; i++) {
+	unsigned int best_comm     = neigh_pos[i];
+	float best_nblinks  = neigh_weight[neigh_pos[i]];
+	if (best_comm==comm) {
+	  insert(node, best_comm, best_nblinks);
+	  break;
+	}
+      }
+      if (i==neigh_last)
+	insert(node, comm, 0);
+    }
+  }
+  finput.close();
+}
+
+// inline void
+// Community::remove(int node, int comm, double dnodecomm) {
+//   assert(node>=0 && node<size);
+
+//   tot[comm] -= g.weighted_degree(node);
+//   in[comm]  -= 2*dnodecomm + g.nb_selfloops(node);
+//   n2c[node]  = -1;
+// }
+
+// inline void
+// Community::insert(int node, int comm, double dnodecomm) {
+//   assert(node>=0 && node<size);
+
+//   tot[comm] += g.weighted_degree(node);
+//   in[comm]  += 2*dnodecomm + g.nb_selfloops(node);
+//   n2c[node]=comm;
+// }
+
+void
+Community::display() {
+  for (int i=0 ; i<size ; i++)
+    cerr << " " << i << "/" << n2c[i] << "/" << in[i] << "/" << tot[i] ;
+  cerr << endl;
+}
+
+
+double
+Community::modularity() {
+  double q  = 0.;
+  double m2 = (double)g.total_weight;
+
+  for (int i=0 ; i<size ; i++) {
+    if (tot[i]>0)
+      q += (double)in[i]/m2 - ((double)tot[i]/m2)*((double)tot[i]/m2);
+  }
+
+  return q;
+}
+
+void
+Community::neigh_comm(unsigned int node) {
+  for (unsigned int i=0 ; i<neigh_last ; i++)
+    neigh_weight[neigh_pos[i]]=-1;
+  neigh_last=0;
+
+  pair<vector<unsigned int>::iterator, vector<float>::iterator> p = g.neighbors(node);
+
+  unsigned int deg = g.nb_neighbors(node);
+
+  neigh_pos[0]=n2c[node];
+  neigh_weight[neigh_pos[0]]=0;
+  neigh_last=1;
+
+  for (unsigned int i=0 ; i<deg ; i++) {
+    unsigned int neigh        = *(p.first+i);
+    unsigned int neigh_comm   = n2c[neigh];
+    double neigh_w = (g.weights.size()==0)?1.:*(p.second+i);
+    
+    if (neigh!=node) {
+      if (neigh_weight[neigh_comm]==-1) {
+	neigh_weight[neigh_comm]=0.;
+	neigh_pos[neigh_last++]=neigh_comm;
+      }
+      neigh_weight[neigh_comm]+=neigh_w;
+    }
+  }
+}
+
+void
+Community::partition2graph() {
+  vector<int> renumber(size, -1);
+  for (int node=0 ; node<size ; node++) {
+    renumber[n2c[node]]++;
+  }
+
+  int final=0;
+  for (int i=0 ; i<size ; i++)
+    if (renumber[i]!=-1)
+      renumber[i]=final++;
+
+
+  for (int i=0 ; i<size ; i++) {
+    pair<vector<unsigned int>::iterator, vector<float>::iterator> p = g.neighbors(i);
+
+    int deg = g.nb_neighbors(i);
+    for (int j=0 ; j<deg ; j++) {
+      int neigh = *(p.first+j);
+      cout << renumber[n2c[i]] << " " << renumber[n2c[neigh]] << endl;
+    }
+  }
+}
+
+void
+Community::display_partition() {
+  vector<int> renumber(size, -1);
+  for (int node=0 ; node<size ; node++) {
+    renumber[n2c[node]]++;
+  }
+
+  int final=0;
+  for (int i=0 ; i<size ; i++)
+    if (renumber[i]!=-1)
+      renumber[i]=final++;
+
+  for (int i=0 ; i<size ; i++)
+    cout << i << " " << renumber[n2c[i]] << endl;
+}
+
+
+Graph
+Community::partition2graph_binary() {
+  // Renumber communities
+  vector<int> renumber(size, -1);
+  for (int node=0 ; node<size ; node++) {
+    renumber[n2c[node]]++;
+  }
+
+  int final=0;
+  for (int i=0 ; i<size ; i++)
+    if (renumber[i]!=-1)
+      renumber[i]=final++;
+
+  // Compute communities
+  vector<vector<int> > comm_nodes(final);
+  for (int node=0 ; node<size ; node++) {
+    comm_nodes[renumber[n2c[node]]].push_back(node);
+  }
+
+  // Compute weighted graph
+  Graph g2;
+  g2.nb_nodes = comm_nodes.size();
+  g2.degrees.resize(comm_nodes.size());
+
+  int comm_deg = comm_nodes.size();
+  for (int comm=0 ; comm<comm_deg ; comm++) {
+    map<int,float> m;
+    map<int,float>::iterator it;
+
+    int comm_size = comm_nodes[comm].size();
+    for (int node=0 ; node<comm_size ; node++) {
+      pair<vector<unsigned int>::iterator, vector<float>::iterator> p = g.neighbors(comm_nodes[comm][node]);
+      int deg = g.nb_neighbors(comm_nodes[comm][node]);
+      for (int i=0 ; i<deg ; i++) {
+	int neigh        = *(p.first+i);
+	int neigh_comm   = renumber[n2c[neigh]];
+	double neigh_weight = (g.weights.size()==0)?1.:*(p.second+i);
+
+	it = m.find(neigh_comm);
+	if (it==m.end())
+	  m.insert(make_pair(neigh_comm, neigh_weight));
+	else
+	  it->second+=neigh_weight;
+      }
+    }
+    g2.degrees[comm]=(comm==0)?m.size():g2.degrees[comm-1]+m.size();
+    g2.nb_links+=m.size();
+
+    
+    for (it = m.begin() ; it!=m.end() ; it++) {
+      g2.total_weight  += it->second;
+      g2.links.push_back(it->first);
+      g2.weights.push_back(it->second);
+    }
+  }
+
+  return g2;
+}
+
+
+bool
+Community::one_level() {
+  bool improvement=false ;
+  int nb_moves;
+  int nb_pass_done = 0;
+  double new_mod   = modularity();
+  double cur_mod   = new_mod;
+
+  vector<int> random_order(size);
+  for (int i=0 ; i<size ; i++)
+    random_order[i]=i;
+  for (int i=0 ; i<size-1 ; i++) {
+    int rand_pos = rand()%(size-i)+i;
+    int tmp      = random_order[i];
+    random_order[i] = random_order[rand_pos];
+    random_order[rand_pos] = tmp;
+  }
+
+  // repeat while 
+  //   there is an improvement of modularity
+  //   or there is an improvement of modularity greater than a given epsilon 
+  //   or a predefined number of pass have been done
+  do {
+    cur_mod = new_mod;
+    nb_moves = 0;
+    nb_pass_done++;
+
+    // for each node: remove the node from its community and insert it in the best community
+    for (int node_tmp=0 ; node_tmp<size ; node_tmp++) {
+//      int node = node_tmp;
+      int node = random_order[node_tmp];
+      int node_comm     = n2c[node];
+      double w_degree = g.weighted_degree(node);
+
+      // computation of all neighboring communities of current node
+      neigh_comm(node);
+      // remove node from its current community
+      remove(node, node_comm, neigh_weight[node_comm]);
+
+      // compute the nearest community for node
+      // default choice for future insertion is the former community
+      int best_comm        = node_comm;
+      double best_nblinks  = 0.;
+      double best_increase = 0.;
+      for (unsigned int i=0 ; i<neigh_last ; i++) {
+        double increase = modularity_gain(node, neigh_pos[i], neigh_weight[neigh_pos[i]], w_degree);
+        if (increase>best_increase) {
+          best_comm     = neigh_pos[i];
+          best_nblinks  = neigh_weight[neigh_pos[i]];
+          best_increase = increase;
+        }
+      }
+
+      // insert node in the nearest community
+      insert(node, best_comm, best_nblinks);
+     
+      if (best_comm!=node_comm)
+        nb_moves++;
+    }
+
+    double total_tot=0;
+    double total_in=0;
+    for (unsigned int i=0 ; i<tot.size() ;i++) {
+      total_tot+=tot[i];
+      total_in+=in[i];
+    }
+
+    new_mod = modularity();
+    if (nb_moves>0)
+      improvement=true;
+    
+  } while (nb_moves>0 && new_mod-cur_mod>min_modularity);
+
+  return improvement;
+}
+