alexgutteridge 19 years ago
parent
commit
9e7c53c386
12 changed files with 564 additions and 40 deletions
  1. +7
    -11
      README.txt
  2. +42
    -10
      ext/cIGraph.c
  3. +19
    -5
      ext/cIGraph.h
  4. +30
    -9
      ext/cIGraph_add_delete.c
  5. +47
    -0
      ext/cIGraph_attribute_handler.c
  6. +196
    -2
      ext/cIGraph_shortest_paths.c
  7. +3
    -3
      ext/cIGraph_utility.c
  8. +155
    -0
      ext/cIGraph_vertex_neighbourhood.c
  9. +24
    -0
      test/tc_attributes.rb
  10. +23
    -0
      test/tc_shortest_paths.rb
  11. +16
    -0
      test/tc_vertex_neighbourhood.rb
  12. +2
    -0
      test/test_all.rb

+ 7
- 11
README.txt View File

@@ -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



+ 42
- 10
ext/cIGraph.c View File

@@ -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);}

+ 19
- 5
ext/cIGraph.h View File

@@ -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);

+ 30
- 9
ext/cIGraph_add_delete.c View File

@@ -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;


+ 47
- 0
ext/cIGraph_attribute_handler.c View File

@@ -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;
}

+ 196
- 2
ext/cIGraph_shortest_paths.c View File

@@ -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;

}

+ 3
- 3
ext/cIGraph_utility.c View File

@@ -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;


+ 155
- 0
ext/cIGraph_vertex_neighbourhood.c View File

@@ -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;

}




+ 24
- 0
test/tc_attributes.rb View File

@@ -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

+ 23
- 0
test/tc_shortest_paths.rb View File

@@ -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

+ 16
- 0
test/tc_vertex_neighbourhood.rb View File

@@ -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
- 0
test/test_all.rb View File

@@ -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'

Loading…
Cancel
Save