diff --git a/ext/cIGraph.c b/ext/cIGraph.c index f8a2f8d..ea5970e 100644 --- a/ext/cIGraph.c +++ b/ext/cIGraph.c @@ -207,6 +207,14 @@ void Init_igraph(){ rb_define_const(cIGraph, "GET_ADJACENCY_LOWER", INT2NUM(1)); rb_define_const(cIGraph, "GET_ADJACENCY_BOTH", INT2NUM(2)); + rb_define_const(cIGraph, "ERDOS_RENYI_GNP", INT2NUM(0)); + rb_define_const(cIGraph, "ERDOS_RENYI_GNM", INT2NUM(1)); + + rb_define_singleton_method(cIGraph, "grg_game", cIGraph_grg_game, 3); /* in cIGraph_generators_random.c */ + rb_define_singleton_method(cIGraph, "barabasi_game", cIGraph_barabasi_game, 4); /* in cIGraph_generators_random.c */ + rb_define_singleton_method(cIGraph, "nonlinear_barabasi_game", cIGraph_nonlinear_barabasi_game, 6); /* in cIGraph_generators_random.c */ +rb_define_singleton_method(cIGraph, "erdos_renyi_game", cIGraph_erdos_renyi_game, 5); /* in cIGraph_generators_random.c */ + 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", "[]"); @@ -328,9 +336,14 @@ void Init_igraph(){ 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); /* in cIGraph_layout.c */ - rb_define_method(cIGraph, "layout_circle", cIGraph_layout_circle, 0); /* in cIGraph_layout.c */ - rb_define_method(cIGraph, "layout_fruchterman_reingold", cIGraph_layout_fruchterman_reingold, 6); /* in cIGraph_layout.c */ + rb_define_method(cIGraph, "layout_random", cIGraph_layout_random, 0); /* in cIGraph_layout.c */ + rb_define_method(cIGraph, "layout_circle", cIGraph_layout_circle, 0); /* in cIGraph_layout.c */ + rb_define_method(cIGraph, "layout_fruchterman_reingold", cIGraph_layout_fruchterman_reingold, 6); /* in cIGraph_layout.c */ + rb_define_method(cIGraph, "layout_kamada_kawai", cIGraph_layout_kamada_kawai, 5); /* in cIGraph_layout.c */ + rb_define_method(cIGraph, "layout_reingold_tilford", cIGraph_layout_reingold_tilford, 1); /* in cIGraph_layout.c */ + rb_define_method(cIGraph, "layout_reingold_tilford_circular", cIGraph_layout_reingold_tilford_circular, 1); /* in cIGraph_layout.c */ + rb_define_method(cIGraph, "layout_grid_fruchterman_reingold", cIGraph_layout_grid_fruchterman_reingold, 7); /* in cIGraph_layout.c */ + rb_define_method(cIGraph, "layout_lgl", cIGraph_layout_lgl, 7); /* in cIGraph_layout.c */ //Matrix class cIGraphMatrix = rb_define_class("IGraphMatrix", rb_cObject); diff --git a/ext/cIGraph.h b/ext/cIGraph.h index a5294b5..ef1d029 100644 --- a/ext/cIGraph.h +++ b/ext/cIGraph.h @@ -30,6 +30,15 @@ VALUE cIGraph_alloc(VALUE klass); VALUE cIGraph_initialize(int argc, VALUE *argv, VALUE self); VALUE cIGraph_init_copy(VALUE copy, VALUE orig); +//Random graph generators +VALUE cIGraph_grg_game (VALUE self, VALUE nodes, + VALUE radius, VALUE torus); +VALUE cIGraph_barabasi_game(VALUE self, VALUE nodes, + VALUE m, VALUE outpref, VALUE directed); +VALUE cIGraph_nonlinear_barabasi_game(VALUE self, VALUE nodes, VALUE power, + VALUE m, VALUE outpref, VALUE zeroappeal, VALUE directed); +VALUE cIGraph_erdos_renyi_game (VALUE self, VALUE type, VALUE nodes, VALUE mp, VALUE directed, VALUE loops); + //Attribute accessors int replace_i(VALUE key, VALUE val, VALUE hash); VALUE cIGraph_get_edge_attr(VALUE self, VALUE from, VALUE to); @@ -171,8 +180,8 @@ 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); -VALUE cIGraph_layout_circle(VALUE self); +VALUE cIGraph_layout_random (VALUE self); +VALUE cIGraph_layout_circle (VALUE self); VALUE cIGraph_layout_fruchterman_reingold(VALUE self, VALUE niter, VALUE maxdelta, @@ -180,6 +189,33 @@ VALUE cIGraph_layout_fruchterman_reingold(VALUE self, VALUE coolexp, VALUE repulserad, VALUE use_seed); +VALUE cIGraph_layout_kamada_kawai (VALUE self, + VALUE niter, + VALUE sigma, + VALUE initemp, + VALUE coolexp, + VALUE kkconst); +VALUE cIGraph_layout_reingold_tilford (VALUE self, + VALUE root); +VALUE cIGraph_layout_reingold_tilford_circular(VALUE self, + VALUE root); +VALUE cIGraph_layout_grid_fruchterman_reingold(VALUE self, + VALUE niter, + VALUE maxdelta, + VALUE area, + VALUE coolexp, + VALUE repulserad, + VALUE cellsize, + VALUE use_seed); +VALUE cIGraph_layout_lgl(VALUE self, + VALUE maxit, + VALUE maxdelta, + VALUE area, + VALUE coolexp, + VALUE repulserad, + VALUE cellsize, + VALUE proot); + //Attributes int cIGraph_attribute_init(igraph_t *graph, diff --git a/ext/cIGraph_layout.c b/ext/cIGraph_layout.c index 10ca9d4..74134b5 100644 --- a/ext/cIGraph_layout.c +++ b/ext/cIGraph_layout.c @@ -22,7 +22,7 @@ VALUE cIGraph_layout_random(VALUE self){ } /* call-seq: - * graph.layout_random -> IGraphMatrix + * graph.layout_circle -> IGraphMatrix * * Returns a layout with nodes laid out around a circle. */ @@ -41,7 +41,7 @@ VALUE cIGraph_layout_circle(VALUE self){ } /* call-seq: - * graph.layout_random -> IGraphMatrix + * graph.layout_fruchterman_reingold -> IGraphMatrix * * Places the vertices on a plane according to the Fruchterman-Reingold * algorithm. @@ -75,3 +75,175 @@ VALUE cIGraph_layout_fruchterman_reingold(VALUE self, return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res); } + +/* call-seq: + * graph.layout_kamada_kawai -> IGraphMatrix + * + * Places the vertices on a plane according the Kamada-Kawai algorithm. + * + * This is a force directed layout, see Kamada, T. and Kawai, S.: An + * Algorithm for Drawing General Undirected Graphs. Information Processing + * Letters, 31/1, 7--15, 1989. + */ +VALUE cIGraph_layout_kamada_kawai(VALUE self, + VALUE niter, + VALUE sigma, + VALUE initemp, + VALUE coolexp, + VALUE kkconst){ + + igraph_t *graph; + igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t)); + + Data_Get_Struct(self, igraph_t, graph); + + igraph_matrix_init(res,0,0); + igraph_layout_kamada_kawai(graph,res, + NUM2INT(niter), + NUM2DBL(sigma), + NUM2DBL(initemp), + NUM2DBL(coolexp), + NUM2DBL(kkconst)); + + return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res); + +} + +/* call-seq: + * graph.layout_reingold_tilford -> IGraphMatrix + * + * Reingold-Tilford layout for tree graphs + * + * Arranges the nodes in a tree where the given node is used as the root. + * The tree is directed downwards and the parents are centered above its + * children. For the exact algorithm, see: + * + * Reingold, E and Tilford, J: Tidier drawing of trees. IEEE Trans. Softw. + * Eng., SE-7(2):223--228, 1981 + * + * If the given graph is not a tree, a breadth-first search is executed + * first to obtain a possible spanning tree. + */ +VALUE cIGraph_layout_reingold_tilford(VALUE self, + VALUE root){ + + igraph_t *graph; + igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t)); + + Data_Get_Struct(self, igraph_t, graph); + + igraph_matrix_init(res,0,0); + igraph_layout_reingold_tilford(graph,res, + cIGraph_get_vertex_id(self, root)); + + return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res); + +} + +/* call-seq: + * graph.layout_reingold_tilford_circular -> IGraphMatrix + * + * Reingold-Tilford layout for tree graphs, drawn in a circular style + * + * Arranges the nodes in a tree where the given node is used as the root. + * The tree is directed downwards and the parents are centered above its + * children. For the exact algorithm, see: + * + * Reingold, E and Tilford, J: Tidier drawing of trees. IEEE Trans. Softw. + * Eng., SE-7(2):223--228, 1981 + * + * If the given graph is not a tree, a breadth-first search is executed + * first to obtain a possible spanning tree. + */ +VALUE cIGraph_layout_reingold_tilford_circular(VALUE self, + VALUE root){ + + igraph_t *graph; + igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t)); + + Data_Get_Struct(self, igraph_t, graph); + + igraph_matrix_init(res,0,0); + igraph_layout_reingold_tilford_circular(graph,res, + cIGraph_get_vertex_id(self, root)); + + return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res); + +} + +/* call-seq: + * graph.layout_grid_fruchterman_reingold -> IGraphMatrix + * + * Places the vertices on a plane according to the Fruchterman-Reingold + * algorithm. + * + * This is a force-directed layout, see Fruchterman, T.M.J. and Reingold, + * E.M.: Graph Drawing by Force-directed Placement. Software -- Practice and + * Experience, 21/11, 1129--1164, 1991. + */ +VALUE cIGraph_layout_grid_fruchterman_reingold(VALUE self, + VALUE niter, + VALUE maxdelta, + VALUE area, + VALUE coolexp, + VALUE repulserad, + VALUE cellsize, + VALUE use_seed){ + + igraph_t *graph; + igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t)); + + Data_Get_Struct(self, igraph_t, graph); + + igraph_matrix_init(res,0,0); + igraph_layout_grid_fruchterman_reingold(graph,res, + NUM2INT(niter), + NUM2DBL(maxdelta), + NUM2DBL(area), + NUM2DBL(coolexp), + NUM2DBL(repulserad), + NUM2DBL(cellsize), + use_seed == Qtrue ? 1: 0); + + return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res); + +} + +/* call-seq: + * graph.layout_lgl -> IGraphMatrix + * + * Places the vertices on a plane according to the Fruchterman-Reingold + * algorithm. + * + * This is a force-directed layout, see Fruchterman, T.M.J. and Reingold, + * E.M.: Graph Drawing by Force-directed Placement. Software -- Practice and + * Experience, 21/11, 1129--1164, 1991. + */ +VALUE cIGraph_layout_lgl(VALUE self, + VALUE maxit, + VALUE maxdelta, + VALUE area, + VALUE coolexp, + VALUE repulserad, + VALUE cellsize, + VALUE proot){ + + igraph_t *graph; + igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t)); + + Data_Get_Struct(self, igraph_t, graph); + + igraph_matrix_init(res,0,0); + igraph_layout_lgl(graph,res, + NUM2INT(maxit), + NUM2DBL(maxdelta), + NUM2DBL(area), + NUM2DBL(coolexp), + NUM2DBL(repulserad), + NUM2DBL(cellsize), + cIGraph_get_vertex_id(self, proot)); + + return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res); + +} + diff --git a/test/tc_layout.rb b/test/tc_layout.rb index e8dde79..ec5364b 100644 --- a/test/tc_layout.rb +++ b/test/tc_layout.rb @@ -23,4 +23,39 @@ class TestGraph < Test::Unit::TestCase assert_equal g.vcount, l.nrow assert_equal 2, l.ncol end + def test_kamada_kawai + g = IGraph.new([1,2,3,4],true) + l = g.layout_kamada_kawai(10,1,1,2,1) + assert_instance_of IGraphMatrix, l + assert_equal g.vcount, l.nrow + assert_equal 2, l.ncol + end + def test_reingold_tilford + g = IGraph.new([1,2,3,4],true) + l = g.layout_reingold_tilford(1) + assert_instance_of IGraphMatrix, l + assert_equal g.vcount, l.nrow + assert_equal 2, l.ncol + end + def test_reingold_tilford_circular + g = IGraph.new([1,2,3,4],true) + l = g.layout_reingold_tilford_circular(1) + assert_instance_of IGraphMatrix, l + assert_equal g.vcount, l.nrow + assert_equal 2, l.ncol + end + def test_grid_fruchterman_reingold + g = IGraph.new([1,2,3,4],true) + l = g.layout_grid_fruchterman_reingold(10,1,1,2,1,1,false) + assert_instance_of IGraphMatrix, l + assert_equal g.vcount, l.nrow + assert_equal 2, l.ncol + end + def test_lgl + g = IGraph.new([1,2,3,4],true) + l = g.layout_lgl(10,1,1,2,1,1,1) + assert_instance_of IGraphMatrix, l + assert_equal g.vcount, l.nrow + assert_equal 2, l.ncol + end end diff --git a/test/test_all.rb b/test/test_all.rb index 42e9bc5..b063457 100644 --- a/test/test_all.rb +++ b/test/test_all.rb @@ -16,6 +16,7 @@ require 'tc_dijkstra' require 'tc_directedness' require 'tc_error_handling' require 'tc_file_read_write' +require 'tc_generators_random' require 'tc_independent_vertex_sets' require 'tc_isomorphic' require 'tc_iterators'