diff --git a/Manifest.txt b/Manifest.txt index 538a466..8ef5074 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -11,6 +11,8 @@ ext/cIGraph_basic_query.c ext/cIGraph_error_handlers.c ext/cIGraph_file.c ext/cIGraph_iterators.c +ext/cIGraph_layout.c +ext/cIGraph_matrix.c ext/cIGraph_operators.c ext/cIGraph_selectors.c ext/cIGraph_shortest_paths.c @@ -21,10 +23,13 @@ test/tc_add_delete.rb test/tc_attributes.rb test/tc_basic_properties.rb test/tc_basic_query.rb +test/tc_copy.rb test/tc_create.rb test/tc_error_handling.rb test/tc_file_read_write.rb test/tc_iterators.rb +test/tc_layout.rb +test/tc_matrix.rb test/tc_selectors.rb test/tc_shortest_paths.rb test/tc_topological_sort.rb diff --git a/Rakefile.rb b/Rakefile.rb index bd8f3ae..dab177e 100644 --- a/Rakefile.rb +++ b/Rakefile.rb @@ -2,7 +2,14 @@ require 'hoe' $LOAD_PATH.unshift("./ext") -require 'igraph' +class IGraph + VERSION = "0.0" +end + +begin + require 'igraph' +rescue RuntimeError +end hoe = Hoe.new("igraph",IGraph::VERSION) do |p| diff --git a/ext/cIGraph.c b/ext/cIGraph.c index 42663c1..ecd25e6 100644 --- a/ext/cIGraph.c +++ b/ext/cIGraph.c @@ -13,6 +13,7 @@ void cIGraph_free(void *p){ void cIGraph_mark(void *p){ rb_gc_mark(((VALUE*)((igraph_t*)p)->attr)[0]); rb_gc_mark(((VALUE*)((igraph_t*)p)->attr)[1]); + rb_gc_mark(((VALUE*)((igraph_t*)p)->attr)[2]); } VALUE cIGraph_alloc(VALUE klass){ @@ -89,6 +90,16 @@ VALUE cIGraph_initialize(int argc, VALUE *argv, VALUE self){ igraph_vector_ptr_t vertex_attr; igraph_vector_ptr_t edge_attr; + igraph_i_attribute_record_t v_attr_rec; + v_attr_rec.name = "__RUBY__"; + v_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT; + v_attr_rec.value = (void*)rb_ary_new(); + + igraph_i_attribute_record_t e_attr_rec; + e_attr_rec.name = "__RUBY__"; + e_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT; + e_attr_rec.value = (void*)rb_ary_new(); + rb_scan_args(argc,argv,"12", &edges, &directed, &attrs); //Initialize edge vector @@ -117,19 +128,22 @@ VALUE cIGraph_initialize(int argc, VALUE *argv, VALUE self){ vertex_n++; //Add object to list of vertex attributes - igraph_vector_ptr_push_back(&vertex_attr,(void*)vertex); + rb_ary_push((VALUE)v_attr_rec.value,vertex); } igraph_vector_push_back(&edge_v,current_vertex_id); if (i % 2){ if (attrs != Qnil){ - igraph_vector_ptr_push_back(&edge_attr,(void*)RARRAY(attrs)->ptr[i/2]); + rb_ary_push((VALUE)e_attr_rec.value,RARRAY(attrs)->ptr[i/2]); } else { - igraph_vector_ptr_push_back(&edge_attr,(void*)Qnil); + rb_ary_push((VALUE)e_attr_rec.value,Qnil); } } } + igraph_vector_ptr_push_back(&vertex_attr, &v_attr_rec); + igraph_vector_ptr_push_back(&edge_attr, &e_attr_rec); + if(igraph_vector_size(&edge_v) > 0){ igraph_add_vertices(graph,vertex_n,&vertex_attr); igraph_add_edges(graph,&edge_v,&edge_attr); @@ -179,6 +193,8 @@ void Init_igraph(){ rb_define_alias (cIGraph, "get_edge_attr", "[]"); rb_define_alias (cIGraph, "set_edge_attr", "[]="); + rb_define_method(cIGraph, "attributes", cIGraph_graph_attributes, 0); /* in cIGraph_attribute_handler.c */ + 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 */ rb_define_method(cIGraph, "each_edge_eid", cIGraph_each_edge_eid,1); /* in cIGraph_iterators.c */ @@ -231,7 +247,11 @@ void Init_igraph(){ 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 */ + rb_define_singleton_method(cIGraph, "read_graph_graphml", cIGraph_read_graph_graphml, 2); /* in cIGraph_file.c */ + rb_define_singleton_method(cIGraph, "read_graph_pajek", cIGraph_read_graph_pajek, 2); /* in cIGraph_file.c */ rb_define_method(cIGraph, "write_graph_edgelist", cIGraph_write_graph_edgelist, 1); /* in cIGraph_file.c */ + rb_define_method(cIGraph, "write_graph_graphml", cIGraph_write_graph_graphml, 1); /* in cIGraph_file.c */ + rb_define_method(cIGraph, "write_graph_pajek", cIGraph_write_graph_pajek, 1); /* in cIGraph_file.c */ rb_define_method(cIGraph, "layout_random", cIGraph_layout_random, 0); rb_define_method(cIGraph, "layout_circle", cIGraph_layout_circle, 0); diff --git a/ext/cIGraph.h b/ext/cIGraph.h index 3ae7de9..fd0e8f5 100644 --- a/ext/cIGraph.h +++ b/ext/cIGraph.h @@ -1,3 +1,9 @@ +#include "math.h" +#include "ruby.h" +#include "igraph.h" + +//#define DEBUG + //Classes extern VALUE cIGraph; extern VALUE cIGraphError; @@ -25,8 +31,11 @@ VALUE cIGraph_initialize(int argc, VALUE *argv, VALUE self); VALUE cIGraph_init_copy(VALUE copy, VALUE orig); //Attribute accessors +int replace_i(VALUE key, VALUE val, VALUE hash); VALUE cIGraph_get_edge_attr(VALUE self, VALUE from, VALUE to); VALUE cIGraph_set_edge_attr(VALUE self, VALUE from, VALUE to, VALUE attr); +VALUE cIGraph_graph_attributes(VALUE self); +igraph_i_attribute_record_t cIGraph_create_record(VALUE v); //Iterators VALUE cIGraph_each_vertex (VALUE self); @@ -83,7 +92,10 @@ VALUE cIGraph_topological_sorting(VALUE self, VALUE mode); //File handling VALUE cIGraph_read_graph_edgelist (VALUE self, VALUE file, VALUE mode); VALUE cIGraph_write_graph_edgelist(VALUE self, VALUE file); - +VALUE cIGraph_read_graph_graphml (VALUE self, VALUE file, VALUE index); +VALUE cIGraph_write_graph_graphml (VALUE self, VALUE file); +VALUE cIGraph_read_graph_pajek (VALUE self, VALUE file); +VALUE cIGraph_write_graph_pajek (VALUE self, VALUE file); //Layouts VALUE cIGraph_layout_random(VALUE self); diff --git a/ext/cIGraph_add_delete.c b/ext/cIGraph_add_delete.c index 582b9b0..ebc72ab 100644 --- a/ext/cIGraph_add_delete.c +++ b/ext/cIGraph_add_delete.c @@ -32,6 +32,11 @@ VALUE cIGraph_add_edges(int argc, VALUE *argv, VALUE self){ int i; igraph_vector_ptr_t edge_attr; + igraph_i_attribute_record_t e_attr_rec; + e_attr_rec.name = "__RUBY__"; + e_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT; + e_attr_rec.value = (void*)rb_ary_new(); + rb_scan_args(argc, argv, "11", &edges, &attrs); //Initialize edge vector @@ -53,13 +58,15 @@ VALUE cIGraph_add_edges(int argc, VALUE *argv, VALUE self){ igraph_vector_push_back(&edge_v,vid); if (i % 2){ if (attrs != Qnil){ - igraph_vector_ptr_push_back(&edge_attr,(void*)RARRAY(attrs)->ptr[i/2]); + rb_ary_push((VALUE)e_attr_rec.value,RARRAY(attrs)->ptr[i/2]); } else { - igraph_vector_ptr_push_back(&edge_attr,(void*)Qnil); + rb_ary_push((VALUE)e_attr_rec.value,Qnil); } } } + igraph_vector_ptr_push_back(&edge_attr, &e_attr_rec); + if(igraph_vector_size(&edge_v) > 0){ code = igraph_add_edges(graph,&edge_v,&edge_attr); } @@ -96,6 +103,11 @@ VALUE cIGraph_add_vertices(VALUE self, VALUE vs){ int i; igraph_vector_ptr_t vertex_attr; + igraph_i_attribute_record_t v_attr_rec; + v_attr_rec.name = "__RUBY__"; + v_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT; + v_attr_rec.value = (void*)rb_ary_new(); + igraph_vector_ptr_init(&vertex_attr,0); Data_Get_Struct(self, igraph_t, graph); @@ -111,10 +123,12 @@ VALUE cIGraph_add_vertices(VALUE self, VALUE vs){ //rb_raise(cIGraphError, "Vertex already added to graph"); to_add--; } else { - igraph_vector_ptr_push_back(&vertex_attr,(void*)RARRAY(vs)->ptr[i]); + rb_ary_push((VALUE)v_attr_rec.value,RARRAY(vs)->ptr[i]); } } + igraph_vector_ptr_push_back(&vertex_attr,&v_attr_rec); + code = igraph_add_vertices(graph,to_add,&vertex_attr); return INT2NUM(code); @@ -150,6 +164,11 @@ VALUE cIGraph_add_edge(int argc, VALUE *argv, VALUE self){ VALUE to; VALUE attr; + igraph_i_attribute_record_t e_attr_rec; + e_attr_rec.name = "__RUBY__"; + e_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT; + e_attr_rec.value = (void*)rb_ary_new(); + rb_scan_args(argc, argv, "21", &from, &to, &attr); //Initialize edge vector @@ -164,11 +183,13 @@ VALUE cIGraph_add_edge(int argc, VALUE *argv, VALUE self){ //If graph includes this vertex then look up the vertex number igraph_vector_push_back(&edge_v,cIGraph_get_vertex_id(self, from)); igraph_vector_push_back(&edge_v,cIGraph_get_vertex_id(self, to)); - igraph_vector_ptr_push_back(&edge_attr,(void*)attr); + rb_ary_push((VALUE)e_attr_rec.value,attr); } else { rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices"); } + igraph_vector_ptr_push_back(&edge_attr,&e_attr_rec); + code = igraph_add_edges(graph,&edge_v,&edge_attr); igraph_vector_ptr_destroy(&edge_attr); @@ -203,6 +224,11 @@ VALUE cIGraph_add_vertex(VALUE self, VALUE v){ VALUE v_ary; + igraph_i_attribute_record_t v_attr_rec; + v_attr_rec.name = "__RUBY__"; + v_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT; + v_attr_rec.value = (void*)rb_ary_new(); + igraph_vector_ptr_init(&vertex_attr,0); Data_Get_Struct(self, igraph_t, graph); @@ -214,9 +240,11 @@ VALUE cIGraph_add_vertex(VALUE self, VALUE v){ //rb_raise(cIGraphError, "Vertex already added to graph"); return code; } else { - igraph_vector_ptr_push_back(&vertex_attr,(void*)v); + rb_ary_push((VALUE)v_attr_rec.value,v); } + igraph_vector_ptr_push_back(&vertex_attr,&v_attr_rec); + code = igraph_add_vertices(graph,1,&vertex_attr); return INT2NUM(code); diff --git a/ext/cIGraph_attribute_handler.c b/ext/cIGraph_attribute_handler.c index 2c362ab..999258b 100644 --- a/ext/cIGraph_attribute_handler.c +++ b/ext/cIGraph_attribute_handler.c @@ -44,6 +44,18 @@ VALUE cIGraph_set_edge_attr(VALUE self, VALUE from, VALUE to, VALUE attr){ } +VALUE cIGraph_graph_attributes(VALUE self){ + + igraph_t *graph; + VALUE hsh; + + Data_Get_Struct(self, igraph_t, graph); + hsh = ((VALUE*)graph->attr)[2]; + + return hsh; + +} + igraph_attribute_table_t cIGraph_attribute_table = { cIGraph_attribute_init, cIGraph_attribute_destroy, @@ -67,16 +79,44 @@ igraph_attribute_table_t cIGraph_attribute_table = { int cIGraph_attribute_init(igraph_t *graph, igraph_vector_ptr_t *attr) { VALUE* attrs; + int i; + VALUE key; + VALUE value; - //attrs = (VALUE*)calloc(2, sizeof(VALUE)); - attrs = ALLOC_N(VALUE, 2); + attrs = ALLOC_N(VALUE, 3); if(!attrs) IGRAPH_ERROR("Error allocating Arrays\n", IGRAPH_ENOMEM); - //[0] is vertex array, [1] is edge array + //[0] is vertex array, [1] is edge array, [2] is graph attr attrs[0] = rb_ary_new(); attrs[1] = rb_ary_new(); + attrs[2] = rb_hash_new(); + + if(attr){ + for(i=0;iname); + switch (attr_rec->type) { + case IGRAPH_ATTRIBUTE_NUMERIC: + value=rb_float_new((double)VECTOR(*(igraph_vector_t*)attr_rec->value)[0]); + break; + case IGRAPH_ATTRIBUTE_STRING: + igraph_strvector_get((igraph_strvector_t*)attr_rec->value, 0, &s); + value=rb_str_new2(s); + break; + default: + IGRAPH_WARNING("unsupported attribute type (not string and not numeric)"); + value=0; + break; + } + if (value){ + rb_hash_aset((VALUE)attrs[2],key,value); + } + } + } graph->attr = attrs; @@ -90,34 +130,101 @@ void cIGraph_attribute_destroy(igraph_t *graph) { } /* Copying */ + +int replace_i(VALUE key, VALUE val, VALUE hash){ + if (key != Qundef) { + rb_hash_aset(hash, key, val); + } + + //return ST_CONTINUE; + return 0; +} + + int cIGraph_attribute_copy(igraph_t *to, const igraph_t *from) { +#ifdef DEBUG + printf("Entering cIGraph_attribute_copy\n"); +#endif + VALUE* attrs; VALUE vertex_array = ((VALUE*)from->attr)[0]; VALUE edge_array = ((VALUE*)from->attr)[1]; + VALUE graph_attr = ((VALUE*)from->attr)[2]; - //VALUE* attrs = (VALUE*)calloc(2, sizeof(VALUE)); - attrs = ALLOC_N(VALUE, 2); + attrs = ALLOC_N(VALUE, 3); attrs[0] = rb_ary_dup(vertex_array); attrs[1] = rb_ary_dup(edge_array); + attrs[2] = rb_hash_new(); + + rb_hash_foreach(graph_attr, replace_i, attrs[2]); to->attr = attrs; +#ifdef DEBUG + printf("Leaving cIGraph_attribute_copy\n"); +#endif + return IGRAPH_SUCCESS; } /* Adding vertices */ int cIGraph_attribute_add_vertices(igraph_t *graph, long int nv, igraph_vector_ptr_t *attr) { - int i; +#ifdef DEBUG + printf("Entering cIGraph_attribute_add_vertices\n"); +#endif + + int i,j; VALUE vertex_array = ((VALUE*)graph->attr)[0]; + VALUE values; if(attr){ - for(i=0;itype == IGRAPH_ATTRIBUTE_PY_OBJECT){ + + values = (VALUE)((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->value; + Check_Type(values, T_ARRAY); + for(i=0;ilen;i++){ + rb_ary_push(vertex_array, RARRAY(values)->ptr[i]); + } + //Otherwise read each attriute into hashes and use those + } else { + for(i=0;iname); + switch (attr_rec->type) { + case IGRAPH_ATTRIBUTE_NUMERIC: + value=rb_float_new((double)VECTOR(*(igraph_vector_t*)attr_rec->value)[i]); + break; + case IGRAPH_ATTRIBUTE_STRING: + igraph_strvector_get((igraph_strvector_t*)attr_rec->value, i, &s); + value=rb_str_new2(s); + break; + default: + IGRAPH_WARNING("unsupported attribute type (not string and not numeric)"); + value=Qnil; + break; + } + rb_hash_aset(record,key,value); + } + rb_ary_push(vertex_array,record); + } } } + +#ifdef DEBUG + printf("Leaving cIGraph_attribute_add_vertices\n"); +#endif return IGRAPH_SUCCESS; } @@ -127,6 +234,10 @@ void cIGraph_attribute_delete_vertices(igraph_t *graph, const igraph_vector_t *eidx, const igraph_vector_t *vidx) { +#ifdef DEBUG + printf("Entering cIGraph_attribute_delete_vertices\n"); +#endif + int i; VALUE vertex_array = ((VALUE*)graph->attr)[0]; VALUE edge_array = ((VALUE*)graph->attr)[1]; @@ -146,6 +257,10 @@ void cIGraph_attribute_delete_vertices(igraph_t *graph, ((VALUE*)graph->attr)[0] = n_v_ary; ((VALUE*)graph->attr)[1] = n_e_ary; +#ifdef DEBUG + printf("Leaving cIGraph_attribute_delete_vertices\n"); +#endif + return; } @@ -154,21 +269,69 @@ int cIGraph_attribute_add_edges(igraph_t *graph, const igraph_vector_t *edges, igraph_vector_ptr_t *attr) { - int i; +#ifdef DEBUG + printf("Entering cIGraph_attribute_add_edges\n"); +#endif + + int i,j; VALUE edge_array = ((VALUE*)graph->attr)[1]; + VALUE values; if(attr){ - for(i=0;itype == IGRAPH_ATTRIBUTE_PY_OBJECT){ + values = (VALUE)((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->value; + Check_Type(values, T_ARRAY); + for(i=0;ilen;i++){ + rb_ary_push(edge_array, RARRAY(values)->ptr[i]); + } + //Otherwise read each attriute into hashes and use those + } else { + for(i=0;iname); + switch (attr_rec->type) { + case IGRAPH_ATTRIBUTE_NUMERIC: + value=rb_float_new((double)VECTOR(*(igraph_vector_t*)attr_rec->value)[i]); + break; + case IGRAPH_ATTRIBUTE_STRING: + igraph_strvector_get((igraph_strvector_t*)attr_rec->value, i, &s); + value=rb_str_new2(s); + break; + default: + IGRAPH_WARNING("unsupported attribute type (not string and not numeric)"); + value=Qnil; + break; + } + rb_hash_aset(record,key,value); + } + rb_ary_push(edge_array,record); + } } } - + +#ifdef DEBUG + printf("Leaving cIGraph_attribute_add_edges\n"); +#endif + return IGRAPH_SUCCESS; } /* Deleting edges */ void cIGraph_attribute_delete_edges(igraph_t *graph, const igraph_vector_t *idx) { +#ifdef DEBUG + printf("Entering cIGraph_attribute_delete_edges\n"); +#endif + int i; VALUE edge_array = ((VALUE*)graph->attr)[1]; VALUE n_e_ary = rb_ary_new(); @@ -179,6 +342,10 @@ void cIGraph_attribute_delete_edges(igraph_t *graph, const igraph_vector_t *idx) } ((VALUE*)graph->attr)[1] = n_e_ary; + +#ifdef DEBUG + printf("Leaving cIGraph_attribute_delete_edges\n"); +#endif return; } @@ -187,6 +354,10 @@ void cIGraph_attribute_delete_edges(igraph_t *graph, const igraph_vector_t *idx) int cIGraph_attribute_permute_edges(igraph_t *graph, const igraph_vector_t *idx) { +#ifdef DEBUG + printf("Entering cIGraph_attribute_permute_edges\n"); +#endif + int i; VALUE edge_array = ((VALUE*)graph->attr)[1]; VALUE n_e_ary = rb_ary_new(); @@ -196,45 +367,218 @@ int cIGraph_attribute_permute_edges(igraph_t *graph, } ((VALUE*)graph->attr)[1] = n_e_ary; + +#ifdef DEBUG + printf("Leaving cIGraph_attribute_permute_edges\n"); +#endif return 0; } +VALUE keys_to_strvec(VALUE data, VALUE arr){ + + VALUE key = rb_ary_entry(data, 0); + VALUE val = rb_ary_entry(data, 1); + + VALUE rb_names = rb_ary_entry(arr, 0); + VALUE rb_types = rb_ary_entry(arr, 1); + + VALUE str = StringValue(key); + + rb_ary_push(rb_names,str); + + if(TYPE(val) == T_STRING){ + rb_ary_push(rb_types,INT2FIX(IGRAPH_ATTRIBUTE_STRING)); + } else if (TYPE(val) == T_FLOAT || TYPE(val) == T_FIXNUM){ + rb_ary_push(rb_types,INT2FIX(IGRAPH_ATTRIBUTE_NUMERIC)); + } else { + rb_ary_push(rb_types,INT2FIX(IGRAPH_ATTRIBUTE_PY_OBJECT)); + } + + return data; + +} + /* Getting attribute names and types */ int cIGraph_attribute_get_info(const igraph_t *graph, - igraph_strvector_t *gnames, - igraph_vector_t *gtypes, - igraph_strvector_t *vnames, - igraph_vector_t *vtypes, - igraph_strvector_t *enames, - igraph_vector_t *etypes) { + igraph_strvector_t *gnames, + igraph_vector_t *gtypes, + igraph_strvector_t *vnames, + igraph_vector_t *vtypes, + igraph_strvector_t *enames, + igraph_vector_t *etypes) { + + +#ifdef DEBUG + printf("Entering cIGraph_attribute_get_info\n"); +#endif + + igraph_strvector_t *names[3] = { vnames, enames, gnames }; + igraph_vector_t *types[3] = { vtypes, etypes, gtypes }; + + long int i,j; + + for (i=0; i<3; i++) { + + igraph_strvector_t *n = names[i]; + igraph_vector_t *t = types[i]; + + VALUE rb_names = rb_ary_new(); + VALUE rb_types = rb_ary_new(); + + VALUE obj_hash; + + //Graph attributes are different + if (i != 2){ + + VALUE store = ((VALUE*)graph->attr)[i]; + VALUE obj = RARRAY(store)->ptr[0]; + + obj_hash = Qnil; + if(rb_funcall(obj, rb_intern("respond_to?"), 1, rb_str_new2("to_hash")) == Qtrue){ + obj_hash = rb_funcall(obj, rb_intern("to_hash"), 0); + } + } else { + obj_hash = ((VALUE*)graph->attr)[2]; + } + + if(!NIL_P(obj_hash)){ + //Take the keys of the hash, convert to strings and put in vector n + rb_iterate(rb_each, obj_hash, keys_to_strvec, rb_ary_new3(2,rb_names,rb_types)); + } + + //Push names onto n and types onto t + for(j=0;jlen;j++){ + igraph_strvector_add(n, RSTRING(RARRAY(rb_names)->ptr[j])->ptr); + igraph_vector_push_back(t, NUM2INT(RARRAY(rb_types)->ptr[j])); + } + + } + +#ifdef DEBUG + printf("Leaving cIGraph_attribute_get_info\n"); +#endif + return 0; + } /* Checks whether the graph has a graph/vertex/edge attribute with the given name */ igraph_bool_t cIGraph_attribute_has_attr(const igraph_t *graph, - igraph_attribute_elemtype_t type, - const char* name) { - return 0; + igraph_attribute_elemtype_t type, + const char* name) { + +#ifdef DEBUG + printf("Entering cIGraph_attribute_has_attr\n"); +#endif + + long int attrnum; + igraph_bool_t res = 0; + VALUE obj; + + switch (type) { + case IGRAPH_ATTRIBUTE_GRAPH: attrnum=0; break; + case IGRAPH_ATTRIBUTE_VERTEX: attrnum=1; break; + case IGRAPH_ATTRIBUTE_EDGE: attrnum=2; break; + default: return 0; break; + } + + obj = ((VALUE*)graph->attr)[attrnum]; + if (attrnum != 2) + obj = RARRAY(obj)->ptr[0]; + + if(rb_funcall(obj,rb_intern("include?"), 1, rb_str_new2(name))){ + res = 1; + } + +#ifdef DEBUG + printf("Leaving cIGraph_attribute_has_attr\n"); +#endif + + return res; } /* Returns the type of a given attribute */ int cIGraph_attribute_get_type(const igraph_t *graph, - igraph_attribute_type_t *type, - igraph_attribute_elemtype_t elemtype, - const char *name) { + igraph_attribute_type_t *type, + igraph_attribute_elemtype_t elemtype, + const char *name) { + +#ifdef DEBUG + printf("Entering cIGraph_attribute_get_type\n"); +#endif + + long int attrnum; + VALUE obj; + VALUE val; + + switch (elemtype) { + case IGRAPH_ATTRIBUTE_GRAPH: attrnum=0; break; + case IGRAPH_ATTRIBUTE_VERTEX: attrnum=1; break; + case IGRAPH_ATTRIBUTE_EDGE: attrnum=2; break; + default: return 0; break; + } + + obj = ((VALUE*)graph->attr)[attrnum]; + if (attrnum != 2) + obj = RARRAY(obj)->ptr[0]; + + if(rb_funcall(obj,rb_intern("includes"), rb_str_new2(name))){ + val = rb_hash_aref(obj,rb_str_new2(name)); + if (TYPE(val) == T_STRING){ + *type = IGRAPH_ATTRIBUTE_STRING; + } else if (TYPE(val) == T_FIXNUM || TYPE(val) == T_FLOAT){ + *type = IGRAPH_ATTRIBUTE_NUMERIC; + } else { + *type = IGRAPH_ATTRIBUTE_PY_OBJECT; + } + } + +#ifdef DEBUG + printf("Leaving cIGraph_attribute_get_type\n"); +#endif + return 0; + } /* Getting numeric graph attributes */ int cIGraph_get_numeric_graph_attr(const igraph_t *graph, - const char *name, igraph_vector_t *value) { + const char *name, igraph_vector_t *value) { + +#ifdef DEBUG + printf("Entering cIGraph_get_numeric_graph_attr\n"); +#endif + + VALUE val; + + val = rb_hash_aref(((VALUE*)graph->attr)[2],rb_str_new2(name)); + VECTOR(*value)[0] = NUM2DBL(val); + +#ifdef DEBUG + printf("Leaving cIGraph_get_numeric_graph_attr\n"); +#endif + return 0; } /* Getting string graph attributes */ int cIGraph_get_string_graph_attr(const igraph_t *graph, const char *name, igraph_strvector_t *value) { + +#ifdef DEBUG + printf("Entering cIGraph_get_string_graph_attr\n"); +#endif + + VALUE val; + + val = rb_hash_aref(((VALUE*)graph->attr)[2],rb_str_new2(name)); + igraph_strvector_set(value,0,RSTRING(val)->ptr); + +#ifdef DEBUG + printf("Leaving cIGraph_get_string_graph_attr\n"); +#endif + return 0; } @@ -243,6 +587,39 @@ int cIGraph_get_numeric_vertex_attr(const igraph_t *graph, const char *name, igraph_vs_t vs, igraph_vector_t *value) { + +#ifdef DEBUG + printf("Entering cIGraph_get_numeric_vertex_attr\n"); +#endif + + VALUE array = ((VALUE*)graph->attr)[0]; + VALUE val, vertex; + igraph_vit_t it; + int i = 0; + + IGRAPH_CHECK(igraph_vit_create(graph, vs, &it)); + IGRAPH_FINALLY(igraph_vit_destroy, &it); + IGRAPH_CHECK(igraph_vector_resize(value, IGRAPH_VIT_SIZE(it))); + + while(!IGRAPH_VIT_END(it)){ + vertex = RARRAY(array)->ptr[(int)IGRAPH_VIT_GET(it)]; + val = rb_hash_aref(vertex,rb_str_new2(name)); + + if(val == Qnil) + val = rb_float_new(NAN); + + VECTOR(*value)[i] = NUM2DBL(val); + IGRAPH_VIT_NEXT(it); + i++; + } + + igraph_vit_destroy(&it); + IGRAPH_FINALLY_CLEAN(1); + +#ifdef DEBUG + printf("Leaving cIGraph_get_numeric_vertex_attr\n"); +#endif + return 0; } @@ -251,6 +628,39 @@ int cIGraph_get_string_vertex_attr(const igraph_t *graph, const char *name, igraph_vs_t vs, igraph_strvector_t *value) { + +#ifdef DEBUG + printf("Entering cIGraph_get_string_vertex_attr\n"); +#endif + + VALUE array = ((VALUE*)graph->attr)[0]; + VALUE val, vertex; + igraph_vit_t it; + int i=0; + + IGRAPH_CHECK(igraph_vit_create(graph, vs, &it)); + IGRAPH_FINALLY(igraph_vit_destroy, &it); + IGRAPH_CHECK(igraph_strvector_resize(value, IGRAPH_VIT_SIZE(it))); + + while(!IGRAPH_VIT_END(it)){ + vertex = RARRAY(array)->ptr[(int)IGRAPH_VIT_GET(it)]; + val = rb_hash_aref(vertex,rb_str_new2(name)); + + if(val == Qnil) + val = rb_str_new2(""); + + igraph_strvector_set(value,i,RSTRING(val)->ptr); + IGRAPH_VIT_NEXT(it); + i++; + } + + igraph_vit_destroy(&it); + IGRAPH_FINALLY_CLEAN(1); + +#ifdef DEBUG + printf("Leaving cIGraph_get_string_vertex_attr\n"); +#endif + return 0; } @@ -259,6 +669,39 @@ int cIGraph_get_numeric_edge_attr(const igraph_t *graph, const char *name, igraph_es_t es, igraph_vector_t *value) { + +#ifdef DEBUG + printf("Entering cIGraph_get_numeric_edge_attr\n"); +#endif + + VALUE array = ((VALUE*)graph->attr)[1]; + VALUE val, vertex; + igraph_eit_t it; + int i = 0; + + IGRAPH_CHECK(igraph_eit_create(graph, es, &it)); + IGRAPH_FINALLY(igraph_eit_destroy, &it); + IGRAPH_CHECK(igraph_vector_resize(value, IGRAPH_EIT_SIZE(it))); + + while(!IGRAPH_EIT_END(it)){ + vertex = RARRAY(array)->ptr[(int)IGRAPH_EIT_GET(it)]; + val = rb_hash_aref(vertex,rb_str_new2(name)); + + if(val == Qnil) + val = rb_float_new(NAN); + + VECTOR(*value)[i] = NUM2DBL(val); + IGRAPH_EIT_NEXT(it); + i++; + } + + igraph_eit_destroy(&it); + IGRAPH_FINALLY_CLEAN(1); + +#ifdef DEBUG + printf("Leaving cIGraph_get_numeric_edge_attr\n"); +#endif + return 0; } @@ -267,5 +710,36 @@ int cIGraph_get_string_edge_attr(const igraph_t *graph, const char *name, igraph_es_t es, igraph_strvector_t *value) { + +#ifdef DEBUG + printf("Entering cIGraph_get_string_edge_attr\n"); +#endif + + VALUE array = ((VALUE*)graph->attr)[1]; + VALUE val, vertex; + igraph_eit_t it; + int i=0; + + IGRAPH_CHECK(igraph_eit_create(graph, es, &it)); + IGRAPH_FINALLY(igraph_eit_destroy, &it); + IGRAPH_CHECK(igraph_strvector_resize(value, IGRAPH_EIT_SIZE(it))); + + while(!IGRAPH_EIT_END(it)){ + vertex = RARRAY(array)->ptr[(int)IGRAPH_EIT_GET(it)]; + val = rb_hash_aref(vertex,rb_str_new2(name)); + if(val == Qnil) + val = rb_str_new2(""); + igraph_strvector_set(value,i,RSTRING(val)->ptr); + IGRAPH_EIT_NEXT(it); + i++; + } + + igraph_eit_destroy(&it); + IGRAPH_FINALLY_CLEAN(1); + +#ifdef DEBUG + printf("Leaving cIGraph_get_string_edge_attr\n"); +#endif + return 0; } diff --git a/test/tc_attributes.rb b/test/tc_attributes.rb index 57ea9c1..e8e4690 100644 --- a/test/tc_attributes.rb +++ b/test/tc_attributes.rb @@ -21,4 +21,9 @@ class TestGraph < Test::Unit::TestCase graph.add_edge('A','D',4) assert_equal 4, graph['A','D'] end + def test_graph_attr + graph = IGraph.new(['A','B','C','D'],true,[1,2]) + graph.attributes['test'] = 1 + assert_equal 1, graph.attributes['test'] + end end diff --git a/test/test_all.rb b/test/test_all.rb index b6dbdf2..5bfb493 100644 --- a/test/test_all.rb +++ b/test/test_all.rb @@ -12,6 +12,8 @@ require 'tc_basic_properties' require 'tc_copy' require 'tc_error_handling' require 'tc_file_read_write' +require 'tc_layout' +require 'tc_matrix' require 'tc_shortest_paths' require 'tc_topological_sort' require 'tc_vertex_neighbourhood'