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