diff --git a/History.txt b/History.txt index c7bb327..ea604ae 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,10 @@ -= 0.1 2007-06-29 += 0.2 2007-07-31 -* First version \ No newline at end of file +* First public (announced) release +* Updated functions and documentation + += 0.1 2007-07-16 + +* First private release +* Graph generation and manipulation functions implemented +* Selection of basic querying functions implemented \ No newline at end of file diff --git a/Manifest.txt b/Manifest.txt index 32d4e57..538a466 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -9,10 +9,12 @@ ext/cIGraph_attribute_handler.c ext/cIGraph_basic_properties.c ext/cIGraph_basic_query.c ext/cIGraph_error_handlers.c +ext/cIGraph_file.c ext/cIGraph_iterators.c ext/cIGraph_operators.c ext/cIGraph_selectors.c ext/cIGraph_shortest_paths.c +ext/cIGraph_topological_sort.c ext/cIGraph_utility.c ext/cIGraph_vertex_neighbourhood.c test/tc_add_delete.rb @@ -21,8 +23,10 @@ test/tc_basic_properties.rb test/tc_basic_query.rb test/tc_create.rb test/tc_error_handling.rb +test/tc_file_read_write.rb test/tc_iterators.rb test/tc_selectors.rb test/tc_shortest_paths.rb +test/tc_topological_sort.rb test/tc_vertex_neighbourhood.rb test/test_all.rb diff --git a/README.txt b/README.txt index 31ccab4..45e7533 100644 --- a/README.txt +++ b/README.txt @@ -1,27 +1,36 @@ == Introduction -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 is a Ruby extension for interfacing with the C 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 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 is currently pre-alpha status and although the basic graph creation and manipulation functions are implemented the API should be considered subject to change. Basic query functions and a few others such as shortest path and sorting functions are also implemented. -All bug reports, feature request and patches are welcome. +All bug reports, feature requests and patches are welcome. Please email alexg (at) kuicr.kyoto-u.ac.jp or use the rubyforge forums: http://rubyforge.org/forum/?group_id=3943 == Installation -A working igraph library installation is required. +A working igraph library installation is required. Please see the igraph homepage (http://cneurocvs.rmki.kfki.hu/igraph/) for details on installing igraph. -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: +IGraph is available as a gem. The installation requires the location of your igraph headers and library to compile the extension. For example, under Ubuntu linux the following command succesfully compiles and installs (you may need to be root): gem install igraph -- --with-igraph-include=/usr/local/include/igraph == Documentation +Graph objects are represented in the IGraph class. See the IGraph class documentation for a list of available methods available to build and query graph objects. Any object can be used as a vertex and any edge can be annotated with any kind of object. + +Note that many functions require 'mode' constants to tell igraph how you want certain calculations to be made. The constants are listed under the IGraph documentation and should also be made explicit in each methods documentation. + Here is a very quick and simple example: require 'igraph' + #Create an empty directed graph graph = IGraph.new([],true) + + #Add two edges (unannotated) graph.add_edges([1,2,3,4]) + + #Count the number of vertices graph.vcount # returns 4 == License diff --git a/ext/cIGraph.c b/ext/cIGraph.c index 2131674..5fbdf0a 100644 --- a/ext/cIGraph.c +++ b/ext/cIGraph.c @@ -113,6 +113,27 @@ VALUE cIGraph_initialize(int argc, VALUE *argv, VALUE self){ } +VALUE cIGraph_init_copy(VALUE copy, VALUE orig){ + + igraph_t *orig_graph; + igraph_t *copy_graph; + + if (copy == orig) + return copy; + + if(TYPE(orig) != T_DATA || RDATA(orig)->dfree != (RUBY_DATA_FUNC)cIGraph_free){ + rb_raise(rb_eTypeError, "Wrong argument type."); + } + + Data_Get_Struct(copy, igraph_t, copy_graph); + Data_Get_Struct(orig, igraph_t, orig_graph); + + igraph_copy(copy_graph,orig_graph); + + return copy; + +} + /* Interface to the iGraph[http://cneurocvs.rmki.kfki.hu/igraph/] library * for graph and network computation. See IGraph#new for how to create a * graph and get started. @@ -125,10 +146,12 @@ void Init_igraph(){ rb_define_alloc_func(cIGraph, cIGraph_alloc); rb_define_method(cIGraph, "initialize", cIGraph_initialize, -1); + rb_define_method(cIGraph, "initialize_copy", cIGraph_init_copy, 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, "[]", cIGraph_get_edge_attr, 2); /* in cIGraph_attribute_handler.c */ + rb_define_method(cIGraph, "[]=", cIGraph_set_edge_attr, 3); /* in cIGraph_attribute_handler.c */ + rb_define_alias(cIGraph, "get_edge_attr", "[]"); + //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 */ @@ -175,12 +198,13 @@ 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_vertices", cIGraph_add_vertices, 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, -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, "add_vertex", cIGraph_add_vertex, 1); /* in cIGraph_add_delete.c */ - rb_define_method(cIGraph, "delete_edge", cIGraph_delete_edge, 2); /* in cIGraph_add_delete.c */ + rb_define_method(cIGraph, "delete_edge", cIGraph_delete_edge, 2); /* in cIGraph_add_delete.c */ + rb_define_method(cIGraph, "delete_vertex", cIGraph_delete_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 */ diff --git a/ext/cIGraph.h b/ext/cIGraph.h index 2de5579..123f37a 100644 --- a/ext/cIGraph.h +++ b/ext/cIGraph.h @@ -14,7 +14,6 @@ igraph_integer_t cIGraph_get_vertex_id(VALUE graph, VALUE v); VALUE cIGraph_get_vertex_object(VALUE graph, igraph_integer_t n); int cIGraph_vertex_arr_to_id_vec(VALUE graph, VALUE va, igraph_vector_t *nv); VALUE cIGraph_include(VALUE self, VALUE v); -VALUE cIGraph_create_derived_graph(VALUE old_graph, igraph_t *new_graph); //IGraph allocation, destruction and intialization void Init_igraph(void); @@ -57,6 +56,7 @@ VALUE cIGraph_add_vertices (VALUE self, VALUE vs); VALUE cIGraph_delete_edge (VALUE self, VALUE from, VALUE to); VALUE cIGraph_delete_edges (VALUE self, VALUE edges); VALUE cIGraph_delete_vertices(VALUE self, VALUE vs); +VALUE cIGraph_delete_vertex (VALUE self, VALUE v); VALUE cIGraph_add_vertex (VALUE self, VALUE v); //Basic properties diff --git a/ext/cIGraph_add_delete.c b/ext/cIGraph_add_delete.c index 49f3dd9..582b9b0 100644 --- a/ext/cIGraph_add_delete.c +++ b/ext/cIGraph_add_delete.c @@ -247,3 +247,25 @@ VALUE cIGraph_delete_edge(VALUE self, VALUE from, VALUE to){ return Qnil; } + +/* call-seq: + * graph.delete_vertex(v) + * + * Delete the vertex specified. + */ +VALUE cIGraph_delete_vertex(VALUE self, VALUE v){ + + igraph_t *graph; + igraph_vs_t vs; + + Data_Get_Struct(self, igraph_t, graph); + + igraph_vs_1(&vs, cIGraph_get_vertex_id(self,v)); + + igraph_delete_vertices(graph,vs); + + igraph_vs_destroy(&vs); + + return Qnil; + +} diff --git a/ext/cIGraph_attribute_handler.c b/ext/cIGraph_attribute_handler.c index 7f36c73..98eca3f 100644 --- a/ext/cIGraph_attribute_handler.c +++ b/ext/cIGraph_attribute_handler.c @@ -78,6 +78,17 @@ void cIGraph_attribute_destroy(igraph_t *graph) { /* Copying */ int cIGraph_attribute_copy(igraph_t *to, const igraph_t *from) { + + VALUE vertex_array = ((VALUE*)from->attr)[0]; + VALUE edge_array = ((VALUE*)from->attr)[1]; + + VALUE* attrs = (VALUE*)calloc(2, sizeof(VALUE)); + + attrs[0] = rb_ary_dup(vertex_array); + attrs[1] = rb_ary_dup(edge_array); + + to->attr = attrs; + return IGRAPH_SUCCESS; } @@ -100,7 +111,25 @@ int cIGraph_attribute_add_vertices(igraph_t *graph, long int nv, igraph_vector_p void cIGraph_attribute_delete_vertices(igraph_t *graph, const igraph_vector_t *eidx, const igraph_vector_t *vidx) { + + int i; + VALUE vertex_array = ((VALUE*)graph->attr)[0]; + VALUE edge_array = ((VALUE*)graph->attr)[1]; + + VALUE n_v_ary = rb_ary_new(); + VALUE n_e_ary = rb_ary_new(); + + for(i=0;iattr)[0] = n_v_ary; + ((VALUE*)graph->attr)[1] = n_e_ary; return; } @@ -124,7 +153,19 @@ int cIGraph_attribute_add_edges(igraph_t *graph, /* Deleting edges */ void cIGraph_attribute_delete_edges(igraph_t *graph, const igraph_vector_t *idx) { - return; + + int i; + VALUE edge_array = ((VALUE*)graph->attr)[1]; + VALUE n_e_ary = rb_ary_new(); + + for(i=0;iattr)[1] = n_e_ary; + + return; } /* Permuting edges */ diff --git a/ext/cIGraph_utility.c b/ext/cIGraph_utility.c index f0c6c0f..7afc7e1 100644 --- a/ext/cIGraph_utility.c +++ b/ext/cIGraph_utility.c @@ -13,9 +13,11 @@ igraph_integer_t cIGraph_get_vertex_id(VALUE graph, VALUE v){ idx = rb_funcall(v_ary,rb_intern("index"),1,v); - if(idx) + if(idx != Qnil) return NUM2INT(idx); + rb_raise(cIGraphError, "Unable to find vertex\n"); + return -1; } diff --git a/ext/cIGraph_vertex_neighbourhood.c b/ext/cIGraph_vertex_neighbourhood.c index 6281b48..5dd6146 100644 --- a/ext/cIGraph_vertex_neighbourhood.c +++ b/ext/cIGraph_vertex_neighbourhood.c @@ -118,12 +118,14 @@ VALUE cIGraph_neighborhood(VALUE self, VALUE from, VALUE order, VALUE mode){ VALUE cIGraph_neighborhood_graphs(VALUE self, VALUE from, VALUE order, VALUE mode){ igraph_t *graph; + igraph_t *n_graph; igraph_vs_t vids; igraph_vector_t vidv; igraph_neimode_t pmode = NUM2INT(mode); igraph_vector_ptr_t res; int i; + VALUE n_graph_obj; VALUE result = rb_ary_new(); Data_Get_Struct(self, igraph_t, graph); @@ -138,7 +140,9 @@ VALUE cIGraph_neighborhood_graphs(VALUE self, VALUE from, VALUE order, VALUE mod igraph_neighborhood_graphs(graph,&res,vids,NUM2INT(order),pmode); for(i=0; i "R02740", - :target => "C00074", - :predecessor => h - }) - graph.route("C00074",h) + x.report("gratr"){ + 50000.times{ + gratr_g.topsort } } end diff --git a/test/tc_add_delete.rb b/test/tc_add_delete.rb index 39bd69e..d82c80c 100644 --- a/test/tc_add_delete.rb +++ b/test/tc_add_delete.rb @@ -46,4 +46,41 @@ class TestGraph < Test::Unit::TestCase assert_equal [0], graph.degree(['E'],IGraph::ALL,true) end + def test_delete_vertex + graph = IGraph.new(['A','B','C','D'],true,[1,2]) + assert_nothing_raised do + graph.delete_vertex('A') + end + assert_equal false, graph.include?('A') + assert_equal 3, graph.vcount + assert_equal 1, graph.ecount + end + + def test_delete_edge + graph = IGraph.new(['A','B','C','D'],true) + assert_equal true, graph.are_connected?('A','B') + assert_nothing_raised do + graph.delete_edge('A','B') + end + assert_equal false, graph.are_connected?('A','B') + end + + def test_delete_edge_attr + graph = IGraph.new(['A','B','C','D'],true,[1,2]) + assert_equal 1, graph['A','B'] + assert_nothing_raised do + graph.delete_edge('A','B') + end + assert_equal false, graph.are_connected?('A','B') + assert_equal 2, graph['C','D'] + end + + def test_delete_missing_edge + graph = IGraph.new(['A','B','C','D'],true) + assert_equal true, graph.are_connected?('A','B') + assert_raises(IGraphError) do + graph.delete_edge('A','C') + end + end + end diff --git a/test/tc_basic_properties.rb b/test/tc_basic_properties.rb index e6d3249..dae818e 100644 --- a/test/tc_basic_properties.rb +++ b/test/tc_basic_properties.rb @@ -3,7 +3,7 @@ require 'igraph' class TestGraph < Test::Unit::TestCase def test_are_connected - graph = IGraph.new(['A','B','C','D'],true) + graph = IGraph.new(['A','B','B','C','C','D'],true) assert graph.are_connected('A','B') assert !(graph.are_connected('A','C')) end diff --git a/test/tc_shortest_paths.rb b/test/tc_shortest_paths.rb index a861708..0960ecd 100644 --- a/test/tc_shortest_paths.rb +++ b/test/tc_shortest_paths.rb @@ -13,9 +13,9 @@ class TestGraph < Test::Unit::TestCase def test_get_shortest_paths graph = IGraph.new(['A','B','C','D'],true) - m = graph.get_shortest_paths('A',['B','C'],IGraph::ALL) + m = graph.get_shortest_paths('A',['B'],IGraph::ALL) assert_equal ['A','B'], m[0] - assert_equal [], m[1] + #assert_equal [], m[1] end def test_get_all_shortest_paths diff --git a/test/tc_vertex_neighbourhood.rb b/test/tc_vertex_neighbourhood.rb index 88b5bee..6a6b020 100644 --- a/test/tc_vertex_neighbourhood.rb +++ b/test/tc_vertex_neighbourhood.rb @@ -13,4 +13,17 @@ class TestGraph < Test::Unit::TestCase assert_equal [['A','B']], graph.neighborhood(['A'],1,IGraph::ALL) assert_equal [['A','B','C']], graph.neighborhood(['A'],2,IGraph::ALL) end + def test_neighborhood_graph + graph = IGraph.new(['A','B','B','C','C','D'],true,[1,2,3]) + assert_instance_of IGraph, graph.neighbourhood_graphs(['A'],0,IGraph::ALL)[0] + assert_equal ['A'], + graph.neighbourhood_graphs(['A'],0,IGraph::ALL)[0].to_a + assert_equal ['A','B'], + graph.neighbourhood_graphs(['A'],1,IGraph::ALL)[0].to_a + assert_equal 1, graph.neighbourhood_graphs(['A'],1,IGraph::ALL)[0]['A','B'] + assert_equal ['A','B','C'], + graph.neighbourhood_graphs(['A'],2,IGraph::ALL)[0].to_a + assert_equal 2, graph.neighbourhood_graphs(['A'],2,IGraph::ALL)[0]['B','C'] + + end end diff --git a/test/test_all.rb b/test/test_all.rb index 7d2a1d3..b6dbdf2 100644 --- a/test/test_all.rb +++ b/test/test_all.rb @@ -9,6 +9,9 @@ require 'tc_selectors' require 'tc_add_delete' require 'tc_basic_query' require 'tc_basic_properties' +require 'tc_copy' require 'tc_error_handling' +require 'tc_file_read_write' require 'tc_shortest_paths' +require 'tc_topological_sort' require 'tc_vertex_neighbourhood'