diff --git a/ext/cIGraph.c b/ext/cIGraph.c index e6a4112..f8a2f8d 100644 --- a/ext/cIGraph.c +++ b/ext/cIGraph.c @@ -256,6 +256,9 @@ void Init_igraph(){ rb_define_method(cIGraph, "diameter", cIGraph_diameter, 2); /* in cIGraph_shortest_paths.c */ rb_define_method(cIGraph, "girth", cIGraph_girth, 0); /* in cIGraph_shortest_paths.c */ + + rb_define_method(cIGraph, "dijkstra_shortest_paths", cIGraph_dijkstra_shortest_paths, 3); + rb_define_method(cIGraph, "neighbourhood_size", cIGraph_neighborhood_size, 3); /* in cIGraph_vertex_neighbourhood.c */ rb_define_method(cIGraph, "neighbourhood", cIGraph_neighborhood, 3); /* in cIGraph_vertex_neighbourhood.c */ rb_define_method(cIGraph, "neighbourhood_graphs", cIGraph_neighborhood_graphs, 3); /* in cIGraph_vertex_neighbourhood.c */ @@ -301,6 +304,21 @@ void Init_igraph(){ rb_define_method(cIGraph, "maximal_cliques", cIGraph_maximal_cliques, 0); /* in cIGraph_cliques.c */ rb_define_method(cIGraph, "clique_number", cIGraph_clique_number, 0); /* in cIGraph_cliques.c */ + rb_define_method(cIGraph, "independent_vertex_sets", cIGraph_independent_vertex_sets, 2); /* in cIGraph_independent_vertex_sets.c */ + rb_define_method(cIGraph, "largest_independent_vertex_sets", cIGraph_largest_independent_vertex_sets, 0); /* in cIGraph_independent_vertex_sets.c */ + rb_define_method(cIGraph, "maximal_independent_vertex_sets", cIGraph_maximal_independent_vertex_sets, 0); /* in cIGraph_independent_vertex_sets.c */ + rb_define_method(cIGraph, "independence_number", cIGraph_independence_number, 0); /* in cIGraph_independent_vertex_sets.c */ + + rb_define_method(cIGraph, "isomorphic", cIGraph_isomorphic, 1); /* in cIGraph_isomorphic.c */ + rb_define_method(cIGraph, "isomorphic_vf2", cIGraph_isomorphic_vf2, 1); /* in cIGraph_isomorphic.c */ + rb_define_method(cIGraph, "isoclass", cIGraph_isoclass, 0); /* in cIGraph_isomorphic.c */ + rb_define_method(cIGraph, "isoclass_subgraph", cIGraph_isoclass_subgraph, 1); /* in cIGraph_isomorphic.c */ + rb_define_singleton_method(cIGraph, "isoclass_create", cIGraph_isoclass_create, 3); /* in cIGraph_isomorphic.c */ + + rb_define_method(cIGraph, "motifs_randesu", cIGraph_motifs_randesu, 2); /* in cIGraph_motif.c */ + rb_define_method(cIGraph, "motifs_randesu_no", cIGraph_motifs_randesu_no, 2); /* in cIGraph_motif.c */ + rb_define_method(cIGraph, "motifs_randesu_estimate", cIGraph_motifs_randesu_estimate, 4); /* in cIGraph_motif.c */ + rb_define_method(cIGraph, "topological_sorting", cIGraph_topological_sorting, 1); /* in cIGraph_topological_sort.c */ rb_define_singleton_method(cIGraph, "read_graph_edgelist", cIGraph_read_graph_edgelist, 2); /* in cIGraph_file.c */ diff --git a/ext/cIGraph.h b/ext/cIGraph.h index 5da8386..a5294b5 100644 --- a/ext/cIGraph.h +++ b/ext/cIGraph.h @@ -81,6 +81,13 @@ VALUE cIGraph_average_path_length (VALUE self, VALUE directed, VALUE unconn); VALUE cIGraph_diameter (VALUE self, VALUE directed, VALUE unconn); VALUE cIGraph_girth (VALUE self); +VALUE cIGraph_dijkstra_shortest_paths(VALUE self, VALUE from, VALUE weights, VALUE mode); +int igraph_dijkstra_shortest_paths(const igraph_t *graph, + igraph_matrix_t *res, + const igraph_vs_t from, + const igraph_vector_t *wghts, + igraph_neimode_t mode); + //Vertex neighbourhood functions VALUE cIGraph_neighborhood_size (VALUE self, VALUE from, VALUE order, VALUE mode); VALUE cIGraph_neighborhood (VALUE self, VALUE from, VALUE order, VALUE mode); @@ -136,6 +143,25 @@ VALUE cIGraph_largest_cliques(VALUE self); VALUE cIGraph_maximal_cliques(VALUE self); VALUE cIGraph_clique_number(VALUE self); +//Independent vertex sets +VALUE cIGraph_independent_vertex_sets(VALUE self, VALUE min, VALUE max); +VALUE cIGraph_largest_independent_vertex_sets(VALUE self); +VALUE cIGraph_maximal_independent_vertex_sets(VALUE self); +VALUE cIGraph_independence_number(VALUE self); + +//Graph isomorphism +VALUE cIGraph_isomorphic (VALUE self, VALUE g); +VALUE cIGraph_isomorphic_vf2 (VALUE self, VALUE g); +VALUE cIGraph_isoclass (VALUE self); +VALUE cIGraph_isoclass_subgraph(VALUE self, VALUE vs); +VALUE cIGraph_isoclass_create (VALUE self, VALUE vn, VALUE iso, VALUE dir); + +//Motifs +VALUE cIGraph_motifs_randesu (VALUE self, VALUE size, VALUE cuts); +VALUE cIGraph_motifs_randesu_no (VALUE self, VALUE size, VALUE cuts); +VALUE cIGraph_motifs_randesu_estimate(VALUE self, VALUE size, VALUE cuts, + VALUE samplen, VALUE samplev); + //File handling VALUE cIGraph_read_graph_edgelist (VALUE self, VALUE file, VALUE mode); VALUE cIGraph_write_graph_edgelist(VALUE self, VALUE file); diff --git a/ext/cIGraph_attribute_handler.c b/ext/cIGraph_attribute_handler.c index 8c8f178..9d7cace 100644 --- a/ext/cIGraph_attribute_handler.c +++ b/ext/cIGraph_attribute_handler.c @@ -189,6 +189,7 @@ int cIGraph_attribute_add_vertices(igraph_t *graph, long int nv, igraph_vector_p VALUE values; if(attr){ + if(igraph_vector_ptr_size(attr) > 0 && ((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->type == IGRAPH_ATTRIBUTE_PY_OBJECT){ values = (VALUE)((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->value; @@ -234,6 +235,11 @@ int cIGraph_attribute_add_vertices(igraph_t *graph, long int nv, igraph_vector_p rb_ary_push(vertex_array,record); } } + } else { + //Default: Add numbered vertices. + for(i=0;i Array + * + * Calculates the length of the shortest paths from each of the vertices in + * the varray Array to all of the other vertices in the graph given a set of + * edge weights given in the weights Array. The result + * is returned as an Array of Array. Each top-level Array contains the results + * for a vertex in the varray Array. Each entry in the Array is the path length + * to another vertex in the graph in vertex order (the order the vertices were + * added to the graph. (This should probalby be changed to give a Hash of Hash + * to allow easier look up.) + */ +VALUE cIGraph_dijkstra_shortest_paths(VALUE self, VALUE from, VALUE weights, VALUE mode){ + + igraph_t *graph; + igraph_vs_t vids; + igraph_vector_t vidv; + igraph_vector_t wghts; + igraph_neimode_t pmode = NUM2INT(mode); + igraph_matrix_t res; + int i; + int j; + VALUE row; + VALUE path_length; + VALUE matrix = rb_ary_new(); + int n_row; + int n_col; + + Data_Get_Struct(self, igraph_t, graph); + + n_row = NUM2INT(rb_funcall(from,rb_intern("length"),0)); + n_col = igraph_vcount(graph); + + //matrix to hold the results of the calculations + igraph_matrix_init(&res,n_row,n_col); + + igraph_vector_init(&wghts,RARRAY(weights)->len); + + for(i=0;ilen;i++){ + VECTOR(wghts)[i] = NUM2DBL(RARRAY(weights)->ptr[i]); + } + + //Convert an array of vertices to a vector of vertex ids + igraph_vector_init_int(&vidv,0); + cIGraph_vertex_arr_to_id_vec(self,from,&vidv); + //create vertex selector from the vecotr of ids + igraph_vs_vector(&vids,&vidv); + + igraph_dijkstra_shortest_paths(graph,&res,vids,&wghts,pmode); + + for(i=0; i Array + * + * Calculates the paths from the vertex specified as from to each vertex in the + * to_array Array. Returns an Array of Arrays. Each top level Array represents + * a path and each entry in each Array is a vertex on the path. mode + * represents the type of shortest paths to be calculated: IGraph::OUT + * the outgoing paths are calculated. IGraph::IN the incoming paths are + * calculated. IGraph::ALL the directed graph is considered as an undirected + * one for the computation. + */ +VALUE cIGraph_get_dijkstra_shortest_paths(VALUE self, VALUE from, VALUE to, VALUE mode){ + + igraph_t *graph; + + igraph_integer_t from_vid; + igraph_vs_t to_vids; + igraph_vector_t to_vidv; + + igraph_neimode_t pmode = NUM2INT(mode); + + igraph_vector_ptr_t res; + igraph_vector_t *path_v; + + int i; + int j; + VALUE path; + VALUE matrix = rb_ary_new(); + int n_paths; + + Data_Get_Struct(self, igraph_t, graph); + + n_paths = RARRAY(to)->len; + + //vector to hold the results of the calculations + igraph_vector_ptr_init(&res,0); + for(i=0;i Array + * + * Find all independent vertex sets in a graph + * + * A vertex set is considered independent if there are no edges between them. + * + * If you are interested in the size of the largest independent vertex set, + * use IGraph#independence_number() instead. + */ + +VALUE cIGraph_independent_vertex_sets(VALUE self, VALUE min, VALUE max){ + + igraph_t *graph; + igraph_vector_ptr_t res; + igraph_vector_t *vec; + int i; + int j; + VALUE independent_vertex_set; + VALUE object; + VALUE independent_vertex_sets = rb_ary_new(); + + Data_Get_Struct(self, igraph_t, graph); + + igraph_vector_ptr_init(&res,0); + + igraph_independent_vertex_sets(graph, &res, NUM2INT(min), NUM2INT(max)); + + for(i=0; i Array + * + * Finds the largest independent vertex set(s) in a graph. + + * An independent vertex set is largest if there is no other independent + * vertex set with more vertices in the graph. + */ + +VALUE cIGraph_largest_independent_vertex_sets(VALUE self){ + + igraph_t *graph; + igraph_vector_ptr_t res; + igraph_vector_t *vec; + int i; + int j; + VALUE independent_vertex_set; + VALUE object; + VALUE independent_vertex_sets = rb_ary_new(); + + Data_Get_Struct(self, igraph_t, graph); + + igraph_vector_ptr_init(&res,0); + + igraph_largest_independent_vertex_sets(graph, &res); + + for(i=0; i Array + * + * Find all maximal independent vertex sets of a graph + * + * A maximal independent vertex set is an independent vertex set which can't + * be extended any more by adding a new vertex to it. + * + * The algorithm used here is based on the following paper: S. Tsukiyama, + * M. Ide, H. Ariyoshi and I. Shirawaka. A new algorithm for generating all + * the maximal independent sets. SIAM J Computing, 6:505--517, 1977. + * + * The implementation was originally written by Kevin O'Neill and modified + * by K M Briggs in the Very Nauty Graph Library. I simply re-wrote it to + * use igraph's data structures. + * + * If you are interested in the size of the largest independent vertex set, + * use IGraph#independence_number() instead. + */ + +VALUE cIGraph_maximal_independent_vertex_sets(VALUE self){ + + igraph_t *graph; + igraph_vector_ptr_t res; + igraph_vector_t *vec; + int i; + int j; + VALUE independent_vertex_set; + VALUE object; + VALUE independent_vertex_sets = rb_ary_new(); + + Data_Get_Struct(self, igraph_t, graph); + + igraph_vector_ptr_init(&res,0); + + igraph_maximal_independent_vertex_sets(graph, &res); + + for(i=0; i Integer + * + * Find the independence number of the graph + * + * The independence number of a graph is the cardinality of the largest + * independent vertex set. + */ + +VALUE cIGraph_independence_number(VALUE self){ + + igraph_t *graph; + igraph_integer_t res; + + Data_Get_Struct(self, igraph_t, graph); + + igraph_independence_number(graph, &res); + + return INT2NUM(res); + +} diff --git a/ext/cIGraph_isomorphism.c b/ext/cIGraph_isomorphism.c new file mode 100644 index 0000000..db9b5ef --- /dev/null +++ b/ext/cIGraph_isomorphism.c @@ -0,0 +1,137 @@ +#include "igraph.h" +#include "ruby.h" +#include "cIGraph.h" + +/* call-seq: + * graph.isomorphic(graph) -> True/False + * + * Decides whether two graphs are isomorphic + * + * From Wikipedia: The graph isomorphism problem or GI problem is the graph + * theory problem of determining whether, given two graphs G1 and G2, it is + * possible to permute (or relabel) the vertices of one graph so that it is + * equal to the other. Such a permutation is called a graph isomorphism. + */ +VALUE cIGraph_isomorphic(VALUE self, VALUE g){ + + igraph_bool_t res = 0; + igraph_t *graph; + igraph_t *graph2; + + Data_Get_Struct(self, igraph_t, graph); + Data_Get_Struct(g, igraph_t, graph2); + + IGRAPH_CHECK(igraph_isomorphic(graph,graph2,&res)); + + return res == 0 ? Qfalse : Qtrue; + +} + +/* call-seq: + * graph.isomorphic_vf2(graph) -> True/False + * + * Decides whether two graphs are isomorphic + * + * This function is an implementation of the VF2 isomorphism algorithm, + * see P. Foggia, C. Sansone, M. Vento, An Improved algorithm for matching + * large graphs, Prof. of the 3rd IAPR-TC-15 International Workshop on + * Graph-based Representations, Italy, 2001. + */ +VALUE cIGraph_isomorphic_vf2(VALUE self, VALUE g){ + + igraph_bool_t res = 0; + igraph_t *graph; + igraph_t *graph2; + + Data_Get_Struct(self, igraph_t, graph); + Data_Get_Struct(g, igraph_t, graph2); + + IGRAPH_CHECK(igraph_isomorphic_vf2(graph,graph2,&res)); + + return res == 0 ? Qfalse : Qtrue; + +} + +/* call-seq: + * graph.isoclass() -> Integer + * + * Determine the isomorphism class of a graph + * + * All graphs with a given number of vertices belong to a number of + * isomorpism classes, with every graph in a given class being isomorphic + * to each other. + * + * This function gives the isomorphism class (a number) of a graph. Two + * graphs have the same isomorphism class if and only if they are isomorphic. + * + * The first isomorphism class is numbered zero and it is the empty graph, + * the last isomorphism class is the full graph. The number of isomorphism + * class for directed graphs with three vertices is 16 (between 0 and 15), + * for undirected graph it is only 4. For graphs with four vertices it is + * 218 (directed) and 11 (undirected). + */ +VALUE cIGraph_isoclass(VALUE self){ + + int res = 0; + igraph_t *graph; + + Data_Get_Struct(self, igraph_t, graph); + + IGRAPH_CHECK(igraph_isoclass(graph,&res)); + + return INT2NUM(res); + +} + +/* call-seq: + * graph.isoclass_subgraph(vs) -> Integer + * + * Determine the isomorphism class of a subgraph given by the vertices given + * in the Array vs. + * + */ +VALUE cIGraph_isoclass_subgraph(VALUE self, VALUE vs){ + + int res = 0; + igraph_t *graph; + igraph_vector_t vidv; + + Data_Get_Struct(self, igraph_t, graph); + + //Convert an array of vertices to a vector of vertex ids + igraph_vector_init_int(&vidv,0); + cIGraph_vertex_arr_to_id_vec(self,vs,&vidv); + + IGRAPH_CHECK(igraph_isoclass_subgraph(graph,&vidv,&res)); + + igraph_vector_destroy(&vidv); + + return INT2NUM(res); + +} + +/* call-seq: + * IGraph.isoclass_create(vn,iso,dir) -> IGraph + * + * Creates a graph with the number of vertices given by vn from the given + * isomorphism class iso and the direction boolean dir. + * + * This function is implemented only for graphs with three or four vertices. + */ +VALUE cIGraph_isoclass_create(VALUE self, VALUE vn, VALUE iso, VALUE dir){ + + igraph_t *graph; + VALUE new_graph; + igraph_bool_t dir_b = 0; + + if(dir) + dir_b = 1; + + new_graph = cIGraph_alloc(cIGraph); + Data_Get_Struct(new_graph, igraph_t, graph); + + IGRAPH_CHECK(igraph_isoclass_create(graph,NUM2INT(vn),NUM2INT(iso),dir_b)); + + return new_graph; + +} diff --git a/ext/cIGraph_motif.c b/ext/cIGraph_motif.c new file mode 100644 index 0000000..1a7a365 --- /dev/null +++ b/ext/cIGraph_motif.c @@ -0,0 +1,109 @@ +#include "igraph.h" +#include "ruby.h" +#include "cIGraph.h" + +/* call-seq: + * igraph.motifs_randesu(size,cut) + * + */ +VALUE cIGraph_motifs_randesu(VALUE self, VALUE size, VALUE cuts){ + + igraph_t *graph; + igraph_vector_t cutsv; + igraph_vector_t res; + int i; + VALUE hist = rb_ary_new(); + + Data_Get_Struct(self, igraph_t, graph); + + igraph_vector_init(&res,0); + + //Convert an array of vertices to a vector of vertex ids + igraph_vector_init(&cutsv,0); + for(i=0;ilen;i++){ + igraph_vector_push_back(&cutsv,NUM2DBL(RARRAY(cuts)->ptr[i])); + } + + igraph_motifs_randesu(graph,&res,NUM2INT(size),&cutsv); + + for(i=0; ilen;i++){ + igraph_vector_push_back(&cutsv,NUM2DBL(RARRAY(cuts)->ptr[i])); + } + + igraph_motifs_randesu_no(graph,&res,NUM2INT(size),&cutsv); + + igraph_vector_destroy(&cutsv); + + return INT2NUM(res); + +} + +/* call-seq: + * igraph.motifs_randesu_estimate(size,cut,samplen,samplev) + * + */ +VALUE cIGraph_motifs_randesu_estimate(VALUE self, VALUE size, VALUE cuts, + VALUE samplen, VALUE samplev){ + + igraph_t *graph; + igraph_vector_t cutsv; + igraph_vector_t vidv; + igraph_integer_t res; + int i; + + if(samplev != Qnil){ + igraph_vector_init(&vidv,0); + //Convert an array of vertices to a vector of vertex ids + igraph_vector_init_int(&vidv,0); + cIGraph_vertex_arr_to_id_vec(self,samplev,&vidv); + } + + Data_Get_Struct(self, igraph_t, graph); + + igraph_vector_init(&cutsv,0); + for(i=0;ilen;i++){ + igraph_vector_push_back(&cutsv,NUM2DBL(RARRAY(cuts)->ptr[i])); + } + + if(samplev == Qnil){ + igraph_motifs_randesu_estimate(graph,&res,NUM2INT(size), + &cutsv,NUM2INT(samplen),NULL); + } else { + igraph_motifs_randesu_estimate(graph,&res,NUM2INT(size), + &cutsv,NUM2INT(samplen),&vidv); + } + + igraph_vector_destroy(&cutsv); + if(samplev != Qnil){ + igraph_vector_destroy(&vidv); + } + + return INT2NUM(res); + +} diff --git a/ext/cIGraph_spectral.c b/ext/cIGraph_spectral.c index ddc1b01..3de9dff 100644 --- a/ext/cIGraph_spectral.c +++ b/ext/cIGraph_spectral.c @@ -31,7 +31,7 @@ VALUE cIGraph_laplacian(VALUE self, VALUE mode){ VALUE val; VALUE matrix = rb_ary_new(); - if(mode = Qtrue) + if(mode == Qtrue) pmode = 1; Data_Get_Struct(self, igraph_t, graph); diff --git a/test/test_all.rb b/test/test_all.rb index c836dfe..42e9bc5 100644 --- a/test/test_all.rb +++ b/test/test_all.rb @@ -12,12 +12,16 @@ require 'tc_centrality' require 'tc_components' require 'tc_copy' require 'tc_cores' +require 'tc_dijkstra' require 'tc_directedness' require 'tc_error_handling' require 'tc_file_read_write' +require 'tc_independent_vertex_sets' +require 'tc_isomorphic' require 'tc_iterators' require 'tc_layout' require 'tc_matrix' +require 'tc_motif' require 'tc_other_ops' require 'tc_selectors' require 'tc_shortest_paths'