| @@ -198,6 +198,11 @@ void Init_igraph(){ | |||
| rb_define_const(cIGraph, "WEAK", INT2NUM(1)); | |||
| rb_define_const(cIGraph, "STRONG", INT2NUM(2)); | |||
| rb_define_const(cIGraph, "ARBITRARY", INT2NUM(0)); | |||
| rb_define_const(cIGraph, "MUTUAL", INT2NUM(1)); | |||
| rb_define_const(cIGraph, "EACH", INT2NUM(0)); | |||
| rb_define_const(cIGraph, "COLLAPSE", INT2NUM(1)); | |||
| 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", "[]"); | |||
| @@ -269,9 +274,16 @@ void Init_igraph(){ | |||
| rb_define_method(cIGraph, "minimum_spanning_tree_unweighted", cIGraph_minimum_spanning_tree_unweighted, 0); /* in cIGraph_spanning.c */ | |||
| rb_define_method(cIGraph, "minimum_spanning_tree_prim", cIGraph_minimum_spanning_tree_prim, 1); /* in cIGraph_spanning.c */ | |||
| rb_define_method(cIGraph, "transitivity", cIGraph_transitivity, 0); | |||
| rb_define_method(cIGraph, "transitivity_local", cIGraph_transitivity_local, 1); | |||
| rb_define_method(cIGraph, "transitivity_avglocal", cIGraph_transitivity_avglocal, 0); | |||
| rb_define_method(cIGraph, "transitivity", cIGraph_transitivity, 0); /* in cIGraph_transitivity.c */ | |||
| rb_define_method(cIGraph, "transitivity_local", cIGraph_transitivity_local, 1); /* in cIGraph_transitivity.c */ | |||
| rb_define_method(cIGraph, "transitivity_avglocal", cIGraph_transitivity_avglocal, 0); /* in cIGraph_transitivity.c */ | |||
| rb_define_method(cIGraph, "to_directed", cIGraph_to_directed, 1); /* in cIGraph_direction.c */ | |||
| rb_define_method(cIGraph, "to_undirected", cIGraph_to_undirected, 1); /* in cIGraph_direction.c */ | |||
| rb_define_method(cIGraph, "laplacian", cIGraph_laplacian, 1); /* in cIGraph_spectral.c */ | |||
| rb_define_method(cIGraph, "coreness", cIGraph_coreness, 1); /* in cIGraph_kcores.c */ | |||
| rb_define_method(cIGraph, "topological_sorting", cIGraph_topological_sorting, 1); /* in cIGraph_topological_sort.c */ | |||
| @@ -109,6 +109,16 @@ VALUE cIGraph_transitivity (VALUE self); | |||
| VALUE cIGraph_transitivity_local (VALUE self, VALUE vs); | |||
| VALUE cIGraph_transitivity_avglocal(VALUE self); | |||
| //Directedness conversion | |||
| VALUE cIGraph_to_directed (VALUE self, VALUE mode); | |||
| VALUE cIGraph_to_undirected(VALUE self, VALUE mode); | |||
| //Spectral properties | |||
| VALUE cIGraph_laplacian(VALUE self, VALUE mode); | |||
| //K-Cores | |||
| VALUE cIGraph_coreness(VALUE self, VALUE mode); | |||
| //Topological sorting | |||
| VALUE cIGraph_topological_sorting(VALUE self, VALUE mode); | |||
| @@ -0,0 +1,39 @@ | |||
| #include "igraph.h" | |||
| #include "ruby.h" | |||
| #include "cIGraph.h" | |||
| /* call-seq: | |||
| * graph.to_directed(mode) | |||
| * | |||
| * Converts the graph to a directed graph. | |||
| */ | |||
| VALUE cIGraph_to_directed(VALUE self, VALUE mode){ | |||
| igraph_t *graph; | |||
| igraph_neimode_t pmode = NUM2INT(mode); | |||
| int ret; | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| IGRAPH_CHECK(ret = igraph_to_directed(graph,pmode)); | |||
| return INT2NUM(ret); | |||
| } | |||
| /* call-seq: | |||
| * graph.to_undirected(mode) | |||
| * | |||
| * Converts the graph to a directed graph. | |||
| */ | |||
| VALUE cIGraph_to_undirected(VALUE self, VALUE mode){ | |||
| igraph_t *graph; | |||
| igraph_neimode_t pmode = NUM2INT(mode); | |||
| int ret; | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| IGRAPH_CHECK(ret = igraph_to_undirected(graph,pmode)); | |||
| return INT2NUM(ret); | |||
| } | |||
| @@ -0,0 +1,39 @@ | |||
| #include "igraph.h" | |||
| #include "ruby.h" | |||
| #include "cIGraph.h" | |||
| /* call-seq: | |||
| * graph.coreness(mode) -> Array | |||
| * | |||
| * Finding the coreness of the vertices in a network. The k-core of a | |||
| * graph is a maximal subgraph in which each vertex has at least degree k. | |||
| * (Degree here means the degree in the subgraph of course.). The coreness | |||
| * of a vertex is the highest order of a k-core containing the vertex. | |||
| * | |||
| * This function implements the algorithm presented in Vladimir Batagelj, | |||
| * Matjaz Zaversnik: An O(m) Algorithm for Cores Decomposition of Networks. | |||
| */ | |||
| VALUE cIGraph_coreness(VALUE self, VALUE mode){ | |||
| igraph_t *graph; | |||
| igraph_neimode_t pmode = NUM2INT(mode); | |||
| igraph_vector_t cores; | |||
| int i; | |||
| VALUE result = rb_ary_new(); | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| //vector to hold the results of the calculations | |||
| igraph_vector_init(&cores,0); | |||
| igraph_coreness(graph,&cores,pmode); | |||
| for(i=0; i< igraph_vector_size(&cores); i++){ | |||
| rb_ary_push(result,VECTOR(cores)[i]); | |||
| } | |||
| igraph_vector_destroy(&cores); | |||
| return result; | |||
| } | |||
| @@ -0,0 +1,57 @@ | |||
| #include "igraph.h" | |||
| #include "ruby.h" | |||
| #include "cIGraph.h" | |||
| /* call-seq: | |||
| * graph.laplacian(mode) -> Array | |||
| * | |||
| * Returns the Laplacian matrix of a graph | |||
| * | |||
| * The graph Laplacian matrix is similar to an adjacency matrix but | |||
| * contains -1's instead of 1's and the vertex degrees are included | |||
| * in the diagonal. So the result for edge i--j is -1 if i!=j and is | |||
| * equal to the degree of vertex i if i==j. igraph_laplacian will work | |||
| * on a directed graph (although this does not seem to make much sense) | |||
| * and ignores loops. | |||
| * | |||
| * Mode is a boolean specifying whether the normalized version should be used | |||
| * The normalised Laplacian matrix has 1 in the diagonal | |||
| * and -1/sqrt(d[i]d[j]) if there is an edge from i to j. | |||
| * | |||
| * The first version of this function was written by Vincent Matossian. | |||
| */ | |||
| VALUE cIGraph_laplacian(VALUE self, VALUE mode){ | |||
| igraph_t *graph; | |||
| igraph_bool_t pmode = 0; | |||
| igraph_matrix_t res; | |||
| int i; | |||
| int j; | |||
| VALUE row; | |||
| VALUE val; | |||
| VALUE matrix = rb_ary_new(); | |||
| if(mode = Qtrue) | |||
| pmode = 1; | |||
| Data_Get_Struct(self, igraph_t, graph); | |||
| //matrix to hold the results of the calculations | |||
| igraph_matrix_init(&res,igraph_vcount(graph),igraph_vcount(graph)); | |||
| IGRAPH_CHECK(igraph_laplacian(graph,&res,pmode)); | |||
| for(i=0; i<igraph_matrix_nrow(&res); i++){ | |||
| row = rb_ary_new(); | |||
| rb_ary_push(matrix,row); | |||
| for(j=0; j<igraph_matrix_ncol(&res); j++){ | |||
| val = rb_float_new(MATRIX(res,i,j)); | |||
| rb_ary_push(row,val); | |||
| } | |||
| } | |||
| igraph_matrix_destroy(&res); | |||
| return matrix; | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_coreness | |||
| g = IGraph.new(['A','B','C','D'],true) | |||
| c = g.coreness(IGraph::ALL) | |||
| assert_equal c.length, g.vcount | |||
| end | |||
| end | |||
| @@ -0,0 +1,31 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_directed_conv | |||
| g = IGraph.new(['A','B','B','C','C','D'],false) | |||
| g.to_directed(IGraph::ARBITRARY) | |||
| assert g.are_connected?('A','B') || g.are_connected?('B','A') | |||
| assert !(g.are_connected?('A','B') && g.are_connected?('B','A')) | |||
| g = IGraph.new(['A','B','B','C','C','D'],false) | |||
| g.to_directed(IGraph::MUTUAL) | |||
| assert g.are_connected?('A','B') && g.are_connected?('B','A') | |||
| end | |||
| def test_undirected | |||
| g = IGraph.new(['A','B','B','A','B','C','C','D'],true) | |||
| g.to_undirected(IGraph::EACH) | |||
| assert_equal 4, g.ecount | |||
| g = IGraph.new(['A','B','B','A','B','C','C','D'],true) | |||
| g.to_undirected(IGraph::COLLAPSE) | |||
| assert_equal 3, g.ecount | |||
| end | |||
| end | |||
| @@ -0,0 +1,31 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_directed | |||
| g = IGraph.new(['A','B','B','C','C','D'],false) | |||
| g.to_directed(IGraph::ARBITRARY) | |||
| assert g.are_connected?('A','B') || g.are_connected?('B','A') | |||
| assert !(g.are_connected?('A','B') && g.are_connected?('B','A')) | |||
| g = IGraph.new(['A','B','B','C','C','D'],false) | |||
| g.to_directed(IGraph::MUTUAL) | |||
| assert g.are_connected?('A','B') && g.are_connected?('B','A') | |||
| end | |||
| def test_undirected | |||
| g = IGraph.new(['A','B','B','A','B','C','C','D'],true) | |||
| g.to_undirected(IGraph::EACH) | |||
| assert_equal 4, g.ecount | |||
| g = IGraph.new(['A','B','B','A','B','C','C','D'],true) | |||
| g.to_undirected(IGraph::COLLAPSE) | |||
| assert_equal 3, g.ecount | |||
| end | |||
| end | |||
| @@ -0,0 +1,44 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_shortest_paths | |||
| graph = IGraph.new(['A','B','C','D'],true) | |||
| m = graph.shortest_paths(['A'],IGraph::ALL) | |||
| assert_equal 1, m[0][1] | |||
| assert_equal 0, m[0][0] | |||
| assert_equal graph.vcount, m[0].size | |||
| assert_equal nil, m[0][2] | |||
| end | |||
| def test_get_shortest_paths | |||
| graph = IGraph.new(['A','B','C','D'],true) | |||
| m = graph.get_shortest_paths('A',['B'],IGraph::ALL) | |||
| assert_equal ['A','B'], m[0] | |||
| #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,33 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_closeness | |||
| g = IGraph.new(['A','B','B','C','C','D'],true) | |||
| assert_equal [0.75], g.closeness(['B'],IGraph::ALL) | |||
| end | |||
| def test_betweenness | |||
| g = IGraph.new(['A','B','B','C','C','D'],true) | |||
| assert_equal [0,2], g.betweenness(['A','B'],true) | |||
| end | |||
| def test_edge_betweenness | |||
| g = IGraph.new(['A','B','C','D'],true) | |||
| assert_equal [1,1], g.edge_betweenness(true) | |||
| end | |||
| def test_pagerank | |||
| g = IGraph.new(['A','B','C','D','E','B','F','B'],true) | |||
| assert_equal 67, (g.pagerank(['B'],true,100,0.01,0.8)[0] * 100).to_i | |||
| end | |||
| def test_constraint | |||
| g = IGraph.new(['A','B','C','D'],true) | |||
| assert_equal [1], g.constraint(['A']) | |||
| assert_raises IGraphError do | |||
| g.constraint(['A'],[3]) | |||
| end | |||
| assert_equal [1], g.constraint(['A'],[2,3]) | |||
| end | |||
| def test_maxdegree | |||
| g = IGraph.new(['A','B','C','D','A','E','A','F'],true) | |||
| assert_equal 3, g.maxdegree(g.vertices,IGraph::ALL,true) | |||
| end | |||
| end | |||
| @@ -0,0 +1,12 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_laplacian | |||
| g = IGraph.new(['A','B','C','D'],false) | |||
| m = g.laplacian(false) | |||
| assert_equal m.length, g.vcount | |||
| m = g.laplacian(true) | |||
| assert_equal m.length, g.vcount | |||
| end | |||
| end | |||
| @@ -0,0 +1,12 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_laplacian | |||
| g = IGraph.new(['A','B','C','D'],true) | |||
| m = g.laplacian(false) | |||
| p m | |||
| m = g.laplacian(true) | |||
| p m | |||
| end | |||
| end | |||
| @@ -0,0 +1,41 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class Array | |||
| def mean | |||
| total = 0.0 | |||
| self.each do |i| | |||
| total += i | |||
| end | |||
| total / self.length.to_f | |||
| end | |||
| end | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_thrash | |||
| g = IGraph.new([],true) | |||
| v = 100 | |||
| v.times do |x| | |||
| g.add_vertex(x) | |||
| end | |||
| 200.times do |x| | |||
| g.add_edge(rand(v/2),rand(v/2)) | |||
| end | |||
| 200.times do |x| | |||
| g.add_edge(rand(v/2)+v/2,rand(v/2)+v/2) | |||
| end | |||
| assert_equal v, g.vcount | |||
| h,i = g.decompose(IGraph::WEAK,-1,2) | |||
| p h.vcount | |||
| p i.vcount | |||
| p h.degree(h.to_a[20..30],IGraph::ALL,false).mean | |||
| p h.degree(h.to_a[10..20],IGraph::ALL,false).mean | |||
| p h.betweenness(h.to_a[20..30],true).mean | |||
| p h.betweenness(h.to_a[10..20],true).mean | |||
| end | |||
| end | |||
| @@ -0,0 +1,13 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_thrash | |||
| g = IGraph.new([],true) | |||
| 10_000.times do |x| | |||
| g.add_vertex(x) | |||
| end | |||
| assert_equal 10_000, g.vcount | |||
| end | |||
| end | |||
| @@ -0,0 +1,25 @@ | |||
| require 'test/unit' | |||
| require 'igraph' | |||
| class TestGraph < Test::Unit::TestCase | |||
| def test_subcomponent | |||
| g = IGraph.new([1,2,3,4]) | |||
| assert_equal [1,2], g.subcomponent(1,IGraph::ALL) | |||
| end | |||
| def test_subgraph | |||
| g = IGraph.new([1,2,3,4]) | |||
| h = g.subgraph([1,2]) | |||
| assert_equal 2, h.vcount | |||
| assert_equal [1,2], h.vertices | |||
| end | |||
| def test_clusters | |||
| g = IGraph.new([1,2,3,4]) | |||
| assert_equal 2, g.clusters(IGraph::WEAK).length | |||
| assert_equal [1,2], g.clusters(IGraph::WEAK)[0] | |||
| end | |||
| def test_decompose | |||
| g = IGraph.new([1,2,3,4]) | |||
| assert_equal 2, g.decompose(IGraph::WEAK).length | |||
| assert_equal [1,2], g.decompose(IGraph::WEAK)[0].vertices | |||
| end | |||
| end | |||
| @@ -12,12 +12,15 @@ require 'tc_basic_properties' | |||
| require 'tc_centrality' | |||
| require 'tc_components' | |||
| require 'tc_copy' | |||
| require 'tc_cores' | |||
| require 'tc_directedness' | |||
| require 'tc_error_handling' | |||
| require 'tc_file_read_write' | |||
| require 'tc_layout' | |||
| require 'tc_matrix' | |||
| require 'tc_shortest_paths' | |||
| require 'tc_spanning' | |||
| require 'tc_spectral' | |||
| require 'tc_topological_sort' | |||
| require 'tc_transitivity' | |||
| require 'tc_vertex_neighbourhood' | |||