igraph 0.3.3 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +5 -0
- data/Manifest.txt +12 -1
- data/README.txt +50 -10
- data/Rakefile.rb +1 -1
- data/ext/cIGraph.c +347 -110
- data/ext/cIGraph.h +98 -0
- data/ext/cIGraph_attribute_handler.c +23 -13
- data/ext/cIGraph_community.c +654 -0
- data/ext/cIGraph_connectivity.c +230 -0
- data/ext/cIGraph_file.c +634 -3
- data/ext/cIGraph_generators_deterministic.c +324 -0
- data/ext/cIGraph_generators_random.c +718 -0
- data/ext/cIGraph_layout.c +43 -0
- data/ext/cIGraph_layout3d.c +119 -0
- data/ext/cIGraph_min_cuts.c +195 -0
- data/ext/cIGraph_randomisation.c +57 -0
- data/ext/cIGraph_utility.c +2 -0
- data/test/tc_add_delete.rb +21 -0
- data/test/tc_community.rb +72 -0
- data/test/tc_connectivity.rb +22 -0
- data/test/tc_file_read_write.rb +193 -3
- data/test/tc_generators_deterministic.rb +61 -0
- data/test/tc_generators_random.rb +82 -8
- data/test/tc_isomorphic.rb +1 -1
- data/test/tc_layout.rb +10 -0
- data/test/tc_layout3d.rb +34 -0
- data/test/tc_mincuts.rb +20 -0
- data/test/tc_randomisation.rb +15 -0
- data/test/test_all.rb +6 -0
- metadata +15 -4
- data/test/test_draw.rb +0 -61
data/ext/cIGraph_layout.c
CHANGED
@@ -247,3 +247,46 @@ VALUE cIGraph_layout_lgl(VALUE self,
|
|
247
247
|
|
248
248
|
}
|
249
249
|
|
250
|
+
/* call-seq:
|
251
|
+
* graph.layout_merge_dla(graphs,layouts) -> IGraphMatrix
|
252
|
+
*
|
253
|
+
* Merge multiple layouts by using a DLA algorithm
|
254
|
+
*
|
255
|
+
* First each layout is covered by a circle. Then the layout of the largest
|
256
|
+
* graph is placed at the origin. Then the other layouts are placed by the
|
257
|
+
* DLA algorithm, larger ones first and smaller ones last.
|
258
|
+
*
|
259
|
+
* graphs: Array of IGraph objects
|
260
|
+
*
|
261
|
+
* layouts: Array of IGraphMatrix layouts
|
262
|
+
*/
|
263
|
+
VALUE cIGraph_layout_merge_dla(VALUE self, VALUE graphs, VALUE layouts){
|
264
|
+
|
265
|
+
igraph_vector_ptr_t thegraphs;
|
266
|
+
igraph_vector_ptr_t coords;
|
267
|
+
int i;
|
268
|
+
igraph_t *graph;
|
269
|
+
igraph_matrix_t *coord;
|
270
|
+
igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t));
|
271
|
+
|
272
|
+
igraph_vector_ptr_init(&thegraphs,0);
|
273
|
+
igraph_vector_ptr_init(&coords,0);
|
274
|
+
igraph_matrix_init(res,0,0);
|
275
|
+
|
276
|
+
for(i=0;i<RARRAY(graphs)->len;i++){
|
277
|
+
Data_Get_Struct(RARRAY(graphs)->ptr[i], igraph_t, graph);
|
278
|
+
igraph_vector_ptr_push_back(&thegraphs,graph);
|
279
|
+
}
|
280
|
+
for(i=0;i<RARRAY(layouts)->len;i++){
|
281
|
+
Data_Get_Struct(RARRAY(layouts)->ptr[i], igraph_matrix_t, coord);
|
282
|
+
igraph_vector_ptr_push_back(&coords,coord);
|
283
|
+
}
|
284
|
+
|
285
|
+
igraph_layout_merge_dla(&thegraphs, &coords, res);
|
286
|
+
|
287
|
+
igraph_vector_ptr_destroy(&thegraphs);
|
288
|
+
igraph_vector_ptr_destroy(&coords);
|
289
|
+
|
290
|
+
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
|
291
|
+
|
292
|
+
}
|
@@ -0,0 +1,119 @@
|
|
1
|
+
#include "igraph.h"
|
2
|
+
#include "ruby.h"
|
3
|
+
#include "cIGraph.h"
|
4
|
+
|
5
|
+
/* call-seq:
|
6
|
+
* graph.layout_random -> IGraphMatrix
|
7
|
+
*
|
8
|
+
* Returns a random layout in 3D.
|
9
|
+
*/
|
10
|
+
VALUE cIGraph_layout_random_3d(VALUE self){
|
11
|
+
|
12
|
+
igraph_t *graph;
|
13
|
+
igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t));
|
14
|
+
|
15
|
+
Data_Get_Struct(self, igraph_t, graph);
|
16
|
+
|
17
|
+
igraph_matrix_init(res,0,0);
|
18
|
+
igraph_layout_random_3d(graph,res);
|
19
|
+
|
20
|
+
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
|
21
|
+
|
22
|
+
}
|
23
|
+
|
24
|
+
/* call-seq:
|
25
|
+
* graph.layout_sphere -> IGraphMatrix
|
26
|
+
*
|
27
|
+
* Places vertices (more or less) uniformly on a sphere.
|
28
|
+
*
|
29
|
+
* The algorithm was described in the following paper: Distributing many
|
30
|
+
* points on a sphere by E.B. Saff and A.B.J. Kuijlaars, Mathematical
|
31
|
+
* Intelligencer 19.1 (1997) 5--11.
|
32
|
+
*/
|
33
|
+
VALUE cIGraph_layout_sphere(VALUE self){
|
34
|
+
|
35
|
+
igraph_t *graph;
|
36
|
+
igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t));
|
37
|
+
|
38
|
+
Data_Get_Struct(self, igraph_t, graph);
|
39
|
+
|
40
|
+
igraph_matrix_init(res,0,0);
|
41
|
+
igraph_layout_sphere(graph,res);
|
42
|
+
|
43
|
+
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
|
44
|
+
|
45
|
+
}
|
46
|
+
|
47
|
+
/* call-seq:
|
48
|
+
* graph.layout_fruchterman_reingold_3d(niter,maxdelta,volume,coolexp,repulserad) -> IGraphMatrix
|
49
|
+
*
|
50
|
+
* This is the 3D version of the force based Fruchterman-Reingold layout.
|
51
|
+
*
|
52
|
+
* niter: The number of iterations to do.
|
53
|
+
*
|
54
|
+
* maxdelta: The maximum distance to move a vertex in an iteration.
|
55
|
+
*
|
56
|
+
* volume: The volume parameter of the algorithm.
|
57
|
+
*
|
58
|
+
* coolexp: The cooling exponent of the simulated annealing.
|
59
|
+
*
|
60
|
+
* repulserad: Determines the radius at which vertex-vertex repulsion
|
61
|
+
* cancels out attraction of adjacent vertices.
|
62
|
+
*/
|
63
|
+
VALUE cIGraph_layout_fruchterman_reingold_3d(VALUE self,
|
64
|
+
VALUE niter,
|
65
|
+
VALUE maxdelta,
|
66
|
+
VALUE volume,
|
67
|
+
VALUE coolexp,
|
68
|
+
VALUE repulserad){
|
69
|
+
|
70
|
+
igraph_t *graph;
|
71
|
+
igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t));
|
72
|
+
|
73
|
+
Data_Get_Struct(self, igraph_t, graph);
|
74
|
+
|
75
|
+
igraph_matrix_init(res,0,0);
|
76
|
+
igraph_layout_fruchterman_reingold_3d(graph,res,
|
77
|
+
NUM2INT(niter),
|
78
|
+
NUM2DBL(maxdelta),
|
79
|
+
NUM2DBL(volume),
|
80
|
+
NUM2DBL(coolexp),
|
81
|
+
NUM2DBL(repulserad),
|
82
|
+
1);
|
83
|
+
|
84
|
+
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
|
85
|
+
|
86
|
+
}
|
87
|
+
|
88
|
+
/* call-seq:
|
89
|
+
* graph.layout_kamada_kawai_3d -> IGraphMatrix
|
90
|
+
*
|
91
|
+
* Places the vertices on a plane according the Kamada-Kawai algorithm.
|
92
|
+
*
|
93
|
+
* This is a force directed layout, see Kamada, T. and Kawai, S.: An
|
94
|
+
* Algorithm for Drawing General Undirected Graphs. Information Processing
|
95
|
+
* Letters, 31/1, 7--15, 1989.
|
96
|
+
*/
|
97
|
+
VALUE cIGraph_layout_kamada_kawai_3d(VALUE self,
|
98
|
+
VALUE niter,
|
99
|
+
VALUE sigma,
|
100
|
+
VALUE initemp,
|
101
|
+
VALUE coolexp,
|
102
|
+
VALUE kkconst){
|
103
|
+
|
104
|
+
igraph_t *graph;
|
105
|
+
igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t));
|
106
|
+
|
107
|
+
Data_Get_Struct(self, igraph_t, graph);
|
108
|
+
|
109
|
+
igraph_matrix_init(res,0,0);
|
110
|
+
igraph_layout_kamada_kawai_3d(graph,res,
|
111
|
+
NUM2INT(niter),
|
112
|
+
NUM2DBL(sigma),
|
113
|
+
NUM2DBL(initemp),
|
114
|
+
NUM2DBL(coolexp),
|
115
|
+
NUM2DBL(kkconst));
|
116
|
+
|
117
|
+
return Data_Wrap_Struct(cIGraphMatrix, 0, cIGraph_matrix_free, res);
|
118
|
+
|
119
|
+
}
|
@@ -0,0 +1,195 @@
|
|
1
|
+
#include "igraph.h"
|
2
|
+
#include "ruby.h"
|
3
|
+
#include "cIGraph.h"
|
4
|
+
|
5
|
+
/* call-seq:
|
6
|
+
* graph.maxflow_value(source,target,capacity) -> Max Flow
|
7
|
+
*
|
8
|
+
* Maximum flow in a network with the push/relabel algorithm
|
9
|
+
*
|
10
|
+
* This function implements the Goldberg-Tarjan algorithm for calculating
|
11
|
+
* value of the maximum flow in a directed or undirected graph. The algorithm
|
12
|
+
* was given in Andrew V. Goldberg, Robert E. Tarjan: A New Approach to the
|
13
|
+
* Maximum-Flow Problem, Journal of the ACM, 35(4), 921-940, 1988.
|
14
|
+
*
|
15
|
+
* Note that the value of the maximum flow is the same as the minimum cut in
|
16
|
+
* the graph.
|
17
|
+
*
|
18
|
+
*/
|
19
|
+
|
20
|
+
VALUE cIGraph_maxflow_value(VALUE self, VALUE source, VALUE target, VALUE capacity){
|
21
|
+
|
22
|
+
igraph_t *graph;
|
23
|
+
igraph_integer_t from_i;
|
24
|
+
igraph_integer_t to_i;
|
25
|
+
igraph_real_t value;
|
26
|
+
|
27
|
+
int i;
|
28
|
+
|
29
|
+
igraph_vector_t capacity_v;
|
30
|
+
|
31
|
+
igraph_vector_init(&capacity_v, 0);
|
32
|
+
for(i=0;i<RARRAY(capacity)->len;i++){
|
33
|
+
igraph_vector_push_back(&capacity_v,NUM2DBL(RARRAY(capacity)->ptr[i]));
|
34
|
+
}
|
35
|
+
|
36
|
+
Data_Get_Struct(self, igraph_t, graph);
|
37
|
+
|
38
|
+
from_i = cIGraph_get_vertex_id(self,source);
|
39
|
+
to_i = cIGraph_get_vertex_id(self,target);
|
40
|
+
|
41
|
+
igraph_maxflow_value(graph,&value,from_i,to_i,&capacity_v);
|
42
|
+
|
43
|
+
igraph_vector_destroy(&capacity_v);
|
44
|
+
|
45
|
+
return rb_float_new(value);
|
46
|
+
|
47
|
+
}
|
48
|
+
|
49
|
+
/* call-seq:
|
50
|
+
* graph.st_mincut_value(source,target,capacity) -> Max Flow
|
51
|
+
*
|
52
|
+
* Maximum flow in a network with the push/relabel algorithm
|
53
|
+
*
|
54
|
+
* This function implements the Goldberg-Tarjan algorithm for calculating
|
55
|
+
* value of the maximum flow in a directed or undirected graph. The algorithm
|
56
|
+
* was given in Andrew V. Goldberg, Robert E. Tarjan: A New Approach to the
|
57
|
+
* Maximum-Flow Problem, Journal of the ACM, 35(4), 921-940, 1988.
|
58
|
+
*
|
59
|
+
* Note that the value of the maximum flow is the same as the minimum cut in
|
60
|
+
* the graph.
|
61
|
+
*
|
62
|
+
*/
|
63
|
+
|
64
|
+
VALUE cIGraph_st_mincut_value(VALUE self, VALUE source, VALUE target, VALUE capacity){
|
65
|
+
|
66
|
+
igraph_t *graph;
|
67
|
+
igraph_integer_t from_i;
|
68
|
+
igraph_integer_t to_i;
|
69
|
+
igraph_real_t value;
|
70
|
+
|
71
|
+
int i;
|
72
|
+
|
73
|
+
igraph_vector_t capacity_v;
|
74
|
+
|
75
|
+
igraph_vector_init(&capacity_v, 0);
|
76
|
+
for(i=0;i<RARRAY(capacity)->len;i++){
|
77
|
+
igraph_vector_push_back(&capacity_v,NUM2DBL(RARRAY(capacity)->ptr[i]));
|
78
|
+
}
|
79
|
+
|
80
|
+
Data_Get_Struct(self, igraph_t, graph);
|
81
|
+
|
82
|
+
from_i = cIGraph_get_vertex_id(self,source);
|
83
|
+
to_i = cIGraph_get_vertex_id(self,target);
|
84
|
+
|
85
|
+
igraph_st_mincut_value(graph,&value,from_i,to_i,&capacity_v);
|
86
|
+
|
87
|
+
igraph_vector_destroy(&capacity_v);
|
88
|
+
|
89
|
+
return rb_float_new(value);
|
90
|
+
|
91
|
+
}
|
92
|
+
|
93
|
+
/* call-seq:
|
94
|
+
* graph.mincut_value(capacity) -> Float
|
95
|
+
*
|
96
|
+
* The minimum edge cut in a graph is the total minimum weight of the edges
|
97
|
+
* needed to remove from the graph to make the graph not strongly connected.
|
98
|
+
* (If the original graph is not strongly connected then this is zero.) Note
|
99
|
+
* that in undirected graphs strong connectedness is the same as weak
|
100
|
+
* connectedness.
|
101
|
+
*
|
102
|
+
*/
|
103
|
+
|
104
|
+
VALUE cIGraph_mincut_value(VALUE self, VALUE capacity){
|
105
|
+
|
106
|
+
igraph_t *graph;
|
107
|
+
igraph_real_t value;
|
108
|
+
|
109
|
+
int i;
|
110
|
+
|
111
|
+
igraph_vector_t capacity_v;
|
112
|
+
|
113
|
+
igraph_vector_init(&capacity_v, 0);
|
114
|
+
for(i=0;i<RARRAY(capacity)->len;i++){
|
115
|
+
igraph_vector_push_back(&capacity_v,NUM2DBL(RARRAY(capacity)->ptr[i]));
|
116
|
+
}
|
117
|
+
|
118
|
+
Data_Get_Struct(self, igraph_t, graph);
|
119
|
+
|
120
|
+
igraph_mincut_value(graph,&value,&capacity_v);
|
121
|
+
|
122
|
+
igraph_vector_destroy(&capacity_v);
|
123
|
+
|
124
|
+
return rb_float_new(value);
|
125
|
+
|
126
|
+
}
|
127
|
+
|
128
|
+
/* call-seq:
|
129
|
+
* graph.mincut(capacity) -> Array
|
130
|
+
*
|
131
|
+
* Calculates the minimum cut in a graph. This function calculates the
|
132
|
+
* minimum cut in a graph. Right now it is implemented only for undirected
|
133
|
+
* graphs, in which case it uses the Stoer-Wagner algorithm, as described
|
134
|
+
* in M. Stoer and F. Wagner: A simple min-cut algorithm, Journal of the
|
135
|
+
* ACM, 44 585-591, 1997.
|
136
|
+
*
|
137
|
+
*/
|
138
|
+
|
139
|
+
VALUE cIGraph_mincut(VALUE self, VALUE capacity){
|
140
|
+
|
141
|
+
VALUE res_ary;
|
142
|
+
|
143
|
+
VALUE p1_a;
|
144
|
+
VALUE p2_a;
|
145
|
+
VALUE cut_a;
|
146
|
+
|
147
|
+
igraph_t *graph;
|
148
|
+
igraph_real_t value;
|
149
|
+
|
150
|
+
int i;
|
151
|
+
|
152
|
+
igraph_vector_t p1;
|
153
|
+
igraph_vector_t p2;
|
154
|
+
igraph_vector_t cut;
|
155
|
+
|
156
|
+
igraph_vector_t capacity_v;
|
157
|
+
|
158
|
+
igraph_vector_init(&p1, 0);
|
159
|
+
igraph_vector_init(&p2, 0);
|
160
|
+
igraph_vector_init(&cut, 0);
|
161
|
+
|
162
|
+
igraph_vector_init(&capacity_v, 0);
|
163
|
+
for(i=0;i<RARRAY(capacity)->len;i++){
|
164
|
+
igraph_vector_push_back(&capacity_v,NUM2DBL(RARRAY(capacity)->ptr[i]));
|
165
|
+
}
|
166
|
+
|
167
|
+
Data_Get_Struct(self, igraph_t, graph);
|
168
|
+
|
169
|
+
igraph_mincut(graph,&value,&p1,&p2,&cut,&capacity_v);
|
170
|
+
|
171
|
+
p1_a = rb_ary_new();
|
172
|
+
for(i=0;i<igraph_vector_size(&p1);i++){
|
173
|
+
rb_ary_push(p1_a,cIGraph_get_vertex_object(self,VECTOR(p1)[i]));
|
174
|
+
}
|
175
|
+
p2_a = rb_ary_new();
|
176
|
+
for(i=0;i<igraph_vector_size(&p2);i++){
|
177
|
+
rb_ary_push(p2_a,cIGraph_get_vertex_object(self,VECTOR(p2)[i]));
|
178
|
+
}
|
179
|
+
cut_a = rb_ary_new();
|
180
|
+
for(i=0;i<igraph_vector_size(&cut);i++){
|
181
|
+
rb_ary_push(cut_a,INT2NUM(VECTOR(cut)[i]));
|
182
|
+
}
|
183
|
+
|
184
|
+
res_ary = rb_ary_new3(4,rb_float_new(value),p1_a,p2_a,cut_a);
|
185
|
+
|
186
|
+
igraph_vector_destroy(&p1);
|
187
|
+
igraph_vector_destroy(&p2);
|
188
|
+
igraph_vector_destroy(&cut);
|
189
|
+
|
190
|
+
igraph_vector_destroy(&capacity_v);
|
191
|
+
|
192
|
+
return res_ary;
|
193
|
+
|
194
|
+
}
|
195
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#include "igraph.h"
|
2
|
+
#include "ruby.h"
|
3
|
+
#include "cIGraph.h"
|
4
|
+
|
5
|
+
/* call-seq:
|
6
|
+
* g.rewire_edges(prob) -> IGraph
|
7
|
+
*
|
8
|
+
* Rewire the edges of a graph with constant probability This function
|
9
|
+
* rewires the edges of a graph with a constant probability. More precisely
|
10
|
+
* each end point of each edge is rewired to an uniformly randomly chosen
|
11
|
+
* vertex with constant probability prob.
|
12
|
+
*
|
13
|
+
* prob: The rewiring probability a constant between zero and one (inclusive).
|
14
|
+
*/
|
15
|
+
VALUE cIGraph_rewire_edges(VALUE self, VALUE prop){
|
16
|
+
|
17
|
+
igraph_t *graph;
|
18
|
+
igraph_t *copy_graph;
|
19
|
+
VALUE new_graph;
|
20
|
+
|
21
|
+
new_graph = cIGraph_alloc(cIGraph);
|
22
|
+
Data_Get_Struct(new_graph, igraph_t, copy_graph);
|
23
|
+
Data_Get_Struct(self, igraph_t, graph);
|
24
|
+
|
25
|
+
igraph_copy(copy_graph,graph);
|
26
|
+
igraph_rewire_edges(copy_graph,NUM2DBL(prop));
|
27
|
+
|
28
|
+
return new_graph;
|
29
|
+
|
30
|
+
}
|
31
|
+
|
32
|
+
/* call-seq:
|
33
|
+
* g.rewire(n) -> IGraph
|
34
|
+
*
|
35
|
+
* Randomly rewires a graph while preserving the degree distribution.
|
36
|
+
*
|
37
|
+
* This function generates a new graph based on the original one by randomly
|
38
|
+
* rewiring edges while preserving the original graph's degree distribution.
|
39
|
+
*
|
40
|
+
* n: Number of rewiring trials to perform.
|
41
|
+
*/
|
42
|
+
VALUE cIGraph_rewire(VALUE self, VALUE n){
|
43
|
+
|
44
|
+
igraph_t *graph;
|
45
|
+
igraph_t *copy_graph;
|
46
|
+
VALUE new_graph;
|
47
|
+
|
48
|
+
new_graph = cIGraph_alloc(cIGraph);
|
49
|
+
Data_Get_Struct(new_graph, igraph_t, copy_graph);
|
50
|
+
Data_Get_Struct(self, igraph_t, graph);
|
51
|
+
|
52
|
+
igraph_copy(copy_graph,graph);
|
53
|
+
igraph_rewire(copy_graph,NUM2INT(n),0);
|
54
|
+
|
55
|
+
return new_graph;
|
56
|
+
|
57
|
+
}
|
data/ext/cIGraph_utility.c
CHANGED
data/test/tc_add_delete.rb
CHANGED
@@ -56,6 +56,27 @@ class TestGraph < Test::Unit::TestCase
|
|
56
56
|
assert_equal 1, graph.ecount
|
57
57
|
end
|
58
58
|
|
59
|
+
def test_delete_large
|
60
|
+
vs = (0..99).to_a
|
61
|
+
h = IGraph.new([],true)
|
62
|
+
vs.each do |id|
|
63
|
+
h.add_vertex(id)
|
64
|
+
end
|
65
|
+
|
66
|
+
g = h.dup
|
67
|
+
|
68
|
+
delete_ids = (0..99).to_a.sort_by{rand}[0..19]
|
69
|
+
assert_nothing_raised do
|
70
|
+
delete_ids.each do |id|
|
71
|
+
g.delete_vertex(id)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
delete_ids.each do |id|
|
75
|
+
assert_equal false, g.include?(id)
|
76
|
+
end
|
77
|
+
assert_equal 80, g.vcount
|
78
|
+
end
|
79
|
+
|
59
80
|
def test_delete_edge
|
60
81
|
graph = IGraph.new(['A','B','C','D'],true)
|
61
82
|
assert_equal true, graph.are_connected?('A','B')
|