Compare commits
No commits in common. "0.1.1-prerelease" and "master" have entirely different histories.
0.1.1-prer
...
master
29
History.txt
29
History.txt
|
@ -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
|
57
Manifest.txt
57
Manifest.txt
|
@ -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
|
||||
|
|
75
README.txt
75
README.txt
|
@ -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
|
||||
|
||||
|
|
39
Rakefile.rb
39
Rakefile.rb
|
@ -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
|
||||
|
|
597
ext/cIGraph.c
597
ext/cIGraph.c
|
@ -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 */
|
||||
|
||||
}
|
||||
|
|
356
ext/cIGraph.h
356
ext/cIGraph.h
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include "igraph.h"
|
||||
#include "ruby.h"
|
||||
#include "cIGraph.h"
|
||||
|
||||
VALUE cIGraph_add_op(VALUE self, VALUE graph){
|
||||
|
||||
return Qnil;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#include "igraph.h"
|
||||
#include "ruby.h"
|
||||
#include "cIGraph.h"
|
||||
|
||||
/* call-seq:
|
||||
* graph.laplacian(mode) -> Array
|
||||
*
|
||||
* Returns the Laplacian matrix of a graph
|
||||
*
|
||||
* The graph Laplacian matrix is similar to an adjacency matrix but
|
||||
* contains -1's instead of 1's and the vertex degrees are included
|
||||
* in the diagonal. So the result for edge i--j is -1 if i!=j and is
|
||||
* equal to the degree of vertex i if i==j. igraph_laplacian will work
|
||||
* on a directed graph (although this does not seem to make much sense)
|
||||
* and ignores loops.
|
||||
*
|
||||
* Mode is a boolean specifying whether the normalized version should be used
|
||||
* The normalised Laplacian matrix has 1 in the diagonal
|
||||
* and -1/sqrt(d[i]d[j]) if there is an edge from i to j.
|
||||
*
|
||||
* The first version of this function was written by Vincent Matossian.
|
||||
*/
|
||||
VALUE cIGraph_laplacian(VALUE self, VALUE mode){
|
||||
|
||||
igraph_t *graph;
|
||||
igraph_bool_t pmode = 0;
|
||||
igraph_matrix_t res;
|
||||
int i;
|
||||
int j;
|
||||
VALUE row;
|
||||
VALUE val;
|
||||
VALUE matrix = rb_ary_new();
|
||||
|
||||
if(mode == Qtrue)
|
||||
pmode = 1;
|
||||
|
||||
Data_Get_Struct(self, igraph_t, graph);
|
||||
|
||||
//matrix to hold the results of the calculations
|
||||
igraph_matrix_init(&res,igraph_vcount(graph),igraph_vcount(graph));
|
||||
|
||||
IGRAPH_CHECK(igraph_laplacian(graph,&res,pmode));
|
||||
|
||||
for(i=0; i<igraph_matrix_nrow(&res); i++){
|
||||
row = rb_ary_new();
|
||||
rb_ary_push(matrix,row);
|
||||
for(j=0; j<igraph_matrix_ncol(&res); j++){
|
||||
val = rb_float_new(MATRIX(res,i,j));
|
||||
rb_ary_push(row,val);
|
||||
}
|
||||
}
|
||||
|
||||
igraph_matrix_destroy(&res);
|
||||
|
||||
return matrix;
|
||||
|
||||
}
|
|
@ -0,0 +1,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;
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
1027
manual.tex
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
require 'test/unit'
|
||||
require 'igraph'
|
||||
|
||||
class TestGraph < Test::Unit::TestCase
|
||||
def test_coreness
|
||||
g = IGraph.new(['A','B','C','D'],true)
|
||||
c = g.coreness(IGraph::ALL)
|
||||
assert_equal c.length, g.vcount
|
||||
end
|
||||
end
|
|
@ -0,0 +1,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
|
|
@ -0,0 +1,31 @@
|
|||
require 'test/unit'
|
||||
require 'igraph'
|
||||
|
||||
class TestGraph < Test::Unit::TestCase
|
||||
def test_directed_conv
|
||||
|
||||
g = IGraph.new(['A','B','B','C','C','D'],false)
|
||||
|
||||
g.to_directed(IGraph::ARBITRARY)
|
||||
assert g.are_connected?('A','B') || g.are_connected?('B','A')
|
||||
assert !(g.are_connected?('A','B') && g.are_connected?('B','A'))
|
||||
|
||||
g = IGraph.new(['A','B','B','C','C','D'],false)
|
||||
|
||||
g.to_directed(IGraph::MUTUAL)
|
||||
assert g.are_connected?('A','B') && g.are_connected?('B','A')
|
||||
|
||||
end
|
||||
def test_undirected
|
||||
g = IGraph.new(['A','B','B','A','B','C','C','D'],true)
|
||||
|
||||
g.to_undirected(IGraph::EACH)
|
||||
assert_equal 4, g.ecount
|
||||
|
||||
g = IGraph.new(['A','B','B','A','B','C','C','D'],true)
|
||||
|
||||
g.to_undirected(IGraph::COLLAPSE)
|
||||
assert_equal 3, g.ecount
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,12 @@
|
|||
require 'test/unit'
|
||||
require 'igraph'
|
||||
|
||||
class TestGraph < Test::Unit::TestCase
|
||||
def test_laplacian
|
||||
g = IGraph.new(['A','B','C','D'],false)
|
||||
m = g.laplacian(false)
|
||||
assert_equal m.length, g.vcount
|
||||
m = g.laplacian(true)
|
||||
assert_equal m.length, g.vcount
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
require 'test/unit'
|
||||
require 'igraph'
|
||||
|
||||
class Array
|
||||
def mean
|
||||
total = 0.0
|
||||
self.each do |i|
|
||||
total += i
|
||||
end
|
||||
total / self.length.to_f
|
||||
end
|
||||
end
|
||||
|
||||
class TestGraph < Test::Unit::TestCase
|
||||
def test_thrash
|
||||
g = IGraph.new([],true)
|
||||
v = 100
|
||||
v.times do |x|
|
||||
g.add_vertex(x)
|
||||
end
|
||||
200.times do |x|
|
||||
g.add_edge(rand(v/2),rand(v/2))
|
||||
end
|
||||
200.times do |x|
|
||||
g.add_edge(rand(v/2)+v/2,rand(v/2)+v/2)
|
||||
end
|
||||
assert_equal v, g.vcount
|
||||
h,i = g.decompose(IGraph::WEAK,-1,2)
|
||||
|
||||
p h.vcount
|
||||
p i.vcount
|
||||
|
||||
p h.degree(h.to_a[20..30],IGraph::ALL,false).mean
|
||||
p h.degree(h.to_a[10..20],IGraph::ALL,false).mean
|
||||
|
||||
p h.betweenness(h.to_a[20..30],true).mean
|
||||
p h.betweenness(h.to_a[10..20],true).mean
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,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
|
|
@ -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
|
|
@ -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
|
|
@ -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'
|
||||
|
|
|
@ -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")
|
|
@ -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")
|
Loading…
Reference in New Issue