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
@@ -0,0 +1,230 @@
|
|
1
|
+
#include "igraph.h"
|
2
|
+
#include "ruby.h"
|
3
|
+
#include "cIGraph.h"
|
4
|
+
|
5
|
+
/* call-seq:
|
6
|
+
* graph.st_edge_connectivity(source,target) -> Integer
|
7
|
+
*
|
8
|
+
* Edge connectivity of a pair of vertices
|
9
|
+
*
|
10
|
+
* The edge connectivity of two vertices (source and target) in a graph is
|
11
|
+
* the minimum number of edges that have to be deleted from the graph to
|
12
|
+
* eliminate all paths from source to target.
|
13
|
+
*
|
14
|
+
* This function uses the maximum flow algorithm to calculate the edge
|
15
|
+
* connectivity.
|
16
|
+
*
|
17
|
+
*/
|
18
|
+
|
19
|
+
VALUE cIGraph_st_edge_connectivity(VALUE self, VALUE source, VALUE target){
|
20
|
+
|
21
|
+
igraph_t *graph;
|
22
|
+
igraph_integer_t from_i;
|
23
|
+
igraph_integer_t to_i;
|
24
|
+
igraph_integer_t value;
|
25
|
+
|
26
|
+
int i;
|
27
|
+
|
28
|
+
Data_Get_Struct(self, igraph_t, graph);
|
29
|
+
|
30
|
+
from_i = cIGraph_get_vertex_id(self,source);
|
31
|
+
to_i = cIGraph_get_vertex_id(self,target);
|
32
|
+
|
33
|
+
igraph_st_edge_connectivity(graph,&value,from_i,to_i);
|
34
|
+
|
35
|
+
return INT2NUM(value);
|
36
|
+
|
37
|
+
}
|
38
|
+
|
39
|
+
/* call-seq:
|
40
|
+
* graph.edge_connectivity() -> Integer
|
41
|
+
*
|
42
|
+
* This is the minimum of the edge connectivity over all pairs of vertices
|
43
|
+
* in the graph.
|
44
|
+
*
|
45
|
+
*/
|
46
|
+
|
47
|
+
VALUE cIGraph_edge_connectivity(VALUE self){
|
48
|
+
|
49
|
+
igraph_t *graph;
|
50
|
+
igraph_integer_t value;
|
51
|
+
|
52
|
+
Data_Get_Struct(self, igraph_t, graph);
|
53
|
+
|
54
|
+
igraph_edge_connectivity(graph,&value,1);
|
55
|
+
|
56
|
+
return INT2NUM(value);
|
57
|
+
|
58
|
+
}
|
59
|
+
|
60
|
+
/* call-seq:
|
61
|
+
* graph.st_vertex_connectivity(source,target,neigh) -> Integer
|
62
|
+
*
|
63
|
+
* The vertex connectivity of two vertices (source and target) is the minimum
|
64
|
+
* number of vertices that have to be deleted to eliminate all paths from
|
65
|
+
* source to target. Directed paths are considered in directed graphs.
|
66
|
+
*
|
67
|
+
* A constant giving what to do if the two vertices are connected. Possible
|
68
|
+
* values: IGraph::VCONN_NEI_ERROR, stop with an error message,
|
69
|
+
* IGraph::VCONN_INFINITY, return infinity (ie. 1.0/0.0).
|
70
|
+
* IGraph::VCONN_IGNORE, ignore the fact that the two vertices are connected
|
71
|
+
* and calculated the number of vertices needed to aliminate all paths except
|
72
|
+
* for the trivial (direct) paths between source and vertex.
|
73
|
+
*
|
74
|
+
*/
|
75
|
+
|
76
|
+
VALUE cIGraph_st_vertex_connectivity(VALUE self, VALUE source, VALUE target, VALUE neighbours){
|
77
|
+
|
78
|
+
igraph_t *graph;
|
79
|
+
igraph_integer_t from_i;
|
80
|
+
igraph_integer_t to_i;
|
81
|
+
igraph_integer_t value;
|
82
|
+
|
83
|
+
int i;
|
84
|
+
|
85
|
+
Data_Get_Struct(self, igraph_t, graph);
|
86
|
+
|
87
|
+
from_i = cIGraph_get_vertex_id(self,source);
|
88
|
+
to_i = cIGraph_get_vertex_id(self,target);
|
89
|
+
|
90
|
+
igraph_st_vertex_connectivity(graph,&value,from_i,to_i,NUM2INT(neighbours));
|
91
|
+
|
92
|
+
return INT2NUM(value);
|
93
|
+
|
94
|
+
}
|
95
|
+
|
96
|
+
/* call-seq:
|
97
|
+
* graph.vertex_connectivity() -> Integer
|
98
|
+
*
|
99
|
+
* This is the minimum of the vertex connectivity over all pairs of vertices
|
100
|
+
* in the graph.
|
101
|
+
*
|
102
|
+
*/
|
103
|
+
|
104
|
+
VALUE cIGraph_vertex_connectivity(VALUE self){
|
105
|
+
|
106
|
+
igraph_t *graph;
|
107
|
+
igraph_integer_t value;
|
108
|
+
|
109
|
+
Data_Get_Struct(self, igraph_t, graph);
|
110
|
+
|
111
|
+
igraph_vertex_connectivity(graph,&value,1);
|
112
|
+
|
113
|
+
return INT2NUM(value);
|
114
|
+
|
115
|
+
}
|
116
|
+
|
117
|
+
/* call-seq:
|
118
|
+
* graph.edge_disjoint_paths(source,target) -> Integer
|
119
|
+
*
|
120
|
+
* The maximum number of edge-disjoint paths between two vertices.
|
121
|
+
*
|
122
|
+
* A set of paths between two vertices is called edge-disjoint if they do not
|
123
|
+
* share any edges. The maximum number of edge-disjoint paths are calculated
|
124
|
+
* by this function using maximum flow techniques. Directed paths are
|
125
|
+
* considered in directed graphs.
|
126
|
+
*
|
127
|
+
*/
|
128
|
+
|
129
|
+
VALUE cIGraph_edge_disjoint_paths(VALUE self, VALUE source, VALUE target){
|
130
|
+
|
131
|
+
igraph_t *graph;
|
132
|
+
igraph_integer_t from_i;
|
133
|
+
igraph_integer_t to_i;
|
134
|
+
igraph_integer_t value;
|
135
|
+
|
136
|
+
int i;
|
137
|
+
|
138
|
+
Data_Get_Struct(self, igraph_t, graph);
|
139
|
+
|
140
|
+
from_i = cIGraph_get_vertex_id(self,source);
|
141
|
+
to_i = cIGraph_get_vertex_id(self,target);
|
142
|
+
|
143
|
+
igraph_edge_disjoint_paths(graph,&value,from_i,to_i);
|
144
|
+
|
145
|
+
return INT2NUM(value);
|
146
|
+
|
147
|
+
}
|
148
|
+
|
149
|
+
/* call-seq:
|
150
|
+
* graph.vertex_disjoint_paths(source,target) -> Integer
|
151
|
+
*
|
152
|
+
* The maximum number of vertex-disjoint paths between two vertices.
|
153
|
+
*
|
154
|
+
* A set of paths between two vertices is called vertex-disjoint if they do
|
155
|
+
* not share any vertexs. The maximum number of vertex-disjoint paths are
|
156
|
+
* calculated by this function using maximum flow techniques. Directed paths
|
157
|
+
* are considered in directed graphs.
|
158
|
+
*
|
159
|
+
*/
|
160
|
+
|
161
|
+
VALUE cIGraph_vertex_disjoint_paths(VALUE self, VALUE source, VALUE target){
|
162
|
+
|
163
|
+
igraph_t *graph;
|
164
|
+
igraph_integer_t from_i;
|
165
|
+
igraph_integer_t to_i;
|
166
|
+
igraph_integer_t value;
|
167
|
+
|
168
|
+
int i;
|
169
|
+
|
170
|
+
Data_Get_Struct(self, igraph_t, graph);
|
171
|
+
|
172
|
+
from_i = cIGraph_get_vertex_id(self,source);
|
173
|
+
to_i = cIGraph_get_vertex_id(self,target);
|
174
|
+
|
175
|
+
igraph_vertex_disjoint_paths(graph,&value,from_i,to_i);
|
176
|
+
|
177
|
+
return INT2NUM(value);
|
178
|
+
|
179
|
+
}
|
180
|
+
|
181
|
+
/* call-seq:
|
182
|
+
* graph.adhesion() -> Integer
|
183
|
+
*
|
184
|
+
* Graph adhesion, this is (almost) the same as edge connectivity.
|
185
|
+
*
|
186
|
+
* This quantity is defined by White and Harary in The cohesiveness of
|
187
|
+
* blocks in social networks: node connectivity and conditional density,
|
188
|
+
* (Sociological Methodology 31:305--359, 2001) and basically it is the
|
189
|
+
* edge connectivity of the graph with uniform edge weights.
|
190
|
+
*
|
191
|
+
*/
|
192
|
+
|
193
|
+
VALUE cIGraph_adhesion(VALUE self){
|
194
|
+
|
195
|
+
igraph_t *graph;
|
196
|
+
igraph_integer_t value;
|
197
|
+
|
198
|
+
Data_Get_Struct(self, igraph_t, graph);
|
199
|
+
|
200
|
+
igraph_adhesion(graph,&value,1);
|
201
|
+
|
202
|
+
return INT2NUM(value);
|
203
|
+
|
204
|
+
}
|
205
|
+
|
206
|
+
/* call-seq:
|
207
|
+
* graph.cohesion() -> Integer
|
208
|
+
*
|
209
|
+
* Graph cohesion, this is the same as vertex connectivity.
|
210
|
+
*
|
211
|
+
* This quantity is defined by White and Harary in The cohesiveness of
|
212
|
+
* blocks in social networks: node connectivity and conditional density,
|
213
|
+
* (Sociological Methodology 31:305--359, 2001) and basically it is the
|
214
|
+
* edge connectivity of the graph with uniform edge weights.
|
215
|
+
*
|
216
|
+
*/
|
217
|
+
|
218
|
+
VALUE cIGraph_cohesion(VALUE self){
|
219
|
+
|
220
|
+
igraph_t *graph;
|
221
|
+
igraph_integer_t value;
|
222
|
+
|
223
|
+
Data_Get_Struct(self, igraph_t, graph);
|
224
|
+
|
225
|
+
igraph_cohesion(graph,&value,1);
|
226
|
+
|
227
|
+
return INT2NUM(value);
|
228
|
+
|
229
|
+
}
|
230
|
+
|
data/ext/cIGraph_file.c
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
#include "cIGraph.h"
|
4
4
|
|
5
5
|
/* call-seq:
|
6
|
-
* IGraph.read_graph_edgelist(file,mode) -> IGraph
|
6
|
+
* IGraph::FileRead.read_graph_edgelist(file,mode) -> IGraph
|
7
7
|
*
|
8
8
|
* Reads an edge list from a File (or any IO) and creates a graph.
|
9
9
|
*
|
@@ -90,7 +90,577 @@ VALUE cIGraph_write_graph_edgelist(VALUE self, VALUE file){
|
|
90
90
|
}
|
91
91
|
|
92
92
|
/* call-seq:
|
93
|
-
* IGraph.
|
93
|
+
* IGraph::FileRead.read_graph_ncol(file,predefnames,names,weights,directed) -> IGraph
|
94
|
+
*
|
95
|
+
* Reads a .ncol file used by LGL, also useful for creating graphs from
|
96
|
+
* 'named' (and optionally weighted) edge lists.
|
97
|
+
*
|
98
|
+
* This format is used by the Large Graph Layout program
|
99
|
+
* (http://bioinformatics.icmb.utexas.edu/lgl/), and it is simply a symbolic
|
100
|
+
* weighted edge list. It is a simple text file with one edge per line. An
|
101
|
+
* edge is defined by two symbolic vertex names separated by whitespace.
|
102
|
+
* (The symbolic vertex names themselves cannot contain whitespace. They
|
103
|
+
* might follow by an optional number, this will be the weight of the edge;
|
104
|
+
* the number can be negative and can be in scientific notation. If there is
|
105
|
+
* no weight specified to an edge it is assumed to be zero.
|
106
|
+
*
|
107
|
+
* The resulting graph is always undirected. LGL cannot deal with files which
|
108
|
+
* contain multiple or loop edges, this is however not checked here, as
|
109
|
+
* igraph is happy with these.
|
110
|
+
*
|
111
|
+
* file: A File or IO object to read from.
|
112
|
+
*
|
113
|
+
* predefnames: Array of the symbolic names of the vertices in the file.
|
114
|
+
* If empty then vertex ids will be assigned to vertex names in the order of
|
115
|
+
* their appearence in the .ncol file.
|
116
|
+
*
|
117
|
+
* names: Logical value, if TRUE the symbolic names of the vertices will be
|
118
|
+
* added to the graph as a vertex attribute called 'name'.
|
119
|
+
*
|
120
|
+
* weights: Logical value, if TRUE the weights of the edges is added to the
|
121
|
+
* graph as an edge attribute called 'weight'.
|
122
|
+
*
|
123
|
+
* directed: Whether to create a directed graph. As this format was originally
|
124
|
+
* used only for undirected graphs there is no information in the file about
|
125
|
+
* the directedness of the graph. Set this parameter to IGRAPH_DIRECTED or
|
126
|
+
* IGRAPH_UNDIRECTED to create a directed or undirected graph.
|
127
|
+
*/
|
128
|
+
VALUE cIGraph_read_graph_ncol(VALUE self, VALUE file, VALUE predefnames, VALUE names, VALUE weights, VALUE directed){
|
129
|
+
|
130
|
+
VALUE string;
|
131
|
+
FILE *stream;
|
132
|
+
VALUE new_graph;
|
133
|
+
VALUE v_ary;
|
134
|
+
VALUE e_ary;
|
135
|
+
VALUE new_ary;
|
136
|
+
|
137
|
+
igraph_t *graph;
|
138
|
+
igraph_strvector_t names_vec;
|
139
|
+
igraph_bool_t directed_b = 0;
|
140
|
+
igraph_bool_t weights_b = 0;
|
141
|
+
igraph_bool_t names_b = 0;
|
142
|
+
|
143
|
+
int i;
|
144
|
+
|
145
|
+
if(directed)
|
146
|
+
directed_b = 1;
|
147
|
+
|
148
|
+
if(names)
|
149
|
+
names_b = 1;
|
150
|
+
|
151
|
+
if(weights)
|
152
|
+
weights_b = 1;
|
153
|
+
|
154
|
+
new_graph = cIGraph_alloc(cIGraph);
|
155
|
+
Data_Get_Struct(new_graph, igraph_t, graph);
|
156
|
+
|
157
|
+
igraph_strvector_init(&names_vec,RARRAY(predefnames)->len);
|
158
|
+
|
159
|
+
for(i=0;i<RARRAY(predefnames)->len;i++){
|
160
|
+
igraph_strvector_set(&names_vec, i, RSTRING(RARRAY(predefnames)->ptr[i])->ptr);
|
161
|
+
}
|
162
|
+
|
163
|
+
string = rb_funcall(file, rb_intern("read"), 0);
|
164
|
+
stream = fmemopen(RSTRING(string)->ptr,RSTRING(string)->len, "r");
|
165
|
+
|
166
|
+
if (RARRAY(predefnames)->len == 0){
|
167
|
+
igraph_read_graph_ncol(graph, stream, NULL, names_b, weights_b, directed_b);
|
168
|
+
} else {
|
169
|
+
igraph_read_graph_ncol(graph, stream, &names_vec, names_b, weights_b, directed_b);
|
170
|
+
}
|
171
|
+
|
172
|
+
fclose(stream);
|
173
|
+
|
174
|
+
//Convert the Hash of names to Strings instead
|
175
|
+
if(names){
|
176
|
+
v_ary = ((VALUE*)graph->attr)[0];
|
177
|
+
new_ary = rb_ary_new();
|
178
|
+
for(i=0;i<RARRAY(v_ary)->len;i++){
|
179
|
+
rb_ary_push(new_ary, rb_hash_aref(RARRAY(v_ary)->ptr[i], rb_str_new2("name")));
|
180
|
+
}
|
181
|
+
((VALUE*)graph->attr)[0] = new_ary;
|
182
|
+
}
|
183
|
+
//Convert the Hash of weights to floats instead
|
184
|
+
if(weights){
|
185
|
+
e_ary = ((VALUE*)graph->attr)[1];
|
186
|
+
new_ary = rb_ary_new();
|
187
|
+
for(i=0;i<RARRAY(e_ary)->len;i++){
|
188
|
+
rb_ary_push(new_ary, rb_hash_aref(RARRAY(e_ary)->ptr[i], rb_str_new2("weight")));
|
189
|
+
}
|
190
|
+
((VALUE*)graph->attr)[1] = new_ary;
|
191
|
+
}
|
192
|
+
|
193
|
+
igraph_strvector_destroy(&names_vec);
|
194
|
+
|
195
|
+
return new_graph;
|
196
|
+
|
197
|
+
}
|
198
|
+
|
199
|
+
/* call-seq:
|
200
|
+
* graph.write_graph_ncol(file,names,weights) -> Integer
|
201
|
+
*
|
202
|
+
* Writes the graph to a file in .ncol format
|
203
|
+
*
|
204
|
+
* .ncol is a format used by LGL, see igraph_read_graph_ncol() for details.
|
205
|
+
*
|
206
|
+
* Note that having multiple or loop edges in an .ncol file breaks the LGL
|
207
|
+
* software but igraph does not check for this condition.
|
208
|
+
*
|
209
|
+
* file: The file object to write to, it should be writable.
|
210
|
+
*
|
211
|
+
* names: The name of the vertex attribute, if symbolic names are to be
|
212
|
+
* written to the file.
|
213
|
+
*
|
214
|
+
* weights: The name of the edge attribute, if they are also written to the
|
215
|
+
* file.
|
216
|
+
*/
|
217
|
+
VALUE cIGraph_write_graph_ncol(VALUE self, VALUE file, VALUE names, VALUE weights){
|
218
|
+
|
219
|
+
char *buf;
|
220
|
+
size_t size;
|
221
|
+
FILE *stream;
|
222
|
+
igraph_t *graph;
|
223
|
+
int e, i;
|
224
|
+
|
225
|
+
VALUE v_ary;
|
226
|
+
VALUE e_ary;
|
227
|
+
VALUE new_v_ary;
|
228
|
+
VALUE new_e_ary;
|
229
|
+
|
230
|
+
VALUE vertex_h;
|
231
|
+
VALUE edge_h;
|
232
|
+
|
233
|
+
char *weights_b = "0";
|
234
|
+
char *names_b = "0";
|
235
|
+
|
236
|
+
if(names)
|
237
|
+
names_b = "name";
|
238
|
+
|
239
|
+
if(weights)
|
240
|
+
weights_b = "weight";
|
241
|
+
|
242
|
+
Data_Get_Struct(self, igraph_t, graph);
|
243
|
+
|
244
|
+
//Convert each object to it's String representation and each edge to
|
245
|
+
//it's Float
|
246
|
+
if(names){
|
247
|
+
v_ary = ((VALUE*)graph->attr)[0];
|
248
|
+
new_v_ary = rb_ary_new();
|
249
|
+
for(i=0;i<RARRAY(v_ary)->len;i++){
|
250
|
+
vertex_h = rb_hash_new();
|
251
|
+
rb_hash_aset(vertex_h, rb_str_new2("name"), StringValue(RARRAY(v_ary)->ptr[i]));
|
252
|
+
rb_ary_push(new_v_ary, vertex_h);
|
253
|
+
}
|
254
|
+
((VALUE*)graph->attr)[0] = new_v_ary;
|
255
|
+
}
|
256
|
+
if(weights){
|
257
|
+
e_ary = ((VALUE*)graph->attr)[1];
|
258
|
+
new_e_ary = rb_ary_new();
|
259
|
+
for(i=0;i<RARRAY(e_ary)->len;i++){
|
260
|
+
edge_h = rb_hash_new();
|
261
|
+
rb_hash_aset(edge_h, rb_str_new2("weight"), rb_funcall(RARRAY(e_ary)->ptr[i],rb_intern("to_f"),0));
|
262
|
+
rb_ary_push(new_e_ary, edge_h);
|
263
|
+
}
|
264
|
+
((VALUE*)graph->attr)[1] = new_e_ary;
|
265
|
+
}
|
266
|
+
|
267
|
+
stream = open_memstream(&buf,&size);
|
268
|
+
e = igraph_write_graph_ncol(graph, stream, names_b, weights_b);
|
269
|
+
fflush(stream);
|
270
|
+
rb_funcall(file, rb_intern("write"), 1, rb_str_new(buf,size));
|
271
|
+
fclose(stream);
|
272
|
+
|
273
|
+
//Replace initital vertices and edges
|
274
|
+
if(names){
|
275
|
+
((VALUE*)graph->attr)[0] = v_ary;
|
276
|
+
}
|
277
|
+
if(weights){
|
278
|
+
((VALUE*)graph->attr)[0] = e_ary;
|
279
|
+
}
|
280
|
+
|
281
|
+
return e;
|
282
|
+
|
283
|
+
}
|
284
|
+
|
285
|
+
/* call-seq:
|
286
|
+
* IGraph::FileRead.read_graph_lgl(file,predefnames,names,weights) -> IGraph
|
287
|
+
*
|
288
|
+
* Reads a graph from an .lgl file
|
289
|
+
*
|
290
|
+
* The .lgl format is used by the Large Graph Layout visualization software
|
291
|
+
* (http://bioinformatics.icmb.utexas.edu/lgl/), it can describe undirected
|
292
|
+
* optionally weighted graphs. From the LGL manual:
|
293
|
+
*
|
294
|
+
* The second format is the LGL file format ( .lgl file suffix). This is yet
|
295
|
+
* another graph file format that tries to be as stingy as possible with
|
296
|
+
* space, yet keeping the edge file in a human readable (not binary) format.
|
297
|
+
* The format itself is like the following:
|
298
|
+
*
|
299
|
+
* # vertex1name
|
300
|
+
* vertex2name [optionalWeight]
|
301
|
+
* vertex3name [optionalWeight]
|
302
|
+
*
|
303
|
+
* Here, the first vertex of an edge is preceded with a pound sign '#'.
|
304
|
+
* Then each vertex that shares an edge with that vertex is listed one per
|
305
|
+
* line on subsequent lines.
|
306
|
+
*
|
307
|
+
* LGL cannot handle loop and multiple edges or directed graphs, but in
|
308
|
+
* igraph it is not an error to have multiple and loop edges.
|
309
|
+
*
|
310
|
+
* file: A File or IO object to read from.
|
311
|
+
*
|
312
|
+
* names: Logical value, if TRUE the symbolic names of the vertices will be
|
313
|
+
* added to the graph as a vertex attribute called $B!H(Bname$B!I(B.
|
314
|
+
*
|
315
|
+
* weights: Logical value, if TRUE the weights of the edges is added to the
|
316
|
+
* graph as an edge attribute called $B!H(Bweight$B!I(B.
|
317
|
+
*/
|
318
|
+
VALUE cIGraph_read_graph_lgl(VALUE self, VALUE file, VALUE names, VALUE weights){
|
319
|
+
|
320
|
+
VALUE string;
|
321
|
+
FILE *stream;
|
322
|
+
VALUE new_graph;
|
323
|
+
VALUE v_ary;
|
324
|
+
VALUE e_ary;
|
325
|
+
VALUE new_ary;
|
326
|
+
|
327
|
+
igraph_t *graph;
|
328
|
+
igraph_bool_t weights_b = 0;
|
329
|
+
igraph_bool_t names_b = 0;
|
330
|
+
|
331
|
+
int i;
|
332
|
+
|
333
|
+
if(names)
|
334
|
+
names_b = 1;
|
335
|
+
|
336
|
+
if(weights)
|
337
|
+
weights_b = 1;
|
338
|
+
|
339
|
+
new_graph = cIGraph_alloc(cIGraph);
|
340
|
+
Data_Get_Struct(new_graph, igraph_t, graph);
|
341
|
+
|
342
|
+
string = rb_funcall(file, rb_intern("read"), 0);
|
343
|
+
stream = fmemopen(RSTRING(string)->ptr,RSTRING(string)->len, "r");
|
344
|
+
|
345
|
+
igraph_read_graph_lgl(graph, stream, names_b, weights_b);
|
346
|
+
|
347
|
+
fclose(stream);
|
348
|
+
|
349
|
+
//Convert the Hash of names to Strings instead
|
350
|
+
if(names){
|
351
|
+
v_ary = ((VALUE*)graph->attr)[0];
|
352
|
+
new_ary = rb_ary_new();
|
353
|
+
for(i=0;i<RARRAY(v_ary)->len;i++){
|
354
|
+
rb_ary_push(new_ary, rb_hash_aref(RARRAY(v_ary)->ptr[i], rb_str_new2("name")));
|
355
|
+
}
|
356
|
+
((VALUE*)graph->attr)[0] = new_ary;
|
357
|
+
}
|
358
|
+
//Convert the Hash of weights to floats instead
|
359
|
+
if(weights){
|
360
|
+
e_ary = ((VALUE*)graph->attr)[1];
|
361
|
+
new_ary = rb_ary_new();
|
362
|
+
for(i=0;i<RARRAY(e_ary)->len;i++){
|
363
|
+
rb_ary_push(new_ary, rb_hash_aref(RARRAY(e_ary)->ptr[i], rb_str_new2("weight")));
|
364
|
+
}
|
365
|
+
((VALUE*)graph->attr)[1] = new_ary;
|
366
|
+
}
|
367
|
+
|
368
|
+
return new_graph;
|
369
|
+
|
370
|
+
}
|
371
|
+
|
372
|
+
/* call-seq:
|
373
|
+
* graph.write_graph_lgl(file,names,weights,isolates) -> Integer
|
374
|
+
*
|
375
|
+
* Writes the graph to a file in .lgl format
|
376
|
+
*
|
377
|
+
* .lgl is a format used by LGL, see read_graph_lgl() for details.
|
378
|
+
*
|
379
|
+
* Note that having multiple or loop edges in an .lgl file breaks the LGL
|
380
|
+
* software but igraph does not check for this condition.
|
381
|
+
*
|
382
|
+
* file: The File object to write to, it should be writable.
|
383
|
+
*
|
384
|
+
* names: The name of the vertex attribute, if symbolic names are written to
|
385
|
+
* the file.
|
386
|
+
*
|
387
|
+
* weights: The name of the edge attribute, if they are also written to the
|
388
|
+
* file.
|
389
|
+
*
|
390
|
+
* isolates: Logical, if TRUE isolated vertices are also written to the file.
|
391
|
+
* If FALSE they will be omitted.
|
392
|
+
*/
|
393
|
+
VALUE cIGraph_write_graph_lgl(VALUE self, VALUE file, VALUE names, VALUE weights, VALUE isolates){
|
394
|
+
|
395
|
+
char *buf;
|
396
|
+
size_t size;
|
397
|
+
FILE *stream;
|
398
|
+
igraph_t *graph;
|
399
|
+
int e, i;
|
400
|
+
|
401
|
+
VALUE v_ary;
|
402
|
+
VALUE e_ary;
|
403
|
+
VALUE new_v_ary;
|
404
|
+
VALUE new_e_ary;
|
405
|
+
|
406
|
+
VALUE vertex_h;
|
407
|
+
VALUE edge_h;
|
408
|
+
|
409
|
+
char *weights_b = "0";
|
410
|
+
char *names_b = "0";
|
411
|
+
|
412
|
+
igraph_bool_t isolates_b;
|
413
|
+
|
414
|
+
if(names)
|
415
|
+
names_b = "name";
|
416
|
+
|
417
|
+
if(weights)
|
418
|
+
weights_b = "weight";
|
419
|
+
|
420
|
+
if(isolates)
|
421
|
+
isolates_b = 1;
|
422
|
+
|
423
|
+
Data_Get_Struct(self, igraph_t, graph);
|
424
|
+
|
425
|
+
//Convert each object to it's String representation and each edge to
|
426
|
+
//it's Float
|
427
|
+
if(names){
|
428
|
+
v_ary = ((VALUE*)graph->attr)[0];
|
429
|
+
new_v_ary = rb_ary_new();
|
430
|
+
for(i=0;i<RARRAY(v_ary)->len;i++){
|
431
|
+
vertex_h = rb_hash_new();
|
432
|
+
rb_hash_aset(vertex_h, rb_str_new2("name"), StringValue(RARRAY(v_ary)->ptr[i]));
|
433
|
+
rb_ary_push(new_v_ary, vertex_h);
|
434
|
+
}
|
435
|
+
((VALUE*)graph->attr)[0] = new_v_ary;
|
436
|
+
}
|
437
|
+
if(weights){
|
438
|
+
e_ary = ((VALUE*)graph->attr)[1];
|
439
|
+
new_e_ary = rb_ary_new();
|
440
|
+
for(i=0;i<RARRAY(e_ary)->len;i++){
|
441
|
+
edge_h = rb_hash_new();
|
442
|
+
rb_hash_aset(edge_h, rb_str_new2("weight"), rb_funcall(RARRAY(e_ary)->ptr[i],rb_intern("to_f"),0));
|
443
|
+
rb_ary_push(new_e_ary, edge_h);
|
444
|
+
}
|
445
|
+
((VALUE*)graph->attr)[1] = new_e_ary;
|
446
|
+
}
|
447
|
+
|
448
|
+
stream = open_memstream(&buf,&size);
|
449
|
+
e = igraph_write_graph_lgl(graph, stream, names_b, weights_b, isolates);
|
450
|
+
fflush(stream);
|
451
|
+
rb_funcall(file, rb_intern("write"), 1, rb_str_new(buf,size));
|
452
|
+
fclose(stream);
|
453
|
+
|
454
|
+
//Replace initital vertices and edges
|
455
|
+
if(names){
|
456
|
+
((VALUE*)graph->attr)[0] = v_ary;
|
457
|
+
}
|
458
|
+
if(weights){
|
459
|
+
((VALUE*)graph->attr)[0] = e_ary;
|
460
|
+
}
|
461
|
+
|
462
|
+
return e;
|
463
|
+
|
464
|
+
}
|
465
|
+
|
466
|
+
/* call-seq:
|
467
|
+
* IGraph::FileRead.read_graph_dimacs(file,directed) -> IGraph
|
468
|
+
*
|
469
|
+
* This function reads the DIMACS file format, more specifically the version
|
470
|
+
* for network flow problems, see the files at
|
471
|
+
* ftp://dimacs.rutgers.edu/pub/netflow/general-info/
|
472
|
+
*
|
473
|
+
* This is a line-oriented text file (ASCII) format. The first character of
|
474
|
+
* each line defines the type of the line. If the first character is c the
|
475
|
+
* line is a comment line and it is ignored. There is one problem line ( p in
|
476
|
+
* the file, it must appear before any node and arc descriptor lines. The
|
477
|
+
* problem line has three fields separated by spaces: the problem type
|
478
|
+
* ( min , max or asn ), the number of vertices and number of edges in the
|
479
|
+
* graph. Exactly two node identification lines are expected ( n ), one for
|
480
|
+
* the source, one for the target vertex. These have two fields: the id of
|
481
|
+
* the vertex and the type of the vertex, either s (=source) or t (=target).
|
482
|
+
* Arc lines start with a and have three fields: the source vertex, the
|
483
|
+
* target vertex and the edge capacity.
|
484
|
+
*
|
485
|
+
* Vertex ids are numbered from 1. The source, target vertices and edge
|
486
|
+
* capacities are added as attributes of the graph.
|
487
|
+
* I.e: g.attributes['source'].
|
488
|
+
*
|
489
|
+
* file: The File to read from.
|
490
|
+
*
|
491
|
+
* directed: Boolean, whether to create a directed graph.
|
492
|
+
*/
|
493
|
+
VALUE cIGraph_read_graph_dimacs(VALUE self, VALUE file, VALUE directed){
|
494
|
+
|
495
|
+
VALUE string;
|
496
|
+
FILE *stream;
|
497
|
+
VALUE new_graph;
|
498
|
+
|
499
|
+
igraph_integer_t source;
|
500
|
+
igraph_integer_t target;
|
501
|
+
igraph_vector_t capacity;
|
502
|
+
|
503
|
+
igraph_t *graph;
|
504
|
+
igraph_bool_t directed_b = 0;
|
505
|
+
|
506
|
+
igraph_vs_t vs;
|
507
|
+
igraph_vit_t vit;
|
508
|
+
|
509
|
+
VALUE v_ary;
|
510
|
+
VALUE g_hsh;
|
511
|
+
|
512
|
+
int i;
|
513
|
+
int vid;
|
514
|
+
|
515
|
+
if(directed)
|
516
|
+
directed_b = 1;
|
517
|
+
|
518
|
+
igraph_vector_init(&capacity, 0);
|
519
|
+
|
520
|
+
new_graph = cIGraph_alloc(cIGraph);
|
521
|
+
Data_Get_Struct(new_graph, igraph_t, graph);
|
522
|
+
|
523
|
+
string = rb_funcall(file, rb_intern("read"), 0);
|
524
|
+
stream = fmemopen(RSTRING(string)->ptr,RSTRING(string)->len, "r");
|
525
|
+
|
526
|
+
igraph_read_graph_dimacs(graph, stream, &source, &target, &capacity, directed_b);
|
527
|
+
|
528
|
+
fclose(stream);
|
529
|
+
|
530
|
+
igraph_vs_all(&vs);
|
531
|
+
igraph_vit_create(graph, vs, &vit);
|
532
|
+
|
533
|
+
//Push Integer onto vertex array
|
534
|
+
v_ary = ((VALUE*)graph->attr)[0];
|
535
|
+
|
536
|
+
while (!IGRAPH_VIT_END(vit)) {
|
537
|
+
vid = IGRAPH_VIT_GET(vit);
|
538
|
+
rb_ary_push(v_ary,INT2NUM(vid));
|
539
|
+
IGRAPH_VIT_NEXT(vit);
|
540
|
+
}
|
541
|
+
|
542
|
+
g_hsh = ((VALUE*)graph->attr)[2];
|
543
|
+
|
544
|
+
rb_hash_aset(g_hsh, rb_str_new2("source"), INT2NUM(source));
|
545
|
+
rb_hash_aset(g_hsh, rb_str_new2("target"), INT2NUM(target));
|
546
|
+
rb_hash_aset(g_hsh, rb_str_new2("capacity"), rb_ary_new());
|
547
|
+
|
548
|
+
for(i=0;i<igraph_vector_size(&capacity);i++){
|
549
|
+
rb_ary_push(rb_hash_aref(g_hsh, rb_str_new2("capacity")), rb_float_new(VECTOR(capacity)[i]));
|
550
|
+
}
|
551
|
+
|
552
|
+
igraph_vit_destroy(&vit);
|
553
|
+
igraph_vs_destroy(&vs);
|
554
|
+
|
555
|
+
return new_graph;
|
556
|
+
|
557
|
+
}
|
558
|
+
|
559
|
+
/* call-seq:
|
560
|
+
* graph.write_graph_dimacs(file,source,target,capacity) -> Integer
|
561
|
+
*
|
562
|
+
* This function writes a graph to an output stream in DIMACS format,
|
563
|
+
* describing a maximum flow problem. See
|
564
|
+
* ftp://dimacs.rutgers.edu/pub/netflow/general-info/
|
565
|
+
*
|
566
|
+
* This file format is discussed in the documentation of read_graph_dimacs(),
|
567
|
+
* see that for more information.
|
568
|
+
*
|
569
|
+
* file: IO object to write to.
|
570
|
+
*
|
571
|
+
* source: The source vertex for the maximum flow.
|
572
|
+
*
|
573
|
+
* target: The target vertex.
|
574
|
+
*
|
575
|
+
* capacity: Array containing the edge capacity values.
|
576
|
+
*/
|
577
|
+
VALUE cIGraph_write_graph_dimacs(VALUE self, VALUE file, VALUE source, VALUE target, VALUE capacity){
|
578
|
+
|
579
|
+
char *buf;
|
580
|
+
size_t size;
|
581
|
+
FILE *stream;
|
582
|
+
igraph_t *graph;
|
583
|
+
int e, i;
|
584
|
+
|
585
|
+
igraph_vector_t capacity_v;
|
586
|
+
|
587
|
+
Data_Get_Struct(self, igraph_t, graph);
|
588
|
+
|
589
|
+
igraph_vector_init(&capacity_v,0);
|
590
|
+
|
591
|
+
for(i=0;i<RARRAY(capacity)->len;i++){
|
592
|
+
igraph_vector_push_back(&capacity_v,NUM2DBL(RARRAY(capacity)->ptr[i]));
|
593
|
+
}
|
594
|
+
|
595
|
+
stream = open_memstream(&buf,&size);
|
596
|
+
e = igraph_write_graph_dimacs(graph, stream, NUM2INT(source), NUM2INT(target), &capacity_v);
|
597
|
+
fflush(stream);
|
598
|
+
rb_funcall(file, rb_intern("write"), 1, rb_str_new(buf,size));
|
599
|
+
fclose(stream);
|
600
|
+
|
601
|
+
return e;
|
602
|
+
|
603
|
+
}
|
604
|
+
|
605
|
+
/* call-seq:
|
606
|
+
* IGraph::FileRead.read_graph_graphdb(file,directed) -> IGraph
|
607
|
+
*
|
608
|
+
* Read a graph in the binary graph database format.
|
609
|
+
*
|
610
|
+
* file: The IO object to read from.
|
611
|
+
*
|
612
|
+
* directed: Boolean, whether to create a directed graph.
|
613
|
+
*/
|
614
|
+
VALUE cIGraph_read_graph_graphdb(VALUE self, VALUE file, VALUE directed){
|
615
|
+
|
616
|
+
VALUE string;
|
617
|
+
FILE *stream;
|
618
|
+
VALUE new_graph;
|
619
|
+
|
620
|
+
VALUE v_ary;
|
621
|
+
|
622
|
+
igraph_t *graph;
|
623
|
+
igraph_bool_t directed_b = 0;
|
624
|
+
|
625
|
+
igraph_vs_t vs;
|
626
|
+
igraph_vit_t vit;
|
627
|
+
|
628
|
+
int vid;
|
629
|
+
|
630
|
+
if(directed)
|
631
|
+
directed_b = 1;
|
632
|
+
|
633
|
+
new_graph = cIGraph_alloc(cIGraph);
|
634
|
+
Data_Get_Struct(new_graph, igraph_t, graph);
|
635
|
+
|
636
|
+
string = rb_funcall(file, rb_intern("read"), 0);
|
637
|
+
stream = fmemopen(RSTRING(string)->ptr,RSTRING(string)->len, "r");
|
638
|
+
|
639
|
+
igraph_read_graph_graphdb(graph, stream, directed_b);
|
640
|
+
|
641
|
+
fclose(stream);
|
642
|
+
|
643
|
+
igraph_vs_all(&vs);
|
644
|
+
igraph_vit_create(graph, vs, &vit);
|
645
|
+
|
646
|
+
//Push Integer onto vertex array
|
647
|
+
v_ary = ((VALUE*)graph->attr)[0];
|
648
|
+
|
649
|
+
while (!IGRAPH_VIT_END(vit)) {
|
650
|
+
vid = IGRAPH_VIT_GET(vit);
|
651
|
+
rb_ary_push(v_ary,INT2NUM(vid));
|
652
|
+
IGRAPH_VIT_NEXT(vit);
|
653
|
+
}
|
654
|
+
|
655
|
+
igraph_vit_destroy(&vit);
|
656
|
+
igraph_vs_destroy(&vs);
|
657
|
+
|
658
|
+
return new_graph;
|
659
|
+
|
660
|
+
}
|
661
|
+
|
662
|
+
/* call-seq:
|
663
|
+
* IGraph::FileRead.read_graph_graphml(file,index) -> IGraph
|
94
664
|
*
|
95
665
|
* Reads a graph from a GraphML file specified as the File object file.
|
96
666
|
*
|
@@ -156,7 +726,68 @@ VALUE cIGraph_write_graph_graphml(VALUE self, VALUE file){
|
|
156
726
|
}
|
157
727
|
|
158
728
|
/* call-seq:
|
159
|
-
* IGraph.
|
729
|
+
* IGraph::FileRead.read_graph_gml(file) -> IGraph
|
730
|
+
*
|
731
|
+
* Reads a graph from a GraphML file.
|
732
|
+
*
|
733
|
+
* GraphML is an XML-based file format for representing various types of
|
734
|
+
* graphs. Currently only the most basic import functionality is implemented
|
735
|
+
* in igraph: it can read GraphML files without nested graphs and hyperedges.
|
736
|
+
*
|
737
|
+
* file: IO object to read from
|
738
|
+
*/
|
739
|
+
VALUE cIGraph_read_graph_gml(VALUE self, VALUE file){
|
740
|
+
|
741
|
+
VALUE string;
|
742
|
+
FILE *stream;
|
743
|
+
VALUE new_graph;
|
744
|
+
igraph_t *graph;
|
745
|
+
|
746
|
+
new_graph = cIGraph_alloc(cIGraph);
|
747
|
+
Data_Get_Struct(new_graph, igraph_t, graph);
|
748
|
+
|
749
|
+
string = rb_funcall(file, rb_intern("read"), 0);
|
750
|
+
stream = fmemopen(RSTRING(string)->ptr,RSTRING(string)->len, "r");
|
751
|
+
|
752
|
+
igraph_read_graph_gml(graph, stream);
|
753
|
+
|
754
|
+
fclose(stream);
|
755
|
+
|
756
|
+
return new_graph;
|
757
|
+
|
758
|
+
}
|
759
|
+
|
760
|
+
/* call-seq:
|
761
|
+
* graph.write_graph_gml(file) -> IGraph
|
762
|
+
*
|
763
|
+
* Writes the graph to a file in GraphML format.
|
764
|
+
*
|
765
|
+
* file: IO object to write to
|
766
|
+
*/
|
767
|
+
VALUE cIGraph_write_graph_gml(VALUE self, VALUE file){
|
768
|
+
|
769
|
+
char *buf;
|
770
|
+
size_t size;
|
771
|
+
FILE *stream;
|
772
|
+
igraph_t *graph;
|
773
|
+
int e;
|
774
|
+
|
775
|
+
Data_Get_Struct(self, igraph_t, graph);
|
776
|
+
|
777
|
+
stream = open_memstream(&buf,&size);
|
778
|
+
e = igraph_write_graph_gml(graph, stream, NULL, 0);
|
779
|
+
fflush(stream);
|
780
|
+
|
781
|
+
rb_funcall(file, rb_intern("write"), 1, rb_str_new(buf,size));
|
782
|
+
|
783
|
+
fclose(stream);
|
784
|
+
|
785
|
+
return e;
|
786
|
+
|
787
|
+
}
|
788
|
+
|
789
|
+
/* call-seq:
|
790
|
+
* IGraph::FileRead.read_graph_pajek(file) -> IGraph
|
160
791
|
*
|
161
792
|
* Reads a file in Pajek format
|
162
793
|
*
|