Compare commits

...

No commits in common. "0.1.1-prerelease" and "master" have entirely different histories.

81 changed files with 9899 additions and 2895 deletions

View File

@ -1,3 +1,28 @@
= 0.1 2007-06-29
= 0.9 2007-11-19
* First version
* All igraph functions wrapped
* Documentation updated with examples
= 0.3.2 2007-09-03
* All 'structural property' functions now complete.
= 0.3.1 2007-08-31
* New functions added
= 0.3 2007-08-16
* Over-hauled attribute code
* Some file read/write support
= 0.2 2007-07-31
* 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

View File

@ -2,23 +2,80 @@ History.txt
License.txt
Manifest.txt
README.txt
Rakefile.rb
ext/cIGraph.c
ext/cIGraph.h
ext/cIGraph_add_delete.c
ext/cIGraph_attribute_handler.c
ext/cIGraph_basic_properties.c
ext/cIGraph_basic_query.c
ext/cIGraph_centrality.c
ext/cIGraph_cliques.c
ext/cIGraph_community.c
ext/cIGraph_components.c
ext/cIGraph_connectivity.c
ext/cIGraph_dijkstra.c
ext/cIGraph_direction.c
ext/cIGraph_error_handlers.c
ext/cIGraph_file.c
ext/cIGraph_generators_deterministic.c
ext/cIGraph_generators_random.c
ext/cIGraph_independent_vertex_sets.c
ext/cIGraph_isomorphism.c
ext/cIGraph_iterators.c
ext/cIGraph_kcores.c
ext/cIGraph_layout.c
ext/cIGraph_layout3d.c
ext/cIGraph_matrix.c
ext/cIGraph_min_cuts.c
ext/cIGraph_motif.c
ext/cIGraph_operators.c
ext/cIGraph_other_ops.c
ext/cIGraph_randomisation.c
ext/cIGraph_selectors.c
ext/cIGraph_shortest_paths.c
ext/cIGraph_spanning.c
ext/cIGraph_spectral.c
ext/cIGraph_topological_sort.c
ext/cIGraph_transitivity.c
ext/cIGraph_utility.c
ext/cIGraph_vertex_neighbourhood.c
ext/extconf.rb
test/tc_add_delete.rb
test/tc_adj_to_distance.rb
test/tc_attributes.rb
test/tc_basic_properties.rb
test/tc_basic_query.rb
test/tc_centrality.rb
test/tc_cliques.rb
test/tc_community.rb
test/tc_components.rb
test/tc_connectivity.rb
test/tc_copy.rb
test/tc_cores.rb
test/tc_create.rb
test/tc_dijkstra.rb
test/tc_directedness.rb
test/tc_error_handling.rb
test/tc_file_read_write.rb
test/tc_generators_deterministic.rb
test/tc_generators_random.rb
test/tc_independent_vertex_sets.rb
test/tc_isomorphic.rb
test/tc_iterators.rb
test/tc_layout.rb
test/tc_layout3d.rb
test/tc_matrix.rb
test/tc_mincuts.rb
test/tc_motif.rb
test/tc_other_ops.rb
test/tc_randomisation.rb
test/tc_selectors.rb
test/tc_shortest_paths.rb
test/tc_spanning.rb
test/tc_spectral.rb
test/tc_thrash.rb
test/tc_topological_sort.rb
test/tc_transitivity.rb
test/tc_vertex_neighbourhood.rb
test/test_all.rb

View File

@ -1,32 +1,77 @@
== Introduction
IGraph
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
IGraph is currently in beta status and the API should be considered stable. The main documentation can be found at http://igraph.rubyforge.org/igraph/ though it is incomplete in places. you can also see the test suite for examples of how to use the various functions.
IGraph
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 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:
IGraph is only 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):
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
Here is a very quick and simple example:
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. The graph generators will use simple Integers as the vertices, but you can use any object as a vertex and edges can also be annotated with any kind of object.
require 'igraph'
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.
graph = IGraph.new([],true)
Here are three examples which translate the C tutorial programs from the igraph documentation (http://cneurocvs.rmki.kfki.hu/igraph/doc/html/igraph-tutorial.html).
= 1.
require 'igraph'
g = IGraph::GenerateRandom.erdos_renyi_game(IGraph::ERDOS_RENYI_GNP,
1000, 5.0/1000,
false, false)
d = g.diameter(false,true).size-1
puts "Diameter of a random graph with average degree 5: #{d}"
= 2.
require 'igraph'
graph = IGraph::Generate.lattice([30,30],false,false,true)
puts "Average path (lattice): #{graph.average_path_length(false,true)}"
graph.add_edges(Array.new(20){rand(graph.vcount)})
puts "Average path (randomised): #{graph.average_path_length(false,true)}"
= 3.
require 'igraph'
edges = [
0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
0, 10, 0,11, 0,12, 0,13, 0,17, 0,19, 0,21, 0,31,
1, 2, 1, 3, 1, 7, 1,13, 1,17, 1,19, 1,21, 1,30,
2, 3, 2, 7, 2,27, 2,28, 2,32, 2, 9, 2, 8, 2,13,
3, 7, 3,12, 3,13, 4, 6, 4,10, 5, 6, 5,10, 5,16,
6, 16, 8,32, 8,32, 8,33, 9,33,13,33,14,32,14,33,
15,32,15,33,18,32,18,33,19,33,20,32,20,33,
22,32,22,33,23,25,23,27,23,32,23,33,23,29,
24,25,24,27,24,31,25,31,26,29,26,33,27,33,
28,31,28,33,29,32,29,33,30,32,30,33,31,32,31,33,
32,33
]
g = IGraph.new(edges,false)
vs = g.vertices
max = vs.zip(g.degree(vs,IGraph::ALL,true)).max{|a,b| a[1] <=> b[1]}
puts "Maximum degree is #{sprintf("%10i",max[1])}, vertex #{max[0]}."
max = vs.zip(g.closeness(vs,IGraph::ALL)).max{|a,b| a[1] <=> b[1]}
puts "Maximum closeness is #{sprintf("%10f",max[1])}, vertex #{max[0]}."
max = vs.zip(g.betweenness(vs,IGraph::ALL)).max{|a,b| a[1] <=> b[1]}
puts "Maximum betweenness is #{sprintf("%10f",max[1])}, vertex #{max[0]}."
== License

View File

@ -1,12 +1,20 @@
require 'hoe'
$LOAD_PATH.unshift("./lib")
$LOAD_PATH.unshift("./ext")
hoe = Hoe.new("igraph",'0.1.1') do |p|
class IGraph
VERSION = "0.9.7"
end
#begin
# require 'igraph'
#rescue RuntimeError
#end
hoe = Hoe.new("igraph",IGraph::VERSION) do |p|
p.author = "Alex Gutteridge"
p.email = "alexg@kuicr.kyoto-u.ac.jp"
p.email = "ag357@cam.ac.uk"
p.url = "http://igraph.rubyforge.org/"
p.description = p.paragraphs_of("README.txt",1..3)[0]
@ -25,18 +33,6 @@ hoe = Hoe.new("igraph",'0.1.1') do |p|
:rdoc_options => ["--exclude", "test/*", "--main", "README.txt", "--inline-source"]
}
task :setup_rb_package => [:clean, :package, :build_manual] do
package_dir = "#{p.name}-#{p.version}"
cp("setup.rb","pkg/#{package_dir}")
cp("manual.pdf","pkg/#{package_dir}")
Dir.chdir("pkg")
system("tar -czf #{p.name}-#{p.version}.tgz #{package_dir}")
Dir.chdir("..")
end
end
hoe.spec.dependencies.delete_if{|dep| dep.name == "hoe"}
@ -54,16 +50,3 @@ file 'ext/igraph.so' => SRC do
end
task :test => [:build_extension]
desc "Build PDF manual"
task :build_manual => ["manual.pdf"]
file "manual.pdf" => ["manual.tex"] do
out = 'Rerun'
while out.match(/Rerun/)
out = `pdflatex manual.tex`
end
end
task :build_manual_clean => [:build_manual] do
system("rm manual.{aux,log,out,toc}")
end

View File

@ -2,8 +2,19 @@
#include "ruby.h"
#include "cIGraph.h"
//Classes
VALUE cIGraph;
VALUE cIGraphError;
void cIGraph_free(void *p){
igraph_destroy(p);
free(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){
@ -12,12 +23,38 @@ VALUE cIGraph_alloc(VALUE klass){
VALUE obj;
igraph_empty(graph, 0, 1);
obj = Data_Wrap_Struct(klass, 0, cIGraph_free, graph);
obj = Data_Wrap_Struct(klass, cIGraph_mark, cIGraph_free, graph);
return obj;
}
/* Document-method: initialize_copy
*
* Internal method for copying IGraph objects.
*/
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_CHECK(igraph_copy(copy_graph,orig_graph));
return copy;
}
/* call-seq:
* IGraph.new(edges,directed) -> IGraph
*
@ -38,123 +75,557 @@ 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;
VALUE v_ary;
int vertex_n = 0;
int current_vertex_id;
int i;
igraph_set_error_handler(cIGraph_error_handler);
igraph_set_warning_handler(cIGraph_warning_handler);
igraph_vector_ptr_t vertex_attr;
igraph_vector_ptr_t edge_attr;
//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());
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
igraph_vector_init_int(&edge_v,0);
IGRAPH_FINALLY(igraph_vector_destroy,&edge_v);
IGRAPH_FINALLY(igraph_vector_ptr_destroy,&vertex_attr);
IGRAPH_FINALLY(igraph_vector_ptr_destroy,&edge_attr);
IGRAPH_CHECK(igraph_vector_init_int(&edge_v,0));
IGRAPH_CHECK(igraph_vector_ptr_init(&vertex_attr,0));
IGRAPH_CHECK(igraph_vector_ptr_init(&edge_attr,0));
Data_Get_Struct(self, igraph_t, graph);
v_ary = rb_ary_new();
if(!directed)
igraph_to_undirected(graph,IGRAPH_TO_UNDIRECTED_COLLAPSE);
IGRAPH_CHECK(igraph_to_undirected(graph,IGRAPH_TO_UNDIRECTED_COLLAPSE));
//Loop through objects in edge Array
vertex = rb_ary_shift(edges);
while(vertex != Qnil){
if(rb_funcall(object_h,rb_intern("has_key?"),1,vertex)){
for (i=0; i<RARRAY_LEN(edges); i++) {
vertex = RARRAY_PTR(edges)[i];
if(rb_ary_includes(v_ary,vertex)){
//If @vertices includes this vertex then look up the vertex number
current_vertex_id = NUM2INT(rb_hash_aref(object_h,vertex));
current_vertex_id = NUM2INT(rb_funcall(v_ary,rb_intern("index"),1,vertex));
} else {
//otherwise add a new entry to Hash
rb_hash_aset(object_h,vertex,INT2NUM(vertex_n));
rb_hash_aset(id_h, INT2NUM(vertex_n),vertex);
//Otherwise add to the list of vertices
rb_ary_push(v_ary,vertex);
current_vertex_id = vertex_n;
vertex_n++;
//Add object to list of vertex attributes
rb_ary_push((VALUE)v_attr_rec.value,vertex);
}
IGRAPH_CHECK(igraph_vector_push_back(&edge_v,current_vertex_id));
if (i % 2){
if (attrs != Qnil){
rb_ary_push((VALUE)e_attr_rec.value,RARRAY_PTR(attrs)[i/2]);
} else {
rb_ary_push((VALUE)e_attr_rec.value,Qnil);
}
}
igraph_vector_push_back(&edge_v,current_vertex_id);
vertex = rb_ary_shift(edges);
}
IGRAPH_CHECK(igraph_vector_ptr_push_back(&vertex_attr, &v_attr_rec));
IGRAPH_CHECK(igraph_vector_ptr_push_back(&edge_attr, &e_attr_rec));
if(igraph_vector_size(&edge_v) > 0){
igraph_add_vertices(graph,vertex_n,0);
igraph_add_edges(graph,&edge_v,0);
IGRAPH_CHECK(igraph_add_vertices(graph,vertex_n,&vertex_attr));
IGRAPH_CHECK(igraph_add_edges(graph,&edge_v,&edge_attr));
}
igraph_vector_destroy(&edge_v);
igraph_vector_ptr_destroy(&vertex_attr);
igraph_vector_ptr_destroy(&edge_attr);
IGRAPH_FINALLY_CLEAN(3);
return self;
}
VALUE cIGraph_unavailable_method(int argc, VALUE *argv, VALUE self){
rb_raise(rb_eNoMethodError,"Method not available on OSX");
}
/* 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.
* for graph and network computation.
*
* Basic graph operations are defined on the IGraph class itself, but many
* other operations are defined in Modules included into IGraph:
*
* - Deterministic graph generation: IGraph::Generate
* - Random graph generation: IGraph::GenerateRandom
* - Graph randomisation: IGraph::Randomise
* - Shortest paths: IGraph::ShortestPaths
* - Vertex neighborhoods: IGraph::Neighborhood
* - Graph components: IGraph::Components
* - Closeness centrality calculations: IGraph::Closeness
* - Spanning tree: IGraph::Spanning
* - Transitivity calculations: IGraph::Transitivity
* - Spectral properties: IGraph::Spectral
* - Coreness: IGraph::KCores
* - Other operations: IGraph::OtherOperations
* - Clique calculations: IGraph::Cliques
* - Independent vertex sets: IGraph::IndependentVertexSets
* - Graph isomorphism: IGraph::Isomorphism
* - Motifs: IGraph::Motifs
* - Sorting: IGraph::Sorting
* - File read/write: IGraph::FileRead, IGraph::FileWrite
* - Graph layout algorithms: IGraph::Layout
* - Minimum cuts: IGraph::MinimumCuts
* - Connectivity: IGraph::Connectivity
* - Community: IGraph::Community
*
* Some methods return (or require as a paramter) an IGraphMatrix object. This
* class wraps the igraph C matrix type.
*/
void Init_igraph(){
cIGraph = rb_define_class("IGraph", rb_cObject);
//Modules
VALUE cIGraph_generate;
VALUE cIGraph_genrandom;
VALUE cIGraph_connectivity;
VALUE cIGraph_mincuts;
VALUE cIGraph_layout;
VALUE cIGraph_clique;
VALUE cIGraph_indyver;
VALUE cIGraph_isomor;
VALUE cIGraph_motifs;
VALUE cIGraph_sorting;
VALUE cIGraph_filewrite;
VALUE cIGraph_fileread;
VALUE cIGraph_community;
VALUE cIGraph_shortestpaths;
VALUE cIGraph_neighborhoodm;
VALUE cIGraph_components;
VALUE cIGraph_closenessm;
VALUE cIGraph_spanning;
VALUE cIGraph_transitivitym;
VALUE cIGraph_spectral;
VALUE cIGraph_kcore;
VALUE cIGraph_otherop;
VALUE cIGraph_randomise;
igraph_i_set_attribute_table(&cIGraph_attribute_table);
igraph_set_error_handler(cIGraph_error_handler);
igraph_set_warning_handler(cIGraph_warning_handler);
cIGraph = rb_define_class("IGraph", rb_cObject);
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, "initialize_copy", cIGraph_init_copy, 1);
rb_include_module(cIGraph, rb_mEnumerable);
/* Functions for deterministically generating graphs. */
cIGraph_generate = rb_define_module_under(cIGraph, "Generate");
rb_include_module(cIGraph, cIGraph_generate);
rb_define_singleton_method(cIGraph_generate, "adjacency", cIGraph_adjacency, 2); /* in cIGraph_generators_deterministic.c */
rb_define_singleton_method(cIGraph_generate, "star", cIGraph_star, 3); /* in cIGraph_generators_deterministic.c */
rb_define_singleton_method(cIGraph_generate, "lattice", cIGraph_lattice, 4); /* in cIGraph_generators_deterministic.c */
rb_define_singleton_method(cIGraph_generate, "ring", cIGraph_ring, 4); /* in cIGraph_generators_deterministic.c */
rb_define_singleton_method(cIGraph_generate, "tree", cIGraph_tree, 3); /* in cIGraph_generators_deterministic.c */
rb_define_singleton_method(cIGraph_generate, "full", cIGraph_full, 3); /* in cIGraph_generators_deterministic.c */
rb_define_singleton_method(cIGraph_generate, "atlas", cIGraph_atlas, 1); /* in cIGraph_generators_deterministic.c */
rb_define_singleton_method(cIGraph_generate, "extended_chordal_ring", cIGraph_extended_chordal_ring, 2); /* in cIGraph_generators_deterministic.c */
/* Functions for randomly generating graphs. */
cIGraph_genrandom = rb_define_module_under(cIGraph, "GenerateRandom");
rb_include_module(cIGraph, cIGraph_genrandom);
rb_define_singleton_method(cIGraph_genrandom, "grg_game", cIGraph_grg_game, 3); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "barabasi_game", cIGraph_barabasi_game, 4); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "nonlinear_barabasi_game", cIGraph_nonlinear_barabasi_game, 6); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "erdos_renyi_game", cIGraph_erdos_renyi_game, 5); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "watts_strogatz_game", cIGraph_watts_strogatz_game, 4); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "degree_sequence_game", cIGraph_degree_sequence_game, 2); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "growing_random_game", cIGraph_growing_random_game, 4); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "callaway_traits_game", cIGraph_callaway_traits_game, 6); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "establishment_game", cIGraph_establishment_game, 6); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "preference_game", cIGraph_preference_game, 6); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "asymmetric_preference_game", cIGraph_asymmetric_preference_game, 5); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "recent_degree_game", cIGraph_recent_degree_game, 7); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "barabasi_aging_game", cIGraph_barabasi_aging_game, 11); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "recent_degree_aging_game", cIGraph_recent_degree_aging_game, 9); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "cited_type_game", cIGraph_cited_type_game, 5); /* in cIGraph_generators_random.c */
rb_define_singleton_method(cIGraph_genrandom, "citing_cited_type_game", cIGraph_citing_cited_type_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", "[]");
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 */
rb_define_alias (cIGraph, "each", "each_vertex");
rb_define_method(cIGraph, "vertices", cIGraph_all_v, 0); /* in cIGraph_selectors.c */
rb_define_method(cIGraph, "adjacent_vertices", cIGraph_adj_v, 2); /* in cIGraph_selectors.c */
rb_define_method(cIGraph, "nonadjacent_vertices", cIGraph_nonadj_v, 2); /* in cIGraph_selectors.c */
rb_define_alias (cIGraph, "all_vertices", "vertices");
rb_define_method(cIGraph, "edges", cIGraph_all_e, 1); /* in cIGraph_selectors.c */
rb_define_method(cIGraph, "adjacent_edges", cIGraph_adj_e, 2); /* in cIGraph_selectors.c */
rb_define_alias (cIGraph, "all_edges", "edges");
rb_define_method(cIGraph, "vcount", cIGraph_vcount, 0); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "ecount", cIGraph_ecount, 0); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "edge", cIGraph_edge, 1); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "get_eid", cIGraph_get_eid, 2); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "neighbours", cIGraph_neighbors, 2); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "adjacent", cIGraph_adjacent, 2); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "degree", cIGraph_degree, 3); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "is_directed?", cIGraph_is_directed, 0); /* in cIGraph_basic_query.c */
rb_define_alias (cIGraph, "is_directed", "is_directed?");
rb_define_alias (cIGraph, "neighbors", "neighbours");
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, -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_vertex", cIGraph_delete_vertex, 1); /* in cIGraph_add_delete.c */
rb_define_method(cIGraph, "are_connected", cIGraph_are_connected,2); /* in cIGraph_basic_properties.c */
rb_define_alias (cIGraph, "are_connected?", "are_connected");
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 */
/* These methods randomise a graph by rewiring the edges. */
cIGraph_randomise = rb_define_module_under(cIGraph, "Randomise");
rb_include_module(cIGraph, cIGraph_randomise);
rb_define_method(cIGraph_randomise, "rewire_edges", cIGraph_rewire_edges, 1); /* in cIGraph_randomisation.c */
rb_define_method(cIGraph_randomise, "rewire", cIGraph_rewire, 1); /* in cIGraph_randomisation.c */
/* Functions for calculating the shortest path through a graph */
cIGraph_shortestpaths = rb_define_module_under(cIGraph, "ShortestPaths");
rb_include_module(cIGraph, cIGraph_shortestpaths);
rb_define_method(cIGraph_shortestpaths, "shortest_paths", cIGraph_shortest_paths, 2); /* in cIGraph_shortest_paths.c */
rb_define_method(cIGraph_shortestpaths, "get_shortest_paths", cIGraph_get_shortest_paths, 3); /* in cIGraph_shortest_paths.c */
rb_define_method(cIGraph_shortestpaths, "get_all_shortest_paths", cIGraph_get_all_shortest_paths, 3); /* in cIGraph_shortest_paths.c */
rb_define_method(cIGraph_shortestpaths, "average_path_length", cIGraph_average_path_length, 2); /* in cIGraph_shortest_paths.c */
rb_define_method(cIGraph_shortestpaths, "diameter", cIGraph_diameter, 2); /* in cIGraph_shortest_paths.c */
rb_define_method(cIGraph_shortestpaths, "girth", cIGraph_girth, 0); /* in cIGraph_shortest_paths.c */
rb_define_method(cIGraph_shortestpaths, "dijkstra_shortest_paths", cIGraph_dijkstra_shortest_paths, 3); /* in cIGraph_dijkstra.c */
/* Functions for querying the neighborhood of vertices */
cIGraph_neighborhoodm = rb_define_module_under(cIGraph, "Neighborhood");
rb_include_module(cIGraph, cIGraph_neighborhoodm);
rb_define_method(cIGraph_neighborhoodm, "neighbourhood_size", cIGraph_neighborhood_size, 3); /* in cIGraph_vertex_neighbourhood.c */
rb_define_method(cIGraph_neighborhoodm, "neighbourhood", cIGraph_neighborhood, 3); /* in cIGraph_vertex_neighbourhood.c */
rb_define_method(cIGraph_neighborhoodm, "neighbourhood_graphs", cIGraph_neighborhood_graphs, 3); /* in cIGraph_vertex_neighbourhood.c */
rb_define_alias (cIGraph_neighborhoodm, "neighborhood_size", "neighbourhood_size");
rb_define_alias (cIGraph_neighborhoodm, "neighborhood", "neighbourhood");
rb_define_alias (cIGraph_neighborhoodm, "neighborhood_graphs", "neighbourhood_graphs");
rb_define_method(cIGraph_neighborhoodm, "connect_neighborhood", cIGraph_connect_neighborhood, 2); /* in cIGraph_generators_deterministic.c */
/* Functions for splitting the graph into components */
cIGraph_components = rb_define_module_under(cIGraph, "Components");
rb_include_module(cIGraph, cIGraph_components);
rb_define_method(cIGraph_components, "subcomponent", cIGraph_subcomponent, 2); /* in cIGraph_components.c */
rb_define_method(cIGraph_components, "subgraph", cIGraph_subgraph, 1); /* in cIGraph_components.c */
rb_define_method(cIGraph_components, "clusters", cIGraph_clusters, 1); /* in cIGraph_components.c */
rb_define_method(cIGraph_components, "decompose", cIGraph_decompose, -1); /* in cIGraph_components.c */
/* Graph centrality functions */
cIGraph_closenessm = rb_define_module_under(cIGraph, "Closeness");
rb_include_module(cIGraph, cIGraph_closenessm);
rb_define_method(cIGraph_closenessm, "closeness", cIGraph_closeness, 2); /* in cIGraph_centrality.c */
rb_define_method(cIGraph_closenessm, "betweenness", cIGraph_betweenness, 2); /* in cIGraph_centrality.c */
rb_define_method(cIGraph_closenessm, "edge_betweenness", cIGraph_edge_betweenness, 1); /* in cIGraph_centrality.c */
rb_define_method(cIGraph_closenessm, "pagerank", cIGraph_pagerank, 5); /* in cIGraph_centrality.c */
rb_define_method(cIGraph_closenessm, "constraint", cIGraph_constraint, -1); /* in cIGraph_centrality.c */
rb_define_method(cIGraph_closenessm, "maxdegree", cIGraph_maxdegree, 3); /* in cIGraph_centrality.c */
/* Minimum spanning tree functions */
cIGraph_spanning = rb_define_module_under(cIGraph, "Spanning");
rb_include_module(cIGraph, cIGraph_spanning);
rb_define_method(cIGraph_spanning, "minimum_spanning_tree_unweighted", cIGraph_minimum_spanning_tree_unweighted, 0); /* in cIGraph_spanning.c */
rb_define_method(cIGraph_spanning, "minimum_spanning_tree_prim", cIGraph_minimum_spanning_tree_prim, 1); /* in cIGraph_spanning.c */
/* Graph transitivity functions */
cIGraph_transitivitym = rb_define_module_under(cIGraph, "Transitivity");
rb_include_module(cIGraph, cIGraph_transitivitym);
rb_define_method(cIGraph_transitivitym, "transitivity", cIGraph_transitivity, 0); /* in cIGraph_transitivity.c */
rb_define_method(cIGraph_transitivitym, "transitivity_local", cIGraph_transitivity_local, 1); /* in cIGraph_transitivity.c */
rb_define_method(cIGraph_transitivitym, "transitivity_avglocal", cIGraph_transitivity_avglocal, 0); /* in cIGraph_transitivity.c */
/* Functions for the Laplacian matrix. */
cIGraph_spectral = rb_define_module_under(cIGraph, "Spectral");
rb_include_module(cIGraph, cIGraph_spectral);
rb_define_method(cIGraph_spectral, "laplacian", cIGraph_laplacian, 1); /* in cIGraph_spectral.c */
/* Functions for finding the coreness of a graph */
cIGraph_kcore = rb_define_module_under(cIGraph, "KCores");
rb_include_module(cIGraph, cIGraph_kcore);
rb_define_method(cIGraph_kcore, "coreness", cIGraph_coreness, 1); /* in cIGraph_kcores.c */
/* Other general graph operations */
cIGraph_otherop = rb_define_module_under(cIGraph, "OtherOperations");
rb_include_module(cIGraph, cIGraph_otherop);
rb_define_method(cIGraph_otherop, "density", cIGraph_density, 1); /* in cIGraph_other_ops.c */
rb_define_method(cIGraph_otherop, "simplify", cIGraph_simplify, 2); /* in cIGraph_other_ops.c */
rb_define_method(cIGraph_otherop, "reciprocity", cIGraph_reciprocity, 1); /* in cIGraph_other_ops.c */
rb_define_method(cIGraph_otherop, "bibcoupling", cIGraph_bibcoupling, 1); /* in cIGraph_other_ops.c */
rb_define_method(cIGraph_otherop, "cocitation", cIGraph_cocitation, 1); /* in cIGraph_other_ops.c */
rb_define_method(cIGraph_otherop, "get_adjacency", cIGraph_get_adjacency, 1); /* in cIGraph_other_ops.c */
/* Clique finding functions */
cIGraph_clique = rb_define_module_under(cIGraph, "Cliques");
rb_include_module(cIGraph, cIGraph_clique);
rb_define_method(cIGraph_clique, "cliques", cIGraph_cliques, 2); /* in cIGraph_cliques.c */
rb_define_method(cIGraph_clique, "largest_cliques", cIGraph_largest_cliques, 0); /* in cIGraph_cliques.c */
rb_define_method(cIGraph_clique, "maximal_cliques", cIGraph_maximal_cliques, 0); /* in cIGraph_cliques.c */
rb_define_method(cIGraph_clique, "clique_number", cIGraph_clique_number, 0); /* in cIGraph_cliques.c */
/* Independent vertex set finding functions */
cIGraph_indyver = rb_define_module_under(cIGraph, "IndependentVertexSets");
rb_include_module(cIGraph, cIGraph_indyver);
rb_define_method(cIGraph_indyver, "independent_vertex_sets", cIGraph_independent_vertex_sets, 2); /* in cIGraph_independent_vertex_sets.c */
rb_define_method(cIGraph_indyver, "largest_independent_vertex_sets", cIGraph_largest_independent_vertex_sets, 0); /* in cIGraph_independent_vertex_sets.c */
rb_define_method(cIGraph_indyver, "maximal_independent_vertex_sets", cIGraph_maximal_independent_vertex_sets, 0); /* in cIGraph_independent_vertex_sets.c */
rb_define_method(cIGraph_indyver, "independence_number", cIGraph_independence_number, 0); /* in cIGraph_independent_vertex_sets.c */
/* Functions for isomorphism and isoclasses */
cIGraph_isomor = rb_define_module_under(cIGraph, "Isomorphism");
rb_include_module(cIGraph, cIGraph_isomor);
rb_define_method(cIGraph_isomor, "isomorphic", cIGraph_isomorphic, 1); /* in cIGraph_isomorphism.c */
rb_define_method(cIGraph_isomor, "isomorphic_vf2", cIGraph_isomorphic_vf2, 1); /* in cIGraph_isomorphism.c */
rb_define_method(cIGraph_isomor, "isoclass", cIGraph_isoclass, 0); /* in cIGraph_isomorphism.c */
rb_define_method(cIGraph_isomor, "isoclass_subgraph", cIGraph_isoclass_subgraph, 1); /* in cIGraph_isomorphism.c */
rb_define_singleton_method(cIGraph_generate, "isoclass_create", cIGraph_isoclass_create, 3); /* in cIGraph_isomorphism.c */
/* Motif finding functions */
cIGraph_motifs = rb_define_module_under(cIGraph, "Motifs");
rb_include_module(cIGraph, cIGraph_motifs);
rb_define_method(cIGraph_motifs, "motifs_randesu", cIGraph_motifs_randesu, 2); /* in cIGraph_motif.c */
rb_define_method(cIGraph_motifs, "motifs_randesu_no", cIGraph_motifs_randesu_no, 2); /* in cIGraph_motif.c */
rb_define_method(cIGraph_motifs, "motifs_randesu_estimate", cIGraph_motifs_randesu_estimate, 4); /* in cIGraph_motif.c */
/* Graph sorting functions. */
cIGraph_sorting = rb_define_module_under(cIGraph, "Sorting");
rb_include_module(cIGraph, cIGraph_sorting);
rb_define_method(cIGraph_sorting, "topological_sorting", cIGraph_topological_sorting, 1); /* in cIGraph_topological_sort.c */
/* Functions for reading graphs from files */
cIGraph_fileread = rb_define_module_under(cIGraph, "FileRead");
rb_include_module(cIGraph, cIGraph_fileread);
#ifdef __APPLE__
rb_define_singleton_method(cIGraph_fileread, "read_graph_edgelist", cIGraph_unavailable_method, -1);
rb_define_singleton_method(cIGraph_fileread, "read_graph_graphml", cIGraph_unavailable_method, -1);
rb_define_singleton_method(cIGraph_fileread, "read_graph_ncol", cIGraph_unavailable_method, -1);
rb_define_singleton_method(cIGraph_fileread, "read_graph_lgl", cIGraph_unavailable_method, -1);
rb_define_singleton_method(cIGraph_fileread, "read_graph_dimacs", cIGraph_unavailable_method, -1);
rb_define_singleton_method(cIGraph_fileread, "read_graph_graphdb", cIGraph_unavailable_method, -1);
rb_define_singleton_method(cIGraph_fileread, "read_graph_gml", cIGraph_unavailable_method, -1);
rb_define_singleton_method(cIGraph_fileread, "read_graph_pajek", cIGraph_unavailable_method, -1);
#else
rb_define_singleton_method(cIGraph_fileread, "read_graph_edgelist", cIGraph_read_graph_edgelist, 2); /* in cIGraph_file.c */
rb_define_singleton_method(cIGraph_fileread, "read_graph_graphml", cIGraph_read_graph_graphml, 2); /* in cIGraph_file.c */
rb_define_singleton_method(cIGraph_fileread, "read_graph_ncol", cIGraph_read_graph_ncol, 5); /* in cIGraph_file.c */
rb_define_singleton_method(cIGraph_fileread, "read_graph_lgl", cIGraph_read_graph_lgl, 3); /* in cIGraph_file.c */
rb_define_singleton_method(cIGraph_fileread, "read_graph_dimacs", cIGraph_read_graph_dimacs, 2); /* in cIGraph_file.c */
rb_define_singleton_method(cIGraph_fileread, "read_graph_graphdb", cIGraph_read_graph_graphdb, 2); /* in cIGraph_file.c */
rb_define_singleton_method(cIGraph_fileread, "read_graph_gml", cIGraph_read_graph_gml, 1); /* in cIGraph_file.c */
rb_define_singleton_method(cIGraph_fileread, "read_graph_pajek", cIGraph_read_graph_pajek, 2); /* in cIGraph_file.c */
#endif
/* Functions for writing graphs to files */
cIGraph_filewrite = rb_define_module_under(cIGraph, "FileWrite");
rb_include_module(cIGraph, cIGraph_filewrite);
#ifdef __APPLE__
rb_define_method(cIGraph_filewrite, "write_graph_edgelist", cIGraph_unavailable_method, -1);
rb_define_method(cIGraph_filewrite, "write_graph_graphml", cIGraph_unavailable_method, -1);
rb_define_method(cIGraph_filewrite, "write_graph_gml", cIGraph_unavailable_method, -1);
rb_define_method(cIGraph_filewrite, "write_graph_ncol", cIGraph_unavailable_method, -1);
rb_define_method(cIGraph_filewrite, "write_graph_lgl", cIGraph_unavailable_method, -1);
rb_define_method(cIGraph_filewrite, "write_graph_dimacs", cIGraph_unavailable_method, -1);
rb_define_method(cIGraph_filewrite, "write_graph_pajek", cIGraph_unavailable_method, -1);
#else
rb_define_method(cIGraph_filewrite, "write_graph_edgelist", cIGraph_write_graph_edgelist, 1); /* in cIGraph_file.c */
rb_define_method(cIGraph_filewrite, "write_graph_graphml", cIGraph_write_graph_graphml, 1); /* in cIGraph_file.c */
rb_define_method(cIGraph_filewrite, "write_graph_gml", cIGraph_write_graph_gml, 1); /* in cIGraph_file.c */
rb_define_method(cIGraph_filewrite, "write_graph_ncol", cIGraph_write_graph_ncol, 3); /* in cIGraph_file.c */
rb_define_method(cIGraph_filewrite, "write_graph_lgl", cIGraph_write_graph_lgl, 4); /* in cIGraph_file.c */
rb_define_method(cIGraph_filewrite, "write_graph_dimacs", cIGraph_write_graph_dimacs, 4); /* in cIGraph_file.c */
rb_define_method(cIGraph_filewrite, "write_graph_pajek", cIGraph_write_graph_pajek, 1); /* in cIGraph_file.c */
#endif
/* Graph layout functions */
cIGraph_layout = rb_define_module_under(cIGraph, "Layout");
rb_include_module(cIGraph, cIGraph_layout);
rb_define_method(cIGraph_layout, "layout_random", cIGraph_layout_random, 0); /* in cIGraph_layout.c */
rb_define_method(cIGraph_layout, "layout_circle", cIGraph_layout_circle, 0); /* in cIGraph_layout.c */
rb_define_method(cIGraph_layout, "layout_fruchterman_reingold", cIGraph_layout_fruchterman_reingold, 6); /* in cIGraph_layout.c */
rb_define_method(cIGraph_layout, "layout_kamada_kawai", cIGraph_layout_kamada_kawai, 5); /* in cIGraph_layout.c */
rb_define_method(cIGraph_layout, "layout_reingold_tilford", cIGraph_layout_reingold_tilford, 1); /* in cIGraph_layout.c */
rb_define_method(cIGraph_layout, "layout_reingold_tilford_circular", cIGraph_layout_reingold_tilford_circular, 1); /* in cIGraph_layout.c */
rb_define_method(cIGraph_layout, "layout_grid_fruchterman_reingold", cIGraph_layout_grid_fruchterman_reingold, 7); /* in cIGraph_layout.c */
rb_define_method(cIGraph_layout, "layout_lgl", cIGraph_layout_lgl, 7); /* in cIGraph_layout.c */
rb_define_method(cIGraph_layout, "layout_random_3d", cIGraph_layout_random_3d, 0); /* in cIGraph_layout3d.c */
rb_define_method(cIGraph_layout, "layout_sphere", cIGraph_layout_sphere, 0); /* in cIGraph_layout3d.c */
rb_define_method(cIGraph_layout, "layout_fruchterman_reingold_3d", cIGraph_layout_fruchterman_reingold_3d, 5); /* in cIGraph_layout3d.c */
rb_define_method(cIGraph_layout, "layout_kamada_kawai_3d", cIGraph_layout_kamada_kawai_3d, 5); /* in cIGraph_layout3d.c */
rb_define_singleton_method(cIGraph_layout, "layout_merge_dla", cIGraph_layout_merge_dla, 2); /* in cIGraph_layout.c */
/* Minimum cuts related functions */
cIGraph_mincuts = rb_define_module_under(cIGraph, "MinimumCuts");
rb_include_module(cIGraph, cIGraph_mincuts);
rb_define_method(cIGraph_mincuts, "maxflow_value", cIGraph_maxflow_value, 3); /* in cIGraph_min_cuts.c */
rb_define_method(cIGraph_mincuts, "st_mincut_value", cIGraph_st_mincut_value, 3); /* in cIGraph_min_cuts.c */
rb_define_method(cIGraph_mincuts, "mincut_value", cIGraph_mincut_value, 1); /* in cIGraph_min_cuts.c */
rb_define_method(cIGraph_mincuts, "mincut", cIGraph_mincut, 1); /* in cIGraph_min_cuts.c */
/* Vertex and edge connectivity functions */
cIGraph_connectivity = rb_define_module_under(cIGraph, "Connectivity");
rb_include_module(cIGraph, cIGraph_connectivity);
rb_define_method(cIGraph_connectivity, "st_edge_connectivity", cIGraph_st_edge_connectivity, 2); /* in cIGraph_connectivity.c */
rb_define_method(cIGraph_connectivity, "edge_connectivity", cIGraph_edge_connectivity, 0); /* in cIGraph_connectivity.c */
rb_define_method(cIGraph_connectivity, "st_vertex_connectivity", cIGraph_st_vertex_connectivity, 3); /* in cIGraph_connectivity.c */
rb_define_method(cIGraph_connectivity, "vertex_connectivity", cIGraph_vertex_connectivity, 0); /* in cIGraph_connectivity.c */
rb_define_method(cIGraph_connectivity, "edge_disjoint_paths", cIGraph_edge_disjoint_paths, 2); /* in cIGraph_connectivity.c */
rb_define_method(cIGraph_connectivity, "vertex_disjoint_paths", cIGraph_vertex_disjoint_paths, 2); /* in cIGraph_connectivity.c */
rb_define_method(cIGraph_connectivity, "adhesion", cIGraph_adhesion, 0); /* in cIGraph_connectivity.c */
rb_define_method(cIGraph_connectivity, "cohesion", cIGraph_cohesion, 0); /* in cIGraph_connectivity.c */
/* Community and modularity related functions */
cIGraph_community = rb_define_module_under(cIGraph, "Community");
rb_include_module(cIGraph, cIGraph_community);
rb_define_method(cIGraph_community, "modularity", cIGraph_modularity, 1); /* in cIGraph_community.c */
rb_define_method(cIGraph_community, "community_to_membership", cIGraph_community_to_membership, 3); /* in cIGraph_community.c */
rb_define_method(cIGraph_community, "community_spinglass", cIGraph_community_spinglass, 8); /* in cIGraph_community.c */
rb_define_method(cIGraph_community, "community_spinglass_single", cIGraph_community_spinglass_single, 5); /* in cIGraph_community.c */
rb_define_method(cIGraph_community, "community_leading_eigenvector", cIGraph_community_leading_eigenvector, 1); /* in cIGraph_community.c */
rb_define_method(cIGraph_community, "community_leading_eigenvector_naive", cIGraph_community_leading_eigenvector_naive, 1); /* in cIGraph_community.c */
rb_define_method(cIGraph_community, "community_leading_eigenvector_step", cIGraph_community_leading_eigenvector_step, 2); /* in cIGraph_community.c */ rb_define_method(cIGraph_community, "community_walktrap", cIGraph_community_walktrap, 2); /* in cIGraph_community.c */
rb_define_method(cIGraph_community, "community_edge_betweenness", cIGraph_community_edge_betweenness, 1); /* in cIGraph_community.c */
rb_define_method(cIGraph_community, "community_eb_get_merges", cIGraph_community_eb_get_merges, 1); /* in cIGraph_community.c */
rb_define_method(cIGraph_community, "community_fastgreedy", cIGraph_community_fastgreedy, 0); /* in cIGraph_community.c */
rb_define_const(cIGraph, "VERSION", rb_str_new2("0.9.1"));
rb_define_const(cIGraph, "EDGEORDER_ID", INT2NUM(1));
rb_define_const(cIGraph, "EDGEORDER_FROM", INT2NUM(2));
rb_define_const(cIGraph, "EDGEORDER_TO", INT2NUM(3));
rb_define_method(cIGraph, "each", cIGraph_each_vertex, 0);
rb_include_module(cIGraph, rb_mEnumerable);
rb_define_method(cIGraph, "include?", cIGraph_include, 1);
rb_define_method(cIGraph, "all_vertices", cIGraph_all_v, 0);
rb_define_method(cIGraph, "vertices", cIGraph_all_v, 0); /* in cIGraph_selectors.c */
rb_define_method(cIGraph, "adjacent_vertices", cIGraph_adj_v, 2); /* in cIGraph_selectors.c */
rb_define_method(cIGraph, "nonadjacent_vertices", cIGraph_nonadj_v, 2); /* in cIGraph_selectors.c */
rb_define_method(cIGraph, "all_edges", cIGraph_all_e, 1);
rb_define_method(cIGraph, "edges", cIGraph_all_e, 1);
rb_define_method(cIGraph, "adjacent_edges", cIGraph_adj_e, 2);
rb_define_method(cIGraph, "nonadjacent_edges", cIGraph_nonadj_e, 2);
rb_define_method(cIGraph, "vcount", cIGraph_vcount, 0); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "ecount", cIGraph_ecount, 0); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "edge", cIGraph_edge, 1); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "get_eid", cIGraph_get_eid, 2); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "neighbors", cIGraph_neighbors,2);
rb_define_method(cIGraph, "neighbours", cIGraph_neighbors,2); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "adjacent", cIGraph_adjacent,2); /* in cIGraph_basic_query.c */
rb_define_const(cIGraph, "OUT", INT2NUM(1));
rb_define_const(cIGraph, "IN", INT2NUM(2));
rb_define_const(cIGraph, "ALL", INT2NUM(3));
rb_define_const(cIGraph, "TOTAL", INT2NUM(4));
rb_define_method(cIGraph, "is_directed", cIGraph_is_directed,0);
rb_define_method(cIGraph, "is_directed?", cIGraph_is_directed,0); /* in cIGraph_basic_query.c */
rb_define_method(cIGraph, "degree", cIGraph_degree,3); /* in cIGraph_basic_query.c */
rb_define_const(cIGraph_components, "WEAK", INT2NUM(1));
rb_define_const(cIGraph_components, "STRONG", INT2NUM(2));
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_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, "add_edge", cIGraph_add_edge, 2); /* in cIGraph_add_delete.c */
rb_define_method(cIGraph, "add_vertex", cIGraph_add_vertex, 1); /* in cIGraph_add_delete.c */
rb_define_const(cIGraph_otherop, "GET_ADJACENCY_UPPER", INT2NUM(0));
rb_define_const(cIGraph_otherop, "GET_ADJACENCY_LOWER", INT2NUM(1));
rb_define_const(cIGraph_otherop, "GET_ADJACENCY_BOTH", INT2NUM(2));
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_const(cIGraph, "ERDOS_RENYI_GNP", INT2NUM(0));
rb_define_const(cIGraph, "ERDOS_RENYI_GNM", INT2NUM(1));
rb_define_method(cIGraph, "shortest_paths", cIGraph_shortest_paths,2);
rb_define_method(cIGraph, "get_shortest_paths", cIGraph_get_shortest_paths,3);
rb_define_const(cIGraph_generate, "ADJ_DIRECTED", INT2NUM(0));
rb_define_const(cIGraph_generate, "ADJ_UNDIRECTED", INT2NUM(1));
rb_define_const(cIGraph_generate, "ADJ_MAX", INT2NUM(2));
rb_define_const(cIGraph_generate, "ADJ_MIN", INT2NUM(3));
rb_define_const(cIGraph_generate, "ADJ_PLUS", INT2NUM(4));
rb_define_const(cIGraph_generate, "ADJ_UPPER", INT2NUM(5));
rb_define_const(cIGraph_generate, "ADJ_LOWER", INT2NUM(6));
rb_define_const(cIGraph_generate, "STAR_OUT", INT2NUM(0));
rb_define_const(cIGraph_generate, "STAR_IN", INT2NUM(1));
rb_define_const(cIGraph_generate, "STAR_UNDIRECTED", INT2NUM(2));
rb_define_const(cIGraph_generate, "TREE_OUT", INT2NUM(0));
rb_define_const(cIGraph_generate, "TREE_IN", INT2NUM(1));
rb_define_const(cIGraph_generate, "TREE_UNDIRECTED", INT2NUM(2));
rb_define_const(cIGraph_connectivity, "VCONN_NEI_ERROR", INT2NUM(0));
rb_define_const(cIGraph_connectivity, "VCONN_NEI_INFINITY", INT2NUM(1));
rb_define_const(cIGraph_connectivity, "VCONN_NEI_IGNORE", INT2NUM(2));
rb_define_const(cIGraph_community, "SPINCOMM_UPDATE_SIMPLE", INT2NUM(0));
rb_define_const(cIGraph_community, "SPINCOMM_UPDATE_CONFIG", INT2NUM(1));
/* This class wraps the igraph matrix type. It can be created from and
* converted to an Array of Ruby Arrays.
*/
cIGraphMatrix = rb_define_class("IGraphMatrix", rb_cObject);
rb_define_alloc_func(cIGraphMatrix, cIGraph_matrix_alloc);
rb_define_method(cIGraphMatrix, "initialize", cIGraph_matrix_initialize, -1); /* in cIGraph_matrix.c */
rb_define_method(cIGraphMatrix, "initialize_copy", cIGraph_matrix_init_copy, 1); /* in cIGraph_matrix.c */
//rb_define_singleton_method(cIGraphMatrix, "[]", cIGraph_matrix_initialize, -1);
rb_include_module(cIGraphMatrix, rb_mEnumerable);
rb_define_method (cIGraphMatrix, "each", cIGraph_matrix_each,0); /* in cIGraph_matrix.c */
rb_define_method(cIGraphMatrix, "[]", cIGraph_matrix_get, 2); /* in cIGraph_matrix.c */
rb_define_method(cIGraphMatrix, "[]=", cIGraph_matrix_set, 3); /* in cIGraph_matrix.c */
rb_define_method(cIGraphMatrix, "size", cIGraph_matrix_size, 0); /* in cIGraph_matrix.c */
rb_define_method(cIGraphMatrix, "nrow", cIGraph_matrix_nrow, 0); /* in cIGraph_matrix.c */
rb_define_method(cIGraphMatrix, "ncol", cIGraph_matrix_ncol, 0); /* in cIGraph_matrix.c */
rb_define_method(cIGraphMatrix, "max", cIGraph_matrix_max, 0); /* in cIGraph_matrix.c */
rb_define_method(cIGraphMatrix, "*", cIGraph_matrix_scale, 1); /* in cIGraph_matrix.c */
rb_define_method(cIGraphMatrix, "to_a", cIGraph_matrix_toa, 0); /* in cIGraph_matrix.c */
}

View File

@ -1,6 +1,14 @@
#include "math.h"
#include "ruby.h"
#include "igraph.h"
//#define DEBUG
//Classes
VALUE cIGraph;
VALUE cIGraphError;
extern VALUE cIGraph;
extern VALUE cIGraphError;
extern VALUE cIGraphMatrix;
extern igraph_attribute_table_t cIGraph_attribute_table;
//Error and warning handling functions
void cIGraph_error_handler(const char *reason, const char *file,
@ -17,8 +25,52 @@ VALUE cIGraph_include(VALUE self, VALUE v);
//IGraph allocation, destruction and intialization
void Init_igraph(void);
void cIGraph_free(void *p);
void cIGraph_mark(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);
VALUE cIGraph_init_copy(VALUE copy, VALUE orig);
//Graph generators
VALUE cIGraph_adjacency(VALUE self, VALUE matrix, VALUE mode);
VALUE cIGraph_star (VALUE self, VALUE n, VALUE mode, VALUE center);
VALUE cIGraph_lattice (VALUE self, VALUE dim, VALUE directed, VALUE mutual, VALUE circular);
VALUE cIGraph_ring(VALUE self, VALUE n, VALUE directed, VALUE mutual, VALUE circular);
VALUE cIGraph_tree(VALUE self, VALUE n, VALUE children, VALUE type);
VALUE cIGraph_full(VALUE self, VALUE n, VALUE directed, VALUE loops);
VALUE cIGraph_atlas(VALUE self, VALUE n);
VALUE cIGraph_extended_chordal_ring(VALUE self, VALUE n, VALUE matrix);
VALUE cIGraph_connect_neighborhood(VALUE self, VALUE order, VALUE mode);
//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);
VALUE cIGraph_watts_strogatz_game(VALUE self, VALUE dim, VALUE size, VALUE nei, VALUE p);
VALUE cIGraph_degree_sequence_game(VALUE self, VALUE out_deg, VALUE in_deg);
VALUE cIGraph_growing_random_game(VALUE self, VALUE n, VALUE m, VALUE directed, VALUE citation);
VALUE cIGraph_callaway_traits_game(VALUE self, VALUE nodes, VALUE types, VALUE e_per_step, VALUE type_dist, VALUE pref_matrix, VALUE directed);
VALUE cIGraph_establishment_game(VALUE self, VALUE nodes, VALUE types, VALUE k, VALUE type_dist, VALUE pref_matrix, VALUE directed);
VALUE cIGraph_preference_game(VALUE self, VALUE nodes, VALUE types, VALUE type_dist, VALUE pref_matrix, VALUE directed, VALUE loops);
VALUE cIGraph_asymmetric_preference_game(VALUE self, VALUE nodes, VALUE types, VALUE type_dist_matrix, VALUE pref_matrix, VALUE loops);
VALUE cIGraph_recent_degree_game(VALUE self, VALUE n, VALUE power, VALUE window, VALUE m, VALUE outpref, VALUE zero_appeal, VALUE directed);
VALUE cIGraph_barabasi_aging_game(VALUE self, VALUE nodes, VALUE m, VALUE outpref, VALUE pa_exp, VALUE aging_exp, VALUE aging_bin, VALUE zero_deg_appeal, VALUE zero_age_appeal, VALUE deg_coef, VALUE age_coef, VALUE directed);
VALUE cIGraph_recent_degree_aging_game(VALUE self, VALUE nodes, VALUE m, VALUE outpref, VALUE pa_exp, VALUE aging_exp, VALUE aging_bin, VALUE time_window, VALUE zero_appeal, VALUE directed);
VALUE cIGraph_cited_type_game(VALUE self, VALUE nodes, VALUE types, VALUE pref, VALUE e_per_s, VALUE directed);
VALUE cIGraph_citing_cited_type_game(VALUE self, VALUE nodes, VALUE types, VALUE pref, VALUE e_per_s, VALUE directed);
VALUE cIGraph_rewire_edges(VALUE self, VALUE prop);
VALUE cIGraph_rewire(VALUE self, VALUE n);
//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);
@ -32,7 +84,6 @@ VALUE cIGraph_nonadj_v(VALUE self, VALUE v, VALUE mode);
VALUE cIGraph_all_e (VALUE self, VALUE mode);
VALUE cIGraph_adj_e (VALUE self, VALUE v, VALUE mode);
VALUE cIGraph_nonadj_e(VALUE self, VALUE v, VALUE mode);
//Basic query operations
VALUE cIGraph_vcount (VALUE self);
@ -45,16 +96,305 @@ 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_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_add_edge (VALUE self, VALUE from, VALUE to);
VALUE cIGraph_delete_vertex (VALUE self, VALUE v);
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);
VALUE cIGraph_dijkstra_shortest_paths(VALUE self, VALUE from, VALUE weights, VALUE mode);
int igraph_dijkstra_shortest_paths(const igraph_t *graph,
igraph_matrix_t *res,
const igraph_vs_t from,
const igraph_vector_t *wghts,
igraph_neimode_t mode);
//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);
//Component functions
VALUE cIGraph_subcomponent(VALUE self, VALUE v, VALUE mode);
VALUE cIGraph_subgraph (VALUE self, VALUE vs);
VALUE cIGraph_clusters (VALUE self, VALUE mode);
VALUE cIGraph_decompose (int argc, VALUE *argv, VALUE self);
//Centrality measures
VALUE cIGraph_closeness (VALUE self, VALUE vs, VALUE mode);
VALUE cIGraph_betweenness (VALUE self, VALUE vs, VALUE directed);
VALUE cIGraph_edge_betweenness(VALUE self, VALUE directed);
VALUE cIGraph_pagerank (VALUE self, VALUE vs, VALUE directed, VALUE niter, VALUE eps, VALUE damping);
VALUE cIGraph_constraint (int argc, VALUE *argv, VALUE self);
VALUE cIGraph_maxdegree (VALUE self, VALUE vs, VALUE mode, VALUE loops);
//Spanning trees
VALUE cIGraph_minimum_spanning_tree_prim (VALUE self, VALUE weights);
VALUE cIGraph_minimum_spanning_tree_unweighted(VALUE self);
//Transitivity
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);
//Other operations
VALUE cIGraph_density (VALUE self, VALUE loops);
VALUE cIGraph_simplify (VALUE self, VALUE mult, VALUE loops);
VALUE cIGraph_reciprocity (VALUE self, VALUE loops);
VALUE cIGraph_bibcoupling (VALUE self, VALUE vs);
VALUE cIGraph_cocitation (VALUE self, VALUE vs);
VALUE cIGraph_get_adjacency(VALUE self, VALUE mode);
//Cliques
VALUE cIGraph_cliques(VALUE self, VALUE min, VALUE max);
VALUE cIGraph_largest_cliques(VALUE self);
VALUE cIGraph_maximal_cliques(VALUE self);
VALUE cIGraph_clique_number(VALUE self);
//Independent vertex sets
VALUE cIGraph_independent_vertex_sets(VALUE self, VALUE min, VALUE max);
VALUE cIGraph_largest_independent_vertex_sets(VALUE self);
VALUE cIGraph_maximal_independent_vertex_sets(VALUE self);
VALUE cIGraph_independence_number(VALUE self);
//Graph isomorphism
VALUE cIGraph_isomorphic (VALUE self, VALUE g);
VALUE cIGraph_isomorphic_vf2 (VALUE self, VALUE g);
VALUE cIGraph_isoclass (VALUE self);
VALUE cIGraph_isoclass_subgraph(VALUE self, VALUE vs);
VALUE cIGraph_isoclass_create (VALUE self, VALUE vn, VALUE iso, VALUE dir);
//Motifs
VALUE cIGraph_motifs_randesu (VALUE self, VALUE size, VALUE cuts);
VALUE cIGraph_motifs_randesu_no (VALUE self, VALUE size, VALUE cuts);
VALUE cIGraph_motifs_randesu_estimate(VALUE self, VALUE size, VALUE cuts,
VALUE samplen, VALUE samplev);
//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_ncol (VALUE self, VALUE file, VALUE predefnames, VALUE names, VALUE weights, VALUE directed);
VALUE cIGraph_write_graph_ncol (VALUE self, VALUE file, VALUE names, VALUE weights);
VALUE cIGraph_read_graph_lgl (VALUE self, VALUE file, VALUE names, VALUE weights);
VALUE cIGraph_write_graph_lgl (VALUE self, VALUE file, VALUE names, VALUE weights, VALUE isolates);
VALUE cIGraph_read_graph_dimacs (VALUE self, VALUE file, VALUE directed);
VALUE cIGraph_write_graph_dimacs (VALUE self, VALUE file, VALUE source, VALUE target, VALUE capacity);
VALUE cIGraph_read_graph_graphdb (VALUE self, VALUE file, VALUE directed);
VALUE cIGraph_read_graph_graphml (VALUE self, VALUE file, VALUE index);
VALUE cIGraph_write_graph_graphml (VALUE self, VALUE file);
VALUE cIGraph_read_graph_gml (VALUE self, VALUE file);
VALUE cIGraph_write_graph_gml (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);
VALUE cIGraph_layout_circle (VALUE self);
VALUE cIGraph_layout_fruchterman_reingold(VALUE self,
VALUE niter,
VALUE maxdelta,
VALUE area,
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);
VALUE cIGraph_layout_random_3d(VALUE self);
VALUE cIGraph_layout_sphere (VALUE self);
VALUE cIGraph_layout_fruchterman_reingold_3d(VALUE self,
VALUE niter,
VALUE maxdelta,
VALUE volume,
VALUE coolexp,
VALUE repulserad);
VALUE cIGraph_layout_kamada_kawai_3d (VALUE self,
VALUE niter,
VALUE sigma,
VALUE initemp,
VALUE coolexp,
VALUE kkconst);
VALUE cIGraph_layout_merge_dla(VALUE self, VALUE graphs, VALUE layouts);
//Min cuts
VALUE cIGraph_maxflow_value (VALUE self, VALUE source, VALUE target, VALUE capacity);
VALUE cIGraph_st_mincut_value(VALUE self, VALUE source, VALUE target, VALUE capacity);
VALUE cIGraph_mincut_value (VALUE self, VALUE capacity);
VALUE cIGraph_mincut (VALUE self, VALUE capacity);
//Connectivity
VALUE cIGraph_st_edge_connectivity (VALUE self, VALUE source, VALUE target);
VALUE cIGraph_edge_connectivity (VALUE self);
VALUE cIGraph_st_vertex_connectivity(VALUE self, VALUE source, VALUE target, VALUE neighbours);
VALUE cIGraph_vertex_connectivity (VALUE self);
VALUE cIGraph_edge_disjoint_paths (VALUE self, VALUE source, VALUE target);
VALUE cIGraph_vertex_disjoint_paths (VALUE self, VALUE source, VALUE target);
VALUE cIGraph_adhesion(VALUE self);
VALUE cIGraph_cohesion(VALUE self);
//Community
VALUE cIGraph_modularity (VALUE self, VALUE groups);
VALUE cIGraph_community_to_membership (VALUE self, VALUE merge,
VALUE steps, VALUE nodes);
VALUE cIGraph_community_spinglass (VALUE self, VALUE weights,
VALUE spins,
VALUE parupdate,
VALUE starttemp,
VALUE stoptemp,
VALUE coolfact,
VALUE update_rule,
VALUE gamma);
VALUE cIGraph_community_spinglass_single (VALUE self, VALUE weights,
VALUE vertex,
VALUE spins,
VALUE update_rule,
VALUE gamma);
VALUE cIGraph_community_leading_eigenvector (VALUE self, VALUE steps);
VALUE cIGraph_community_leading_eigenvector_naive(VALUE self, VALUE steps);
VALUE cIGraph_community_leading_eigenvector_step (VALUE self,
VALUE membership,
VALUE steps);
VALUE cIGraph_community_walktrap (VALUE self,
VALUE weights,
VALUE steps);
VALUE cIGraph_community_edge_betweenness (VALUE self,
VALUE directed);
VALUE cIGraph_community_eb_get_merges (VALUE self,
VALUE edges);
VALUE cIGraph_community_fastgreedy (VALUE self);
//Attributes
int cIGraph_attribute_init(igraph_t *graph,
igraph_vector_ptr_t *attr);
void cIGraph_attribute_destroy(igraph_t *graph);
int cIGraph_attribute_copy(igraph_t *to,
const igraph_t *from);
int cIGraph_attribute_add_vertices(igraph_t *graph,
long int nv,
igraph_vector_ptr_t *attr);
void cIGraph_attribute_delete_edges(igraph_t *graph,
const igraph_vector_t *idx);
void cIGraph_attribute_delete_vertices(igraph_t *graph,
const igraph_vector_t *eidx,
const igraph_vector_t *vidx);
int cIGraph_attribute_add_edges(igraph_t *graph,
const igraph_vector_t *edges,
igraph_vector_ptr_t *attr);
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);
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_bool_t cIGraph_attribute_has_attr(const igraph_t *graph,
igraph_attribute_elemtype_t type,
const char* name);
int cIGraph_attribute_get_type(const igraph_t *graph,
igraph_attribute_type_t *type,
igraph_attribute_elemtype_t elemtype,
const char *name);
int cIGraph_get_numeric_graph_attr(const igraph_t *graph,
const char *name,
igraph_vector_t *value);
int cIGraph_get_string_graph_attr(const igraph_t *graph,
const char *name,
igraph_strvector_t *value);
int cIGraph_get_numeric_vertex_attr(const igraph_t *graph,
const char *name,
igraph_vs_t vs,
igraph_vector_t *value);
int cIGraph_get_string_vertex_attr(const igraph_t *graph,
const char *name,
igraph_vs_t vs,
igraph_strvector_t *value);
int cIGraph_get_numeric_edge_attr(const igraph_t *graph,
const char *name,
igraph_es_t es,
igraph_vector_t *value);
int cIGraph_get_string_edge_attr(const igraph_t *graph,
const char *name,
igraph_es_t es,
igraph_strvector_t *value);
//Matrix functions
void cIGraph_matrix_free(void *p);
VALUE cIGraph_matrix_alloc(VALUE klass);
VALUE cIGraph_matrix_init_copy(VALUE copy, VALUE orig);
VALUE cIGraph_matrix_initialize(int argc, VALUE *argv, VALUE self);
void Init_igraphmatrix();
VALUE cIGraph_matrix_each(VALUE self);
VALUE cIGraph_matrix_get (VALUE self, VALUE i, VALUE j);
VALUE cIGraph_matrix_set (VALUE self, VALUE i, VALUE j, VALUE x);
VALUE cIGraph_matrix_size(VALUE self);
VALUE cIGraph_matrix_nrow(VALUE self);
VALUE cIGraph_matrix_ncol(VALUE self);
VALUE cIGraph_matrix_max (VALUE self);
VALUE cIGraph_matrix_scale(VALUE self, VALUE x);
VALUE cIGraph_matrix_toa(VALUE self);
//Not implemented yet
//VALUE cIGraph_add_rows(VALUE self, VALUE n);
//VALUE cIGraph_add_cols(VALUE self, VALUE n);
//VALUE cIGraph_matrix_resize(VALUE self, VALUE nrow, VALUE ncol);

View File

@ -19,39 +19,64 @@
* 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;
VALUE v_ary;
int vid;
int code = 0;
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
igraph_vector_init_int(&edge_v,0);
object_h = rb_iv_get(self,"@object_ids");
IGRAPH_FINALLY(igraph_vector_destroy,&edge_v);
IGRAPH_FINALLY(igraph_vector_ptr_destroy,&edge_attr);
IGRAPH_CHECK(igraph_vector_init_int(&edge_v,0));
IGRAPH_CHECK(igraph_vector_ptr_init(&edge_attr,0));
Data_Get_Struct(self, igraph_t, graph);
v_ary = ((VALUE*)graph->attr)[0];
//Loop through objects in edge Array
vertex = rb_ary_shift(edges);
while(vertex != Qnil){
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));
for (i=0; i<RARRAY_LEN(edges); i++) {
vertex = RARRAY_PTR(edges)[i];
if(rb_ary_includes(v_ary,vertex)){
vid = cIGraph_get_vertex_id(self, vertex);
} else {
rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices first");
}
igraph_vector_push_back(&edge_v,vid);
vertex = rb_ary_shift(edges);
IGRAPH_CHECK(igraph_vector_push_back(&edge_v,vid));
if (i % 2){
if (attrs != Qnil){
rb_ary_push((VALUE)e_attr_rec.value,RARRAY_PTR(attrs)[i/2]);
} else {
rb_ary_push((VALUE)e_attr_rec.value,Qnil);
}
}
}
IGRAPH_CHECK(igraph_vector_ptr_push_back(&edge_attr, &e_attr_rec));
if(igraph_vector_size(&edge_v) > 0){
code = igraph_add_edges(graph,&edge_v,0);
IGRAPH_CHECK(code = igraph_add_edges(graph,&edge_v,&edge_attr));
}
igraph_vector_destroy(&edge_v);
igraph_vector_ptr_destroy(&edge_attr);
IGRAPH_FINALLY_CLEAN(2);
return INT2NUM(code);
@ -76,36 +101,43 @@ VALUE cIGraph_add_vertices(VALUE self, VALUE vs){
igraph_t *graph;
VALUE vertex;
VALUE object_h;
VALUE id_h;
int vertex_n;
VALUE v_ary;
int code = 0;
int length;
int to_add;
int i;
igraph_vector_ptr_t vertex_attr;
object_h = rb_iv_get(self,"@object_ids");
id_h = rb_iv_get(self,"@id_objects");
length = NUM2INT(rb_funcall(vs, rb_intern("length"),0));
vertex_n = NUM2INT(rb_funcall(object_h,rb_intern("length"),0));
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_CHECK(igraph_vector_ptr_init(&vertex_attr,0));
IGRAPH_FINALLY(igraph_vector_ptr_destroy,&vertex_attr);
Data_Get_Struct(self, igraph_t, graph);
v_ary = ((VALUE*)graph->attr)[0];
to_add = RARRAY_LEN(vs);
//Loop through objects in vertex array
vertex = rb_ary_shift(vs);
while(vertex != Qnil){
if(rb_funcall(object_h,rb_intern("has_key?"),1,vertex)){
//If @vertices includes this vertex then raise an error
//Silently ignore
for (i=0; i<RARRAY_LEN(vs); i++) {
vertex = RARRAY_PTR(vs)[i];
if(rb_ary_includes(v_ary,vertex)){
//Silently ignore duplicated additions
//rb_raise(cIGraphError, "Vertex already added to graph");
length--;
to_add--;
} else {
//otherwise add a new entry to Hash
rb_hash_aset(object_h,vertex,INT2NUM(vertex_n));
rb_hash_aset(id_h, INT2NUM(vertex_n),vertex);
vertex_n++;
rb_ary_push((VALUE)v_attr_rec.value,RARRAY_PTR(vs)[i]);
}
vertex = rb_ary_shift(vs);
}
code = igraph_add_vertices(graph,length,0);
IGRAPH_CHECK(igraph_vector_ptr_push_back(&vertex_attr,&v_attr_rec));
IGRAPH_CHECK(code = igraph_add_vertices(graph,to_add,&vertex_attr));
igraph_vector_ptr_destroy(&vertex_attr);
IGRAPH_FINALLY_CLEAN(1);
return INT2NUM(code);
@ -127,40 +159,53 @@ 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;
igraph_vector_ptr_t edge_attr;
int code = 0;
VALUE v_ary;
VALUE from;
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
igraph_vector_init_int(&edge_v,0);
object_h = rb_iv_get(self,"@object_ids");
IGRAPH_FINALLY(igraph_vector_destroy,&edge_v);
IGRAPH_FINALLY(igraph_vector_ptr_destroy,&edge_attr);
IGRAPH_CHECK(igraph_vector_init_int(&edge_v,0));
IGRAPH_CHECK(igraph_vector_ptr_init(&edge_attr,0));
Data_Get_Struct(self, igraph_t, graph);
if(rb_funcall(object_h,rb_intern("has_key?"),1,from)){
//If @vertices includes this vertex then look up the vertex number
vid = NUM2INT(rb_hash_aref(object_h,from));
v_ary = ((VALUE*)graph->attr)[0];
if(rb_ary_includes(v_ary,from) && rb_ary_includes(v_ary,to)){
//If graph includes this vertex then look up the vertex number
IGRAPH_CHECK(igraph_vector_push_back(&edge_v,cIGraph_get_vertex_id(self, from)));
IGRAPH_CHECK(igraph_vector_push_back(&edge_v,cIGraph_get_vertex_id(self, to)));
rb_ary_push((VALUE)e_attr_rec.value,attr);
} else {
rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices first");
rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices");
}
igraph_vector_push_back(&edge_v,vid);
if(rb_funcall(object_h,rb_intern("has_key?"),1,to)){
//If @vertices includes this vertex then look up the vertex number
vid = NUM2INT(rb_hash_aref(object_h,to));
} else {
rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices first");
}
igraph_vector_push_back(&edge_v,vid);
code = igraph_add_edges(graph,&edge_v,0);
IGRAPH_CHECK(igraph_vector_ptr_push_back(&edge_attr,&e_attr_rec));
IGRAPH_CHECK(code = igraph_add_edges(graph,&edge_v,&edge_attr));
igraph_vector_ptr_destroy(&edge_attr);
igraph_vector_destroy(&edge_v);
IGRAPH_FINALLY_CLEAN(2);
return INT2NUM(code);
}
@ -184,36 +229,87 @@ 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;
int code = 0;
int length;
igraph_vector_ptr_t vertex_attr;
object_h = rb_iv_get(self,"@object_ids");
id_h = rb_iv_get(self,"@id_objects");
length = 1;
vertex_n = NUM2INT(rb_funcall(object_h,rb_intern("length"),0));
int code = 0;
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_CHECK(igraph_vector_ptr_init(&vertex_attr,0));
IGRAPH_FINALLY(igraph_vector_ptr_destroy,&vertex_attr);
Data_Get_Struct(self, igraph_t, graph);
v_ary = ((VALUE*)graph->attr)[0];
//Loop through objects in vertex array
if(rb_funcall(object_h,rb_intern("has_key?"),1,v)){
//If @vertices includes this vertex then raise an error
//Silently ignore
if(rb_ary_includes(v_ary,v)){
//rb_raise(cIGraphError, "Vertex already added to graph");
length--;
igraph_vector_ptr_destroy(&vertex_attr);
IGRAPH_FINALLY_CLEAN(1);
return code;
} else {
//otherwise add a new entry to Hash
rb_hash_aset(object_h,v,INT2NUM(vertex_n));
rb_hash_aset(id_h, INT2NUM(vertex_n),v);
vertex_n++;
rb_ary_push((VALUE)v_attr_rec.value,v);
}
if(length != 0)
code = igraph_add_vertices(graph,length,0);
IGRAPH_CHECK(igraph_vector_ptr_push_back(&vertex_attr,&v_attr_rec));
IGRAPH_CHECK(code = igraph_add_vertices(graph,1,&vertex_attr));
igraph_vector_ptr_destroy(&vertex_attr);
IGRAPH_FINALLY_CLEAN(1);
return INT2NUM(code);
}
/* call-seq:
* graph.delete_edge(from,to)
*
* Deletes the edge connecting the two vertices given.
*/
VALUE cIGraph_delete_edge(VALUE self, VALUE from, VALUE to){
igraph_t *graph;
igraph_integer_t eid = 0;
int from_i;
int to_i;
Data_Get_Struct(self, igraph_t, graph);
from_i = cIGraph_get_vertex_id(self,from);
to_i = cIGraph_get_vertex_id(self,to);
igraph_get_eid(graph,&eid,from_i,to_i,1);
igraph_delete_edges(graph,igraph_ess_1(eid));
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;
}

View File

@ -0,0 +1,775 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph[u,v] -> Object
*
* Returns the object associated with the edge connecting vertices u and v.
* Aliased to graph.get_edge_attr(u,v)
*/
VALUE cIGraph_get_edge_attr(VALUE self, VALUE from, VALUE to){
int idx;
igraph_t *graph;
VALUE e_ary;
Data_Get_Struct(self, igraph_t, graph);
e_ary = ((VALUE*)graph->attr)[1];
idx = NUM2INT(cIGraph_get_eid(self, from, to, 1));
return rb_ary_entry(e_ary,idx);
}
/* call-seq:
* graph[u,v] = w
*
* Sets the object associated with the edge connecting vertices u and v.
* Aliased to graph.set_edge_attr(u,v)
*/
VALUE cIGraph_set_edge_attr(VALUE self, VALUE from, VALUE to, VALUE attr){
int idx;
igraph_t *graph;
VALUE e_ary;
Data_Get_Struct(self, igraph_t, graph);
e_ary = ((VALUE*)graph->attr)[1];
idx = NUM2INT(cIGraph_get_eid(self, from, to, 1));
rb_ary_store(e_ary,idx,attr);
return Qtrue;
}
/* call-seq:
* graph.attributes -> Hash
*
* Returns the graph attributes. This is usually only used when reading in
* graphs from GraphML format. Feel free to use instance variables on the
* graph object if you like (they won't get copied though!).
*/
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,
cIGraph_attribute_copy,
cIGraph_attribute_add_vertices,
cIGraph_attribute_delete_vertices,
cIGraph_attribute_add_edges,
cIGraph_attribute_delete_edges,
cIGraph_attribute_permute_edges,
cIGraph_attribute_get_info,
cIGraph_attribute_has_attr,
cIGraph_attribute_get_type,
cIGraph_get_numeric_graph_attr,
cIGraph_get_string_graph_attr,
cIGraph_get_numeric_vertex_attr,
cIGraph_get_string_vertex_attr,
cIGraph_get_numeric_edge_attr,
cIGraph_get_string_edge_attr,
};
int cIGraph_attribute_init(igraph_t *graph, igraph_vector_ptr_t *attr) {
VALUE* attrs;
int i;
VALUE key;
VALUE value;
attrs = (VALUE*)calloc(3, sizeof(VALUE));
if(!attrs)
IGRAPH_ERROR("Error allocating Arrays\n", IGRAPH_ENOMEM);
//[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;i<igraph_vector_ptr_size(attr);i++){
igraph_i_attribute_record_t *attr_rec;
char *s;
attr_rec = VECTOR(*attr)[i];
key = rb_str_new2(attr_rec->name);
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;
return IGRAPH_SUCCESS;
}
/* Destruction */
void cIGraph_attribute_destroy(igraph_t *graph) {
VALUE *attrs = (VALUE*)graph->attr;
free(attrs);
return;
}
/* 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];
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) {
#ifdef DEBUG
printf("Entering cIGraph_attribute_add_vertices\n");
#endif
int i,j;
VALUE vertex_array = ((VALUE*)graph->attr)[0];
VALUE values;
if(attr){
if(igraph_vector_ptr_size(attr) > 0 && ((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->type == IGRAPH_ATTRIBUTE_PY_OBJECT){
values = (VALUE)((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->value;
Check_Type(values, T_ARRAY);
for(i=0;i<RARRAY_LEN(values);i++){
rb_ary_push(vertex_array, RARRAY_PTR(values)[i]);
}
//Otherwise read each attriute into hashes and use those
} else {
for(i=0;i<nv;i++){
VALUE record;
igraph_i_attribute_record_t *attr_rec;
char *s;
record = rb_hash_new();
//For when no attributes are given
if(igraph_vector_ptr_size(attr) == 0){
record = INT2NUM(i+1);
}
for (j=0; j<igraph_vector_ptr_size(attr); j++) {
VALUE key;
VALUE value;
//Add key value pair
attr_rec = VECTOR(*attr)[j];
key = rb_str_new2(attr_rec->name);
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);
}
}
} else {
//Default: Add numbered vertices.
for(i=0;i<nv;i++){
rb_ary_push(vertex_array,INT2NUM(i));
}
}
#ifdef DEBUG
printf("Leaving cIGraph_attribute_add_vertices\n");
#endif
return IGRAPH_SUCCESS;
}
/* Deleting vertices */
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];
VALUE n_v_ary = rb_ary_new();
VALUE n_e_ary = rb_ary_new();
for(i=0;i<igraph_vector_size(vidx);i++){
if(VECTOR(*vidx)[i] != 0)
rb_ary_store(n_v_ary,VECTOR(*vidx)[i]-1,rb_ary_entry(vertex_array,i));
}
for(i=0;i<igraph_vector_size(eidx);i++){
if(VECTOR(*eidx)[i] != 0)
rb_ary_store(n_e_ary,VECTOR(*eidx)[i]-1,rb_ary_entry(edge_array,i));
}
((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;
}
/* Adding edges */
int cIGraph_attribute_add_edges(igraph_t *graph,
const igraph_vector_t *edges,
igraph_vector_ptr_t *attr) {
#ifdef DEBUG
printf("Entering cIGraph_attribute_add_edges\n");
#endif
int i,j;
VALUE edge_array = ((VALUE*)graph->attr)[1];
VALUE values;
if(attr){
//If the only record is of type PY_OBJ then use the values as attributes
if(((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->type == IGRAPH_ATTRIBUTE_PY_OBJECT){
values = (VALUE)((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->value;
Check_Type(values, T_ARRAY);
for(i=0;i<RARRAY_LEN(values);i++){
rb_ary_push(edge_array, RARRAY_PTR(values)[i]);
}
//Otherwise read each attriute into hashes and use those
} else {
for(i=0;i<igraph_vector_size(edges)/2;i++){
VALUE record;
igraph_i_attribute_record_t *attr_rec;
char *s;
record = rb_hash_new();
for (j=0; j<igraph_vector_ptr_size(attr); j++) {
VALUE key;
VALUE value;
//Add key value pair
attr_rec = VECTOR(*attr)[j];
key = rb_str_new2(attr_rec->name);
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();
for(i=0;i<igraph_vector_size(idx);i++){
if(VECTOR(*idx)[i] != 0)
rb_ary_store(n_e_ary,VECTOR(*idx)[i]-1,rb_ary_entry(edge_array,i));
}
((VALUE*)graph->attr)[1] = n_e_ary;
#ifdef DEBUG
printf("Leaving cIGraph_attribute_delete_edges\n");
#endif
return;
}
/* Permuting edges */
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();
for(i=0;i<igraph_vector_size(idx);i++){
rb_ary_push(n_e_ary,rb_ary_entry(edge_array,VECTOR(*idx)[i]));
}
((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) {
#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_PTR(store)[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;j<RARRAY_LEN(rb_names);j++){
igraph_strvector_add(n, RSTRING_PTR(RARRAY_PTR(rb_names)[j]));
igraph_vector_push_back(t, NUM2INT(RARRAY_PTR(rb_types)[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) {
#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 = 2; break;
case IGRAPH_ATTRIBUTE_VERTEX: attrnum = 0; break;
case IGRAPH_ATTRIBUTE_EDGE: attrnum = 1; break;
default: return 0; break;
}
obj = ((VALUE*)graph->attr)[attrnum];
if (attrnum != 2)
obj = RARRAY_PTR(obj)[0];
if(TYPE(obj) == T_HASH && 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) {
#ifdef DEBUG
printf("Entering cIGraph_attribute_get_type\n");
#endif
long int attrnum;
VALUE obj;
VALUE val;
switch (elemtype) {
case IGRAPH_ATTRIBUTE_GRAPH: attrnum = 2; break;
case IGRAPH_ATTRIBUTE_VERTEX: attrnum = 0; break;
case IGRAPH_ATTRIBUTE_EDGE: attrnum = 1; break;
default: return 0; break;
}
obj = ((VALUE*)graph->attr)[attrnum];
if (attrnum != 2)
obj = RARRAY_PTR(obj)[0];
rb_funcall(obj,rb_intern("include?"), 1, rb_str_new2(name));
if(rb_funcall(obj,rb_intern("include?"), 1, 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;
}
} 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) {
#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_PTR(val));
#ifdef DEBUG
printf("Leaving cIGraph_get_string_graph_attr\n");
#endif
return 0;
}
/* Getting numeric vertex attributes */
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_PTR(array)[(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;
}
/* Getting string vertex attributes */
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_PTR(array)[(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_PTR(val));
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;
}
/* Getting numeric edge attributes */
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_PTR(array)[(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;
}
/* Getting string edge attributes */
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, edge;
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)){
edge = RARRAY_PTR(array)[(int)IGRAPH_EIT_GET(it)];
val = rb_hash_aref(edge,rb_str_new2(name));
if(val == Qnil)
val = rb_str_new2("");
//Fix for floats when required by ncol write
val = rb_funcall(val,rb_intern("to_s"),0);
igraph_strvector_set(value,i,RSTRING_PTR(val));
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;
}

View File

@ -85,10 +85,11 @@ VALUE cIGraph_edge(VALUE self, VALUE eid){
*
*/
VALUE cIGraph_get_eid(VALUE self, VALUE from, VALUE to, VALUE directed){
igraph_t *graph;
igraph_integer_t eid = 0;
int from_i;
int to_i;
int from_i = 0;
int to_i = 0;
igraph_bool_t directed_b = 0;
Data_Get_Struct(self, igraph_t, graph);
@ -241,6 +242,7 @@ VALUE cIGraph_degree(VALUE self, VALUE v, VALUE mode, VALUE loops){
Data_Get_Struct(self, igraph_t, graph);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,v,&vidv);
//create vertex selector from the vecotr of ids
igraph_vs_vector(&vids,&vidv);

275
ext/cIGraph_centrality.c Normal file
View File

@ -0,0 +1,275 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.closeness(vs,mode) -> Array
*
* Returns an Array of closeness centrality measures for the vertices given in
* the vs Array. mode defines the type of shortest paths used for the
* calculation
*/
VALUE cIGraph_closeness(VALUE self, VALUE vs, 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 closeness = rb_ary_new();
//vector to hold the results of the degree calculations
igraph_vector_init_int(&res,0);
Data_Get_Struct(self, igraph_t, graph);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,vs,&vidv);
//create vertex selector from the vecotr of ids
igraph_vs_vector(&vids,&vidv);
igraph_closeness(graph,&res,vids,pmode);
for(i=0;i<igraph_vector_size(&res);i++){
rb_ary_push(closeness,rb_float_new(VECTOR(res)[i]));
}
igraph_vector_destroy(&vidv);
igraph_vector_destroy(&res);
igraph_vs_destroy(&vids);
return closeness;
}
/* call-seq:
* graph.betweenness(vs,mode) -> Array
*
* Returns an Array of betweenness centrality measures for the vertices given
* in the vs Array. mode defines whether directed paths or considered for
* directed graphs.
*/
VALUE cIGraph_betweenness(VALUE self, VALUE vs, VALUE directed){
igraph_t *graph;
igraph_vs_t vids;
igraph_vector_t vidv;
igraph_bool_t dir = 0;
igraph_vector_t res;
int i;
VALUE betweenness = rb_ary_new();
if(directed == Qtrue)
dir = 1;
//vector to hold the results of the degree calculations
IGRAPH_FINALLY(igraph_vector_destroy, &res);
IGRAPH_FINALLY(igraph_vector_destroy, &vidv);
IGRAPH_FINALLY(igraph_vs_destroy,&vids);
IGRAPH_CHECK(igraph_vector_init(&res,0));
Data_Get_Struct(self, igraph_t, graph);
//Convert an array of vertices to a vector of vertex ids
IGRAPH_CHECK(igraph_vector_init_int(&vidv,0));
cIGraph_vertex_arr_to_id_vec(self,vs,&vidv);
//create vertex selector from the vecotr of ids
IGRAPH_CHECK(igraph_vs_vector(&vids,&vidv));
IGRAPH_CHECK(igraph_betweenness(graph,&res,vids,dir));
for(i=0;i<igraph_vector_size(&res);i++){
rb_ary_push(betweenness,rb_float_new((float)VECTOR(res)[i]));
}
igraph_vector_destroy(&vidv);
igraph_vector_destroy(&res);
igraph_vs_destroy(&vids);
IGRAPH_FINALLY_CLEAN(3);
return betweenness;
}
/* call-seq:
* graph.edge_betweenness(mode) -> Array
*
* Returns an Array of betweenness centrality measures for the edges
* in the graph. mode defines whether directed paths or considered for
* directed graphs.
*/
VALUE cIGraph_edge_betweenness(VALUE self, VALUE directed){
igraph_t *graph;
igraph_bool_t dir = 0;
igraph_vector_t res;
int i;
VALUE betweenness = rb_ary_new();
if(directed == Qtrue)
dir = 1;
//vector to hold the results of the degree calculations
igraph_vector_init_int(&res,0);
Data_Get_Struct(self, igraph_t, graph);
igraph_edge_betweenness(graph,&res,dir);
for(i=0;i<igraph_vector_size(&res);i++){
rb_ary_push(betweenness,INT2NUM((int)VECTOR(res)[i]));
}
igraph_vector_destroy(&res);
return betweenness;
}
/* call-seq:
* graph.pagerank(vs,mode,niter,eps,damping) -> Array
*
* Returns an Array of PageRank measures for the vertices
* in the graph. mode defines whether directed paths or considered for
* directed graphs.
*/
VALUE cIGraph_pagerank(VALUE self, VALUE vs, VALUE directed, VALUE niter, VALUE eps, VALUE damping){
igraph_t *graph;
igraph_vs_t vids;
igraph_vector_t vidv;
igraph_vector_t res;
int i;
VALUE pagerank = rb_ary_new();
igraph_bool_t dir = 0;
if(directed == Qtrue)
dir = 1;
//vector to hold the results of the degree calculations
igraph_vector_init_int(&res,0);
Data_Get_Struct(self, igraph_t, graph);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,vs,&vidv);
//create vertex selector from the vecotr of ids
igraph_vs_vector(&vids,&vidv);
igraph_pagerank_old(graph,&res,vids,dir,
NUM2INT(niter),NUM2DBL(eps),NUM2DBL(damping),0);
for(i=0;i<igraph_vector_size(&res);i++){
rb_ary_push(pagerank,rb_float_new(VECTOR(res)[i]));
}
igraph_vector_destroy(&vidv);
igraph_vector_destroy(&res);
igraph_vs_destroy(&vids);
return pagerank;
}
/* call-seq:
* graph.constraint(vs,weights) -> Array
*
* Returns an Array of constraint measures for the vertices
* in the graph. Weights is an Array of weight measures for each edge.
*/
VALUE cIGraph_constraint(int argc, VALUE *argv, VALUE self){
igraph_t *graph;
igraph_vs_t vids;
igraph_vector_t vidv;
igraph_vector_t res;
igraph_vector_t wght;
int i;
VALUE constraints = rb_ary_new();
VALUE vs, weights;
rb_scan_args(argc,argv,"11",&vs, &weights);
//vector to hold the results of the degree calculations
IGRAPH_FINALLY(igraph_vector_destroy, &res);
IGRAPH_FINALLY(igraph_vector_destroy, &wght);
IGRAPH_FINALLY(igraph_vector_destroy, &vidv);
IGRAPH_CHECK(igraph_vector_init(&res,0));
IGRAPH_CHECK(igraph_vector_init(&wght,0));
Data_Get_Struct(self, igraph_t, graph);
//Convert an array of vertices to a vector of vertex ids
IGRAPH_CHECK(igraph_vector_init_int(&vidv,0));
cIGraph_vertex_arr_to_id_vec(self,vs,&vidv);
//create vertex selector from the vecotr of ids
igraph_vs_vector(&vids,&vidv);
if(weights == Qnil){
IGRAPH_CHECK(igraph_constraint(graph,&res,vids,NULL));
} else {
for(i=0;i<RARRAY_LEN(weights);i++){
IGRAPH_CHECK(igraph_vector_push_back(&wght,NUM2DBL(RARRAY_PTR(weights)[i])));
}
IGRAPH_CHECK(igraph_constraint(graph,&res,vids,&wght));
}
for(i=0;i<igraph_vector_size(&res);i++){
rb_ary_push(constraints,rb_float_new(VECTOR(res)[i]));
}
igraph_vector_destroy(&vidv);
igraph_vector_destroy(&res);
igraph_vector_destroy(&wght);
igraph_vs_destroy(&vids);
IGRAPH_FINALLY_CLEAN(3);
return constraints;
}
/* call-seq:
* graph.maxdegree(vs,mode,loops) -> Vertex
*
* Returns the vertex Object in the vs Array with the largest degree.
* mode defines the type
* of the degree. IGRAPH_OUT, out-degree, IGRAPH_IN, in-degree, IGRAPH_ALL,
* total degree (sum of the in- and out-degree). This parameter is ignored
* for undirected graphs. loops is a boolean gives whether the self-loops
* should be counted.
*/
VALUE cIGraph_maxdegree(VALUE self, VALUE vs, VALUE mode, VALUE loops){
igraph_t *graph;
igraph_bool_t loop = 0;
igraph_integer_t res;
igraph_neimode_t pmode = NUM2INT(mode);
igraph_vs_t vids;
igraph_vector_t vidv;
if(loops == Qtrue)
loop = 1;
Data_Get_Struct(self, igraph_t, graph);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,vs,&vidv);
//create vertex selector from the vecotr of ids
igraph_vs_vector(&vids,&vidv);
igraph_maxdegree(graph,&res,vids,pmode,loop);
igraph_vector_destroy(&vidv);
igraph_vs_destroy(&vids);
return INT2NUM(res);
}

178
ext/cIGraph_cliques.c Normal file
View File

@ -0,0 +1,178 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.cliques(min_size,max_size) -> Array
*
* Find all or some cliques in a graph
*
* Cliques are fully connected subgraphs of a graph.
*
* If you are only interested in the size of the largest clique in the
* graph, use IGraph#clique_number instead.
*/
VALUE cIGraph_cliques(VALUE self, VALUE min, VALUE max){
igraph_t *graph;
igraph_vector_ptr_t res;
igraph_vector_t *vec;
int i;
int j;
VALUE clique;
VALUE object;
VALUE cliques = rb_ary_new();
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_ptr_init(&res,0);
igraph_cliques(graph, &res, NUM2INT(min), NUM2INT(max));
for(i=0; i<igraph_vector_ptr_size(&res); i++){
clique = rb_ary_new();
rb_ary_push(cliques,clique);
vec = VECTOR(res)[i];
for(j=0; j<igraph_vector_size(vec); j++){
vec = VECTOR(res)[i];
object = cIGraph_get_vertex_object(self,VECTOR(*vec)[j]);
rb_ary_push(clique,object);
}
}
for(i=0;i<igraph_vector_ptr_size(&res);i++){
igraph_vector_destroy(VECTOR(res)[i]);
free(VECTOR(res)[i]);
}
igraph_vector_ptr_destroy(&res);
return cliques;
}
/* call-seq:
* graph.largest_cliques() -> Array
*
* Finds the largest clique(s) in a graph.
*
* A clique is largest (quite intuitively) if there is no other clique in
* the graph which contains more vertices.
*
* Note that this is not neccessarily the same as a maximal clique, ie.
* the largest cliques are always maximal but a maximal clique is not always
* largest.
*/
VALUE cIGraph_largest_cliques(VALUE self){
igraph_t *graph;
igraph_vector_ptr_t res;
igraph_vector_t *vec;
int i;
int j;
VALUE clique;
VALUE object;
VALUE cliques = rb_ary_new();
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_ptr_init(&res,0);
igraph_largest_cliques(graph, &res);
for(i=0; i<igraph_vector_ptr_size(&res); i++){
clique = rb_ary_new();
rb_ary_push(cliques,clique);
vec = VECTOR(res)[i];
for(j=0; j<igraph_vector_size(vec); j++){
vec = VECTOR(res)[i];
object = cIGraph_get_vertex_object(self,VECTOR(*vec)[j]);
rb_ary_push(clique,object);
}
}
for(i=0;i<igraph_vector_ptr_size(&res);i++){
igraph_vector_destroy(VECTOR(res)[i]);
free(VECTOR(res)[i]);
}
igraph_vector_ptr_destroy(&res);
return cliques;
}
/* call-seq:
* graph.maximal_cliques() -> Array
*
* Find all maximal cliques of a graph
*
* A maximal clique is a clique which can't be extended any more by adding a
* new vertex to it. This is actually implemented by looking for a maximal
* independent vertex set in the complementer of the graph.
*
* If you are only interested in the size of the largest clique in the
* graph, use IGraph#clique_number instead.
*/
VALUE cIGraph_maximal_cliques(VALUE self){
igraph_t *graph;
igraph_vector_ptr_t res;
igraph_vector_t *vec;
int i;
int j;
VALUE clique;
VALUE object;
VALUE cliques = rb_ary_new();
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_ptr_init(&res,0);
igraph_maximal_cliques(graph, &res);
for(i=0; i<igraph_vector_ptr_size(&res); i++){
clique = rb_ary_new();
rb_ary_push(cliques,clique);
vec = VECTOR(res)[i];
for(j=0; j<igraph_vector_size(vec); j++){
vec = VECTOR(res)[i];
object = cIGraph_get_vertex_object(self,VECTOR(*vec)[j]);
rb_ary_push(clique,object);
}
}
for(i=0;i<igraph_vector_ptr_size(&res);i++){
igraph_vector_destroy(VECTOR(res)[i]);
free(VECTOR(res)[i]);
}
igraph_vector_ptr_destroy(&res);
return cliques;
}
/* call-seq:
* graph.clique_number() -> Integer
*
* Find the clique number of the graph
*
* The clique number of a graph is the size of the largest clique.
*/
VALUE cIGraph_clique_number(VALUE self){
igraph_t *graph;
igraph_integer_t res;
Data_Get_Struct(self, igraph_t, graph);
igraph_clique_number(graph, &res);
return INT2NUM(res);
}

661
ext/cIGraph_community.c Normal file
View File

@ -0,0 +1,661 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.modularity(groups) -> Float
*
* Calculate the modularity of a graph with respect to some vertex types.
* The modularity of a graph with respect to some division (or vertex types)
* measures how good the division is, or how separated are the different
* vertex types from each other.
*
*/
VALUE cIGraph_modularity(VALUE self, VALUE groups){
igraph_t *graph;
igraph_real_t value;
igraph_vector_t membership;
VALUE group;
int i,j;
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_init(&membership,igraph_vcount(graph));
for(i=0;i<RARRAY_LEN(groups);i++){
group = RARRAY_PTR(groups)[i];
for(j=0;j<RARRAY_LEN(group);j++){
igraph_vector_set(&membership,
cIGraph_get_vertex_id(self,RARRAY_PTR(group)[j]),i);
}
}
igraph_modularity(graph,&membership,&value,NULL);
igraph_vector_destroy(&membership);
return rb_float_new(value);
}
/* call-seq:
* graph.community_to_membership(merge,steps) -> Array
*
* Create membership vector from community structure dendrogram This function
* creates a membership vector from a community structure dendrogram.
* A membership vector contains for each vertex the id of its graph
* component, the graph components are numbered from zero, see the same
* argument of igraph_clusters() for an example of a membership vector.
*
*/
VALUE cIGraph_community_to_membership(VALUE self, VALUE merge, VALUE steps, VALUE nodes){
igraph_t *graph;
igraph_matrix_t *merges;
igraph_vector_t membership;
VALUE groups;
int i,groupid,max_groupid;
Data_Get_Struct(self, igraph_t, graph);
Data_Get_Struct(merge, igraph_matrix_t, merges);
igraph_vector_init(&membership,0);
igraph_community_to_membership(merges,NUM2INT(nodes),NUM2INT(steps),&membership,NULL);
max_groupid = 0;
for(i=0;i<igraph_vector_size(&membership);i++){
if(VECTOR(membership)[i] > max_groupid)
max_groupid = VECTOR(membership)[i];
}
groups = rb_ary_new();
for(i=0;i<max_groupid+1;i++){
rb_ary_push(groups,rb_ary_new());
}
for(i=0;i<igraph_vector_size(&membership);i++){
groupid = VECTOR(membership)[i];
if(RARRAY_PTR(groups)[groupid] == Qnil){
RARRAY_PTR(groups)[groupid] = rb_ary_new();
}
rb_ary_push(RARRAY_PTR(groups)[groupid],
cIGraph_get_vertex_object(self, i));
}
igraph_vector_destroy(&membership);
return groups;
}
/* call-seq:
* graph.community_spinglass(weights,spins,parupdate,starttemp,stoptemp,coolfact,update_rule,gamma) -> Array
*
* Community detection based on statistical mechanics This function
* implements the community structure detection algorithm proposed by Joerg
* Reichardt and Stefan Bornholdt. The algorithm is described in their
* paper: Statistical Mechanics of Community Detection.
*
*/
VALUE cIGraph_community_spinglass(VALUE self, VALUE weights, VALUE spins, VALUE parupdate, VALUE starttemp, VALUE stoptemp, VALUE coolfact, VALUE update_rule, VALUE gamma){
igraph_t *graph;
igraph_vector_t weights_vec;
igraph_vector_t membership;
igraph_real_t temperature;
igraph_real_t modularity;
igraph_bool_t parupdate_b;
VALUE group;
VALUE groups;
VALUE res;
int i,groupid,max_groupid;
if(parupdate)
parupdate_b = 1;
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_init(&membership,0);
igraph_vector_init(&weights_vec,RARRAY_LEN(weights));
for(i=0;i<RARRAY_LEN(weights);i++){
VECTOR(weights_vec)[i] = NUM2DBL(RARRAY_PTR(weights)[i]);
}
igraph_community_spinglass(graph,
igraph_vector_size(&weights_vec) > 0 ? &weights_vec : NULL,
&modularity,&temperature,
&membership,NULL,NUM2INT(spins),parupdate_b,
NUM2DBL(starttemp),NUM2DBL(stoptemp),
NUM2DBL(coolfact),NUM2INT(update_rule),
NUM2DBL(gamma));
max_groupid = 0;
for(i=0;i<igraph_vector_size(&membership);i++){
if(VECTOR(membership)[i] > max_groupid)
max_groupid = VECTOR(membership)[i];
}
groups = rb_ary_new();
for(i=0;i<max_groupid+1;i++){
rb_ary_push(groups,rb_ary_new());
}
for(i=0;i<igraph_vector_size(&membership);i++){
groupid = VECTOR(membership)[i];
if(groupid == -1)
groupid = 0;
group = RARRAY_PTR(groups)[groupid];
rb_ary_push(group,cIGraph_get_vertex_object(self, i));
}
res = rb_ary_new3(3,groups,
rb_float_new(modularity),
rb_float_new(temperature));
igraph_vector_destroy(&membership);
igraph_vector_destroy(&weights_vec);
return res;
}
/* call-seq:
* graph.community_spinglass_single(weights,vertex,spins,update_rule,gamma) -> Array
*
* Community detection based on statistical mechanics This function
* implements the community structure detection algorithm proposed by Joerg
* Reichardt and Stefan Bornholdt. The algorithm is described in their
* paper: Statistical Mechanics of Community Detection.
*
*/
VALUE cIGraph_community_spinglass_single(VALUE self, VALUE weights, VALUE vertex, VALUE spins, VALUE update_rule, VALUE gamma){
igraph_t *graph;
igraph_vector_t weights_vec;
igraph_vector_t community;
igraph_real_t cohesion;
igraph_real_t adhesion;
VALUE group;
VALUE res;
int i;
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_init(&community,0);
igraph_vector_init(&weights_vec,RARRAY_LEN(weights));
for(i=0;i<RARRAY_LEN(weights);i++){
VECTOR(weights_vec)[i] = NUM2DBL(RARRAY_PTR(weights)[i]);
}
igraph_community_spinglass_single(graph,
igraph_vector_size(&weights_vec) > 0 ? &weights_vec : NULL,
cIGraph_get_vertex_id(self, vertex),
&community, &cohesion, &adhesion,
NULL, NULL,
NUM2INT(spins),NUM2INT(update_rule),
NUM2DBL(gamma));
group = rb_ary_new();
for(i=0;i<igraph_vector_size(&community);i++){
rb_ary_push(group,cIGraph_get_vertex_object(self, i));
}
res = rb_ary_new3(3,group,
rb_float_new(cohesion),
rb_float_new(adhesion));
igraph_vector_destroy(&community);
igraph_vector_destroy(&weights_vec);
return res;
}
/* call-seq:
* graph.community_leading_eigenvector(steps) -> Array
*
* Newman's leading eigenvector method for detecting community structure.
* This is the proper implementation of the recursive, divisive algorithm:
* each split is done by maximizing the modularity regarding the original
* network, see MEJ Newman: Finding community structure in networks using
* the eigenvectors of matrices, arXiv:physics/0605087.
*
*/
VALUE cIGraph_community_leading_eigenvector(VALUE self, VALUE steps){
igraph_t *graph;
igraph_vector_t membership;
igraph_matrix_t *merges = malloc(sizeof(igraph_matrix_t));
igraph_arpack_options_t arpack_opt;
igraph_arpack_options_init(&arpack_opt);
int i,groupid,max_groupid;
VALUE groups, group, res;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(merges,0,0);
igraph_vector_init(&membership,0);
igraph_community_leading_eigenvector(graph,merges,&membership,
NUM2INT(steps),&arpack_opt);
max_groupid = 0;
for(i=0;i<igraph_vector_size(&membership);i++){
if(VECTOR(membership)[i] > max_groupid)
max_groupid = VECTOR(membership)[i];
}
groups = rb_ary_new();
for(i=0;i<max_groupid+1;i++){
rb_ary_push(groups,rb_ary_new());
}
for(i=0;i<igraph_vector_size(&membership);i++){
groupid = VECTOR(membership)[i];
if(groupid == -1)
groupid = 0;
group = RARRAY_PTR(groups)[groupid];
rb_ary_push(group,cIGraph_get_vertex_object(self, i));
}
res = rb_ary_new3(2,groups,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, merges));
igraph_vector_destroy(&membership);
return res;
}
/* call-seq:
* graph.community_leading_eigenvector_naive(steps) -> Array
*
* Newman's leading eigenvector method for detecting community structure.
* This is the proper implementation of the recursive, divisive algorithm:
* each split is done by maximizing the modularity regarding the original
* network, see MEJ Newman: Finding community structure in networks using
* the eigenvectors of matrices, arXiv:physics/0605087.
*
*/
VALUE cIGraph_community_leading_eigenvector_naive(VALUE self, VALUE steps){
igraph_t *graph;
igraph_vector_t membership;
igraph_matrix_t *merges = malloc(sizeof(igraph_matrix_t));
igraph_arpack_options_t arpack_opt;
igraph_arpack_options_init(&arpack_opt);
int i,groupid,max_groupid;
VALUE groups, group, res;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(merges,0,0);
igraph_vector_init(&membership,0);
igraph_community_leading_eigenvector_naive(graph,merges,&membership,
NUM2INT(steps), &arpack_opt);
max_groupid = 0;
for(i=0;i<igraph_vector_size(&membership);i++){
if(VECTOR(membership)[i] > max_groupid)
max_groupid = VECTOR(membership)[i];
}
groups = rb_ary_new();
for(i=0;i<max_groupid+1;i++){
rb_ary_push(groups,rb_ary_new());
}
for(i=0;i<igraph_vector_size(&membership);i++){
groupid = VECTOR(membership)[i];
if(groupid == -1)
groupid = 0;
group = RARRAY_PTR(groups)[groupid];
rb_ary_push(group,cIGraph_get_vertex_object(self, i));
}
res = rb_ary_new3(2,groups,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, merges));
igraph_vector_destroy(&membership);
return res;
}
/* call-seq:
* graph.community_leading_eigenvector_step(membership,community) -> Array
*
* Do one split according to Mark Newman's leading eigenvector community
* detection method. See MEJ Newman: Finding community structure in networks
* using the eigenvectors of matrices, arXiv:phyisics/0605087 for the details.
*
*/
VALUE cIGraph_community_leading_eigenvector_step(VALUE self, VALUE membership, VALUE community){
igraph_t *graph;
igraph_vector_t membership_vec;
igraph_vector_t eigenvector;
igraph_real_t eigenvalue;
igraph_bool_t split;
int i,j,groupid,max_groupid,vid;
igraph_arpack_options_t arpack_opt;
igraph_arpack_options_init(&arpack_opt);
VALUE groups, group, res, eigenvector_a, obj;
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_init(&membership_vec,igraph_vcount(graph));
igraph_vector_init(&eigenvector,0);
for(i=0;i<RARRAY_LEN(membership);i++){
group = RARRAY_PTR(membership)[i];
for(j=0;j<RARRAY_LEN(group);j++){
obj = RARRAY_PTR(group)[j];
vid = cIGraph_get_vertex_id(self,obj);
VECTOR(membership_vec)[vid] = i;
}
}
igraph_community_leading_eigenvector_step(graph,&membership_vec,
NUM2INT(community),
&split,&eigenvector,&eigenvalue,&arpack_opt,NULL);
max_groupid = 0;
for(i=0;i<igraph_vector_size(&membership_vec);i++){
if(VECTOR(membership_vec)[i] > max_groupid)
max_groupid = VECTOR(membership_vec)[i];
}
groups = rb_ary_new();
for(i=0;i<max_groupid+1;i++){
rb_ary_push(groups,rb_ary_new());
}
for(i=0;i<igraph_vector_size(&membership_vec);i++){
groupid = VECTOR(membership_vec)[i];
if(groupid == -1)
groupid = 0;
group = RARRAY_PTR(groups)[groupid];
rb_ary_push(group,cIGraph_get_vertex_object(self, i));
}
eigenvector_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&eigenvector);i++){
rb_ary_push(eigenvector_a,rb_float_new(VECTOR(eigenvector)[i]));
}
res = rb_ary_new3(4,groups,split==0 ? Qfalse : Qtrue,
eigenvector_a,rb_float_new(eigenvalue));
igraph_vector_destroy(&membership_vec);
igraph_vector_destroy(&eigenvector);
return res;
}
/* call-seq:
* graph.community_walktrap(weights,steps) -> Array
*
* This function is the implementation of the Walktrap community finding
* algorithm, see Pascal Pons, Matthieu Latapy: Computing communities in
* large networks using random walks, http://arxiv.org/abs/physics/0512106
*
*/
VALUE cIGraph_community_walktrap(VALUE self, VALUE weights, VALUE steps){
igraph_t *graph;
igraph_vector_t weights_vec;
igraph_vector_t modularity;
igraph_matrix_t *merges = malloc(sizeof(igraph_matrix_t));
int i;
VALUE modularity_a, res;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(merges,0,0);
igraph_vector_init(&weights_vec,0);
igraph_vector_init(&modularity,0);
for(i=0;i<RARRAY_LEN(weights);i++){
VECTOR(weights_vec)[i] = NUM2DBL(RARRAY_PTR(weights)[i]);
}
igraph_community_walktrap(graph,
igraph_vector_size(&weights_vec) > 0 ? &weights_vec : NULL,
NUM2INT(steps),merges,&modularity);
modularity_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&modularity);i++){
rb_ary_push(modularity_a,rb_float_new(VECTOR(modularity)[i]));
}
res = rb_ary_new3(2,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, merges),
modularity_a);
igraph_vector_destroy(&weights_vec);
igraph_vector_destroy(&modularity);
return res;
}
/* call-seq:
* graph.community_edge_betweenness(directed) -> Array
*
* Community structure detection based on the betweenness of the edges in the
* network. The algorithm was invented by M. Girvan and M. Newman, see:
* M. Girvan and M. E. J. Newman: Community structure in social and
* biological networks, Proc. Nat. Acad. Sci. USA 99, 7821-7826 (2002).
*
*/
VALUE cIGraph_community_edge_betweenness(VALUE self, VALUE directed){
igraph_t *graph;
igraph_vector_t result_vec;
igraph_vector_t edge_betw_vec;
igraph_vector_t bridges_vec;
igraph_matrix_t *merges = malloc(sizeof(igraph_matrix_t));
igraph_bool_t directed_b = 0;
int i;
VALUE result_a, edge_betw_a, bridges_a, res;
if(directed)
directed_b = 1;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(merges,0,0);
igraph_vector_init(&result_vec,0);
igraph_vector_init(&edge_betw_vec,0);
igraph_vector_init(&bridges_vec,0);
igraph_community_edge_betweenness(graph,
&result_vec,&edge_betw_vec,
merges,&bridges_vec,directed_b);
result_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&result_vec);i++){
rb_ary_push(result_a,INT2NUM(VECTOR(result_vec)[i]));
}
edge_betw_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&edge_betw_vec);i++){
rb_ary_push(edge_betw_a,INT2NUM(VECTOR(edge_betw_vec)[i]));
}
bridges_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&bridges_vec);i++){
rb_ary_push(bridges_a,INT2NUM(VECTOR(bridges_vec)[i]));
}
res = rb_ary_new3(4,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, merges),
result_a, edge_betw_a, bridges_a);
igraph_vector_destroy(&result_vec);
igraph_vector_destroy(&edge_betw_vec);
igraph_vector_destroy(&bridges_vec);
return res;
}
/* call-seq:
* graph.community_eb_get_merges(edges) -> Array
*
* Calculating the merges, ie. the dendrogram for an edge betweenness
* community structure
*
*/
VALUE cIGraph_community_eb_get_merges(VALUE self, VALUE edges){
igraph_t *graph;
igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t));
igraph_vector_t edges_vec;
igraph_vector_t bridges_vec;
VALUE result,bridges_a;
int i;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(res,0,0);
igraph_vector_init(&edges_vec,0);
igraph_vector_init(&bridges_vec,0);
for(i=0;i<RARRAY_LEN(edges);i++){
igraph_vector_push_back(&edges_vec,NUM2INT(RARRAY_PTR(edges)[i]));
}
igraph_community_eb_get_merges(graph,&edges_vec,res,&bridges_vec);
bridges_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&bridges_vec);i++){
rb_ary_push(bridges_a,INT2NUM(VECTOR(bridges_vec)[i]));
}
igraph_vector_destroy(&bridges_vec);
igraph_vector_destroy(&edges_vec);
result = rb_ary_new3(2,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, res),
bridges_a);
return result;
}
/* call-seq:
* graph.community_fastgreedy() -> Array
*
* Finding community structure by greedy optimization of modularity.
* This function implements the fast greedy modularity optimization algorithm
* for finding community structure, see A Clauset, MEJ Newman, C Moore:
* Finding community structure in very large networks,
* http://www.arxiv.org/abs/cond-mat/0408187 for the details.
*
*/
VALUE cIGraph_community_fastgreedy(VALUE self){
igraph_t *graph;
igraph_vector_t modularity;
igraph_matrix_t *merges = malloc(sizeof(igraph_matrix_t));
int i;
VALUE modularity_a, res;
Data_Get_Struct(self, igraph_t, graph);
igraph_matrix_init(merges,0,0);
igraph_vector_init(&modularity,0);
igraph_community_fastgreedy(graph,NULL,
merges,&modularity);
modularity_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&modularity);i++){
rb_ary_push(modularity_a,rb_float_new(VECTOR(modularity)[i]));
}
res = rb_ary_new3(2,
Data_Wrap_Struct(cIGraphMatrix, 0,
cIGraph_matrix_free, merges),
modularity_a);
igraph_vector_destroy(&modularity);
return res;
}

155
ext/cIGraph_components.c Normal file
View File

@ -0,0 +1,155 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.subcomponent(v,mode) -> Array
*
* Returns an Array of vertices that are in the same component as the vertex v.
* mode defines the type of the component for directed graphs, possible
* values: IGraph::OUT: the set of vertices reachable from the vertex,
* IGraph::IN the set of vertices from which the vertex is reachable,
* IGraph::ALL the graph is considered as an undirected graph. Note that
* this is not the same as the union of the previous two.
*/
VALUE cIGraph_subcomponent(VALUE self, VALUE v, VALUE mode){
igraph_t *graph;
igraph_neimode_t pmode = NUM2INT(mode);
igraph_vector_t neis;
int i;
VALUE component = rb_ary_new();
igraph_vector_init_int(&neis,0);
Data_Get_Struct(self, igraph_t, graph);
igraph_subcomponent(graph, &neis, cIGraph_get_vertex_id(self,v), pmode);
for(i=0;i<igraph_vector_size(&neis);i++){
rb_ary_push(component,cIGraph_get_vertex_object(self,VECTOR(neis)[i]));
}
igraph_vector_destroy(&neis);
return component;
}
/* call-seq:
* graph.subgraph(vs) -> IGraph
*
* Returns an IGraph object containing the vertices defined in the Array vs.
*/
VALUE cIGraph_subgraph(VALUE self, VALUE vs){
igraph_t *graph;
igraph_t *n_graph = malloc(sizeof(igraph_t));
igraph_vs_t vids;
igraph_vector_t vidv;
VALUE n_graph_obj;
Data_Get_Struct(self, igraph_t, graph);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,vs,&vidv);
//create vertex selector from the vecotr of ids
igraph_vs_vector(&vids,&vidv);
igraph_subgraph(graph,n_graph,vids);
n_graph_obj = Data_Wrap_Struct(cIGraph, cIGraph_mark, cIGraph_free, n_graph);
igraph_vector_destroy(&vidv);
igraph_vs_destroy(&vids);
return n_graph_obj;
}
/* call-seq:
* graph.clusters(mode) -> Array
*
* Calculates the (weakly or strongly) connected components in a graph.
* Returns an Array of Arrays of vertices. Each sub-Array is a graph component
*/
VALUE cIGraph_clusters(VALUE self, VALUE mode){
igraph_t *graph;
igraph_vector_t membership;
igraph_integer_t no;
VALUE components;
VALUE v,c;
int i;
igraph_vector_init_int(&membership,0);
Data_Get_Struct(self, igraph_t, graph);
igraph_clusters(graph, &membership, NULL, &no, NUM2INT(mode));
components = rb_ary_new();
for(i=0;i<no;i++){
rb_ary_push(components,rb_ary_new());
}
for(i=0;i<igraph_vector_size(&membership);i++){
v = cIGraph_get_vertex_object(self, i);
c = rb_ary_entry(components,VECTOR(membership)[i]);
rb_ary_push(c,v);
}
igraph_vector_destroy(&membership);
return components;
}
/* call-seq:
* graph.decompose(mode,maxcomp=-1,minelem=1) -> Array
*
* Create separate graph for each component of a graph. Returns an Array
* of new IGraph object. mode specifies whether weakly and strongly connected
* components are returned. Right now only the former is implemented. maxcomp
* limits the number of components returned. Leave at the default -1 to return
* all components. minelements specifies the minimum number of vertices a
* component should contain before it is returned. Default 1 returns all
* components.
*/
VALUE cIGraph_decompose(int argc, VALUE *argv, VALUE self){
igraph_t *graph;
igraph_t *n_graph;
igraph_vector_ptr_t components;
VALUE mode,maxcomp, minelem, components_a;
VALUE n_graph_obj;
int i;
rb_scan_args(argc,argv,"12", &mode, &maxcomp, &minelem);
if(maxcomp == Qnil)
maxcomp = INT2NUM(-1);
if(minelem == Qnil)
minelem = INT2NUM(1);
igraph_vector_ptr_init(&components,0);
Data_Get_Struct(self, igraph_t, graph);
igraph_decompose(graph, &components, NUM2INT(mode), NUM2INT(maxcomp), NUM2INT(minelem));
components_a = rb_ary_new();
for(i=0; i<igraph_vector_ptr_size(&components); i++){
n_graph = VECTOR(components)[i];
n_graph_obj = Data_Wrap_Struct(cIGraph, cIGraph_mark, cIGraph_free, n_graph);
rb_ary_push(components_a,n_graph_obj);
}
igraph_vector_ptr_destroy(&components);
return components_a;
}

222
ext/cIGraph_connectivity.c Normal file
View File

@ -0,0 +1,222 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.st_edge_connectivity(source,target) -> Integer
*
* Edge connectivity of a pair of vertices
*
* The edge connectivity of two vertices (source and target) in a graph is
* the minimum number of edges that have to be deleted from the graph to
* eliminate all paths from source to target.
*
* This function uses the maximum flow algorithm to calculate the edge
* connectivity.
*
*/
VALUE cIGraph_st_edge_connectivity(VALUE self, VALUE source, VALUE target){
igraph_t *graph;
igraph_integer_t from_i;
igraph_integer_t to_i;
igraph_integer_t value;
Data_Get_Struct(self, igraph_t, graph);
from_i = cIGraph_get_vertex_id(self,source);
to_i = cIGraph_get_vertex_id(self,target);
igraph_st_edge_connectivity(graph,&value,from_i,to_i);
return INT2NUM(value);
}
/* call-seq:
* graph.edge_connectivity() -> Integer
*
* This is the minimum of the edge connectivity over all pairs of vertices
* in the graph.
*
*/
VALUE cIGraph_edge_connectivity(VALUE self){
igraph_t *graph;
igraph_integer_t value;
Data_Get_Struct(self, igraph_t, graph);
igraph_edge_connectivity(graph,&value,1);
return INT2NUM(value);
}
/* call-seq:
* graph.st_vertex_connectivity(source,target,neigh) -> Integer
*
* The vertex connectivity of two vertices (source and target) is the minimum
* number of vertices that have to be deleted to eliminate all paths from
* source to target. Directed paths are considered in directed graphs.
*
* A constant giving what to do if the two vertices are connected. Possible
* values: IGraph::VCONN_NEI_ERROR, stop with an error message,
* IGraph::VCONN_INFINITY, return infinity (ie. 1.0/0.0).
* IGraph::VCONN_IGNORE, ignore the fact that the two vertices are connected
* and calculated the number of vertices needed to aliminate all paths except
* for the trivial (direct) paths between source and vertex.
*
*/
VALUE cIGraph_st_vertex_connectivity(VALUE self, VALUE source, VALUE target, VALUE neighbours){
igraph_t *graph;
igraph_integer_t from_i;
igraph_integer_t to_i;
igraph_integer_t value;
Data_Get_Struct(self, igraph_t, graph);
from_i = cIGraph_get_vertex_id(self,source);
to_i = cIGraph_get_vertex_id(self,target);
igraph_st_vertex_connectivity(graph,&value,from_i,to_i,NUM2INT(neighbours));
return INT2NUM(value);
}
/* call-seq:
* graph.vertex_connectivity() -> Integer
*
* This is the minimum of the vertex connectivity over all pairs of vertices
* in the graph.
*
*/
VALUE cIGraph_vertex_connectivity(VALUE self){
igraph_t *graph;
igraph_integer_t value;
Data_Get_Struct(self, igraph_t, graph);
igraph_vertex_connectivity(graph,&value,1);
return INT2NUM(value);
}
/* call-seq:
* graph.edge_disjoint_paths(source,target) -> Integer
*
* The maximum number of edge-disjoint paths between two vertices.
*
* A set of paths between two vertices is called edge-disjoint if they do not
* share any edges. The maximum number of edge-disjoint paths are calculated
* by this function using maximum flow techniques. Directed paths are
* considered in directed graphs.
*
*/
VALUE cIGraph_edge_disjoint_paths(VALUE self, VALUE source, VALUE target){
igraph_t *graph;
igraph_integer_t from_i;
igraph_integer_t to_i;
igraph_integer_t value;
Data_Get_Struct(self, igraph_t, graph);
from_i = cIGraph_get_vertex_id(self,source);
to_i = cIGraph_get_vertex_id(self,target);
igraph_edge_disjoint_paths(graph,&value,from_i,to_i);
return INT2NUM(value);
}
/* call-seq:
* graph.vertex_disjoint_paths(source,target) -> Integer
*
* The maximum number of vertex-disjoint paths between two vertices.
*
* A set of paths between two vertices is called vertex-disjoint if they do
* not share any vertexs. The maximum number of vertex-disjoint paths are
* calculated by this function using maximum flow techniques. Directed paths
* are considered in directed graphs.
*
*/
VALUE cIGraph_vertex_disjoint_paths(VALUE self, VALUE source, VALUE target){
igraph_t *graph;
igraph_integer_t from_i;
igraph_integer_t to_i;
igraph_integer_t value;
Data_Get_Struct(self, igraph_t, graph);
from_i = cIGraph_get_vertex_id(self,source);
to_i = cIGraph_get_vertex_id(self,target);
igraph_vertex_disjoint_paths(graph,&value,from_i,to_i);
return INT2NUM(value);
}
/* call-seq:
* graph.adhesion() -> Integer
*
* Graph adhesion, this is (almost) the same as edge connectivity.
*
* This quantity is defined by White and Harary in The cohesiveness of
* blocks in social networks: node connectivity and conditional density,
* (Sociological Methodology 31:305--359, 2001) and basically it is the
* edge connectivity of the graph with uniform edge weights.
*
*/
VALUE cIGraph_adhesion(VALUE self){
igraph_t *graph;
igraph_integer_t value;
Data_Get_Struct(self, igraph_t, graph);
igraph_adhesion(graph,&value,1);
return INT2NUM(value);
}
/* call-seq:
* graph.cohesion() -> Integer
*
* Graph cohesion, this is the same as vertex connectivity.
*
* This quantity is defined by White and Harary in The cohesiveness of
* blocks in social networks: node connectivity and conditional density,
* (Sociological Methodology 31:305--359, 2001) and basically it is the
* edge connectivity of the graph with uniform edge weights.
*
*/
VALUE cIGraph_cohesion(VALUE self){
igraph_t *graph;
igraph_integer_t value;
Data_Get_Struct(self, igraph_t, graph);
igraph_cohesion(graph,&value,1);
return INT2NUM(value);
}

258
ext/cIGraph_dijkstra.c Normal file
View File

@ -0,0 +1,258 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.dijkstra_shortest_paths(varray,weights,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 given a set of
* edge weights given in the weights Array. 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_dijkstra_shortest_paths(VALUE self, VALUE from, VALUE weights, VALUE mode){
igraph_t *graph;
igraph_vs_t vids;
igraph_vector_t vidv;
igraph_vector_t wghts;
igraph_neimode_t pmode = NUM2INT(mode);
igraph_matrix_t res;
int i;
int j;
VALUE row;
VALUE path_length;
VALUE matrix = rb_ary_new();
int n_row;
int n_col;
Data_Get_Struct(self, igraph_t, graph);
n_row = NUM2INT(rb_funcall(from,rb_intern("length"),0));
n_col = igraph_vcount(graph);
//matrix to hold the results of the calculations
igraph_matrix_init(&res,n_row,n_col);
igraph_vector_init(&wghts,RARRAY_LEN(weights));
for(i=0;i<RARRAY_LEN(weights);i++){
VECTOR(wghts)[i] = NUM2DBL(RARRAY_PTR(weights)[i]);
}
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,from,&vidv);
//create vertex selector from the vecotr of ids
igraph_vs_vector(&vids,&vidv);
igraph_dijkstra_shortest_paths(graph,&res,vids,&wghts,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++){
path_length = MATRIX(res,i,j) == n_col ? Qnil : rb_float_new(MATRIX(res,i,j));
rb_ary_push(row,path_length);
}
}
igraph_vector_destroy(&vidv);
igraph_matrix_destroy(&res);
igraph_vs_destroy(&vids);
return matrix;
}
/* 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_dijkstra_shortest_paths(VALUE self, VALUE from, VALUE to, VALUE mode){
igraph_t *graph;
igraph_integer_t from_vid;
igraph_vs_t to_vids;
igraph_vector_t to_vidv;
igraph_neimode_t pmode = NUM2INT(mode);
igraph_vector_ptr_t res;
igraph_vector_t *path_v;
int i;
int j;
VALUE path;
VALUE matrix = rb_ary_new();
int n_paths;
Data_Get_Struct(self, igraph_t, graph);
n_paths = RARRAY_LEN(to);
//vector to hold the results of the calculations
igraph_vector_ptr_init(&res,0);
for(i=0;i<n_paths;i++){
path_v = malloc(sizeof(igraph_vector_t));
igraph_vector_init(path_v,0);
igraph_vector_ptr_push_back(&res,path_v);
}
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&to_vidv,0);
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);
//The id of the vertex from where we are counting
from_vid = cIGraph_get_vertex_id(self, from);
igraph_get_shortest_paths(graph,&res,from_vid,to_vids,pmode);
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++){
rb_ary_push(path,cIGraph_get_vertex_object(self,VECTOR(*path_v)[j]));
}
}
for(i=0;i<n_paths;i++){
igraph_vector_destroy(VECTOR(res)[i]);
free(VECTOR(res)[i]);
}
igraph_vector_destroy(&to_vidv);
igraph_vector_ptr_destroy(&res);
igraph_vs_destroy(&to_vids);
return matrix;
}
int igraph_dijkstra_shortest_paths(const igraph_t *graph,
igraph_matrix_t *res,
const igraph_vs_t from,
const igraph_vector_t *wghts,
igraph_neimode_t mode) {
long int no_of_nodes=igraph_vcount(graph);
long int no_of_from;
igraph_real_t *shortest;
igraph_real_t min,alt;
int i, j, uj, included;
igraph_integer_t eid, u,v;
igraph_vector_t q;
igraph_vit_t fromvit;
igraph_vector_t neis;
IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit));
IGRAPH_FINALLY(igraph_vit_destroy, &fromvit);
no_of_from=IGRAPH_VIT_SIZE(fromvit);
if (mode != IGRAPH_OUT && mode != IGRAPH_IN &&
mode != IGRAPH_ALL) {
IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
}
shortest=calloc(no_of_nodes, sizeof(igraph_real_t));
if (shortest==0) {
IGRAPH_ERROR("shortest paths failed", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(free, shortest);
IGRAPH_CHECK(igraph_matrix_resize(res, no_of_from, no_of_nodes));
igraph_matrix_null(res);
for (IGRAPH_VIT_RESET(fromvit), i=0;
!IGRAPH_VIT_END(fromvit);
IGRAPH_VIT_NEXT(fromvit), i++) {
//Start shortest and previous
for(j=0;j<no_of_nodes;j++){
shortest[j] = INFINITY;
//memset(previous,NAN, no_of_nodes);
}
shortest[(int)IGRAPH_VIT_GET(fromvit)] = 0;
igraph_vector_init_seq(&q,0,no_of_nodes-1);
while(igraph_vector_size(&q) != 0){
min = INFINITY;
u = no_of_nodes;
uj = igraph_vector_size(&q);
for(j=0;j<igraph_vector_size(&q);j++){
v = VECTOR(q)[j];
if(shortest[(int)v] < min){
min = shortest[(int)v];
u = v;
uj = j;
}
}
if(min == INFINITY)
break;
igraph_vector_remove(&q,uj);
igraph_vector_init(&neis,0);
igraph_neighbors(graph,&neis,u,mode);
for(j=0;j<igraph_vector_size(&neis);j++){
v = VECTOR(neis)[j];
//v must be in Q
included = 0;
for(j=0;j<igraph_vector_size(&q);j++){
if(v == VECTOR(q)[j]){
included = 1;
break;
}
}
if(!included)
continue;
igraph_get_eid(graph,&eid,u,v,1);
alt = shortest[(int)u] + VECTOR(*wghts)[(int)eid];
if(alt < shortest[(int)v]){
shortest[(int)v] = alt;
}
}
igraph_vector_destroy(&neis);
}
for(j=0;j<no_of_nodes;j++){
MATRIX(*res,i,j) = shortest[j];
}
igraph_vector_destroy(&q);
}
/* Clean */
free(shortest);
igraph_vit_destroy(&fromvit);
IGRAPH_FINALLY_CLEAN(2);
return 0;
}

39
ext/cIGraph_direction.c Normal file
View File

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

View File

@ -4,6 +4,7 @@
void cIGraph_error_handler(const char *reason, const char *file,
int line, int igraph_errno) {
IGRAPH_FINALLY_FREE();
rb_raise(cIGraphError, reason);
}

851
ext/cIGraph_file.c Normal file
View File

@ -0,0 +1,851 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
#ifdef __APPLE__
#else
/* call-seq:
* IGraph::FileRead.read_graph_edgelist(file,mode) -> IGraph
*
* Reads an edge list from a File (or any IO) and creates a graph.
*
* This format is simply a series of even number integers separated by
* whitespace. The one edge (ie. two integers) per line format is thus not
* required (but recommended for readability). Edges of directed graphs are
* assumed to be in from, to order.
*/
VALUE cIGraph_read_graph_edgelist(VALUE self, VALUE file, VALUE directed){
VALUE string;
FILE *stream;
VALUE new_graph;
VALUE v_ary;
igraph_t *graph;
igraph_bool_t directed_b = 0;
igraph_vs_t vs;
igraph_vit_t vit;
int vid;
if(directed)
directed_b = 1;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
string = rb_funcall(file, rb_intern("read"), 0);
stream = fmemopen(RSTRING_PTR(string),RSTRING_LEN(string), "r");
igraph_read_graph_edgelist(graph, stream, 0, directed_b);
fclose(stream);
igraph_vs_all(&vs);
igraph_vit_create(graph, vs, &vit);
v_ary = ((VALUE*)graph->attr)[0];
while (!IGRAPH_VIT_END(vit)) {
vid = IGRAPH_VIT_GET(vit);
rb_ary_push(v_ary,INT2NUM(vid));
IGRAPH_VIT_NEXT(vit);
}
igraph_vit_destroy(&vit);
igraph_vs_destroy(&vs);
return new_graph;
}
/* call-seq:
* graph.write_graph_edgelist(file) -> Integer
*
* Writes an edge list to an IO
*
* This format is simply a series of even number integers separated by
* whitespace. The one edge (ie. two integers) per line format is thus not
* required (but recommended for readability). Edges of directed graphs are
* assumed to be in from, to order.
*/
VALUE cIGraph_write_graph_edgelist(VALUE self, VALUE file){
char *buf;
size_t size;
FILE *stream;
igraph_t *graph;
int e;
Data_Get_Struct(self, igraph_t, graph);
stream = open_memstream(&buf,&size);
e = igraph_write_graph_edgelist(graph, stream);
fflush(stream);
rb_funcall(file, rb_intern("write"), 1, rb_str_new(buf,size));
fclose(stream);
return e;
}
/* call-seq:
* IGraph::FileRead.read_graph_ncol(file,predefnames,names,weights,directed) -> IGraph
*
* Reads a .ncol file used by LGL, also useful for creating graphs from
* 'named' (and optionally weighted) edge lists.
*
* This format is used by the Large Graph Layout program
* (http://bioinformatics.icmb.utexas.edu/lgl/), and it is simply a symbolic
* weighted edge list. It is a simple text file with one edge per line. An
* edge is defined by two symbolic vertex names separated by whitespace.
* (The symbolic vertex names themselves cannot contain whitespace. They
* might follow by an optional number, this will be the weight of the edge;
* the number can be negative and can be in scientific notation. If there is
* no weight specified to an edge it is assumed to be zero.
*
* The resulting graph is always undirected. LGL cannot deal with files which
* contain multiple or loop edges, this is however not checked here, as
* igraph is happy with these.
*
* file: A File or IO object to read from.
*
* predefnames: Array of the symbolic names of the vertices in the file.
* If empty then vertex ids will be assigned to vertex names in the order of
* their appearence in the .ncol file.
*
* names: Logical value, if TRUE the symbolic names of the vertices will be
* added to the graph as a vertex attribute called 'name'.
*
* weights: Logical value, if TRUE the weights of the edges is added to the
* graph as an edge attribute called 'weight'.
*
* directed: Whether to create a directed graph. As this format was originally
* used only for undirected graphs there is no information in the file about
* the directedness of the graph. Set this parameter to IGRAPH_DIRECTED or
* IGRAPH_UNDIRECTED to create a directed or undirected graph.
*/
VALUE cIGraph_read_graph_ncol(VALUE self, VALUE file, VALUE predefnames, VALUE names, VALUE weights, VALUE directed){
VALUE string;
FILE *stream;
VALUE new_graph;
VALUE v_ary;
VALUE e_ary;
VALUE new_ary;
igraph_t *graph;
igraph_strvector_t names_vec;
igraph_bool_t directed_b = 0;
igraph_bool_t weights_b = 0;
igraph_bool_t names_b = 0;
int i;
if(directed)
directed_b = 1;
if(names)
names_b = 1;
if(weights)
weights_b = 1;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_strvector_init(&names_vec,RARRAY_LEN(predefnames));
for(i=0;i<RARRAY_LEN(predefnames);i++){
igraph_strvector_set(&names_vec, i, RSTRING_PTR(RARRAY_PTR(predefnames)[i]));
}
string = rb_funcall(file, rb_intern("read"), 0);
stream = fmemopen(RSTRING_PTR(string),RSTRING_LEN(string), "r");
if (RARRAY_LEN(predefnames) == 0){
igraph_read_graph_ncol(graph, stream, NULL, names_b, weights_b, directed_b);
} else {
igraph_read_graph_ncol(graph, stream, &names_vec, names_b, weights_b, directed_b);
}
fclose(stream);
//Convert the Hash of names to Strings instead
if(names){
v_ary = ((VALUE*)graph->attr)[0];
new_ary = rb_ary_new();
for(i=0;i<RARRAY_LEN(v_ary);i++){
rb_ary_push(new_ary, rb_hash_aref(RARRAY_PTR(v_ary)[i], rb_str_new2("name")));
}
((VALUE*)graph->attr)[0] = new_ary;
}
//Convert the Hash of weights to floats instead
if(weights){
e_ary = ((VALUE*)graph->attr)[1];
new_ary = rb_ary_new();
for(i=0;i<RARRAY_LEN(e_ary);i++){
rb_ary_push(new_ary, rb_hash_aref(RARRAY_PTR(e_ary)[i], rb_str_new2("weight")));
}
((VALUE*)graph->attr)[1] = new_ary;
}
igraph_strvector_destroy(&names_vec);
return new_graph;
}
/* call-seq:
* graph.write_graph_ncol(file,names,weights) -> Integer
*
* Writes the graph to a file in .ncol format
*
* .ncol is a format used by LGL, see igraph_read_graph_ncol() for details.
*
* Note that having multiple or loop edges in an .ncol file breaks the LGL
* software but igraph does not check for this condition.
*
* file: The file object to write to, it should be writable.
*
* names: The name of the vertex attribute, if symbolic names are to be
* written to the file.
*
* weights: The name of the edge attribute, if they are also written to the
* file.
*/
VALUE cIGraph_write_graph_ncol(VALUE self, VALUE file, VALUE names, VALUE weights){
char *buf;
size_t size;
FILE *stream;
igraph_t *graph;
int e, i;
VALUE v_ary = Qnil;
VALUE e_ary = Qnil;
VALUE new_v_ary;
VALUE new_e_ary;
VALUE vertex_h;
VALUE edge_h;
char *weights_b = "0";
char *names_b = "0";
if(names)
names_b = "name";
if(weights)
weights_b = "weight";
Data_Get_Struct(self, igraph_t, graph);
//Convert each object to it's String representation and each edge to
//it's Float
if(names){
v_ary = ((VALUE*)graph->attr)[0];
new_v_ary = rb_ary_new();
for(i=0;i<RARRAY_LEN(v_ary);i++){
vertex_h = rb_hash_new();
rb_hash_aset(vertex_h, rb_str_new2("name"), StringValue(RARRAY_PTR(v_ary)[i]));
rb_ary_push(new_v_ary, vertex_h);
}
((VALUE*)graph->attr)[0] = new_v_ary;
}
if(weights){
e_ary = ((VALUE*)graph->attr)[1];
new_e_ary = rb_ary_new();
for(i=0;i<RARRAY_LEN(e_ary);i++){
edge_h = rb_hash_new();
rb_hash_aset(edge_h, rb_str_new2("weight"), rb_funcall(RARRAY_PTR(e_ary)[i],rb_intern("to_f"),0));
rb_ary_push(new_e_ary, edge_h);
}
((VALUE*)graph->attr)[1] = new_e_ary;
}
stream = open_memstream(&buf,&size);
e = igraph_write_graph_ncol(graph, stream, names_b, weights_b);
fflush(stream);
rb_funcall(file, rb_intern("write"), 1, rb_str_new(buf,size));
fclose(stream);
//Replace initital vertices and edges
if(names){
((VALUE*)graph->attr)[0] = v_ary;
}
if(weights){
((VALUE*)graph->attr)[0] = e_ary;
}
return e;
}
/* call-seq:
* IGraph::FileRead.read_graph_lgl(file,predefnames,names,weights) -> IGraph
*
* Reads a graph from an .lgl file
*
* The .lgl format is used by the Large Graph Layout visualization software
* (http://bioinformatics.icmb.utexas.edu/lgl/), it can describe undirected
* optionally weighted graphs. From the LGL manual:
*
* The second format is the LGL file format ( .lgl file suffix). This is yet
* another graph file format that tries to be as stingy as possible with
* space, yet keeping the edge file in a human readable (not binary) format.
* The format itself is like the following:
*
* # vertex1name
* vertex2name [optionalWeight]
* vertex3name [optionalWeight]
*
* Here, the first vertex of an edge is preceded with a pound sign '#'.
* Then each vertex that shares an edge with that vertex is listed one per
* line on subsequent lines.
*
* LGL cannot handle loop and multiple edges or directed graphs, but in
* igraph it is not an error to have multiple and loop edges.
*
* file: A File or IO object to read from.
*
* names: Logical value, if TRUE the symbolic names of the vertices will be
* added to the graph as a vertex attribute called $B!H(Bname$B!I(B.
*
* weights: Logical value, if TRUE the weights of the edges is added to the
* graph as an edge attribute called $B!H(Bweight$B!I(B.
*/
VALUE cIGraph_read_graph_lgl(VALUE self, VALUE file, VALUE names, VALUE weights){
VALUE string;
FILE *stream;
VALUE new_graph;
VALUE v_ary;
VALUE e_ary;
VALUE new_ary;
igraph_t *graph;
igraph_bool_t weights_b = 0;
igraph_bool_t names_b = 0;
int i;
if(names)
names_b = 1;
if(weights)
weights_b = 1;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
string = rb_funcall(file, rb_intern("read"), 0);
stream = fmemopen(RSTRING_PTR(string),RSTRING_LEN(string), "r");
igraph_read_graph_lgl(graph, stream, names_b, weights_b);
fclose(stream);
//Convert the Hash of names to Strings instead
if(names){
v_ary = ((VALUE*)graph->attr)[0];
new_ary = rb_ary_new();
for(i=0;i<RARRAY_LEN(v_ary);i++){
rb_ary_push(new_ary, rb_hash_aref(RARRAY_PTR(v_ary)[i], rb_str_new2("name")));
}
((VALUE*)graph->attr)[0] = new_ary;
}
//Convert the Hash of weights to floats instead
if(weights){
e_ary = ((VALUE*)graph->attr)[1];
new_ary = rb_ary_new();
for(i=0;i<RARRAY_LEN(e_ary);i++){
rb_ary_push(new_ary, rb_hash_aref(RARRAY_PTR(e_ary)[i], rb_str_new2("weight")));
}
((VALUE*)graph->attr)[1] = new_ary;
}
return new_graph;
}
/* call-seq:
* graph.write_graph_lgl(file,names,weights,isolates) -> Integer
*
* Writes the graph to a file in .lgl format
*
* .lgl is a format used by LGL, see read_graph_lgl() for details.
*
* Note that having multiple or loop edges in an .lgl file breaks the LGL
* software but igraph does not check for this condition.
*
* file: The File object to write to, it should be writable.
*
* names: The name of the vertex attribute, if symbolic names are written to
* the file.
*
* weights: The name of the edge attribute, if they are also written to the
* file.
*
* isolates: Logical, if TRUE isolated vertices are also written to the file.
* If FALSE they will be omitted.
*/
VALUE cIGraph_write_graph_lgl(VALUE self, VALUE file, VALUE names, VALUE weights, VALUE isolates){
char *buf;
size_t size;
FILE *stream;
igraph_t *graph;
int e, i;
VALUE v_ary = Qnil;
VALUE e_ary = Qnil;
VALUE new_v_ary;
VALUE new_e_ary;
VALUE vertex_h;
VALUE edge_h;
char *weights_b = "0";
char *names_b = "0";
igraph_bool_t isolates_b;
if(names)
names_b = "name";
if(weights)
weights_b = "weight";
if(isolates)
isolates_b = 1;
Data_Get_Struct(self, igraph_t, graph);
//Convert each object to it's String representation and each edge to
//it's Float
if(names){
v_ary = ((VALUE*)graph->attr)[0];
new_v_ary = rb_ary_new();
for(i=0;i<RARRAY_LEN(v_ary);i++){
vertex_h = rb_hash_new();
rb_hash_aset(vertex_h, rb_str_new2("name"), StringValue(RARRAY_PTR(v_ary)[i]));
rb_ary_push(new_v_ary, vertex_h);
}
((VALUE*)graph->attr)[0] = new_v_ary;
}
if(weights){
e_ary = ((VALUE*)graph->attr)[1];
new_e_ary = rb_ary_new();
for(i=0;i<RARRAY_LEN(e_ary);i++){
edge_h = rb_hash_new();
rb_hash_aset(edge_h, rb_str_new2("weight"), rb_funcall(RARRAY_PTR(e_ary)[i],rb_intern("to_f"),0));
rb_ary_push(new_e_ary, edge_h);
}
((VALUE*)graph->attr)[1] = new_e_ary;
}
stream = open_memstream(&buf,&size);
e = igraph_write_graph_lgl(graph, stream, names_b, weights_b, isolates);
fflush(stream);
rb_funcall(file, rb_intern("write"), 1, rb_str_new(buf,size));
fclose(stream);
//Replace initital vertices and edges
if(names){
((VALUE*)graph->attr)[0] = v_ary;
}
if(weights){
((VALUE*)graph->attr)[0] = e_ary;
}
return e;
}
/* call-seq:
* IGraph::FileRead.read_graph_dimacs(file,directed) -> IGraph
*
* This function reads the DIMACS file format, more specifically the version
* for network flow problems, see the files at
* ftp://dimacs.rutgers.edu/pub/netflow/general-info/
*
* This is a line-oriented text file (ASCII) format. The first character of
* each line defines the type of the line. If the first character is c the
* line is a comment line and it is ignored. There is one problem line ( p in
* the file, it must appear before any node and arc descriptor lines. The
* problem line has three fields separated by spaces: the problem type
* ( min , max or asn ), the number of vertices and number of edges in the
* graph. Exactly two node identification lines are expected ( n ), one for
* the source, one for the target vertex. These have two fields: the id of
* the vertex and the type of the vertex, either s (=source) or t (=target).
* Arc lines start with a and have three fields: the source vertex, the
* target vertex and the edge capacity.
*
* Vertex ids are numbered from 1. The source, target vertices and edge
* capacities are added as attributes of the graph.
* I.e: g.attributes['source'].
*
* file: The File to read from.
*
* directed: Boolean, whether to create a directed graph.
*/
VALUE cIGraph_read_graph_dimacs(VALUE self, VALUE file, VALUE directed){
VALUE string;
FILE *stream;
VALUE new_graph;
igraph_integer_t source;
igraph_integer_t target;
igraph_vector_t capacity;
igraph_vector_t label;
igraph_strvector_t problem;
igraph_t *graph;
igraph_bool_t directed_b = 0;
igraph_vs_t vs;
igraph_vit_t vit;
VALUE v_ary;
VALUE g_hsh;
int i;
int vid;
if(directed)
directed_b = 1;
igraph_vector_init(&capacity, 0);
igraph_vector_init(&label, 0);
igraph_strvector_init(&problem, 0);
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
string = rb_funcall(file, rb_intern("read"), 0);
stream = fmemopen(RSTRING_PTR(string),RSTRING_LEN(string), "r");
igraph_read_graph_dimacs(graph, stream, &problem, &label, &source, &target, &capacity, directed_b);
fclose(stream);
igraph_vs_all(&vs);
igraph_vit_create(graph, vs, &vit);
//Push Integer onto vertex array
v_ary = ((VALUE*)graph->attr)[0];
while (!IGRAPH_VIT_END(vit)) {
vid = IGRAPH_VIT_GET(vit);
rb_ary_push(v_ary,INT2NUM(vid));
IGRAPH_VIT_NEXT(vit);
}
g_hsh = ((VALUE*)graph->attr)[2];
rb_hash_aset(g_hsh, rb_str_new2("source"), INT2NUM(source));
rb_hash_aset(g_hsh, rb_str_new2("target"), INT2NUM(target));
rb_hash_aset(g_hsh, rb_str_new2("capacity"), rb_ary_new());
for(i=0;i<igraph_vector_size(&capacity);i++){
rb_ary_push(rb_hash_aref(g_hsh, rb_str_new2("capacity")), rb_float_new(VECTOR(capacity)[i]));
}
igraph_vit_destroy(&vit);
igraph_vs_destroy(&vs);
return new_graph;
}
/* call-seq:
* graph.write_graph_dimacs(file,source,target,capacity) -> Integer
*
* This function writes a graph to an output stream in DIMACS format,
* describing a maximum flow problem. See
* ftp://dimacs.rutgers.edu/pub/netflow/general-info/
*
* This file format is discussed in the documentation of read_graph_dimacs(),
* see that for more information.
*
* file: IO object to write to.
*
* source: The source vertex for the maximum flow.
*
* target: The target vertex.
*
* capacity: Array containing the edge capacity values.
*/
VALUE cIGraph_write_graph_dimacs(VALUE self, VALUE file, VALUE source, VALUE target, VALUE capacity){
char *buf;
size_t size;
FILE *stream;
igraph_t *graph;
int e, i;
igraph_vector_t capacity_v;
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_init(&capacity_v,0);
for(i=0;i<RARRAY_LEN(capacity);i++){
igraph_vector_push_back(&capacity_v,NUM2DBL(RARRAY_PTR(capacity)[i]));
}
stream = open_memstream(&buf,&size);
e = igraph_write_graph_dimacs(graph, stream, NUM2INT(source), NUM2INT(target), &capacity_v);
fflush(stream);
rb_funcall(file, rb_intern("write"), 1, rb_str_new(buf,size));
fclose(stream);
return e;
}
/* call-seq:
* IGraph::FileRead.read_graph_graphdb(file,directed) -> IGraph
*
* Read a graph in the binary graph database format.
*
* file: The IO object to read from.
*
* directed: Boolean, whether to create a directed graph.
*/
VALUE cIGraph_read_graph_graphdb(VALUE self, VALUE file, VALUE directed){
VALUE string;
FILE *stream;
VALUE new_graph;
VALUE v_ary;
igraph_t *graph;
igraph_bool_t directed_b = 0;
igraph_vs_t vs;
igraph_vit_t vit;
int vid;
if(directed)
directed_b = 1;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
string = rb_funcall(file, rb_intern("read"), 0);
stream = fmemopen(RSTRING_PTR(string),RSTRING_LEN(string), "r");
igraph_read_graph_graphdb(graph, stream, directed_b);
fclose(stream);
igraph_vs_all(&vs);
igraph_vit_create(graph, vs, &vit);
//Push Integer onto vertex array
v_ary = ((VALUE*)graph->attr)[0];
while (!IGRAPH_VIT_END(vit)) {
vid = IGRAPH_VIT_GET(vit);
rb_ary_push(v_ary,INT2NUM(vid));
IGRAPH_VIT_NEXT(vit);
}
igraph_vit_destroy(&vit);
igraph_vs_destroy(&vs);
return new_graph;
}
/* call-seq:
* IGraph::FileRead.read_graph_graphml(file,index) -> IGraph
*
* Reads a graph from a GraphML file specified as the File object file.
*
* GraphML is an XML-based file format for representing various types of
* graphs. Currently only the most basic import functionality is implemented
* in igraph: it can read GraphML files without nested graphs and hyperedges.
*
* If the GraphML file contains more than one graph, the one specified by
* this index will be loaded. Indices start from zero, so supply zero here
* if your GraphML file contains only a single graph.
*/
VALUE cIGraph_read_graph_graphml(VALUE self, VALUE file, VALUE index){
VALUE string;
FILE *stream;
VALUE new_graph;
igraph_t *graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
string = rb_funcall(file, rb_intern("read"), 0);
stream = fmemopen(RSTRING_PTR(string),RSTRING_LEN(string), "r");
igraph_read_graph_graphml(graph, stream, NUM2INT(index));
fclose(stream);
return new_graph;
}
/* call-seq:
* graph.write_graph_graphml(file) -> Integer
*
* Writes the graph to a File in GraphML format
*
* GraphML is an XML-based file format for representing various types of
* graphs. See the GraphML Primer
* (http://graphml.graphdrawing.org/primer/graphml-primer.html) for detailed
* format description.
*/
VALUE cIGraph_write_graph_graphml(VALUE self, VALUE file){
char *buf;
size_t size;
FILE *stream;
igraph_t *graph;
int e;
Data_Get_Struct(self, igraph_t, graph);
stream = open_memstream(&buf,&size);
e = igraph_write_graph_graphml(graph, stream);
fflush(stream);
rb_funcall(file, rb_intern("write"), 1, rb_str_new(buf,size));
fclose(stream);
return e;
}
/* call-seq:
* IGraph::FileRead.read_graph_gml(file) -> IGraph
*
* Reads a graph from a GraphML file.
*
* GraphML is an XML-based file format for representing various types of
* graphs. Currently only the most basic import functionality is implemented
* in igraph: it can read GraphML files without nested graphs and hyperedges.
*
* file: IO object to read from
*/
VALUE cIGraph_read_graph_gml(VALUE self, VALUE file){
VALUE string;
FILE *stream;
VALUE new_graph;
igraph_t *graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
string = rb_funcall(file, rb_intern("read"), 0);
stream = fmemopen(RSTRING_PTR(string),RSTRING_LEN(string), "r");
igraph_read_graph_gml(graph, stream);
fclose(stream);
return new_graph;
}
/* call-seq:
* graph.write_graph_gml(file) -> IGraph
*
* Writes the graph to a file in GraphML format.
*
* file: IO object to write to
*/
VALUE cIGraph_write_graph_gml(VALUE self, VALUE file){
char *buf;
size_t size;
FILE *stream;
igraph_t *graph;
int e;
Data_Get_Struct(self, igraph_t, graph);
stream = open_memstream(&buf,&size);
e = igraph_write_graph_gml(graph, stream, NULL, 0);
fflush(stream);
rb_funcall(file, rb_intern("write"), 1, rb_str_new(buf,size));
fclose(stream);
return e;
}
/* call-seq:
* IGraph::FileRead.read_graph_pajek(file) -> IGraph
*
* Reads a file in Pajek format
*
* Only a subset of the Pajek format is implemented. This is partially
* because this format is not very well documented, but also because
* igraph does not support some Pajek features, like multigraphs.
*/
VALUE cIGraph_read_graph_pajek(VALUE self, VALUE file){
VALUE string;
FILE *stream;
VALUE new_graph;
igraph_t *graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
string = rb_funcall(file, rb_intern("read"), 0);
stream = fmemopen(RSTRING_PTR(string),RSTRING_LEN(string), "r");
IGRAPH_CHECK(igraph_read_graph_pajek(graph, stream));
fclose(stream);
return new_graph;
}
/* call-seq:
* graph.write_graph_pajek(file) -> Integer
*
* Writes a graph to a file in Pajek format.
*/
VALUE cIGraph_write_graph_pajek(VALUE self, VALUE file){
char *buf;
size_t size;
FILE *stream;
igraph_t *graph;
int e;
Data_Get_Struct(self, igraph_t, graph);
stream = open_memstream(&buf,&size);
e = igraph_write_graph_pajek(graph, stream);
fflush(stream);
rb_funcall(file, rb_intern("write"), 1, rb_str_new(buf,size));
fclose(stream);
return e;
}
#endif

View File

@ -0,0 +1,324 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* IGraph::Generate.adjacency(matrix,mode) -> IGraph
*
* Creates a graph object from an adjacency matrix.
*
* matrix should be given as an IGraphMatrix object. mode controls how the
* matrix is interpreted:
*
* IGraph::ADJ_DIRECTED - The graph will be directed and an element
* gives the number of edges between two vertex.
*
* IGraph::ADJ_UNDIRECTED - This is the same as
* IGraph::ADJ_MAX, for convenience.
*
* IGraph::ADJ_MAX - Undirected graph will be created and the
* number of edges between vertex i and j is max(A(i,j), A(j,i)).
*
* IGraph::ADJ_MIN - Undirected graph will be created with
* min(A(i,j), A(j,i)) edges between vertex i and j.
*
* IGraph::ADJ_PLUS - Undirected graph will be created with
* A(i,j)+A(j,i) edges between vertex i and j.
*
* IGraph::ADJ_UPPER - Undirected graph will be created, only the
* upper right triangle (including the diagonal) is used for the number of
* edges.
*
* IGraph::ADJ_LOWER - Undirected graph will be created, only the
* lower left triangle (including th * e diagonal) is used for creating the
* edges.
*/
VALUE cIGraph_adjacency(VALUE self, VALUE matrix, VALUE mode){
igraph_t *graph;
igraph_matrix_t *matrixp;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
Data_Get_Struct(matrix, igraph_matrix_t, matrixp);
igraph_destroy(graph);
igraph_adjacency(graph, matrixp, NUM2INT(mode));
return new_graph;
}
/* call-seq:
* IGraph::Generate.star(n,mode,center) -> IGraph
*
* Creates a star graph, every vertex connects only to the center.
*
* The number of vertices should be given in n. mode gives the type of the
* star graph to create. Possible values:
*
* IGraph::STAR_OUT - directed star graph, edges point from the center to the
* other vertices.
*
* IGraph::STAR_IN - directed star graph, edges point to the center from the
* other vertices.
*
* IGraph::STAR_UNDIRECTED - an undirected star graph is created.
*
* The id of the vertex which will be the center of the graph is given by
* center
*/
VALUE cIGraph_star(VALUE self, VALUE n, VALUE mode, VALUE center){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_star(graph, NUM2INT(n), NUM2INT(mode), NUM2INT(center));
return new_graph;
}
/* call-seq:
* IGraph::Generate.lattice(dim,directed,mutual,circular) -> IGraph
*
* Creates most kind of lattices.
*
* The dimensions of the lattice should be given as an Array of Fixnums in dim
*
* directed: Boolean, whether to create a directed graph. The direction of
* the edges is determined by the generation algorithm and is unlikely to
* suit you, so this isn't a very useful option.
*
* mutual: Boolean, if the graph is directed this gives whether to create
* all connections as mutual.
*
* circular: Boolean, defines whether the generated lattice is periodic.
*/
VALUE cIGraph_lattice(VALUE self, VALUE dim, VALUE directed, VALUE mutual, VALUE circular){
igraph_t *graph;
VALUE new_graph;
igraph_vector_t dimvector;
int i;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_vector_init(&dimvector,0);
for(i=0; i<RARRAY_LEN(dim); i++){
igraph_vector_push_back(&dimvector,NUM2INT(RARRAY_PTR(dim)[i]));
}
igraph_destroy(graph);
igraph_lattice(graph, &dimvector, 0,
directed == Qtrue ? 1 : 0,
mutual == Qtrue ? 1 : 0,
circular == Qtrue ? 1 : 0);
igraph_vector_destroy(&dimvector);
return new_graph;
}
/* call-seq:
* IGraph::Generate.ring(n,directed,mutual,circular) -> IGraph
*
* Creates a ring graph, a one dimensional lattice.
*
* n: The number of vertices in the ring.
*
* directed: Logical, whether to create a directed ring.
*
* mutual: Logical, whether to create mutual edges in a directed ring. It is
* ignored for undirected graphs.
*
* circular: Logical, if false, the ring will be open (this is not a real
* ring actually).
*/
VALUE cIGraph_ring(VALUE self, VALUE n, VALUE directed, VALUE mutual, VALUE circular){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_ring(graph, NUM2INT(n),
directed == Qtrue ? 1 : 0,
mutual == Qtrue ? 1 : 0,
circular == Qtrue ? 1 : 0);
return new_graph;
}
/* call-seq:
* IGraph::Generate.tree(n,children,type) -> IGraph
*
* Creates a tree in which almost all vertices have the same number of
* children.
*
* n: Integer, the number of vertices in the graph.
*
* children: Integer, the number of children of a vertex in the tree.
*
* type: Constant, gives whether to create a directed tree, and if this is
* the case, also its orientation. Possible values:
*
* IGraph::TREE_OUT - directed tree, the edges point from the parents to
* their children,
*
* IGraph::TREE_IN - directed tree, the edges point from the children to
* their parents.
*
* IGraph::TREE_UNDIRECTED - undirected tree.
*/
VALUE cIGraph_tree(VALUE self, VALUE n, VALUE children, VALUE type){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_tree(graph, NUM2INT(n), NUM2INT(children), NUM2INT(type));
return new_graph;
}
/* call-seq:
* IGraph::Generate.full(n,directed,loops) -> IGraph
*
* Creates a full graph (directed or undirected, with or without loops).
*
* In a full graph every possible edge is present, every vertex is connected
* to every other vertex.
*
* n: Integer, the number of vertices in the graph.
*
* directed: Logical, whether to create a directed graph.
*
* loops: Logical, whether to include self-edges (loops).
*/
VALUE cIGraph_full(VALUE self, VALUE n, VALUE directed, VALUE loops){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_full(graph, NUM2INT(n),
directed == Qtrue ? 1 : 0,
loops == Qtrue ? 1 : 0);
return new_graph;
}
/* call-seq:
* IGraph::Generate.atlas(number) -> IGraph
*
* Create a small graph from the $B!H(BGraph Atlas$B!I(B.
*
* The number of the graph is given as the parameter. The graphs are listed:
*
* 1. in increasing order of number of nodes
* 2. for a fixed number of nodes, in increasing order of the number of edges
* 3. for fixed numbers of nodes and edges, in increasing order of the degree
* sequence, for example 111223 < 112222;
* 4. for fixed degree sequence, in increasing number of automorphisms.
*
* The data was converted from the networkx software package, see
* http://networkx.lanl.gov.
*
* See An Atlas of Graphs by Ronald C. Read and Robin J. Wilson, Oxford
* University Press, 1998.
*/
VALUE cIGraph_atlas(VALUE self, VALUE n){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_atlas(graph, NUM2INT(n));
return new_graph;
}
/* call-seq:
* IGraph::Generate.chordal_ring(nodes,w) -> IGraph
*
* Create an extended chordal ring. An extended chordal ring is regular graph,
* each node has the same degree. It can be obtained from a simple ring by
* adding some extra edges specified by a matrix. Let p denote the number of
* columns in the W matrix. The extra edges of vertex i are added according
* to column (i mod p) in W. The number of extra edges is the number of rows
* in W: for each row j an edge i->i+w[ij] is added if i+w[ij] is less than
* the number of total nodes.
*
* See also Kotsis, G: Interconnection Topologies for Parallel Processing
* Systems, PARS Mitteilungen 11, 1-6, 1993.
*
* nodes: Integer, the number of vertices in the graph. It must be at least 3.
*
* w: The matrix specifying the extra edges. The number of columns should
* divide the number of total vertices.
*/
VALUE cIGraph_extended_chordal_ring(VALUE self, VALUE n, VALUE matrix){
igraph_t *graph;
igraph_matrix_t *matrixp;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
Data_Get_Struct(matrix, igraph_matrix_t, matrixp);
igraph_destroy(graph);
igraph_extended_chordal_ring(graph, NUM2INT(n), matrixp);
return new_graph;
}
/* call-seq:
* g.connect_neighborhood(order,mode) -> nil
*
* Connects every vertex to its neighborhood This function adds new edges to
* graph. For each vertex vertices reachable by at most order steps and not
* yet connected to the vertex a new edge is created.
*
* order: Integer, it gives the distance within which the vertices will be
* connected to the source vertex.
*
* mode: Constant, it specifies how the neighborhood search is performed for
* directed graphs. If IGraph::OUT then vertices reachable from the source
* vertex will be connected, IGraph::IN is the opposite. If IGRAPH_ALL then
* the directed graph is considered as an undirected one.
*/
VALUE cIGraph_connect_neighborhood(VALUE self, VALUE order, VALUE mode){
igraph_t *graph;
Data_Get_Struct(self, igraph_t, graph);
igraph_connect_neighborhood(graph, NUM2INT(order), NUM2INT(mode));
return Qnil;
}

View File

@ -0,0 +1,790 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* IGraph::GenerateRandom.grg_game(nodes,radius,torus) -> IGraph
*
* Generating geometric random graphs. A geometric random graph is created by
* dropping points (=vertices) randomly to the unit square and then
* connecting all those pairs which are less than radius apart in Euclidean
* norm.
*
* nodes: The number of vertices in the graph.
*
* radius: The radius within which the vertices will be connected.
* torus: Logical constant, if true periodic boundary conditions will be used,
* ie. the vertices are assumed to be on a torus instead of a square.
*/
VALUE cIGraph_grg_game(VALUE self, VALUE nodes, VALUE radius, VALUE torus){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_grg_game(graph, NUM2INT(nodes), NUM2DBL(radius),
torus == Qtrue ? 1: 0, NULL, NULL);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.barabasi_game(n,m,outpref,directed) -> IGraph
*
* Generates a graph based on the Barabási-Albert model.
*
* n: The number of vertices in the graph.
* m: The number of outgoing edges generated for each vertex.
*
* outpref: Boolean, if true not only the in- but also the out-degree of a
* vertex increases its citation probability. Ie. the citation probability is
* determined by the total degree of the vertices.
*
* directed: Boolean, whether to generate a directed graph.
*/
VALUE cIGraph_barabasi_game(VALUE self, VALUE nodes, VALUE m, VALUE outpref, VALUE directed){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_barabasi_game(graph, NUM2INT(nodes), NUM2INT(m), NULL,
outpref == Qtrue ? 1: 0, directed == Qtrue ? 1: 0);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.nonlinear_barabasi_game(n,m,outpref,directed) -> IGraph
*
* Generates graph with non-linear preferential attachment.
*
* This function is very similar to barabasi_game(), only in this game the
* probability that a new vertex attaches to a given old vertex is not
* proportional to the degree of the old node, but some power of the degree
* of the old node.
*
* More precisely the attachment probability is the degree to the power of
* power plus zeroappeal.
*
* This function might generate graphs with multiple edges if the value of m
* is at least two. You can call simplify() to get rid of the multiple
* edges.
*
* n: The number of vertices in the generated graph.
*
* power: The power of the preferential attachment.
*
* m: The number of edges to generate in each time step.
*
* outpref: Logical constant, if TRUE then the preferential attachment is
* based on the total degree of the nodes instead of the in-degree.
*
* zeroappeal: Positive number, the attachment probability for vertices with
* degree zero.
*
* directed: Logical constant, whether to generate a directed graph.
*/
VALUE cIGraph_nonlinear_barabasi_game(VALUE self, VALUE nodes, VALUE power, VALUE m, VALUE outpref, VALUE zeroappeal, VALUE directed){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_nonlinear_barabasi_game(graph, NUM2INT(nodes), NUM2DBL(power),
NUM2INT(m), NULL,
outpref == Qtrue ? 1: 0,
NUM2DBL(zeroappeal),
directed == Qtrue ? 1: 0);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.erdos_renyi_game(type,n,p_or_m,directed,loops) -> IGraph
*
* Generates a random (Erdos-Renyi) graph.
*
* type: The type of the random graph, possible values:
*
* IGraph::ERDOS_RENYI_GNM - G(n,m) graph, m edges are selected uniformly
* randomly in a graph with n vertices.
*
* IGraph::ERDOS_RENYI_GNP - G(n,p) graph, every possible edge is included in
* the graph with probability p.
*
* n: The number of vertices in the graph.
*
* p_or_m: This is the p parameter for G(n,p) graphs and the m parameter
* for G(n,m) graphs.
*
* directed: Logical, whether to generate a directed graph.
*
* loops: Logical, whether to generate loops (self) edges.
*/
VALUE cIGraph_erdos_renyi_game(VALUE self, VALUE type, VALUE nodes, VALUE mp, VALUE directed, VALUE loops){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_erdos_renyi_game(graph, NUM2INT(type), NUM2INT(nodes),
NUM2DBL(mp),
directed == Qtrue ? 1: 0,
loops == Qtrue ? 1: 0);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.watts_strogatz_game(dim,size,nei,p) -> IGraph
*
* The Watts-Strogatz small-world model This function generates a graph
* according to the Watts-Strogatz model of small-world networks. The graph
* is obtained by creating a circular undirected lattice and then rewire the
* edges randomly with a constant probability.
*
* dim: The dimension of the lattice.
*
* size: The size of the lattice along each dimension.
*
* nei: The size of the neighborhood for each vertex.
*
* p: The rewiring probability. A real number between zero and one (inclusive).
*/
VALUE cIGraph_watts_strogatz_game(VALUE self, VALUE dim, VALUE size, VALUE nei, VALUE p){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_watts_strogatz_game(graph, NUM2INT(dim), NUM2INT(size),
NUM2INT(nei), NUM2DBL(p));
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.degree_sequence_game(out_deg,in_deg) -> IGraph
*
* Generates a random graph with a given degree sequence
*
* out_deg: The degree sequence for an undirected graph (if in_seq is of
* length zero), or the out-degree sequence of a directed graph (if in_deq is
* not of length zero.
*
* in_deg: It is either a zero-length Array or the in-degree sequence.
*/
VALUE cIGraph_degree_sequence_game(VALUE self, VALUE out_deg, VALUE in_deg){
igraph_t *graph;
VALUE new_graph;
igraph_vector_t out_degv;
igraph_vector_t in_degv;
int i;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_vector_init(&out_degv,0);
igraph_vector_init(&in_degv,0);
for(i=0;i<RARRAY_LEN(out_deg);i++){
igraph_vector_push_back(&out_degv,NUM2INT(RARRAY_PTR(out_deg)[i]));
}
for(i=0;i<RARRAY_LEN(in_deg);i++){
igraph_vector_push_back(&in_degv,NUM2INT(RARRAY_PTR(in_deg)[i]));
}
igraph_destroy(graph);
igraph_degree_sequence_game(graph, &out_degv, &in_degv, 0);
igraph_vector_destroy(&out_degv);
igraph_vector_destroy(&in_degv);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.growing_random_game(n,m,directed,citation) -> IGraph
*
* Generates a growing random graph.
*
* This function simulates a growing random graph. In each discrete time
* step a new vertex is added and a number of new edges are also added.
* These graphs are known to be different from standard (not growing) random
* graphs.
*
* n: The number of vertices in the graph.
*
* m: The number of edges to add in a time step (ie. after adding a vertex).
*
* directed: Boolean, whether to generate a directed graph.
*
* citation: Boolean, if TRUE, the edges always originate from the most
* recently added vertex.
*/
VALUE cIGraph_growing_random_game(VALUE self, VALUE n, VALUE m, VALUE directed, VALUE citation){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_growing_random_game(graph, NUM2INT(n), NUM2INT(m),
directed == Qtrue ? 1: 0,
citation == Qtrue ? 1: 0);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.callaway_traits_game(nodes,types,edges_per_step,type_dist,pref_matrix,directed) -> IGraph
*
* This function simulates a growing network with vertex types. The different
* types of vertices prefer to connect other types of vertices with a given
* probability.
*
* The simulation goes like this: in each discrete time step a new vertex is
* added to the graph. The type of this vertex is generated based on
* type_dist. Then two vertices are selected uniformly randomly from the
* graph. The probability that they will be connected depends on the types
* of these vertices and is taken from pref_matrix. Then another two vertices
* are selected and this is repeated edges_per_step times in each time step.
*
* nodes: The number of nodes in the graph.
*
* types: Number of node types.
*
* edges_per_step: The number of edges to be add per time step.
*
* type_dist: Array giving the distribution of the vertex types.
*
* pref_matrix: IGraphMatrix giving the connection probabilities for the
* vertex types.
*
* directed: Logical, whether to generate a directed graph.
*/
VALUE cIGraph_callaway_traits_game(VALUE self, VALUE nodes, VALUE types, VALUE e_per_step, VALUE type_dist, VALUE pref_matrix, VALUE directed){
igraph_t *graph;
VALUE new_graph;
igraph_vector_t type_distv;
igraph_matrix_t *pref_matrixm;
int i;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
Data_Get_Struct(pref_matrix, igraph_matrix_t, pref_matrixm);
igraph_vector_init(&type_distv,0);
for(i=0;i<RARRAY_LEN(type_dist);i++){
igraph_vector_push_back(&type_distv,NUM2DBL(RARRAY_PTR(type_dist)[i]));
}
igraph_destroy(graph);
igraph_callaway_traits_game(graph, NUM2INT(nodes), NUM2INT(types),
NUM2INT(e_per_step), &type_distv,
pref_matrixm,
directed == Qtrue ? 1: 0);
igraph_vector_destroy(&type_distv);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.establishment_game(nodes,types,k,type_dist,pref_matrix,directed) -> IGraph
*
* Generates a graph with a simple growing model with vertex types
*
* The simulation goes like this: a single vertex is added at each time step.
* This new vertex tries to connect to k vertices in the graph. The
* probability that such a connection is realized depends on the types of the
* vertices involved.
*
* nodes: The number of vertices in the graph.
*
* types: The number of vertex types.
*
* k: The number of connections tried in each time step.
*
* type_dist: Array giving the distribution of vertex types.
*
* pref_matrix: IGraphMatrix giving the connection probabilities for
* different vertex types.
*
* directed: Logical, whether to generate a directed graph.
*/
VALUE cIGraph_establishment_game(VALUE self, VALUE nodes, VALUE types, VALUE k, VALUE type_dist, VALUE pref_matrix, VALUE directed){
igraph_t *graph;
VALUE new_graph;
igraph_vector_t type_distv;
igraph_matrix_t *pref_matrixm;
int i;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
Data_Get_Struct(pref_matrix, igraph_matrix_t, pref_matrixm);
igraph_vector_init(&type_distv,0);
for(i=0;i<RARRAY_LEN(type_dist);i++){
igraph_vector_push_back(&type_distv,NUM2DBL(RARRAY_PTR(type_dist)[i]));
}
igraph_destroy(graph);
igraph_establishment_game(graph, NUM2INT(nodes), NUM2INT(types),
NUM2INT(k), &type_distv,
pref_matrixm,
directed == Qtrue ? 1: 0);
igraph_vector_destroy(&type_distv);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.preference_game(nodes,types,type_dist,pref_matrixdirected,loops) -> IGraph
*
* Generates a graph with vertex types and connection preferences
*
* This is practically the nongrowing variant of igraph_establishment_game.
* A given number of vertices are generated. Every vertex is assigned to a
* vertex type according to the given type probabilities. Finally, every
* vertex pair is evaluated and an edge is created between them with a
* probability depending on the types of the vertices involved.
*
* nodes: The number of vertices in the graph.
*
* types: The number of vertex types.
*
* type_dist: Vector giving the distribution of vertex types.
*
* pref_matrix: IGraphMatrix giving the connection probabilities for
* different vertex types.
*
* directed: Logical, whether to generate a directed graph. If undirected
* graphs are requested, only the lower left triangle of the preference
* matrix is considered.
*
* loops: Logical, whether loop edges are allowed.
*/
VALUE cIGraph_preference_game(VALUE self, VALUE nodes, VALUE types, VALUE type_dist, VALUE pref_matrix, VALUE directed, VALUE loops){
igraph_t *graph;
VALUE new_graph;
igraph_vector_t type_distv;
igraph_matrix_t *pref_matrixm;
int i;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
Data_Get_Struct(pref_matrix, igraph_matrix_t, pref_matrixm);
igraph_vector_init(&type_distv,0);
for(i=0;i<RARRAY_LEN(type_dist);i++){
igraph_vector_push_back(&type_distv,NUM2DBL(RARRAY_PTR(type_dist)[i]));
}
igraph_destroy(graph);
igraph_preference_game(graph, NUM2INT(nodes), NUM2INT(types),
&type_distv,
pref_matrixm,
NULL,
directed == Qtrue ? 1: 0,
loops == Qtrue ? 1 : 0);
igraph_vector_destroy(&type_distv);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.asymmetric_preference_game(nodes,types,type_dist_matrix,pref_matrix,loops) -> IGraph
*
* Generates a graph with asymmetric vertex types and connection preferences
*
* This is the asymmetric variant of preference_game() . A given number of
* vertices are generated. Every vertex is assigned to an "incoming" and an
* "outgoing" vertex type according to the given joint type probabilities.
* Finally, every vertex pair is evaluated and a directed edge is created
* between them with a probability depending on the "outgoing" type of the
* source vertex and the "incoming" type of the target vertex.
*
* nodes: The number of vertices in the graph.
*
* types: The number of vertex types.
*
* type_dist_matrix: IGraphMatrix giving the joint distribution of vertex
* types.
*
* pref_matrix: IGraphMatrix giving the connection probabilities for different
* vertex types.
*
* loops: Logical, whether loop edges are allowed.
*/
VALUE cIGraph_asymmetric_preference_game(VALUE self, VALUE nodes, VALUE types, VALUE type_dist_matrix, VALUE pref_matrix, VALUE loops){
igraph_t *graph;
VALUE new_graph;
igraph_matrix_t *type_dist_matrixm;
igraph_matrix_t *pref_matrixm;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
Data_Get_Struct(pref_matrix, igraph_matrix_t, pref_matrixm);
Data_Get_Struct(type_dist_matrix, igraph_matrix_t, type_dist_matrixm);
igraph_destroy(graph);
igraph_asymmetric_preference_game(graph, NUM2INT(nodes), NUM2INT(types),
type_dist_matrixm,
pref_matrixm,
NULL, NULL,
loops == Qtrue ? 1 : 0);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.recent_degree_game(n,power,window,m,outseq,outpref,zero_appeal,directed) -> IGraph
*
* Stochastic graph generator based on the number of adjacent edges a node
* has gained recently
*
* n: The number of vertices in the graph, this is the same as the number of
* time steps.
*
* power: The exponent, the probability that a node gains a new edge is
* proportional to the number of edges it has gained recently (in the last
* window time steps) to power.
*
* window: Integer constant, the size of the time window to use to count the
* number of recent edges.
*
* m: Integer constant, the number of edges to add per time step
*
* outpref: Logical constant, if true the edges originated by a vertex also
* count as recent adjacent edges. It is false in most cases.
*
* zero_appeal: Constant giving the attractiveness of the vertices which
* haven't gained any edge recently.
* directed: Logical constant, whether to generate a directed graph.
*/
VALUE cIGraph_recent_degree_game(VALUE self, VALUE n, VALUE power, VALUE window, VALUE m, VALUE outpref, VALUE zero_appeal, VALUE directed){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_recent_degree_game(graph, NUM2INT(n), NUM2DBL(power),
NUM2INT(window), NUM2INT(m),
NULL,
outpref == Qtrue ? 1: 0,
NUM2DBL(zero_appeal),
directed == Qtrue ? 1: 0);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.barabasi_aging_game(nodes,m,outpref,pa_exp,aging_exp,aging_bin,zero_deg_appeal,zero_age_appeal,deg_coef,age_coef,directed) -> IGraph
*
* Preferential attachment with aging of vertices.
*
* In this game, the probability that a node gains a new edge is given by
* its (in-)degree (k) and age (l). This probability has a degree dependent
* component multiplied by an age dependent component. The degree dependent
* part is: deg_coef times k to the power of pa_exp plus zero_deg_appeal; and
* the age dependent part is age_coef times l to the power of aging_exp plus
* zero_age_appeal.
*
* The age is based on the number of vertices in the network and the
* aging_bin argument: vertices grew one unit older after each aging_bin
* vertices added to the network.
*
* nodes: The number of vertices in the graph.
*
* m: The number of edges to add in each time step.
*
* outpref: Logical constant, whether the edges initiated by a vertex
* contribute to the probability to gain a new edge.
*
* pa_exp: The exponent of the preferential attachment, a small positive
* number usually, the value 1 yields the classic linear preferential
* attachment.
*
* aging_exp: The exponent of the aging, this is a negative number usually.
*
* aging_bin: Integer constant, the number of vertices to add before vertices
* in the network grew one unit older.
*
* zero_deg_appeal: The degree dependent part of the attractiveness of the
* zero degree vertices.
*
* zero_age_appeal: The age dependent part of the attractiveness of the
* vertices of age zero. This parameter is usually zero.
*
* deg_coef: The coefficient for the degree.
*
* age_coef: The coefficient for the age.
*
* directed: Logical constant, whether to generate a directed graph.
*/
VALUE cIGraph_barabasi_aging_game(VALUE self, VALUE nodes, VALUE m, VALUE outpref, VALUE pa_exp, VALUE aging_exp, VALUE aging_bin, VALUE zero_deg_appeal, VALUE zero_age_appeal, VALUE deg_coef, VALUE age_coef, VALUE directed){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_barabasi_aging_game(graph, NUM2INT(nodes), NUM2INT(m),
NULL,
outpref == Qtrue ? 1: 0,
NUM2DBL(pa_exp), NUM2DBL(aging_exp),
NUM2INT(aging_bin),
NUM2DBL(zero_deg_appeal),
NUM2DBL(zero_age_appeal),
NUM2DBL(deg_coef),
NUM2DBL(age_coef),
directed == Qtrue ? 1: 0);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.recent_degree_aging_game(nodes,m,outpref,pa_exp,aging_exp,aging_bin,time_window,zero_appeal,directed) -> IGraph
*
* Preferential attachment based on the number of edges gained recently, with
* aging of vertices
*
* This game is very similar to igraph_barabasi_aging_game(), except that
* instead of the total number of adjacent edges the number of edges gained
* in the last time_window time steps are counted.
*
* The degree dependent part of the attractiveness is given by k to the power
* of pa_exp plus zero_appeal; the age dependent part is l to the power to
* aging_exp. k is the number of edges gained in the last time_window time
* steps, l is the age of the vertex.
*
* nodes: The number of vertices in the graph.
*
* m: The number of edges to add in each time step.
*
* outpref: Logical constant, whether the edges initiated by a vertex
* contribute to the probability to gain a new edge.
*
* pa_exp: The exponent of the preferential attachment, a small positive
* number usually, the value 1 yields the classic linear preferential
* attachment.
*
* aging_exp: The exponent of the aging, this is a negative number usually.
*
* aging_bin: Integer constant, the number of vertices to add before vertices
* in the network grew one unit older.
*
* zero_appeal: The degree dependent part of the attractiveness of the
* zero degree vertices.
*
* time_window: The time window to use to count the number of adjacent edges
* for the vertices.
*
* directed: Logical constant, whether to generate a directed graph.
*/
VALUE cIGraph_recent_degree_aging_game(VALUE self, VALUE nodes, VALUE m, VALUE outpref, VALUE pa_exp, VALUE aging_exp, VALUE aging_bin, VALUE time_window, VALUE zero_appeal, VALUE directed){
igraph_t *graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_destroy(graph);
igraph_recent_degree_aging_game(graph, NUM2INT(nodes), NUM2INT(m),
NULL,
outpref == Qtrue ? 1: 0,
NUM2DBL(pa_exp), NUM2DBL(aging_exp),
NUM2INT(aging_bin),
NUM2INT(time_window),
NUM2DBL(zero_appeal),
directed == Qtrue ? 1: 0);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.cited_type_game(nodes,types,pref,edges_per_step_directed) -> IGraph
*
* Function to create a network based on some vertex categories. This function
* creates a citation network, in each step a single vertex and edges_per_step
* citating edges are added, nodes with different categories (may) have
* different probabilities to get cited, as given by the pref vector.
*
* Note that this function might generate networks with multiple edges if
* edges_per_step is greater than one. You might want to call
* igraph_simplify() on the result to remove multiple edges.
*
* nodes: The number of vertices in the network.
*
* types: Numeric Array giving the categories of the vertices, so it should
* contain nodes non-negative integer numbers. Types are numbered from zero.
*
* pref: The attractivity of the different vertex categories in an Array. Its
* length should be the maximum element in types plus one (types are numbered
* from zero).
*
* edges_per_step: Integer constant, the number of edges to add in each time
* step.
*
* directed: Logical constant, whether to create a directed network.
*/
VALUE cIGraph_cited_type_game(VALUE self, VALUE nodes, VALUE types, VALUE pref, VALUE e_per_s, VALUE directed){
igraph_t *graph;
VALUE new_graph;
igraph_vector_t type_distv;
igraph_vector_t prefv;
int i;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
igraph_vector_init(&type_distv,0);
igraph_vector_init(&prefv,0);
for(i=0;i<RARRAY_LEN(types);i++){
igraph_vector_push_back(&type_distv,NUM2DBL(RARRAY_PTR(types)[i]));
}
for(i=0;i<RARRAY_LEN(pref);i++){
igraph_vector_push_back(&prefv,NUM2DBL(RARRAY_PTR(pref)[i]));
}
igraph_destroy(graph);
igraph_cited_type_game(graph, NUM2INT(nodes),
&type_distv,
&prefv,
NUM2INT(e_per_s),
directed == Qtrue ? 1: 0);
igraph_vector_destroy(&type_distv);
igraph_vector_destroy(&prefv);
return new_graph;
}
/* call-seq:
* IGraph::GenerateRandom.citing_cited_type_game(nodes,types,pref,edges_per_step_directed) -> IGraph
*
* This game is similar to igraph_cited_type_game() but here the category of
* the citing vertex is also considered.
*
* An evolving citation network is modeled here, a single vertex and its
* edges_per_step citation are added in each time step. The odds the a given
* vertex is cited by the new vertex depends on the category of both the
* citing and the cited vertex and is given in the pref matrix. The categories
* of the citing vertex correspond to the rows, the categories of the cited
* vertex to the columns of this matrix. Ie. the element in row i and column
* j gives the probability that a j vertex is cited, if the category of the
* citing vertex is i.
*
* Note that this function might generate networks with multiple edges if
* edges_per_step is greater than one. You might want to call
* igraph_simplify() on the result to remove multiple edges.
*
* nodes: The number of vertices in the network.
*
* types: A numeric IGraphMatrix of length nodes, containing the categories
* of the vertices. The categories are numbered from zero.
*
* pref: The preference IGraphMatrix, a square matrix is required, both the
* number of rows and columns should be the maximum element in types plus
* one (types are numbered from zero).
*
* edges_per_step: Integer constant, the number of edges to add in each time
* step.
*
* directed: Logical constant, whether to create a directed network.
*/
VALUE cIGraph_citing_cited_type_game(VALUE self, VALUE nodes, VALUE types, VALUE pref, VALUE e_per_s, VALUE directed){
igraph_t *graph;
VALUE new_graph;
igraph_vector_t typev;
igraph_matrix_t *prefm;
int i;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
Data_Get_Struct(pref, igraph_matrix_t, prefm);
igraph_vector_init(&typev,0);
for(i=0;i<RARRAY_LEN(types);i++){
igraph_vector_push_back(&typev,NUM2INT(RARRAY_PTR(types)[i]));
}
printf("ok\n");
igraph_destroy(graph);
igraph_citing_cited_type_game(graph, NUM2INT(nodes),
&typev,
prefm,
NUM2INT(e_per_s),
directed == Qtrue ? 1: 0);
printf("death\n");
igraph_vector_destroy(&typev);
return new_graph;
}

View File

@ -0,0 +1,182 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.independent_vertex_sets(min_size,max_size) -> Array
*
* Find all independent vertex sets in a graph
*
* A vertex set is considered independent if there are no edges between them.
*
* If you are interested in the size of the largest independent vertex set,
* use IGraph#independence_number() instead.
*/
VALUE cIGraph_independent_vertex_sets(VALUE self, VALUE min, VALUE max){
igraph_t *graph;
igraph_vector_ptr_t res;
igraph_vector_t *vec;
int i;
int j;
VALUE independent_vertex_set;
VALUE object;
VALUE independent_vertex_sets = rb_ary_new();
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_ptr_init(&res,0);
igraph_independent_vertex_sets(graph, &res, NUM2INT(min), NUM2INT(max));
for(i=0; i<igraph_vector_ptr_size(&res); i++){
independent_vertex_set = rb_ary_new();
rb_ary_push(independent_vertex_sets,independent_vertex_set);
vec = VECTOR(res)[i];
for(j=0; j<igraph_vector_size(vec); j++){
vec = VECTOR(res)[i];
object = cIGraph_get_vertex_object(self,VECTOR(*vec)[j]);
rb_ary_push(independent_vertex_set,object);
}
}
for(i=0;i<igraph_vector_ptr_size(&res);i++){
igraph_vector_destroy(VECTOR(res)[i]);
free(VECTOR(res)[i]);
}
igraph_vector_ptr_destroy(&res);
return independent_vertex_sets;
}
/* call-seq:
* graph.largest_independent_vertex_sets() -> Array
*
* Finds the largest independent vertex set(s) in a graph.
* An independent vertex set is largest if there is no other independent
* vertex set with more vertices in the graph.
*/
VALUE cIGraph_largest_independent_vertex_sets(VALUE self){
igraph_t *graph;
igraph_vector_ptr_t res;
igraph_vector_t *vec;
int i;
int j;
VALUE independent_vertex_set;
VALUE object;
VALUE independent_vertex_sets = rb_ary_new();
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_ptr_init(&res,0);
igraph_largest_independent_vertex_sets(graph, &res);
for(i=0; i<igraph_vector_ptr_size(&res); i++){
independent_vertex_set = rb_ary_new();
rb_ary_push(independent_vertex_sets,independent_vertex_set);
vec = VECTOR(res)[i];
for(j=0; j<igraph_vector_size(vec); j++){
vec = VECTOR(res)[i];
object = cIGraph_get_vertex_object(self,VECTOR(*vec)[j]);
rb_ary_push(independent_vertex_set,object);
}
}
for(i=0;i<igraph_vector_ptr_size(&res);i++){
igraph_vector_destroy(VECTOR(res)[i]);
free(VECTOR(res)[i]);
}
igraph_vector_ptr_destroy(&res);
return independent_vertex_sets;
}
/* call-seq:
* graph.maximal_independent_vertex_sets() -> Array
*
* Find all maximal independent vertex sets of a graph
*
* A maximal independent vertex set is an independent vertex set which can't
* be extended any more by adding a new vertex to it.
*
* The algorithm used here is based on the following paper: S. Tsukiyama,
* M. Ide, H. Ariyoshi and I. Shirawaka. A new algorithm for generating all
* the maximal independent sets. SIAM J Computing, 6:505--517, 1977.
*
* The implementation was originally written by Kevin O'Neill and modified
* by K M Briggs in the Very Nauty Graph Library. I simply re-wrote it to
* use igraph's data structures.
*
* If you are interested in the size of the largest independent vertex set,
* use IGraph#independence_number() instead.
*/
VALUE cIGraph_maximal_independent_vertex_sets(VALUE self){
igraph_t *graph;
igraph_vector_ptr_t res;
igraph_vector_t *vec;
int i;
int j;
VALUE independent_vertex_set;
VALUE object;
VALUE independent_vertex_sets = rb_ary_new();
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_ptr_init(&res,0);
igraph_maximal_independent_vertex_sets(graph, &res);
for(i=0; i<igraph_vector_ptr_size(&res); i++){
independent_vertex_set = rb_ary_new();
rb_ary_push(independent_vertex_sets,independent_vertex_set);
vec = VECTOR(res)[i];
for(j=0; j<igraph_vector_size(vec); j++){
vec = VECTOR(res)[i];
object = cIGraph_get_vertex_object(self,VECTOR(*vec)[j]);
rb_ary_push(independent_vertex_set,object);
}
}
for(i=0;i<igraph_vector_ptr_size(&res);i++){
igraph_vector_destroy(VECTOR(res)[i]);
free(VECTOR(res)[i]);
}
igraph_vector_ptr_destroy(&res);
return independent_vertex_sets;
}
/* call-seq:
* graph.independence_number() -> Integer
*
* Find the independence number of the graph
*
* The independence number of a graph is the cardinality of the largest
* independent vertex set.
*/
VALUE cIGraph_independence_number(VALUE self){
igraph_t *graph;
igraph_integer_t res;
Data_Get_Struct(self, igraph_t, graph);
igraph_independence_number(graph, &res);
return INT2NUM(res);
}

137
ext/cIGraph_isomorphism.c Normal file
View File

@ -0,0 +1,137 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.isomorphic(graph) -> True/False
*
* Decides whether two graphs are isomorphic
*
* From Wikipedia: The graph isomorphism problem or GI problem is the graph
* theory problem of determining whether, given two graphs G1 and G2, it is
* possible to permute (or relabel) the vertices of one graph so that it is
* equal to the other. Such a permutation is called a graph isomorphism.
*/
VALUE cIGraph_isomorphic(VALUE self, VALUE g){
igraph_bool_t res = 0;
igraph_t *graph;
igraph_t *graph2;
Data_Get_Struct(self, igraph_t, graph);
Data_Get_Struct(g, igraph_t, graph2);
igraph_isomorphic(graph,graph2,&res);
return res == 0 ? Qfalse : Qtrue;
}
/* call-seq:
* graph.isomorphic_vf2(graph) -> True/False
*
* Decides whether two graphs are isomorphic
*
* This function is an implementation of the VF2 isomorphism algorithm,
* see P. Foggia, C. Sansone, M. Vento, An Improved algorithm for matching
* large graphs, Prof. of the 3rd IAPR-TC-15 International Workshop on
* Graph-based Representations, Italy, 2001.
*/
VALUE cIGraph_isomorphic_vf2(VALUE self, VALUE g){
igraph_bool_t res = 0;
igraph_t *graph;
igraph_t *graph2;
Data_Get_Struct(self, igraph_t, graph);
Data_Get_Struct(g, igraph_t, graph2);
IGRAPH_CHECK(igraph_isomorphic_vf2(graph,graph2,&res,NULL,NULL));
return res == 0 ? Qfalse : Qtrue;
}
/* call-seq:
* graph.isoclass() -> Integer
*
* Determine the isomorphism class of a graph
*
* All graphs with a given number of vertices belong to a number of
* isomorpism classes, with every graph in a given class being isomorphic
* to each other.
*
* This function gives the isomorphism class (a number) of a graph. Two
* graphs have the same isomorphism class if and only if they are isomorphic.
*
* The first isomorphism class is numbered zero and it is the empty graph,
* the last isomorphism class is the full graph. The number of isomorphism
* class for directed graphs with three vertices is 16 (between 0 and 15),
* for undirected graph it is only 4. For graphs with four vertices it is
* 218 (directed) and 11 (undirected).
*/
VALUE cIGraph_isoclass(VALUE self){
igraph_integer_t res = 0;
igraph_t *graph;
Data_Get_Struct(self, igraph_t, graph);
IGRAPH_CHECK(igraph_isoclass(graph,&res));
return INT2NUM(res);
}
/* call-seq:
* graph.isoclass_subgraph(vs) -> Integer
*
* Determine the isomorphism class of a subgraph given by the vertices given
* in the Array vs.
*
*/
VALUE cIGraph_isoclass_subgraph(VALUE self, VALUE vs){
igraph_integer_t res = 0;
igraph_t *graph;
igraph_vector_t vidv;
Data_Get_Struct(self, igraph_t, graph);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,vs,&vidv);
IGRAPH_CHECK(igraph_isoclass_subgraph(graph,&vidv,&res));
igraph_vector_destroy(&vidv);
return INT2NUM(res);
}
/* call-seq:
* IGraph.isoclass_create(vn,iso,dir) -> IGraph
*
* Creates a graph with the number of vertices given by vn from the given
* isomorphism class iso and the direction boolean dir.
*
* This function is implemented only for graphs with three or four vertices.
*/
VALUE cIGraph_isoclass_create(VALUE self, VALUE vn, VALUE iso, VALUE dir){
igraph_t *graph;
VALUE new_graph;
igraph_bool_t dir_b = 0;
if(dir)
dir_b = 1;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, graph);
IGRAPH_CHECK(igraph_isoclass_create(graph,NUM2INT(vn),NUM2INT(iso),dir_b));
return new_graph;
}

39
ext/cIGraph_kcores.c Normal file
View File

@ -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,INT2NUM(VECTOR(cores)[i]));
}
igraph_vector_destroy(&cores);
return result;
}

292
ext/cIGraph_layout.c Normal file
View File

@ -0,0 +1,292 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.layout_random -> IGraphMatrix
*
* Returns a random layout
*/
VALUE cIGraph_layout_random(VALUE self){
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_random(graph,res);
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
}
/* call-seq:
* graph.layout_circle -> IGraphMatrix
*
* Returns a layout with nodes laid out around a circle.
*/
VALUE cIGraph_layout_circle(VALUE self){
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_circle(graph,res);
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
}
/* call-seq:
* graph.layout_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_fruchterman_reingold(VALUE self,
VALUE niter,
VALUE maxdelta,
VALUE area,
VALUE coolexp,
VALUE repulserad,
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_fruchterman_reingold(graph,res,
NUM2INT(niter),
NUM2DBL(maxdelta),
NUM2DBL(area),
NUM2DBL(coolexp),
NUM2DBL(repulserad),
use_seed == Qtrue ? 1: 0, NULL);
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),0);
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);
}
/* call-seq:
* graph.layout_merge_dla(graphs,layouts) -> IGraphMatrix
*
* Merge multiple layouts by using a DLA algorithm
*
* First each layout is covered by a circle. Then the layout of the largest
* graph is placed at the origin. Then the other layouts are placed by the
* DLA algorithm, larger ones first and smaller ones last.
*
* graphs: Array of IGraph objects
*
* layouts: Array of IGraphMatrix layouts
*/
VALUE cIGraph_layout_merge_dla(VALUE self, VALUE graphs, VALUE layouts){
igraph_vector_ptr_t thegraphs;
igraph_vector_ptr_t coords;
int i;
igraph_t *graph;
igraph_matrix_t *coord;
igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t));
igraph_vector_ptr_init(&thegraphs,0);
igraph_vector_ptr_init(&coords,0);
igraph_matrix_init(res,0,0);
for(i=0;i<RARRAY_LEN(graphs);i++){
Data_Get_Struct(RARRAY_PTR(graphs)[i], igraph_t, graph);
igraph_vector_ptr_push_back(&thegraphs,graph);
}
for(i=0;i<RARRAY_LEN(layouts);i++){
Data_Get_Struct(RARRAY_PTR(layouts)[i], igraph_matrix_t, coord);
igraph_vector_ptr_push_back(&coords,coord);
}
igraph_layout_merge_dla(&thegraphs, &coords, res);
igraph_vector_ptr_destroy(&thegraphs);
igraph_vector_ptr_destroy(&coords);
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
}

119
ext/cIGraph_layout3d.c Normal file
View File

@ -0,0 +1,119 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.layout_random -> IGraphMatrix
*
* Returns a random layout in 3D.
*/
VALUE cIGraph_layout_random_3d(VALUE self){
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_random_3d(graph,res);
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
}
/* call-seq:
* graph.layout_sphere -> IGraphMatrix
*
* Places vertices (more or less) uniformly on a sphere.
*
* The algorithm was described in the following paper: Distributing many
* points on a sphere by E.B. Saff and A.B.J. Kuijlaars, Mathematical
* Intelligencer 19.1 (1997) 5--11.
*/
VALUE cIGraph_layout_sphere(VALUE self){
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_sphere(graph,res);
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
}
/* call-seq:
* graph.layout_fruchterman_reingold_3d(niter,maxdelta,volume,coolexp,repulserad) -> IGraphMatrix
*
* This is the 3D version of the force based Fruchterman-Reingold layout.
*
* niter: The number of iterations to do.
*
* maxdelta: The maximum distance to move a vertex in an iteration.
*
* volume: The volume parameter of the algorithm.
*
* coolexp: The cooling exponent of the simulated annealing.
*
* repulserad: Determines the radius at which vertex-vertex repulsion
* cancels out attraction of adjacent vertices.
*/
VALUE cIGraph_layout_fruchterman_reingold_3d(VALUE self,
VALUE niter,
VALUE maxdelta,
VALUE volume,
VALUE coolexp,
VALUE repulserad){
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_fruchterman_reingold_3d(graph,res,
NUM2INT(niter),
NUM2DBL(maxdelta),
NUM2DBL(volume),
NUM2DBL(coolexp),
NUM2DBL(repulserad),
1, NULL);
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
}
/* call-seq:
* graph.layout_kamada_kawai_3d -> 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_3d(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_3d(graph,res,
NUM2INT(niter),
NUM2DBL(sigma),
NUM2DBL(initemp),
NUM2DBL(coolexp),
NUM2DBL(kkconst),0);
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
}

241
ext/cIGraph_matrix.c Normal file
View File

@ -0,0 +1,241 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
//Classes
VALUE cIGraphMatrix;
void cIGraph_matrix_free(void *p){
igraph_matrix_destroy(p);
}
VALUE cIGraph_matrix_alloc(VALUE klass){
igraph_matrix_t *m = malloc(sizeof(igraph_matrix_t));
VALUE obj;
igraph_matrix_init(m, 0, 0);
obj = Data_Wrap_Struct(klass, 0, cIGraph_matrix_free, m);
return obj;
}
/* Document-method: initialize_copy
*
* Internal method for copying IGraph objects.
*/
VALUE cIGraph_matrix_init_copy(VALUE copy, VALUE orig){
igraph_matrix_t *orig_m;
igraph_matrix_t *copy_m;
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_matrix_t, copy_m);
Data_Get_Struct(orig, igraph_matrix_t, orig_m);
igraph_matrix_copy(copy_m,orig_m);
return copy;
}
/* call-seq:
* IGraphMatrix.new([[x,y,...],...]) -> IGraphMatrix
*
* Creates a new IGraphMatrix object. The argument should be an Array of
* Arrays which each contain the data for a row of the matrix.
*/
VALUE cIGraph_matrix_initialize(int argc, VALUE *argv, VALUE self){
igraph_matrix_t *m;
VALUE rows;
int nrows;
int ncols;
int i;
int j;
rb_scan_args(argc,argv,"0*", &rows);
Data_Get_Struct(self, igraph_matrix_t, m);
nrows = RARRAY_LEN(rows);
ncols = RARRAY_LEN(RARRAY_PTR(rows)[0]);
igraph_matrix_resize(m, nrows, ncols);
//Loop through rows
for (i=0; i<nrows; i++) {
for (j=0; j<ncols; j++){
MATRIX(*m,i,j) = NUM2DBL(RARRAY_PTR(RARRAY_PTR(rows)[i])[j]);
}
}
return self;
}
/* call-seq:
* matrix[i,j] -> Float
*
* Returns the value stored at row i and column j.
*/
VALUE cIGraph_matrix_get(VALUE self, VALUE i, VALUE j){
igraph_matrix_t *m;
Data_Get_Struct(self, igraph_matrix_t, m);
return rb_float_new(MATRIX(*m,NUM2INT(i),NUM2INT(j)));
}
/* call-seq:
* matrix[i,j]= -> Float
*
* Sets the value stored at row i and column j.
*/
VALUE cIGraph_matrix_set(VALUE self, VALUE i, VALUE j, VALUE x){
igraph_matrix_t *m;
Data_Get_Struct(self, igraph_matrix_t, m);
MATRIX(*m,NUM2INT(i),NUM2INT(j)) = NUM2DBL(x);
return x;
}
/* call-seq:
* matrix.each{|v| } -> nil
*
* Iterates through each value in the matrix.
*/
VALUE cIGraph_matrix_each(VALUE self){
igraph_matrix_t *m;
int i;
int j;
Data_Get_Struct(self, igraph_matrix_t, m);
for(i=0;i < m->nrow;i++){
for(j=0;j < m->ncol;j++){
rb_yield(rb_float_new(MATRIX(*m,i,j)));
}
}
return Qnil;
}
/* call-seq:
* matrix.size -> Integer
*
* Returns the number of elements in the matrix.
*/
VALUE cIGraph_matrix_size(VALUE self){
igraph_matrix_t *m;
Data_Get_Struct(self, igraph_matrix_t, m);
return LONG2FIX(igraph_matrix_size(m));
}
/* call-seq:
* matrix.nrow -> Integer
*
* Returns the number of rows in the matrix.
*/
VALUE cIGraph_matrix_nrow(VALUE self){
igraph_matrix_t *m;
Data_Get_Struct(self, igraph_matrix_t, m);
return LONG2FIX(igraph_matrix_nrow(m));
}
/* call-seq:
* matrix.ncol -> Integer
*
* Returns the number of columns in the matrix.
*/
VALUE cIGraph_matrix_ncol(VALUE self){
igraph_matrix_t *m;
Data_Get_Struct(self, igraph_matrix_t, m);
return LONG2FIX(igraph_matrix_ncol(m));
}
/* call-seq:
* matrix.max -> Float
*
* Returns the value of the maximum element in the matrix.
*/
VALUE cIGraph_matrix_max(VALUE self){
igraph_matrix_t *m;
Data_Get_Struct(self, igraph_matrix_t, m);
return rb_float_new(igraph_matrix_max(m));
}
/* call-seq:
* matrix * num -> IGraphMatrix
*
* Multiples two IGraphMatrix objects together
*/
VALUE cIGraph_matrix_scale(VALUE self, VALUE x){
igraph_matrix_t *m;
igraph_matrix_t *n = malloc(sizeof(igraph_matrix_t));
VALUE nobj;
Data_Get_Struct(self, igraph_matrix_t, m);
igraph_matrix_copy(n,m);
igraph_matrix_scale(n, NUM2DBL(x));
nobj = Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, n);
return nobj;
}
/* call-seq:
* matrix.to_a -> Array
*
* Returns the matrix represented as an Array of Arrays.
*/
VALUE cIGraph_matrix_toa(VALUE self){
igraph_matrix_t *m;
int i;
int j;
VALUE a = rb_ary_new();
VALUE row;
Data_Get_Struct(self, igraph_matrix_t, m);
for(i=0;i < m->nrow;i++){
row = rb_ary_new();
for(j=0;j < m->ncol;j++){
rb_ary_push(row,rb_float_new(MATRIX(*m,i,j)));
}
rb_ary_push(a,row);
}
return a;
}

195
ext/cIGraph_min_cuts.c Normal file
View File

@ -0,0 +1,195 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.maxflow_value(source,target,capacity) -> Max Flow
*
* Maximum flow in a network with the push/relabel algorithm
*
* This function implements the Goldberg-Tarjan algorithm for calculating
* value of the maximum flow in a directed or undirected graph. The algorithm
* was given in Andrew V. Goldberg, Robert E. Tarjan: A New Approach to the
* Maximum-Flow Problem, Journal of the ACM, 35(4), 921-940, 1988.
*
* Note that the value of the maximum flow is the same as the minimum cut in
* the graph.
*
*/
VALUE cIGraph_maxflow_value(VALUE self, VALUE source, VALUE target, VALUE capacity){
igraph_t *graph;
igraph_integer_t from_i;
igraph_integer_t to_i;
igraph_real_t value;
int i;
igraph_vector_t capacity_v;
igraph_vector_init(&capacity_v, 0);
for(i=0;i<RARRAY_LEN(capacity);i++){
igraph_vector_push_back(&capacity_v,NUM2DBL(RARRAY_PTR(capacity)[i]));
}
Data_Get_Struct(self, igraph_t, graph);
from_i = cIGraph_get_vertex_id(self,source);
to_i = cIGraph_get_vertex_id(self,target);
igraph_maxflow_value(graph,&value,from_i,to_i,&capacity_v);
igraph_vector_destroy(&capacity_v);
return rb_float_new(value);
}
/* call-seq:
* graph.st_mincut_value(source,target,capacity) -> Max Flow
*
* Maximum flow in a network with the push/relabel algorithm
*
* This function implements the Goldberg-Tarjan algorithm for calculating
* value of the maximum flow in a directed or undirected graph. The algorithm
* was given in Andrew V. Goldberg, Robert E. Tarjan: A New Approach to the
* Maximum-Flow Problem, Journal of the ACM, 35(4), 921-940, 1988.
*
* Note that the value of the maximum flow is the same as the minimum cut in
* the graph.
*
*/
VALUE cIGraph_st_mincut_value(VALUE self, VALUE source, VALUE target, VALUE capacity){
igraph_t *graph;
igraph_integer_t from_i;
igraph_integer_t to_i;
igraph_real_t value;
int i;
igraph_vector_t capacity_v;
igraph_vector_init(&capacity_v, 0);
for(i=0;i<RARRAY_LEN(capacity);i++){
igraph_vector_push_back(&capacity_v,NUM2DBL(RARRAY_PTR(capacity)[i]));
}
Data_Get_Struct(self, igraph_t, graph);
from_i = cIGraph_get_vertex_id(self,source);
to_i = cIGraph_get_vertex_id(self,target);
igraph_st_mincut_value(graph,&value,from_i,to_i,&capacity_v);
igraph_vector_destroy(&capacity_v);
return rb_float_new(value);
}
/* call-seq:
* graph.mincut_value(capacity) -> Float
*
* The minimum edge cut in a graph is the total minimum weight of the edges
* needed to remove from the graph to make the graph not strongly connected.
* (If the original graph is not strongly connected then this is zero.) Note
* that in undirected graphs strong connectedness is the same as weak
* connectedness.
*
*/
VALUE cIGraph_mincut_value(VALUE self, VALUE capacity){
igraph_t *graph;
igraph_real_t value;
int i;
igraph_vector_t capacity_v;
igraph_vector_init(&capacity_v, 0);
for(i=0;i<RARRAY_LEN(capacity);i++){
igraph_vector_push_back(&capacity_v,NUM2DBL(RARRAY_PTR(capacity)[i]));
}
Data_Get_Struct(self, igraph_t, graph);
igraph_mincut_value(graph,&value,&capacity_v);
igraph_vector_destroy(&capacity_v);
return rb_float_new(value);
}
/* call-seq:
* graph.mincut(capacity) -> Array
*
* Calculates the minimum cut in a graph. This function calculates the
* minimum cut in a graph. Right now it is implemented only for undirected
* graphs, in which case it uses the Stoer-Wagner algorithm, as described
* in M. Stoer and F. Wagner: A simple min-cut algorithm, Journal of the
* ACM, 44 585-591, 1997.
*
*/
VALUE cIGraph_mincut(VALUE self, VALUE capacity){
VALUE res_ary;
VALUE p1_a;
VALUE p2_a;
VALUE cut_a;
igraph_t *graph;
igraph_real_t value;
int i;
igraph_vector_t p1;
igraph_vector_t p2;
igraph_vector_t cut;
igraph_vector_t capacity_v;
igraph_vector_init(&p1, 0);
igraph_vector_init(&p2, 0);
igraph_vector_init(&cut, 0);
igraph_vector_init(&capacity_v, 0);
for(i=0;i<RARRAY_LEN(capacity);i++){
igraph_vector_push_back(&capacity_v,NUM2DBL(RARRAY_PTR(capacity)[i]));
}
Data_Get_Struct(self, igraph_t, graph);
igraph_mincut(graph,&value,&p1,&p2,&cut,&capacity_v);
p1_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&p1);i++){
rb_ary_push(p1_a,cIGraph_get_vertex_object(self,VECTOR(p1)[i]));
}
p2_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&p2);i++){
rb_ary_push(p2_a,cIGraph_get_vertex_object(self,VECTOR(p2)[i]));
}
cut_a = rb_ary_new();
for(i=0;i<igraph_vector_size(&cut);i++){
rb_ary_push(cut_a,INT2NUM(VECTOR(cut)[i]));
}
res_ary = rb_ary_new3(4,rb_float_new(value),p1_a,p2_a,cut_a);
igraph_vector_destroy(&p1);
igraph_vector_destroy(&p2);
igraph_vector_destroy(&cut);
igraph_vector_destroy(&capacity_v);
return res_ary;
}

109
ext/cIGraph_motif.c Normal file
View File

@ -0,0 +1,109 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* igraph.motifs_randesu(size,cut)
*
*/
VALUE cIGraph_motifs_randesu(VALUE self, VALUE size, VALUE cuts){
igraph_t *graph;
igraph_vector_t cutsv;
igraph_vector_t res;
int i;
VALUE hist = 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
igraph_vector_init(&cutsv,0);
for(i=0;i<RARRAY_LEN(cuts);i++){
igraph_vector_push_back(&cutsv,NUM2DBL(RARRAY_PTR(cuts)[i]));
}
igraph_motifs_randesu(graph,&res,NUM2INT(size),&cutsv);
for(i=0; i<igraph_vector_size(&res); i++){
rb_ary_push(hist,INT2NUM(VECTOR(res)[i]));
}
igraph_vector_destroy(&cutsv);
igraph_vector_destroy(&res);
return hist;
}
/* call-seq:
* igraph.motifs_randesu_no(size,cut)
*
*/
VALUE cIGraph_motifs_randesu_no(VALUE self, VALUE size, VALUE cuts){
igraph_t *graph;
igraph_vector_t cutsv;
igraph_integer_t res;
int i;
Data_Get_Struct(self, igraph_t, graph);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init(&cutsv,0);
for(i=0;i<RARRAY_LEN(cuts);i++){
igraph_vector_push_back(&cutsv,NUM2DBL(RARRAY_PTR(cuts)[i]));
}
igraph_motifs_randesu_no(graph,&res,NUM2INT(size),&cutsv);
igraph_vector_destroy(&cutsv);
return INT2NUM(res);
}
/* call-seq:
* igraph.motifs_randesu_estimate(size,cut,samplen,samplev)
*
*/
VALUE cIGraph_motifs_randesu_estimate(VALUE self, VALUE size, VALUE cuts,
VALUE samplen, VALUE samplev){
igraph_t *graph;
igraph_vector_t cutsv;
igraph_vector_t vidv;
igraph_integer_t res;
int i;
if(samplev != Qnil){
igraph_vector_init(&vidv,0);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,samplev,&vidv);
}
Data_Get_Struct(self, igraph_t, graph);
igraph_vector_init(&cutsv,0);
for(i=0;i<RARRAY_LEN(cuts);i++){
igraph_vector_push_back(&cutsv,NUM2DBL(RARRAY_PTR(cuts)[i]));
}
if(samplev == Qnil){
igraph_motifs_randesu_estimate(graph,&res,NUM2INT(size),
&cutsv,NUM2INT(samplen),NULL);
} else {
igraph_motifs_randesu_estimate(graph,&res,NUM2INT(size),
&cutsv,NUM2INT(samplen),&vidv);
}
igraph_vector_destroy(&cutsv);
if(samplev != Qnil){
igraph_vector_destroy(&vidv);
}
return INT2NUM(res);
}

9
ext/cIGraph_operators.c Normal file
View File

@ -0,0 +1,9 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
VALUE cIGraph_add_op(VALUE self, VALUE graph){
return Qnil;
}

249
ext/cIGraph_other_ops.c Normal file
View File

@ -0,0 +1,249 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.density(loops) -> Float
*
* Calculate the density of a graph.
*
* The density of a graph is simply the ratio number of edges and the number
* of possible edges. Note that density is ill-defined for graphs with
* multiple and/or loop edges, so consider calling IGraph#simplify() on the
* graph if you know that it contains multiple or loop edges.
*
*/
VALUE cIGraph_density(VALUE self, VALUE loops){
igraph_t *graph;
igraph_bool_t l = 0;
igraph_real_t r;
if(loops == Qtrue)
l = 1;
Data_Get_Struct(self, igraph_t, graph);
igraph_density(graph,&r,l);
return rb_float_new(r);
}
/* call-seq:
* graph.simplify(multiple,loops) -> nil
*
* Removes loop and/or multiple edges from the graph.
* multiple: Logical, if true, multiple edges will be removed. loops: Logical,
* if true, loops (self edges) will be removed.
*
*/
VALUE cIGraph_simplify(VALUE self, VALUE mult, VALUE loops){
igraph_t *graph;
igraph_bool_t l = 0;
igraph_bool_t m = 0;
if(loops == Qtrue)
l = 1;
if(mult == Qtrue)
m = 1;
Data_Get_Struct(self, igraph_t, graph);
igraph_simplify(graph,m,l);
return Qnil;
}
/* call-seq:
* graph.reciprocity(loops) -> Float
*
* Calculates the reciprocity of a directed graph.
*
* A vertex pair (A, B) is said to be reciprocal if there are edges between
* them in both directions. The reciprocity of a directed graph is the
* proportion of all possible (A, B) pairs which are reciprocal, provided
* there is at least one edge between A and B. The reciprocity of an empty
* graph is undefined (results in an error code). Undirected graphs always
* have a reciprocity of 1.0 unless they are empty.
*
*/
VALUE cIGraph_reciprocity(VALUE self, VALUE loops){
igraph_t *graph;
igraph_bool_t l = 0;
igraph_real_t r;
if(loops == Qtrue)
l = 1;
Data_Get_Struct(self, igraph_t, graph);
igraph_reciprocity(graph,&r,l);
return rb_float_new(r);
}
/* call-seq:
* graph.bibcoupling(varray) -> Array
*
* Bibliographic coupling.
*
* The bibliographic coupling of two vertices is the number of other
* vertices they both cite. The
* bibliographic coupling score for each given vertex and all other
* vertices in the graph will be calculated.
*
*/
VALUE cIGraph_bibcoupling(VALUE self, VALUE vs){
igraph_t *graph;
igraph_vs_t vids;
igraph_vector_t vidv;
igraph_matrix_t res;
int i;
int j;
VALUE row;
VALUE path_length;
VALUE matrix = rb_ary_new();
int n_row;
int n_col;
Data_Get_Struct(self, igraph_t, graph);
n_row = NUM2INT(rb_funcall(vs,rb_intern("length"),0));
n_col = igraph_vcount(graph);
//matrix to hold the results of the calculations
igraph_matrix_init(&res,n_row,n_col);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,vs,&vidv);
//create vertex selector from the vecotr of ids
igraph_vs_vector(&vids,&vidv);
igraph_bibcoupling(graph,&res,vids);
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++){
path_length = INT2NUM(MATRIX(res,i,j));
rb_ary_push(row,path_length);
}
}
igraph_vector_destroy(&vidv);
igraph_matrix_destroy(&res);
igraph_vs_destroy(&vids);
return matrix;
}
/* call-seq:
* graph.cocitation(varray) -> Array
*
* Cocitation coupling.
*
* Two vertices are cocited if there is another vertex citing both of them.
* igraph_cocitation() simply counts how many types two vertices are cocited.
* The cocitation score for each given vertex and all other vertices in the
* graph will be calculated.
*
*/
VALUE cIGraph_cocitation(VALUE self, VALUE vs){
igraph_t *graph;
igraph_vs_t vids;
igraph_vector_t vidv;
igraph_matrix_t res;
int i;
int j;
VALUE row;
VALUE path_length;
VALUE matrix = rb_ary_new();
int n_row;
int n_col;
Data_Get_Struct(self, igraph_t, graph);
n_row = NUM2INT(rb_funcall(vs,rb_intern("length"),0));
n_col = igraph_vcount(graph);
//matrix to hold the results of the calculations
igraph_matrix_init(&res,n_row,n_col);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,vs,&vidv);
//create vertex selector from the vecotr of ids
igraph_vs_vector(&vids,&vidv);
igraph_cocitation(graph,&res,vids);
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++){
path_length = INT2NUM(MATRIX(res,i,j));
rb_ary_push(row,path_length);
}
}
igraph_vector_destroy(&vidv);
igraph_matrix_destroy(&res);
igraph_vs_destroy(&vids);
return matrix;
}
/* call-seq:
* graph.get_adjacency(type) -> Array
*
* Returns the adjacency matrix of a graph
*
*/
VALUE cIGraph_get_adjacency(VALUE self, VALUE mode){
igraph_t *graph;
igraph_get_adjacency_t pmode = NUM2INT(mode);
igraph_matrix_t res;
int i;
int j;
VALUE row;
VALUE path_length;
VALUE matrix = rb_ary_new();
int n;
Data_Get_Struct(self, igraph_t, graph);
n = igraph_vcount(graph);
//matrix to hold the results of the calculations
igraph_matrix_init(&res,n,n);
igraph_get_adjacency(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++){
path_length = INT2NUM(MATRIX(res,i,j));
rb_ary_push(row,path_length);
}
}
igraph_matrix_destroy(&res);
return matrix;
}

57
ext/cIGraph_randomisation.c Executable file
View File

@ -0,0 +1,57 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* g.rewire_edges(prob) -> IGraph
*
* Rewire the edges of a graph with constant probability This function
* rewires the edges of a graph with a constant probability. More precisely
* each end point of each edge is rewired to an uniformly randomly chosen
* vertex with constant probability prob.
*
* prob: The rewiring probability a constant between zero and one (inclusive).
*/
VALUE cIGraph_rewire_edges(VALUE self, VALUE prop){
igraph_t *graph;
igraph_t *copy_graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, copy_graph);
Data_Get_Struct(self, igraph_t, graph);
igraph_copy(copy_graph,graph);
igraph_rewire_edges(copy_graph,NUM2DBL(prop));
return new_graph;
}
/* call-seq:
* g.rewire(n) -> IGraph
*
* Randomly rewires a graph while preserving the degree distribution.
*
* This function generates a new graph based on the original one by randomly
* rewiring edges while preserving the original graph's degree distribution.
*
* n: Number of rewiring trials to perform.
*/
VALUE cIGraph_rewire(VALUE self, VALUE n){
igraph_t *graph;
igraph_t *copy_graph;
VALUE new_graph;
new_graph = cIGraph_alloc(cIGraph);
Data_Get_Struct(new_graph, igraph_t, copy_graph);
Data_Get_Struct(self, igraph_t, graph);
igraph_copy(copy_graph,graph);
igraph_rewire(copy_graph,NUM2INT(n),0);
return new_graph;
}

181
ext/cIGraph_selectors.c Normal file
View File

@ -0,0 +1,181 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.vertices -> Array
*
* Returns an Array containing all the vertices in the graph. Also aliased
* to IGraph#all_vertices
*
* Example:
*
* g = IGraph.new([1,2,3,4],true)
* g.vertices #returns [1,2,3,4]
*
*/
VALUE cIGraph_all_v(VALUE self){
igraph_t *graph;
Data_Get_Struct(self, igraph_t, graph);
return ((VALUE*)graph->attr)[0];
}
/* call-seq:
* graph.adjacent_vertices(v,mode) -> Array
*
* Returns an Array containing all the vertices in the graph that are
* adjacent to vertex v. mode decides the type of the neighborhood for
* directed graphs. Possible values: IGRAPH_OUT, all vertices to which
* there is a directed edge from vid. IGRAPH_IN, all vertices from which
* there is a directed edge from vid. IGRAPH_ALL, all vertices to which
* or from which there is a directed edge from/to vid. This parameter is
* ignored for undirected graphs.
*
* Example:
*
* g = IGraph.new([1,2,3,4],true)
* g.adjacent_vertices(1,IGraph::ALL) #returns [2]
*
*/
VALUE cIGraph_adj_v(VALUE self, VALUE v, VALUE mode){
igraph_t *graph;
igraph_integer_t pnode;
VALUE adjacent = rb_ary_new();
igraph_neimode_t pmode = NUM2INT(mode);
igraph_vs_t vs;
igraph_vit_t vit;
Data_Get_Struct(self, igraph_t, graph);
pnode = cIGraph_get_vertex_id(self,v);
igraph_vs_adj(&vs,pnode,pmode);
igraph_vit_create(graph, vs, &vit);
while(!IGRAPH_VIT_END(vit)) {
rb_ary_push(adjacent,cIGraph_get_vertex_object(self,IGRAPH_VIT_GET(vit)));
IGRAPH_VIT_NEXT(vit);
}
igraph_vit_destroy(&vit);
igraph_vs_destroy(&vs);
return adjacent;
}
/* call-seq:
* graph.noadjacent_vertices(v,mode) -> Array
*
* Returns all non-neighboring vertices of a given vertex (v). The mode
* argument controls the type of neighboring vertics not to select. Possible
* values: IGRAPH_OUT, all vertices will be selected except those to which
* there is a directed edge from vid. IGRAPH_IN, all vertices will be
* selected except those from which there is a directed edge to vid.
* IGRAPH_ALL, all vertices will be selected except those from or to which
* there is a directed edge to or from vid.
*/
VALUE cIGraph_nonadj_v(VALUE self, VALUE v, VALUE mode){
igraph_t *graph;
igraph_integer_t pnode;
VALUE nonadjacent = rb_ary_new();
igraph_neimode_t pmode = NUM2INT(mode);
igraph_vs_t vs;
igraph_vit_t vit;
Data_Get_Struct(self, igraph_t, graph);
pnode = cIGraph_get_vertex_id(self,v);
igraph_vs_nonadj(&vs,pnode,pmode);
igraph_vit_create(graph, vs, &vit);
while(!IGRAPH_VIT_END(vit)) {
rb_ary_push(nonadjacent,cIGraph_get_vertex_object(self,IGRAPH_VIT_GET(vit)));
IGRAPH_VIT_NEXT(vit);
}
igraph_vit_destroy(&vit);
igraph_vs_destroy(&vs);
return nonadjacent;
}
/* call-seq:
* graph.edges(mode) -> Array
*
* Returns an Array of all edge ids in the graph. The mode argument specifies
* the order the eids are returned. Possible values: IGRAPH_EDGEORDER_ID,
* edge id order. IGRAPH_EDGEORDER_FROM, vertex id order, the id of the
* source vertex counts for directed graphs. The order of the adjacent edges
* of a given vertex is arbitrary. IGRAPH_EDGEORDER_TO, vertex id order, the
* id of the target vertex counts for directed graphs. The order of the
* adjacent edges of a given vertex is arbitrary. For undirected graph the
* latter two is the same.
*/
VALUE cIGraph_all_e(VALUE self, VALUE mode){
igraph_t *graph;
igraph_es_t es;
igraph_eit_t eit;
igraph_edgeorder_type_t pmode = NUM2INT(mode);
VALUE edge_ids = rb_ary_new();
Data_Get_Struct(self, igraph_t, graph);
igraph_es_all(&es,pmode);
igraph_eit_create(graph, es, &eit);
while(!IGRAPH_EIT_END(eit)) {
rb_ary_push(edge_ids,INT2NUM(IGRAPH_EIT_GET(eit)));
IGRAPH_EIT_NEXT(eit);
}
igraph_eit_destroy(&eit);
igraph_es_destroy(&es);
return edge_ids;
}
/* call-seq:
* graph.adjacent_edges(v,mode) -> Array
*
* Returns an Array of the eids of the adjacent edges of a vertex (v). The
* mode argument gives the type of edges to select. Possible values:
* IGRAPH_OUT, outgoing edges IGRAPH_IN, incoming edges IGRAPH_ALL, all edges
*/
VALUE cIGraph_adj_e(VALUE self, VALUE v, VALUE mode){
igraph_t *graph;
igraph_es_t es;
igraph_eit_t eit;
VALUE adjacent = rb_ary_new();
Data_Get_Struct(self, igraph_t, graph);
igraph_es_none(&es);
igraph_es_adj(&es,cIGraph_get_vertex_id(self,v),NUM2INT(mode));
igraph_eit_create(graph, es, &eit);
while(!IGRAPH_EIT_END(eit)) {
rb_ary_push(adjacent,INT2NUM(IGRAPH_EIT_GET(eit)));
IGRAPH_EIT_NEXT(eit);
}
igraph_eit_destroy(&eit);
igraph_es_destroy(&es);
return adjacent;
}

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;
@ -26,6 +37,7 @@ VALUE cIGraph_shortest_paths(VALUE self, VALUE from, VALUE mode){
igraph_matrix_init(&res,n_row,n_col);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,from,&vidv);
//create vertex selector from the vecotr of ids
igraph_vs_vector(&vids,&vidv);
@ -36,7 +48,7 @@ VALUE cIGraph_shortest_paths(VALUE self, VALUE from, VALUE mode){
row = rb_ary_new();
rb_ary_push(matrix,row);
for(j=0; j<igraph_matrix_ncol(&res); j++){
path_length = MATRIX(res,i,j) == n_col ? Qnil : INT2NUM(MATRIX(res,i,j));
path_length = MATRIX(res,i,j) == IGRAPH_INFINITY ? Qnil : INT2NUM(MATRIX(res,i,j));
rb_ary_push(row,path_length);
}
}
@ -49,6 +61,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 +93,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_LEN(to);
//vector to hold the results of the calculations
igraph_vector_ptr_init(&res,0);
@ -81,6 +104,7 @@ VALUE cIGraph_get_shortest_paths(VALUE self, VALUE from, VALUE to, VALUE mode){
}
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&to_vidv,0);
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);
@ -93,14 +117,15 @@ 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]));
}
}
for(i=0;i<n_paths;i++){
igraph_vector_destroy(VECTOR(res)[i]);
free(VECTOR(res)[i]);
}
igraph_vector_destroy(&to_vidv);
@ -110,3 +135,185 @@ 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_FINALLY(igraph_vector_ptr_destroy,&res);
IGRAPH_CHECK(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
igraph_vector_init_int(&to_vidv,0);
cIGraph_vertex_arr_to_id_vec(self,to,&to_vidv);
//create vertex selector from the vecotr of ids
IGRAPH_CHECK(igraph_vs_vector(&to_vids,&to_vidv));
IGRAPH_CHECK(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]);
free(VECTOR(res)[i]);
}
igraph_vector_ptr_destroy(&res);
igraph_vector_destroy(&to_vidv);
IGRAPH_FINALLY_CLEAN(1);
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;
igraph_integer_t girth = 0;
int i;
VALUE path = rb_ary_new();
Data_Get_Struct(self, igraph_t, graph);
//vector to hold the results of the calculations
IGRAPH_FINALLY(igraph_vector_destroy,&res);
IGRAPH_CHECK(igraph_vector_init(&res,0));
IGRAPH_CHECK(igraph_girth(graph,&girth,&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);
IGRAPH_FINALLY_CLEAN(1);
return path;
}

78
ext/cIGraph_spanning.c Normal file
View File

@ -0,0 +1,78 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.minimum_spanning_tree_unweighted() -> IGraph
*
* Calculates one minimum spanning tree of an unweighted graph.
*
* If the graph has more minimum spanning trees (this is always the case,
* except if it is a forest) this implementation returns only the same one.
*
* Directed graphs are considered as undirected for this computation.
*
* If the graph is not connected then its minimum spanning forest is returned.
* This is the set of the minimum spanning trees of each component.
*/
VALUE cIGraph_minimum_spanning_tree_unweighted(VALUE self){
igraph_t *graph;
igraph_t *n_graph = malloc(sizeof(igraph_t));
VALUE n_graph_obj;
Data_Get_Struct(self, igraph_t, graph);
igraph_minimum_spanning_tree_unweighted(graph,n_graph);
n_graph_obj = Data_Wrap_Struct(cIGraph, cIGraph_mark, cIGraph_free, n_graph);
return n_graph_obj;
}
/* call-seq:
* graph.minimum_spanning_tree_prim(weights) -> IGraph
*
* Calculates one minimum spanning tree of a weighted graph.
*
* This function uses Prim's method for carrying out the computation, see
* Prim, R.C.: Shortest connection networks and some generalizations, Bell
* System Technical Journal, Vol. 36, 1957, 1389--1401.
*
* If the graph has more than one minimum spanning tree, the current
* implementation returns always the same one.
*
* Directed graphs are considered as undirected for this computation.
*
* If the graph is not connected then its minimum spanning forest is returned.
* This is the set of the minimum spanning trees of each component.
*
* The weights Array must contain the weights of the the edges. in the same
* order as the simple edge iterator visits them.
*/
VALUE cIGraph_minimum_spanning_tree_prim(VALUE self, VALUE weights){
igraph_t *graph;
igraph_t *n_graph = malloc(sizeof(igraph_t));
VALUE n_graph_obj;
igraph_vector_t weights_vec;
int i;
igraph_vector_init(&weights_vec,RARRAY_LEN(weights));
Data_Get_Struct(self, igraph_t, graph);
for(i=0;i<RARRAY_LEN(weights);i++){
VECTOR(weights_vec)[i] = NUM2DBL(RARRAY_PTR(weights)[i]);
}
igraph_minimum_spanning_tree_prim(graph,n_graph,&weights_vec);
n_graph_obj = Data_Wrap_Struct(cIGraph, cIGraph_mark, cIGraph_free, n_graph);
igraph_vector_destroy(&weights_vec);
return n_graph_obj;
}

57
ext/cIGraph_spectral.c Normal file
View File

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

View File

@ -0,0 +1,43 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.topological_sorting(mode) -> Array
*
* Calculate a possible topological sorting of the graph. A topological
* sorting of a directed acyclic graph is a linear ordering of its nodes
* where each node comes before all nodes to which it has edges. Every DAG
* has at least one topological sort, and may have many. This function
* returns a possible topological sort among them. If the graph is not
* acyclic (it has at least one cycle), a partial topological sort is
* returned and a warning is issued. mode specifies how to use the direction
* of the edges. For IGRAPH_OUT, the sorting order ensures that each node
* comes before all nodes to which it has edges, so nodes with no incoming
* edges go first. For IGRAPH_IN, it is quite the opposite: each node comes
* before all nodes from which it receives edges. Nodes with no outgoing
* edges go first.
*/
VALUE cIGraph_topological_sorting(VALUE self, VALUE mode){
igraph_t *graph;
igraph_vector_t res;
igraph_neimode_t pmode = NUM2INT(mode);
VALUE result = rb_ary_new();
int i;
igraph_vector_init_int(&res,0);
Data_Get_Struct(self, igraph_t, graph);
igraph_topological_sorting(graph, &res, pmode);
for(i=0;i<igraph_vector_size(&res);i++){
rb_ary_push(result,cIGraph_get_vertex_object(self,VECTOR(res)[i]));
}
igraph_vector_destroy(&res);
return result;
}

View File

@ -0,0 +1,97 @@
#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.transitivity() -> Float
*
* Calculates the transitivity (clustering coefficient) of a graph.
*
* The transitivity measures the probability that two neighbors of a vertex
* are connected. More precisely this is the ratio of the triangles and
* connected triples in the graph, the result is a single real number or
* NaN (0/0) if there are no connected triples in the graph. Directed graphs
* are considered as undirected ones.
*/
VALUE cIGraph_transitivity(VALUE self){
igraph_t *graph;
igraph_real_t res;
Data_Get_Struct(self, igraph_t, graph);
igraph_transitivity_undirected(graph,&res);
return rb_float_new(res);
}
/* call-seq:
* graph.transitivity() -> Float
*
* Calculates the transitivity (clustering coefficient) of a graph.
*
* The transitivity measures the probability that two neighbors of a vertex
* are connected. More precisely this is the ratio of the triangles and
* connected triples in the graph, the result is a single real number or
* NaN (0/0) if there are no connected triples in the graph. Directed graphs
* are considered as undirected ones.
*/
VALUE cIGraph_transitivity_local(VALUE self, VALUE vs){
igraph_t *graph;
igraph_vs_t vids;
igraph_vector_t vidv;
igraph_vector_t res;
VALUE trans = rb_ary_new();
int i;
//vector to hold the results of the calculations
igraph_vector_init_int(&res,0);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,vs,&vidv);
//create vertex selector from the vecotr of ids
igraph_vs_vector(&vids,&vidv);
Data_Get_Struct(self, igraph_t, graph);
igraph_transitivity_local_undirected(graph,&res,vids);
for(i=0;i<igraph_vector_size(&res);i++){
rb_ary_push(trans,rb_float_new(VECTOR(res)[i]));
}
igraph_vector_destroy(&vidv);
igraph_vector_destroy(&res);
igraph_vs_destroy(&vids);
return trans;
}
/* call-seq:
* graph.transitivity_avglocal() -> Float
*
* Calculates the transitivity (clustering coefficient) of a graph.
*
* The transitivity measures the probability that two neighbors of a vertex
* are connected. More precisely this is the ratio of the triangles and
* connected triples in the graph, the result is a single real number or
* NaN (0/0) if there are no connected triples in the graph. Directed graphs
* are considered as undirected ones.
*/
VALUE cIGraph_transitivity_avglocal(VALUE self){
igraph_t *graph;
igraph_real_t res;
Data_Get_Struct(self, igraph_t, graph);
igraph_transitivity_avglocal_undirected(graph,&res);
return rb_float_new(res);
}

View File

@ -4,12 +4,19 @@
igraph_integer_t cIGraph_get_vertex_id(VALUE graph, VALUE v){
VALUE vertex_h;
VALUE v_ary;
VALUE idx;
igraph_t *igraph;
vertex_h = rb_iv_get(graph,"@object_ids");
Data_Get_Struct(graph, igraph_t, igraph);
v_ary = ((VALUE*)igraph->attr)[0];
if(rb_funcall(vertex_h,rb_intern("has_key?"),1,v))
return NUM2INT(rb_hash_aref(vertex_h,v));
idx = rb_funcall(v_ary,rb_intern("index"),1,v);
if(idx != Qnil)
return NUM2INT(idx);
rb_raise(cIGraphError, "Unable to find vertex\n");
return -1;
@ -17,14 +24,16 @@ igraph_integer_t cIGraph_get_vertex_id(VALUE graph, VALUE v){
VALUE cIGraph_get_vertex_object(VALUE graph, igraph_integer_t n){
VALUE vertex_h;
VALUE v_ary;
VALUE obj;
igraph_t *igraph;
vertex_h = rb_iv_get(graph,"@id_objects");
Data_Get_Struct(graph, igraph_t, igraph);
v_ary = ((VALUE*)igraph->attr)[0];
if(rb_funcall(vertex_h,rb_intern("has_key?"),1,INT2NUM(n)))
return rb_hash_aref(vertex_h,INT2NUM(n));
obj = rb_ary_entry(v_ary,n);
return Qnil;
return obj;
}
@ -32,6 +41,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);
@ -39,11 +49,10 @@ int cIGraph_vertex_arr_to_id_vec(VALUE graph, VALUE va, igraph_vector_t *nv){
rb_raise(cIGraphError, "Array expected\n");
//Initialize edge vector
igraph_vector_init_int(nv,0);
vertex = rb_ary_shift(va);
while(vertex != Qnil){
//igraph_vector_init_int(nv,0);
for (i=0; i<RARRAY_LEN(va); i++) {
vertex = RARRAY_PTR(va)[i];
igraph_vector_push_back(nv,cIGraph_get_vertex_id(graph, vertex));
vertex = rb_ary_shift(va);
}
return 0;
@ -51,6 +60,12 @@ int cIGraph_vertex_arr_to_id_vec(VALUE graph, VALUE va, igraph_vector_t *nv){
}
VALUE cIGraph_include(VALUE self, VALUE v){
VALUE vertex_h = rb_iv_get(self,"@object_ids");
return rb_funcall(vertex_h,rb_intern("has_key?"),1,v);
VALUE v_ary;
igraph_t *igraph;
Data_Get_Struct(self, igraph_t, igraph);
v_ary = ((VALUE*)igraph->attr)[0];
return rb_ary_includes(v_ary,v);
}

View File

@ -0,0 +1,167 @@
#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
igraph_vector_init_int(&vidv,0);
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_FINALLY(igraph_vector_ptr_destroy,&res);
IGRAPH_CHECK(igraph_vector_ptr_init(&res,0));
//Convert an array of vertices to a vector of vertex ids
IGRAPH_FINALLY(igraph_vector_destroy,&vidv);
igraph_vector_init_int(&vidv,0);
cIGraph_vertex_arr_to_id_vec(self,from,&vidv);
//create vertex selector from the vecotr of ids
IGRAPH_FINALLY(igraph_vs_destroy,&vids);
IGRAPH_CHECK(igraph_vs_vector(&vids,&vidv));
IGRAPH_CHECK(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]);
free(VECTOR(res)[i]);
}
igraph_vector_destroy(&vidv);
igraph_vector_ptr_destroy(&res);
igraph_vs_destroy(&vids);
IGRAPH_FINALLY_CLEAN(3);
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_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);
igraph_vector_ptr_init(&res,0);
//Convert an array of vertices to a vector of vertex ids
igraph_vector_init_int(&vidv,0);
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++){
n_graph = VECTOR(res)[i];
n_graph_obj = Data_Wrap_Struct(cIGraph, cIGraph_mark, cIGraph_free, n_graph);
rb_ary_push(result,n_graph_obj);
}
igraph_vector_destroy(&vidv);
igraph_vector_ptr_destroy(&res);
igraph_vs_destroy(&vids);
return result;
}

34
igraph.gemspec Normal file
View File

@ -0,0 +1,34 @@
(in /home/ag357/Projects/igraph)
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{igraph}
s.version = "0.9.7"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Alex Gutteridge"]
s.date = %q{2009-02-11}
s.description = %q{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.}
s.email = %q{ag357@cam.ac.uk}
s.extensions = ["ext/extconf.rb"]
s.extra_rdoc_files = ["README.txt", "History.txt", "License.txt"]
s.files = ["History.txt", "License.txt", "Manifest.txt", "README.txt", "Rakefile.rb", "ext/cIGraph.c", "ext/cIGraph.h", "ext/cIGraph_add_delete.c", "ext/cIGraph_attribute_handler.c", "ext/cIGraph_basic_properties.c", "ext/cIGraph_basic_query.c", "ext/cIGraph_centrality.c", "ext/cIGraph_cliques.c", "ext/cIGraph_community.c", "ext/cIGraph_components.c", "ext/cIGraph_connectivity.c", "ext/cIGraph_dijkstra.c", "ext/cIGraph_direction.c", "ext/cIGraph_error_handlers.c", "ext/cIGraph_file.c", "ext/cIGraph_generators_deterministic.c", "ext/cIGraph_generators_random.c", "ext/cIGraph_independent_vertex_sets.c", "ext/cIGraph_isomorphism.c", "ext/cIGraph_iterators.c", "ext/cIGraph_kcores.c", "ext/cIGraph_layout.c", "ext/cIGraph_layout3d.c", "ext/cIGraph_matrix.c", "ext/cIGraph_min_cuts.c", "ext/cIGraph_motif.c", "ext/cIGraph_operators.c", "ext/cIGraph_other_ops.c", "ext/cIGraph_randomisation.c", "ext/cIGraph_selectors.c", "ext/cIGraph_shortest_paths.c", "ext/cIGraph_spanning.c", "ext/cIGraph_spectral.c", "ext/cIGraph_topological_sort.c", "ext/cIGraph_transitivity.c", "ext/cIGraph_utility.c", "ext/cIGraph_vertex_neighbourhood.c", "ext/extconf.rb", "test/tc_add_delete.rb", "test/tc_adj_to_distance.rb", "test/tc_attributes.rb", "test/tc_basic_properties.rb", "test/tc_basic_query.rb", "test/tc_centrality.rb", "test/tc_cliques.rb", "test/tc_community.rb", "test/tc_components.rb", "test/tc_connectivity.rb", "test/tc_copy.rb", "test/tc_cores.rb", "test/tc_create.rb", "test/tc_dijkstra.rb", "test/tc_directedness.rb", "test/tc_error_handling.rb", "test/tc_file_read_write.rb", "test/tc_generators_deterministic.rb", "test/tc_generators_random.rb", "test/tc_independent_vertex_sets.rb", "test/tc_isomorphic.rb", "test/tc_iterators.rb", "test/tc_layout.rb", "test/tc_layout3d.rb", "test/tc_matrix.rb", "test/tc_mincuts.rb", "test/tc_motif.rb", "test/tc_other_ops.rb", "test/tc_randomisation.rb", "test/tc_selectors.rb", "test/tc_shortest_paths.rb", "test/tc_spanning.rb", "test/tc_spectral.rb", "test/tc_thrash.rb", "test/tc_topological_sort.rb", "test/tc_transitivity.rb", "test/tc_vertex_neighbourhood.rb", "test/test_all.rb"]
s.has_rdoc = true
s.homepage = %q{http://igraph.rubyforge.org/}
s.rdoc_options = ["--exclude", "test/*", "--main", "README.txt", "--inline-source"]
s.require_paths = ["test"]
s.rubyforge_project = %q{igraph}
s.rubygems_version = %q{1.3.1}
s.summary = %q{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.}
s.test_files = ["test/test_all.rb"]
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 2
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
else
end
else
end
end

1027
manual.tex

File diff suppressed because it is too large Load Diff

1585
setup.rb

File diff suppressed because it is too large Load Diff

View File

@ -1,62 +0,0 @@
require 'igraph'
require 'kgml'
require 'benchmark'
xmlfiles = Dir.glob(ARGV[0])
pathway =
DirectedBipartiteMetabolicPathway.new(File.open(xmlfiles.shift).read)
pathway = xmlfiles.inject(pathway){|p,file|
p + DirectedBipartiteMetabolicPathway.new(File.open(file).read)
}
igraph = IGraph.new([],0,true);
pathway.reactions.each do |reaction|
reaction_name = reaction.name.gsub(/rn:/,'')
unless igraph.include?(reaction_name)
igraph.add_vertices([reaction_name])
end
reaction.substrates.each do |s_name|
s_name.gsub!(/cpd:/,'')
unless igraph.include?(s_name)
igraph.add_vertices([s_name])
end
igraph.add_edges([s_name,reaction_name])
if reaction.type == 'reversible'
igraph.add_edges([reaction_name,s_name])
end
end
reaction.products.each do |p_name|
p_name.gsub!(/cpd:/,'')
unless igraph.include?(p_name)
igraph.add_vertices([p_name])
end
igraph.add_edges([reaction_name,p_name])
if reaction.type == 'reversible'
igraph.add_edges([p_name,reaction_name])
end
end
end
include Benchmark
graph = pathway.graph
bm(6) do |x|
x.report("igraph"){
100.times{
igraph.get_shortest_paths("R02740",["C00074"])
}
}
x.report("hashgraph"){
100.times{
h = {}
graph.dijkstra_shortest_paths({
:root => "R02740",
:target => "C00074",
:predecessor => h
})
graph.route("C00074",h)
}
}
end

View File

@ -2,7 +2,7 @@ require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_add_edges
def test_add_edges
graph = IGraph.new(['A','B','C','D'],true)
graph.add_edges(['A','C'])
assert_equal [2], graph.degree(['A'],IGraph::ALL,true)
@ -46,4 +46,62 @@ 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_large
vs = (0..99).to_a
h = IGraph.new([],true)
vs.each do |id|
h.add_vertex(id)
end
g = h.dup
delete_ids = (0..99).to_a.sort_by{rand}[0..19]
assert_nothing_raised do
delete_ids.each do |id|
g.delete_vertex(id)
end
end
delete_ids.each do |id|
assert_equal false, g.include?(id)
end
assert_equal 80, g.vcount
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

View File

@ -0,0 +1,24 @@
require 'igraph'
g = IGraph.new(['A','B','A','C','A','D','C','D'],false)
adj = g.get_adjacency(2)
g.vcount.times do |k|
adj[k][k] = 1
end
dis = Array.new(4){|i| Array.new(4)}
dis.each_with_index do |row,i|
row.each_with_index do |cell,j|
cij = 0
g.vcount.times do |k|
puts "#{i} #{j} #{k}"
cij += adj[i][k] * adj[j][k]
end
dis[i][j] = 10 - cij
end
end
p adj
p dis

29
test/tc_attributes.rb Normal file
View File

@ -0,0 +1,29 @@
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
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

View File

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

View File

@ -2,7 +2,7 @@ require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_graph_size
def test_graph_size
assert_equal 4, IGraph.new([1,2,3,4],true).vcount
assert_equal 2, IGraph.new([1,2,3,4],true).ecount
end

33
test/tc_centrality.rb Normal file
View File

@ -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 48, (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

21
test/tc_cliques.rb Normal file
View File

@ -0,0 +1,21 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_cliques
g = IGraph.new([1,2,3,4],false)
assert_equal [[1,2],[3,4]], g.cliques(2,0)
end
def test_largest_cliques
g = IGraph.new(['A','B','C','D','A','E','B','E'],false)
assert_equal [['A','B','E']], g.largest_cliques()
end
def test_maximal_cliques
g = IGraph.new(['A','B','C','D','A','E','B','E'],false)
assert_equal [['A','B','E'],['C','D']], g.maximal_cliques()
end
def test_clique_number
g = IGraph.new(['A','B','C','D','A','E','B','E'],false)
assert_equal 3, g.clique_number
end
end

72
test/tc_community.rb Normal file
View File

@ -0,0 +1,72 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_modularity
g = IGraph.new(['A','B','B','C','A','C','C','D','D','E','E','F','D','F'])
assert_in_delta 0.357, g.modularity([['A','B','C'],['D','E','F']]), 0.001
end
def test_spinglass
g = IGraph.new(['A','B','B','C','A','C','C','D','D','E','E','F','D','F'])
groups,mod,temp = g.community_spinglass([],25,false,1,0.01,0.99,IGraph::SPINCOMM_UPDATE_SIMPLE,1.0)
assert_in_delta 0.25, mod, 0.15
assert_in_delta 0.200, temp, 0.100
assert_equal [['A','B','C','D','E','F']], groups
commun,coh,adh = g.community_spinglass_single([],'A',25,IGraph::SPINCOMM_UPDATE_SIMPLE,1.0)
assert_in_delta 1.25, coh, 0.001
assert_in_delta(-2.5, adh, 0.100)
assert_equal ['A','B','C'], commun
end
def test_eigen
g = IGraph.new(['A','B','B','C','A','C','C','D','D','E','E','F','D','F'],false)
groups,merges = g.community_leading_eigenvector(6)
assert_equal [['A','B','C'],['D','E','F']], groups
assert_equal [[0,1]], merges.to_a
groups,merges = g.community_leading_eigenvector_naive(6)
assert_equal [['A','B','C'],['D','E','F']], groups
assert_equal [[0,1]], merges.to_a
groups,split,eigenvec,eigenval =
g.community_leading_eigenvector_step([['A','B','C','D','E','F']],0)
assert_equal [['A','B','C'],['D','E','F']], groups
assert split
assert_in_delta 0.433, eigenvec[0], 0.02
assert_in_delta 1.730, eigenval, 0.02
end
def test_random_walk
g = IGraph.new(['A','B','B','C','A','C','C','D','D','E','E','F','D','F'],false)
merges,modularity = g.community_walktrap([],10)
groups = g.community_to_membership(merges,4,6)
assert_equal [['A','B','C'],['D','E','F']], groups.sort
assert_in_delta 0.19, modularity[3], 0.1
end
def test_comm_edge_betweenness
g = IGraph.new(['A','B','B','C','A','C','C','D','D','E','E','F','D','F'],false)
merges,result,edge_betw,bridges = g.community_edge_betweenness(false)
groups = g.community_to_membership(merges,4,6)
assert_equal [['A','B','C'],['D','E','F']], groups.sort
assert_equal 3, result[0]
assert_equal 9, edge_betw[0]
assert_equal 7, bridges[0]
merges,bridges = g.community_eb_get_merges(result)
groups = g.community_to_membership(merges,4,6)
assert_equal [['A','B','C'],['D','E','F']], groups.sort
assert_equal 7, bridges[0]
end
def test_fastgreedy
g = IGraph.new(['A','B','B','C','A','C','C','D','D','E','E','F','D','F'],false)
merges,mod = g.community_fastgreedy
groups = g.community_to_membership(merges,4,6)
assert_equal [['A','B','C'],['D','E','F']], groups.sort
assert_in_delta 0.19, mod[3], 0.1
end
end

25
test/tc_components.rb Normal file
View File

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

22
test/tc_connectivity.rb Normal file
View File

@ -0,0 +1,22 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_connecitivity
g = IGraph.new(['A','B','B','C','C','D'],true)
assert_equal 1, g.st_edge_connectivity('A','B')
assert_equal 0, g.edge_connectivity
assert_equal 1, g.st_vertex_connectivity('A','C',IGraph::VCONN_NEI_ERROR)
assert_equal 0, g.vertex_connectivity
end
def test_disjoint
g = IGraph.new(['A','B','B','C','C','D','A','E','E','D'],true)
assert_equal 2, g.edge_disjoint_paths('A','D')
assert_equal 2, g.vertex_disjoint_paths('A','D')
end
def test_adhesion
g = IGraph.new(['A','B','B','C','C','D'],true)
assert_equal 0, g.adhesion
assert_equal 0, g.cohesion
end
end

13
test/tc_copy.rb Normal file
View File

@ -0,0 +1,13 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_copy
g = IGraph.new(['A','B','C','D'],true,[1,2]);
h = g.dup
assert g.vcount == h.vcount
assert g['A','B'] == h['A','B']
h['A','B'] = g['A','B'] + 1
assert g['A','B'] != h['A','B']
end
end

10
test/tc_cores.rb Normal file
View File

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

11
test/tc_dijkstra.rb Normal file
View File

@ -0,0 +1,11 @@
require 'test/unit'
require 'igraph'
Infinity = 1.0/0
class TestGraph < Test::Unit::TestCase
def test_dijkstra
g = IGraph.new([1,2,3,4],false)
assert_equal [[0,1.5,Infinity,Infinity]], g.dijkstra_shortest_paths([1],[1.5,2.5],IGraph::OUT)
end
end

31
test/tc_directedness.rb Normal file
View File

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

436
test/tc_file_read_write.rb Normal file
View File

@ -0,0 +1,436 @@
require 'test/unit'
require 'igraph'
require 'stringio'
require 'rbconfig'
include Config
class TestGraph < Test::Unit::TestCase
def test_edgelist_read
g = nil
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
IGraph::FileRead.read_graph_edgelist(StringIO.new("0 1 2 3"),true)
}
return
end
assert_nothing_raised{
g = IGraph::FileRead.read_graph_edgelist(StringIO.new("0 1 2 3"),true)
}
assert_instance_of IGraph, g
assert_equal 4, g.vcount
assert g.are_connected?(0,1)
end
def test_edgelist_write
g = IGraph.new([0,1,2,3])
s = StringIO.new("")
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
g.write_graph_edgelist(s)
}
return
end
str = g.write_graph_edgelist(s)
s.rewind
assert_equal "0 1\n2 3\n", s.read
end
def test_ncol_read
g = nil
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
IGraph::FileRead.read_graph_ncol(StringIO.new("0 1\n2 3\n"),[],
false,false,false)
}
return
end
assert_nothing_raised{
g = IGraph::FileRead.read_graph_ncol(StringIO.new("0 1\n2 3\n"),[],
false,false,false)
}
assert_instance_of IGraph, g
assert_equal 4, g.vcount
assert g.are_connected?(0,1)
assert_nothing_raised{
g = IGraph::FileRead.read_graph_ncol(StringIO.new("A B\nC D\n"),[],
true,false,false)
}
assert_instance_of IGraph, g
assert_equal 4, g.vcount
assert g.are_connected?('A','B')
assert_nothing_raised{
g = IGraph::FileRead.read_graph_ncol(StringIO.new("A B 1\nC D 2\n"),[],
true,true,false)
}
assert_instance_of IGraph, g
assert_equal 4, g.vcount
assert g.are_connected?('A','B')
assert_equal 1, g['A','B']
end
def test_ncol_write
g = IGraph.new(["A","B","C","D"],true,[1,2])
s = StringIO.new("")
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
g.write_graph_ncol(s,true,true)
}
return
end
str = g.write_graph_ncol(s,true,true)
s.rewind
assert_equal "A B 1.0\nC D 2.0\n", s.read
end
def test_lgl_read
g = nil
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
IGraph::FileRead.read_graph_lgl(StringIO.new("#A\nB\n#C\nD\n"))
}
return
end
assert_nothing_raised{
g = IGraph::FileRead.read_graph_lgl(StringIO.new("#A\nB\n#C\nD\n"),
false,false)
}
assert_instance_of IGraph, g
assert_equal 4, g.vcount
assert g.are_connected?(0,1)
assert_nothing_raised{
g = IGraph::FileRead.read_graph_lgl(StringIO.new("#A\nB 1\n#C\nD 1\n"),
true,true)
}
assert_instance_of IGraph, g
assert_equal 4, g.vcount
assert g.are_connected?('A','B')
assert_equal 1, g['A','B']
end
def test_lgl_write
g = IGraph.new(["A","B","C","D"],true,[1,2])
s = StringIO.new("")
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
g.write_graph_lgl(s,true,true,false)
}
return
end
str = g.write_graph_lgl(s,true,true,false)
s.rewind
assert_equal "# A\nB 1.0\n# C\nD 2.0\n", s.read
end
def test_dimacs_read
s = StringIO.new("c com\np max 4 2\nn 1 s\nn 2 t\na 1 2 1\na 3 4 2\n")
g = nil
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
IGraph::FileRead.read_graph_dimacs(s,false)
}
return
end
assert_nothing_raised{
g = IGraph::FileRead.read_graph_dimacs(s,
false)
}
assert_instance_of IGraph, g
assert_equal 4, g.vcount
assert g.are_connected?(0,1)
assert_equal 0, g.attributes['source']
assert_equal 1, g.attributes['target']
assert_equal [1,2], g.attributes['capacity']
end
def test_dimacs_write
g = IGraph.new(["A","B","C","D"],true,[1,2])
s = StringIO.new("")
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
g.write_graph_dimacs(s,0,1,[1,2])
}
return
end
str = g.write_graph_dimacs(s,0,1,[1,2])
s.rewind
assert_equal "c created by igraph\np max 4 2\nn 1 s\nn 2 t\na 1 2 1\na 3 4 2\n", s.read
end
def test_graphml_read
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
IGraph::FileRead.read_graph_graphml(StringIO.new(Graphml),0)
}
return
end
g = nil
err = StringIO.open('','w')
$stderr = err
g = IGraph::FileRead.read_graph_graphml(StringIO.new(Graphml),0)
assert_equal "warning: unknown attribute key in GraphML file, ignoring attribute\n", err.string.sub(/.*?:\d+: /,'')
$stderr = STDERR
assert_instance_of IGraph, g
assert_equal '2006-11-12', g.attributes['date']
h = g.dup
assert_equal g.to_a,h.to_a
assert_equal g.attributes['date'], h.attributes['date']
end
def test_graphml_write
g = IGraph.new([{'id'=>0,'name'=>'a','type' => 4.0},
{'id'=>1,'name'=>'b','type' => 5},
{'id'=>2,'type' => 6},
{'id'=>3,'name'=>'d'}],
true,
[{'eid'=>'e1'},
{'eid'=>'e2'}])
g.attributes['date'] = 'Friday'
s = StringIO.new("")
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
g.write_graph_graphml(s)
}
return
end
str = g.write_graph_graphml(s)
s.rewind
#assert_equal Graphml_out, s.read
end
def test_gml_read
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
IGraph::FileRead.read_graph_gml(StringIO.new(Gml))
}
return
end
g = IGraph::FileRead.read_graph_gml(StringIO.new(Gml))
assert_instance_of IGraph, g
end
def test_gml_write
g = IGraph.new([{'id'=>0,'name'=>'a','type' => 4.0},
{'id'=>1,'name'=>'b','type' => 5},
{'id'=>2,'type' => 6},
{'id'=>3,'name'=>'d'}],
true,
[{'eid'=>'e1'},
{'eid'=>'e2'}])
g.attributes['date'] = 'Friday'
s = StringIO.new("")
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
g.write_graph_gml(s)
}
return
end
str = g.write_graph_gml(s)
s.rewind
s = s.read
s = s.split(/\n/)[1..-1].join("\n")
#assert_equal Gml_out, s
end
def test_pajek_read_write
if CONFIG['host'] =~ /apple/
assert_raises(NoMethodError){
IGraph::FileRead.read_graph_pajek(StringIO.new(Pajek),0)
}
return
end
g = nil
g = IGraph::FileRead.read_graph_pajek(StringIO.new(Pajek),0)
assert_instance_of IGraph, g
assert_equal 4, g.vcount
assert_equal 1, g[4,1]['weight']
h = g.dup
s = StringIO.new('')
h.write_graph_pajek(s)
s.rewind
str = s.read
str.gsub!(/\r/,'')
#assert_equal Pajek, str
end
Graphml = %q{<?xml version="1.0" encoding="UTF-8"?>
<!-- This file was written by the JAVA GraphML Library.-->
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3
.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdr
awing.org/xmlns/1.0/graphml.xsd">
<key id="d0" for="node" attr.name="color" attr.type="string">yellow</key>
<key id="d1" for="edge" attr.name="weight" attr.type="double"/>
<key id="d2" for="graph" attr.name="date" attr.type="string"></key>
<graph id="G" edgedefault="undirected">
<data key="d2">2006-11-12</data>
<node id="n0">
<data key="d0">green</data>
<data key="d3">incorrect</data>
<!-- incorrect attribute key, should issue a warning -->
</node>
<node id="n1"/>
<node id="n2">
<data key="d0">blue</data>
</node>
<node id="n3">
<data key="d0">red</data>
</node>
<node id="n4"/>
<node id="n5">
<data key="d0">turquoise</data>
</node>
<edge id="e0" source="n0" target="n2">
<data key="d1">1.0</data>
</edge>
<edge id="e1" source="n0" target="n1">
<data key="d1">1.0</data>
</edge>
<edge id="e2" source="n1" target="n3">
<data key="d1">2.0</data>
</edge>
<edge id="e3" source="n3" target="n2"/>
<edge id="e4" source="n2" target="n4"/>
<edge id="e5" source="n3" target="n5"/>
<edge id="e6" source="n5" target="n4">
<data key="d1">1.1</data>
</edge>
</graph>
</graphml>
}
Graphml_out = %q{<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<!-- Created by igraph -->
<key id="date" for="graph" attr.name="date" attr.type="string"/>
<key id="name" for="node" attr.name="name" attr.type="string"/>
<key id="type" for="node" attr.name="type" attr.type="double"/>
<key id="id" for="node" attr.name="id" attr.type="double"/>
<key id="eid" for="edge" attr.name="eid" attr.type="string"/>
<graph id="G" edgedefault="directed">
<data key="date">Friday</data>
<node id="n0">
<data key="name">a</data>
<data key="type">4</data>
<data key="id">0</data>
</node>
<node id="n1">
<data key="name">b</data>
<data key="type">5</data>
<data key="id">1</data>
</node>
<node id="n2">
<data key="name"></data>
<data key="type">6</data>
<data key="id">2</data>
</node>
<node id="n3">
<data key="name">d</data>
<data key="id">3</data>
</node>
<edge source="n0" target="n1">
<data key="eid">e1</data>
</edge>
<edge source="n2" target="n3">
<data key="eid">e2</data>
</edge>
</graph>
</graphml>
}
Pajek = %q{*Vertices 4
*Edges
4 1 1
1 2 4
1 3 2
2 3 2
}
Gml = %q{graph [
comment "This is a sample graph"
directed 1
id 42
label "Hello, I am a graph"
node [
id 1
label "Node 1"
thisIsASampleAttribute 42
]
node [
id 2
label "node 2"
thisIsASampleAttribute 43
]
node [
id 3
label "node 3"
thisIsASampleAttribute 44
]
edge [
source 1
target 2
label "Edge from node 1 to node 2"
]
edge [
source 2
target 3
label "Edge from node 2 to node 3"
]
edge [
source 3
target 1
label "Edge from node 3 to node 1"
]
]
}
Gml_out = %q{Version 1
graph
[
directed 0
date "Friday"
node
[
id 0
name "a"
type 4
]
node
[
id 1
name "b"
type 5
]
node
[
id 2
name ""
type 6
]
node
[
id 3
name "d"
type nan
]
edge
[
source 0
target 1
eid "e1"
]
edge
[
source 2
target 3
eid "e2"
]
]}
end

View File

@ -0,0 +1,61 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_adjacency
m = IGraphMatrix.new([0,1,1,0],[1,0,0,0],[1,0,0,1],[0,0,1,0])
g = IGraph::Generate.adjacency(m,IGraph::ADJ_MAX)
assert_equal 4, g.vcount
assert_equal 3, g.ecount
end
def test_star
g = IGraph::Generate.star(10,IGraph::STAR_UNDIRECTED,0)
assert_equal 10, g.vcount
assert_equal 9, g.ecount
end
def test_lattice
g = IGraph::Generate.lattice([2,2],false,false,false)
assert_equal 4, g.vcount
assert_equal 4, g.ecount
end
def test_ring
g = IGraph::Generate.ring(10,false,false,false)
assert_equal 10, g.vcount
assert_equal 9, g.ecount
end
def test_tree
g = IGraph::Generate.tree(13,3,IGraph::TREE_UNDIRECTED)
assert_equal 13, g.vcount
assert_equal 12, g.ecount
end
def test_full
g = IGraph::Generate.full(10,false,false)
assert_equal 10, g.vcount
assert_equal 45, g.ecount
end
def test_atlas
g = IGraph::Generate.atlas(10)
assert_equal 4, g.vcount
assert_equal 2, g.ecount
end
def test_extended_chordal_ring
g = IGraph::Generate.extended_chordal_ring(3,IGraphMatrix.new([1,2,3],[1,2,3],[1,2,3]))
assert_equal 3, g.vcount
assert_equal 6, g.ecount
end
def test_connect_neighborhood
g = IGraph.new([1,2,1,3,3,4],false)
g.connect_neighborhood(2,IGraph::ALL)
assert g.are_connected?(2,3)
end
end

View File

@ -0,0 +1,100 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_grg
g = IGraph::GenerateRandom.grg_game(10,0.1,false)
assert_equal 10, g.vertices.size
end
def test_barabasi
g = IGraph::GenerateRandom.barabasi_game(10,3,false,false)
assert_equal 10, g.vertices.size
end
def test_nonlinear_barabasi
g = IGraph::GenerateRandom.nonlinear_barabasi_game(10,1.9,3,false,0.1,false)
assert_equal 10, g.vertices.size
end
def test_erdos_renyi
g = IGraph::GenerateRandom.erdos_renyi_game(IGraph::ERDOS_RENYI_GNP,10,0.5,false,false)
assert_instance_of IGraph, g
g = IGraph::GenerateRandom.erdos_renyi_game(IGraph::ERDOS_RENYI_GNM,10,0.5,false,false)
assert_instance_of IGraph, g
end
def test_watts_strogatz
g = IGraph::GenerateRandom.watts_strogatz_game(10,1,2,0.6)
assert_instance_of IGraph, g
end
def test_degree_sequence_game
g = IGraph::GenerateRandom.degree_sequence_game([1,2,3],[1,2,3])
assert_instance_of IGraph, g
end
def test_growing_random_game
assert_instance_of IGraph, IGraph::GenerateRandom.growing_random_game(10,2,true,true)
end
def test_callaway_traits_game
assert_instance_of IGraph,
IGraph::GenerateRandom.callaway_traits_game(30,4,2,[0.25,0.25,0.25,0.25],
IGraphMatrix.new([0,0.5,0.25,0.25],
[0.5,0,0.25,0.25],
[0.5,0.25,0,0.25],
[0.5,0.25,0.25,0]),true)
end
def test_establishment_game
assert_instance_of IGraph,
IGraph::GenerateRandom.establishment_game(30,4,2,[0.25,0.25,0.25,0.25],
IGraphMatrix.new([0,0.5,0.25,0.25],
[0.5,0,0.25,0.25],
[0.5,0.25,0,0.25],
[0.5,0.25,0.25,0]),true)
end
def test_preference_game
assert_instance_of IGraph,
IGraph::GenerateRandom.preference_game(30,4,[0.25,0.25,0.25,0.25],
IGraphMatrix.new([0,0.5,0.25,0.25],
[0.5,0,0.25,0.25],
[0.5,0.25,0,0.25],
[0.5,0.25,0.25,0]),true,false)
end
def test_asymmetric_preference_game
assert_instance_of IGraph,
IGraph::GenerateRandom.asymmetric_preference_game(30,4,
IGraphMatrix.new([0,0.5,0.25,0.25],
[0.5,0,0.25,0.25],
[0.5,0.25,0,0.25],
[0.5,0.25,0.25,0]),
IGraphMatrix.new([0,0.5,0.25,0.25],
[0.5,0,0.25,0.25],
[0.5,0.25,0,0.25],
[0.5,0.25,0.25,0]),
false)
end
def test_recent_degree_game
assert_instance_of IGraph,
IGraph::GenerateRandom.recent_degree_game(30,2,4,5,false,0.1,true)
end
def test_barabasi_aging_game
assert_instance_of IGraph,
IGraph::GenerateRandom.barabasi_aging_game(30,2,true,0.9,-0.5,3,0.1,0.1,2,2,true)
end
def test_recent_degree_aging_game
assert_instance_of IGraph,
IGraph::GenerateRandom.recent_degree_aging_game(30,2,true,0.9,-0.5,3,4,0.1,true)
end
def test_cited_type_game
assert_instance_of IGraph,
IGraph::GenerateRandom.cited_type_game(10,(0..9).to_a,
Array.new(5,0.5)+Array.new(5,0.2),
2,true)
end
def test_citing_cited_type_Game
# assert_instance_of IGraph,
# IGraph::GenerateRandom.citing_cited_type_game(4,(0..3).to_a,
# IGraphMatrix.new([0,0.5,0.25,0.25],
# [0.5,0,0.25,0.25],
# [0.5,0.25,0,0.25],
# [0.5,0.25,0.25,0]),
# 1,
# true)
end
end

View File

@ -0,0 +1,21 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_independent_vertex_sets
g = IGraph.new([1,2,3,4],false)
assert_equal [[1,3],[1,4],[2,3],[2,4]], g.independent_vertex_sets(2,0)
end
def test_largest_independent_vertex_sets
g = IGraph.new([1,2,3,4,1,5],false)
assert_equal [[2,3,5],[2,4,5]], g.largest_independent_vertex_sets
end
def test_maximal_independent_vertex_sets
g = IGraph.new([1,2,3,4],false)
assert_equal [[1,3],[1,4],[2,3],[2,4]], g.maximal_independent_vertex_sets
end
def test_independence_number
g = IGraph.new([1,2,3,4],false)
assert_equal 2, g.independence_number
end
end

33
test/tc_isomorphic.rb Normal file
View File

@ -0,0 +1,33 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_isomorphic
g = IGraph.new([1,2,3,4],false)
h = IGraph.new([5,6,7,8],false)
assert_equal true, g.isomorphic(h)
assert_equal true, h.isomorphic(g)
end
def test_isomorphic_vf2
g = IGraph.new([1,2,3,4],false)
h = IGraph.new([5,6,7,8],false)
assert_equal true, g.isomorphic_vf2(h)
assert_equal true, h.isomorphic_vf2(g)
end
def test_isoclass
g = IGraph.new([1,2,3,4],false)
h = IGraph.new([5,6,7,8],false)
assert g.isoclass >= 0 and g.isoclass <= 11
assert_equal h.isoclass, g.isoclass
end
def test_isoclass_subgraph
g = IGraph.new([1,2,3,4],false)
assert g.isoclass_subgraph([1,2,3]) >= 0 and g.isoclass <= 4
assert_equal g.isoclass_subgraph([1,2,3]), g.isoclass_subgraph([2,3,4])
end
def test_igraph_isoclass_create
g = IGraph.new([1,2,3,4],false)
h = IGraph::Generate.isoclass_create(4,g.isoclass,false)
assert_equal g.isoclass, h.isoclass
end
end

44
test/tc_iterators.rb Normal file
View File

@ -0,0 +1,44 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_each_vertex
graph = IGraph.new(['A','B','C','D'],true)
assert_nothing_raised do
graph.each_vertex do |v|
end
end
assert_nothing_raised do
graph.each do |v|
end
end
end
def test_each_edge
graph = IGraph.new(['A','B','C','D'],true)
assert_nothing_raised do
graph.each_edge(IGraph::EDGEORDER_ID) do |v,w|
end
end
assert_nothing_raised do
graph.each_edge_eid(IGraph::EDGEORDER_ID) do |v|
end
end
edges = []
graph.each_edge(IGraph::EDGEORDER_ID){|v,w| edges.push([v,w])}
assert_equal [['A','B'],['C','D']], edges
edges = []
graph.each_edge_eid(IGraph::EDGEORDER_ID){|v| edges.push(v)}
assert_equal [0,1], edges
end
def test_enumerable
graph = IGraph.new(['A','B','C','D'],true)
assert graph.all?{|v| v.kind_of? String}
assert graph.any?{|v| v == 'B'}
assert_equal ['A','B','C','D'], graph.collect{|v| v}
assert graph.detect(Proc.new{true}){|v| }
assert_equal ['A'], graph.find_all{|v| v < 'B'}
end
end

71
test/tc_layout.rb Normal file
View File

@ -0,0 +1,71 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_random
g = IGraph.new([1,2,3,4],true)
l = g.layout_random
assert_instance_of IGraphMatrix, l
assert_equal g.vcount, l.nrow
assert_equal 2, l.ncol
end
def test_circle
g = IGraph.new([1,2,3,4],true)
l = g.layout_circle
assert_instance_of IGraphMatrix, l
assert_equal g.vcount, l.nrow
assert_equal 2, l.ncol
end
def test_fruchterman_reingold
g = IGraph.new([1,2,3,4],true)
l = g.layout_fruchterman_reingold(10,1,1,2,1,false)
assert_instance_of IGraphMatrix, l
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
def test_merge
g = IGraph.new([1,2,3,4],true)
l = g.layout_lgl(10,1,1,2,1,1,1)
h = IGraph.new([1,2,3,4],true)
m = h.layout_lgl(10,1,1,2,1,1,1)
f = IGraph::Layout.layout_merge_dla([g,h],[l,m])
assert_instance_of IGraphMatrix, f
assert_equal g.vcount + h.vcount, f.nrow
assert_equal 2, f.ncol
end
end

34
test/tc_layout3d.rb Normal file
View File

@ -0,0 +1,34 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_random_3d
g = IGraph.new([1,2,3,4],true)
l = g.layout_random_3d
assert_instance_of IGraphMatrix, l
assert_equal g.vcount, l.nrow
assert_equal 3, l.ncol
end
def test_sphere
g = IGraph.new([1,2,3,4],true)
l = g.layout_sphere
assert_instance_of IGraphMatrix, l
assert_equal g.vcount, l.nrow
assert_equal 3, l.ncol
end
def test_fruchterman_reingold_3d
g = IGraph.new([1,2,3,4],true)
l = g.layout_fruchterman_reingold_3d(10,1,1,2,1)
assert_instance_of IGraphMatrix, l
assert_equal g.vcount, l.nrow
assert_equal 3, l.ncol
end
def test_kamada_kawai_3d
g = IGraph.new([1,2,3,4],true)
l = g.layout_kamada_kawai_3d(10,1,1,2,1)
assert_instance_of IGraphMatrix, l
assert_equal g.vcount, l.nrow
assert_equal 3, l.ncol
end
end

32
test/tc_matrix.rb Normal file
View File

@ -0,0 +1,32 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_matrix
m = IGraphMatrix.new([1,2],[3,4])
assert_equal 1, m[0,0]
assert_equal 3, m[1,0]
end
def test_set
m = IGraphMatrix.new([1,2],[3,4])
m[0,0] = 6
assert_equal 6, m[0,0]
end
def test_prop
m = IGraphMatrix.new([1,2],[3,4])
assert_equal 4, m.size
assert_equal 2, m.nrow
assert_equal 2, m.ncol
assert_equal 4, m.max
end
def test_op
m = IGraphMatrix.new([1,2],[3,4])
n = m * 2
assert_equal 1, m[0,0]
assert_equal 2, n[0,0]
end
def test_to_a
m = IGraphMatrix.new([1,2],[3,4])
assert_equal [[1,2],[3,4]], m.to_a
end
end

20
test/tc_mincuts.rb Normal file
View File

@ -0,0 +1,20 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_maxflow_mincut
g = IGraph.new([1,2,2,3,3,4])
assert_equal 3, g.maxflow_value(1,4,[5,4,3])
assert_equal 3, g.st_mincut_value(1,4,[5,4,3])
end
def test_mincut
g = IGraph.new([1,2,2,3,3,4,2,1,3,2,4,3],true)
assert_equal 3, g.mincut_value([5,4,3,3,4,5])
g = IGraph.new([1,2,2,3,1,3,3,4,4,5,4,6,5,6],false)
val,p1,p2,cut_eid = g.mincut(Array.new(7,1))
assert_equal 1, val
assert_equal [1,2,3], p2.sort
assert_equal [4,5,6], p1.sort
assert_equal [3], cut_eid
end
end

19
test/tc_motif.rb Normal file
View File

@ -0,0 +1,19 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_motifs_randesu
g = IGraph.new(['A','B','C','D','A','C'],false)
hist = g.motifs_randesu(3,[0,0,0])
assert_equal [0,0,2,0], hist
end
def test_motifs_randesu_no
g = IGraph.new(['A','B','C','D','A','C'],false)
assert_equal 2, g.motifs_randesu_no(3,[0,0,0])
end
def test_motifs_randesu_estimate
g = IGraph.new(['A','B','C','D','A','C'],false)
assert_equal 2, g.motifs_randesu_estimate(3,[0,0,0],4,nil)
assert_equal 2, g.motifs_randesu_estimate(3,[0,0,0],0,['A','B','C','D'])
end
end

34
test/tc_other_ops.rb Normal file
View File

@ -0,0 +1,34 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_density
g = IGraph.new(['A','B','C','D'],true)
assert_equal 0.125, g.density(true)
end
def test_simplify
g = IGraph.new(['A','B','A','B','C','D','A','A'],true)
assert_equal 4, g.ecount
g.simplify(true,false)
assert_equal 3, g.ecount
g.simplify(true,true)
assert_equal 2, g.ecount
end
def test_reciprocity
g = IGraph.new(['A','B','C','D','B','A'],true)
assert_equal 0.5, g.reciprocity(true)
end
def test_bibcoupling
g = IGraph.new(['A','B','C','D','D','B'],true)
assert_equal [[0,0,0,1]], g.bibcoupling(['A'])
end
def test_cocitation
g = IGraph.new(['A','B','C','D','A','D'],true)
assert_equal [[0,0,0,1]], g.cocitation(['B'])
end
def test_get_adjacency
g = IGraph.new(['A','B','C','D'],true)
assert_equal [[0,1,0,0],[0,0,0,0],[0,0,0,1],[0,0,0,0]], g.get_adjacency(1)
end
end

15
test/tc_randomisation.rb Executable file
View File

@ -0,0 +1,15 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_rewire_edges
g = IGraph::GenerateRandom.grg_game(10,0.1,false)
h = g.rewire_edges(0.5)
assert_equal 10, h.to_a.size
end
def test_rewire
g = IGraph::GenerateRandom.grg_game(10,0.1,false)
h = g.rewire(0.5)
assert_equal 10, h.to_a.size
end
end

29
test/tc_selectors.rb Normal file
View File

@ -0,0 +1,29 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_select_all
graph = IGraph.new(['A','B','C','D'],true)
assert_equal ['A','B','C','D'], graph.all_vertices
assert_equal ['A','B','C','D'], graph.vertices
end
def test_adj
graph = IGraph.new(['A','B','C','D'],true)
assert_equal ['B'], graph.adjacent_vertices('A',IGraph::ALL)
end
def test_non_adj
graph = IGraph.new(['A','B','C','D'],true)
assert_equal ['A','C','D'], graph.nonadjacent_vertices('A',IGraph::ALL)
end
def test_e_all
graph = IGraph.new(['A','B','C','D'],true)
assert_equal [0,1], graph.edges(IGraph::EDGEORDER_ID)
end
def test_e_adj
graph = IGraph.new(['A','B','C','D'],true,[1,2])
assert_equal [0], graph.adjacent_edges('B',IGraph::ALL)
end
end

View File

@ -1,6 +1,5 @@
require 'test/unit'
require 'igraph'
require 'mocha'
class TestGraph < Test::Unit::TestCase
def test_shortest_paths
@ -12,17 +11,34 @@ class TestGraph < Test::Unit::TestCase
assert_equal nil, m[0][2]
end
def test_get_shortest_paths_warn
graph = IGraph.new(['A','B','C','D'],true)
graph.expects(:warn).with("Couldn't reach some vertices")
graph.get_shortest_paths('A',['B','C'],IGraph::ALL)
end
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
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

24
test/tc_spanning.rb Normal file
View File

@ -0,0 +1,24 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_minimum_span_tree
g = IGraph.new(['A','B','B','C','C','D','A','D'],true)
st = g.minimum_spanning_tree_unweighted()
assert_kind_of IGraph, st
assert_equal ['A','B','C','D'], st.to_a.sort
end
def test_minimum_span_tree_prim
g = IGraph.new(['A','B','B','C','C','D','A','D'],true)
st = g.minimum_spanning_tree_prim([1,1,5,1])
assert_kind_of IGraph, st
assert_equal ['A','B','C','D'], st.to_a.sort
assert st.are_connected?('A','D')
assert !st.are_connected?('C','D')
st = g.minimum_spanning_tree_prim([1,1,1,5])
assert_kind_of IGraph, st
assert_equal ['A','B','C','D'], st.to_a.sort
assert !st.are_connected?('A','D')
assert st.are_connected?('C','D')
end
end

12
test/tc_spectral.rb Normal file
View File

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

41
test/tc_thrash.rb Normal file
View File

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

View File

@ -0,0 +1,10 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_top_sort
g = IGraph.new([1,2,2,3,3,4])
assert_equal [1,2,3,4], g.topological_sorting(IGraph::OUT)
end
end

17
test/tc_transitivity.rb Normal file
View File

@ -0,0 +1,17 @@
require 'test/unit'
require 'igraph'
class TestGraph < Test::Unit::TestCase
def test_trans
g = IGraph.new(['A','B','A','C','A','D','B','C'],true)
assert_equal 0.6, g.transitivity
end
def test_trans_local
g = IGraph.new(['A','B','A','C','A','D','B','C'],true)
assert_in_delta 0.33, g.transitivity_local(['A'])[0], 0.01
end
def test_trans_avr_local
g = IGraph.new(['A','B','A','C','A','D','B','C'],true)
assert_equal 0.6, g.transitivity
end
end

View File

@ -0,0 +1,29 @@
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
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

View File

@ -1,12 +1,41 @@
#Tests all test cases for rsruby
require 'rbconfig'
include Config
require 'test/unit'
require 'tc_attributes'
require 'tc_cliques'
require 'tc_create'
require 'tc_iterators'
require 'tc_selectors'
require 'tc_add_delete'
require 'tc_basic_query'
require 'tc_basic_properties'
require 'tc_centrality'
require 'tc_community'
require 'tc_components'
require 'tc_connectivity'
require 'tc_copy'
require 'tc_cores'
require 'tc_dijkstra'
require 'tc_directedness'
require 'tc_error_handling'
require 'tc_file_read_write'
require 'tc_generators_deterministic'
require 'tc_generators_random'
require 'tc_independent_vertex_sets'
require 'tc_isomorphic'
require 'tc_iterators'
require 'tc_layout'
require 'tc_layout3d'
require 'tc_matrix'
require 'tc_mincuts'
require 'tc_motif'
require 'tc_other_ops'
require 'tc_randomisation'
require 'tc_selectors'
require 'tc_shortest_paths'
require 'tc_spanning'
require 'tc_spectral'
require 'tc_topological_sort'
require 'tc_transitivity'
require 'tc_vertex_neighbourhood'

61
test/test_draw.rb Normal file
View File

@ -0,0 +1,61 @@
require 'igraph'
require 'cairo'
g = IGraph.barabasi_game(100,3,false,false)
vertices = g.to_a
layout = g.send(ARGV.shift.to_sym,*ARGV.map{|a| eval(a)}).to_a
format = Cairo::FORMAT_ARGB32
width = 1000
height = 1000
surface = Cairo::ImageSurface.new(format, width, height)
cr = Cairo::Context.new(surface)
# fill background with white
cr.set_source_rgba(1.0, 1.0, 1.0, 0.8)
cr.paint
max_x = layout.map{|a| a[0]}.max
min_x = layout.map{|a| a[0]}.min
max_y = layout.map{|a| a[1]}.max
min_y = layout.map{|a| a[1]}.min
x_var = max_x - min_x
y_var = max_y - min_y
max_var = [x_var,y_var].max
layout.each_with_index do |a,i|
x,y = *a
x = (x - min_x)/max_var
y = (y - min_y)/max_var
x *= (width)
y *= (height)
layout[i] = [x,y]
puts "#{x} #{y}"
end
layout.each_with_index do |a,i|
v = vertices[i]
x,y = *a
cr.set_source_rgba(rand,rand,rand,0.5)
cr.circle(x,y,1).fill
g.adjacent_vertices(v,IGraph::OUT).each do |w|
cr.move_to(x,y)
wx,wy = *layout[vertices.index(w)]
cr.line_to(wx,wy)
cr.stroke
end
end
cr.target.write_to_png("test.png")

85
test/test_draw_atlas.rb Normal file
View File

@ -0,0 +1,85 @@
require 'igraph'
require 'cairo'
gs = []
vs = []
ARGV[0].to_i.times do |n|
gs << IGraph.atlas(n+1)
vs += gs[-1].vertices
end
ls = gs.map{|g| g.layout_fruchterman_reingold(10,1,1,2,1,false)}
layout = IGraph.layout_merge_dla(gs,ls).to_a
format = Cairo::FORMAT_ARGB32
width = 1000
height = 1000
surface = Cairo::ImageSurface.new(format, width, height)
cr = Cairo::Context.new(surface)
# fill background with white
cr.set_source_rgba(1.0, 1.0, 1.0, 0.8)
cr.paint
max_x = layout.map{|a| a[0]}.max
min_x = layout.map{|a| a[0]}.min
max_y = layout.map{|a| a[1]}.max
min_y = layout.map{|a| a[1]}.min
x_var = max_x - min_x
y_var = max_y - min_y
max_var = [x_var,y_var].max
layout.each_with_index do |a,i|
x,y = *a
x = (x - min_x)/max_var
y = (y - min_y)/max_var
x *= (width)
y *= (height)
layout[i] = [x,y]
puts "#{x} #{y}"
end
vn = 1
gi = 0
g = gs[gi]
layout.each_with_index do |a,i|
sub_layout = layout[start..finish]
v = vs[i]
x,y = *a
if vn > g.vcount
gi += 1
g = gs[gi]
vn = 1
end
puts "Looking for: " + v.inspect
puts "In: #{g.to_a.inspect}"
puts "Graph number: #{gi}"
puts "Vertex number: #{vn}"
vn += 1
cr.set_source_rgba(0,0,0,0.5)
cr.circle(x,y,10).fill
g.adjacent_vertices(v,IGraph::OUT).each do |w|
cr.move_to(x,y)
wx,wy = *layout[vs.index(w)]
cr.line_to(wx,wy)
cr.stroke
end
end
cr.target.write_to_png("test.png")