| @@ -1,24 +1,18 @@ | |||
| == Introduction | |||
| IGraph | |||
| IGraph is a Ruby extension for using the igraph library ([http://cneurocvs.rmki.kfki.hu/igraph/]). igraph is a library for creating and manipulating graphs with a particular emphasis on network analysis functions. | |||
| IGraph | |||
| IGraph is currently pre-alpha status and should be considered unstable. There are functions for building and querying simple graphs as well as shortest path calculations. | |||
| IGraph | |||
| All bug reports, feature request and patches are welcome. | |||
| == Installation | |||
| A working igraph library installation is required. | |||
| An IGraph gem is available as well as a package using setup.rb. In each case the installation requires the location of your igraph library to compile the extension. If you download the setup.rb package use these incantations: | |||
| An IGraph gem is available. The installation requires the location of your igraph headers and library to compile the extension. E.g. under Ubuntu linux: | |||
| ruby setup.rb config -- --with-igraph-dir=$R_HOME | |||
| ruby setup.rb setup | |||
| ruby setup.rb install | |||
| Using gems it is almost the same: | |||
| gem install igraph -- --with-igraph-dir=$R_HOME | |||
| gem install igraph -- --with-igraph-include=/usr/local/include/igraph | |||
| == Documentation | |||
| @@ -27,6 +21,8 @@ Here is a very quick and simple example: | |||
| require 'igraph' | |||
| graph = IGraph.new([],true) | |||
| graph.add_edges([1,2,3,4]) | |||
| graph.vcount # returns 4 | |||
| == License | |||
| @@ -38,23 +38,32 @@ VALUE cIGraph_alloc(VALUE klass){ | |||
| * Vertex 3 is connected to vertex 4. | |||
| */ | |||
| VALUE cIGraph_initialize(VALUE self, VALUE edges, VALUE directed){ | |||
| VALUE cIGraph_initialize(int argc, VALUE *argv, VALUE self){ | |||
| igraph_t *graph; | |||
| igraph_vector_t edge_v; | |||
| VALUE vertex; | |||
| VALUE object_h; | |||
| VALUE id_h; | |||
| VALUE directed; | |||
| VALUE edges; | |||
| VALUE attrs; | |||
| int vertex_n = 0; | |||
| int current_vertex_id; | |||
| int i; | |||
| rb_scan_args(argc,argv,"12", &edges, &directed, &attrs); | |||
| igraph_set_error_handler(cIGraph_error_handler); | |||
| igraph_set_warning_handler(cIGraph_warning_handler); | |||
| //igraph_i_set_attribute_table(&cIGraph_attribute_table); | |||
| //New hash for mapping vertex objects to floats used by iGraph | |||
| object_h = rb_iv_set(self,"@object_ids",rb_hash_new()); | |||
| id_h = rb_iv_set(self,"@id_objects",rb_hash_new()); | |||
| rb_iv_set(self,"@edge_attrs",rb_hash_new()); | |||
| //Initialize edge vector | |||
| igraph_vector_init_int(&edge_v,0); | |||
| @@ -63,8 +72,8 @@ VALUE cIGraph_initialize(VALUE self, VALUE edges, VALUE directed){ | |||
| igraph_to_undirected(graph,IGRAPH_TO_UNDIRECTED_COLLAPSE); | |||
| //Loop through objects in edge Array | |||
| vertex = rb_ary_shift(edges); | |||
| while(vertex != Qnil){ | |||
| for (i=0; i<RARRAY(edges)->len; i++) { | |||
| vertex = RARRAY(edges)->ptr[i]; | |||
| if(rb_funcall(object_h,rb_intern("has_key?"),1,vertex)){ | |||
| //If @vertices includes this vertex then look up the vertex number | |||
| current_vertex_id = NUM2INT(rb_hash_aref(object_h,vertex)); | |||
| @@ -76,7 +85,6 @@ VALUE cIGraph_initialize(VALUE self, VALUE edges, VALUE directed){ | |||
| vertex_n++; | |||
| } | |||
| igraph_vector_push_back(&edge_v,current_vertex_id); | |||
| vertex = rb_ary_shift(edges); | |||
| } | |||
| if(igraph_vector_size(&edge_v) > 0){ | |||
| @@ -84,6 +92,15 @@ VALUE cIGraph_initialize(VALUE self, VALUE edges, VALUE directed){ | |||
| igraph_add_edges(graph,&edge_v,0); | |||
| } | |||
| if(attrs != Qnil){ | |||
| for (i=0; i<RARRAY(attrs)->len; i++) { | |||
| cIGraph_set_edge_attr(self, | |||
| RARRAY(edges)->ptr[i*2], | |||
| RARRAY(edges)->ptr[(i*2)+1], | |||
| RARRAY(attrs)->ptr[i]); | |||
| } | |||
| } | |||
| igraph_vector_destroy(&edge_v); | |||
| return self; | |||
| @@ -100,7 +117,12 @@ void Init_igraph(){ | |||
| cIGraphError = rb_define_class("IGraphError", rb_eRuntimeError); | |||
| rb_define_alloc_func(cIGraph, cIGraph_alloc); | |||
| rb_define_method(cIGraph, "initialize", cIGraph_initialize, 2); | |||
| rb_define_method(cIGraph, "initialize", cIGraph_initialize, -1); | |||
| rb_define_method(cIGraph, "[]", cIGraph_get_edge_attr, 2); | |||
| rb_define_method(cIGraph, "[]=", cIGraph_set_edge_attr, 3); | |||
| rb_define_method(cIGraph, "get_edge_attr", cIGraph_get_edge_attr, 2); | |||
| rb_define_method(cIGraph, "set_edge_attr", cIGraph_set_edge_attr, 3); | |||
| rb_define_method(cIGraph, "each_vertex", cIGraph_each_vertex, 0); /* in cIGraph_iterators.c */ | |||
| rb_define_method(cIGraph, "each_edge", cIGraph_each_edge, 1); /* in cIGraph_iterators.c */ | |||
| @@ -145,16 +167,26 @@ void Init_igraph(){ | |||
| rb_define_method(cIGraph, "degree", cIGraph_degree,3); /* in cIGraph_basic_query.c */ | |||
| rb_define_method(cIGraph, "add_edges", cIGraph_add_edges, 1); /* in cIGraph_add_delete.c */ | |||
| rb_define_method(cIGraph, "add_edges", cIGraph_add_edges, -1); /* in cIGraph_add_delete.c */ | |||
| rb_define_method(cIGraph, "add_vertices", cIGraph_add_vertices, 1); /* in cIGraph_add_delete.c */ | |||
| rb_define_method(cIGraph, "add_edge", cIGraph_add_edge, 2); /* in cIGraph_add_delete.c */ | |||
| rb_define_method(cIGraph, "add_edge", cIGraph_add_edge, -1); /* in cIGraph_add_delete.c */ | |||
| rb_define_method(cIGraph, "add_vertex", cIGraph_add_vertex, 1); /* in cIGraph_add_delete.c */ | |||
| rb_define_method(cIGraph, "are_connected", cIGraph_are_connected,2); | |||
| rb_define_method(cIGraph, "are_connected?", cIGraph_are_connected,2); /* in cIGraph_basic_properties.c */ | |||
| rb_define_method(cIGraph, "shortest_paths", cIGraph_shortest_paths,2); | |||
| rb_define_method(cIGraph, "get_shortest_paths", cIGraph_get_shortest_paths,3); | |||
| rb_define_method(cIGraph, "shortest_paths", cIGraph_shortest_paths,2); /* in cIGraph_shortest_paths.c */ | |||
| rb_define_method(cIGraph, "get_shortest_paths", cIGraph_get_shortest_paths,3); /* in cIGraph_shortest_paths.c */ | |||
| rb_define_method(cIGraph, "get_all_shortest_paths", cIGraph_get_all_shortest_paths,3); /* in cIGraph_shortest_paths.c */ | |||
| rb_define_method(cIGraph, "average_path_length", cIGraph_average_path_length,2); /* in cIGraph_shortest_paths.c */ | |||
| 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, "neighbourhood_size", cIGraph_neighborhood_size, 3); /* in cIGraph_vertex_neighbourhood.c */ | |||
| rb_define_method(cIGraph, "neighborhood_size", cIGraph_neighborhood_size, 3); | |||
| rb_define_method(cIGraph, "neighbourhood", cIGraph_neighborhood, 3); /* in cIGraph_vertex_neighbourhood.c */ | |||
| rb_define_method(cIGraph, "neighborhood", cIGraph_neighborhood, 3); | |||
| rb_define_method(cIGraph, "neighbourhood_graphs", cIGraph_neighborhood_graphs, 3); /* in cIGraph_vertex_neighbourhood.c */ | |||
| rb_define_method(cIGraph, "neighborhood_graphs", cIGraph_neighborhood_graphs, 3);} | |||
| @@ -18,7 +18,11 @@ VALUE cIGraph_include(VALUE self, VALUE v); | |||
| void Init_igraph(void); | |||
| void cIGraph_free(void *p); | |||
| VALUE cIGraph_alloc(VALUE klass); | |||
| VALUE cIGraph_initialize(VALUE self, VALUE edges, VALUE directed); | |||
| VALUE cIGraph_initialize(int argc, VALUE *argv, VALUE self); | |||
| //Attribute accessors | |||
| VALUE cIGraph_get_edge_attr(VALUE self, VALUE from, VALUE to); | |||
| VALUE cIGraph_set_edge_attr(VALUE self, VALUE from, VALUE to, VALUE attr); | |||
| //Iterators | |||
| VALUE cIGraph_each_vertex (VALUE self); | |||
| @@ -45,16 +49,26 @@ VALUE cIGraph_is_directed(VALUE self); | |||
| VALUE cIGraph_degree (VALUE self, VALUE v, VALUE mode, VALUE loops); | |||
| //Adding and eleting vertices and edges | |||
| VALUE cIGraph_add_edges (VALUE self, VALUE edges); | |||
| VALUE cIGraph_add_edges (int argc, VALUE *argv, VALUE self); | |||
| VALUE cIGraph_add_edge (int argc, VALUE *argv, VALUE self); | |||
| VALUE cIGraph_add_vertices (VALUE self, VALUE vs); | |||
| VALUE cIGraph_delete_edges (VALUE self, VALUE edges); | |||
| VALUE cIGraph_delete_vertices(VALUE self, VALUE vs); | |||
| VALUE cIGraph_add_edge (VALUE self, VALUE from, VALUE to); | |||
| VALUE cIGraph_add_vertex (VALUE self, VALUE v); | |||
| //Basic properties | |||
| VALUE cIGraph_are_connected(VALUE self, VALUE from, VALUE to); | |||
| //Shortest Path Related Functions | |||
| VALUE cIGraph_shortest_paths (VALUE self, VALUE from, VALUE mode); | |||
| VALUE cIGraph_get_shortest_paths(VALUE self, VALUE from, VALUE to, VALUE mode); | |||
| VALUE cIGraph_shortest_paths (VALUE self, VALUE from, VALUE mode); | |||
| VALUE cIGraph_get_shortest_paths (VALUE self, VALUE from, VALUE to, VALUE mode); | |||
| VALUE cIGraph_get_all_shortest_paths(VALUE self, VALUE from, VALUE to, VALUE mode); | |||
| 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); | |||
| //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); | |||
| VALUE cIGraph_neighborhood_graphs(VALUE self, VALUE from, VALUE order, VALUE mode); | |||
| @@ -19,14 +19,19 @@ | |||
| * must have already been added to the graph before they can be used in | |||
| * an edge (throws a IGraphError otherwise). | |||
| */ | |||
| VALUE cIGraph_add_edges(VALUE self, VALUE edges){ | |||
| VALUE cIGraph_add_edges(int argc, VALUE *argv, VALUE self){ | |||
| igraph_t *graph; | |||
| igraph_vector_t edge_v; | |||
| VALUE vertex; | |||
| VALUE object_h; | |||
| VALUE edges; | |||
| VALUE attrs; | |||
| int vid; | |||
| int code = 0; | |||
| int i; | |||
| rb_scan_args(argc, argv, "11", &edges, &attrs); | |||
| //Initialize edge vector | |||
| igraph_vector_init_int(&edge_v,0); | |||
| @@ -35,8 +40,8 @@ VALUE cIGraph_add_edges(VALUE self, VALUE edges){ | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| //Loop through objects in edge Array | |||
| vertex = rb_ary_shift(edges); | |||
| while(vertex != Qnil){ | |||
| for (i=0; i<RARRAY(edges)->len; i++) { | |||
| vertex = RARRAY(edges)->ptr[i]; | |||
| if(rb_funcall(object_h,rb_intern("has_key?"),1,vertex)){ | |||
| //If @vertices includes this vertex then look up the vertex number | |||
| vid = NUM2INT(rb_hash_aref(object_h,vertex)); | |||
| @@ -44,13 +49,21 @@ VALUE cIGraph_add_edges(VALUE self, VALUE edges){ | |||
| rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices first"); | |||
| } | |||
| igraph_vector_push_back(&edge_v,vid); | |||
| vertex = rb_ary_shift(edges); | |||
| } | |||
| if(igraph_vector_size(&edge_v) > 0){ | |||
| code = igraph_add_edges(graph,&edge_v,0); | |||
| } | |||
| if(attrs != Qnil){ | |||
| for (i=0; i<RARRAY(attrs)->len; i++) { | |||
| cIGraph_set_edge_attr(self, | |||
| RARRAY(edges)->ptr[i*2], | |||
| RARRAY(edges)->ptr[(i*2)+1], | |||
| RARRAY(attrs)->ptr[i]); | |||
| } | |||
| } | |||
| igraph_vector_destroy(&edge_v); | |||
| return INT2NUM(code); | |||
| @@ -81,6 +94,7 @@ VALUE cIGraph_add_vertices(VALUE self, VALUE vs){ | |||
| int vertex_n; | |||
| int code = 0; | |||
| int length; | |||
| int i; | |||
| object_h = rb_iv_get(self,"@object_ids"); | |||
| id_h = rb_iv_get(self,"@id_objects"); | |||
| @@ -90,8 +104,8 @@ VALUE cIGraph_add_vertices(VALUE self, VALUE vs){ | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| //Loop through objects in vertex array | |||
| vertex = rb_ary_shift(vs); | |||
| while(vertex != Qnil){ | |||
| for (i=0; i<RARRAY(vs)->len; i++) { | |||
| vertex = RARRAY(vs)->ptr[i]; | |||
| if(rb_funcall(object_h,rb_intern("has_key?"),1,vertex)){ | |||
| //If @vertices includes this vertex then raise an error | |||
| //Silently ignore | |||
| @@ -103,7 +117,6 @@ VALUE cIGraph_add_vertices(VALUE self, VALUE vs){ | |||
| rb_hash_aset(id_h, INT2NUM(vertex_n),vertex); | |||
| vertex_n++; | |||
| } | |||
| vertex = rb_ary_shift(vs); | |||
| } | |||
| code = igraph_add_vertices(graph,length,0); | |||
| @@ -127,13 +140,18 @@ VALUE cIGraph_add_vertices(VALUE self, VALUE vs){ | |||
| * Note that vertices must have already been added to the graph before | |||
| * they can be used in an edge (throws a IGraphError otherwise). | |||
| */ | |||
| VALUE cIGraph_add_edge(VALUE self, VALUE from, VALUE to){ | |||
| VALUE cIGraph_add_edge(int argc, VALUE *argv, VALUE self){ | |||
| igraph_t *graph; | |||
| igraph_vector_t edge_v; | |||
| VALUE object_h; | |||
| int vid; | |||
| int code = 0; | |||
| VALUE from; | |||
| VALUE to; | |||
| VALUE attr; | |||
| rb_scan_args(argc, argv, "21", &from, &to, &attr); | |||
| //Initialize edge vector | |||
| igraph_vector_init_int(&edge_v,0); | |||
| @@ -159,6 +177,10 @@ VALUE cIGraph_add_edge(VALUE self, VALUE from, VALUE to){ | |||
| code = igraph_add_edges(graph,&edge_v,0); | |||
| if(attr != Qnil){ | |||
| cIGraph_set_edge_attr(self, from, to, attr); | |||
| } | |||
| igraph_vector_destroy(&edge_v); | |||
| return INT2NUM(code); | |||
| @@ -184,7 +206,6 @@ VALUE cIGraph_add_edge(VALUE self, VALUE from, VALUE to){ | |||
| VALUE cIGraph_add_vertex(VALUE self, VALUE v){ | |||
| igraph_t *graph; | |||
| VALUE vertex; | |||
| VALUE object_h; | |||
| VALUE id_h; | |||
| int vertex_n; | |||
| @@ -0,0 +1,47 @@ | |||
| #include "igraph.h" | |||
| #include "ruby.h" | |||
| #include "cIGraph.h" | |||
| igraph_attribute_table_t cIGraph_attribute_table; | |||
| int cIGraph_add_edges_attr(igraph_t *graph, const igraph_vector_t *edges, | |||
| igraph_vector_ptr_t *attr){ | |||
| return 0; | |||
| } | |||
| int cIGraph_get_numeric_edge_attr(const igraph_t *graph, const char *name, | |||
| igraph_es_t es, | |||
| igraph_vector_t *value){ | |||
| return 0; | |||
| } | |||
| int cIGraph_get_string_edge_attr(const igraph_t *graph, const char *name, | |||
| igraph_es_t es, | |||
| igraph_strvector_t *value){ | |||
| return 0; | |||
| } | |||
| VALUE cIGraph_get_edge_attr(VALUE self, VALUE from, VALUE to){ | |||
| VALUE eid; | |||
| VALUE attr_hash; | |||
| eid = cIGraph_get_eid(self, from, to, 1); | |||
| attr_hash = rb_iv_get(self,"@edge_attrs"); | |||
| return rb_hash_aref(attr_hash,eid); | |||
| } | |||
| VALUE cIGraph_set_edge_attr(VALUE self, VALUE from, VALUE to, VALUE attr){ | |||
| VALUE eid; | |||
| VALUE attr_hash; | |||
| eid = cIGraph_get_eid(self, from, to, 1); | |||
| attr_hash = rb_iv_get(self,"@edge_attrs"); | |||
| rb_hash_aset(attr_hash,eid,attr); | |||
| return Qnil; | |||
| } | |||
| @@ -2,6 +2,17 @@ | |||
| #include "ruby.h" | |||
| #include "cIGraph.h" | |||
| /* call-seq: | |||
| * graph.shortest_paths(varray,mode) -> 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. 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_shortest_paths(VALUE self, VALUE from, VALUE mode){ | |||
| igraph_t *graph; | |||
| @@ -49,6 +60,17 @@ VALUE cIGraph_shortest_paths(VALUE self, VALUE from, VALUE mode){ | |||
| } | |||
| /* call-seq: | |||
| * graph.get_shortest_paths(from,to_array,mode) -> 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_shortest_paths(VALUE self, VALUE from, VALUE to, VALUE mode){ | |||
| igraph_t *graph; | |||
| @@ -70,7 +92,7 @@ VALUE cIGraph_get_shortest_paths(VALUE self, VALUE from, VALUE to, VALUE mode){ | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| n_paths = NUM2INT(rb_funcall(to,rb_intern("length"),0)); | |||
| n_paths = RARRAY(to)->len; | |||
| //vector to hold the results of the calculations | |||
| igraph_vector_ptr_init(&res,0); | |||
| @@ -93,8 +115,8 @@ VALUE cIGraph_get_shortest_paths(VALUE self, VALUE from, VALUE to, VALUE mode){ | |||
| for(i=0; i<n_paths; i++){ | |||
| path = rb_ary_new(); | |||
| rb_ary_push(matrix,path); | |||
| path_v = VECTOR(res)[i]; | |||
| for(j=0; j<igraph_vector_size(VECTOR(res)[i]); j++){ | |||
| path_v = VECTOR(res)[i]; | |||
| rb_ary_push(path,cIGraph_get_vertex_object(self,VECTOR(*path_v)[j])); | |||
| } | |||
| } | |||
| @@ -110,3 +132,175 @@ VALUE cIGraph_get_shortest_paths(VALUE self, VALUE from, VALUE to, VALUE mode){ | |||
| return matrix; | |||
| } | |||
| /* call-seq: | |||
| * graph.get_all_shortest_paths(from,mode) -> Array | |||
| * | |||
| * Calculates the paths from the vertex specified as from to each vertex | |||
| * in the to_array Arrayevery other. 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. In contrast to | |||
| * IGraph#get_shortest_paths all possible shortest paths are reported here. | |||
| */ | |||
| VALUE cIGraph_get_all_shortest_paths(VALUE self, VALUE from, VALUE to, VALUE mode){ | |||
| igraph_t *graph; | |||
| igraph_integer_t from_vid; | |||
| igraph_neimode_t pmode = NUM2INT(mode); | |||
| igraph_vs_t to_vids; | |||
| igraph_vector_t to_vidv; | |||
| igraph_vector_ptr_t res; | |||
| igraph_vector_t *path_v; | |||
| int i; | |||
| int j; | |||
| VALUE path; | |||
| VALUE matrix = rb_ary_new(); | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| //vector to hold the results of the calculations | |||
| igraph_vector_ptr_init(&res,0); | |||
| //The id of the vertex from where we are counting | |||
| from_vid = cIGraph_get_vertex_id(self, from); | |||
| //Convert an array of vertices to a vector of vertex ids | |||
| cIGraph_vertex_arr_to_id_vec(self,to,&to_vidv); | |||
| //create vertex selector from the vecotr of ids | |||
| igraph_vs_vector(&to_vids,&to_vidv); | |||
| igraph_get_all_shortest_paths(graph,&res,NULL,from_vid,to_vids,pmode); | |||
| for(i=0; i< igraph_vector_ptr_size(&res); i++){ | |||
| path = rb_ary_new(); | |||
| rb_ary_push(matrix,path); | |||
| for(j=0; j<igraph_vector_size(VECTOR(res)[i]); j++){ | |||
| path_v = VECTOR(res)[i]; | |||
| rb_ary_push(path,cIGraph_get_vertex_object(self,VECTOR(*path_v)[j])); | |||
| } | |||
| } | |||
| for(i=0;i<igraph_vector_ptr_size(&res);i++){ | |||
| igraph_vector_destroy(VECTOR(res)[i]); | |||
| } | |||
| igraph_vector_ptr_destroy(&res); | |||
| return matrix; | |||
| } | |||
| /* call-seq: | |||
| * graph.average_path_length(directed,uncon) -> Float | |||
| * | |||
| * Calculates the average geodesic length in a graph. directed should be a | |||
| * boolean specifying whether to consider directed paths. unconn is another | |||
| * boolean specifying what to do about unconnected graphs. If TRUE the | |||
| * average of the geodesics within the components will be returned, | |||
| * otherwise the number of vertices is used for the length of non-existing | |||
| * geodesics. (The rationale behind this is that this is always longer than | |||
| * the longest possible geodesic in a graph.) | |||
| */ | |||
| VALUE cIGraph_average_path_length(VALUE self, VALUE directed, VALUE unconn){ | |||
| igraph_t *graph; | |||
| igraph_bool_t directed_b = 0; | |||
| igraph_bool_t unconn_b = 0; | |||
| igraph_real_t res; | |||
| if(directed) | |||
| directed_b = 1; | |||
| if(unconn) | |||
| unconn_b = 1; | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| igraph_average_path_length(graph,&res,directed_b,unconn_b); | |||
| return rb_float_new(res); | |||
| } | |||
| /* call-seq: | |||
| * graph.diameter(directed,uncon) -> Array | |||
| * | |||
| * Returns the longest path in the graph. directed should be a | |||
| * boolean specifying whether to consider directed paths. unconn is another | |||
| * boolean specifying what to do about unconnected graphs. If TRUE the | |||
| * average of the geodesics within the components will be returned, | |||
| * otherwise the number of vertices is used for the length of non-existing | |||
| * geodesics. (The rationale behind this is that this is always longer than | |||
| * the longest possible diamter in a graph.) | |||
| */ | |||
| VALUE cIGraph_diameter(VALUE self, VALUE directed, VALUE unconn){ | |||
| igraph_t *graph; | |||
| igraph_bool_t directed_b = 0; | |||
| igraph_bool_t unconn_b = 0; | |||
| igraph_vector_t res; | |||
| int i; | |||
| VALUE path = rb_ary_new(); | |||
| if(directed) | |||
| directed_b = 1; | |||
| if(unconn) | |||
| unconn_b = 1; | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| //vector to hold the results of the calculations | |||
| igraph_vector_init(&res,0); | |||
| igraph_diameter(graph,NULL,NULL,NULL,&res,directed_b,unconn_b); | |||
| for(i=0; i<igraph_vector_size(&res); i++){ | |||
| rb_ary_push(path,cIGraph_get_vertex_object(self,VECTOR(res)[i])); | |||
| } | |||
| igraph_vector_destroy(&res); | |||
| return path; | |||
| } | |||
| /* call-seq: | |||
| * graph.diameter(directed,uncon) -> Array | |||
| * | |||
| * Returns the shortest cycle in the graph. directed should be a | |||
| * boolean specifying whether to consider directed paths. unconn is another | |||
| * boolean specifying what to do about unconnected graphs. If TRUE the | |||
| * average of the geodesics within the components will be returned, | |||
| * otherwise the number of vertices is used for the length of non-existing | |||
| * geodesics. (The rationale behind this is that this is always longer than | |||
| * the longest possible diamter in a graph.) | |||
| */ | |||
| VALUE cIGraph_girth(VALUE self){ | |||
| igraph_t *graph; | |||
| igraph_vector_t res; | |||
| int i; | |||
| VALUE path = rb_ary_new(); | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| //vector to hold the results of the calculations | |||
| igraph_vector_init(&res,0); | |||
| igraph_girth(graph,NULL,&res); | |||
| for(i=0; i<igraph_vector_size(&res); i++){ | |||
| rb_ary_push(path,cIGraph_get_vertex_object(self,VECTOR(res)[i])); | |||
| } | |||
| igraph_vector_destroy(&res); | |||
| return path; | |||
| } | |||
| @@ -32,6 +32,7 @@ int cIGraph_vertex_arr_to_id_vec(VALUE graph, VALUE va, igraph_vector_t *nv){ | |||
| VALUE vertex; | |||
| VALUE tmp; | |||
| VALUE i; | |||
| tmp = rb_check_array_type(va); | |||
| @@ -40,10 +41,9 @@ int cIGraph_vertex_arr_to_id_vec(VALUE graph, VALUE va, igraph_vector_t *nv){ | |||
| //Initialize edge vector | |||
| igraph_vector_init_int(nv,0); | |||
| vertex = rb_ary_shift(va); | |||
| while(vertex != Qnil){ | |||
| for (i=0; i<RARRAY(va)->len; i++) { | |||
| vertex = RARRAY(va)->ptr[i]; | |||
| igraph_vector_push_back(nv,cIGraph_get_vertex_id(graph, vertex)); | |||
| vertex = rb_ary_shift(va); | |||
| } | |||
| return 0; | |||
| @@ -0,0 +1,155 @@ | |||
| #include "igraph.h" | |||
| #include "ruby.h" | |||
| #include "cIGraph.h" | |||
| /* call-seq: | |||
| * graph.neighbourhood_size(vertices,order,mode) -> 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. 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_neighborhood_size(VALUE self, VALUE from, VALUE order, VALUE mode){ | |||
| igraph_t *graph; | |||
| igraph_vs_t vids; | |||
| igraph_vector_t vidv; | |||
| igraph_neimode_t pmode = NUM2INT(mode); | |||
| igraph_vector_t res; | |||
| int i; | |||
| VALUE sizes = 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 | |||
| cIGraph_vertex_arr_to_id_vec(self,from,&vidv); | |||
| //create vertex selector from the vecotr of ids | |||
| igraph_vs_vector(&vids,&vidv); | |||
| igraph_neighborhood_size(graph,&res,vids,NUM2INT(order),pmode); | |||
| for(i=0; i<igraph_vector_size(&res); i++){ | |||
| rb_ary_push(sizes,INT2NUM(VECTOR(res)[i])); | |||
| } | |||
| igraph_vector_destroy(&vidv); | |||
| igraph_vector_destroy(&res); | |||
| igraph_vs_destroy(&vids); | |||
| return sizes; | |||
| } | |||
| /* call-seq: | |||
| * graph.neighbourhood(vertices,order,mode) -> 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. 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_neighborhood(VALUE self, VALUE from, VALUE order, VALUE mode){ | |||
| igraph_t *graph; | |||
| igraph_vs_t vids; | |||
| igraph_vector_t vidv; | |||
| igraph_neimode_t pmode = NUM2INT(mode); | |||
| igraph_vector_ptr_t res; | |||
| igraph_vector_t *path_v; | |||
| int i; | |||
| int j; | |||
| VALUE matrix = rb_ary_new(); | |||
| VALUE neighbourhood; | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| igraph_vector_ptr_init(&res,0); | |||
| //Convert an array of vertices to a vector of vertex ids | |||
| cIGraph_vertex_arr_to_id_vec(self,from,&vidv); | |||
| //create vertex selector from the vecotr of ids | |||
| igraph_vs_vector(&vids,&vidv); | |||
| igraph_neighborhood(graph,&res,vids,NUM2INT(order),pmode); | |||
| for(i=0; i<igraph_vector_ptr_size(&res); i++){ | |||
| neighbourhood = rb_ary_new(); | |||
| rb_ary_push(matrix,neighbourhood); | |||
| path_v = VECTOR(res)[i]; | |||
| for(j=0; j<igraph_vector_size(VECTOR(res)[i]); j++){ | |||
| rb_ary_push(neighbourhood,cIGraph_get_vertex_object(self,VECTOR(*path_v)[j])); | |||
| } | |||
| } | |||
| for(i=0;i<igraph_vector_ptr_size(&res);i++){ | |||
| igraph_vector_destroy(VECTOR(res)[i]); | |||
| } | |||
| igraph_vector_destroy(&vidv); | |||
| igraph_vector_ptr_destroy(&res); | |||
| igraph_vs_destroy(&vids); | |||
| return matrix; | |||
| } | |||
| /* call-seq: | |||
| * graph.neighbourhood_graph(vertices,order,mode) -> 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. 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_neighborhood_graphs(VALUE self, VALUE from, VALUE order, VALUE mode){ | |||
| igraph_t *graph; | |||
| igraph_vs_t vids; | |||
| igraph_vector_t vidv; | |||
| igraph_neimode_t pmode = NUM2INT(mode); | |||
| igraph_vector_ptr_t res; | |||
| igraph_vector_t *path_v; | |||
| int i; | |||
| VALUE result = rb_ary_new(); | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| igraph_vector_ptr_init(&res,0); | |||
| //Convert an array of vertices to a vector of vertex ids | |||
| cIGraph_vertex_arr_to_id_vec(self,from,&vidv); | |||
| //create vertex selector from the vecotr of ids | |||
| igraph_vs_vector(&vids,&vidv); | |||
| igraph_neighborhood_graphs(graph,&res,vids,NUM2INT(order),pmode); | |||
| for(i=0; i<igraph_vector_ptr_size(&res); i++){ | |||
| rb_ary_push(result,cIGraph_create_derived_graph(self,VECTOR(res)[i]); | |||
| } | |||
| igraph_vector_destroy(&vidv); | |||
| igraph_vector_ptr_destroy(&res); | |||
| igraph_vs_destroy(&vids); | |||
| return result; | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_get_attributes | |||
| graph = IGraph.new(['A','B','C','D'],true,[1,2]) | |||
| assert_equal 2, graph.get_edge_attr('C','D') | |||
| assert_equal 2, graph['C','D'] | |||
| end | |||
| def test_set_attributes | |||
| graph = IGraph.new(['A','B','C','D'],true,[1,2]) | |||
| graph.set_edge_attr('C','D',3) | |||
| assert_equal 3, graph.get_edge_attr('C','D') | |||
| graph['C','D'] = 4 | |||
| assert_equal 4, graph['C','D'] | |||
| end | |||
| def test_new_edges | |||
| graph = IGraph.new(['A','B','C','D'],true,[1,2]) | |||
| graph.add_edges(['A','C'],[3]) | |||
| assert_equal 3, graph['A','C'] | |||
| graph.add_edge('A','D',4) | |||
| assert_equal 4, graph['A','D'] | |||
| end | |||
| end | |||
| @@ -18,4 +18,27 @@ class TestGraph < Test::Unit::TestCase | |||
| assert_equal [], m[1] | |||
| end | |||
| def test_get_all_shortest_paths | |||
| graph = IGraph.new(['A','B','A','C','B','D','C','D'],true) | |||
| m = graph.get_all_shortest_paths('A',['D'],IGraph::ALL) | |||
| assert_equal 2, m.length | |||
| end | |||
| def test_average_path_length | |||
| graph = IGraph.new(['A','B','A','C','B','D','C','D'],true) | |||
| m = graph.average_path_length(true,true) | |||
| assert_equal 1.2, m | |||
| end | |||
| def test_diameter_girth | |||
| graph = IGraph.new(['A','B','A','C','B','D'],true) | |||
| m = graph.diameter(true,true) | |||
| assert_equal 3, m.length | |||
| assert_raises IGraphError do | |||
| graph.girth | |||
| end | |||
| graph = IGraph.new(['A','B','A','C','B','D','C','D'],true) | |||
| assert_equal 4, graph.girth.length | |||
| end | |||
| end | |||
| @@ -0,0 +1,16 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_neighbourhood_size | |||
| graph = IGraph.new(['A','B','C','D'],true) | |||
| assert_equal [1], graph.neighbourhood_size(['A'],0,IGraph::ALL) | |||
| assert_equal [2], graph.neighbourhood_size(['A'],1,IGraph::ALL) | |||
| end | |||
| def test_neighbourhood | |||
| graph = IGraph.new(['A','B','B','C','C','D'],true) | |||
| assert_equal [['A']], graph.neighborhood(['A'],0,IGraph::ALL) | |||
| assert_equal [['A','B']], graph.neighborhood(['A'],1,IGraph::ALL) | |||
| assert_equal [['A','B','C']], graph.neighborhood(['A'],2,IGraph::ALL) | |||
| end | |||
| end | |||
| @@ -2,6 +2,7 @@ | |||
| require 'test/unit' | |||
| require 'tc_attributes' | |||
| require 'tc_create' | |||
| require 'tc_iterators' | |||
| require 'tc_selectors' | |||
| @@ -10,3 +11,4 @@ require 'tc_basic_query' | |||
| require 'tc_basic_properties' | |||
| require 'tc_error_handling' | |||
| require 'tc_shortest_paths' | |||
| require 'tc_vertex_neighbourhood' | |||