igraph/ext/cIGraph_community.c

662 lines
17 KiB
C

#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.modularity(groups) -> Float
*
* Calculate the modularity of a graph with respect to some vertex types.
* The modularity of a graph with respect to some division (or vertex types)
* measures how good the division is, or how separated are the different
* vertex types from each other.
*
*/
VALUE cIGraph_modularity(VALUE self, VALUE groups){
igraph_t *graph;
igraph_real_t value;
igraph_vector_t membership;
VALUE group;
int i,j;
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_init(&membership,igraph_vcount(graph));
for(i=0;i<RARRAY_LEN(groups);i++){
group = RARRAY_PTR(groups)[i];
for(j=0;j<RARRAY_LEN(group);j++){
igraph_vector_set(&membership,
cIGraph_get_vertex_id(self,RARRAY_PTR(group)[j]),i);
}
}
igraph_modularity(graph,&membership,&value,NULL);
igraph_vector_destroy(&membership);
return rb_float_new(value);
}
/* call-seq:
* graph.community_to_membership(merge,steps) -> Array
*
* Create membership vector from community structure dendrogram This function
* creates a membership vector from a community structure dendrogram.
* A membership vector contains for each vertex the id of its graph
* component, the graph components are numbered from zero, see the same
* argument of igraph_clusters() for an example of a membership vector.
*
*/
VALUE cIGraph_community_to_membership(VALUE self, VALUE merge, VALUE steps, VALUE nodes){
igraph_t *graph;
igraph_matrix_t *merges;
igraph_vector_t membership;
VALUE groups;
int i,groupid,max_groupid;
Data_Get_Struct(self, igraph_t, graph);
Data_Get_Struct(merge, igraph_matrix_t, merges);
igraph_vector_init(&membership,0);
igraph_community_to_membership(merges,NUM2INT(nodes),NUM2INT(steps),&membership,NULL);
max_groupid = 0;
for(i=0;i<igraph_vector_size(&membership);i++){
if(VECTOR(membership)[i] > max_groupid)
max_groupid = VECTOR(membership)[i];
}
groups = rb_ary_new();
for(i=0;i<max_groupid+1;i++){
rb_ary_push(groups,rb_ary_new());
}
for(i=0;i<igraph_vector_size(&membership);i++){
groupid = VECTOR(membership)[i];
if(RARRAY_PTR(groups)[groupid] == Qnil){
RARRAY_PTR(groups)[groupid] = rb_ary_new();
}
rb_ary_push(RARRAY_PTR(groups)[groupid],
cIGraph_get_vertex_object(self, i));
}
igraph_vector_destroy(&membership);
return groups;
}
/* call-seq:
* graph.community_spinglass(weights,spins,parupdate,starttemp,stoptemp,coolfact,update_rule,gamma) -> Array
*
* Community detection based on statistical mechanics This function
* implements the community structure detection algorithm proposed by Joerg
* Reichardt and Stefan Bornholdt. The algorithm is described in their
* paper: Statistical Mechanics of Community Detection.
*
*/
VALUE cIGraph_community_spinglass(VALUE self, VALUE weights, VALUE spins, VALUE parupdate, VALUE starttemp, VALUE stoptemp, VALUE coolfact, VALUE update_rule, VALUE gamma){
igraph_t *graph;
igraph_vector_t weights_vec;
igraph_vector_t membership;
igraph_real_t temperature;
igraph_real_t modularity;
igraph_bool_t parupdate_b;
VALUE group;
VALUE groups;
VALUE res;
int i,groupid,max_groupid;
if(parupdate)
parupdate_b = 1;
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_init(&membership,0);
igraph_vector_init(&weights_vec,RARRAY_LEN(weights));
for(i=0;i<RARRAY_LEN(weights);i++){
VECTOR(weights_vec)[i] = NUM2DBL(RARRAY_PTR(weights)[i]);
}
igraph_community_spinglass(graph,
igraph_vector_size(&weights_vec) > 0 ? &weights_vec : NULL,
&modularity,&temperature,
&membership,NULL,NUM2INT(spins),parupdate_b,
NUM2DBL(starttemp),NUM2DBL(stoptemp),
NUM2DBL(coolfact),NUM2INT(update_rule),
NUM2DBL(gamma));
max_groupid = 0;
for(i=0;i<igraph_vector_size(&membership);i++){
if(VECTOR(membership)[i] > max_groupid)
max_groupid = VECTOR(membership)[i];
}
groups = rb_ary_new();
for(i=0;i<max_groupid+1;i++){
rb_ary_push(groups,rb_ary_new());
}
for(i=0;i<igraph_vector_size(&membership);i++){
groupid = VECTOR(membership)[i];
if(groupid == -1)
groupid = 0;
group = RARRAY_PTR(groups)[groupid];
rb_ary_push(group,cIGraph_get_vertex_object(self, i));
}
res = rb_ary_new3(3,groups,
rb_float_new(modularity),
rb_float_new(temperature));
igraph_vector_destroy(&membership);
igraph_vector_destroy(&weights_vec);
return res;
}
/* call-seq:
* graph.community_spinglass_single(weights,vertex,spins,update_rule,gamma) -> Array
*
* Community detection based on statistical mechanics This function
* implements the community structure detection algorithm proposed by Joerg
* Reichardt and Stefan Bornholdt. The algorithm is described in their
* paper: Statistical Mechanics of Community Detection.
*
*/
VALUE cIGraph_community_spinglass_single(VALUE self, VALUE weights, VALUE vertex, VALUE spins, VALUE update_rule, VALUE gamma){
igraph_t *graph;
igraph_vector_t weights_vec;
igraph_vector_t community;
igraph_real_t cohesion;
igraph_real_t adhesion;
VALUE group;
VALUE res;
int i;
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_init(&community,0);
igraph_vector_init(&weights_vec,RARRAY_LEN(weights));
for(i=0;i<RARRAY_LEN(weights);i++){
VECTOR(weights_vec)[i] = NUM2DBL(RARRAY_PTR(weights)[i]);
}
igraph_community_spinglass_single(graph,
igraph_vector_size(&weights_vec) > 0 ? &weights_vec : NULL,
cIGraph_get_vertex_id(self, vertex),
&community, &cohesion, &adhesion,
NULL, NULL,
NUM2INT(spins),NUM2INT(update_rule),
NUM2DBL(gamma));
group = rb_ary_new();
for(i=0;i<igraph_vector_size(&community);i++){
rb_ary_push(group,cIGraph_get_vertex_object(self, i));
}
res = rb_ary_new3(3,group,
rb_float_new(cohesion),
rb_float_new(adhesion));
igraph_vector_destroy(&community);
igraph_vector_destroy(&weights_vec);
return res;
}
/* call-seq:
* graph.community_leading_eigenvector(steps) -> Array
*
* Newman's leading eigenvector method for detecting community structure.
* This is the proper implementation of the recursive, divisive algorithm:
* each split is done by maximizing the modularity regarding the original
* network, see MEJ Newman: Finding community structure in networks using
* the eigenvectors of matrices, arXiv:physics/0605087.
*
*/
VALUE cIGraph_community_leading_eigenvector(VALUE self, VALUE steps){
igraph_t *graph;
igraph_vector_t membership;
igraph_matrix_t *merges = malloc(sizeof(igraph_matrix_t));
igraph_arpack_options_t arpack_opt;
igraph_arpack_options_init(&arpack_opt);
int i,groupid,max_groupid;
VALUE groups, group, res;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(merges,0,0);
igraph_vector_init(&membership,0);
igraph_community_leading_eigenvector(graph,merges,&membership,
NUM2INT(steps),&arpack_opt);
max_groupid = 0;
for(i=0;i<igraph_vector_size(&membership);i++){
if(VECTOR(membership)[i] > max_groupid)
max_groupid = VECTOR(membership)[i];
}
groups = rb_ary_new();
for(i=0;i<max_groupid+1;i++){
rb_ary_push(groups,rb_ary_new());
}
for(i=0;i<igraph_vector_size(&membership);i++){
groupid = VECTOR(membership)[i];
if(groupid == -1)
groupid = 0;
group = RARRAY_PTR(groups)[groupid];
rb_ary_push(group,cIGraph_get_vertex_object(self, i));
}
res = rb_ary_new3(2,groups,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, merges));
igraph_vector_destroy(&membership);
return res;
}
/* call-seq:
* graph.community_leading_eigenvector_naive(steps) -> Array
*
* Newman's leading eigenvector method for detecting community structure.
* This is the proper implementation of the recursive, divisive algorithm:
* each split is done by maximizing the modularity regarding the original
* network, see MEJ Newman: Finding community structure in networks using
* the eigenvectors of matrices, arXiv:physics/0605087.
*
*/
VALUE cIGraph_community_leading_eigenvector_naive(VALUE self, VALUE steps){
igraph_t *graph;
igraph_vector_t membership;
igraph_matrix_t *merges = malloc(sizeof(igraph_matrix_t));
igraph_arpack_options_t arpack_opt;
igraph_arpack_options_init(&arpack_opt);
int i,groupid,max_groupid;
VALUE groups, group, res;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(merges,0,0);
igraph_vector_init(&membership,0);
igraph_community_leading_eigenvector_naive(graph,merges,&membership,
NUM2INT(steps), &arpack_opt);
max_groupid = 0;
for(i=0;i<igraph_vector_size(&membership);i++){
if(VECTOR(membership)[i] > max_groupid)
max_groupid = VECTOR(membership)[i];
}
groups = rb_ary_new();
for(i=0;i<max_groupid+1;i++){
rb_ary_push(groups,rb_ary_new());
}
for(i=0;i<igraph_vector_size(&membership);i++){
groupid = VECTOR(membership)[i];
if(groupid == -1)
groupid = 0;
group = RARRAY_PTR(groups)[groupid];
rb_ary_push(group,cIGraph_get_vertex_object(self, i));
}
res = rb_ary_new3(2,groups,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, merges));
igraph_vector_destroy(&membership);
return res;
}
/* call-seq:
* graph.community_leading_eigenvector_step(membership,community) -> Array
*
* Do one split according to Mark Newman's leading eigenvector community
* detection method. See MEJ Newman: Finding community structure in networks
* using the eigenvectors of matrices, arXiv:phyisics/0605087 for the details.
*
*/
VALUE cIGraph_community_leading_eigenvector_step(VALUE self, VALUE membership, VALUE community){
igraph_t *graph;
igraph_vector_t membership_vec;
igraph_vector_t eigenvector;
igraph_real_t eigenvalue;
igraph_bool_t split;
int i,j,groupid,max_groupid,vid;
igraph_arpack_options_t arpack_opt;
igraph_arpack_options_init(&arpack_opt);
VALUE groups, group, res, eigenvector_a, obj;
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_init(&membership_vec,igraph_vcount(graph));
igraph_vector_init(&eigenvector,0);
for(i=0;i<RARRAY_LEN(membership);i++){
group = RARRAY_PTR(membership)[i];
for(j=0;j<RARRAY_LEN(group);j++){
obj = RARRAY_PTR(group)[j];
vid = cIGraph_get_vertex_id(self,obj);
VECTOR(membership_vec)[vid] = i;
}
}
igraph_community_leading_eigenvector_step(graph,&membership_vec,
NUM2INT(community),
&split,&eigenvector,&eigenvalue,&arpack_opt,NULL);
max_groupid = 0;
for(i=0;i<igraph_vector_size(&membership_vec);i++){
if(VECTOR(membership_vec)[i] > max_groupid)
max_groupid = VECTOR(membership_vec)[i];
}
groups = rb_ary_new();
for(i=0;i<max_groupid+1;i++){
rb_ary_push(groups,rb_ary_new());
}
for(i=0;i<igraph_vector_size(&membership_vec);i++){
groupid = VECTOR(membership_vec)[i];
if(groupid == -1)
groupid = 0;
group = RARRAY_PTR(groups)[groupid];
rb_ary_push(group,cIGraph_get_vertex_object(self, i));
}
eigenvector_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&eigenvector);i++){
rb_ary_push(eigenvector_a,rb_float_new(VECTOR(eigenvector)[i]));
}
res = rb_ary_new3(4,groups,split==0 ? Qfalse : Qtrue,
eigenvector_a,rb_float_new(eigenvalue));
igraph_vector_destroy(&membership_vec);
igraph_vector_destroy(&eigenvector);
return res;
}
/* call-seq:
* graph.community_walktrap(weights,steps) -> Array
*
* This function is the implementation of the Walktrap community finding
* algorithm, see Pascal Pons, Matthieu Latapy: Computing communities in
* large networks using random walks, http://arxiv.org/abs/physics/0512106
*
*/
VALUE cIGraph_community_walktrap(VALUE self, VALUE weights, VALUE steps){
igraph_t *graph;
igraph_vector_t weights_vec;
igraph_vector_t modularity;
igraph_matrix_t *merges = malloc(sizeof(igraph_matrix_t));
int i;
VALUE modularity_a, res;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(merges,0,0);
igraph_vector_init(&weights_vec,0);
igraph_vector_init(&modularity,0);
for(i=0;i<RARRAY_LEN(weights);i++){
VECTOR(weights_vec)[i] = NUM2DBL(RARRAY_PTR(weights)[i]);
}
igraph_community_walktrap(graph,
igraph_vector_size(&weights_vec) > 0 ? &weights_vec : NULL,
NUM2INT(steps),merges,&modularity);
modularity_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&modularity);i++){
rb_ary_push(modularity_a,rb_float_new(VECTOR(modularity)[i]));
}
res = rb_ary_new3(2,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, merges),
modularity_a);
igraph_vector_destroy(&weights_vec);
igraph_vector_destroy(&modularity);
return res;
}
/* call-seq:
* graph.community_edge_betweenness(directed) -> Array
*
* Community structure detection based on the betweenness of the edges in the
* network. The algorithm was invented by M. Girvan and M. Newman, see:
* M. Girvan and M. E. J. Newman: Community structure in social and
* biological networks, Proc. Nat. Acad. Sci. USA 99, 7821-7826 (2002).
*
*/
VALUE cIGraph_community_edge_betweenness(VALUE self, VALUE directed){
igraph_t *graph;
igraph_vector_t result_vec;
igraph_vector_t edge_betw_vec;
igraph_vector_t bridges_vec;
igraph_matrix_t *merges = malloc(sizeof(igraph_matrix_t));
igraph_bool_t directed_b = 0;
int i;
VALUE result_a, edge_betw_a, bridges_a, res;
if(directed)
directed_b = 1;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(merges,0,0);
igraph_vector_init(&result_vec,0);
igraph_vector_init(&edge_betw_vec,0);
igraph_vector_init(&bridges_vec,0);
igraph_community_edge_betweenness(graph,
&result_vec,&edge_betw_vec,
merges,&bridges_vec,directed_b);
result_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&result_vec);i++){
rb_ary_push(result_a,INT2NUM(VECTOR(result_vec)[i]));
}
edge_betw_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&edge_betw_vec);i++){
rb_ary_push(edge_betw_a,INT2NUM(VECTOR(edge_betw_vec)[i]));
}
bridges_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&bridges_vec);i++){
rb_ary_push(bridges_a,INT2NUM(VECTOR(bridges_vec)[i]));
}
res = rb_ary_new3(4,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, merges),
result_a, edge_betw_a, bridges_a);
igraph_vector_destroy(&result_vec);
igraph_vector_destroy(&edge_betw_vec);
igraph_vector_destroy(&bridges_vec);
return res;
}
/* call-seq:
* graph.community_eb_get_merges(edges) -> Array
*
* Calculating the merges, ie. the dendrogram for an edge betweenness
* community structure
*
*/
VALUE cIGraph_community_eb_get_merges(VALUE self, VALUE edges){
igraph_t *graph;
igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t));
igraph_vector_t edges_vec;
igraph_vector_t bridges_vec;
VALUE result,bridges_a;
int i;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(res,0,0);
igraph_vector_init(&edges_vec,0);
igraph_vector_init(&bridges_vec,0);
for(i=0;i<RARRAY_LEN(edges);i++){
igraph_vector_push_back(&edges_vec,NUM2INT(RARRAY_PTR(edges)[i]));
}
igraph_community_eb_get_merges(graph,&edges_vec,res,&bridges_vec);
bridges_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&bridges_vec);i++){
rb_ary_push(bridges_a,INT2NUM(VECTOR(bridges_vec)[i]));
}
igraph_vector_destroy(&bridges_vec);
igraph_vector_destroy(&edges_vec);
result = rb_ary_new3(2,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, res),
bridges_a);
return result;
}
/* call-seq:
* graph.community_fastgreedy() -> Array
*
* Finding community structure by greedy optimization of modularity.
* This function implements the fast greedy modularity optimization algorithm
* for finding community structure, see A Clauset, MEJ Newman, C Moore:
* Finding community structure in very large networks,
* http://www.arxiv.org/abs/cond-mat/0408187 for the details.
*
*/
VALUE cIGraph_community_fastgreedy(VALUE self){
igraph_t *graph;
igraph_vector_t modularity;
igraph_matrix_t *merges = malloc(sizeof(igraph_matrix_t));
int i;
VALUE modularity_a, res;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(merges,0,0);
igraph_vector_init(&modularity,0);
igraph_community_fastgreedy(graph,NULL,
merges,&modularity);
modularity_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&modularity);i++){
rb_ary_push(modularity_a,rb_float_new(VECTOR(modularity)[i]));
}
res = rb_ary_new3(2,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, merges),
modularity_a);
igraph_vector_destroy(&modularity);
return res;
}