igraph 0.3.3 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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')
|