igraph 0.1.1 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -19,39 +19,60 @@
19
19
  * must have already been added to the graph before they can be used in
20
20
  * an edge (throws a IGraphError otherwise).
21
21
  */
22
- VALUE cIGraph_add_edges(VALUE self, VALUE edges){
22
+ VALUE cIGraph_add_edges(int argc, VALUE *argv, VALUE self){
23
23
 
24
24
  igraph_t *graph;
25
25
  igraph_vector_t edge_v;
26
26
  VALUE vertex;
27
- VALUE object_h;
27
+ VALUE edges;
28
+ VALUE attrs;
29
+ VALUE v_ary;
28
30
  int vid;
29
31
  int code = 0;
32
+ int i;
33
+ igraph_vector_ptr_t edge_attr;
34
+
35
+ igraph_i_attribute_record_t e_attr_rec;
36
+ e_attr_rec.name = "__RUBY__";
37
+ e_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT;
38
+ e_attr_rec.value = (void*)rb_ary_new();
39
+
40
+ rb_scan_args(argc, argv, "11", &edges, &attrs);
30
41
 
31
42
  //Initialize edge vector
32
43
  igraph_vector_init_int(&edge_v,0);
33
- object_h = rb_iv_get(self,"@object_ids");
44
+ igraph_vector_ptr_init(&edge_attr,0);
34
45
 
35
46
  Data_Get_Struct(self, igraph_t, graph);
36
47
 
48
+ v_ary = ((VALUE*)graph->attr)[0];
49
+
37
50
  //Loop through objects in edge Array
38
- vertex = rb_ary_shift(edges);
39
- while(vertex != Qnil){
40
- if(rb_funcall(object_h,rb_intern("has_key?"),1,vertex)){
41
- //If @vertices includes this vertex then look up the vertex number
42
- vid = NUM2INT(rb_hash_aref(object_h,vertex));
51
+ for (i=0; i<RARRAY(edges)->len; i++) {
52
+ vertex = RARRAY(edges)->ptr[i];
53
+ if(rb_ary_includes(v_ary,vertex)){
54
+ vid = cIGraph_get_vertex_id(self, vertex);
43
55
  } else {
44
56
  rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices first");
45
57
  }
46
58
  igraph_vector_push_back(&edge_v,vid);
47
- vertex = rb_ary_shift(edges);
59
+ if (i % 2){
60
+ if (attrs != Qnil){
61
+ rb_ary_push((VALUE)e_attr_rec.value,RARRAY(attrs)->ptr[i/2]);
62
+ } else {
63
+ rb_ary_push((VALUE)e_attr_rec.value,Qnil);
64
+ }
65
+ }
48
66
  }
49
67
 
68
+ igraph_vector_ptr_push_back(&edge_attr, &e_attr_rec);
69
+
50
70
  if(igraph_vector_size(&edge_v) > 0){
51
- code = igraph_add_edges(graph,&edge_v,0);
71
+ code = igraph_add_edges(graph,&edge_v,&edge_attr);
52
72
  }
53
73
 
54
74
  igraph_vector_destroy(&edge_v);
75
+ igraph_vector_ptr_destroy(&edge_attr);
55
76
 
56
77
  return INT2NUM(code);
57
78
 
@@ -76,36 +97,39 @@ VALUE cIGraph_add_vertices(VALUE self, VALUE vs){
76
97
 
77
98
  igraph_t *graph;
78
99
  VALUE vertex;
79
- VALUE object_h;
80
- VALUE id_h;
81
- int vertex_n;
100
+ VALUE v_ary;
82
101
  int code = 0;
83
- int length;
102
+ int to_add;
103
+ int i;
104
+ igraph_vector_ptr_t vertex_attr;
105
+
106
+ igraph_i_attribute_record_t v_attr_rec;
107
+ v_attr_rec.name = "__RUBY__";
108
+ v_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT;
109
+ v_attr_rec.value = (void*)rb_ary_new();
84
110
 
85
- object_h = rb_iv_get(self,"@object_ids");
86
- id_h = rb_iv_get(self,"@id_objects");
87
- length = NUM2INT(rb_funcall(vs, rb_intern("length"),0));
88
- vertex_n = NUM2INT(rb_funcall(object_h,rb_intern("length"),0));
111
+ igraph_vector_ptr_init(&vertex_attr,0);
89
112
 
90
113
  Data_Get_Struct(self, igraph_t, graph);
114
+ v_ary = ((VALUE*)graph->attr)[0];
115
+
116
+ to_add = RARRAY(vs)->len;
91
117
 
92
118
  //Loop through objects in vertex array
93
- vertex = rb_ary_shift(vs);
94
- while(vertex != Qnil){
95
- if(rb_funcall(object_h,rb_intern("has_key?"),1,vertex)){
96
- //If @vertices includes this vertex then raise an error
97
- //Silently ignore
119
+ for (i=0; i<RARRAY(vs)->len; i++) {
120
+ vertex = RARRAY(vs)->ptr[i];
121
+ if(rb_ary_includes(v_ary,vertex)){
122
+ //Silently ignore duplicated additions
98
123
  //rb_raise(cIGraphError, "Vertex already added to graph");
99
- length--;
124
+ to_add--;
100
125
  } else {
101
- //otherwise add a new entry to Hash
102
- rb_hash_aset(object_h,vertex,INT2NUM(vertex_n));
103
- rb_hash_aset(id_h, INT2NUM(vertex_n),vertex);
104
- vertex_n++;
126
+ rb_ary_push((VALUE)v_attr_rec.value,RARRAY(vs)->ptr[i]);
105
127
  }
106
- vertex = rb_ary_shift(vs);
107
128
  }
108
- code = igraph_add_vertices(graph,length,0);
129
+
130
+ igraph_vector_ptr_push_back(&vertex_attr,&v_attr_rec);
131
+
132
+ code = igraph_add_vertices(graph,to_add,&vertex_attr);
109
133
 
110
134
  return INT2NUM(code);
111
135
 
@@ -127,38 +151,48 @@ VALUE cIGraph_add_vertices(VALUE self, VALUE vs){
127
151
  * Note that vertices must have already been added to the graph before
128
152
  * they can be used in an edge (throws a IGraphError otherwise).
129
153
  */
130
- VALUE cIGraph_add_edge(VALUE self, VALUE from, VALUE to){
154
+ VALUE cIGraph_add_edge(int argc, VALUE *argv, VALUE self){
131
155
 
132
156
  igraph_t *graph;
133
157
  igraph_vector_t edge_v;
134
- VALUE object_h;
135
- int vid;
158
+ igraph_vector_ptr_t edge_attr;
159
+
136
160
  int code = 0;
137
161
 
162
+ VALUE v_ary;
163
+ VALUE from;
164
+ VALUE to;
165
+ VALUE attr;
166
+
167
+ igraph_i_attribute_record_t e_attr_rec;
168
+ e_attr_rec.name = "__RUBY__";
169
+ e_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT;
170
+ e_attr_rec.value = (void*)rb_ary_new();
171
+
172
+ rb_scan_args(argc, argv, "21", &from, &to, &attr);
173
+
138
174
  //Initialize edge vector
139
175
  igraph_vector_init_int(&edge_v,0);
140
- object_h = rb_iv_get(self,"@object_ids");
176
+ igraph_vector_ptr_init(&edge_attr,0);
141
177
 
142
178
  Data_Get_Struct(self, igraph_t, graph);
143
179
 
144
- if(rb_funcall(object_h,rb_intern("has_key?"),1,from)){
145
- //If @vertices includes this vertex then look up the vertex number
146
- vid = NUM2INT(rb_hash_aref(object_h,from));
147
- } else {
148
- rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices first");
149
- }
150
- igraph_vector_push_back(&edge_v,vid);
180
+ v_ary = ((VALUE*)graph->attr)[0];
151
181
 
152
- if(rb_funcall(object_h,rb_intern("has_key?"),1,to)){
153
- //If @vertices includes this vertex then look up the vertex number
154
- vid = NUM2INT(rb_hash_aref(object_h,to));
182
+ if(rb_ary_includes(v_ary,from) && rb_ary_includes(v_ary,to)){
183
+ //If graph includes this vertex then look up the vertex number
184
+ igraph_vector_push_back(&edge_v,cIGraph_get_vertex_id(self, from));
185
+ igraph_vector_push_back(&edge_v,cIGraph_get_vertex_id(self, to));
186
+ rb_ary_push((VALUE)e_attr_rec.value,attr);
155
187
  } else {
156
- rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices first");
188
+ rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices");
157
189
  }
158
- igraph_vector_push_back(&edge_v,vid);
159
190
 
160
- code = igraph_add_edges(graph,&edge_v,0);
191
+ igraph_vector_ptr_push_back(&edge_attr,&e_attr_rec);
161
192
 
193
+ code = igraph_add_edges(graph,&edge_v,&edge_attr);
194
+
195
+ igraph_vector_ptr_destroy(&edge_attr);
162
196
  igraph_vector_destroy(&edge_v);
163
197
 
164
198
  return INT2NUM(code);
@@ -184,36 +218,82 @@ VALUE cIGraph_add_edge(VALUE self, VALUE from, VALUE to){
184
218
  VALUE cIGraph_add_vertex(VALUE self, VALUE v){
185
219
 
186
220
  igraph_t *graph;
187
- VALUE vertex;
188
- VALUE object_h;
189
- VALUE id_h;
190
- int vertex_n;
221
+ igraph_vector_ptr_t vertex_attr;
222
+
191
223
  int code = 0;
192
- int length;
193
224
 
194
- object_h = rb_iv_get(self,"@object_ids");
195
- id_h = rb_iv_get(self,"@id_objects");
196
- length = 1;
197
- vertex_n = NUM2INT(rb_funcall(object_h,rb_intern("length"),0));
225
+ VALUE v_ary;
226
+
227
+ igraph_i_attribute_record_t v_attr_rec;
228
+ v_attr_rec.name = "__RUBY__";
229
+ v_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT;
230
+ v_attr_rec.value = (void*)rb_ary_new();
231
+
232
+ igraph_vector_ptr_init(&vertex_attr,0);
198
233
 
199
234
  Data_Get_Struct(self, igraph_t, graph);
200
235
 
236
+ v_ary = ((VALUE*)graph->attr)[0];
237
+
201
238
  //Loop through objects in vertex array
202
- if(rb_funcall(object_h,rb_intern("has_key?"),1,v)){
203
- //If @vertices includes this vertex then raise an error
204
- //Silently ignore
239
+ if(rb_ary_includes(v_ary,v)){
205
240
  //rb_raise(cIGraphError, "Vertex already added to graph");
206
- length--;
241
+ return code;
207
242
  } else {
208
- //otherwise add a new entry to Hash
209
- rb_hash_aset(object_h,v,INT2NUM(vertex_n));
210
- rb_hash_aset(id_h, INT2NUM(vertex_n),v);
211
- vertex_n++;
243
+ rb_ary_push((VALUE)v_attr_rec.value,v);
212
244
  }
213
245
 
214
- if(length != 0)
215
- code = igraph_add_vertices(graph,length,0);
246
+ igraph_vector_ptr_push_back(&vertex_attr,&v_attr_rec);
247
+
248
+ code = igraph_add_vertices(graph,1,&vertex_attr);
216
249
 
217
250
  return INT2NUM(code);
218
251
 
219
252
  }
253
+
254
+ /* call-seq:
255
+ * graph.delete_edge(from,to)
256
+ *
257
+ * Deletes the edge connecting the two vertices given.
258
+ */
259
+ VALUE cIGraph_delete_edge(VALUE self, VALUE from, VALUE to){
260
+
261
+ igraph_t *graph;
262
+ igraph_integer_t eid = 0;
263
+ int from_i;
264
+ int to_i;
265
+
266
+ Data_Get_Struct(self, igraph_t, graph);
267
+
268
+ from_i = cIGraph_get_vertex_id(self,from);
269
+ to_i = cIGraph_get_vertex_id(self,to);
270
+
271
+ igraph_get_eid(graph,&eid,from_i,to_i,1);
272
+
273
+ igraph_delete_edges(graph,igraph_ess_1(eid));
274
+
275
+ return Qnil;
276
+
277
+ }
278
+
279
+ /* call-seq:
280
+ * graph.delete_vertex(v)
281
+ *
282
+ * Delete the vertex specified.
283
+ */
284
+ VALUE cIGraph_delete_vertex(VALUE self, VALUE v){
285
+
286
+ igraph_t *graph;
287
+ igraph_vs_t vs;
288
+
289
+ Data_Get_Struct(self, igraph_t, graph);
290
+
291
+ igraph_vs_1(&vs, cIGraph_get_vertex_id(self,v));
292
+
293
+ igraph_delete_vertices(graph,vs);
294
+
295
+ igraph_vs_destroy(&vs);
296
+
297
+ return Qnil;
298
+
299
+ }
@@ -0,0 +1,758 @@
1
+ #include "igraph.h"
2
+ #include "ruby.h"
3
+ #include "cIGraph.h"
4
+
5
+ /* call-seq:
6
+ * graph[u,v] -> Object
7
+ *
8
+ * Returns the object associated with the edge connecting vertices u and v.
9
+ * Aliased to graph.get_edge_attr(u,v)
10
+ */
11
+ VALUE cIGraph_get_edge_attr(VALUE self, VALUE from, VALUE to){
12
+
13
+ int idx;
14
+ igraph_t *graph;
15
+ VALUE e_ary;
16
+
17
+ Data_Get_Struct(self, igraph_t, graph);
18
+ e_ary = ((VALUE*)graph->attr)[1];
19
+
20
+ idx = NUM2INT(cIGraph_get_eid(self, from, to, 1));
21
+ return rb_ary_entry(e_ary,idx);
22
+
23
+ }
24
+
25
+ /* call-seq:
26
+ * graph[u,v] = w
27
+ *
28
+ * Sets the object associated with the edge connecting vertices u and v.
29
+ * Aliased to graph.set_edge_attr(u,v)
30
+ */
31
+ VALUE cIGraph_set_edge_attr(VALUE self, VALUE from, VALUE to, VALUE attr){
32
+
33
+ int idx;
34
+ igraph_t *graph;
35
+ VALUE e_ary;
36
+
37
+ Data_Get_Struct(self, igraph_t, graph);
38
+ e_ary = ((VALUE*)graph->attr)[1];
39
+
40
+ idx = NUM2INT(cIGraph_get_eid(self, from, to, 1));
41
+ rb_ary_store(e_ary,idx,attr);
42
+
43
+ return Qtrue;
44
+
45
+ }
46
+
47
+ /* call-seq:
48
+ * graph.attributes -> Hash
49
+ *
50
+ * Returns the graph attributes. This is usually only used when reading in
51
+ * graphs from GraphML format. Feel free to use instance variables on the
52
+ * graph object if you like (they won't get copied though!).
53
+ */
54
+ VALUE cIGraph_graph_attributes(VALUE self){
55
+
56
+ igraph_t *graph;
57
+ VALUE hsh;
58
+
59
+ Data_Get_Struct(self, igraph_t, graph);
60
+ hsh = ((VALUE*)graph->attr)[2];
61
+
62
+ return hsh;
63
+
64
+ }
65
+
66
+ igraph_attribute_table_t cIGraph_attribute_table = {
67
+ cIGraph_attribute_init,
68
+ cIGraph_attribute_destroy,
69
+ cIGraph_attribute_copy,
70
+ cIGraph_attribute_add_vertices,
71
+ cIGraph_attribute_delete_vertices,
72
+ cIGraph_attribute_add_edges,
73
+ cIGraph_attribute_delete_edges,
74
+ cIGraph_attribute_permute_edges,
75
+ cIGraph_attribute_get_info,
76
+ cIGraph_attribute_has_attr,
77
+ cIGraph_attribute_get_type,
78
+ cIGraph_get_numeric_graph_attr,
79
+ cIGraph_get_string_graph_attr,
80
+ cIGraph_get_numeric_vertex_attr,
81
+ cIGraph_get_string_vertex_attr,
82
+ cIGraph_get_numeric_edge_attr,
83
+ cIGraph_get_string_edge_attr,
84
+ };
85
+
86
+ int cIGraph_attribute_init(igraph_t *graph, igraph_vector_ptr_t *attr) {
87
+
88
+ VALUE* attrs;
89
+ int i;
90
+ VALUE key;
91
+ VALUE value;
92
+
93
+ attrs = ALLOC_N(VALUE, 3);
94
+
95
+ if(!attrs)
96
+ IGRAPH_ERROR("Error allocating Arrays\n", IGRAPH_ENOMEM);
97
+
98
+ //[0] is vertex array, [1] is edge array, [2] is graph attr
99
+ attrs[0] = rb_ary_new();
100
+ attrs[1] = rb_ary_new();
101
+ attrs[2] = rb_hash_new();
102
+
103
+ if(attr){
104
+ for(i=0;i<igraph_vector_ptr_size(attr);i++){
105
+ igraph_i_attribute_record_t *attr_rec;
106
+ char *s;
107
+ attr_rec = VECTOR(*attr)[i];
108
+ key = rb_str_new2(attr_rec->name);
109
+ switch (attr_rec->type) {
110
+ case IGRAPH_ATTRIBUTE_NUMERIC:
111
+ value=rb_float_new((double)VECTOR(*(igraph_vector_t*)attr_rec->value)[0]);
112
+ break;
113
+ case IGRAPH_ATTRIBUTE_STRING:
114
+ igraph_strvector_get((igraph_strvector_t*)attr_rec->value, 0, &s);
115
+ value=rb_str_new2(s);
116
+ break;
117
+ default:
118
+ IGRAPH_WARNING("unsupported attribute type (not string and not numeric)");
119
+ value=0;
120
+ break;
121
+ }
122
+ if (value){
123
+ rb_hash_aset((VALUE)attrs[2],key,value);
124
+ }
125
+ }
126
+ }
127
+
128
+ graph->attr = attrs;
129
+
130
+ return IGRAPH_SUCCESS;
131
+ }
132
+
133
+ /* Destruction */
134
+ void cIGraph_attribute_destroy(igraph_t *graph) {
135
+ free(graph->attr);
136
+ return;
137
+ }
138
+
139
+ /* Copying */
140
+
141
+ int replace_i(VALUE key, VALUE val, VALUE hash){
142
+ if (key != Qundef) {
143
+ rb_hash_aset(hash, key, val);
144
+ }
145
+
146
+ //return ST_CONTINUE;
147
+ return 0;
148
+ }
149
+
150
+
151
+ int cIGraph_attribute_copy(igraph_t *to, const igraph_t *from) {
152
+
153
+ #ifdef DEBUG
154
+ printf("Entering cIGraph_attribute_copy\n");
155
+ #endif
156
+
157
+ VALUE* attrs;
158
+ VALUE vertex_array = ((VALUE*)from->attr)[0];
159
+ VALUE edge_array = ((VALUE*)from->attr)[1];
160
+ VALUE graph_attr = ((VALUE*)from->attr)[2];
161
+
162
+ attrs = ALLOC_N(VALUE, 3);
163
+
164
+ attrs[0] = rb_ary_dup(vertex_array);
165
+ attrs[1] = rb_ary_dup(edge_array);
166
+ attrs[2] = rb_hash_new();
167
+
168
+ rb_hash_foreach(graph_attr, replace_i, attrs[2]);
169
+
170
+ to->attr = attrs;
171
+
172
+ #ifdef DEBUG
173
+ printf("Leaving cIGraph_attribute_copy\n");
174
+ #endif
175
+
176
+ return IGRAPH_SUCCESS;
177
+ }
178
+
179
+ /* Adding vertices */
180
+ int cIGraph_attribute_add_vertices(igraph_t *graph, long int nv, igraph_vector_ptr_t *attr) {
181
+
182
+ #ifdef DEBUG
183
+ printf("Entering cIGraph_attribute_add_vertices\n");
184
+ #endif
185
+
186
+ int i,j;
187
+ VALUE vertex_array = ((VALUE*)graph->attr)[0];
188
+ VALUE values;
189
+
190
+ if(attr){
191
+ if(igraph_vector_ptr_size(attr) > 0 && ((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->type == IGRAPH_ATTRIBUTE_PY_OBJECT){
192
+
193
+ values = (VALUE)((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->value;
194
+ Check_Type(values, T_ARRAY);
195
+ for(i=0;i<RARRAY(values)->len;i++){
196
+ rb_ary_push(vertex_array, RARRAY(values)->ptr[i]);
197
+ }
198
+ //Otherwise read each attriute into hashes and use those
199
+ } else {
200
+ for(i=0;i<nv;i++){
201
+
202
+ VALUE record;
203
+ igraph_i_attribute_record_t *attr_rec;
204
+ char *s;
205
+ record = rb_hash_new();
206
+
207
+ //For when no attributes are given
208
+ if(igraph_vector_ptr_size(attr) == 0){
209
+ record = INT2NUM(i+1);
210
+ }
211
+
212
+ for (j=0; j<igraph_vector_ptr_size(attr); j++) {
213
+ VALUE key;
214
+ VALUE value;
215
+ //Add key value pair
216
+ attr_rec = VECTOR(*attr)[j];
217
+ key = rb_str_new2(attr_rec->name);
218
+ switch (attr_rec->type) {
219
+ case IGRAPH_ATTRIBUTE_NUMERIC:
220
+ value=rb_float_new((double)VECTOR(*(igraph_vector_t*)attr_rec->value)[i]);
221
+ break;
222
+ case IGRAPH_ATTRIBUTE_STRING:
223
+ igraph_strvector_get((igraph_strvector_t*)attr_rec->value, i, &s);
224
+ value=rb_str_new2(s);
225
+ break;
226
+ default:
227
+ IGRAPH_WARNING("unsupported attribute type (not string and not numeric)");
228
+ value=Qnil;
229
+ break;
230
+ }
231
+ rb_hash_aset(record,key,value);
232
+ }
233
+ rb_ary_push(vertex_array,record);
234
+ }
235
+ }
236
+ }
237
+
238
+ #ifdef DEBUG
239
+ printf("Leaving cIGraph_attribute_add_vertices\n");
240
+ #endif
241
+
242
+ return IGRAPH_SUCCESS;
243
+ }
244
+
245
+ /* Deleting vertices */
246
+ void cIGraph_attribute_delete_vertices(igraph_t *graph,
247
+ const igraph_vector_t *eidx,
248
+ const igraph_vector_t *vidx) {
249
+
250
+ #ifdef DEBUG
251
+ printf("Entering cIGraph_attribute_delete_vertices\n");
252
+ #endif
253
+
254
+ int i;
255
+ VALUE vertex_array = ((VALUE*)graph->attr)[0];
256
+ VALUE edge_array = ((VALUE*)graph->attr)[1];
257
+
258
+ VALUE n_v_ary = rb_ary_new();
259
+ VALUE n_e_ary = rb_ary_new();
260
+
261
+ for(i=0;i<igraph_vector_size(vidx);i++){
262
+ if(VECTOR(*vidx)[i] != 0)
263
+ rb_ary_store(n_v_ary,VECTOR(*vidx)[i]-1,rb_ary_entry(vertex_array,i));
264
+ }
265
+ for(i=0;i<igraph_vector_size(eidx);i++){
266
+ if(VECTOR(*eidx)[i] != 0)
267
+ rb_ary_store(n_e_ary,VECTOR(*eidx)[i]-1,rb_ary_entry(edge_array,i));
268
+ }
269
+
270
+ ((VALUE*)graph->attr)[0] = n_v_ary;
271
+ ((VALUE*)graph->attr)[1] = n_e_ary;
272
+
273
+ #ifdef DEBUG
274
+ printf("Leaving cIGraph_attribute_delete_vertices\n");
275
+ #endif
276
+
277
+ return;
278
+ }
279
+
280
+ /* Adding edges */
281
+ int cIGraph_attribute_add_edges(igraph_t *graph,
282
+ const igraph_vector_t *edges,
283
+ igraph_vector_ptr_t *attr) {
284
+
285
+ #ifdef DEBUG
286
+ printf("Entering cIGraph_attribute_add_edges\n");
287
+ #endif
288
+
289
+ int i,j;
290
+ VALUE edge_array = ((VALUE*)graph->attr)[1];
291
+ VALUE values;
292
+
293
+ if(attr){
294
+ //If the only record is of type PY_OBJ then use the values as attributes
295
+ if(((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->type == IGRAPH_ATTRIBUTE_PY_OBJECT){
296
+ values = (VALUE)((igraph_i_attribute_record_t*)VECTOR(*attr)[0])->value;
297
+ Check_Type(values, T_ARRAY);
298
+ for(i=0;i<RARRAY(values)->len;i++){
299
+ rb_ary_push(edge_array, RARRAY(values)->ptr[i]);
300
+ }
301
+ //Otherwise read each attriute into hashes and use those
302
+ } else {
303
+ for(i=0;i<igraph_vector_size(edges)/2;i++){
304
+ VALUE record;
305
+ igraph_i_attribute_record_t *attr_rec;
306
+ char *s;
307
+ record = rb_hash_new();
308
+ for (j=0; j<igraph_vector_ptr_size(attr); j++) {
309
+ VALUE key;
310
+ VALUE value;
311
+ //Add key value pair
312
+ attr_rec = VECTOR(*attr)[j];
313
+ key = rb_str_new2(attr_rec->name);
314
+ switch (attr_rec->type) {
315
+ case IGRAPH_ATTRIBUTE_NUMERIC:
316
+ value=rb_float_new((double)VECTOR(*(igraph_vector_t*)attr_rec->value)[i]);
317
+ break;
318
+ case IGRAPH_ATTRIBUTE_STRING:
319
+ igraph_strvector_get((igraph_strvector_t*)attr_rec->value, i, &s);
320
+ value=rb_str_new2(s);
321
+ break;
322
+ default:
323
+ IGRAPH_WARNING("unsupported attribute type (not string and not numeric)");
324
+ value=Qnil;
325
+ break;
326
+ }
327
+ rb_hash_aset(record,key,value);
328
+ }
329
+ rb_ary_push(edge_array,record);
330
+ }
331
+ }
332
+ }
333
+
334
+ #ifdef DEBUG
335
+ printf("Leaving cIGraph_attribute_add_edges\n");
336
+ #endif
337
+
338
+ return IGRAPH_SUCCESS;
339
+ }
340
+
341
+ /* Deleting edges */
342
+ void cIGraph_attribute_delete_edges(igraph_t *graph, const igraph_vector_t *idx) {
343
+
344
+ #ifdef DEBUG
345
+ printf("Entering cIGraph_attribute_delete_edges\n");
346
+ #endif
347
+
348
+ int i;
349
+ VALUE edge_array = ((VALUE*)graph->attr)[1];
350
+ VALUE n_e_ary = rb_ary_new();
351
+
352
+ for(i=0;i<igraph_vector_size(idx);i++){
353
+ if(VECTOR(*idx)[i] != 0)
354
+ rb_ary_store(n_e_ary,VECTOR(*idx)[i]-1,rb_ary_entry(edge_array,i));
355
+ }
356
+
357
+ ((VALUE*)graph->attr)[1] = n_e_ary;
358
+
359
+ #ifdef DEBUG
360
+ printf("Leaving cIGraph_attribute_delete_edges\n");
361
+ #endif
362
+
363
+ return;
364
+ }
365
+
366
+ /* Permuting edges */
367
+ int cIGraph_attribute_permute_edges(igraph_t *graph,
368
+ const igraph_vector_t *idx) {
369
+
370
+ #ifdef DEBUG
371
+ printf("Entering cIGraph_attribute_permute_edges\n");
372
+ #endif
373
+
374
+ int i;
375
+ VALUE edge_array = ((VALUE*)graph->attr)[1];
376
+ VALUE n_e_ary = rb_ary_new();
377
+
378
+ for(i=0;i<igraph_vector_size(idx);i++){
379
+ rb_ary_push(n_e_ary,rb_ary_entry(edge_array,VECTOR(*idx)[i]));
380
+ }
381
+
382
+ ((VALUE*)graph->attr)[1] = n_e_ary;
383
+
384
+ #ifdef DEBUG
385
+ printf("Leaving cIGraph_attribute_permute_edges\n");
386
+ #endif
387
+
388
+ return 0;
389
+ }
390
+
391
+ VALUE keys_to_strvec(VALUE data, VALUE arr){
392
+
393
+ VALUE key = rb_ary_entry(data, 0);
394
+ VALUE val = rb_ary_entry(data, 1);
395
+
396
+ VALUE rb_names = rb_ary_entry(arr, 0);
397
+ VALUE rb_types = rb_ary_entry(arr, 1);
398
+
399
+ VALUE str = StringValue(key);
400
+
401
+ rb_ary_push(rb_names,str);
402
+
403
+ if(TYPE(val) == T_STRING){
404
+ rb_ary_push(rb_types,INT2FIX(IGRAPH_ATTRIBUTE_STRING));
405
+ } else if (TYPE(val) == T_FLOAT || TYPE(val) == T_FIXNUM){
406
+ rb_ary_push(rb_types,INT2FIX(IGRAPH_ATTRIBUTE_NUMERIC));
407
+ } else {
408
+ rb_ary_push(rb_types,INT2FIX(IGRAPH_ATTRIBUTE_PY_OBJECT));
409
+ }
410
+
411
+ return data;
412
+
413
+ }
414
+
415
+ /* Getting attribute names and types */
416
+ int cIGraph_attribute_get_info(const igraph_t *graph,
417
+ igraph_strvector_t *gnames,
418
+ igraph_vector_t *gtypes,
419
+ igraph_strvector_t *vnames,
420
+ igraph_vector_t *vtypes,
421
+ igraph_strvector_t *enames,
422
+ igraph_vector_t *etypes) {
423
+
424
+
425
+ #ifdef DEBUG
426
+ printf("Entering cIGraph_attribute_get_info\n");
427
+ #endif
428
+
429
+ igraph_strvector_t *names[3] = { vnames, enames, gnames };
430
+ igraph_vector_t *types[3] = { vtypes, etypes, gtypes };
431
+
432
+ long int i,j;
433
+
434
+ for (i=0; i<3; i++) {
435
+
436
+ igraph_strvector_t *n = names[i];
437
+ igraph_vector_t *t = types[i];
438
+
439
+ VALUE rb_names = rb_ary_new();
440
+ VALUE rb_types = rb_ary_new();
441
+
442
+ VALUE obj_hash;
443
+
444
+ //Graph attributes are different
445
+ if (i != 2){
446
+
447
+ VALUE store = ((VALUE*)graph->attr)[i];
448
+ VALUE obj = RARRAY(store)->ptr[0];
449
+
450
+ obj_hash = Qnil;
451
+ if(rb_funcall(obj, rb_intern("respond_to?"), 1, rb_str_new2("to_hash")) == Qtrue){
452
+ obj_hash = rb_funcall(obj, rb_intern("to_hash"), 0);
453
+ }
454
+ } else {
455
+ obj_hash = ((VALUE*)graph->attr)[2];
456
+ }
457
+
458
+ if(!NIL_P(obj_hash)){
459
+ //Take the keys of the hash, convert to strings and put in vector n
460
+ rb_iterate(rb_each, obj_hash, keys_to_strvec, rb_ary_new3(2,rb_names,rb_types));
461
+ }
462
+
463
+ //Push names onto n and types onto t
464
+ for(j=0;j<RARRAY(rb_names)->len;j++){
465
+ igraph_strvector_add(n, RSTRING(RARRAY(rb_names)->ptr[j])->ptr);
466
+ igraph_vector_push_back(t, NUM2INT(RARRAY(rb_types)->ptr[j]));
467
+ }
468
+
469
+ }
470
+
471
+ #ifdef DEBUG
472
+ printf("Leaving cIGraph_attribute_get_info\n");
473
+ #endif
474
+
475
+ return 0;
476
+
477
+ }
478
+
479
+ /* Checks whether the graph has a graph/vertex/edge attribute with the given name */
480
+ igraph_bool_t cIGraph_attribute_has_attr(const igraph_t *graph,
481
+ igraph_attribute_elemtype_t type,
482
+ const char* name) {
483
+
484
+ #ifdef DEBUG
485
+ printf("Entering cIGraph_attribute_has_attr\n");
486
+ #endif
487
+
488
+ long int attrnum;
489
+ igraph_bool_t res = 0;
490
+ VALUE obj;
491
+
492
+ switch (type) {
493
+ case IGRAPH_ATTRIBUTE_GRAPH: attrnum=0; break;
494
+ case IGRAPH_ATTRIBUTE_VERTEX: attrnum=1; break;
495
+ case IGRAPH_ATTRIBUTE_EDGE: attrnum=2; break;
496
+ default: return 0; break;
497
+ }
498
+
499
+ obj = ((VALUE*)graph->attr)[attrnum];
500
+ if (attrnum != 2)
501
+ obj = RARRAY(obj)->ptr[0];
502
+
503
+ if(rb_funcall(obj,rb_intern("include?"), 1, rb_str_new2(name))){
504
+ res = 1;
505
+ }
506
+
507
+ #ifdef DEBUG
508
+ printf("Leaving cIGraph_attribute_has_attr\n");
509
+ #endif
510
+
511
+ return res;
512
+ }
513
+
514
+ /* Returns the type of a given attribute */
515
+ int cIGraph_attribute_get_type(const igraph_t *graph,
516
+ igraph_attribute_type_t *type,
517
+ igraph_attribute_elemtype_t elemtype,
518
+ const char *name) {
519
+
520
+ #ifdef DEBUG
521
+ printf("Entering cIGraph_attribute_get_type\n");
522
+ #endif
523
+
524
+ long int attrnum;
525
+ VALUE obj;
526
+ VALUE val;
527
+
528
+ switch (elemtype) {
529
+ case IGRAPH_ATTRIBUTE_GRAPH: attrnum=0; break;
530
+ case IGRAPH_ATTRIBUTE_VERTEX: attrnum=1; break;
531
+ case IGRAPH_ATTRIBUTE_EDGE: attrnum=2; break;
532
+ default: return 0; break;
533
+ }
534
+
535
+ obj = ((VALUE*)graph->attr)[attrnum];
536
+ if (attrnum != 2)
537
+ obj = RARRAY(obj)->ptr[0];
538
+
539
+ if(rb_funcall(obj,rb_intern("includes"), rb_str_new2(name))){
540
+ val = rb_hash_aref(obj,rb_str_new2(name));
541
+ if (TYPE(val) == T_STRING){
542
+ *type = IGRAPH_ATTRIBUTE_STRING;
543
+ } else if (TYPE(val) == T_FIXNUM || TYPE(val) == T_FLOAT){
544
+ *type = IGRAPH_ATTRIBUTE_NUMERIC;
545
+ } else {
546
+ *type = IGRAPH_ATTRIBUTE_PY_OBJECT;
547
+ }
548
+ }
549
+
550
+ #ifdef DEBUG
551
+ printf("Leaving cIGraph_attribute_get_type\n");
552
+ #endif
553
+
554
+ return 0;
555
+
556
+ }
557
+
558
+ /* Getting numeric graph attributes */
559
+ int cIGraph_get_numeric_graph_attr(const igraph_t *graph,
560
+ const char *name, igraph_vector_t *value) {
561
+
562
+ #ifdef DEBUG
563
+ printf("Entering cIGraph_get_numeric_graph_attr\n");
564
+ #endif
565
+
566
+ VALUE val;
567
+
568
+ val = rb_hash_aref(((VALUE*)graph->attr)[2],rb_str_new2(name));
569
+ VECTOR(*value)[0] = NUM2DBL(val);
570
+
571
+ #ifdef DEBUG
572
+ printf("Leaving cIGraph_get_numeric_graph_attr\n");
573
+ #endif
574
+
575
+ return 0;
576
+ }
577
+
578
+ /* Getting string graph attributes */
579
+ int cIGraph_get_string_graph_attr(const igraph_t *graph,
580
+ const char *name, igraph_strvector_t *value) {
581
+
582
+ #ifdef DEBUG
583
+ printf("Entering cIGraph_get_string_graph_attr\n");
584
+ #endif
585
+
586
+ VALUE val;
587
+
588
+ val = rb_hash_aref(((VALUE*)graph->attr)[2],rb_str_new2(name));
589
+ igraph_strvector_set(value,0,RSTRING(val)->ptr);
590
+
591
+ #ifdef DEBUG
592
+ printf("Leaving cIGraph_get_string_graph_attr\n");
593
+ #endif
594
+
595
+ return 0;
596
+ }
597
+
598
+ /* Getting numeric vertex attributes */
599
+ int cIGraph_get_numeric_vertex_attr(const igraph_t *graph,
600
+ const char *name,
601
+ igraph_vs_t vs,
602
+ igraph_vector_t *value) {
603
+
604
+ #ifdef DEBUG
605
+ printf("Entering cIGraph_get_numeric_vertex_attr\n");
606
+ #endif
607
+
608
+ VALUE array = ((VALUE*)graph->attr)[0];
609
+ VALUE val, vertex;
610
+ igraph_vit_t it;
611
+ int i = 0;
612
+
613
+ IGRAPH_CHECK(igraph_vit_create(graph, vs, &it));
614
+ IGRAPH_FINALLY(igraph_vit_destroy, &it);
615
+ IGRAPH_CHECK(igraph_vector_resize(value, IGRAPH_VIT_SIZE(it)));
616
+
617
+ while(!IGRAPH_VIT_END(it)){
618
+ vertex = RARRAY(array)->ptr[(int)IGRAPH_VIT_GET(it)];
619
+ val = rb_hash_aref(vertex,rb_str_new2(name));
620
+
621
+ if(val == Qnil)
622
+ val = rb_float_new(NAN);
623
+
624
+ VECTOR(*value)[i] = NUM2DBL(val);
625
+ IGRAPH_VIT_NEXT(it);
626
+ i++;
627
+ }
628
+
629
+ igraph_vit_destroy(&it);
630
+ IGRAPH_FINALLY_CLEAN(1);
631
+
632
+ #ifdef DEBUG
633
+ printf("Leaving cIGraph_get_numeric_vertex_attr\n");
634
+ #endif
635
+
636
+ return 0;
637
+ }
638
+
639
+ /* Getting string vertex attributes */
640
+ int cIGraph_get_string_vertex_attr(const igraph_t *graph,
641
+ const char *name,
642
+ igraph_vs_t vs,
643
+ igraph_strvector_t *value) {
644
+
645
+ #ifdef DEBUG
646
+ printf("Entering cIGraph_get_string_vertex_attr\n");
647
+ #endif
648
+
649
+ VALUE array = ((VALUE*)graph->attr)[0];
650
+ VALUE val, vertex;
651
+ igraph_vit_t it;
652
+ int i=0;
653
+
654
+ IGRAPH_CHECK(igraph_vit_create(graph, vs, &it));
655
+ IGRAPH_FINALLY(igraph_vit_destroy, &it);
656
+ IGRAPH_CHECK(igraph_strvector_resize(value, IGRAPH_VIT_SIZE(it)));
657
+
658
+ while(!IGRAPH_VIT_END(it)){
659
+ vertex = RARRAY(array)->ptr[(int)IGRAPH_VIT_GET(it)];
660
+ val = rb_hash_aref(vertex,rb_str_new2(name));
661
+
662
+ if(val == Qnil)
663
+ val = rb_str_new2("");
664
+
665
+ igraph_strvector_set(value,i,RSTRING(val)->ptr);
666
+ IGRAPH_VIT_NEXT(it);
667
+ i++;
668
+ }
669
+
670
+ igraph_vit_destroy(&it);
671
+ IGRAPH_FINALLY_CLEAN(1);
672
+
673
+ #ifdef DEBUG
674
+ printf("Leaving cIGraph_get_string_vertex_attr\n");
675
+ #endif
676
+
677
+ return 0;
678
+ }
679
+
680
+ /* Getting numeric edge attributes */
681
+ int cIGraph_get_numeric_edge_attr(const igraph_t *graph,
682
+ const char *name,
683
+ igraph_es_t es,
684
+ igraph_vector_t *value) {
685
+
686
+ #ifdef DEBUG
687
+ printf("Entering cIGraph_get_numeric_edge_attr\n");
688
+ #endif
689
+
690
+ VALUE array = ((VALUE*)graph->attr)[1];
691
+ VALUE val, vertex;
692
+ igraph_eit_t it;
693
+ int i = 0;
694
+
695
+ IGRAPH_CHECK(igraph_eit_create(graph, es, &it));
696
+ IGRAPH_FINALLY(igraph_eit_destroy, &it);
697
+ IGRAPH_CHECK(igraph_vector_resize(value, IGRAPH_EIT_SIZE(it)));
698
+
699
+ while(!IGRAPH_EIT_END(it)){
700
+ vertex = RARRAY(array)->ptr[(int)IGRAPH_EIT_GET(it)];
701
+ val = rb_hash_aref(vertex,rb_str_new2(name));
702
+
703
+ if(val == Qnil)
704
+ val = rb_float_new(NAN);
705
+
706
+ VECTOR(*value)[i] = NUM2DBL(val);
707
+ IGRAPH_EIT_NEXT(it);
708
+ i++;
709
+ }
710
+
711
+ igraph_eit_destroy(&it);
712
+ IGRAPH_FINALLY_CLEAN(1);
713
+
714
+ #ifdef DEBUG
715
+ printf("Leaving cIGraph_get_numeric_edge_attr\n");
716
+ #endif
717
+
718
+ return 0;
719
+ }
720
+
721
+ /* Getting string edge attributes */
722
+ int cIGraph_get_string_edge_attr(const igraph_t *graph,
723
+ const char *name,
724
+ igraph_es_t es,
725
+ igraph_strvector_t *value) {
726
+
727
+ #ifdef DEBUG
728
+ printf("Entering cIGraph_get_string_edge_attr\n");
729
+ #endif
730
+
731
+ VALUE array = ((VALUE*)graph->attr)[1];
732
+ VALUE val, vertex;
733
+ igraph_eit_t it;
734
+ int i=0;
735
+
736
+ IGRAPH_CHECK(igraph_eit_create(graph, es, &it));
737
+ IGRAPH_FINALLY(igraph_eit_destroy, &it);
738
+ IGRAPH_CHECK(igraph_strvector_resize(value, IGRAPH_EIT_SIZE(it)));
739
+
740
+ while(!IGRAPH_EIT_END(it)){
741
+ vertex = RARRAY(array)->ptr[(int)IGRAPH_EIT_GET(it)];
742
+ val = rb_hash_aref(vertex,rb_str_new2(name));
743
+ if(val == Qnil)
744
+ val = rb_str_new2("");
745
+ igraph_strvector_set(value,i,RSTRING(val)->ptr);
746
+ IGRAPH_EIT_NEXT(it);
747
+ i++;
748
+ }
749
+
750
+ igraph_eit_destroy(&it);
751
+ IGRAPH_FINALLY_CLEAN(1);
752
+
753
+ #ifdef DEBUG
754
+ printf("Leaving cIGraph_get_string_edge_attr\n");
755
+ #endif
756
+
757
+ return 0;
758
+ }