/src/igraph/src/graph/cattributes.c
Line | Count | Source |
1 | | /* |
2 | | igraph library. |
3 | | Copyright (C) 2005-2012 Gabor Csardi <csardi.gabor@gmail.com> |
4 | | 334 Harvard street, Cambridge, MA 02139 USA |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 2 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | GNU General Public License for more details. |
14 | | |
15 | | You should have received a copy of the GNU General Public License |
16 | | along with this program; if not, write to the Free Software |
17 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
18 | | 02110-1301 USA |
19 | | |
20 | | */ |
21 | | |
22 | | #include "igraph_attributes.h" |
23 | | #include "igraph_memory.h" |
24 | | #include "igraph_interface.h" |
25 | | #include "igraph_random.h" |
26 | | |
27 | | #include <string.h> |
28 | | |
29 | | /* An attribute is either a numeric vector (vector_t), a boolean vector |
30 | | * (vector_bool_t) or a string vector (strvector_t). |
31 | | * The attribute itself is stored in a struct igraph_attribute_record_t. There |
32 | | * is one such object for each attribute. The igraph_t has a pointer to an |
33 | | * igraph_i_cattribute_t, which contains three igraph_attribute_vector_list_t's, |
34 | | * each holding pointers to igraph_attribute_record_t objects. */ |
35 | | |
36 | | typedef struct igraph_i_cattributes_t { |
37 | | igraph_attribute_record_list_t gal; |
38 | | igraph_attribute_record_list_t val; |
39 | | igraph_attribute_record_list_t eal; |
40 | | } igraph_i_cattributes_t; |
41 | | |
42 | | /* |
43 | | * Finds an attribute with the given name in an attribute record list, and |
44 | | * returns the index of the record in the list, or -1 if there was no such |
45 | | * attribute. |
46 | | */ |
47 | | static igraph_int_t igraph_i_cattribute_find_index( |
48 | | const igraph_attribute_record_list_t *attrs, const char *name |
49 | 31.1M | ) { |
50 | 31.1M | igraph_int_t n = igraph_attribute_record_list_size(attrs); |
51 | 38.3M | for (igraph_int_t i = 0; i < n; i++) { |
52 | 38.2M | const igraph_attribute_record_t *rec = igraph_attribute_record_list_get_ptr(attrs, i); |
53 | 38.2M | if (!strcmp(rec->name, name)) { |
54 | 31.0M | return i; |
55 | 31.0M | } |
56 | 38.2M | } |
57 | 123k | return -1; |
58 | 31.1M | } |
59 | | |
60 | | /* |
61 | | * Finds an attribute with the given name in an attribute record list, and |
62 | | * returns the attribute record or NULL if there was no such attribute. |
63 | | * Optionally, the type of the attribute can be enforced; use |
64 | | * IGRAPH_ATTRIBUTE_UNSPECIFIED if you do not care about the type. |
65 | | */ |
66 | | static igraph_attribute_record_t* igraph_i_cattribute_find( |
67 | | igraph_attribute_record_list_t *attrs, const char *name, |
68 | | igraph_attribute_type_t type |
69 | 31.0M | ) { |
70 | 31.0M | igraph_int_t index = igraph_i_cattribute_find_index(attrs, name); |
71 | 31.0M | igraph_attribute_record_t *rec; |
72 | | |
73 | 31.0M | if (index >= 0) { |
74 | 31.0M | rec = igraph_attribute_record_list_get_ptr(attrs, index); |
75 | 31.0M | if (type == IGRAPH_ATTRIBUTE_UNSPECIFIED || type == rec->type) { |
76 | 31.0M | return rec; |
77 | 31.0M | } |
78 | 31.0M | } |
79 | | |
80 | 6.91k | return NULL; |
81 | 31.0M | } |
82 | | |
83 | | /* |
84 | | * Same as igraph_i_cattribute_find(), but suitable for const attribute record |
85 | | * lists. |
86 | | */ |
87 | | static const igraph_attribute_record_t* igraph_i_cattribute_find_const( |
88 | | const igraph_attribute_record_list_t *attrs, const char *name, |
89 | | igraph_attribute_type_t type |
90 | 6.60k | ) { |
91 | 6.60k | igraph_int_t index = igraph_i_cattribute_find_index(attrs, name); |
92 | 6.60k | const igraph_attribute_record_t *rec; |
93 | | |
94 | 6.60k | if (index >= 0) { |
95 | 6.60k | rec = igraph_attribute_record_list_get_ptr(attrs, index); |
96 | 6.60k | if (type == IGRAPH_ATTRIBUTE_UNSPECIFIED || type == rec->type) { |
97 | 6.60k | return rec; |
98 | 6.60k | } |
99 | 6.60k | } |
100 | | |
101 | 0 | return NULL; |
102 | 6.60k | } |
103 | | |
104 | | /* |
105 | | * Finds an attribute with the given name in an attribute record list, and |
106 | | * returns the attribute record in an output argument. Returns an error code |
107 | | * if there is no such attribute. Optionally, the type of the attribute can be |
108 | | * enforced; use IGRAPH_ATTRIBUTE_UNSPECIFIED if you do not care about the type. |
109 | | */ |
110 | | static igraph_error_t igraph_i_cattribute_find_or_return( |
111 | | igraph_attribute_record_list_t *attrs, const char *name, |
112 | | igraph_attribute_type_t type, igraph_attribute_record_t **ptr |
113 | 31.0M | ) { |
114 | 31.0M | igraph_attribute_record_t *rec; |
115 | | |
116 | 31.0M | rec = igraph_i_cattribute_find(attrs, name, IGRAPH_ATTRIBUTE_UNSPECIFIED); |
117 | 31.0M | if (!rec) { |
118 | 0 | IGRAPH_ERRORF("Attribute '%s' does not exist.", IGRAPH_EINVAL, name); |
119 | 0 | } |
120 | | |
121 | 31.0M | if (type != IGRAPH_ATTRIBUTE_UNSPECIFIED) { |
122 | 30.9M | IGRAPH_CHECK(igraph_attribute_record_check_type(rec, type)); |
123 | 30.9M | } |
124 | | |
125 | 31.0M | if (ptr) { |
126 | 31.0M | *ptr = rec; |
127 | 31.0M | } |
128 | | |
129 | 31.0M | return IGRAPH_SUCCESS; |
130 | 31.0M | } |
131 | | |
132 | | /* |
133 | | * Finds an attribute with the given name in an attribute record list, and |
134 | | * returns the attribute record in an output argument. Creates a new attribute |
135 | | * with the given name if there is no such attribute. The type of the attribute |
136 | | * needs to be specified so we can create the appropriate value vector if needed. |
137 | | * You can specify a length; when the existing value vector for the attribute |
138 | | * is shorter than this length, it will be extended to ensure that it has at |
139 | | * least this many elements. You can pass 0 as the length if you do not want to |
140 | | * expand value vectors. |
141 | | */ |
142 | | static igraph_error_t igraph_i_cattribute_find_or_create( |
143 | | igraph_attribute_record_list_t *attrs, |
144 | | const char *name, igraph_attribute_type_t type, |
145 | | igraph_int_t length, |
146 | | igraph_attribute_record_t **ptr |
147 | 6.91k | ) { |
148 | 6.91k | igraph_attribute_record_t *rec; |
149 | | |
150 | 6.91k | rec = igraph_i_cattribute_find(attrs, name, IGRAPH_ATTRIBUTE_UNSPECIFIED); |
151 | 6.91k | if (rec) { |
152 | 0 | if (type != IGRAPH_ATTRIBUTE_UNSPECIFIED) { |
153 | 0 | IGRAPH_CHECK(igraph_attribute_record_check_type(rec, type)); |
154 | 0 | } |
155 | 6.91k | } else { |
156 | 6.91k | IGRAPH_CHECK(igraph_attribute_record_list_push_back_new(attrs, &rec)); |
157 | 6.91k | IGRAPH_CHECK(igraph_attribute_record_set_name(rec, name)); |
158 | 6.91k | IGRAPH_CHECK(igraph_attribute_record_set_type(rec, type)); |
159 | 6.91k | } |
160 | | |
161 | 6.91k | if (length > 0 && igraph_attribute_record_size(rec) < length) { |
162 | 0 | IGRAPH_CHECK(igraph_attribute_record_resize(rec, length)); |
163 | 0 | } |
164 | | |
165 | 6.91k | if (ptr) { |
166 | 0 | *ptr = rec; |
167 | 0 | } |
168 | | |
169 | 6.91k | return IGRAPH_SUCCESS; |
170 | 6.91k | } |
171 | | |
172 | | /* |
173 | | * Restores attribute vector lengths to their original size after a failure. |
174 | | * This function assumes that none of the attribute vectors are shorter than origlen. |
175 | | * Some may be longer due to a partially completed size extension: these will be |
176 | | * shrunk to their original size. |
177 | | */ |
178 | | static void igraph_i_cattribute_revert_attribute_vector_sizes( |
179 | 91 | igraph_attribute_record_list_t *attrlist, igraph_int_t origlen) { |
180 | | |
181 | 91 | igraph_int_t no_of_attrs = igraph_attribute_record_list_size(attrlist); |
182 | 488 | for (igraph_int_t i = 0; i < no_of_attrs; i++) { |
183 | 397 | igraph_attribute_record_t *rec = igraph_attribute_record_list_get_ptr(attrlist, i); |
184 | 397 | IGRAPH_ASSERT(igraph_attribute_record_size(rec) >= origlen); |
185 | 397 | if (igraph_attribute_record_resize(rec, origlen) != IGRAPH_SUCCESS) { |
186 | | /* We should have succeeded for known attribute types because we |
187 | | * always shrink the vector so throw a fatal error if this happens */ |
188 | 0 | IGRAPH_FATAL("Unknown attribute type encountered."); |
189 | 0 | } |
190 | 397 | } |
191 | 91 | } |
192 | | |
193 | | static igraph_error_t igraph_i_cattribute_init( |
194 | | igraph_t *graph, const igraph_attribute_record_list_t *attr |
195 | 2.27k | ) { |
196 | 2.27k | igraph_i_cattributes_t *nattr; |
197 | | |
198 | 2.27k | nattr = IGRAPH_CALLOC(1, igraph_i_cattributes_t); |
199 | 2.27k | IGRAPH_CHECK_OOM(nattr, "Insufficient memory to allocate attribute storage."); |
200 | 2.27k | IGRAPH_FINALLY(igraph_free, nattr); |
201 | | |
202 | 2.27k | if (attr) { |
203 | 0 | IGRAPH_CHECK(igraph_attribute_record_list_init_copy(&nattr->gal, attr)); |
204 | 2.27k | } else { |
205 | 2.27k | IGRAPH_CHECK(igraph_attribute_record_list_init(&nattr->gal, 0)); |
206 | 2.27k | } |
207 | 2.27k | IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &nattr->gal); |
208 | | |
209 | 2.27k | IGRAPH_CHECK(igraph_attribute_record_list_init(&nattr->val, 0)); |
210 | 2.27k | IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &nattr->val); |
211 | | |
212 | 2.27k | IGRAPH_CHECK(igraph_attribute_record_list_init(&nattr->eal, 0)); |
213 | 2.27k | IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &nattr->eal); |
214 | | |
215 | 2.27k | graph->attr = nattr; |
216 | 2.27k | IGRAPH_FINALLY_CLEAN(4); |
217 | | |
218 | 2.27k | return IGRAPH_SUCCESS; |
219 | 2.27k | } |
220 | | |
221 | 2.27k | static void igraph_i_cattribute_destroy(igraph_t *graph) { |
222 | 2.27k | igraph_i_cattributes_t *attr = graph->attr; |
223 | 2.27k | igraph_attribute_record_list_destroy(&attr->eal); |
224 | 2.27k | igraph_attribute_record_list_destroy(&attr->val); |
225 | 2.27k | igraph_attribute_record_list_destroy(&attr->gal); |
226 | 2.27k | IGRAPH_FREE(graph->attr); /* sets to NULL */ |
227 | 2.27k | } |
228 | | |
229 | | /* No reference counting here. If you use attributes in C you should |
230 | | know what you're doing. */ |
231 | | |
232 | | static igraph_error_t igraph_i_cattribute_copy( |
233 | | igraph_t *to, const igraph_t *from, |
234 | | igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea |
235 | 0 | ) { |
236 | 0 | igraph_i_cattributes_t *attrto, *attrfrom = from->attr; |
237 | 0 | igraph_attribute_record_list_t *alto[3], *alfrom[3] = { |
238 | 0 | &attrfrom->gal, &attrfrom->val, &attrfrom->eal |
239 | 0 | }; |
240 | 0 | igraph_bool_t copy[3] = { ga, va, ea }; |
241 | |
|
242 | 0 | attrto = IGRAPH_CALLOC(1, igraph_i_cattributes_t); |
243 | 0 | IGRAPH_CHECK_OOM(attrto, "Insufficient memory to copy attributes."); |
244 | 0 | IGRAPH_FINALLY(igraph_free, attrto); |
245 | |
|
246 | 0 | alto[0] = &attrto->gal; |
247 | 0 | alto[1] = &attrto->val; |
248 | 0 | alto[2] = &attrto->eal; |
249 | |
|
250 | 0 | for (igraph_int_t i = 0; i < 3; i++) { |
251 | 0 | if (copy[i]) { |
252 | 0 | IGRAPH_CHECK(igraph_attribute_record_list_init_copy(alto[i], alfrom[i])); |
253 | 0 | } else { |
254 | 0 | IGRAPH_CHECK(igraph_attribute_record_list_init(alto[i], 0)); |
255 | 0 | } |
256 | 0 | IGRAPH_FINALLY(igraph_attribute_record_list_destroy, alto[i]); |
257 | 0 | } |
258 | | |
259 | 0 | to->attr = attrto; |
260 | 0 | IGRAPH_FINALLY_CLEAN(4); |
261 | |
|
262 | 0 | return IGRAPH_SUCCESS; |
263 | 0 | } |
264 | | |
265 | | static igraph_error_t igraph_i_cattribute_add_vertices_or_edges_inner( |
266 | | igraph_attribute_record_list_t *val, |
267 | | igraph_int_t newlen, igraph_int_t nv, |
268 | | const igraph_attribute_record_list_t *nattr |
269 | 6.77k | ) { |
270 | 6.77k | igraph_int_t length; |
271 | 6.77k | igraph_int_t nattrno = nattr == NULL ? 0 : igraph_attribute_record_list_size(nattr); |
272 | 6.77k | igraph_int_t origlen = newlen - nv; |
273 | | |
274 | 6.77k | IGRAPH_ASSERT(origlen >= 0); |
275 | | |
276 | | /* Find all the attributes that are newly added, and create new value vectors |
277 | | * for them in the original graph */ |
278 | 13.6k | for (igraph_int_t i = 0; i < nattrno; i++) { |
279 | 6.91k | const igraph_attribute_record_t *nattr_entry = igraph_attribute_record_list_get_ptr(nattr, i); |
280 | 6.91k | const char *nname = nattr_entry->name; |
281 | 6.91k | IGRAPH_CHECK(igraph_i_cattribute_find_or_create(val, nname, nattr_entry->type, origlen, NULL)); |
282 | 6.91k | } |
283 | | |
284 | | /* Now append the new values */ |
285 | 6.77k | length = igraph_attribute_record_list_size(val); |
286 | 13.2k | for (igraph_int_t i = 0; i < length; i++) { |
287 | 6.60k | igraph_attribute_record_t *oldrec = igraph_attribute_record_list_get_ptr(val, i); |
288 | 6.60k | const igraph_attribute_record_t *newrec = nattr |
289 | 6.60k | ? igraph_i_cattribute_find_const(nattr, oldrec->name, oldrec->type) |
290 | 6.60k | : NULL; |
291 | | |
292 | 6.60k | IGRAPH_ASSERT(igraph_attribute_record_size(oldrec) == origlen); |
293 | | |
294 | 6.60k | if (newrec) { |
295 | | /* This attribute is present in nattr */ |
296 | 6.60k | switch (oldrec->type) { |
297 | 1.68k | case IGRAPH_ATTRIBUTE_NUMERIC: |
298 | 1.68k | if (nv != igraph_vector_size(newrec->value.as_vector)) { |
299 | 47 | IGRAPH_ERROR("Invalid numeric attribute length.", IGRAPH_EINVAL); |
300 | 47 | } |
301 | 1.63k | IGRAPH_CHECK(igraph_vector_append( |
302 | 1.63k | oldrec->value.as_vector, newrec->value.as_vector |
303 | 1.63k | )); |
304 | 1.63k | break; |
305 | 4.55k | case IGRAPH_ATTRIBUTE_STRING: |
306 | 4.55k | if (nv != igraph_strvector_size(newrec->value.as_strvector)) { |
307 | 44 | IGRAPH_ERROR("Invalid string attribute length.", IGRAPH_EINVAL); |
308 | 44 | } |
309 | 4.51k | IGRAPH_CHECK(igraph_strvector_append( |
310 | 4.51k | oldrec->value.as_strvector, newrec->value.as_strvector |
311 | 4.51k | )); |
312 | 4.51k | break; |
313 | 4.51k | case IGRAPH_ATTRIBUTE_BOOLEAN: |
314 | 364 | if (nv != igraph_vector_bool_size(newrec->value.as_vector_bool)) { |
315 | 0 | IGRAPH_ERROR("Invalid boolean attribute length.", IGRAPH_EINVAL); |
316 | 0 | } |
317 | 364 | IGRAPH_CHECK(igraph_vector_bool_append( |
318 | 364 | oldrec->value.as_vector_bool, newrec->value.as_vector_bool |
319 | 364 | )); |
320 | 364 | break; |
321 | 364 | default: |
322 | 0 | IGRAPH_WARNINGF( |
323 | 0 | "Attribute '%s' with unknown type %d ignored", |
324 | 0 | oldrec->name, (int) oldrec->type |
325 | 0 | ); |
326 | 0 | break; |
327 | 6.60k | } |
328 | 6.60k | } else { |
329 | | /* No such attribute among the new ones so just extend the length |
330 | | * of the current record */ |
331 | 0 | IGRAPH_CHECK(igraph_attribute_record_resize(oldrec, newlen)); |
332 | 0 | } |
333 | | |
334 | 6.51k | IGRAPH_ASSERT(igraph_attribute_record_size(oldrec) == newlen); |
335 | 6.51k | } |
336 | | |
337 | 6.67k | return IGRAPH_SUCCESS; |
338 | 6.77k | } |
339 | | |
340 | | static igraph_error_t igraph_i_cattribute_add_vertices_or_edges( |
341 | | igraph_attribute_record_list_t *val, |
342 | | igraph_int_t newlen, igraph_int_t nv, |
343 | | const igraph_attribute_record_list_t *nattr |
344 | 6.77k | ) { |
345 | 6.77k | igraph_int_t origlen = newlen - nv; |
346 | 6.77k | igraph_error_t err = igraph_i_cattribute_add_vertices_or_edges_inner( |
347 | 6.77k | val, newlen, nv, nattr |
348 | 6.77k | ); |
349 | | |
350 | 6.77k | if (err != IGRAPH_SUCCESS) { |
351 | | /* If unsuccessful, revert attribute vector sizes. |
352 | | * The following function assumes that all attributes vectors that |
353 | | * are present have a length at least as great as origlen. |
354 | | * This is true at the moment because any new attributes that are |
355 | | * added to the graph are created directly at 'origlen' instead of |
356 | | * being created at smaller sizes and resized later. |
357 | | * |
358 | | * NOTE: While this ensures that all attribute vector lengths are |
359 | | * correct, it does not ensure that no extra attributes have |
360 | | * been added to the graph. However, the presence of extra |
361 | | * attributes does not make the attribute table inconsistent |
362 | | * like the incorrect attribute vector lengths would. |
363 | | */ |
364 | 91 | igraph_i_cattribute_revert_attribute_vector_sizes(val, origlen); |
365 | 91 | } |
366 | | |
367 | 6.77k | return err; |
368 | 6.77k | } |
369 | | |
370 | | static igraph_error_t igraph_i_cattribute_add_vertices( |
371 | | igraph_t *graph, igraph_int_t nv, |
372 | | const igraph_attribute_record_list_t *nattr |
373 | 4.55k | ) { |
374 | 4.55k | igraph_i_cattributes_t *attr = graph->attr; |
375 | 4.55k | return igraph_i_cattribute_add_vertices_or_edges(&attr->val, igraph_vcount(graph), nv, nattr); |
376 | 4.55k | } |
377 | | |
378 | | typedef struct { |
379 | | igraph_vector_t *numeric; |
380 | | igraph_vector_bool_t *boolean; |
381 | | igraph_vector_ptr_t *strings; |
382 | | igraph_int_t length; |
383 | | } igraph_i_attribute_permutation_work_area_t; |
384 | | |
385 | | static igraph_error_t igraph_i_attribute_permutation_work_area_init( |
386 | | igraph_i_attribute_permutation_work_area_t *work_area, igraph_int_t length |
387 | 0 | ) { |
388 | 0 | work_area->length = length; |
389 | 0 | work_area->numeric = NULL; |
390 | 0 | work_area->boolean = NULL; |
391 | 0 | work_area->strings = NULL; |
392 | 0 | return IGRAPH_SUCCESS; |
393 | 0 | } |
394 | | |
395 | | static void igraph_i_attribute_permutation_work_area_release_stored_strvectors( |
396 | | igraph_i_attribute_permutation_work_area_t *work_area |
397 | 0 | ) { |
398 | 0 | if (work_area->strings != NULL) { |
399 | 0 | igraph_vector_ptr_destroy_all(work_area->strings); |
400 | 0 | IGRAPH_FREE(work_area->strings); |
401 | 0 | work_area->strings = NULL; |
402 | 0 | } |
403 | 0 | } |
404 | | |
405 | | static void igraph_i_attribute_permutation_work_area_destroy( |
406 | | igraph_i_attribute_permutation_work_area_t *work_area |
407 | 0 | ) { |
408 | 0 | igraph_i_attribute_permutation_work_area_release_stored_strvectors(work_area); |
409 | 0 | if (work_area->numeric != NULL) { |
410 | 0 | igraph_vector_destroy(work_area->numeric); |
411 | 0 | IGRAPH_FREE(work_area->numeric); |
412 | 0 | work_area->numeric = NULL; |
413 | 0 | } |
414 | 0 | if (work_area->boolean != NULL) { |
415 | 0 | igraph_vector_bool_destroy(work_area->boolean); |
416 | 0 | IGRAPH_FREE(work_area->boolean); |
417 | 0 | work_area->boolean = NULL; |
418 | 0 | } |
419 | 0 | } |
420 | | |
421 | | static igraph_error_t igraph_i_attribute_permutation_work_area_alloc_for_numeric( |
422 | | igraph_i_attribute_permutation_work_area_t *work_area |
423 | 0 | ) { |
424 | 0 | igraph_vector_t* vec = work_area->numeric; |
425 | |
|
426 | 0 | if (vec == NULL) { |
427 | 0 | vec = IGRAPH_CALLOC(1, igraph_vector_t); |
428 | 0 | IGRAPH_CHECK_OOM(vec, "Cannot permute attributes."); |
429 | 0 | IGRAPH_FINALLY(igraph_free, vec); |
430 | 0 | IGRAPH_CHECK(igraph_vector_init(vec, work_area->length)); |
431 | 0 | work_area->numeric = vec; |
432 | 0 | IGRAPH_FINALLY_CLEAN(1); |
433 | 0 | } |
434 | | |
435 | 0 | return IGRAPH_SUCCESS; |
436 | 0 | } |
437 | | |
438 | | static igraph_error_t igraph_i_attribute_permutation_work_area_alloc_for_boolean( |
439 | | igraph_i_attribute_permutation_work_area_t *work_area |
440 | 0 | ) { |
441 | 0 | igraph_vector_bool_t* vec = work_area->boolean; |
442 | |
|
443 | 0 | if (vec == NULL) { |
444 | 0 | vec = IGRAPH_CALLOC(1, igraph_vector_bool_t); |
445 | 0 | IGRAPH_CHECK_OOM(vec, "Cannot permute attributes."); |
446 | 0 | IGRAPH_FINALLY(igraph_free, vec); |
447 | 0 | IGRAPH_CHECK(igraph_vector_bool_init(vec, work_area->length)); |
448 | 0 | work_area->boolean = vec; |
449 | 0 | IGRAPH_FINALLY_CLEAN(1); |
450 | 0 | } |
451 | | |
452 | 0 | return IGRAPH_SUCCESS; |
453 | 0 | } |
454 | | |
455 | | static igraph_error_t igraph_i_attribute_permutation_work_area_alloc_for_strings( |
456 | | igraph_i_attribute_permutation_work_area_t *work_area |
457 | 0 | ) { |
458 | 0 | igraph_vector_ptr_t* vec = work_area->strings; |
459 | |
|
460 | 0 | if (vec == NULL) { |
461 | 0 | vec = IGRAPH_CALLOC(1, igraph_vector_ptr_t); |
462 | 0 | IGRAPH_CHECK_OOM(vec, "Cannot permute attributes."); |
463 | 0 | IGRAPH_FINALLY(igraph_free, vec); |
464 | 0 | IGRAPH_CHECK(igraph_vector_ptr_init(vec, 0)); |
465 | 0 | IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(vec, igraph_strvector_destroy); |
466 | 0 | work_area->strings = vec; |
467 | 0 | IGRAPH_FINALLY_CLEAN(1); |
468 | 0 | } |
469 | | |
470 | 0 | return IGRAPH_SUCCESS; |
471 | 0 | } |
472 | | |
473 | | static igraph_error_t igraph_i_attribute_permutation_work_area_permute_and_store_strvector( |
474 | | igraph_i_attribute_permutation_work_area_t *work_area, |
475 | | const igraph_strvector_t *vec, |
476 | | const igraph_vector_int_t *idx |
477 | 0 | ) { |
478 | 0 | igraph_strvector_t *new_vec; |
479 | |
|
480 | 0 | new_vec = IGRAPH_CALLOC(1, igraph_strvector_t); |
481 | 0 | IGRAPH_CHECK_OOM(new_vec, "Cannot permute attributes."); |
482 | 0 | IGRAPH_FINALLY(igraph_free, new_vec); |
483 | 0 | IGRAPH_CHECK(igraph_strvector_init(new_vec, 0)); |
484 | 0 | IGRAPH_FINALLY(igraph_strvector_destroy, new_vec); |
485 | 0 | IGRAPH_CHECK(igraph_vector_ptr_push_back(work_area->strings, new_vec)); |
486 | 0 | IGRAPH_FINALLY_CLEAN(2); |
487 | |
|
488 | 0 | IGRAPH_CHECK(igraph_strvector_index(vec, new_vec, idx)); |
489 | | |
490 | 0 | return IGRAPH_SUCCESS; |
491 | 0 | } |
492 | | |
493 | | static igraph_error_t igraph_i_cattribute_permute_attribute_record_list( |
494 | | igraph_attribute_record_list_t *attrs, |
495 | | igraph_attribute_record_list_t *new_attrs, |
496 | | const igraph_vector_int_t *idx |
497 | 0 | ) { |
498 | 0 | igraph_int_t no_attrs, idxlen; |
499 | |
|
500 | 0 | no_attrs = igraph_attribute_record_list_size(attrs); |
501 | | |
502 | | /* When vertices or edges are permuted, we now assume that there are no |
503 | | * attributes in the target attribute list yet */ |
504 | 0 | IGRAPH_ASSERT(igraph_attribute_record_list_empty(new_attrs)); |
505 | 0 | IGRAPH_FINALLY(igraph_attribute_record_list_clear, new_attrs); |
506 | |
|
507 | 0 | idxlen = igraph_vector_int_size(idx); |
508 | 0 | for (igraph_int_t i = 0; i < no_attrs; i++) { |
509 | 0 | igraph_attribute_record_t *oldrec = igraph_attribute_record_list_get_ptr(attrs, i); |
510 | 0 | igraph_attribute_type_t type = oldrec->type; |
511 | | |
512 | | /* Create a record for the same attribute in the new graph */ |
513 | 0 | igraph_attribute_record_t *newrec; |
514 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create( |
515 | 0 | new_attrs, oldrec->name, oldrec->type, idxlen, &newrec |
516 | 0 | )); |
517 | | |
518 | | /* The data */ |
519 | 0 | switch (type) { |
520 | 0 | case IGRAPH_ATTRIBUTE_NUMERIC: |
521 | 0 | IGRAPH_CHECK(igraph_vector_index( |
522 | 0 | oldrec->value.as_vector, newrec->value.as_vector, idx |
523 | 0 | )); |
524 | 0 | break; |
525 | 0 | case IGRAPH_ATTRIBUTE_BOOLEAN: |
526 | 0 | IGRAPH_CHECK(igraph_vector_bool_index( |
527 | 0 | oldrec->value.as_vector_bool, newrec->value.as_vector_bool, idx |
528 | 0 | )); |
529 | 0 | break; |
530 | 0 | case IGRAPH_ATTRIBUTE_STRING: |
531 | 0 | IGRAPH_CHECK(igraph_strvector_index( |
532 | 0 | oldrec->value.as_strvector, newrec->value.as_strvector, idx |
533 | 0 | )); |
534 | 0 | break; |
535 | 0 | default: |
536 | 0 | IGRAPH_WARNINGF( |
537 | 0 | "Attribute '%s' with unknown type %d ignored", |
538 | 0 | oldrec->name, (int) oldrec->type |
539 | 0 | ); |
540 | 0 | } |
541 | 0 | } |
542 | | |
543 | 0 | IGRAPH_FINALLY_CLEAN(1); |
544 | |
|
545 | 0 | return IGRAPH_SUCCESS; |
546 | 0 | } |
547 | | |
548 | | static igraph_error_t igraph_i_cattribute_permute_attribute_record_list_in_place( |
549 | | igraph_attribute_record_list_t *attrs, const igraph_vector_int_t *idx |
550 | 0 | ) { |
551 | 0 | igraph_int_t no_attrs = igraph_attribute_record_list_size(attrs); |
552 | 0 | igraph_attribute_record_t *oldrec; |
553 | 0 | igraph_vector_t *num, *num_work; |
554 | 0 | igraph_strvector_t *str, str_work; |
555 | 0 | igraph_vector_bool_t *oldbool, *bool_work; |
556 | 0 | igraph_i_attribute_permutation_work_area_t work_area; |
557 | 0 | igraph_int_t idx_size = igraph_vector_int_size(idx); |
558 | | |
559 | | /* shortcut: don't allocate anything if there are no attributes */ |
560 | 0 | if (no_attrs == 0) { |
561 | 0 | return IGRAPH_SUCCESS; |
562 | 0 | } |
563 | | |
564 | | /* do all the allocations that can potentially fail before we actually |
565 | | * start to permute the vertices to ensure that we will not ever need to |
566 | | * back out from a permutation once we've started it */ |
567 | 0 | IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_init(&work_area, idx_size)); |
568 | 0 | IGRAPH_FINALLY(igraph_i_attribute_permutation_work_area_destroy, &work_area); |
569 | 0 | for (igraph_int_t i = 0; i < no_attrs; i++) { |
570 | 0 | oldrec = igraph_attribute_record_list_get_ptr(attrs, i); |
571 | 0 | switch (oldrec->type) { |
572 | 0 | case IGRAPH_ATTRIBUTE_NUMERIC: |
573 | 0 | num = oldrec->value.as_vector; |
574 | 0 | IGRAPH_CHECK(igraph_vector_reserve(num, idx_size)); |
575 | 0 | IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_alloc_for_numeric(&work_area)); |
576 | 0 | break; |
577 | | |
578 | 0 | case IGRAPH_ATTRIBUTE_BOOLEAN: |
579 | 0 | oldbool = oldrec->value.as_vector_bool; |
580 | 0 | IGRAPH_CHECK(igraph_vector_bool_reserve(oldbool, idx_size)); |
581 | 0 | IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_alloc_for_boolean(&work_area)); |
582 | 0 | break; |
583 | | |
584 | 0 | case IGRAPH_ATTRIBUTE_STRING: |
585 | 0 | str = oldrec->value.as_strvector; |
586 | 0 | IGRAPH_CHECK(igraph_strvector_reserve(str, idx_size)); |
587 | 0 | IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_alloc_for_strings(&work_area)); |
588 | 0 | break; |
589 | | |
590 | 0 | default: |
591 | 0 | IGRAPH_WARNINGF( |
592 | 0 | "Vertex attribute '%s' with unknown type %d ignored", |
593 | 0 | oldrec->name, (int) oldrec->type |
594 | 0 | ); |
595 | 0 | } |
596 | 0 | } |
597 | | |
598 | | /* let's do string attributes first because these might need extra |
599 | | * allocations that can fail. The strategy is to build new igraph_strvector_t |
600 | | * instances for the permuted attributes and store them in an |
601 | | * igraph_vector_ptr_t until we are done with all of them. If any of the |
602 | | * allocations fail, we can destroy the igraph_vector_ptr_t safely */ |
603 | 0 | for (igraph_int_t i = 0; i < no_attrs; i++) { |
604 | 0 | oldrec = igraph_attribute_record_list_get_ptr(attrs, i); |
605 | 0 | if (oldrec->type == IGRAPH_ATTRIBUTE_STRING) { |
606 | 0 | str = oldrec->value.as_strvector; |
607 | 0 | IGRAPH_CHECK( |
608 | 0 | igraph_i_attribute_permutation_work_area_permute_and_store_strvector( |
609 | 0 | &work_area, str, idx |
610 | 0 | ) |
611 | 0 | ); |
612 | 0 | } |
613 | 0 | } |
614 | | |
615 | | /* strings are done, and now all vectors involved in the process are |
616 | | * as large as they should be (or larger) so the operations below are not |
617 | | * supposed to fail. We can safely replace the original string attribute |
618 | | * vectors with the permuted ones, and then proceed to the remaining |
619 | | * attributes */ |
620 | 0 | for (igraph_int_t i = 0, j = 0; i < no_attrs; i++) { |
621 | 0 | oldrec = igraph_attribute_record_list_get_ptr(attrs, i); |
622 | 0 | if (oldrec->type != IGRAPH_ATTRIBUTE_STRING) { |
623 | 0 | continue; |
624 | 0 | } |
625 | | |
626 | 0 | str = oldrec->value.as_strvector; |
627 | 0 | str_work = *((igraph_strvector_t*) VECTOR(*(work_area.strings))[j]); |
628 | 0 | *((igraph_strvector_t*) VECTOR(*(work_area.strings))[j]) = *str; |
629 | 0 | *str = str_work; |
630 | 0 | j++; |
631 | 0 | } |
632 | 0 | igraph_i_attribute_permutation_work_area_release_stored_strvectors(&work_area); |
633 | |
|
634 | 0 | for (igraph_int_t i = 0; i < no_attrs; i++) { |
635 | 0 | oldrec = igraph_attribute_record_list_get_ptr(attrs, i); |
636 | 0 | switch (oldrec->type) { |
637 | 0 | case IGRAPH_ATTRIBUTE_NUMERIC: |
638 | 0 | num = oldrec->value.as_vector; |
639 | 0 | num_work = work_area.numeric; |
640 | 0 | IGRAPH_ASSERT(num_work != NULL); |
641 | 0 | IGRAPH_CHECK(igraph_vector_index(num, num_work, idx)); |
642 | 0 | igraph_vector_swap(num, num_work); |
643 | 0 | break; |
644 | 0 | case IGRAPH_ATTRIBUTE_BOOLEAN: |
645 | 0 | oldbool = oldrec->value.as_vector_bool; |
646 | 0 | bool_work = work_area.boolean; |
647 | 0 | IGRAPH_ASSERT(bool_work != NULL); |
648 | 0 | IGRAPH_CHECK(igraph_vector_bool_index(oldbool, bool_work, idx)); |
649 | 0 | igraph_vector_bool_swap(oldbool, bool_work); |
650 | 0 | break; |
651 | 0 | case IGRAPH_ATTRIBUTE_STRING: |
652 | | /* nothing to do */ |
653 | 0 | break; |
654 | 0 | default: |
655 | | /* already warned */ |
656 | 0 | break; |
657 | 0 | } |
658 | 0 | } |
659 | | |
660 | 0 | igraph_i_attribute_permutation_work_area_destroy(&work_area); |
661 | 0 | IGRAPH_FINALLY_CLEAN(1); |
662 | |
|
663 | 0 | return IGRAPH_SUCCESS; |
664 | 0 | } |
665 | | |
666 | | static igraph_error_t igraph_i_cattribute_permute_vertices( |
667 | | const igraph_t *graph, igraph_t *newgraph, const igraph_vector_int_t *idx |
668 | 0 | ) { |
669 | 0 | igraph_i_cattributes_t *attr = graph->attr, *new_attr = newgraph->attr; |
670 | 0 | igraph_attribute_record_list_t *val = &attr->val, *new_val = &new_attr->val; |
671 | 0 | if (graph == newgraph) { |
672 | 0 | return igraph_i_cattribute_permute_attribute_record_list_in_place(val, idx); |
673 | 0 | } else { |
674 | 0 | return igraph_i_cattribute_permute_attribute_record_list(val, new_val, idx); |
675 | 0 | } |
676 | 0 | } |
677 | | |
678 | | typedef igraph_error_t igraph_cattributes_combine_num_t(const igraph_vector_t *input, |
679 | | igraph_real_t *output); |
680 | | |
681 | | typedef igraph_error_t igraph_cattributes_combine_str_t(const igraph_strvector_t *input, |
682 | | char **output); |
683 | | |
684 | | typedef igraph_error_t igraph_cattributes_combine_bool_t(const igraph_vector_bool_t *input, |
685 | | igraph_bool_t *output); |
686 | | |
687 | | static igraph_error_t igraph_i_cattributes_cn_sum(const igraph_attribute_record_t *oldrec, |
688 | | igraph_attribute_record_t * newrec, |
689 | 0 | const igraph_vector_int_list_t *merges) { |
690 | 0 | const igraph_vector_t *oldv = oldrec->value.as_vector; |
691 | 0 | igraph_vector_t *newv = newrec->value.as_vector; |
692 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
693 | |
|
694 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
695 | 0 | igraph_real_t s = 0.0; |
696 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
697 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
698 | 0 | for (igraph_int_t j = 0; j < n; j++) { |
699 | 0 | igraph_int_t x = VECTOR(*idx)[j]; |
700 | 0 | s += VECTOR(*oldv)[x]; |
701 | 0 | } |
702 | 0 | VECTOR(*newv)[i] = s; |
703 | 0 | } |
704 | |
|
705 | 0 | return IGRAPH_SUCCESS; |
706 | 0 | } |
707 | | |
708 | | static igraph_error_t igraph_i_cattributes_cn_prod(const igraph_attribute_record_t *oldrec, |
709 | | igraph_attribute_record_t * newrec, |
710 | 0 | const igraph_vector_int_list_t *merges) { |
711 | 0 | const igraph_vector_t *oldv = oldrec->value.as_vector; |
712 | 0 | igraph_vector_t *newv = newrec->value.as_vector; |
713 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
714 | |
|
715 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
716 | 0 | igraph_real_t s = 1.0; |
717 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
718 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
719 | 0 | for (igraph_int_t j = 0; j < n; j++) { |
720 | 0 | igraph_int_t x = VECTOR(*idx)[j]; |
721 | 0 | s *= VECTOR(*oldv)[x]; |
722 | 0 | } |
723 | 0 | VECTOR(*newv)[i] = s; |
724 | 0 | } |
725 | |
|
726 | 0 | return IGRAPH_SUCCESS; |
727 | 0 | } |
728 | | |
729 | | static igraph_error_t igraph_i_cattributes_cn_min(const igraph_attribute_record_t *oldrec, |
730 | | igraph_attribute_record_t * newrec, |
731 | 0 | const igraph_vector_int_list_t *merges) { |
732 | 0 | const igraph_vector_t *oldv = oldrec->value.as_vector; |
733 | 0 | igraph_vector_t *newv = newrec->value.as_vector; |
734 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
735 | |
|
736 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
737 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
738 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
739 | 0 | igraph_real_t m = n > 0 ? VECTOR(*oldv)[ VECTOR(*idx)[0] ] : IGRAPH_NAN; |
740 | 0 | for (igraph_int_t j = 1; j < n; j++) { |
741 | 0 | igraph_int_t x = VECTOR(*idx)[j]; |
742 | 0 | igraph_real_t val = VECTOR(*oldv)[x]; |
743 | 0 | if (val < m) { |
744 | 0 | m = val; |
745 | 0 | } |
746 | 0 | } |
747 | 0 | VECTOR(*newv)[i] = m; |
748 | 0 | } |
749 | |
|
750 | 0 | return IGRAPH_SUCCESS; |
751 | 0 | } |
752 | | |
753 | | static igraph_error_t igraph_i_cattributes_cn_max(const igraph_attribute_record_t *oldrec, |
754 | | igraph_attribute_record_t * newrec, |
755 | 0 | const igraph_vector_int_list_t *merges) { |
756 | 0 | const igraph_vector_t *oldv = oldrec->value.as_vector; |
757 | 0 | igraph_vector_t *newv = newrec->value.as_vector; |
758 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
759 | |
|
760 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
761 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
762 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
763 | 0 | igraph_real_t m = n > 0 ? VECTOR(*oldv)[ VECTOR(*idx)[0] ] : IGRAPH_NAN; |
764 | 0 | for (igraph_int_t j = 1; j < n; j++) { |
765 | 0 | igraph_int_t x = VECTOR(*idx)[j]; |
766 | 0 | igraph_real_t val = VECTOR(*oldv)[x]; |
767 | 0 | if (val > m) { |
768 | 0 | m = val; |
769 | 0 | } |
770 | 0 | } |
771 | 0 | VECTOR(*newv)[i] = m; |
772 | 0 | } |
773 | |
|
774 | 0 | return IGRAPH_SUCCESS; |
775 | 0 | } |
776 | | |
777 | | static igraph_error_t igraph_i_cattributes_cn_random(const igraph_attribute_record_t *oldrec, |
778 | | igraph_attribute_record_t * newrec, |
779 | 0 | const igraph_vector_int_list_t *merges) { |
780 | |
|
781 | 0 | const igraph_vector_t *oldv = oldrec->value.as_vector; |
782 | 0 | igraph_vector_t *newv = newrec->value.as_vector; |
783 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
784 | |
|
785 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
786 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
787 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
788 | 0 | if (n == 0) { |
789 | 0 | VECTOR(*newv)[i] = IGRAPH_NAN; |
790 | 0 | } else if (n == 1) { |
791 | 0 | VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[0] ]; |
792 | 0 | } else { |
793 | 0 | igraph_int_t r = RNG_INTEGER(0, n - 1); |
794 | 0 | VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[r] ]; |
795 | 0 | } |
796 | 0 | } |
797 | |
|
798 | 0 | return IGRAPH_SUCCESS; |
799 | 0 | } |
800 | | |
801 | | static igraph_error_t igraph_i_cattributes_cn_first(const igraph_attribute_record_t *oldrec, |
802 | | igraph_attribute_record_t * newrec, |
803 | 0 | const igraph_vector_int_list_t *merges) { |
804 | |
|
805 | 0 | const igraph_vector_t *oldv = oldrec->value.as_vector; |
806 | 0 | igraph_vector_t *newv = newrec->value.as_vector; |
807 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
808 | |
|
809 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
810 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
811 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
812 | 0 | if (n == 0) { |
813 | 0 | VECTOR(*newv)[i] = IGRAPH_NAN; |
814 | 0 | } else { |
815 | 0 | VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[0] ]; |
816 | 0 | } |
817 | 0 | } |
818 | |
|
819 | 0 | return IGRAPH_SUCCESS; |
820 | 0 | } |
821 | | |
822 | | static igraph_error_t igraph_i_cattributes_cn_last(const igraph_attribute_record_t *oldrec, |
823 | | igraph_attribute_record_t * newrec, |
824 | 0 | const igraph_vector_int_list_t *merges) { |
825 | |
|
826 | 0 | const igraph_vector_t *oldv = oldrec->value.as_vector; |
827 | 0 | igraph_vector_t *newv = newrec->value.as_vector; |
828 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
829 | |
|
830 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
831 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
832 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
833 | 0 | if (n == 0) { |
834 | 0 | VECTOR(*newv)[i] = IGRAPH_NAN; |
835 | 0 | } else { |
836 | 0 | VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[n - 1] ]; |
837 | 0 | } |
838 | 0 | } |
839 | |
|
840 | 0 | return IGRAPH_SUCCESS; |
841 | 0 | } |
842 | | |
843 | | static igraph_error_t igraph_i_cattributes_cn_mean(const igraph_attribute_record_t *oldrec, |
844 | | igraph_attribute_record_t * newrec, |
845 | 0 | const igraph_vector_int_list_t *merges) { |
846 | 0 | const igraph_vector_t *oldv = oldrec->value.as_vector; |
847 | 0 | igraph_vector_t *newv = newrec->value.as_vector; |
848 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
849 | |
|
850 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
851 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
852 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
853 | 0 | igraph_real_t s = n > 0 ? 0.0 : IGRAPH_NAN; |
854 | 0 | for (igraph_int_t j = 0; j < n; j++) { |
855 | 0 | igraph_int_t x = VECTOR(*idx)[j]; |
856 | 0 | s += VECTOR(*oldv)[x]; |
857 | 0 | } |
858 | 0 | if (n > 0) { |
859 | 0 | s = s / n; |
860 | 0 | } |
861 | 0 | VECTOR(*newv)[i] = s; |
862 | 0 | } |
863 | |
|
864 | 0 | return IGRAPH_SUCCESS; |
865 | 0 | } |
866 | | |
867 | | static igraph_error_t igraph_i_cattributes_cn_func(const igraph_attribute_record_t *oldrec, |
868 | | igraph_attribute_record_t *newrec, |
869 | | const igraph_vector_int_list_t *merges, |
870 | 0 | igraph_cattributes_combine_num_t *func) { |
871 | |
|
872 | 0 | const igraph_vector_t *oldv = oldrec->value.as_vector; |
873 | 0 | igraph_vector_t *newv = newrec->value.as_vector; |
874 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
875 | |
|
876 | 0 | igraph_vector_t values; |
877 | 0 | IGRAPH_VECTOR_INIT_FINALLY(&values, 0); |
878 | | |
879 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
880 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
881 | |
|
882 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
883 | 0 | IGRAPH_CHECK(igraph_vector_resize(&values, n)); |
884 | 0 | for (igraph_int_t j = 0; j < n; j++) { |
885 | 0 | igraph_int_t x = VECTOR(*idx)[j]; |
886 | 0 | VECTOR(values)[j] = VECTOR(*oldv)[x]; |
887 | 0 | } |
888 | |
|
889 | 0 | igraph_real_t res; |
890 | 0 | IGRAPH_CHECK(func(&values, &res)); |
891 | 0 | VECTOR(*newv)[i] = res; |
892 | 0 | } |
893 | | |
894 | 0 | igraph_vector_destroy(&values); |
895 | 0 | IGRAPH_FINALLY_CLEAN(1); |
896 | |
|
897 | 0 | return IGRAPH_SUCCESS; |
898 | 0 | } |
899 | | |
900 | | static igraph_error_t igraph_i_cattributes_cb_random(const igraph_attribute_record_t *oldrec, |
901 | | igraph_attribute_record_t * newrec, |
902 | 0 | const igraph_vector_int_list_t *merges) { |
903 | |
|
904 | 0 | const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; |
905 | 0 | igraph_vector_bool_t *newv = newrec->value.as_vector_bool; |
906 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
907 | |
|
908 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
909 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
910 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
911 | 0 | if (n == 0) { |
912 | 0 | VECTOR(*newv)[i] = 0; |
913 | 0 | } else if (n == 1) { |
914 | 0 | VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[0] ]; |
915 | 0 | } else { |
916 | 0 | igraph_int_t r = RNG_INTEGER(0, n - 1); |
917 | 0 | VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[r] ]; |
918 | 0 | } |
919 | 0 | } |
920 | |
|
921 | 0 | return IGRAPH_SUCCESS; |
922 | 0 | } |
923 | | |
924 | | static igraph_error_t igraph_i_cattributes_cb_first(const igraph_attribute_record_t *oldrec, |
925 | | igraph_attribute_record_t * newrec, |
926 | 0 | const igraph_vector_int_list_t *merges) { |
927 | |
|
928 | 0 | const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; |
929 | 0 | igraph_vector_bool_t *newv = newrec->value.as_vector_bool; |
930 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
931 | |
|
932 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
933 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
934 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
935 | 0 | if (n == 0) { |
936 | 0 | VECTOR(*newv)[i] = 0; |
937 | 0 | } else { |
938 | 0 | VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[0] ]; |
939 | 0 | } |
940 | 0 | } |
941 | |
|
942 | 0 | return IGRAPH_SUCCESS; |
943 | 0 | } |
944 | | |
945 | | static igraph_error_t igraph_i_cattributes_cb_last(const igraph_attribute_record_t *oldrec, |
946 | | igraph_attribute_record_t * newrec, |
947 | 0 | const igraph_vector_int_list_t *merges) { |
948 | |
|
949 | 0 | const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; |
950 | 0 | igraph_vector_bool_t *newv = newrec->value.as_vector_bool; |
951 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
952 | |
|
953 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
954 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
955 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
956 | 0 | if (n == 0) { |
957 | 0 | VECTOR(*newv)[i] = 0; |
958 | 0 | } else { |
959 | 0 | VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[n - 1] ]; |
960 | 0 | } |
961 | 0 | } |
962 | |
|
963 | 0 | return IGRAPH_SUCCESS; |
964 | 0 | } |
965 | | |
966 | | static igraph_error_t igraph_i_cattributes_cb_all_is_true(const igraph_attribute_record_t *oldrec, |
967 | | igraph_attribute_record_t * newrec, |
968 | 0 | const igraph_vector_int_list_t *merges) { |
969 | |
|
970 | 0 | const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; |
971 | 0 | igraph_vector_bool_t *newv = newrec->value.as_vector_bool; |
972 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
973 | |
|
974 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
975 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
976 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
977 | 0 | VECTOR(*newv)[i] = 1; |
978 | 0 | for (igraph_int_t j = 0; j < n; j++) { |
979 | 0 | igraph_int_t x = VECTOR(*idx)[j]; |
980 | 0 | if (!VECTOR(*oldv)[x]) { |
981 | 0 | VECTOR(*newv)[i] = 0; |
982 | 0 | break; |
983 | 0 | } |
984 | 0 | } |
985 | 0 | } |
986 | |
|
987 | 0 | return IGRAPH_SUCCESS; |
988 | 0 | } |
989 | | |
990 | | static igraph_error_t igraph_i_cattributes_cb_any_is_true(const igraph_attribute_record_t *oldrec, |
991 | | igraph_attribute_record_t * newrec, |
992 | 0 | const igraph_vector_int_list_t *merges) { |
993 | |
|
994 | 0 | const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; |
995 | 0 | igraph_vector_bool_t *newv = newrec->value.as_vector_bool; |
996 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
997 | |
|
998 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
999 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
1000 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
1001 | 0 | VECTOR(*newv)[i] = 0; |
1002 | 0 | for (igraph_int_t j = 0; j < n; j++) { |
1003 | 0 | igraph_int_t x = VECTOR(*idx)[j]; |
1004 | 0 | if (VECTOR(*oldv)[x]) { |
1005 | 0 | VECTOR(*newv)[i] = 1; |
1006 | 0 | break; |
1007 | 0 | } |
1008 | 0 | } |
1009 | 0 | } |
1010 | |
|
1011 | 0 | return IGRAPH_SUCCESS; |
1012 | 0 | } |
1013 | | |
1014 | | static igraph_error_t igraph_i_cattributes_cb_majority(const igraph_attribute_record_t *oldrec, |
1015 | | igraph_attribute_record_t * newrec, |
1016 | 0 | const igraph_vector_int_list_t *merges) { |
1017 | |
|
1018 | 0 | const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; |
1019 | 0 | igraph_vector_bool_t *newv = newrec->value.as_vector_bool; |
1020 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
1021 | |
|
1022 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
1023 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
1024 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
1025 | |
|
1026 | 0 | igraph_int_t num_trues = 0; |
1027 | 0 | for (igraph_int_t j = 0; j < n; j++) { |
1028 | 0 | igraph_int_t x = VECTOR(*idx)[j]; |
1029 | 0 | if (VECTOR(*oldv)[x]) { |
1030 | 0 | num_trues++; |
1031 | 0 | } |
1032 | 0 | } |
1033 | |
|
1034 | 0 | if (n % 2 != 0) { |
1035 | 0 | VECTOR(*newv)[i] = (num_trues > n / 2); |
1036 | 0 | } else { |
1037 | 0 | if (num_trues == n / 2) { |
1038 | 0 | VECTOR(*newv)[i] = RNG_BOOL(); |
1039 | 0 | } else { |
1040 | 0 | VECTOR(*newv)[i] = (num_trues > n / 2); |
1041 | 0 | } |
1042 | 0 | } |
1043 | 0 | } |
1044 | |
|
1045 | 0 | return IGRAPH_SUCCESS; |
1046 | 0 | } |
1047 | | |
1048 | | static igraph_error_t igraph_i_cattributes_cb_func(const igraph_attribute_record_t *oldrec, |
1049 | | igraph_attribute_record_t *newrec, |
1050 | | const igraph_vector_int_list_t *merges, |
1051 | 0 | igraph_cattributes_combine_bool_t *func) { |
1052 | |
|
1053 | 0 | const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; |
1054 | 0 | igraph_vector_bool_t *newv = newrec->value.as_vector_bool; |
1055 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
1056 | |
|
1057 | 0 | igraph_vector_bool_t values; |
1058 | 0 | IGRAPH_VECTOR_BOOL_INIT_FINALLY(&values, 0); |
1059 | | |
1060 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
1061 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
1062 | |
|
1063 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
1064 | 0 | IGRAPH_CHECK(igraph_vector_bool_resize(&values, n)); |
1065 | 0 | for (igraph_int_t j = 0; j < n; j++) { |
1066 | 0 | igraph_int_t x = VECTOR(*idx)[j]; |
1067 | 0 | VECTOR(values)[j] = VECTOR(*oldv)[x]; |
1068 | 0 | } |
1069 | |
|
1070 | 0 | igraph_bool_t res; |
1071 | 0 | IGRAPH_CHECK(func(&values, &res)); |
1072 | 0 | VECTOR(*newv)[i] = res; |
1073 | 0 | } |
1074 | | |
1075 | 0 | igraph_vector_bool_destroy(&values); |
1076 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1077 | |
|
1078 | 0 | return IGRAPH_SUCCESS; |
1079 | 0 | } |
1080 | | |
1081 | | static igraph_error_t igraph_i_cattributes_sn_random(const igraph_attribute_record_t *oldrec, |
1082 | | igraph_attribute_record_t *newrec, |
1083 | 0 | const igraph_vector_int_list_t *merges) { |
1084 | |
|
1085 | 0 | const igraph_strvector_t *oldv = oldrec->value.as_strvector; |
1086 | 0 | igraph_strvector_t *newv = newrec->value.as_strvector; |
1087 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
1088 | |
|
1089 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
1090 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
1091 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
1092 | 0 | const char *tmp; |
1093 | 0 | if (n == 0) { |
1094 | 0 | IGRAPH_CHECK(igraph_strvector_set(newv, i, "")); |
1095 | 0 | } else if (n == 1) { |
1096 | 0 | tmp = igraph_strvector_get(oldv, 0); |
1097 | 0 | IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp)); |
1098 | 0 | } else { |
1099 | 0 | igraph_int_t r = RNG_INTEGER(0, n - 1); |
1100 | 0 | tmp = igraph_strvector_get(oldv, r); |
1101 | 0 | IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp)); |
1102 | 0 | } |
1103 | 0 | } |
1104 | | |
1105 | 0 | return IGRAPH_SUCCESS; |
1106 | 0 | } |
1107 | | |
1108 | | static igraph_error_t igraph_i_cattributes_cs_first(const igraph_attribute_record_t *oldrec, |
1109 | | igraph_attribute_record_t *newrec, |
1110 | 0 | const igraph_vector_int_list_t *merges) { |
1111 | |
|
1112 | 0 | const igraph_strvector_t *oldv = oldrec->value.as_strvector; |
1113 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
1114 | 0 | igraph_strvector_t *newv = newrec->value.as_strvector; |
1115 | |
|
1116 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
1117 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
1118 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
1119 | 0 | if (n == 0) { |
1120 | 0 | IGRAPH_CHECK(igraph_strvector_set(newv, i, "")); |
1121 | 0 | } else { |
1122 | 0 | const char *tmp = igraph_strvector_get(oldv, VECTOR(*idx)[0]); |
1123 | 0 | IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp)); |
1124 | 0 | } |
1125 | 0 | } |
1126 | | |
1127 | 0 | return IGRAPH_SUCCESS; |
1128 | 0 | } |
1129 | | |
1130 | | static igraph_error_t igraph_i_cattributes_cs_last(const igraph_attribute_record_t *oldrec, |
1131 | | igraph_attribute_record_t *newrec, |
1132 | 0 | const igraph_vector_int_list_t *merges) { |
1133 | |
|
1134 | 0 | const igraph_strvector_t *oldv = oldrec->value.as_strvector; |
1135 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
1136 | 0 | igraph_strvector_t *newv = newrec->value.as_strvector; |
1137 | |
|
1138 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
1139 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
1140 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
1141 | 0 | if (n == 0) { |
1142 | 0 | IGRAPH_CHECK(igraph_strvector_set(newv, i, "")); |
1143 | 0 | } else { |
1144 | 0 | const char *tmp = igraph_strvector_get(oldv, VECTOR(*idx)[n - 1]); |
1145 | 0 | IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp)); |
1146 | 0 | } |
1147 | 0 | } |
1148 | | |
1149 | 0 | return IGRAPH_SUCCESS; |
1150 | 0 | } |
1151 | | |
1152 | | static igraph_error_t igraph_i_cattributes_cs_concat(const igraph_attribute_record_t *oldrec, |
1153 | | igraph_attribute_record_t *newrec, |
1154 | 0 | const igraph_vector_int_list_t *merges) { |
1155 | |
|
1156 | 0 | const igraph_strvector_t *oldv = oldrec->value.as_strvector; |
1157 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
1158 | 0 | igraph_strvector_t *newv = newrec->value.as_strvector; |
1159 | |
|
1160 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
1161 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
1162 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
1163 | 0 | size_t len = 0; |
1164 | 0 | const char *tmp; |
1165 | 0 | char *tmp2; |
1166 | 0 | for (igraph_int_t j = 0; j < n; j++) { |
1167 | 0 | tmp = igraph_strvector_get(oldv, j); |
1168 | 0 | len += strlen(tmp); |
1169 | 0 | } |
1170 | 0 | tmp2 = IGRAPH_CALLOC(len + 1, char); |
1171 | 0 | IGRAPH_CHECK_OOM(tmp2, "Cannot combine attributes."); |
1172 | 0 | IGRAPH_FINALLY(igraph_free, tmp2); |
1173 | 0 | len = 0; |
1174 | 0 | for (igraph_int_t j = 0; j < n; j++) { |
1175 | 0 | tmp = igraph_strvector_get(oldv, j); |
1176 | 0 | strcpy(tmp2 + len, tmp); |
1177 | 0 | len += strlen(tmp); |
1178 | 0 | } |
1179 | |
|
1180 | 0 | IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp2)); |
1181 | 0 | IGRAPH_FREE(tmp2); |
1182 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1183 | 0 | } |
1184 | | |
1185 | 0 | return IGRAPH_SUCCESS; |
1186 | 0 | } |
1187 | | |
1188 | | static igraph_error_t igraph_i_cattributes_cs_func(const igraph_attribute_record_t *oldrec, |
1189 | | igraph_attribute_record_t *newrec, |
1190 | | const igraph_vector_int_list_t *merges, |
1191 | 0 | igraph_cattributes_combine_str_t *func) { |
1192 | |
|
1193 | 0 | const igraph_strvector_t *oldv = oldrec->value.as_strvector; |
1194 | 0 | igraph_strvector_t *newv = newrec->value.as_strvector; |
1195 | 0 | igraph_int_t newlen = igraph_vector_int_list_size(merges); |
1196 | |
|
1197 | 0 | igraph_strvector_t values; |
1198 | 0 | IGRAPH_STRVECTOR_INIT_FINALLY(&values, 0); |
1199 | | |
1200 | 0 | for (igraph_int_t i = 0; i < newlen; i++) { |
1201 | 0 | const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); |
1202 | |
|
1203 | 0 | igraph_int_t n = igraph_vector_int_size(idx); |
1204 | 0 | IGRAPH_CHECK(igraph_strvector_resize(&values, n)); |
1205 | 0 | for (igraph_int_t j = 0; j < n; j++) { |
1206 | 0 | igraph_int_t x = VECTOR(*idx)[j]; |
1207 | 0 | const char *elem = igraph_strvector_get(oldv, x); |
1208 | 0 | IGRAPH_CHECK(igraph_strvector_set(newv, j, elem)); |
1209 | 0 | } |
1210 | | |
1211 | 0 | char *res; |
1212 | 0 | IGRAPH_CHECK(func(&values, &res)); |
1213 | 0 | IGRAPH_FINALLY(igraph_free, res); |
1214 | |
|
1215 | 0 | IGRAPH_CHECK(igraph_strvector_set(newv, i, res)); |
1216 | | |
1217 | 0 | IGRAPH_FREE(res); |
1218 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1219 | 0 | } |
1220 | | |
1221 | 0 | igraph_strvector_destroy(&values); |
1222 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1223 | |
|
1224 | 0 | return IGRAPH_SUCCESS; |
1225 | 0 | } |
1226 | | |
1227 | | /** |
1228 | | * \section c_attribute_combination_functions |
1229 | | * |
1230 | | * <para> |
1231 | | * The C attribute handler supports combining the attributes of multiple |
1232 | | * vertices of edges into a single attribute during a vertex or edge contraction |
1233 | | * operation via a user-defined function. This is achieved by setting the |
1234 | | * type of the attribute combination to \c IGRAPH_ATTRIBUTE_COMBINE_FUNCTION |
1235 | | * and passing in a pointer to the custom combination function when specifying |
1236 | | * attribute combinations in \ref igraph_attribute_combination() or |
1237 | | * \ref igraph_attribute_combination_add() . For the C attribute handler, the |
1238 | | * signature of the function depends on the type of the underlying attribute. |
1239 | | * For numeric attributes, use: |
1240 | | * \verbatim igraph_error_t function(const igraph_vector_t *input, igraph_real_t *output); \endverbatim |
1241 | | * where \p input will receive a vector containing the value of the attribute |
1242 | | * for all the vertices or edges being combined, and \p output must be filled |
1243 | | * by the function to the combined value. Similarly, for Boolean attributes, the |
1244 | | * function takes a boolean vector in \p input and must return the combined Boolean |
1245 | | * value in \p output: |
1246 | | * \verbatim igraph_error_t function(const igraph_vector_bool_t *input, igraph_bool_t *output); \endverbatim |
1247 | | * For string attributes, the signature is slightly different: |
1248 | | * \verbatim igraph_error_t function(const igraph_strvector_t *input, char **output); \endverbatim |
1249 | | * In case of strings, all strings in the input vector are \em owned by igraph |
1250 | | * and must not be modified or freed in the combination handler. The string |
1251 | | * returned to the caller in \p output remains owned by the caller; igraph will |
1252 | | * make a copy it and store the copy in the appropriate part of the data |
1253 | | * structure holding the vertex or edge attributes. |
1254 | | * </para> |
1255 | | */ |
1256 | | |
1257 | | typedef struct { |
1258 | | igraph_attribute_combination_type_t type; |
1259 | | union { |
1260 | | igraph_function_pointer_t as_void; |
1261 | | igraph_cattributes_combine_num_t *as_num; |
1262 | | igraph_cattributes_combine_str_t *as_str; |
1263 | | igraph_cattributes_combine_bool_t *as_bool; |
1264 | | } func; |
1265 | | } igraph_attribute_combination_todo_item_t; |
1266 | | |
1267 | | static igraph_error_t igraph_i_cattribute_combine_attribute_record_lists( |
1268 | | igraph_attribute_record_list_t *attrs, igraph_attribute_record_list_t *new_attrs, |
1269 | | const igraph_vector_int_list_t *merges, const igraph_attribute_combination_t *comb |
1270 | 0 | ) { |
1271 | 0 | igraph_int_t no_attrs = igraph_attribute_record_list_size(attrs); |
1272 | 0 | igraph_attribute_combination_todo_item_t *todo_items; |
1273 | |
|
1274 | 0 | IGRAPH_ASSERT(attrs != new_attrs); |
1275 | 0 | IGRAPH_ASSERT(igraph_attribute_record_list_empty(new_attrs)); |
1276 | | |
1277 | 0 | todo_items = IGRAPH_CALLOC(no_attrs, igraph_attribute_combination_todo_item_t); |
1278 | 0 | IGRAPH_CHECK_OOM(todo_items, "Cannot combine attributes."); |
1279 | 0 | IGRAPH_FINALLY(igraph_free, todo_items); |
1280 | |
|
1281 | 0 | for (igraph_int_t i = 0; i < no_attrs; i++) { |
1282 | 0 | const igraph_attribute_record_t *oldrec = igraph_attribute_record_list_get_ptr(attrs, i); |
1283 | 0 | const char *name = oldrec->name; |
1284 | 0 | igraph_attribute_combination_type_t type; |
1285 | 0 | igraph_function_pointer_t voidfunc; |
1286 | 0 | IGRAPH_CHECK(igraph_attribute_combination_query(comb, name, &type, &voidfunc)); |
1287 | 0 | todo_items[i].type = type; |
1288 | 0 | todo_items[i].func.as_void = voidfunc; |
1289 | 0 | } |
1290 | | |
1291 | 0 | IGRAPH_FINALLY(igraph_attribute_record_list_clear, new_attrs); |
1292 | |
|
1293 | 0 | for (igraph_int_t i = 0; i < no_attrs; i++) { |
1294 | 0 | const igraph_attribute_record_t *oldrec = igraph_attribute_record_list_get_ptr(attrs, i); |
1295 | 0 | igraph_attribute_record_t newrec; |
1296 | 0 | const char *name = oldrec->name; |
1297 | 0 | igraph_attribute_combination_todo_item_t todo_item = todo_items[i]; |
1298 | 0 | igraph_attribute_type_t attr_type = oldrec->type; |
1299 | |
|
1300 | 0 | if (todo_item.type == IGRAPH_ATTRIBUTE_COMBINE_DEFAULT || |
1301 | 0 | todo_item.type == IGRAPH_ATTRIBUTE_COMBINE_IGNORE) { |
1302 | 0 | continue; |
1303 | 0 | } |
1304 | | |
1305 | 0 | IGRAPH_CHECK(igraph_attribute_record_init(&newrec, name, attr_type)); |
1306 | 0 | IGRAPH_FINALLY(igraph_attribute_record_destroy, &newrec); |
1307 | |
|
1308 | 0 | IGRAPH_CHECK(igraph_attribute_record_resize(&newrec, igraph_vector_int_list_size(merges))); |
1309 | | |
1310 | 0 | if (attr_type == IGRAPH_ATTRIBUTE_NUMERIC) { |
1311 | 0 | switch (todo_item.type) { |
1312 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION: |
1313 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cn_func(oldrec, &newrec, merges, |
1314 | 0 | todo_item.func.as_num)); |
1315 | 0 | break; |
1316 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_SUM: |
1317 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cn_sum(oldrec, &newrec, merges)); |
1318 | 0 | break; |
1319 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_PROD: |
1320 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cn_prod(oldrec, &newrec, merges)); |
1321 | 0 | break; |
1322 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MIN: |
1323 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cn_min(oldrec, &newrec, merges)); |
1324 | 0 | break; |
1325 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MAX: |
1326 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cn_max(oldrec, &newrec, merges)); |
1327 | 0 | break; |
1328 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_RANDOM: |
1329 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cn_random(oldrec, &newrec, merges)); |
1330 | 0 | break; |
1331 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_FIRST: |
1332 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cn_first(oldrec, &newrec, merges)); |
1333 | 0 | break; |
1334 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_LAST: |
1335 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cn_last(oldrec, &newrec, merges)); |
1336 | 0 | break; |
1337 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MEAN: |
1338 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cn_mean(oldrec, &newrec, merges)); |
1339 | 0 | break; |
1340 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN: |
1341 | 0 | IGRAPH_ERROR("Median calculation not implemented.", |
1342 | 0 | IGRAPH_UNIMPLEMENTED); |
1343 | 0 | break; |
1344 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_CONCAT: |
1345 | 0 | IGRAPH_ERROR("Cannot concatenate numeric attributes.", |
1346 | 0 | IGRAPH_EATTRCOMBINE); |
1347 | 0 | break; |
1348 | 0 | default: |
1349 | 0 | IGRAPH_ERROR("Unknown attribute combination.", |
1350 | 0 | IGRAPH_UNIMPLEMENTED); |
1351 | 0 | break; |
1352 | 0 | } |
1353 | 0 | } else if (attr_type == IGRAPH_ATTRIBUTE_BOOLEAN) { |
1354 | 0 | switch (todo_item.type) { |
1355 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION: |
1356 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cb_func(oldrec, &newrec, merges, |
1357 | 0 | todo_item.func.as_bool)); |
1358 | 0 | break; |
1359 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_SUM: |
1360 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MAX: |
1361 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cb_any_is_true(oldrec, &newrec, merges)); |
1362 | 0 | break; |
1363 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_PROD: |
1364 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MIN: |
1365 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cb_all_is_true(oldrec, &newrec, merges)); |
1366 | 0 | break; |
1367 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MEAN: |
1368 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN: |
1369 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cb_majority(oldrec, &newrec, merges)); |
1370 | 0 | break; |
1371 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_RANDOM: |
1372 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cb_random(oldrec, &newrec, merges)); |
1373 | 0 | break; |
1374 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_FIRST: |
1375 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cb_first(oldrec, &newrec, merges)); |
1376 | 0 | break; |
1377 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_LAST: |
1378 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cb_last(oldrec, &newrec, merges)); |
1379 | 0 | break; |
1380 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_CONCAT: |
1381 | 0 | IGRAPH_ERROR("Cannot calculate concatenation of Booleans.", |
1382 | 0 | IGRAPH_EATTRCOMBINE); |
1383 | 0 | break; |
1384 | 0 | default: |
1385 | 0 | IGRAPH_ERROR("Unknown attribute combination.", |
1386 | 0 | IGRAPH_UNIMPLEMENTED); |
1387 | 0 | break; |
1388 | 0 | } |
1389 | 0 | } else if (attr_type == IGRAPH_ATTRIBUTE_STRING) { |
1390 | 0 | switch (todo_item.type) { |
1391 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION: |
1392 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cs_func(oldrec, &newrec, merges, |
1393 | 0 | todo_item.func.as_str)); |
1394 | 0 | break; |
1395 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_SUM: |
1396 | 0 | IGRAPH_ERROR("Cannot sum strings.", IGRAPH_EATTRCOMBINE); |
1397 | 0 | break; |
1398 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_PROD: |
1399 | 0 | IGRAPH_ERROR("Cannot multiply strings.", IGRAPH_EATTRCOMBINE); |
1400 | 0 | break; |
1401 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MIN: |
1402 | 0 | IGRAPH_ERROR("Cannot find minimum of strings.", |
1403 | 0 | IGRAPH_EATTRCOMBINE); |
1404 | 0 | break; |
1405 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MAX: |
1406 | 0 | IGRAPH_ERROR("Cannot find maximum of strings.", |
1407 | 0 | IGRAPH_EATTRCOMBINE); |
1408 | 0 | break; |
1409 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MEAN: |
1410 | 0 | IGRAPH_ERROR("Cannot calculate mean of strings.", |
1411 | 0 | IGRAPH_EATTRCOMBINE); |
1412 | 0 | break; |
1413 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN: |
1414 | 0 | IGRAPH_ERROR("Cannot calculate median of strings.", |
1415 | 0 | IGRAPH_EATTRCOMBINE); |
1416 | 0 | break; |
1417 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_RANDOM: |
1418 | 0 | IGRAPH_CHECK(igraph_i_cattributes_sn_random(oldrec, &newrec, merges)); |
1419 | 0 | break; |
1420 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_FIRST: |
1421 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cs_first(oldrec, &newrec, merges)); |
1422 | 0 | break; |
1423 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_LAST: |
1424 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cs_last(oldrec, &newrec, merges)); |
1425 | 0 | break; |
1426 | 0 | case IGRAPH_ATTRIBUTE_COMBINE_CONCAT: |
1427 | 0 | IGRAPH_CHECK(igraph_i_cattributes_cs_concat(oldrec, &newrec, merges)); |
1428 | 0 | break; |
1429 | 0 | default: |
1430 | 0 | IGRAPH_ERROR("Unknown attribute combination.", |
1431 | 0 | IGRAPH_UNIMPLEMENTED); |
1432 | 0 | break; |
1433 | 0 | } |
1434 | 0 | } else { |
1435 | 0 | IGRAPH_ERROR("Unknown attribute type, this should not happen.", |
1436 | 0 | IGRAPH_UNIMPLEMENTED); |
1437 | 0 | } |
1438 | | |
1439 | 0 | IGRAPH_CHECK(igraph_attribute_record_list_push_back(new_attrs, &newrec)); |
1440 | 0 | IGRAPH_FINALLY_CLEAN(1); /* ownership of newrec transferred */ |
1441 | 0 | } |
1442 | | |
1443 | 0 | IGRAPH_FREE(todo_items); |
1444 | 0 | IGRAPH_FINALLY_CLEAN(2); |
1445 | |
|
1446 | 0 | return IGRAPH_SUCCESS; |
1447 | 0 | } |
1448 | | |
1449 | | static igraph_error_t igraph_i_cattribute_combine_vertices( |
1450 | | const igraph_t *graph, igraph_t *newgraph, |
1451 | | const igraph_vector_int_list_t *merges, const igraph_attribute_combination_t *comb |
1452 | 0 | ) { |
1453 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
1454 | 0 | igraph_i_cattributes_t *toattr = newgraph->attr; |
1455 | 0 | return igraph_i_cattribute_combine_attribute_record_lists( |
1456 | 0 | &attr->val, &toattr->val, merges, comb |
1457 | 0 | ); |
1458 | 0 | } |
1459 | | |
1460 | | static igraph_error_t igraph_i_cattribute_add_edges( |
1461 | | igraph_t *graph, const igraph_vector_int_t *edges, |
1462 | | const igraph_attribute_record_list_t *nattr |
1463 | 2.21k | ) { |
1464 | 2.21k | igraph_int_t ne = igraph_vector_int_size(edges) / 2; |
1465 | 2.21k | igraph_i_cattributes_t *attr = graph->attr; |
1466 | 2.21k | return igraph_i_cattribute_add_vertices_or_edges(&attr->eal, igraph_ecount(graph), ne, nattr); |
1467 | 2.21k | } |
1468 | | |
1469 | | static igraph_error_t igraph_i_cattribute_permute_edges(const igraph_t *graph, |
1470 | | igraph_t *newgraph, |
1471 | 0 | const igraph_vector_int_t *idx) { |
1472 | 0 | igraph_i_cattributes_t *attr = graph->attr, *new_attr = newgraph->attr; |
1473 | 0 | igraph_attribute_record_list_t *eal = &attr->eal, *new_eal = &new_attr->eal; |
1474 | 0 | if (graph == newgraph) { |
1475 | 0 | return igraph_i_cattribute_permute_attribute_record_list_in_place(eal, idx); |
1476 | 0 | } else { |
1477 | 0 | return igraph_i_cattribute_permute_attribute_record_list(eal, new_eal, idx); |
1478 | 0 | } |
1479 | 0 | } |
1480 | | |
1481 | | static igraph_error_t igraph_i_cattribute_combine_edges( |
1482 | | const igraph_t *graph, igraph_t *newgraph, |
1483 | | const igraph_vector_int_list_t *merges, const igraph_attribute_combination_t *comb |
1484 | 0 | ) { |
1485 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
1486 | 0 | igraph_i_cattributes_t *toattr = newgraph->attr; |
1487 | 0 | return igraph_i_cattribute_combine_attribute_record_lists( |
1488 | 0 | &attr->eal, &toattr->eal, merges, comb |
1489 | 0 | ); |
1490 | 0 | } |
1491 | | |
1492 | | static igraph_error_t igraph_i_cattribute_get_info(const igraph_t *graph, |
1493 | | igraph_strvector_t *gnames, |
1494 | | igraph_vector_int_t *gtypes, |
1495 | | igraph_strvector_t *vnames, |
1496 | | igraph_vector_int_t *vtypes, |
1497 | | igraph_strvector_t *enames, |
1498 | 0 | igraph_vector_int_t *etypes) { |
1499 | |
|
1500 | 0 | igraph_strvector_t *names[3] = { gnames, vnames, enames }; |
1501 | 0 | igraph_vector_int_t *types[3] = { gtypes, vtypes, etypes }; |
1502 | 0 | igraph_i_cattributes_t *at = graph->attr; |
1503 | 0 | igraph_attribute_record_list_t *attr[3] = { &at->gal, &at->val, &at->eal }; |
1504 | |
|
1505 | 0 | for (igraph_int_t i = 0; i < 3; i++) { |
1506 | 0 | igraph_strvector_t *n = names[i]; |
1507 | 0 | igraph_vector_int_t *t = types[i]; |
1508 | 0 | const igraph_attribute_record_list_t *al = attr[i]; |
1509 | 0 | igraph_int_t len = igraph_attribute_record_list_size(al); |
1510 | |
|
1511 | 0 | if (n) { |
1512 | 0 | IGRAPH_CHECK(igraph_strvector_resize(n, len)); |
1513 | 0 | } |
1514 | 0 | if (t) { |
1515 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(t, len)); |
1516 | 0 | } |
1517 | | |
1518 | 0 | for (igraph_int_t j = 0; j < len; j++) { |
1519 | 0 | const igraph_attribute_record_t *rec = igraph_attribute_record_list_get_ptr(al, j); |
1520 | 0 | const char *name = rec->name; |
1521 | 0 | igraph_attribute_type_t type = rec->type; |
1522 | 0 | if (n) { |
1523 | 0 | IGRAPH_CHECK(igraph_strvector_set(n, j, name)); |
1524 | 0 | } |
1525 | 0 | if (t) { |
1526 | 0 | VECTOR(*t)[j] = type; |
1527 | 0 | } |
1528 | 0 | } |
1529 | 0 | } |
1530 | | |
1531 | 0 | return IGRAPH_SUCCESS; |
1532 | 0 | } |
1533 | | |
1534 | | static igraph_bool_t igraph_i_cattribute_has_attr(const igraph_t *graph, |
1535 | | igraph_attribute_elemtype_t type, |
1536 | 121k | const char *name) { |
1537 | 121k | const igraph_i_cattributes_t *at = graph->attr; |
1538 | 121k | switch (type) { |
1539 | 0 | case IGRAPH_ATTRIBUTE_GRAPH: |
1540 | 0 | return igraph_i_cattribute_find_index(&at->gal, name) >= 0; |
1541 | 76.4k | case IGRAPH_ATTRIBUTE_VERTEX: |
1542 | 76.4k | return igraph_i_cattribute_find_index(&at->val, name) >= 0; |
1543 | 44.5k | case IGRAPH_ATTRIBUTE_EDGE: |
1544 | 44.5k | return igraph_i_cattribute_find_index(&at->eal, name) >= 0; |
1545 | 0 | default: |
1546 | 0 | IGRAPH_ERROR("Unknown attribute element type.", IGRAPH_EINVAL); |
1547 | 0 | break; |
1548 | 121k | } |
1549 | | |
1550 | 0 | return false; |
1551 | 121k | } |
1552 | | |
1553 | | static igraph_error_t igraph_i_cattribute_get_type(const igraph_t *graph, |
1554 | | igraph_attribute_type_t *type, |
1555 | | igraph_attribute_elemtype_t elemtype, |
1556 | 4.49k | const char *name) { |
1557 | 4.49k | igraph_attribute_record_t *rec; |
1558 | 4.49k | igraph_i_cattributes_t *at = graph->attr; |
1559 | 4.49k | igraph_attribute_record_list_t *al; |
1560 | | |
1561 | 4.49k | switch (elemtype) { |
1562 | 0 | case IGRAPH_ATTRIBUTE_GRAPH: |
1563 | 0 | al = &at->gal; |
1564 | 0 | break; |
1565 | 3.35k | case IGRAPH_ATTRIBUTE_VERTEX: |
1566 | 3.35k | al = &at->val; |
1567 | 3.35k | break; |
1568 | 1.13k | case IGRAPH_ATTRIBUTE_EDGE: |
1569 | 1.13k | al = &at->eal; |
1570 | 1.13k | break; |
1571 | 0 | default: |
1572 | 0 | IGRAPH_ERROR("Unknown attribute element type.", IGRAPH_EINVAL); |
1573 | 0 | break; |
1574 | 4.49k | } |
1575 | | |
1576 | 4.49k | IGRAPH_CHECK(igraph_i_cattribute_find_or_return(al, name, IGRAPH_ATTRIBUTE_UNSPECIFIED, &rec)); |
1577 | 4.49k | *type = rec->type; |
1578 | | |
1579 | 4.49k | return IGRAPH_SUCCESS; |
1580 | 4.49k | } |
1581 | | |
1582 | | static igraph_error_t igraph_i_cattribute_get_numeric_graph_attr( |
1583 | | const igraph_t *graph, const char *name, igraph_vector_t *value |
1584 | 0 | ) { |
1585 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
1586 | 0 | igraph_attribute_record_list_t *gal = &attr->gal; |
1587 | 0 | igraph_attribute_record_t *rec; |
1588 | |
|
1589 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_return(gal, name, IGRAPH_ATTRIBUTE_NUMERIC, &rec)); |
1590 | 0 | IGRAPH_CHECK(igraph_vector_push_back(value, VECTOR(*rec->value.as_vector)[0])); |
1591 | | |
1592 | 0 | return IGRAPH_SUCCESS; |
1593 | 0 | } |
1594 | | |
1595 | | static igraph_error_t igraph_i_cattribute_get_bool_graph_attr( |
1596 | | const igraph_t *graph, const char *name, igraph_vector_bool_t *value |
1597 | 0 | ) { |
1598 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
1599 | 0 | igraph_attribute_record_list_t *gal = &attr->gal; |
1600 | 0 | igraph_attribute_record_t *rec; |
1601 | |
|
1602 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_return(gal, name, IGRAPH_ATTRIBUTE_BOOLEAN, &rec)); |
1603 | 0 | IGRAPH_CHECK(igraph_vector_bool_push_back(value, VECTOR(*rec->value.as_vector_bool)[0])); |
1604 | | |
1605 | 0 | return IGRAPH_SUCCESS; |
1606 | 0 | } |
1607 | | |
1608 | | static igraph_error_t igraph_i_cattribute_get_string_graph_attr( |
1609 | | const igraph_t *graph, const char *name, igraph_strvector_t *value |
1610 | 0 | ) { |
1611 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
1612 | 0 | igraph_attribute_record_list_t *gal = &attr->gal; |
1613 | 0 | igraph_attribute_record_t *rec; |
1614 | |
|
1615 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_return(gal, name, IGRAPH_ATTRIBUTE_STRING, &rec)); |
1616 | 0 | IGRAPH_CHECK(igraph_strvector_push_back(value, igraph_strvector_get(rec->value.as_strvector, 0))); |
1617 | | |
1618 | 0 | return IGRAPH_SUCCESS; |
1619 | 0 | } |
1620 | | |
1621 | | static igraph_error_t igraph_i_cattribute_get_numeric_vertex_attr(const igraph_t *graph, |
1622 | | const char *name, |
1623 | | igraph_vs_t vs, |
1624 | 3.01M | igraph_vector_t *value) { |
1625 | 3.01M | igraph_i_cattributes_t *attr = graph->attr; |
1626 | 3.01M | igraph_attribute_record_list_t *val = &attr->val; |
1627 | 3.01M | igraph_attribute_record_t *rec; |
1628 | 3.01M | const igraph_vector_t *num; |
1629 | | |
1630 | 3.01M | IGRAPH_CHECK(igraph_i_cattribute_find_or_return(val, name, IGRAPH_ATTRIBUTE_NUMERIC, &rec)); |
1631 | | |
1632 | 3.01M | num = rec->value.as_vector; |
1633 | 3.01M | if (igraph_vs_is_all(&vs)) { |
1634 | 0 | IGRAPH_CHECK(igraph_vector_append(value, num)); |
1635 | 3.01M | } else { |
1636 | 3.01M | igraph_vit_t it; |
1637 | 3.01M | igraph_int_t i = igraph_vector_size(value); |
1638 | 3.01M | IGRAPH_CHECK(igraph_vit_create(graph, vs, &it)); |
1639 | 3.01M | IGRAPH_FINALLY(igraph_vit_destroy, &it); |
1640 | 3.01M | IGRAPH_CHECK(igraph_vector_resize(value, i + IGRAPH_VIT_SIZE(it))); |
1641 | 6.02M | for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) { |
1642 | 3.01M | igraph_int_t v = IGRAPH_VIT_GET(it); |
1643 | 3.01M | VECTOR(*value)[i] = VECTOR(*num)[v]; |
1644 | 3.01M | } |
1645 | 3.01M | igraph_vit_destroy(&it); |
1646 | 3.01M | IGRAPH_FINALLY_CLEAN(1); |
1647 | 3.01M | } |
1648 | | |
1649 | 3.01M | return IGRAPH_SUCCESS; |
1650 | 3.01M | } |
1651 | | |
1652 | | static igraph_error_t igraph_i_cattribute_get_bool_vertex_attr(const igraph_t *graph, |
1653 | | const char *name, |
1654 | | igraph_vs_t vs, |
1655 | 20.2M | igraph_vector_bool_t *value) { |
1656 | 20.2M | igraph_i_cattributes_t *attr = graph->attr; |
1657 | 20.2M | igraph_attribute_record_list_t *val = &attr->val; |
1658 | 20.2M | igraph_attribute_record_t *rec; |
1659 | 20.2M | const igraph_vector_bool_t *log; |
1660 | | |
1661 | 20.2M | IGRAPH_CHECK(igraph_i_cattribute_find_or_return(val, name, IGRAPH_ATTRIBUTE_BOOLEAN, &rec)); |
1662 | | |
1663 | 20.2M | log = rec->value.as_vector_bool; |
1664 | 20.2M | if (igraph_vs_is_all(&vs)) { |
1665 | 0 | IGRAPH_CHECK(igraph_vector_bool_append(value, log)); |
1666 | 20.2M | } else { |
1667 | 20.2M | igraph_vit_t it; |
1668 | 20.2M | igraph_int_t i = igraph_vector_bool_size(value); |
1669 | 20.2M | IGRAPH_CHECK(igraph_vit_create(graph, vs, &it)); |
1670 | 20.2M | IGRAPH_FINALLY(igraph_vit_destroy, &it); |
1671 | 20.2M | IGRAPH_CHECK(igraph_vector_bool_resize(value, i + IGRAPH_VIT_SIZE(it))); |
1672 | 40.4M | for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) { |
1673 | 20.2M | igraph_int_t v = IGRAPH_VIT_GET(it); |
1674 | 20.2M | VECTOR(*value)[i] = VECTOR(*log)[v]; |
1675 | 20.2M | } |
1676 | 20.2M | igraph_vit_destroy(&it); |
1677 | 20.2M | IGRAPH_FINALLY_CLEAN(1); |
1678 | 20.2M | } |
1679 | | |
1680 | 20.2M | return IGRAPH_SUCCESS; |
1681 | 20.2M | } |
1682 | | |
1683 | | static igraph_error_t igraph_i_cattribute_get_string_vertex_attr(const igraph_t *graph, |
1684 | | const char *name, |
1685 | | igraph_vs_t vs, |
1686 | 3.50M | igraph_strvector_t *value) { |
1687 | 3.50M | igraph_i_cattributes_t *attr = graph->attr; |
1688 | 3.50M | igraph_attribute_record_list_t *val = &attr->val; |
1689 | 3.50M | igraph_attribute_record_t *rec; |
1690 | 3.50M | const igraph_strvector_t *str; |
1691 | | |
1692 | 3.50M | IGRAPH_CHECK(igraph_i_cattribute_find_or_return(val, name, IGRAPH_ATTRIBUTE_STRING, &rec)); |
1693 | | |
1694 | 3.50M | str = rec->value.as_strvector; |
1695 | 3.50M | if (igraph_vs_is_all(&vs)) { |
1696 | 0 | igraph_strvector_clear(value); |
1697 | 0 | IGRAPH_CHECK(igraph_strvector_append(value, str)); |
1698 | 3.50M | } else { |
1699 | 3.50M | igraph_vit_t it; |
1700 | 3.50M | igraph_int_t i = igraph_strvector_size(value); |
1701 | 3.50M | IGRAPH_CHECK(igraph_vit_create(graph, vs, &it)); |
1702 | 3.50M | IGRAPH_FINALLY(igraph_vit_destroy, &it); |
1703 | 3.50M | IGRAPH_CHECK(igraph_strvector_resize(value, i + IGRAPH_VIT_SIZE(it))); |
1704 | 7.01M | for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) { |
1705 | 3.50M | igraph_int_t v = IGRAPH_VIT_GET(it); |
1706 | 3.50M | IGRAPH_CHECK(igraph_strvector_set(value, i, igraph_strvector_get(str, v))); |
1707 | 3.50M | } |
1708 | 3.50M | igraph_vit_destroy(&it); |
1709 | 3.50M | IGRAPH_FINALLY_CLEAN(1); |
1710 | 3.50M | } |
1711 | | |
1712 | 3.50M | return IGRAPH_SUCCESS; |
1713 | 3.50M | } |
1714 | | |
1715 | | static igraph_error_t igraph_i_cattribute_get_numeric_edge_attr( |
1716 | | const igraph_t *graph, const char *name, igraph_es_t es, igraph_vector_t *value |
1717 | 3.54M | ) { |
1718 | 3.54M | igraph_i_cattributes_t *attr = graph->attr; |
1719 | 3.54M | igraph_attribute_record_list_t *eal = &attr->eal; |
1720 | 3.54M | igraph_attribute_record_t *rec; |
1721 | 3.54M | const igraph_vector_t *num; |
1722 | | |
1723 | 3.54M | IGRAPH_CHECK(igraph_i_cattribute_find_or_return(eal, name, IGRAPH_ATTRIBUTE_NUMERIC, &rec)); |
1724 | | |
1725 | 3.54M | num = rec->value.as_vector; |
1726 | 3.54M | if (igraph_es_is_all(&es)) { |
1727 | 0 | IGRAPH_CHECK(igraph_vector_append(value, num)); |
1728 | 3.54M | } else { |
1729 | 3.54M | igraph_eit_t it; |
1730 | 3.54M | igraph_int_t i = igraph_vector_size(value); |
1731 | 3.54M | IGRAPH_CHECK(igraph_eit_create(graph, es, &it)); |
1732 | 3.54M | IGRAPH_FINALLY(igraph_eit_destroy, &it); |
1733 | 3.54M | IGRAPH_CHECK(igraph_vector_resize(value, i + IGRAPH_EIT_SIZE(it))); |
1734 | 7.09M | for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) { |
1735 | 3.54M | igraph_int_t e = IGRAPH_EIT_GET(it); |
1736 | 3.54M | VECTOR(*value)[i] = VECTOR(*num)[e]; |
1737 | 3.54M | } |
1738 | 3.54M | igraph_eit_destroy(&it); |
1739 | 3.54M | IGRAPH_FINALLY_CLEAN(1); |
1740 | 3.54M | } |
1741 | | |
1742 | 3.54M | return IGRAPH_SUCCESS; |
1743 | 3.54M | } |
1744 | | |
1745 | | static igraph_error_t igraph_i_cattribute_get_string_edge_attr( |
1746 | | const igraph_t *graph, const char *name, igraph_es_t es, |
1747 | | igraph_strvector_t *value |
1748 | 726k | ) { |
1749 | 726k | igraph_i_cattributes_t *attr = graph->attr; |
1750 | 726k | igraph_attribute_record_list_t *eal = &attr->eal; |
1751 | 726k | igraph_attribute_record_t *rec; |
1752 | 726k | const igraph_strvector_t *str; |
1753 | | |
1754 | 726k | IGRAPH_CHECK(igraph_i_cattribute_find_or_return(eal, name, IGRAPH_ATTRIBUTE_STRING, &rec)); |
1755 | | |
1756 | 726k | str = rec->value.as_strvector; |
1757 | 726k | if (igraph_es_is_all(&es)) { |
1758 | 0 | IGRAPH_CHECK(igraph_strvector_append(value, str)); |
1759 | 726k | } else { |
1760 | 726k | igraph_eit_t it; |
1761 | 726k | igraph_int_t i = igraph_strvector_size(value); |
1762 | 726k | IGRAPH_CHECK(igraph_eit_create(graph, es, &it)); |
1763 | 726k | IGRAPH_FINALLY(igraph_eit_destroy, &it); |
1764 | 726k | IGRAPH_CHECK(igraph_strvector_resize(value, i + IGRAPH_EIT_SIZE(it))); |
1765 | 1.45M | for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) { |
1766 | 726k | igraph_int_t e = IGRAPH_EIT_GET(it); |
1767 | 726k | IGRAPH_CHECK(igraph_strvector_set(value, i, igraph_strvector_get(str, e))); |
1768 | 726k | } |
1769 | 726k | igraph_eit_destroy(&it); |
1770 | 726k | IGRAPH_FINALLY_CLEAN(1); |
1771 | 726k | } |
1772 | | |
1773 | 726k | return IGRAPH_SUCCESS; |
1774 | 726k | } |
1775 | | |
1776 | | static igraph_error_t igraph_i_cattribute_get_bool_edge_attr( |
1777 | | const igraph_t *graph, const char *name, igraph_es_t es, |
1778 | | igraph_vector_bool_t *value |
1779 | 0 | ) { |
1780 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
1781 | 0 | igraph_attribute_record_list_t *eal = &attr->eal; |
1782 | 0 | igraph_attribute_record_t *rec; |
1783 | 0 | const igraph_vector_bool_t *log; |
1784 | |
|
1785 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_return(eal, name, IGRAPH_ATTRIBUTE_BOOLEAN, &rec)); |
1786 | | |
1787 | 0 | log = rec->value.as_vector_bool; |
1788 | 0 | if (igraph_es_is_all(&es)) { |
1789 | 0 | IGRAPH_CHECK(igraph_vector_bool_append(value, log)); |
1790 | 0 | } else { |
1791 | 0 | igraph_eit_t it; |
1792 | 0 | igraph_int_t i = igraph_vector_bool_size(value); |
1793 | 0 | IGRAPH_CHECK(igraph_eit_create(graph, es, &it)); |
1794 | 0 | IGRAPH_FINALLY(igraph_eit_destroy, &it); |
1795 | 0 | IGRAPH_CHECK(igraph_vector_bool_resize(value, i + IGRAPH_EIT_SIZE(it))); |
1796 | 0 | for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) { |
1797 | 0 | igraph_int_t e = IGRAPH_EIT_GET(it); |
1798 | 0 | VECTOR(*value)[i] = VECTOR(*log)[e]; |
1799 | 0 | } |
1800 | 0 | igraph_eit_destroy(&it); |
1801 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1802 | 0 | } |
1803 | | |
1804 | 0 | return IGRAPH_SUCCESS; |
1805 | 0 | } |
1806 | | |
1807 | | /* -------------------------------------- */ |
1808 | | |
1809 | | const igraph_attribute_table_t igraph_cattribute_table = { |
1810 | | &igraph_i_cattribute_init, |
1811 | | &igraph_i_cattribute_destroy, |
1812 | | &igraph_i_cattribute_copy, |
1813 | | &igraph_i_cattribute_add_vertices, |
1814 | | &igraph_i_cattribute_permute_vertices, |
1815 | | &igraph_i_cattribute_combine_vertices, |
1816 | | &igraph_i_cattribute_add_edges, |
1817 | | &igraph_i_cattribute_permute_edges, |
1818 | | &igraph_i_cattribute_combine_edges, |
1819 | | &igraph_i_cattribute_get_info, |
1820 | | &igraph_i_cattribute_has_attr, |
1821 | | &igraph_i_cattribute_get_type, |
1822 | | &igraph_i_cattribute_get_numeric_graph_attr, |
1823 | | &igraph_i_cattribute_get_string_graph_attr, |
1824 | | &igraph_i_cattribute_get_bool_graph_attr, |
1825 | | &igraph_i_cattribute_get_numeric_vertex_attr, |
1826 | | &igraph_i_cattribute_get_string_vertex_attr, |
1827 | | &igraph_i_cattribute_get_bool_vertex_attr, |
1828 | | &igraph_i_cattribute_get_numeric_edge_attr, |
1829 | | &igraph_i_cattribute_get_string_edge_attr, |
1830 | | &igraph_i_cattribute_get_bool_edge_attr |
1831 | | }; |
1832 | | |
1833 | | /* -------------------------------------- */ |
1834 | | |
1835 | | /** |
1836 | | * \section cattributes |
1837 | | * <para>There is an experimental attribute handler that can be used |
1838 | | * from C code. In this section we show how this works. This attribute |
1839 | | * handler is by default not attached (the default is no attribute |
1840 | | * handler), so we first need to attach it: |
1841 | | * <programlisting> |
1842 | | * igraph_set_attribute_table(&igraph_cattribute_table); |
1843 | | * </programlisting> |
1844 | | * </para> |
1845 | | * <para>Now the attribute functions are available. Please note that |
1846 | | * the attribute handler must be attached before you call any other |
1847 | | * igraph functions, otherwise you might end up with graphs without |
1848 | | * attributes and an active attribute handler, which might cause |
1849 | | * unexpected program behaviour. The rule is that you attach the |
1850 | | * attribute handler in the beginning of your |
1851 | | * <function>main()</function> and never touch it again. Detaching |
1852 | | * the attribute handler might lead to memory leaks.</para> |
1853 | | * |
1854 | | * <para>It is not currently possible to have attribute handlers on a |
1855 | | * per-graph basis. All graphs in an application must be managed with |
1856 | | * the same attribute handler. This also applies to the default case |
1857 | | * when there is no attribute handler at all.</para> |
1858 | | * |
1859 | | * <para>The C attribute handler supports attaching real numbers, boolean |
1860 | | * values and character strings as attributes. No vector values are allowed. |
1861 | | * For example, vertices have a <code>name</code> attribute holding a single |
1862 | | * string value for each vertex, but it is not possible to have a <code>coords</code> |
1863 | | * attribute which is a vector of numbers per vertex.</para> |
1864 | | * |
1865 | | * <para>The functions documented in this section are specific to the C |
1866 | | * attribute handler. Code using these functions will not function when |
1867 | | * a different attribute handler is attached.</para> |
1868 | | * |
1869 | | * \example examples/simple/cattributes.c |
1870 | | * \example examples/simple/cattributes2.c |
1871 | | * \example examples/simple/cattributes3.c |
1872 | | * \example examples/simple/cattributes4.c |
1873 | | */ |
1874 | | |
1875 | | /** |
1876 | | * \function igraph_cattribute_GAN |
1877 | | * \brief Query a numeric graph attribute. |
1878 | | * |
1879 | | * Returns the value of the given numeric graph attribute. |
1880 | | * If the attribute does not exist, a warning is issued |
1881 | | * and NaN is returned. |
1882 | | * |
1883 | | * \param graph The input graph. |
1884 | | * \param name The name of the attribute to query. |
1885 | | * \return The value of the attribute. |
1886 | | * |
1887 | | * \sa \ref GAN for a simpler interface. |
1888 | | * |
1889 | | * Time complexity: O(Ag), the number of graph attributes. |
1890 | | */ |
1891 | 0 | igraph_real_t igraph_cattribute_GAN(const igraph_t *graph, const char *name) { |
1892 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
1893 | 0 | const igraph_attribute_record_t *rec; |
1894 | 0 | const igraph_vector_t *num; |
1895 | |
|
1896 | 0 | rec = igraph_i_cattribute_find(&attr->gal, name, IGRAPH_ATTRIBUTE_NUMERIC); |
1897 | 0 | if (!rec) { |
1898 | 0 | IGRAPH_WARNINGF("Graph attribute '%s' does not exist, returning default numeric attribute value.", name); |
1899 | 0 | return IGRAPH_NAN; |
1900 | 0 | } |
1901 | | |
1902 | 0 | num = rec->value.as_vector; |
1903 | 0 | return VECTOR(*num)[0]; |
1904 | 0 | } |
1905 | | |
1906 | | /** |
1907 | | * \function igraph_cattribute_GAB |
1908 | | * \brief Query a boolean graph attribute. |
1909 | | * |
1910 | | * Returns the value of the given boolean graph attribute. |
1911 | | * If the attribute does not exist, a warning is issued |
1912 | | * and false is returned. |
1913 | | * |
1914 | | * \param graph The input graph. |
1915 | | * \param name The name of the attribute to query. |
1916 | | * \return The value of the attribute. |
1917 | | * |
1918 | | * \sa \ref GAB for a simpler interface. |
1919 | | * |
1920 | | * Time complexity: O(Ag), the number of graph attributes. |
1921 | | */ |
1922 | 0 | igraph_bool_t igraph_cattribute_GAB(const igraph_t *graph, const char *name) { |
1923 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
1924 | 0 | const igraph_attribute_record_t *rec; |
1925 | 0 | const igraph_vector_bool_t *log; |
1926 | |
|
1927 | 0 | rec = igraph_i_cattribute_find(&attr->gal, name, IGRAPH_ATTRIBUTE_BOOLEAN); |
1928 | 0 | if (!rec) { |
1929 | 0 | IGRAPH_WARNINGF("Graph attribute '%s' does not exist, returning default boolean attribute value.", name); |
1930 | 0 | return false; |
1931 | 0 | } |
1932 | | |
1933 | 0 | log = rec->value.as_vector_bool; |
1934 | 0 | return VECTOR(*log)[0]; |
1935 | 0 | } |
1936 | | |
1937 | | /** |
1938 | | * \function igraph_cattribute_GAS |
1939 | | * \brief Query a string graph attribute. |
1940 | | * |
1941 | | * Returns a <type>const</type> pointer to the string graph attribute |
1942 | | * specified in \p name. The value must not be modified. |
1943 | | * If the attribute does not exist, a warning is issued and |
1944 | | * an empty string is returned. |
1945 | | * |
1946 | | * \param graph The input graph. |
1947 | | * \param name The name of the attribute to query. |
1948 | | * \return The value of the attribute. |
1949 | | * |
1950 | | * \sa \ref GAS for a simpler interface. |
1951 | | * |
1952 | | * Time complexity: O(Ag), the number of graph attributes. |
1953 | | */ |
1954 | 0 | const char *igraph_cattribute_GAS(const igraph_t *graph, const char *name) { |
1955 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
1956 | 0 | const igraph_attribute_record_t *rec; |
1957 | 0 | const igraph_strvector_t *str; |
1958 | |
|
1959 | 0 | rec = igraph_i_cattribute_find(&attr->gal, name, IGRAPH_ATTRIBUTE_STRING); |
1960 | 0 | if (!rec) { |
1961 | 0 | IGRAPH_WARNINGF("Graph attribute '%s' does not exist, returning default string attribute value.", name); |
1962 | 0 | return ""; |
1963 | 0 | } |
1964 | | |
1965 | 0 | str = rec->value.as_strvector; |
1966 | 0 | return igraph_strvector_get(str, 0); |
1967 | 0 | } |
1968 | | |
1969 | | /** |
1970 | | * \function igraph_cattribute_VAN |
1971 | | * \brief Query a numeric vertex attribute. |
1972 | | * |
1973 | | * If the attribute does not exist, a warning is issued and |
1974 | | * NaN is returned. See \ref igraph_cattribute_VANV() for |
1975 | | * an error-checked version. |
1976 | | * |
1977 | | * \param graph The input graph. |
1978 | | * \param name The name of the attribute. |
1979 | | * \param vid The id of the queried vertex. |
1980 | | * \return The value of the attribute. |
1981 | | * |
1982 | | * \sa \ref VAN macro for a simpler interface. |
1983 | | * |
1984 | | * Time complexity: O(Av), the number of vertex attributes. |
1985 | | */ |
1986 | | igraph_real_t igraph_cattribute_VAN(const igraph_t *graph, const char *name, |
1987 | 0 | igraph_int_t vid) { |
1988 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
1989 | 0 | const igraph_attribute_record_t *rec; |
1990 | 0 | const igraph_vector_t *num; |
1991 | |
|
1992 | 0 | rec = igraph_i_cattribute_find(&attr->val, name, IGRAPH_ATTRIBUTE_NUMERIC); |
1993 | 0 | if (!rec) { |
1994 | 0 | IGRAPH_WARNINGF("Vertex attribute '%s' does not exist, returning default numeric attribute value.", name); |
1995 | 0 | return IGRAPH_NAN; |
1996 | 0 | } |
1997 | | |
1998 | 0 | num = rec->value.as_vector; |
1999 | 0 | return VECTOR(*num)[vid]; |
2000 | 0 | } |
2001 | | |
2002 | | /** |
2003 | | * \function igraph_cattribute_VAB |
2004 | | * \brief Query a boolean vertex attribute. |
2005 | | * |
2006 | | * If the vertex attribute does not exist, a warning is issued |
2007 | | * and false is returned. See \ref igraph_cattribute_VABV() for |
2008 | | * an error-checked version. |
2009 | | * |
2010 | | * \param graph The input graph. |
2011 | | * \param name The name of the attribute. |
2012 | | * \param vid The id of the queried vertex. |
2013 | | * \return The value of the attribute. |
2014 | | * |
2015 | | * \sa \ref VAB macro for a simpler interface. |
2016 | | * |
2017 | | * Time complexity: O(Av), the number of vertex attributes. |
2018 | | */ |
2019 | | igraph_bool_t igraph_cattribute_VAB(const igraph_t *graph, const char *name, |
2020 | 0 | igraph_int_t vid) { |
2021 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2022 | 0 | const igraph_attribute_record_t *rec; |
2023 | 0 | const igraph_vector_bool_t *log; |
2024 | |
|
2025 | 0 | rec = igraph_i_cattribute_find(&attr->val, name, IGRAPH_ATTRIBUTE_BOOLEAN); |
2026 | 0 | if (!rec) { |
2027 | 0 | IGRAPH_WARNINGF("Vertex attribute '%s' does not exist, returning default boolean attribute value.", name); |
2028 | 0 | return false; |
2029 | 0 | } |
2030 | | |
2031 | 0 | log = rec->value.as_vector_bool; |
2032 | 0 | return VECTOR(*log)[vid]; |
2033 | 0 | } |
2034 | | |
2035 | | /** |
2036 | | * \function igraph_cattribute_VAS |
2037 | | * \brief Query a string vertex attribute. |
2038 | | * |
2039 | | * Returns a <type>const</type> pointer to the string vertex attribute |
2040 | | * specified in \p name. The value must not be modified. |
2041 | | * If the vertex attribute does not exist, a warning is issued and |
2042 | | * an empty string is returned. See \ref igraph_cattribute_VASV() |
2043 | | * for an error-checked version. |
2044 | | * |
2045 | | * \param graph The input graph. |
2046 | | * \param name The name of the attribute. |
2047 | | * \param vid The id of the queried vertex. |
2048 | | * \return The value of the attribute. |
2049 | | * |
2050 | | * \sa The macro \ref VAS for a simpler interface. |
2051 | | * |
2052 | | * Time complexity: O(Av), the number of vertex attributes. |
2053 | | */ |
2054 | | const char *igraph_cattribute_VAS(const igraph_t *graph, const char *name, |
2055 | 0 | igraph_int_t vid) { |
2056 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2057 | 0 | const igraph_attribute_record_t *rec; |
2058 | 0 | const igraph_strvector_t *str; |
2059 | |
|
2060 | 0 | rec = igraph_i_cattribute_find(&attr->val, name, IGRAPH_ATTRIBUTE_STRING); |
2061 | 0 | if (!rec) { |
2062 | 0 | IGRAPH_WARNINGF("Vertex attribute '%s' does not exist, returning default string attribute value.", name); |
2063 | 0 | return ""; |
2064 | 0 | } |
2065 | | |
2066 | 0 | str = rec->value.as_strvector; |
2067 | 0 | return igraph_strvector_get(str, vid); |
2068 | 0 | } |
2069 | | |
2070 | | /** |
2071 | | * \function igraph_cattribute_EAN |
2072 | | * \brief Query a numeric edge attribute. |
2073 | | * |
2074 | | * If the attribute does not exist, a warning is issued and |
2075 | | * NaN is returned. See \ref igraph_cattribute_EANV() for |
2076 | | * an error-checked version. |
2077 | | * |
2078 | | * \param graph The input graph. |
2079 | | * \param name The name of the attribute. |
2080 | | * \param eid The id of the queried edge. |
2081 | | * \return The value of the attribute. |
2082 | | * |
2083 | | * \sa \ref EAN for an easier interface. |
2084 | | * |
2085 | | * Time complexity: O(Ae), the number of edge attributes. |
2086 | | */ |
2087 | | igraph_real_t igraph_cattribute_EAN(const igraph_t *graph, const char *name, |
2088 | 0 | igraph_int_t eid) { |
2089 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2090 | 0 | const igraph_attribute_record_t *rec; |
2091 | 0 | const igraph_vector_t *num; |
2092 | |
|
2093 | 0 | rec = igraph_i_cattribute_find(&attr->eal, name, IGRAPH_ATTRIBUTE_NUMERIC); |
2094 | 0 | if (!rec) { |
2095 | 0 | IGRAPH_WARNINGF("Edge attribute '%s' does not exist, returning default numeric attribute value.", name); |
2096 | 0 | return IGRAPH_NAN; |
2097 | 0 | } |
2098 | | |
2099 | 0 | num = rec->value.as_vector; |
2100 | 0 | return VECTOR(*num)[eid]; |
2101 | 0 | } |
2102 | | |
2103 | | /** |
2104 | | * \function igraph_cattribute_EAB |
2105 | | * \brief Query a boolean edge attribute. |
2106 | | * |
2107 | | * If the edge attribute does not exist, a warning is issued and |
2108 | | * false is returned. See \ref igraph_cattribute_EABV() for |
2109 | | * an error-checked version. |
2110 | | * |
2111 | | * \param graph The input graph. |
2112 | | * \param name The name of the attribute. |
2113 | | * \param eid The id of the queried edge. |
2114 | | * \return The value of the attribute. |
2115 | | * |
2116 | | * \sa \ref EAB for an easier interface. |
2117 | | * |
2118 | | * Time complexity: O(Ae), the number of edge attributes. |
2119 | | */ |
2120 | | igraph_bool_t igraph_cattribute_EAB(const igraph_t *graph, const char *name, |
2121 | 0 | igraph_int_t eid) { |
2122 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2123 | 0 | const igraph_attribute_record_t *rec; |
2124 | 0 | const igraph_vector_bool_t *log; |
2125 | |
|
2126 | 0 | rec = igraph_i_cattribute_find(&attr->eal, name, IGRAPH_ATTRIBUTE_BOOLEAN); |
2127 | 0 | if (!rec) { |
2128 | 0 | IGRAPH_WARNINGF("Edge attribute '%s' does not exist, returning default boolean attribute value.", name); |
2129 | 0 | return false; |
2130 | 0 | } |
2131 | | |
2132 | 0 | log = rec->value.as_vector_bool; |
2133 | 0 | return VECTOR(*log)[eid]; |
2134 | 0 | } |
2135 | | |
2136 | | /** |
2137 | | * \function igraph_cattribute_EAS |
2138 | | * \brief Query a string edge attribute. |
2139 | | * |
2140 | | * Returns a <type>const</type> pointer to the string edge attribute |
2141 | | * specified in \p name. The value must not be modified. |
2142 | | * If the edge attribute does not exist, a warning is issued and |
2143 | | * an empty string is returned. See \ref igraph_cattribute_EASV() for |
2144 | | * an error-checked version. |
2145 | | * |
2146 | | * \param graph The input graph. |
2147 | | * \param name The name of the attribute. |
2148 | | * \param eid The id of the queried edge. |
2149 | | * \return The value of the attribute. |
2150 | | * |
2151 | | * \se \ref EAS if you want to type less. |
2152 | | * |
2153 | | * Time complexity: O(Ae), the number of edge attributes. |
2154 | | */ |
2155 | | const char *igraph_cattribute_EAS(const igraph_t *graph, const char *name, |
2156 | 0 | igraph_int_t eid) { |
2157 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2158 | 0 | const igraph_attribute_record_t *rec; |
2159 | 0 | const igraph_strvector_t *str; |
2160 | |
|
2161 | 0 | rec = igraph_i_cattribute_find(&attr->eal, name, IGRAPH_ATTRIBUTE_STRING); |
2162 | 0 | if (!rec) { |
2163 | 0 | IGRAPH_WARNINGF("Edge attribute '%s' does not exist, returning default string attribute value.", name); |
2164 | 0 | return ""; |
2165 | 0 | } |
2166 | | |
2167 | 0 | str = rec->value.as_strvector; |
2168 | 0 | return igraph_strvector_get(str, eid); |
2169 | 0 | } |
2170 | | |
2171 | | /** |
2172 | | * \function igraph_cattribute_VANV |
2173 | | * \brief Query a numeric vertex attribute for many vertices. |
2174 | | * |
2175 | | * \param graph The input graph. |
2176 | | * \param name The name of the attribute. |
2177 | | * \param vids The vertices to query. |
2178 | | * \param result Pointer to an initialized vector, the result is |
2179 | | * stored here. It will be resized, if needed. |
2180 | | * \return Error code. |
2181 | | * |
2182 | | * Time complexity: O(v), where v is the number of vertices in 'vids'. |
2183 | | */ |
2184 | | |
2185 | | igraph_error_t igraph_cattribute_VANV(const igraph_t *graph, const char *name, |
2186 | 0 | igraph_vs_t vids, igraph_vector_t *result) { |
2187 | 0 | igraph_vector_clear(result); |
2188 | 0 | return igraph_i_cattribute_get_numeric_vertex_attr(graph, name, vids, result); |
2189 | 0 | } |
2190 | | |
2191 | | /** |
2192 | | * \function igraph_cattribute_VABV |
2193 | | * \brief Query a boolean vertex attribute for many vertices. |
2194 | | * |
2195 | | * \param graph The input graph. |
2196 | | * \param name The name of the attribute. |
2197 | | * \param vids The vertices to query. |
2198 | | * \param result Pointer to an initialized boolean vector, the result is |
2199 | | * stored here. It will be resized, if needed. |
2200 | | * \return Error code. |
2201 | | * |
2202 | | * Time complexity: O(v), where v is the number of vertices in 'vids'. |
2203 | | */ |
2204 | | |
2205 | | igraph_error_t igraph_cattribute_VABV(const igraph_t *graph, const char *name, |
2206 | 0 | igraph_vs_t vids, igraph_vector_bool_t *result) { |
2207 | 0 | igraph_vector_bool_clear(result); |
2208 | 0 | return igraph_i_cattribute_get_bool_vertex_attr(graph, name, vids, result); |
2209 | 0 | } |
2210 | | |
2211 | | /** |
2212 | | * \function igraph_cattribute_EANV |
2213 | | * \brief Query a numeric edge attribute for many edges. |
2214 | | * |
2215 | | * \param graph The input graph. |
2216 | | * \param name The name of the attribute. |
2217 | | * \param eids The edges to query. |
2218 | | * \param result Pointer to an initialized vector, the result is |
2219 | | * stored here. It will be resized, if needed. |
2220 | | * \return Error code. |
2221 | | * |
2222 | | * Time complexity: O(e), where e is the number of edges in 'eids'. |
2223 | | */ |
2224 | | |
2225 | | igraph_error_t igraph_cattribute_EANV(const igraph_t *graph, const char *name, |
2226 | 0 | igraph_es_t eids, igraph_vector_t *result) { |
2227 | 0 | igraph_vector_clear(result); |
2228 | 0 | return igraph_i_cattribute_get_numeric_edge_attr(graph, name, eids, result); |
2229 | 0 | } |
2230 | | |
2231 | | /** |
2232 | | * \function igraph_cattribute_EABV |
2233 | | * \brief Query a boolean edge attribute for many edges. |
2234 | | * |
2235 | | * \param graph The input graph. |
2236 | | * \param name The name of the attribute. |
2237 | | * \param eids The edges to query. |
2238 | | * \param result Pointer to an initialized boolean vector, the result is |
2239 | | * stored here. It will be resized, if needed. |
2240 | | * \return Error code. |
2241 | | * |
2242 | | * Time complexity: O(e), where e is the number of edges in 'eids'. |
2243 | | */ |
2244 | | |
2245 | | igraph_error_t igraph_cattribute_EABV(const igraph_t *graph, const char *name, |
2246 | 0 | igraph_es_t eids, igraph_vector_bool_t *result) { |
2247 | 0 | igraph_vector_bool_clear(result); |
2248 | 0 | return igraph_i_cattribute_get_bool_edge_attr(graph, name, eids, result); |
2249 | 0 | } |
2250 | | |
2251 | | /** |
2252 | | * \function igraph_cattribute_VASV |
2253 | | * \brief Query a string vertex attribute for many vertices. |
2254 | | * |
2255 | | * \param graph The input graph. |
2256 | | * \param name The name of the attribute. |
2257 | | * \param vids The vertices to query. |
2258 | | * \param result Pointer to an initialized string vector, the result |
2259 | | * is stored here. It will be resized, if needed. |
2260 | | * \return Error code. |
2261 | | * |
2262 | | * Time complexity: O(v), where v is the number of vertices in 'vids'. |
2263 | | * (We assume that the string attributes have a bounded length.) |
2264 | | */ |
2265 | | |
2266 | | igraph_error_t igraph_cattribute_VASV(const igraph_t *graph, const char *name, |
2267 | 0 | igraph_vs_t vids, igraph_strvector_t *result) { |
2268 | 0 | igraph_strvector_clear(result); |
2269 | 0 | return igraph_i_cattribute_get_string_vertex_attr(graph, name, vids, result); |
2270 | 0 | } |
2271 | | |
2272 | | /** |
2273 | | * \function igraph_cattribute_EASV |
2274 | | * \brief Query a string edge attribute for many edges. |
2275 | | * |
2276 | | * \param graph The input graph. |
2277 | | * \param name The name of the attribute. |
2278 | | * \param eids The edges to query. |
2279 | | * \param result Pointer to an initialized string vector, the result |
2280 | | * is stored here. It will be resized, if needed. |
2281 | | * \return Error code. |
2282 | | * |
2283 | | * Time complexity: O(e), where e is the number of edges in |
2284 | | * 'eids'. (We assume that the string attributes have a bounded length.) |
2285 | | */ |
2286 | | |
2287 | | igraph_error_t igraph_cattribute_EASV(const igraph_t *graph, const char *name, |
2288 | 0 | igraph_es_t eids, igraph_strvector_t *result) { |
2289 | 0 | igraph_strvector_clear(result); |
2290 | 0 | return igraph_i_cattribute_get_string_edge_attr(graph, name, eids, result); |
2291 | 0 | } |
2292 | | |
2293 | | /** |
2294 | | * \function igraph_cattribute_list |
2295 | | * \brief List all attributes. |
2296 | | * |
2297 | | * See \ref igraph_attribute_type_t for the various attribute types. |
2298 | | * \param graph The input graph. |
2299 | | * \param gnames String vector, the names of the graph attributes. |
2300 | | * \param gtypes Numeric vector, the types of the graph attributes. |
2301 | | * \param vnames String vector, the names of the vertex attributes. |
2302 | | * \param vtypes Numeric vector, the types of the vertex attributes. |
2303 | | * \param enames String vector, the names of the edge attributes. |
2304 | | * \param etypes Numeric vector, the types of the edge attributes. |
2305 | | * \return Error code. |
2306 | | * |
2307 | | * Naturally, the string vector with the attribute names and the |
2308 | | * numeric vector with the attribute types are in the right order, |
2309 | | * i.e. the first name corresponds to the first type, etc. |
2310 | | * |
2311 | | * Time complexity: O(Ag+Av+Ae), the number of all attributes. |
2312 | | */ |
2313 | | igraph_error_t igraph_cattribute_list(const igraph_t *graph, |
2314 | | igraph_strvector_t *gnames, igraph_vector_int_t *gtypes, |
2315 | | igraph_strvector_t *vnames, igraph_vector_int_t *vtypes, |
2316 | 0 | igraph_strvector_t *enames, igraph_vector_int_t *etypes) { |
2317 | 0 | return igraph_i_cattribute_get_info(graph, gnames, gtypes, vnames, vtypes, |
2318 | 0 | enames, etypes); |
2319 | 0 | } |
2320 | | |
2321 | | /** |
2322 | | * \function igraph_cattribute_has_attr |
2323 | | * \brief Checks whether a (graph, vertex or edge) attribute exists. |
2324 | | * |
2325 | | * \param graph The graph. |
2326 | | * \param type The type of the attribute, \c IGRAPH_ATTRIBUTE_GRAPH, |
2327 | | * \c IGRAPH_ATTRIBUTE_VERTEX or \c IGRAPH_ATTRIBUTE_EDGE. |
2328 | | * \param name Character constant, the name of the attribute. |
2329 | | * \return Boolean value, \c true if the attribute exists, \c false otherwise. |
2330 | | * |
2331 | | * Time complexity: O(A), the number of (graph, vertex or edge) |
2332 | | * attributes, assuming attribute names are not too long. |
2333 | | */ |
2334 | | igraph_bool_t igraph_cattribute_has_attr(const igraph_t *graph, |
2335 | | igraph_attribute_elemtype_t type, |
2336 | 0 | const char *name) { |
2337 | 0 | return igraph_i_cattribute_has_attr(graph, type, name); |
2338 | 0 | } |
2339 | | |
2340 | | /** |
2341 | | * \function igraph_cattribute_GAN_set |
2342 | | * \brief Set a numeric graph attribute. |
2343 | | * |
2344 | | * \param graph The graph. |
2345 | | * \param name Name of the graph attribute. If there is no such |
2346 | | * attribute yet, then it will be added. |
2347 | | * \param value The (new) value of the graph attribute. |
2348 | | * \return Error code. |
2349 | | * |
2350 | | * \se \ref SETGAN if you want to type less. |
2351 | | * |
2352 | | * Time complexity: O(1). |
2353 | | */ |
2354 | | igraph_error_t igraph_cattribute_GAN_set(igraph_t *graph, const char *name, |
2355 | 0 | igraph_real_t value) { |
2356 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2357 | 0 | igraph_attribute_record_t *rec; |
2358 | 0 | igraph_vector_t *num; |
2359 | |
|
2360 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create( |
2361 | 0 | &attr->gal, name, IGRAPH_ATTRIBUTE_NUMERIC, 1, &rec |
2362 | 0 | )); |
2363 | | |
2364 | 0 | num = rec->value.as_vector; |
2365 | 0 | VECTOR(*num)[0] = value; |
2366 | |
|
2367 | 0 | return IGRAPH_SUCCESS; |
2368 | 0 | } |
2369 | | |
2370 | | /** |
2371 | | * \function igraph_cattribute_GAB_set |
2372 | | * \brief Set a boolean graph attribute. |
2373 | | * |
2374 | | * \param graph The graph. |
2375 | | * \param name Name of the graph attribute. If there is no such |
2376 | | * attribute yet, then it will be added. |
2377 | | * \param value The (new) value of the graph attribute. |
2378 | | * \return Error code. |
2379 | | * |
2380 | | * \se \ref SETGAN if you want to type less. |
2381 | | * |
2382 | | * Time complexity: O(1). |
2383 | | */ |
2384 | | igraph_error_t igraph_cattribute_GAB_set(igraph_t *graph, const char *name, |
2385 | 0 | igraph_bool_t value) { |
2386 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2387 | 0 | igraph_attribute_record_t *rec; |
2388 | 0 | igraph_vector_bool_t *log; |
2389 | |
|
2390 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create( |
2391 | 0 | &attr->gal, name, IGRAPH_ATTRIBUTE_BOOLEAN, 1, &rec |
2392 | 0 | )); |
2393 | | |
2394 | 0 | log = rec->value.as_vector_bool; |
2395 | 0 | VECTOR(*log)[0] = value; |
2396 | |
|
2397 | 0 | return IGRAPH_SUCCESS; |
2398 | 0 | } |
2399 | | |
2400 | | /** |
2401 | | * \function igraph_cattribute_GAS_set |
2402 | | * \brief Set a string graph attribute. |
2403 | | * |
2404 | | * \param graph The graph. |
2405 | | * \param name Name of the graph attribute. If there is no such |
2406 | | * attribute yet, then it will be added. |
2407 | | * \param value The (new) value of the graph attribute. It will be |
2408 | | * copied. |
2409 | | * \return Error code. |
2410 | | * |
2411 | | * \se \ref SETGAS if you want to type less. |
2412 | | * |
2413 | | * Time complexity: O(1). |
2414 | | */ |
2415 | | igraph_error_t igraph_cattribute_GAS_set(igraph_t *graph, const char *name, |
2416 | 0 | const char *value) { |
2417 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2418 | 0 | igraph_attribute_record_t *rec; |
2419 | 0 | igraph_strvector_t *str; |
2420 | |
|
2421 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create( |
2422 | 0 | &attr->gal, name, IGRAPH_ATTRIBUTE_STRING, 1, &rec |
2423 | 0 | )); |
2424 | | |
2425 | 0 | str = rec->value.as_strvector; |
2426 | 0 | IGRAPH_CHECK(igraph_strvector_set(str, 0, value)); |
2427 | | |
2428 | 0 | return IGRAPH_SUCCESS; |
2429 | 0 | } |
2430 | | |
2431 | | /** |
2432 | | * \function igraph_cattribute_VAN_set |
2433 | | * \brief Set a numeric vertex attribute. |
2434 | | * |
2435 | | * The attribute will be added if not present already. If present it |
2436 | | * will be overwritten. The same \p value is set for all vertices |
2437 | | * included in \p vid. |
2438 | | * \param graph The graph. |
2439 | | * \param name Name of the attribute. |
2440 | | * \param vid Vertices for which to set the attribute. |
2441 | | * \param value The (new) value of the attribute. |
2442 | | * \return Error code. |
2443 | | * |
2444 | | * \sa \ref SETVAN for a simpler way. |
2445 | | * |
2446 | | * Time complexity: O(n), the number of vertices if the attribute is |
2447 | | * new, O(|vid|) otherwise. |
2448 | | */ |
2449 | | igraph_error_t igraph_cattribute_VAN_set(igraph_t *graph, const char *name, |
2450 | 0 | igraph_int_t vid, igraph_real_t value) { |
2451 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2452 | 0 | igraph_attribute_record_t *rec; |
2453 | |
|
2454 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create( |
2455 | 0 | &attr->val, name, IGRAPH_ATTRIBUTE_NUMERIC, igraph_vcount(graph), &rec |
2456 | 0 | )); |
2457 | 0 | VECTOR(*rec->value.as_vector)[vid] = value; |
2458 | |
|
2459 | 0 | return IGRAPH_SUCCESS; |
2460 | 0 | } |
2461 | | |
2462 | | /** |
2463 | | * \function igraph_cattribute_VAB_set |
2464 | | * \brief Set a boolean vertex attribute. |
2465 | | * |
2466 | | * The attribute will be added if not present already. If present it |
2467 | | * will be overwritten. The same \p value is set for all vertices |
2468 | | * included in \p vid. |
2469 | | * \param graph The graph. |
2470 | | * \param name Name of the attribute. |
2471 | | * \param vid Vertices for which to set the attribute. |
2472 | | * \param value The (new) value of the attribute. |
2473 | | * \return Error code. |
2474 | | * |
2475 | | * \sa \ref SETVAB for a simpler way. |
2476 | | * |
2477 | | * Time complexity: O(n), the number of vertices if the attribute is |
2478 | | * new, O(|vid|) otherwise. |
2479 | | */ |
2480 | | igraph_error_t igraph_cattribute_VAB_set(igraph_t *graph, const char *name, |
2481 | 0 | igraph_int_t vid, igraph_bool_t value) { |
2482 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2483 | 0 | igraph_attribute_record_t *rec; |
2484 | |
|
2485 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create( |
2486 | 0 | &attr->val, name, IGRAPH_ATTRIBUTE_BOOLEAN, igraph_vcount(graph), &rec |
2487 | 0 | )); |
2488 | 0 | VECTOR(*rec->value.as_vector_bool)[vid] = value; |
2489 | |
|
2490 | 0 | return IGRAPH_SUCCESS; |
2491 | 0 | } |
2492 | | |
2493 | | /** |
2494 | | * \function igraph_cattribute_VAS_set |
2495 | | * \brief Set a string vertex attribute. |
2496 | | * |
2497 | | * The attribute will be added if not present already. If present it |
2498 | | * will be overwritten. The same \p value is set for all vertices |
2499 | | * included in \p vid. |
2500 | | * \param graph The graph. |
2501 | | * \param name Name of the attribute. |
2502 | | * \param vid Vertices for which to set the attribute. |
2503 | | * \param value The (new) value of the attribute. |
2504 | | * \return Error code. |
2505 | | * |
2506 | | * \sa \ref SETVAS for a simpler way. |
2507 | | * |
2508 | | * Time complexity: O(n*l), n is the number of vertices, l is the |
2509 | | * length of the string to set. If the attribute if not new then only |
2510 | | * O(|vid|*l). |
2511 | | */ |
2512 | | igraph_error_t igraph_cattribute_VAS_set(igraph_t *graph, const char *name, |
2513 | 0 | igraph_int_t vid, const char *value) { |
2514 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2515 | 0 | igraph_attribute_record_t *rec; |
2516 | |
|
2517 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create( |
2518 | 0 | &attr->val, name, IGRAPH_ATTRIBUTE_STRING, igraph_vcount(graph), &rec |
2519 | 0 | )); |
2520 | 0 | IGRAPH_CHECK(igraph_strvector_set(rec->value.as_strvector, vid, value)); |
2521 | | |
2522 | 0 | return IGRAPH_SUCCESS; |
2523 | 0 | } |
2524 | | |
2525 | | /** |
2526 | | * \function igraph_cattribute_EAN_set |
2527 | | * \brief Set a numeric edge attribute. |
2528 | | * |
2529 | | * The attribute will be added if not present already. If present it |
2530 | | * will be overwritten. The same \p value is set for all edges |
2531 | | * included in \p vid. |
2532 | | * \param graph The graph. |
2533 | | * \param name Name of the attribute. |
2534 | | * \param eid Edges for which to set the attribute. |
2535 | | * \param value The (new) value of the attribute. |
2536 | | * \return Error code. |
2537 | | * |
2538 | | * \sa \ref SETEAN for a simpler way. |
2539 | | * |
2540 | | * Time complexity: O(e), the number of edges if the attribute is |
2541 | | * new, O(|eid|) otherwise. |
2542 | | */ |
2543 | | igraph_error_t igraph_cattribute_EAN_set(igraph_t *graph, const char *name, |
2544 | 0 | igraph_int_t eid, igraph_real_t value) { |
2545 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2546 | 0 | igraph_attribute_record_t *rec; |
2547 | |
|
2548 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create( |
2549 | 0 | &attr->eal, name, IGRAPH_ATTRIBUTE_NUMERIC, igraph_ecount(graph), &rec |
2550 | 0 | )); |
2551 | 0 | VECTOR(*rec->value.as_vector)[eid] = value; |
2552 | |
|
2553 | 0 | return IGRAPH_SUCCESS; |
2554 | 0 | } |
2555 | | |
2556 | | /** |
2557 | | * \function igraph_cattribute_EAB_set |
2558 | | * \brief Set a boolean edge attribute. |
2559 | | * |
2560 | | * The attribute will be added if not present already. If present it |
2561 | | * will be overwritten. The same \p value is set for all edges |
2562 | | * included in \p vid. |
2563 | | * \param graph The graph. |
2564 | | * \param name Name of the attribute. |
2565 | | * \param eid Edges for which to set the attribute. |
2566 | | * \param value The (new) value of the attribute. |
2567 | | * \return Error code. |
2568 | | * |
2569 | | * \sa \ref SETEAB for a simpler way. |
2570 | | * |
2571 | | * Time complexity: O(e), the number of edges if the attribute is |
2572 | | * new, O(|eid|) otherwise. |
2573 | | */ |
2574 | | igraph_error_t igraph_cattribute_EAB_set(igraph_t *graph, const char *name, |
2575 | 0 | igraph_int_t eid, igraph_bool_t value) { |
2576 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2577 | 0 | igraph_attribute_record_t *rec; |
2578 | |
|
2579 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create( |
2580 | 0 | &attr->eal, name, IGRAPH_ATTRIBUTE_BOOLEAN, igraph_ecount(graph), &rec |
2581 | 0 | )); |
2582 | 0 | VECTOR(*rec->value.as_vector_bool)[eid] = value; |
2583 | |
|
2584 | 0 | return IGRAPH_SUCCESS; |
2585 | 0 | } |
2586 | | |
2587 | | /** |
2588 | | * \function igraph_cattribute_EAS_set |
2589 | | * \brief Set a string edge attribute. |
2590 | | * |
2591 | | * The attribute will be added if not present already. If present it |
2592 | | * will be overwritten. The same \p value is set for all edges |
2593 | | * included in \p vid. |
2594 | | * \param graph The graph. |
2595 | | * \param name Name of the attribute. |
2596 | | * \param eid Edges for which to set the attribute. |
2597 | | * \param value The (new) value of the attribute. |
2598 | | * \return Error code. |
2599 | | * |
2600 | | * \sa \ref SETEAS for a simpler way. |
2601 | | * |
2602 | | * Time complexity: O(e*l), n is the number of edges, l is the |
2603 | | * length of the string to set. If the attribute if not new then only |
2604 | | * O(|eid|*l). |
2605 | | */ |
2606 | | igraph_error_t igraph_cattribute_EAS_set(igraph_t *graph, const char *name, |
2607 | 0 | igraph_int_t eid, const char *value) { |
2608 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2609 | 0 | igraph_attribute_record_t *rec; |
2610 | |
|
2611 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create( |
2612 | 0 | &attr->eal, name, IGRAPH_ATTRIBUTE_STRING, igraph_ecount(graph), &rec |
2613 | 0 | )); |
2614 | 0 | IGRAPH_CHECK(igraph_strvector_set(rec->value.as_strvector, eid, value)); |
2615 | | |
2616 | 0 | return IGRAPH_SUCCESS; |
2617 | 0 | } |
2618 | | |
2619 | | /** |
2620 | | * \function igraph_cattribute_VAN_setv |
2621 | | * \brief Set a numeric vertex attribute for all vertices. |
2622 | | * |
2623 | | * The attribute will be added if not present yet. |
2624 | | * \param graph The graph. |
2625 | | * \param name Name of the attribute. |
2626 | | * \param v The new attribute values. The length of this vector must |
2627 | | * match the number of vertices. |
2628 | | * \return Error code. |
2629 | | * |
2630 | | * \sa \ref SETVANV for a simpler way. |
2631 | | * |
2632 | | * Time complexity: O(n), the number of vertices. |
2633 | | */ |
2634 | | |
2635 | | igraph_error_t igraph_cattribute_VAN_setv(igraph_t *graph, const char *name, |
2636 | 0 | const igraph_vector_t *v) { |
2637 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2638 | 0 | igraph_attribute_record_t *rec; |
2639 | 0 | igraph_int_t nv = igraph_vcount(graph); |
2640 | | |
2641 | | /* Check length first */ |
2642 | 0 | if (igraph_vector_size(v) != nv) { |
2643 | 0 | IGRAPH_ERROR("Invalid vertex attribute vector length.", IGRAPH_EINVAL); |
2644 | 0 | } |
2645 | | |
2646 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->val, name, IGRAPH_ATTRIBUTE_NUMERIC, nv, &rec)); |
2647 | 0 | IGRAPH_CHECK(igraph_vector_update(rec->value.as_vector, v)); |
2648 | | |
2649 | 0 | return IGRAPH_SUCCESS; |
2650 | 0 | } |
2651 | | |
2652 | | /** |
2653 | | * \function igraph_cattribute_VAB_setv |
2654 | | * \brief Set a boolean vertex attribute for all vertices. |
2655 | | * |
2656 | | * The attribute will be added if not present yet. |
2657 | | * \param graph The graph. |
2658 | | * \param name Name of the attribute. |
2659 | | * \param v The new attribute values. The length of this boolean vector must |
2660 | | * match the number of vertices. |
2661 | | * \return Error code. |
2662 | | * |
2663 | | * \sa \ref SETVANV for a simpler way. |
2664 | | * |
2665 | | * Time complexity: O(n), the number of vertices. |
2666 | | */ |
2667 | | |
2668 | | igraph_error_t igraph_cattribute_VAB_setv(igraph_t *graph, const char *name, |
2669 | 0 | const igraph_vector_bool_t *v) { |
2670 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2671 | 0 | igraph_attribute_record_t *rec; |
2672 | 0 | igraph_int_t nv = igraph_vcount(graph); |
2673 | | |
2674 | | /* Check length first */ |
2675 | 0 | if (igraph_vector_bool_size(v) != nv) { |
2676 | 0 | IGRAPH_ERROR("Invalid vertex attribute vector length.", IGRAPH_EINVAL); |
2677 | 0 | } |
2678 | | |
2679 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->val, name, IGRAPH_ATTRIBUTE_BOOLEAN, nv, &rec)); |
2680 | 0 | IGRAPH_CHECK(igraph_vector_bool_update(rec->value.as_vector_bool, v)); |
2681 | | |
2682 | 0 | return IGRAPH_SUCCESS; |
2683 | 0 | } |
2684 | | |
2685 | | /** |
2686 | | * \function igraph_cattribute_VAS_setv |
2687 | | * \brief Set a string vertex attribute for all vertices. |
2688 | | * |
2689 | | * The attribute will be added if not present yet. |
2690 | | * \param graph The graph. |
2691 | | * \param name Name of the attribute. |
2692 | | * \param sv String vector, the new attribute values. The length of this vector must |
2693 | | * match the number of vertices. |
2694 | | * \return Error code. |
2695 | | * |
2696 | | * \sa \ref SETVASV for a simpler way. |
2697 | | * |
2698 | | * Time complexity: O(n+l), n is the number of vertices, l is the |
2699 | | * total length of the strings. |
2700 | | */ |
2701 | | igraph_error_t igraph_cattribute_VAS_setv(igraph_t *graph, const char *name, |
2702 | 0 | const igraph_strvector_t *sv) { |
2703 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2704 | 0 | igraph_attribute_record_t *rec; |
2705 | 0 | igraph_int_t nv = igraph_vcount(graph); |
2706 | | |
2707 | | /* Check length first */ |
2708 | 0 | if (igraph_strvector_size(sv) != nv) { |
2709 | 0 | IGRAPH_ERROR("Invalid vertex attribute vector length.", IGRAPH_EINVAL); |
2710 | 0 | } |
2711 | | |
2712 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->val, name, IGRAPH_ATTRIBUTE_STRING, nv, &rec)); |
2713 | 0 | IGRAPH_CHECK(igraph_strvector_update(rec->value.as_strvector, sv)); |
2714 | | |
2715 | 0 | return IGRAPH_SUCCESS; |
2716 | 0 | } |
2717 | | |
2718 | | /** |
2719 | | * \function igraph_cattribute_EAN_setv |
2720 | | * \brief Set a numeric edge attribute for all edges. |
2721 | | * |
2722 | | * The attribute will be added if not present yet. |
2723 | | * \param graph The graph. |
2724 | | * \param name Name of the attribute. |
2725 | | * \param v The new attribute values. The length of this vector must |
2726 | | * match the number of edges. |
2727 | | * \return Error code. |
2728 | | * |
2729 | | * \sa \ref SETEANV for a simpler way. |
2730 | | * |
2731 | | * Time complexity: O(e), the number of edges. |
2732 | | */ |
2733 | | igraph_error_t igraph_cattribute_EAN_setv(igraph_t *graph, const char *name, |
2734 | 0 | const igraph_vector_t *v) { |
2735 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2736 | 0 | igraph_attribute_record_t *rec; |
2737 | 0 | igraph_int_t ne = igraph_ecount(graph); |
2738 | | |
2739 | | /* Check length first */ |
2740 | 0 | if (igraph_vector_size(v) != ne) { |
2741 | 0 | IGRAPH_ERROR("Invalid edge attribute vector length.", IGRAPH_EINVAL); |
2742 | 0 | } |
2743 | | |
2744 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->eal, name, IGRAPH_ATTRIBUTE_NUMERIC, ne, &rec)); |
2745 | 0 | IGRAPH_CHECK(igraph_vector_update(rec->value.as_vector, v)); |
2746 | | |
2747 | 0 | return IGRAPH_SUCCESS; |
2748 | 0 | } |
2749 | | |
2750 | | /** |
2751 | | * \function igraph_cattribute_EAB_setv |
2752 | | * \brief Set a boolean edge attribute for all edges. |
2753 | | * |
2754 | | * The attribute will be added if not present yet. |
2755 | | * \param graph The graph. |
2756 | | * \param name Name of the attribute. |
2757 | | * \param v The new attribute values. The length of this vector must |
2758 | | * match the number of edges. |
2759 | | * \return Error code. |
2760 | | * |
2761 | | * \sa \ref SETEABV for a simpler way. |
2762 | | * |
2763 | | * Time complexity: O(e), the number of edges. |
2764 | | */ |
2765 | | igraph_error_t igraph_cattribute_EAB_setv(igraph_t *graph, const char *name, |
2766 | 0 | const igraph_vector_bool_t *v) { |
2767 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2768 | 0 | igraph_attribute_record_t *rec; |
2769 | 0 | igraph_int_t ne = igraph_ecount(graph); |
2770 | | |
2771 | | /* Check length first */ |
2772 | 0 | if (igraph_vector_bool_size(v) != ne) { |
2773 | 0 | IGRAPH_ERROR("Invalid edge attribute vector length.", IGRAPH_EINVAL); |
2774 | 0 | } |
2775 | | |
2776 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->eal, name, IGRAPH_ATTRIBUTE_BOOLEAN, ne, &rec)); |
2777 | 0 | IGRAPH_CHECK(igraph_vector_bool_update(rec->value.as_vector_bool, v)); |
2778 | | |
2779 | 0 | return IGRAPH_SUCCESS; |
2780 | 0 | } |
2781 | | |
2782 | | /** |
2783 | | * \function igraph_cattribute_EAS_setv |
2784 | | * \brief Set a string edge attribute for all edges. |
2785 | | * |
2786 | | * The attribute will be added if not present yet. |
2787 | | * \param graph The graph. |
2788 | | * \param name Name of the attribute. |
2789 | | * \param sv String vector, the new attribute values. The length of this vector must |
2790 | | * match the number of edges. |
2791 | | * \return Error code. |
2792 | | * |
2793 | | * \sa \ref SETEASV for a simpler way. |
2794 | | * |
2795 | | * Time complexity: O(e+l), e is the number of edges, l is the |
2796 | | * total length of the strings. |
2797 | | */ |
2798 | | igraph_error_t igraph_cattribute_EAS_setv(igraph_t *graph, const char *name, |
2799 | 0 | const igraph_strvector_t *sv) { |
2800 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2801 | 0 | igraph_attribute_record_t *rec; |
2802 | 0 | igraph_int_t ne = igraph_ecount(graph); |
2803 | | |
2804 | | /* Check length first */ |
2805 | 0 | if (igraph_strvector_size(sv) != ne) { |
2806 | 0 | IGRAPH_ERROR("Invalid edge attribute vector length.", IGRAPH_EINVAL); |
2807 | 0 | } |
2808 | | |
2809 | 0 | IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->eal, name, IGRAPH_ATTRIBUTE_STRING, ne, &rec)); |
2810 | 0 | IGRAPH_CHECK(igraph_strvector_update(rec->value.as_strvector, sv)); |
2811 | | |
2812 | 0 | return IGRAPH_SUCCESS; |
2813 | 0 | } |
2814 | | |
2815 | | /** |
2816 | | * \function igraph_cattribute_remove_g |
2817 | | * \brief Remove a graph attribute. |
2818 | | * |
2819 | | * \param graph The graph object. |
2820 | | * \param name Name of the graph attribute to remove. |
2821 | | * |
2822 | | * \sa \ref DELGA for a simpler way. |
2823 | | * |
2824 | | */ |
2825 | 0 | void igraph_cattribute_remove_g(igraph_t *graph, const char *name) { |
2826 | |
|
2827 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2828 | 0 | igraph_attribute_record_list_t *gal = &attr->gal; |
2829 | 0 | igraph_int_t j = igraph_i_cattribute_find_index(gal, name); |
2830 | |
|
2831 | 0 | if (j >= 0) { |
2832 | 0 | igraph_attribute_record_list_discard(gal, j); |
2833 | 0 | } else { |
2834 | 0 | IGRAPH_WARNING("Cannot remove non-existent graph attribute"); |
2835 | 0 | } |
2836 | 0 | } |
2837 | | |
2838 | | /** |
2839 | | * \function igraph_cattribute_remove_v |
2840 | | * \brief Remove a vertex attribute. |
2841 | | * |
2842 | | * \param graph The graph object. |
2843 | | * \param name Name of the vertex attribute to remove. |
2844 | | * |
2845 | | * \sa \ref DELVA for a simpler way. |
2846 | | * |
2847 | | */ |
2848 | 0 | void igraph_cattribute_remove_v(igraph_t *graph, const char *name) { |
2849 | |
|
2850 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2851 | 0 | igraph_attribute_record_list_t *val = &attr->val; |
2852 | 0 | igraph_int_t j = igraph_i_cattribute_find_index(val, name); |
2853 | |
|
2854 | 0 | if (j >= 0) { |
2855 | 0 | igraph_attribute_record_list_discard(val, j); |
2856 | 0 | } else { |
2857 | 0 | IGRAPH_WARNING("Cannot remove non-existent graph attribute"); |
2858 | 0 | } |
2859 | 0 | } |
2860 | | |
2861 | | /** |
2862 | | * \function igraph_cattribute_remove_e |
2863 | | * \brief Remove an edge attribute. |
2864 | | * |
2865 | | * \param graph The graph object. |
2866 | | * \param name Name of the edge attribute to remove. |
2867 | | * |
2868 | | * \sa \ref DELEA for a simpler way. |
2869 | | */ |
2870 | 0 | void igraph_cattribute_remove_e(igraph_t *graph, const char *name) { |
2871 | |
|
2872 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2873 | 0 | igraph_attribute_record_list_t *eal = &attr->eal; |
2874 | 0 | igraph_int_t j = igraph_i_cattribute_find_index(eal, name); |
2875 | |
|
2876 | 0 | if (j >= 0) { |
2877 | 0 | igraph_attribute_record_list_discard(eal, j); |
2878 | 0 | } else { |
2879 | 0 | IGRAPH_WARNING("Cannot remove non-existent graph attribute"); |
2880 | 0 | } |
2881 | 0 | } |
2882 | | |
2883 | | /** |
2884 | | * \function igraph_cattribute_remove_all |
2885 | | * \brief Remove all graph/vertex/edge attributes. |
2886 | | * |
2887 | | * \param graph The graph object. |
2888 | | * \param g Boolean, whether to remove graph attributes. |
2889 | | * \param v Boolean, whether to remove vertex attributes. |
2890 | | * \param e Boolean, whether to remove edge attributes. |
2891 | | * |
2892 | | * \sa \ref DELGAS, \ref DELVAS, \ref DELEAS, \ref DELALL for simpler |
2893 | | * ways. |
2894 | | */ |
2895 | | void igraph_cattribute_remove_all(igraph_t *graph, igraph_bool_t g, |
2896 | 0 | igraph_bool_t v, igraph_bool_t e) { |
2897 | |
|
2898 | 0 | igraph_i_cattributes_t *attr = graph->attr; |
2899 | |
|
2900 | 0 | if (g) { |
2901 | 0 | igraph_attribute_record_list_clear(&attr->gal); |
2902 | 0 | } |
2903 | 0 | if (v) { |
2904 | 0 | igraph_attribute_record_list_clear(&attr->val); |
2905 | 0 | } |
2906 | 0 | if (e) { |
2907 | 0 | igraph_attribute_record_list_clear(&attr->eal); |
2908 | 0 | } |
2909 | 0 | } |