haskell-igraph-0.8.5: igraph/src/cattributes.c
/* -*- mode: C -*- */
/*
IGraph library.
Copyright (C) 2005-2012 Gabor Csardi <csardi.gabor@gmail.com>
334 Harvard street, Cambridge, MA 02139 USA
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "igraph_attributes.h"
#include "igraph_memory.h"
#include "igraph_math.h"
#include "igraph_interface.h"
#include "igraph_random.h"
#include "config.h"
#include <string.h>
/* An attribute is either a numeric vector (vector_t) or a string
vector (strvector_t). The attribute itself is stored in a
struct igraph_attribute_record_t, there is one such object for each
attribute. The igraph_t has a pointer to an array of three
vector_ptr_t's which contains pointers to
igraph_i_cattribute_t's. Graph attributes are first, then vertex
and edge attributes. */
igraph_bool_t igraph_i_cattribute_find(const igraph_vector_ptr_t *ptrvec,
const char *name, long int *idx) {
long int i, n = igraph_vector_ptr_size(ptrvec);
igraph_bool_t l = 0;
for (i = 0; !l && i < n; i++) {
igraph_attribute_record_t *rec = VECTOR(*ptrvec)[i];
l = !strcmp(rec->name, name);
}
if (idx) {
*idx = i - 1;
}
return l;
}
typedef struct igraph_i_cattributes_t {
igraph_vector_ptr_t gal;
igraph_vector_ptr_t val;
igraph_vector_ptr_t eal;
} igraph_i_cattributes_t;
int igraph_i_cattributes_copy_attribute_record(igraph_attribute_record_t **newrec,
const igraph_attribute_record_t *rec) {
igraph_vector_t *num, *newnum;
igraph_strvector_t *str, *newstr;
*newrec = igraph_Calloc(1, igraph_attribute_record_t);
if (!(*newrec)) {
IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, *newrec);
(*newrec)->type = rec->type;
(*newrec)->name = strdup(rec->name);
if (!(*newrec)->name) {
IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (void*)(*newrec)->name);
if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
num = (igraph_vector_t *)rec->value;
newnum = igraph_Calloc(1, igraph_vector_t);
if (!newnum) {
IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newnum);
IGRAPH_CHECK(igraph_vector_copy(newnum, num));
IGRAPH_FINALLY(igraph_vector_destroy, newnum);
(*newrec)->value = newnum;
} else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
str = (igraph_strvector_t*)rec->value;
newstr = igraph_Calloc(1, igraph_strvector_t);
if (!newstr) {
IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newstr);
IGRAPH_CHECK(igraph_strvector_copy(newstr, str));
IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
(*newrec)->value = newstr;
} else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
igraph_vector_bool_t *log = (igraph_vector_bool_t*) rec->value;
igraph_vector_bool_t *newlog = igraph_Calloc(1, igraph_vector_bool_t);
if (!newlog) {
IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newlog);
IGRAPH_CHECK(igraph_vector_bool_copy(newlog, log));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newlog);
(*newrec)->value = newlog;
}
IGRAPH_FINALLY_CLEAN(4);
return 0;
}
int igraph_i_cattribute_init(igraph_t *graph, igraph_vector_ptr_t *attr) {
igraph_attribute_record_t *attr_rec;
long int i, n;
igraph_i_cattributes_t *nattr;
n = attr ? igraph_vector_ptr_size(attr) : 0;
nattr = igraph_Calloc(1, igraph_i_cattributes_t);
if (!nattr) {
IGRAPH_ERROR("Can't init attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, nattr);
IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->gal, n));
IGRAPH_FINALLY(igraph_vector_ptr_destroy, &nattr->gal);
IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->val, 0));
IGRAPH_FINALLY(igraph_vector_ptr_destroy, &nattr->val);
IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->eal, 0));
IGRAPH_FINALLY_CLEAN(3);
for (i = 0; i < n; i++) {
IGRAPH_CHECK(igraph_i_cattributes_copy_attribute_record(
&attr_rec, VECTOR(*attr)[i]));
VECTOR(nattr->gal)[i] = attr_rec;
}
graph->attr = nattr;
return 0;
}
void igraph_i_cattribute_destroy(igraph_t *graph) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *als[3] = { &attr->gal, &attr->val, &attr->eal };
long int i, n, a;
igraph_vector_t *num;
igraph_strvector_t *str;
igraph_vector_bool_t *boolvec;
igraph_attribute_record_t *rec;
for (a = 0; a < 3; a++) {
n = igraph_vector_ptr_size(als[a]);
for (i = 0; i < n; i++) {
rec = VECTOR(*als[a])[i];
if (rec) {
if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
num = (igraph_vector_t*)rec->value;
igraph_vector_destroy(num);
igraph_free(num);
} else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
str = (igraph_strvector_t*)rec->value;
igraph_strvector_destroy(str);
igraph_free(str);
} else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
boolvec = (igraph_vector_bool_t*)rec->value;
igraph_vector_bool_destroy(boolvec);
igraph_free(boolvec);
}
igraph_free((char*)rec->name);
igraph_free(rec);
}
}
}
igraph_vector_ptr_destroy(&attr->gal);
igraph_vector_ptr_destroy(&attr->val);
igraph_vector_ptr_destroy(&attr->eal);
igraph_free(graph->attr);
graph->attr = 0;
}
/* Almost the same as destroy, but we might have null pointers */
void igraph_i_cattribute_copy_free(igraph_i_cattributes_t *attr) {
igraph_vector_ptr_t *als[3] = { &attr->gal, &attr->val, &attr->eal };
long int i, n, a;
igraph_vector_t *num;
igraph_strvector_t *str;
igraph_vector_bool_t *boolvec;
igraph_attribute_record_t *rec;
for (a = 0; a < 3; a++) {
n = igraph_vector_ptr_size(als[a]);
for (i = 0; i < n; i++) {
rec = VECTOR(*als[a])[i];
if (!rec) {
continue;
}
if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
num = (igraph_vector_t*)rec->value;
igraph_vector_destroy(num);
igraph_free(num);
} else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
boolvec = (igraph_vector_bool_t*)rec->value;
igraph_vector_bool_destroy(boolvec);
igraph_free(boolvec);
} else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
str = (igraph_strvector_t*)rec->value;
igraph_strvector_destroy(str);
igraph_free(str);
}
igraph_free((char*)rec->name);
igraph_free(rec);
}
}
}
/* No reference counting here. If you use attributes in C you should
know what you're doing. */
int igraph_i_cattribute_copy(igraph_t *to, const igraph_t *from,
igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea) {
igraph_i_cattributes_t *attrfrom = from->attr, *attrto;
igraph_vector_ptr_t *alto[3], *alfrom[3] = { &attrfrom->gal, &attrfrom->val,
&attrfrom->eal
};
long int i, n, a;
igraph_bool_t copy[3] = { ga, va, ea };
to->attr = attrto = igraph_Calloc(1, igraph_i_cattributes_t);
if (!attrto) {
IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, attrto);
IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->gal, 0);
IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->val, 0);
IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->eal, 0);
IGRAPH_FINALLY_CLEAN(3);
IGRAPH_FINALLY(igraph_i_cattribute_copy_free, attrto);
alto[0] = &attrto->gal; alto[1] = &attrto->val; alto[2] = &attrto->eal;
for (a = 0; a < 3; a++) {
if (copy[a]) {
n = igraph_vector_ptr_size(alfrom[a]);
IGRAPH_CHECK(igraph_vector_ptr_resize(alto[a], n));
igraph_vector_ptr_null(alto[a]);
for (i = 0; i < n; i++) {
igraph_attribute_record_t *newrec;
IGRAPH_CHECK(igraph_i_cattributes_copy_attribute_record(&newrec,
VECTOR(*alfrom[a])[i]));
VECTOR(*alto[a])[i] = newrec;
}
}
}
IGRAPH_FINALLY_CLEAN(2);
return 0;
}
int igraph_i_cattribute_add_vertices(igraph_t *graph, long int nv,
igraph_vector_ptr_t *nattr) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int length = igraph_vector_ptr_size(val);
long int nattrno = nattr == NULL ? 0 : igraph_vector_ptr_size(nattr);
long int origlen = igraph_vcount(graph) - nv;
long int newattrs = 0, i;
igraph_vector_t news;
/* First add the new attributes if any */
newattrs = 0;
IGRAPH_VECTOR_INIT_FINALLY(&news, 0);
for (i = 0; i < nattrno; i++) {
igraph_attribute_record_t *nattr_entry = VECTOR(*nattr)[i];
const char *nname = nattr_entry->name;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(val, nname, &j);
if (!l) {
newattrs++;
IGRAPH_CHECK(igraph_vector_push_back(&news, i));
} else {
/* check types */
if (nattr_entry->type !=
((igraph_attribute_record_t*)VECTOR(*val)[j])->type) {
IGRAPH_ERROR("You cannot mix attribute types", IGRAPH_EINVAL);
}
}
}
/* Add NA/empty string vectors for the existing vertices */
if (newattrs != 0) {
for (i = 0; i < newattrs; i++) {
igraph_attribute_record_t *tmp = VECTOR(*nattr)[(long int)VECTOR(news)[i]];
igraph_attribute_record_t *newrec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_attribute_type_t type = tmp->type;
if (!newrec) {
IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newrec);
newrec->type = type;
newrec->name = strdup(tmp->name);
if (!newrec->name) {
IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)newrec->name);
if (type == IGRAPH_ATTRIBUTE_NUMERIC) {
igraph_vector_t *newnum = igraph_Calloc(1, igraph_vector_t);
if (!newnum) {
IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newnum);
IGRAPH_VECTOR_INIT_FINALLY(newnum, origlen);
newrec->value = newnum;
igraph_vector_fill(newnum, IGRAPH_NAN);
} else if (type == IGRAPH_ATTRIBUTE_STRING) {
igraph_strvector_t *newstr = igraph_Calloc(1, igraph_strvector_t);
if (!newstr) {
IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newstr);
IGRAPH_STRVECTOR_INIT_FINALLY(newstr, origlen);
newrec->value = newstr;
} else if (type == IGRAPH_ATTRIBUTE_BOOLEAN) {
igraph_vector_bool_t *newbool = igraph_Calloc(1, igraph_vector_bool_t);
if (!newbool) {
IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newbool);
IGRAPH_CHECK(igraph_vector_bool_init(newbool, origlen));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
newrec->value = newbool;
igraph_vector_bool_fill(newbool, 0);
}
IGRAPH_CHECK(igraph_vector_ptr_push_back(val, newrec));
IGRAPH_FINALLY_CLEAN(4);
}
length = igraph_vector_ptr_size(val);
}
/* Now append the new values */
for (i = 0; i < length; i++) {
igraph_attribute_record_t *oldrec = VECTOR(*val)[i];
igraph_attribute_record_t *newrec = 0;
const char *name = oldrec->name;
long int j;
igraph_bool_t l = 0;
if (nattr) {
l = igraph_i_cattribute_find(nattr, name, &j);
}
if (l) {
/* This attribute is present in nattr */
igraph_vector_t *oldnum, *newnum;
igraph_strvector_t *oldstr, *newstr;
igraph_vector_bool_t *oldbool, *newbool;
newrec = VECTOR(*nattr)[j];
oldnum = (igraph_vector_t*)oldrec->value;
newnum = (igraph_vector_t*)newrec->value;
oldstr = (igraph_strvector_t*)oldrec->value;
newstr = (igraph_strvector_t*)newrec->value;
oldbool = (igraph_vector_bool_t*)oldrec->value;
newbool = (igraph_vector_bool_t*)newrec->value;
if (oldrec->type != newrec->type) {
IGRAPH_ERROR("Attribute types do not match", IGRAPH_EINVAL);
}
switch (oldrec->type) {
case IGRAPH_ATTRIBUTE_NUMERIC:
if (nv != igraph_vector_size(newnum)) {
IGRAPH_ERROR("Invalid numeric attribute length", IGRAPH_EINVAL);
}
IGRAPH_CHECK(igraph_vector_append(oldnum, newnum));
break;
case IGRAPH_ATTRIBUTE_STRING:
if (nv != igraph_strvector_size(newstr)) {
IGRAPH_ERROR("Invalid string attribute length", IGRAPH_EINVAL);
}
IGRAPH_CHECK(igraph_strvector_append(oldstr, newstr));
break;
case IGRAPH_ATTRIBUTE_BOOLEAN:
if (nv != igraph_vector_bool_size(newbool)) {
IGRAPH_ERROR("Invalid Boolean attribute length", IGRAPH_EINVAL);
}
IGRAPH_CHECK(igraph_vector_bool_append(oldbool, newbool));
break;
default:
IGRAPH_WARNING("Invalid attribute type");
break;
}
} else {
/* No such attribute, append NA's */
igraph_vector_t *oldnum = (igraph_vector_t *)oldrec->value;
igraph_strvector_t *oldstr = (igraph_strvector_t*)oldrec->value;
igraph_vector_bool_t *oldbool = (igraph_vector_bool_t*)oldrec->value;
switch (oldrec->type) {
case IGRAPH_ATTRIBUTE_NUMERIC:
IGRAPH_CHECK(igraph_vector_resize(oldnum, origlen + nv));
for (j = origlen; j < origlen + nv; j++) {
VECTOR(*oldnum)[j] = IGRAPH_NAN;
}
break;
case IGRAPH_ATTRIBUTE_STRING:
IGRAPH_CHECK(igraph_strvector_resize(oldstr, origlen + nv));
break;
case IGRAPH_ATTRIBUTE_BOOLEAN:
IGRAPH_CHECK(igraph_vector_bool_resize(oldbool, origlen + nv));
for (j = origlen; j < origlen + nv; j++) {
VECTOR(*oldbool)[j] = 0;
}
break;
default:
IGRAPH_WARNING("Invalid attribute type");
break;
}
}
}
igraph_vector_destroy(&news);
IGRAPH_FINALLY_CLEAN(1);
return 0;
}
void igraph_i_cattribute_permute_free(igraph_vector_ptr_t *v) {
long int i, n = igraph_vector_ptr_size(v);
for (i = 0; i < n; i++) {
igraph_attribute_record_t *rec = VECTOR(*v)[i];
igraph_Free(rec->name);
if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
igraph_vector_t *numv = (igraph_vector_t*) rec->value;
igraph_vector_destroy(numv);
igraph_Free(numv);
} else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
igraph_strvector_t *strv = (igraph_strvector_t*) rec->value;
igraph_strvector_destroy(strv);
igraph_Free(strv);
} else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
igraph_vector_bool_t *boolv = (igraph_vector_bool_t*) rec->value;
igraph_vector_bool_destroy(boolv);
igraph_Free(boolv);
}
igraph_Free(rec);
}
igraph_vector_ptr_clear(v);
}
int igraph_i_cattribute_permute_vertices(const igraph_t *graph,
igraph_t *newgraph,
const igraph_vector_t *idx) {
if (graph == newgraph) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int valno = igraph_vector_ptr_size(val);
long int i;
for (i = 0; i < valno; i++) {
igraph_attribute_record_t *oldrec = VECTOR(*val)[i];
igraph_attribute_type_t type = oldrec->type;
igraph_vector_t *num, *newnum;
igraph_strvector_t *str, *newstr;
igraph_vector_bool_t *oldbool, *newbool;
switch (type) {
case IGRAPH_ATTRIBUTE_NUMERIC:
num = (igraph_vector_t*) oldrec->value;
newnum = igraph_Calloc(1, igraph_vector_t);
if (!newnum) {
IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
}
IGRAPH_VECTOR_INIT_FINALLY(newnum, 0);
igraph_vector_index(num, newnum, idx);
oldrec->value = newnum;
igraph_vector_destroy(num);
igraph_Free(num);
IGRAPH_FINALLY_CLEAN(1);
break;
case IGRAPH_ATTRIBUTE_BOOLEAN:
oldbool = (igraph_vector_bool_t*) oldrec->value;
newbool = igraph_Calloc(1, igraph_vector_bool_t);
if (!newbool) {
IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
}
IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
igraph_vector_bool_index(oldbool, newbool, idx);
oldrec->value = newbool;
igraph_vector_bool_destroy(oldbool);
igraph_Free(oldbool);
IGRAPH_FINALLY_CLEAN(1);
break;
case IGRAPH_ATTRIBUTE_STRING:
str = (igraph_strvector_t*)oldrec->value;
newstr = igraph_Calloc(1, igraph_strvector_t);
if (!newstr) {
IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
}
IGRAPH_CHECK(igraph_strvector_init(newstr, 0));
IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
igraph_strvector_index(str, newstr, idx);
oldrec->value = newstr;
igraph_strvector_destroy(str);
igraph_Free(str);
IGRAPH_FINALLY_CLEAN(1);
break;
default:
IGRAPH_WARNING("Unknown edge attribute ignored");
}
}
} else {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int valno = igraph_vector_ptr_size(val);
long int i;
/* New vertex attributes */
igraph_i_cattributes_t *new_attr = newgraph->attr;
igraph_vector_ptr_t *new_val = &new_attr->val;
if (igraph_vector_ptr_size(new_val) != 0) {
IGRAPH_ERROR("Vertex attributes were already copied",
IGRAPH_EATTRIBUTES);
}
IGRAPH_CHECK(igraph_vector_ptr_resize(new_val, valno));
IGRAPH_FINALLY(igraph_i_cattribute_permute_free, new_val);
for (i = 0; i < valno; i++) {
igraph_attribute_record_t *oldrec = VECTOR(*val)[i];
igraph_attribute_type_t type = oldrec->type;
igraph_vector_t *num, *newnum;
igraph_strvector_t *str, *newstr;
igraph_vector_bool_t *oldbool, *newbool;
/* The record itself */
igraph_attribute_record_t *new_rec =
igraph_Calloc(1, igraph_attribute_record_t);
if (!new_rec) {
IGRAPH_ERROR("Cannot create vertex attributes", IGRAPH_ENOMEM);
}
new_rec->name = strdup(oldrec->name);
new_rec->type = oldrec->type;
VECTOR(*new_val)[i] = new_rec;
/* The data */
switch (type) {
case IGRAPH_ATTRIBUTE_NUMERIC:
num = (igraph_vector_t*)oldrec->value;
newnum = igraph_Calloc(1, igraph_vector_t);
if (!newnum) {
IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
}
IGRAPH_VECTOR_INIT_FINALLY(newnum, 0);
igraph_vector_index(num, newnum, idx);
new_rec->value = newnum;
IGRAPH_FINALLY_CLEAN(1);
break;
case IGRAPH_ATTRIBUTE_BOOLEAN:
oldbool = (igraph_vector_bool_t*)oldrec->value;
newbool = igraph_Calloc(1, igraph_vector_bool_t);
if (!newbool) {
IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
}
IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
igraph_vector_bool_index(oldbool, newbool, idx);
new_rec->value = newbool;
IGRAPH_FINALLY_CLEAN(1);
break;
case IGRAPH_ATTRIBUTE_STRING:
str = (igraph_strvector_t*)oldrec->value;
newstr = igraph_Calloc(1, igraph_strvector_t);
if (!newstr) {
IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
}
IGRAPH_CHECK(igraph_strvector_init(newstr, 0));
IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
igraph_strvector_index(str, newstr, idx);
new_rec->value = newstr;
IGRAPH_FINALLY_CLEAN(1);
break;
default:
IGRAPH_WARNING("Unknown vertex attribute ignored");
}
}
}
IGRAPH_FINALLY_CLEAN(1);
return 0;
}
typedef int igraph_cattributes_combine_num_t(const igraph_vector_t *input,
igraph_real_t *output);
typedef int igraph_cattributes_combine_str_t(const igraph_strvector_t *input,
char **output);
typedef int igraph_cattributes_combine_bool_t(const igraph_vector_bool_t *input,
igraph_bool_t *output);
int igraph_i_cattributes_cn_sum(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_t *oldv = oldrec->value;
igraph_vector_t *newv = igraph_Calloc(1, igraph_vector_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
for (i = 0; i < newlen; i++) {
igraph_real_t s = 0.0;
igraph_vector_t *idx = VECTOR(*merges)[i];
long int j, n = igraph_vector_size(idx);
for (j = 0; j < n; j++) {
long int x = (long int) VECTOR(*idx)[j];
s += VECTOR(*oldv)[x];
}
VECTOR(*newv)[i] = s;
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cn_prod(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_t *oldv = oldrec->value;
igraph_vector_t *newv = igraph_Calloc(1, igraph_vector_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
for (i = 0; i < newlen; i++) {
igraph_real_t s = 1.0;
igraph_vector_t *idx = VECTOR(*merges)[i];
long int j, n = igraph_vector_size(idx);
for (j = 0; j < n; j++) {
long int x = (long int) VECTOR(*idx)[j];
s *= VECTOR(*oldv)[x];
}
VECTOR(*newv)[i] = s;
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cn_min(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_t *oldv = oldrec->value;
igraph_vector_t *newv = igraph_Calloc(1, igraph_vector_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i;
igraph_real_t nan = IGRAPH_NAN;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int j, n = igraph_vector_size(idx);
igraph_real_t m = n > 0 ? VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ] : nan;
for (j = 1; j < n; j++) {
long int x = (long int) VECTOR(*idx)[j];
igraph_real_t val = VECTOR(*oldv)[x];
if (val < m) {
m = val;
}
}
VECTOR(*newv)[i] = m;
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cn_max(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_t *oldv = oldrec->value;
igraph_vector_t *newv = igraph_Calloc(1, igraph_vector_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i;
igraph_real_t nan = IGRAPH_NAN;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int j, n = igraph_vector_size(idx);
igraph_real_t m = n > 0 ? VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ] : nan;
for (j = 1; j < n; j++) {
long int x = (long int) VECTOR(*idx)[j];
igraph_real_t val = VECTOR(*oldv)[x];
if (val > m) {
m = val;
}
}
VECTOR(*newv)[i] = m;
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cn_random(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_t *oldv = oldrec->value;
igraph_vector_t *newv = igraph_Calloc(1, igraph_vector_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i;
igraph_real_t nan = IGRAPH_NAN;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
RNG_BEGIN();
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int n = igraph_vector_size(idx);
if (n == 0) {
VECTOR(*newv)[i] = nan;
} else if (n == 1) {
VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ];
} else {
long int r = RNG_INTEGER(0, n - 1);
VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[r] ];
}
}
RNG_END();
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cn_first(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_t *oldv = oldrec->value;
igraph_vector_t *newv = igraph_Calloc(1, igraph_vector_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i;
igraph_real_t nan = IGRAPH_NAN;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int n = igraph_vector_size(idx);
if (n == 0) {
VECTOR(*newv)[i] = nan;
} else {
VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ];
}
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cn_last(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_t *oldv = oldrec->value;
igraph_vector_t *newv = igraph_Calloc(1, igraph_vector_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i;
igraph_real_t nan = IGRAPH_NAN;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int n = igraph_vector_size(idx);
if (n == 0) {
VECTOR(*newv)[i] = nan;
} else {
VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[n - 1] ];
}
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cn_mean(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_t *oldv = oldrec->value;
igraph_vector_t *newv = igraph_Calloc(1, igraph_vector_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i;
igraph_real_t nan = IGRAPH_NAN;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int j, n = igraph_vector_size(idx);
igraph_real_t s = n > 0 ? 0.0 : nan;
for (j = 0; j < n; j++) {
long int x = (long int) VECTOR(*idx)[j];
s += VECTOR(*oldv)[x];
}
if (n > 0) {
s = s / n;
}
VECTOR(*newv)[i] = s;
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cn_func(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t *newrec,
const igraph_vector_ptr_t *merges,
igraph_cattributes_combine_num_t *func) {
const igraph_vector_t *oldv = oldrec->value;
long int newlen = igraph_vector_ptr_size(merges);
long int i;
igraph_vector_t *newv = igraph_Calloc(1, igraph_vector_t);
igraph_vector_t values;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_VECTOR_INIT_FINALLY(newv, newlen);
IGRAPH_VECTOR_INIT_FINALLY(&values, 0);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int j, n = igraph_vector_size(idx);
igraph_real_t res;
IGRAPH_CHECK(igraph_vector_resize(&values, n));
for (j = 0; j < n; j++) {
long int x = (long int) VECTOR(*idx)[j];
VECTOR(values)[j] = VECTOR(*oldv)[x];
}
IGRAPH_CHECK(func(&values, &res));
VECTOR(*newv)[i] = res;
}
igraph_vector_destroy(&values);
IGRAPH_FINALLY_CLEAN(3);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cb_random(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_bool_t *oldv = oldrec->value;
igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
RNG_BEGIN();
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int n = igraph_vector_size(idx);
if (n == 0) {
VECTOR(*newv)[i] = 0;
} else if (n == 1) {
VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ];
} else {
long int r = RNG_INTEGER(0, n - 1);
VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[r] ];
}
}
RNG_END();
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cb_first(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_bool_t *oldv = oldrec->value;
igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int n = igraph_vector_size(idx);
if (n == 0) {
VECTOR(*newv)[i] = 0;
} else {
VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ];
}
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cb_last(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_bool_t *oldv = oldrec->value;
igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int n = igraph_vector_size(idx);
if (n == 0) {
VECTOR(*newv)[i] = 0;
} else {
VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[n - 1] ];
}
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cb_all_is_true(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_bool_t *oldv = oldrec->value;
igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i, j, n, x;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
n = igraph_vector_size(idx);
VECTOR(*newv)[i] = 1;
for (j = 0; j < n; j++) {
x = (long int) VECTOR(*idx)[j];
if (!VECTOR(*oldv)[x]) {
VECTOR(*newv)[i] = 0;
break;
}
}
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cb_any_is_true(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_bool_t *oldv = oldrec->value;
igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i, j, n, x;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
n = igraph_vector_size(idx);
VECTOR(*newv)[i] = 0;
for (j = 0; j < n; j++) {
x = (long int) VECTOR(*idx)[j];
if (VECTOR(*oldv)[x]) {
VECTOR(*newv)[i] = 1;
break;
}
}
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cb_majority(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t * newrec,
const igraph_vector_ptr_t *merges) {
const igraph_vector_bool_t *oldv = oldrec->value;
igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);
long int newlen = igraph_vector_ptr_size(merges);
long int i, j, n, x, num_trues;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
RNG_BEGIN();
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
n = igraph_vector_size(idx);
num_trues = 0;
for (j = 0; j < n; j++) {
x = (long int) VECTOR(*idx)[j];
if (VECTOR(*oldv)[x]) {
num_trues++;
}
}
if (n % 2 != 0) {
VECTOR(*newv)[i] = (num_trues > n / 2);
} else {
if (num_trues == n / 2) {
VECTOR(*newv)[i] = (RNG_UNIF01() < 0.5);
} else {
VECTOR(*newv)[i] = (num_trues > n / 2);
}
}
}
RNG_END();
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_cb_func(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t *newrec,
const igraph_vector_ptr_t *merges,
igraph_cattributes_combine_bool_t *func) {
const igraph_vector_bool_t *oldv = oldrec->value;
long int newlen = igraph_vector_ptr_size(merges);
long int i;
igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);
igraph_vector_bool_t values;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
IGRAPH_CHECK(igraph_vector_bool_init(&values, 0));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int j, n = igraph_vector_size(idx);
igraph_bool_t res;
IGRAPH_CHECK(igraph_vector_bool_resize(&values, n));
for (j = 0; j < n; j++) {
long int x = (long int) VECTOR(*idx)[j];
VECTOR(values)[j] = VECTOR(*oldv)[x];
}
IGRAPH_CHECK(func(&values, &res));
VECTOR(*newv)[i] = res;
}
igraph_vector_bool_destroy(&values);
IGRAPH_FINALLY_CLEAN(3);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_sn_random(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t *newrec,
const igraph_vector_ptr_t *merges) {
const igraph_strvector_t *oldv = oldrec->value;
long int newlen = igraph_vector_ptr_size(merges);
long int i;
igraph_strvector_t *newv = igraph_Calloc(1, igraph_strvector_t);
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_strvector_init(newv, newlen));
IGRAPH_FINALLY(igraph_strvector_destroy, newv);
RNG_BEGIN();
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int n = igraph_vector_size(idx);
char *tmp;
if (n == 0) {
IGRAPH_CHECK(igraph_strvector_set(newv, i, ""));
} else if (n == 1) {
igraph_strvector_get(oldv, 0, &tmp);
IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp));
} else {
long int r = RNG_INTEGER(0, n - 1);
igraph_strvector_get(oldv, r, &tmp);
IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp));
}
}
RNG_END();
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_sn_first(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t *newrec,
const igraph_vector_ptr_t *merges) {
const igraph_strvector_t *oldv = oldrec->value;
long int i, newlen = igraph_vector_ptr_size(merges);
igraph_strvector_t *newv = igraph_Calloc(1, igraph_strvector_t);
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_strvector_init(newv, newlen));
IGRAPH_FINALLY(igraph_strvector_destroy, newv);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int n = igraph_vector_size(idx);
if (n == 0) {
IGRAPH_CHECK(igraph_strvector_set(newv, i, ""));
} else {
char *tmp;
igraph_strvector_get(oldv, (long int) VECTOR(*idx)[0], &tmp);
IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp));
}
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_sn_last(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t *newrec,
const igraph_vector_ptr_t *merges) {
const igraph_strvector_t *oldv = oldrec->value;
long int i, newlen = igraph_vector_ptr_size(merges);
igraph_strvector_t *newv = igraph_Calloc(1, igraph_strvector_t);
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_strvector_init(newv, newlen));
IGRAPH_FINALLY(igraph_strvector_destroy, newv);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int n = igraph_vector_size(idx);
if (n == 0) {
IGRAPH_CHECK(igraph_strvector_set(newv, i, ""));
} else {
char *tmp;
igraph_strvector_get(oldv, (long int) VECTOR(*idx)[n - 1], &tmp);
IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp));
}
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_sn_concat(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t *newrec,
const igraph_vector_ptr_t *merges) {
const igraph_strvector_t *oldv = oldrec->value;
long int i, newlen = igraph_vector_ptr_size(merges);
igraph_strvector_t *newv = igraph_Calloc(1, igraph_strvector_t);
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_strvector_init(newv, newlen));
IGRAPH_FINALLY(igraph_strvector_destroy, newv);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int j, n = igraph_vector_size(idx);
size_t len = 0;
char *tmp, *tmp2;
for (j = 0; j < n; j++) {
igraph_strvector_get(oldv, j, &tmp);
len += strlen(tmp);
}
tmp2 = igraph_Calloc(len + 1, char);
if (!tmp2) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, tmp2);
len = 0;
for (j = 0; j < n; j++) {
igraph_strvector_get(oldv, j, &tmp);
strcpy(tmp2 + len, tmp);
len += strlen(tmp);
}
IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp2));
igraph_Free(tmp2);
IGRAPH_FINALLY_CLEAN(1);
}
IGRAPH_FINALLY_CLEAN(2);
newrec->value = newv;
return 0;
}
int igraph_i_cattributes_sn_func(const igraph_attribute_record_t *oldrec,
igraph_attribute_record_t *newrec,
const igraph_vector_ptr_t *merges,
igraph_cattributes_combine_str_t *func) {
const igraph_strvector_t *oldv = oldrec->value;
long int newlen = igraph_vector_ptr_size(merges);
long int i;
igraph_strvector_t *newv = igraph_Calloc(1, igraph_strvector_t);
igraph_strvector_t values;
if (!newv) {
IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newv);
IGRAPH_CHECK(igraph_strvector_init(newv, newlen));
IGRAPH_FINALLY(igraph_strvector_destroy, newv);
IGRAPH_CHECK(igraph_strvector_init(newv, 0));
IGRAPH_FINALLY(igraph_strvector_destroy, &values);
for (i = 0; i < newlen; i++) {
igraph_vector_t *idx = VECTOR(*merges)[i];
long int j, n = igraph_vector_size(idx);
char *res;
IGRAPH_CHECK(igraph_strvector_resize(&values, n));
for (j = 0; j < n; j++) {
long int x = (long int) VECTOR(*idx)[j];
char *elem;
igraph_strvector_get(oldv, x, &elem);
IGRAPH_CHECK(igraph_strvector_set(newv, j, elem));
}
IGRAPH_CHECK(func(&values, &res));
IGRAPH_FINALLY(igraph_free, res);
IGRAPH_CHECK(igraph_strvector_set(newv, i, res));
IGRAPH_FINALLY_CLEAN(1);
igraph_Free(res);
}
igraph_strvector_destroy(&values);
IGRAPH_FINALLY_CLEAN(3);
newrec->value = newv;
return 0;
}
int igraph_i_cattribute_combine_vertices(const igraph_t *graph,
igraph_t *newgraph,
const igraph_vector_ptr_t *merges,
const igraph_attribute_combination_t *comb) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_i_cattributes_t *toattr = newgraph->attr;
igraph_vector_ptr_t *val = &attr->val;
igraph_vector_ptr_t *new_val = &toattr->val;
long int valno = igraph_vector_ptr_size(val);
long int i, j, keepno = 0;
int *TODO;
igraph_function_pointer_t *funcs;
TODO = igraph_Calloc(valno, int);
if (!TODO) {
IGRAPH_ERROR("Cannot combine vertex attributes",
IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, TODO);
funcs = igraph_Calloc(valno, igraph_function_pointer_t);
if (!funcs) {
IGRAPH_ERROR("Cannot combine vertex attributes",
IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, funcs);
for (i = 0; i < valno; i++) {
igraph_attribute_record_t *oldrec = VECTOR(*val)[i];
const char *name = oldrec->name;
igraph_attribute_combination_type_t todo;
igraph_function_pointer_t voidfunc;
igraph_attribute_combination_query(comb, name, &todo, &voidfunc);
TODO[i] = todo;
funcs[i] = voidfunc;
if (todo != IGRAPH_ATTRIBUTE_COMBINE_IGNORE) {
keepno++;
}
}
IGRAPH_CHECK(igraph_vector_ptr_resize(new_val, keepno));
IGRAPH_FINALLY(igraph_i_cattribute_permute_free, new_val);
for (i = 0, j = 0; i < valno; i++) {
igraph_attribute_record_t *newrec, *oldrec = VECTOR(*val)[i];
const char *name = oldrec->name;
igraph_attribute_combination_type_t todo =
(igraph_attribute_combination_type_t) (TODO[i]);
igraph_attribute_type_t type = oldrec->type;
igraph_cattributes_combine_num_t *numfunc =
(igraph_cattributes_combine_num_t*) funcs[i];
igraph_cattributes_combine_str_t *strfunc =
(igraph_cattributes_combine_str_t*) funcs[i];
igraph_cattributes_combine_bool_t *boolfunc =
(igraph_cattributes_combine_bool_t*) funcs[i];
if (todo == IGRAPH_ATTRIBUTE_COMBINE_DEFAULT ||
todo == IGRAPH_ATTRIBUTE_COMBINE_IGNORE) {
continue;
}
newrec = igraph_Calloc(1, igraph_attribute_record_t);
if (!newrec) {
IGRAPH_ERROR("Cannot combine vertex attributes",
IGRAPH_ENOMEM);
}
newrec->name = strdup(name);
newrec->type = type;
VECTOR(*new_val)[j] = newrec;
if (type == IGRAPH_ATTRIBUTE_NUMERIC) {
switch (todo) {
case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
IGRAPH_CHECK(igraph_i_cattributes_cn_func(oldrec, newrec, merges,
numfunc));
break;
case IGRAPH_ATTRIBUTE_COMBINE_SUM:
IGRAPH_CHECK(igraph_i_cattributes_cn_sum(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_PROD:
IGRAPH_CHECK(igraph_i_cattributes_cn_prod(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_MIN:
IGRAPH_CHECK(igraph_i_cattributes_cn_min(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_MAX:
IGRAPH_CHECK(igraph_i_cattributes_cn_max(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
IGRAPH_CHECK(igraph_i_cattributes_cn_random(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
IGRAPH_CHECK(igraph_i_cattributes_cn_first(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_LAST:
IGRAPH_CHECK(igraph_i_cattributes_cn_last(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
IGRAPH_CHECK(igraph_i_cattributes_cn_mean(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
IGRAPH_ERROR("Median calculation not implemented",
IGRAPH_UNIMPLEMENTED);
break;
case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
IGRAPH_ERROR("Cannot concatenate numeric attributes",
IGRAPH_EATTRCOMBINE);
break;
default:
IGRAPH_ERROR("Unknown attribute_combination",
IGRAPH_UNIMPLEMENTED);
break;
}
} else if (type == IGRAPH_ATTRIBUTE_BOOLEAN) {
switch (todo) {
case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
IGRAPH_CHECK(igraph_i_cattributes_cb_func(oldrec, newrec, merges,
boolfunc));
break;
case IGRAPH_ATTRIBUTE_COMBINE_SUM:
case IGRAPH_ATTRIBUTE_COMBINE_MAX:
IGRAPH_CHECK(igraph_i_cattributes_cb_any_is_true(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_PROD:
case IGRAPH_ATTRIBUTE_COMBINE_MIN:
IGRAPH_CHECK(igraph_i_cattributes_cb_all_is_true(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
IGRAPH_CHECK(igraph_i_cattributes_cb_majority(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
IGRAPH_CHECK(igraph_i_cattributes_cb_random(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
IGRAPH_CHECK(igraph_i_cattributes_cb_first(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_LAST:
IGRAPH_CHECK(igraph_i_cattributes_cb_last(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
IGRAPH_ERROR("Cannot calculate concatenation of Booleans",
IGRAPH_EATTRCOMBINE);
break;
default:
IGRAPH_ERROR("Unknown attribute_combination",
IGRAPH_UNIMPLEMENTED);
break;
}
} else if (type == IGRAPH_ATTRIBUTE_STRING) {
switch (todo) {
case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
IGRAPH_CHECK(igraph_i_cattributes_sn_func(oldrec, newrec, merges,
strfunc));
break;
case IGRAPH_ATTRIBUTE_COMBINE_SUM:
IGRAPH_ERROR("Cannot sum strings", IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_PROD:
IGRAPH_ERROR("Cannot multiply strings", IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_MIN:
IGRAPH_ERROR("Cannot find minimum of strings",
IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_MAX:
IGRAPH_ERROR("Cannot find maximum of strings",
IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
IGRAPH_ERROR("Cannot calculate mean of strings",
IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
IGRAPH_ERROR("Cannot calculate median of strings",
IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
IGRAPH_CHECK(igraph_i_cattributes_sn_random(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
IGRAPH_CHECK(igraph_i_cattributes_sn_first(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_LAST:
IGRAPH_CHECK(igraph_i_cattributes_sn_last(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
IGRAPH_CHECK(igraph_i_cattributes_sn_concat(oldrec, newrec, merges));
break;
default:
IGRAPH_ERROR("Unknown attribute_combination",
IGRAPH_UNIMPLEMENTED);
break;
}
} else {
IGRAPH_ERROR("Unknown attribute type, this should not happen",
IGRAPH_UNIMPLEMENTED);
}
j++;
}
igraph_free(funcs);
igraph_free(TODO);
igraph_i_cattribute_permute_free(new_val);
IGRAPH_FINALLY_CLEAN(3);
return 0;
}
/* void igraph_i_cattribute_delete_vertices(igraph_t *graph, */
/* const igraph_vector_t *eidx, */
/* const igraph_vector_t *vidx) { */
/* igraph_i_cattributes_t *attr=graph->attr; */
/* igraph_vector_ptr_t *val=&attr->val; */
/* igraph_vector_ptr_t *eal=&attr->eal; */
/* long int valno=igraph_vector_ptr_size(val); */
/* long int ealno=igraph_vector_ptr_size(eal); */
/* long int i; */
/* long int origlen, newlen; */
/* /\* Vertices *\/ */
/* origlen=igraph_vector_size(vidx); */
/* newlen=0; */
/* for (i=0; i<origlen; i++) { */
/* if (VECTOR(*vidx)[i]>0) { */
/* newlen++; */
/* } */
/* } */
/* for (i=0; i<valno; i++) { */
/* igraph_attribute_record_t *oldrec=VECTOR(*val)[i]; */
/* igraph_attribute_type_t type=oldrec->type; */
/* igraph_vector_t *num=(igraph_vector_t*)oldrec->value; */
/* igraph_strvector_t *str=(igraph_strvector_t*)oldrec->value; */
/* switch (type) { */
/* case IGRAPH_ATTRIBUTE_NUMERIC: */
/* igraph_vector_permdelete(num, vidx, origlen-newlen); */
/* break; */
/* case IGRAPH_ATTRIBUTE_STRING: */
/* igraph_strvector_permdelete(str, vidx, origlen-newlen); */
/* break; */
/* default: */
/* IGRAPH_WARNING("Unknown vertex attribute ignored"); */
/* } */
/* } */
/* /\* Edges *\/ */
/* origlen=igraph_vector_size(eidx); */
/* newlen=0; */
/* for (i=0; i<origlen; i++) { */
/* if (VECTOR(*eidx)[i]>0) { */
/* newlen++; */
/* } */
/* } */
/* for (i=0; i<ealno; i++) { */
/* igraph_attribute_record_t *oldrec=VECTOR(*eal)[i]; */
/* igraph_attribute_type_t type=oldrec->type; */
/* igraph_vector_t *num=(igraph_vector_t*)oldrec->value; */
/* igraph_strvector_t *str=(igraph_strvector_t*)oldrec->value; */
/* switch (type) { */
/* case IGRAPH_ATTRIBUTE_NUMERIC: */
/* igraph_vector_permdelete(num, eidx, origlen-newlen); */
/* break; */
/* case IGRAPH_ATTRIBUTE_STRING: */
/* igraph_strvector_permdelete(str, eidx, origlen-newlen); */
/* break; */
/* default: */
/* IGRAPH_WARNING("Unknown edge attribute ignored"); */
/* } */
/* } */
/* } */
int igraph_i_cattribute_add_edges(igraph_t *graph, const igraph_vector_t *edges,
igraph_vector_ptr_t *nattr) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int ealno = igraph_vector_ptr_size(eal);
long int ne = igraph_vector_size(edges) / 2;
long int origlen = igraph_ecount(graph) - ne;
long int nattrno = nattr == 0 ? 0 : igraph_vector_ptr_size(nattr);
igraph_vector_t news;
long int newattrs, i;
/* First add the new attributes if any */
newattrs = 0;
IGRAPH_VECTOR_INIT_FINALLY(&news, 0);
for (i = 0; i < nattrno; i++) {
igraph_attribute_record_t *nattr_entry = VECTOR(*nattr)[i];
const char *nname = nattr_entry->name;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(eal, nname, &j);
if (!l) {
newattrs++;
IGRAPH_CHECK(igraph_vector_push_back(&news, i));
} else {
/* check types */
if (nattr_entry->type !=
((igraph_attribute_record_t*)VECTOR(*eal)[j])->type) {
IGRAPH_ERROR("You cannot mix attribute types", IGRAPH_EINVAL);
}
}
}
/* Add NA/empty string vectors for the existing vertices */
if (newattrs != 0) {
for (i = 0; i < newattrs; i++) {
igraph_attribute_record_t *tmp = VECTOR(*nattr)[(long int)VECTOR(news)[i]];
igraph_attribute_record_t *newrec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_attribute_type_t type = tmp->type;
if (!newrec) {
IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newrec);
newrec->type = type;
newrec->name = strdup(tmp->name);
if (!newrec->name) {
IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)newrec->name);
if (type == IGRAPH_ATTRIBUTE_NUMERIC) {
igraph_vector_t *newnum = igraph_Calloc(1, igraph_vector_t);
if (!newnum) {
IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newnum);
IGRAPH_VECTOR_INIT_FINALLY(newnum, origlen);
newrec->value = newnum;
igraph_vector_fill(newnum, IGRAPH_NAN);
} else if (type == IGRAPH_ATTRIBUTE_BOOLEAN) {
igraph_vector_bool_t *newbool = igraph_Calloc(1, igraph_vector_bool_t);
if (!newbool) {
IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newbool);
IGRAPH_CHECK(igraph_vector_bool_init(newbool, origlen));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
newrec->value = newbool;
igraph_vector_bool_fill(newbool, 0);
} else if (type == IGRAPH_ATTRIBUTE_STRING) {
igraph_strvector_t *newstr = igraph_Calloc(1, igraph_strvector_t);
if (!newstr) {
IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, newstr);
IGRAPH_STRVECTOR_INIT_FINALLY(newstr, origlen);
newrec->value = newstr;
}
IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, newrec));
IGRAPH_FINALLY_CLEAN(4);
}
ealno = igraph_vector_ptr_size(eal);
}
/* Now append the new values */
for (i = 0; i < ealno; i++) {
igraph_attribute_record_t *oldrec = VECTOR(*eal)[i];
igraph_attribute_record_t *newrec = 0;
const char *name = oldrec->name;
long int j;
igraph_bool_t l = 0;
if (nattr) {
l = igraph_i_cattribute_find(nattr, name, &j);
}
if (l) {
/* This attribute is present in nattr */
igraph_vector_t *oldnum, *newnum;
igraph_strvector_t *oldstr, *newstr;
igraph_vector_bool_t *oldbool, *newbool;
newrec = VECTOR(*nattr)[j];
oldnum = (igraph_vector_t*)oldrec->value;
newnum = (igraph_vector_t*)newrec->value;
oldstr = (igraph_strvector_t*)oldrec->value;
newstr = (igraph_strvector_t*)newrec->value;
oldbool = (igraph_vector_bool_t*)oldrec->value;
newbool = (igraph_vector_bool_t*)newrec->value;
if (oldrec->type != newrec->type) {
IGRAPH_ERROR("Attribute types do not match", IGRAPH_EINVAL);
}
switch (oldrec->type) {
case IGRAPH_ATTRIBUTE_NUMERIC:
if (ne != igraph_vector_size(newnum)) {
IGRAPH_ERROR("Invalid numeric attribute length", IGRAPH_EINVAL);
}
IGRAPH_CHECK(igraph_vector_append(oldnum, newnum));
break;
case IGRAPH_ATTRIBUTE_STRING:
if (ne != igraph_strvector_size(newstr)) {
IGRAPH_ERROR("Invalid string attribute length", IGRAPH_EINVAL);
}
IGRAPH_CHECK(igraph_strvector_append(oldstr, newstr));
break;
case IGRAPH_ATTRIBUTE_BOOLEAN:
if (ne != igraph_vector_bool_size(newbool)) {
IGRAPH_ERROR("Invalid Boolean attribute length", IGRAPH_EINVAL);
}
IGRAPH_CHECK(igraph_vector_bool_append(oldbool, newbool));
break;
default:
IGRAPH_WARNING("Invalid attribute type");
break;
}
} else {
/* No such attribute, append NA's */
igraph_vector_t *oldnum = (igraph_vector_t *)oldrec->value;
igraph_strvector_t *oldstr = (igraph_strvector_t*)oldrec->value;
igraph_vector_bool_t *oldbool = (igraph_vector_bool_t *)oldrec->value;
switch (oldrec->type) {
case IGRAPH_ATTRIBUTE_NUMERIC:
IGRAPH_CHECK(igraph_vector_resize(oldnum, origlen + ne));
for (j = origlen; j < origlen + ne; j++) {
VECTOR(*oldnum)[j] = IGRAPH_NAN;
}
break;
case IGRAPH_ATTRIBUTE_STRING:
IGRAPH_CHECK(igraph_strvector_resize(oldstr, origlen + ne));
break;
case IGRAPH_ATTRIBUTE_BOOLEAN:
IGRAPH_CHECK(igraph_vector_bool_resize(oldbool, origlen + ne));
for (j = origlen; j < origlen + ne; j++) {
VECTOR(*oldbool)[j] = 0;
}
break;
default:
IGRAPH_WARNING("Invalid attribute type");
break;
}
}
}
igraph_vector_destroy(&news);
IGRAPH_FINALLY_CLEAN(1);
return 0;
}
/* void igraph_i_cattribute_delete_edges(igraph_t *graph, const igraph_vector_t *idx) { */
/* igraph_i_cattributes_t *attr=graph->attr; */
/* igraph_vector_ptr_t *eal=&attr->eal; */
/* long int ealno=igraph_vector_ptr_size(eal); */
/* long int i; */
/* long int origlen=igraph_vector_size(idx), newlen; */
/* newlen=0; */
/* for (i=0; i<origlen; i++) { */
/* if (VECTOR(*idx)[i]>0) { */
/* newlen++; */
/* } */
/* } */
/* for (i=0; i<ealno; i++) { */
/* igraph_attribute_record_t *oldrec=VECTOR(*eal)[i]; */
/* igraph_attribute_type_t type=oldrec->type; */
/* igraph_vector_t *num=(igraph_vector_t*)oldrec->value; */
/* igraph_strvector_t *str=(igraph_strvector_t*)oldrec->value; */
/* switch (type) { */
/* case IGRAPH_ATTRIBUTE_NUMERIC: */
/* igraph_vector_permdelete(num, idx, origlen-newlen); */
/* break; */
/* case IGRAPH_ATTRIBUTE_STRING: */
/* igraph_strvector_permdelete(str, idx, origlen-newlen); */
/* break; */
/* default: */
/* IGRAPH_WARNING("Unknown edge attribute ignored"); */
/* } */
/* } */
/* } */
int igraph_i_cattribute_permute_edges(const igraph_t *graph,
igraph_t *newgraph,
const igraph_vector_t *idx) {
if (graph == newgraph) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int ealno = igraph_vector_ptr_size(eal);
long int i;
for (i = 0; i < ealno; i++) {
igraph_attribute_record_t *oldrec = VECTOR(*eal)[i];
igraph_attribute_type_t type = oldrec->type;
igraph_vector_t *num, *newnum;
igraph_strvector_t *str, *newstr;
igraph_vector_bool_t *oldbool, *newbool;
switch (type) {
case IGRAPH_ATTRIBUTE_NUMERIC:
num = (igraph_vector_t*) oldrec->value;
newnum = igraph_Calloc(1, igraph_vector_t);
if (!newnum) {
IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
}
IGRAPH_VECTOR_INIT_FINALLY(newnum, 0);
igraph_vector_index(num, newnum, idx);
oldrec->value = newnum;
igraph_vector_destroy(num);
igraph_Free(num);
IGRAPH_FINALLY_CLEAN(1);
break;
case IGRAPH_ATTRIBUTE_BOOLEAN:
oldbool = (igraph_vector_bool_t*) oldrec->value;
newbool = igraph_Calloc(1, igraph_vector_bool_t);
if (!newbool) {
IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
}
IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
igraph_vector_bool_index(oldbool, newbool, idx);
oldrec->value = newbool;
igraph_vector_bool_destroy(oldbool);
igraph_Free(oldbool);
IGRAPH_FINALLY_CLEAN(1);
break;
case IGRAPH_ATTRIBUTE_STRING:
str = (igraph_strvector_t*)oldrec->value;
newstr = igraph_Calloc(1, igraph_strvector_t);
if (!newstr) {
IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
}
IGRAPH_CHECK(igraph_strvector_init(newstr, 0));
IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
igraph_strvector_index(str, newstr, idx);
oldrec->value = newstr;
igraph_strvector_destroy(str);
igraph_Free(str);
IGRAPH_FINALLY_CLEAN(1);
break;
default:
IGRAPH_WARNING("Unknown edge attribute ignored");
}
}
} else {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int ealno = igraph_vector_ptr_size(eal);
long int i;
/* New edge attributes */
igraph_i_cattributes_t *new_attr = newgraph->attr;
igraph_vector_ptr_t *new_eal = &new_attr->eal;
IGRAPH_CHECK(igraph_vector_ptr_resize(new_eal, ealno));
IGRAPH_FINALLY(igraph_i_cattribute_permute_free, new_eal);
for (i = 0; i < ealno; i++) {
igraph_attribute_record_t *oldrec = VECTOR(*eal)[i];
igraph_attribute_type_t type = oldrec->type;
igraph_vector_t *num, *newnum;
igraph_strvector_t *str, *newstr;
igraph_vector_bool_t *oldbool, *newbool;
/* The record itself */
igraph_attribute_record_t *new_rec =
igraph_Calloc(1, igraph_attribute_record_t);
if (!new_rec) {
IGRAPH_ERROR("Cannot create edge attributes", IGRAPH_ENOMEM);
}
new_rec->name = strdup(oldrec->name);
new_rec->type = oldrec->type;
VECTOR(*new_eal)[i] = new_rec;
switch (type) {
case IGRAPH_ATTRIBUTE_NUMERIC:
num = (igraph_vector_t*) oldrec->value;
newnum = igraph_Calloc(1, igraph_vector_t);
if (!newnum) {
IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
}
IGRAPH_VECTOR_INIT_FINALLY(newnum, 0);
igraph_vector_index(num, newnum, idx);
new_rec->value = newnum;
IGRAPH_FINALLY_CLEAN(1);
break;
case IGRAPH_ATTRIBUTE_STRING:
str = (igraph_strvector_t*)oldrec->value;
newstr = igraph_Calloc(1, igraph_strvector_t);
if (!newstr) {
IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
}
IGRAPH_CHECK(igraph_strvector_init(newstr, 0));
IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
igraph_strvector_index(str, newstr, idx);
new_rec->value = newstr;
IGRAPH_FINALLY_CLEAN(1);
break;
case IGRAPH_ATTRIBUTE_BOOLEAN:
oldbool = (igraph_vector_bool_t*) oldrec->value;
newbool = igraph_Calloc(1, igraph_vector_bool_t);
if (!newbool) {
IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
}
IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));
IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
igraph_vector_bool_index(oldbool, newbool, idx);
new_rec->value = newbool;
IGRAPH_FINALLY_CLEAN(1);
break;
default:
IGRAPH_WARNING("Unknown edge attribute ignored");
}
}
IGRAPH_FINALLY_CLEAN(1);
}
return 0;
}
int igraph_i_cattribute_combine_edges(const igraph_t *graph,
igraph_t *newgraph,
const igraph_vector_ptr_t *merges,
const igraph_attribute_combination_t *comb) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_i_cattributes_t *toattr = newgraph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
igraph_vector_ptr_t *new_eal = &toattr->eal;
long int ealno = igraph_vector_ptr_size(eal);
long int i, j, keepno = 0;
int *TODO;
igraph_function_pointer_t *funcs;
TODO = igraph_Calloc(ealno, int);
if (!TODO) {
IGRAPH_ERROR("Cannot combine edge attributes",
IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, TODO);
funcs = igraph_Calloc(ealno, igraph_function_pointer_t);
if (!funcs) {
IGRAPH_ERROR("Cannot combine edge attributes",
IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, funcs);
for (i = 0; i < ealno; i++) {
igraph_attribute_record_t *oldrec = VECTOR(*eal)[i];
const char *name = oldrec->name;
igraph_attribute_combination_type_t todo;
igraph_function_pointer_t voidfunc;
igraph_attribute_combination_query(comb, name, &todo, &voidfunc);
TODO[i] = todo;
funcs[i] = voidfunc;
if (todo != IGRAPH_ATTRIBUTE_COMBINE_IGNORE) {
keepno++;
}
}
IGRAPH_CHECK(igraph_vector_ptr_resize(new_eal, keepno));
IGRAPH_FINALLY(igraph_i_cattribute_permute_free, new_eal);
for (i = 0, j = 0; i < ealno; i++) {
igraph_attribute_record_t *newrec, *oldrec = VECTOR(*eal)[i];
const char *name = oldrec->name;
igraph_attribute_combination_type_t todo =
(igraph_attribute_combination_type_t) (TODO[i]);
igraph_attribute_type_t type = oldrec->type;
igraph_cattributes_combine_num_t *numfunc =
(igraph_cattributes_combine_num_t*) funcs[i];
igraph_cattributes_combine_str_t *strfunc =
(igraph_cattributes_combine_str_t*) funcs[i];
igraph_cattributes_combine_bool_t *boolfunc =
(igraph_cattributes_combine_bool_t*) funcs[i];
if (todo == IGRAPH_ATTRIBUTE_COMBINE_DEFAULT ||
todo == IGRAPH_ATTRIBUTE_COMBINE_IGNORE) {
continue;
}
newrec = igraph_Calloc(1, igraph_attribute_record_t);
if (!newrec) {
IGRAPH_ERROR("Cannot combine edge attributes",
IGRAPH_ENOMEM);
}
newrec->name = strdup(name);
newrec->type = type;
VECTOR(*new_eal)[j] = newrec;
if (type == IGRAPH_ATTRIBUTE_NUMERIC) {
switch (todo) {
case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
IGRAPH_CHECK(igraph_i_cattributes_cn_func(oldrec, newrec, merges,
numfunc));
break;
case IGRAPH_ATTRIBUTE_COMBINE_SUM:
IGRAPH_CHECK(igraph_i_cattributes_cn_sum(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_PROD:
IGRAPH_CHECK(igraph_i_cattributes_cn_prod(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_MIN:
IGRAPH_CHECK(igraph_i_cattributes_cn_min(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_MAX:
IGRAPH_CHECK(igraph_i_cattributes_cn_max(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
IGRAPH_CHECK(igraph_i_cattributes_cn_random(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
IGRAPH_CHECK(igraph_i_cattributes_cn_first(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_LAST:
IGRAPH_CHECK(igraph_i_cattributes_cn_last(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
IGRAPH_CHECK(igraph_i_cattributes_cn_mean(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
IGRAPH_ERROR("Median calculation not implemented",
IGRAPH_UNIMPLEMENTED);
break;
case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
IGRAPH_ERROR("Cannot concatenate numeric attributes",
IGRAPH_EATTRCOMBINE);
break;
default:
IGRAPH_ERROR("Unknown attribute_combination",
IGRAPH_UNIMPLEMENTED);
break;
}
} else if (type == IGRAPH_ATTRIBUTE_BOOLEAN) {
switch (todo) {
case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
IGRAPH_CHECK(igraph_i_cattributes_cb_func(oldrec, newrec, merges,
boolfunc));
break;
case IGRAPH_ATTRIBUTE_COMBINE_SUM:
case IGRAPH_ATTRIBUTE_COMBINE_MAX:
IGRAPH_CHECK(igraph_i_cattributes_cb_any_is_true(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_PROD:
case IGRAPH_ATTRIBUTE_COMBINE_MIN:
IGRAPH_CHECK(igraph_i_cattributes_cb_all_is_true(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
IGRAPH_CHECK(igraph_i_cattributes_cb_majority(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
IGRAPH_CHECK(igraph_i_cattributes_cb_random(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
IGRAPH_CHECK(igraph_i_cattributes_cb_first(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_LAST:
IGRAPH_CHECK(igraph_i_cattributes_cb_last(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
IGRAPH_ERROR("Cannot calculate concatenation of Booleans",
IGRAPH_EATTRCOMBINE);
break;
default:
IGRAPH_ERROR("Unknown attribute_combination",
IGRAPH_UNIMPLEMENTED);
break;
}
} else if (type == IGRAPH_ATTRIBUTE_STRING) {
switch (todo) {
case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
IGRAPH_CHECK(igraph_i_cattributes_sn_func(oldrec, newrec, merges,
strfunc));
break;
case IGRAPH_ATTRIBUTE_COMBINE_SUM:
IGRAPH_ERROR("Cannot sum strings", IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_PROD:
IGRAPH_ERROR("Cannot multiply strings", IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_MIN:
IGRAPH_ERROR("Cannot find minimum of strings",
IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_MAX:
IGRAPH_ERROR("Cannot find maximum of strings",
IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
IGRAPH_ERROR("Cannot calculate mean of strings",
IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
IGRAPH_ERROR("Cannot calculate median of strings",
IGRAPH_EATTRCOMBINE);
break;
case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
IGRAPH_CHECK(igraph_i_cattributes_sn_random(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
IGRAPH_CHECK(igraph_i_cattributes_sn_first(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_LAST:
IGRAPH_CHECK(igraph_i_cattributes_sn_last(oldrec, newrec, merges));
break;
case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
IGRAPH_CHECK(igraph_i_cattributes_sn_concat(oldrec, newrec, merges));
break;
default:
IGRAPH_ERROR("Unknown attribute_combination",
IGRAPH_UNIMPLEMENTED);
break;
}
} else {
IGRAPH_ERROR("Unknown attribute type, this should not happen",
IGRAPH_UNIMPLEMENTED);
}
j++;
}
igraph_free(funcs);
igraph_free(TODO);
IGRAPH_FINALLY_CLEAN(3);
return 0;
}
int igraph_i_cattribute_get_info(const igraph_t *graph,
igraph_strvector_t *gnames,
igraph_vector_t *gtypes,
igraph_strvector_t *vnames,
igraph_vector_t *vtypes,
igraph_strvector_t *enames,
igraph_vector_t *etypes) {
igraph_strvector_t *names[3] = { gnames, vnames, enames };
igraph_vector_t *types[3] = { gtypes, vtypes, etypes };
igraph_i_cattributes_t *at = graph->attr;
igraph_vector_ptr_t *attr[3] = { &at->gal, &at->val, &at->eal };
long int i, j;
for (i = 0; i < 3; i++) {
igraph_strvector_t *n = names[i];
igraph_vector_t *t = types[i];
igraph_vector_ptr_t *al = attr[i];
long int len = igraph_vector_ptr_size(al);
if (n) {
IGRAPH_CHECK(igraph_strvector_resize(n, len));
}
if (t) {
IGRAPH_CHECK(igraph_vector_resize(t, len));
}
for (j = 0; j < len; j++) {
igraph_attribute_record_t *rec = VECTOR(*al)[j];
const char *name = rec->name;
igraph_attribute_type_t type = rec->type;
if (n) {
IGRAPH_CHECK(igraph_strvector_set(n, j, name));
}
if (t) {
VECTOR(*t)[j] = type;
}
}
}
return 0;
}
igraph_bool_t igraph_i_cattribute_has_attr(const igraph_t *graph,
igraph_attribute_elemtype_t type,
const char *name) {
igraph_i_cattributes_t *at = graph->attr;
igraph_vector_ptr_t *attr[3] = { &at->gal, &at->val, &at->eal };
long int attrnum;
switch (type) {
case IGRAPH_ATTRIBUTE_GRAPH:
attrnum = 0;
break;
case IGRAPH_ATTRIBUTE_VERTEX:
attrnum = 1;
break;
case IGRAPH_ATTRIBUTE_EDGE:
attrnum = 2;
break;
default:
IGRAPH_ERROR("Unknown attribute element type", IGRAPH_EINVAL);
break;
}
return igraph_i_cattribute_find(attr[attrnum], name, 0);
}
int igraph_i_cattribute_gettype(const igraph_t *graph,
igraph_attribute_type_t *type,
igraph_attribute_elemtype_t elemtype,
const char *name) {
long int attrnum;
igraph_attribute_record_t *rec;
igraph_i_cattributes_t *at = graph->attr;
igraph_vector_ptr_t *attr[3] = { &at->gal, &at->val, &at->eal };
igraph_vector_ptr_t *al;
long int j;
igraph_bool_t l = 0;
switch (elemtype) {
case IGRAPH_ATTRIBUTE_GRAPH:
attrnum = 0;
break;
case IGRAPH_ATTRIBUTE_VERTEX:
attrnum = 1;
break;
case IGRAPH_ATTRIBUTE_EDGE:
attrnum = 2;
break;
default:
IGRAPH_ERROR("Unknown attribute element type", IGRAPH_EINVAL);
break;
}
al = attr[attrnum];
l = igraph_i_cattribute_find(al, name, &j);
if (!l) {
IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
}
rec = VECTOR(*al)[j];
*type = rec->type;
return 0;
}
int igraph_i_cattribute_get_numeric_graph_attr(const igraph_t *graph,
const char *name,
igraph_vector_t *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *gal = &attr->gal;
long int j;
igraph_attribute_record_t *rec;
igraph_vector_t *num;
igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j);
if (!l) {
IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
}
rec = VECTOR(*gal)[j];
num = (igraph_vector_t*)rec->value;
IGRAPH_CHECK(igraph_vector_resize(value, 1));
VECTOR(*value)[0] = VECTOR(*num)[0];
return 0;
}
int igraph_i_cattribute_get_bool_graph_attr(const igraph_t *graph,
const char *name,
igraph_vector_bool_t *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *gal = &attr->gal;
long int j;
igraph_attribute_record_t *rec;
igraph_vector_bool_t *log;
igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j);
if (!l) {
IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
}
rec = VECTOR(*gal)[j];
log = (igraph_vector_bool_t*)rec->value;
IGRAPH_CHECK(igraph_vector_bool_resize(value, 1));
VECTOR(*value)[0] = VECTOR(*log)[0];
return 0;
}
int igraph_i_cattribute_get_string_graph_attr(const igraph_t *graph,
const char *name,
igraph_strvector_t *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *gal = &attr->gal;
long int j;
igraph_attribute_record_t *rec;
igraph_strvector_t *str;
igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j);
if (!l) {
IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
}
rec = VECTOR(*gal)[j];
str = (igraph_strvector_t*)rec->value;
IGRAPH_CHECK(igraph_strvector_resize(value, 1));
IGRAPH_CHECK(igraph_strvector_set(value, 0, STR(*str, 0)));
return 0;
}
int igraph_i_cattribute_get_numeric_vertex_attr(const igraph_t *graph,
const char *name,
igraph_vs_t vs,
igraph_vector_t *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_attribute_record_t *rec;
igraph_vector_t *num;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
if (!l) {
IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
}
rec = VECTOR(*val)[j];
num = (igraph_vector_t*)rec->value;
if (igraph_vs_is_all(&vs)) {
igraph_vector_clear(value);
IGRAPH_CHECK(igraph_vector_append(value, num));
} else {
igraph_vit_t it;
long int i = 0;
IGRAPH_CHECK(igraph_vit_create(graph, vs, &it));
IGRAPH_FINALLY(igraph_vit_destroy, &it);
IGRAPH_CHECK(igraph_vector_resize(value, IGRAPH_VIT_SIZE(it)));
for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) {
long int v = IGRAPH_VIT_GET(it);
VECTOR(*value)[i] = VECTOR(*num)[v];
}
igraph_vit_destroy(&it);
IGRAPH_FINALLY_CLEAN(1);
}
return 0;
}
int igraph_i_cattribute_get_bool_vertex_attr(const igraph_t *graph,
const char *name,
igraph_vs_t vs,
igraph_vector_bool_t *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
igraph_vit_t it;
long int i, j, v;
igraph_attribute_record_t *rec;
igraph_vector_bool_t *log;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
if (!l) {
IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
}
rec = VECTOR(*val)[j];
log = (igraph_vector_bool_t*)rec->value;
if (igraph_vs_is_all(&vs)) {
igraph_vector_bool_clear(value);
IGRAPH_CHECK(igraph_vector_bool_append(value, log));
} else {
IGRAPH_CHECK(igraph_vit_create(graph, vs, &it));
IGRAPH_FINALLY(igraph_vit_destroy, &it);
IGRAPH_CHECK(igraph_vector_bool_resize(value, IGRAPH_VIT_SIZE(it)));
for (i = 0; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) {
v = IGRAPH_VIT_GET(it);
VECTOR(*value)[i] = VECTOR(*log)[v];
}
igraph_vit_destroy(&it);
IGRAPH_FINALLY_CLEAN(1);
}
return 0;
}
int igraph_i_cattribute_get_string_vertex_attr(const igraph_t *graph,
const char *name,
igraph_vs_t vs,
igraph_strvector_t *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_attribute_record_t *rec;
igraph_strvector_t *str;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
if (!l) {
IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
}
rec = VECTOR(*val)[j];
str = (igraph_strvector_t*)rec->value;
if (igraph_vs_is_all(&vs)) {
igraph_strvector_resize(value, 0);
IGRAPH_CHECK(igraph_strvector_append(value, str));
} else {
igraph_vit_t it;
long int i = 0;
IGRAPH_CHECK(igraph_vit_create(graph, vs, &it));
IGRAPH_FINALLY(igraph_vit_destroy, &it);
IGRAPH_CHECK(igraph_strvector_resize(value, IGRAPH_VIT_SIZE(it)));
for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) {
long int v = IGRAPH_VIT_GET(it);
char *s;
igraph_strvector_get(str, v, &s);
IGRAPH_CHECK(igraph_strvector_set(value, i, s));
}
igraph_vit_destroy(&it);
IGRAPH_FINALLY_CLEAN(1);
}
return 0;
}
int igraph_i_cattribute_get_numeric_edge_attr(const igraph_t *graph,
const char *name,
igraph_es_t es,
igraph_vector_t *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_attribute_record_t *rec;
igraph_vector_t *num;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
if (!l) {
IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
}
rec = VECTOR(*eal)[j];
num = (igraph_vector_t*)rec->value;
if (igraph_es_is_all(&es)) {
igraph_vector_clear(value);
IGRAPH_CHECK(igraph_vector_append(value, num));
} else {
igraph_eit_t it;
long int i = 0;
IGRAPH_CHECK(igraph_eit_create(graph, es, &it));
IGRAPH_FINALLY(igraph_eit_destroy, &it);
IGRAPH_CHECK(igraph_vector_resize(value, IGRAPH_EIT_SIZE(it)));
for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) {
long int e = IGRAPH_EIT_GET(it);
VECTOR(*value)[i] = VECTOR(*num)[e];
}
igraph_eit_destroy(&it);
IGRAPH_FINALLY_CLEAN(1);
}
return 0;
}
int igraph_i_cattribute_get_string_edge_attr(const igraph_t *graph,
const char *name,
igraph_es_t es,
igraph_strvector_t *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_attribute_record_t *rec;
igraph_strvector_t *str;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
if (!l) {
IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
}
rec = VECTOR(*eal)[j];
str = (igraph_strvector_t*)rec->value;
if (igraph_es_is_all(&es)) {
igraph_strvector_resize(value, 0);
IGRAPH_CHECK(igraph_strvector_append(value, str));
} else {
igraph_eit_t it;
long int i = 0;
IGRAPH_CHECK(igraph_eit_create(graph, es, &it));
IGRAPH_FINALLY(igraph_eit_destroy, &it);
IGRAPH_CHECK(igraph_strvector_resize(value, IGRAPH_EIT_SIZE(it)));
for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) {
long int e = IGRAPH_EIT_GET(it);
char *s;
igraph_strvector_get(str, e, &s);
IGRAPH_CHECK(igraph_strvector_set(value, i, s));
}
igraph_eit_destroy(&it);
IGRAPH_FINALLY_CLEAN(1);
}
return 0;
}
int igraph_i_cattribute_get_bool_edge_attr(const igraph_t *graph,
const char *name,
igraph_es_t es,
igraph_vector_bool_t *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_attribute_record_t *rec;
igraph_vector_bool_t *log;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
if (!l) {
IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);
}
rec = VECTOR(*eal)[j];
log = (igraph_vector_bool_t*)rec->value;
if (igraph_es_is_all(&es)) {
igraph_vector_bool_clear(value);
IGRAPH_CHECK(igraph_vector_bool_append(value, log));
} else {
igraph_eit_t it;
long int i = 0;
IGRAPH_CHECK(igraph_eit_create(graph, es, &it));
IGRAPH_FINALLY(igraph_eit_destroy, &it);
IGRAPH_CHECK(igraph_vector_bool_resize(value, IGRAPH_EIT_SIZE(it)));
for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) {
long int e = IGRAPH_EIT_GET(it);
VECTOR(*value)[i] = VECTOR(*log)[e];
}
igraph_eit_destroy(&it);
IGRAPH_FINALLY_CLEAN(1);
}
return 0;
}
/* -------------------------------------- */
const igraph_attribute_table_t igraph_cattribute_table = {
&igraph_i_cattribute_init, &igraph_i_cattribute_destroy,
&igraph_i_cattribute_copy, &igraph_i_cattribute_add_vertices,
&igraph_i_cattribute_permute_vertices,
&igraph_i_cattribute_combine_vertices, &igraph_i_cattribute_add_edges,
&igraph_i_cattribute_permute_edges,
&igraph_i_cattribute_combine_edges,
&igraph_i_cattribute_get_info,
&igraph_i_cattribute_has_attr, &igraph_i_cattribute_gettype,
&igraph_i_cattribute_get_numeric_graph_attr,
&igraph_i_cattribute_get_string_graph_attr,
&igraph_i_cattribute_get_bool_graph_attr,
&igraph_i_cattribute_get_numeric_vertex_attr,
&igraph_i_cattribute_get_string_vertex_attr,
&igraph_i_cattribute_get_bool_vertex_attr,
&igraph_i_cattribute_get_numeric_edge_attr,
&igraph_i_cattribute_get_string_edge_attr,
&igraph_i_cattribute_get_bool_edge_attr
};
/* -------------------------------------- */
/**
* \section cattributes
* <para>There is an experimental attribute handler that can be used
* from C code. In this section we show how this works. This attribute
* handler is by default not attached (the default is no attribute
* handler), so we first need to attach it:
* <programlisting>
* igraph_i_set_attribute_table(&igraph_cattribute_table);
* </programlisting>
* </para>
* <para>Now the attribute functions are available. Please note that
* the attribute handler must be attached before you call any other
* igraph functions, otherwise you might end up with graphs without
* attributes and an active attribute handler, which might cause
* unexpected program behaviour. The rule is that you attach the
* attribute handler in the beginning of your
* <function>main()</function> and never touch it again. (Detaching
* the attribute handler might lead to memory leaks.)</para>
*
* <para>It is not currently possible to have attribute handlers on a
* per-graph basis. All graphs in an application must be managed with
* the same attribute handler. (Including the default case when there
* is no attribute handler at all.</para>
*
* <para>The C attribute handler supports attaching real numbers and
* character strings as attributes. No vectors are allowed, i.e. every
* vertex might have an attribute called <code>name</code>, but it is
* not possible to have a <code>coords</code> graph (or other)
* attribute which is a vector of numbers.</para>
*
* \example examples/simple/cattributes.c
* \example examples/simple/cattributes2.c
* \example examples/simple/cattributes3.c
* \example examples/simple/cattributes4.c
*/
/**
* \function igraph_cattribute_GAN
* Query a numeric graph attribute.
*
* Returns the value of the given numeric graph attribute.
* The attribute must exist, otherwise an error is triggered.
* \param graph The input graph.
* \param name The name of the attribute to query.
* \return The value of the attribute.
*
* \sa \ref GAN for a simpler interface.
*
* Time complexity: O(Ag), the number of graph attributes.
*/
igraph_real_t igraph_cattribute_GAN(const igraph_t *graph, const char *name) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *gal = &attr->gal;
long int j;
igraph_attribute_record_t *rec;
igraph_vector_t *num;
igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j);
if (!l) {
igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
return 0;
}
rec = VECTOR(*gal)[j];
num = (igraph_vector_t*)rec->value;
return VECTOR(*num)[0];
}
/**
* \function igraph_cattribute_GAB
* Query a boolean graph attribute.
*
* Returns the value of the given numeric graph attribute.
* The attribute must exist, otherwise an error is triggered.
* \param graph The input graph.
* \param name The name of the attribute to query.
* \return The value of the attribute.
*
* \sa \ref GAB for a simpler interface.
*
* Time complexity: O(Ag), the number of graph attributes.
*/
igraph_bool_t igraph_cattribute_GAB(const igraph_t *graph, const char *name) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *gal = &attr->gal;
long int j;
igraph_attribute_record_t *rec;
igraph_vector_bool_t *log;
igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j);
if (!l) {
igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
return 0;
}
rec = VECTOR(*gal)[j];
log = (igraph_vector_bool_t*)rec->value;
return VECTOR(*log)[0];
}
/**
* \function igraph_cattribute_GAS
* Query a string graph attribute.
*
* Returns a <type>const</type> pointer to the string graph attribute
* specified in \p name.
* The attribute must exist, otherwise an error is triggered.
* \param graph The input graph.
* \param name The name of the attribute to query.
* \return The value of the attribute.
*
* \sa \ref GAS for a simpler interface.
*
* Time complexity: O(Ag), the number of graph attributes.
*/
const char* igraph_cattribute_GAS(const igraph_t *graph, const char *name) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *gal = &attr->gal;
long int j;
igraph_attribute_record_t *rec;
igraph_strvector_t *str;
igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j);
if (!l) {
igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
return 0;
}
rec = VECTOR(*gal)[j];
str = (igraph_strvector_t*)rec->value;
return STR(*str, 0);
}
/**
* \function igraph_cattribute_VAN
* Query a numeric vertex attribute.
*
* The attribute must exist, otherwise an error is triggered.
* \param graph The input graph.
* \param name The name of the attribute.
* \param vid The id of the queried vertex.
* \return The value of the attribute.
*
* \sa \ref VAN macro for a simpler interface.
*
* Time complexity: O(Av), the number of vertex attributes.
*/
igraph_real_t igraph_cattribute_VAN(const igraph_t *graph, const char *name,
igraph_integer_t vid) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_attribute_record_t *rec;
igraph_vector_t *num;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
if (!l) {
igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
return 0;
}
rec = VECTOR(*val)[j];
num = (igraph_vector_t*)rec->value;
return VECTOR(*num)[(long int)vid];
}
/**
* \function igraph_cattribute_VAB
* Query a boolean vertex attribute.
*
* The attribute must exist, otherwise an error is triggered.
* \param graph The input graph.
* \param name The name of the attribute.
* \param vid The id of the queried vertex.
* \return The value of the attribute.
*
* \sa \ref VAB macro for a simpler interface.
*
* Time complexity: O(Av), the number of vertex attributes.
*/
igraph_bool_t igraph_cattribute_VAB(const igraph_t *graph, const char *name,
igraph_integer_t vid) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_attribute_record_t *rec;
igraph_vector_bool_t *log;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
if (!l) {
igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
return 0;
}
rec = VECTOR(*val)[j];
log = (igraph_vector_bool_t*)rec->value;
return VECTOR(*log)[(long int)vid];
}
/**
* \function igraph_cattribute_VAS
* Query a string vertex attribute.
*
* The attribute must exist, otherwise an error is triggered.
* \param graph The input graph.
* \param name The name of the attribute.
* \param vid The id of the queried vertex.
* \return The value of the attribute.
*
* \sa The macro \ref VAS for a simpler interface.
*
* Time complexity: O(Av), the number of vertex attributes.
*/
const char* igraph_cattribute_VAS(const igraph_t *graph, const char *name,
igraph_integer_t vid) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_attribute_record_t *rec;
igraph_strvector_t *str;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
if (!l) {
igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
return 0;
}
rec = VECTOR(*val)[j];
str = (igraph_strvector_t*)rec->value;
return STR(*str, (long int)vid);
}
/**
* \function igraph_cattribute_EAN
* Query a numeric edge attribute.
*
* The attribute must exist, otherwise an error is triggered.
* \param graph The input graph.
* \param name The name of the attribute.
* \param eid The id of the queried edge.
* \return The value of the attribute.
*
* \sa \ref EAN for an easier interface.
*
* Time complexity: O(Ae), the number of edge attributes.
*/
igraph_real_t igraph_cattribute_EAN(const igraph_t *graph, const char *name,
igraph_integer_t eid) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_attribute_record_t *rec;
igraph_vector_t *num;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
if (!l) {
igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
return 0;
}
rec = VECTOR(*eal)[j];
num = (igraph_vector_t*)rec->value;
return VECTOR(*num)[(long int)eid];
}
/**
* \function igraph_cattribute_EAB
* Query a boolean edge attribute.
*
* The attribute must exist, otherwise an error is triggered.
* \param graph The input graph.
* \param name The name of the attribute.
* \param eid The id of the queried edge.
* \return The value of the attribute.
*
* \sa \ref EAB for an easier interface.
*
* Time complexity: O(Ae), the number of edge attributes.
*/
igraph_bool_t igraph_cattribute_EAB(const igraph_t *graph, const char *name,
igraph_integer_t eid) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_attribute_record_t *rec;
igraph_vector_bool_t *log;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
if (!l) {
igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
return 0;
}
rec = VECTOR(*eal)[j];
log = (igraph_vector_bool_t*)rec->value;
return VECTOR(*log)[(long int)eid];
}
/**
* \function igraph_cattribute_EAS
* Query a string edge attribute.
*
* The attribute must exist, otherwise an error is triggered.
* \param graph The input graph.
* \param name The name of the attribute.
* \param eid The id of the queried edge.
* \return The value of the attribute.
*
* \se \ref EAS if you want to type less.
*
* Time complexity: O(Ae), the number of edge attributes.
*/
const char* igraph_cattribute_EAS(const igraph_t *graph, const char *name,
igraph_integer_t eid) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_attribute_record_t *rec;
igraph_strvector_t *str;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
if (!l) {
igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);
return 0;
}
rec = VECTOR(*eal)[j];
str = (igraph_strvector_t*)rec->value;
return STR(*str, (long int)eid);
}
/**
* \function igraph_cattribute_VANV
* Query a numeric vertex attribute for many vertices
*
* \param graph The input graph.
* \param name The name of the attribute.
* \param vids The vertices to query.
* \param result Pointer to an initialized vector, the result is
* stored here. It will be resized, if needed.
* \return Error code.
*
* Time complexity: O(v), where v is the number of vertices in 'vids'.
*/
int igraph_cattribute_VANV(const igraph_t *graph, const char *name,
igraph_vs_t vids, igraph_vector_t *result) {
return igraph_i_cattribute_get_numeric_vertex_attr(graph, name, vids,
result);
}
/**
* \function igraph_cattribute_VABV
* Query a boolean vertex attribute for many vertices
*
* \param graph The input graph.
* \param name The name of the attribute.
* \param vids The vertices to query.
* \param result Pointer to an initialized boolean vector, the result is
* stored here. It will be resized, if needed.
* \return Error code.
*
* Time complexity: O(v), where v is the number of vertices in 'vids'.
*/
int igraph_cattribute_VABV(const igraph_t *graph, const char *name,
igraph_vs_t vids, igraph_vector_bool_t *result) {
return igraph_i_cattribute_get_bool_vertex_attr(graph, name, vids,
result);
}
/**
* \function igraph_cattribute_EANV
* Query a numeric edge attribute for many edges
*
* \param graph The input graph.
* \param name The name of the attribute.
* \param eids The edges to query.
* \param result Pointer to an initialized vector, the result is
* stored here. It will be resized, if needed.
* \return Error code.
*
* Time complexity: O(e), where e is the number of edges in 'eids'.
*/
int igraph_cattribute_EANV(const igraph_t *graph, const char *name,
igraph_es_t eids, igraph_vector_t *result) {
return igraph_i_cattribute_get_numeric_edge_attr(graph, name, eids,
result);
}
/**
* \function igraph_cattribute_EABV
* Query a boolean edge attribute for many edges
*
* \param graph The input graph.
* \param name The name of the attribute.
* \param eids The edges to query.
* \param result Pointer to an initialized boolean vector, the result is
* stored here. It will be resized, if needed.
* \return Error code.
*
* Time complexity: O(e), where e is the number of edges in 'eids'.
*/
int igraph_cattribute_EABV(const igraph_t *graph, const char *name,
igraph_es_t eids, igraph_vector_bool_t *result) {
return igraph_i_cattribute_get_bool_edge_attr(graph, name, eids,
result);
}
/**
* \function igraph_cattribute_VASV
* Query a string vertex attribute for many vertices
*
* \param graph The input graph.
* \param name The name of the attribute.
* \param vids The vertices to query.
* \param result Pointer to an initialized string vector, the result
* is stored here. It will be resized, if needed.
* \return Error code.
*
* Time complexity: O(v), where v is the number of vertices in 'vids'.
* (We assume that the string attributes have a bounded length.)
*/
int igraph_cattribute_VASV(const igraph_t *graph, const char *name,
igraph_vs_t vids, igraph_strvector_t *result) {
return igraph_i_cattribute_get_string_vertex_attr(graph, name, vids,
result);
}
/**
* \function igraph_cattribute_EASV
* Query a string edge attribute for many edges
*
* \param graph The input graph.
* \param name The name of the attribute.
* \param vids The edges to query.
* \param result Pointer to an initialized string vector, the result
* is stored here. It will be resized, if needed.
* \return Error code.
*
* Time complexity: O(e), where e is the number of edges in
* 'eids'. (We assume that the string attributes have a bounded length.)
*/
int igraph_cattribute_EASV(const igraph_t *graph, const char *name,
igraph_es_t eids, igraph_strvector_t *result) {
return igraph_i_cattribute_get_string_edge_attr(graph, name, eids,
result);
}
/**
* \function igraph_cattribute_list
* List all attributes
*
* See \ref igraph_attribute_type_t for the various attribute types.
* \param graph The input graph.
* \param gnames String vector, the names of the graph attributes.
* \param gtypes Numeric vector, the types of the graph attributes.
* \param vnames String vector, the names of the vertex attributes.
* \param vtypes Numeric vector, the types of the vertex attributes.
* \param enames String vector, the names of the edge attributes.
* \param etypes Numeric vector, the types of the edge attributes.
* \return Error code.
*
* Naturally, the string vector with the attribute names and the
* numeric vector with the attribute types are in the right order,
* i.e. the first name corresponds to the first type, etc.
*
* Time complexity: O(Ag+Av+Ae), the number of all attributes.
*/
int igraph_cattribute_list(const igraph_t *graph,
igraph_strvector_t *gnames, igraph_vector_t *gtypes,
igraph_strvector_t *vnames, igraph_vector_t *vtypes,
igraph_strvector_t *enames, igraph_vector_t *etypes) {
return igraph_i_cattribute_get_info(graph, gnames, gtypes, vnames, vtypes,
enames, etypes);
}
/**
* \function igraph_cattribute_has_attr
* Checks whether a (graph, vertex or edge) attribute exists
*
* \param graph The graph.
* \param type The type of the attribute, \c IGRAPH_ATTRIBUTE_GRAPH,
* \c IGRAPH_ATTRIBUTE_VERTEX or \c IGRAPH_ATTRIBUTE_EDGE.
* \param name Character constant, the name of the attribute.
* \return Logical value, TRUE if the attribute exists, FALSE otherwise.
*
* Time complexity: O(A), the number of (graph, vertex or edge)
* attributes, assuming attribute names are not too long.
*/
igraph_bool_t igraph_cattribute_has_attr(const igraph_t *graph,
igraph_attribute_elemtype_t type,
const char *name) {
return igraph_i_cattribute_has_attr(graph, type, name);
}
/**
* \function igraph_cattribute_GAN_set
* Set a numeric graph attribute
*
* \param graph The graph.
* \param name Name of the graph attribute. If there is no such
* attribute yet, then it will be added.
* \param value The (new) value of the graph attribute.
* \return Error code.
*
* \se \ref SETGAN if you want to type less.
*
* Time complexity: O(1).
*/
int igraph_cattribute_GAN_set(igraph_t *graph, const char *name,
igraph_real_t value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *gal = &attr->gal;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j);
if (l) {
igraph_attribute_record_t *rec = VECTOR(*gal)[j];
if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) {
IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
} else {
igraph_vector_t *num = (igraph_vector_t *)rec->value;
VECTOR(*num)[0] = value;
}
} else {
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_vector_t *num;
if (!rec) {
IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
rec->type = IGRAPH_ATTRIBUTE_NUMERIC;
num = igraph_Calloc(1, igraph_vector_t);
if (!num) {
IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, num);
IGRAPH_VECTOR_INIT_FINALLY(num, 1);
VECTOR(*num)[0] = value;
rec->value = num;
IGRAPH_CHECK(igraph_vector_ptr_push_back(gal, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_GAB_set
* Set a boolean graph attribute
*
* \param graph The graph.
* \param name Name of the graph attribute. If there is no such
* attribute yet, then it will be added.
* \param value The (new) value of the graph attribute.
* \return Error code.
*
* \se \ref SETGAN if you want to type less.
*
* Time complexity: O(1).
*/
int igraph_cattribute_GAB_set(igraph_t *graph, const char *name,
igraph_bool_t value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *gal = &attr->gal;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j);
if (l) {
igraph_attribute_record_t *rec = VECTOR(*gal)[j];
if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) {
IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
} else {
igraph_vector_bool_t *log = (igraph_vector_bool_t *)rec->value;
VECTOR(*log)[0] = value;
}
} else {
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_vector_bool_t *log;
if (!rec) {
IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
rec->type = IGRAPH_ATTRIBUTE_BOOLEAN;
log = igraph_Calloc(1, igraph_vector_bool_t);
if (!log) {
IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, log);
IGRAPH_CHECK(igraph_vector_bool_init(log, 1));
IGRAPH_FINALLY(igraph_vector_bool_destroy, log);
VECTOR(*log)[0] = value;
rec->value = log;
IGRAPH_CHECK(igraph_vector_ptr_push_back(gal, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_GAS_set
* Set a string graph attribute.
*
* \param graph The graph.
* \param name Name of the graph attribute. If there is no such
* attribute yet, then it will be added.
* \param value The (new) value of the graph attribute. It will be
* copied.
* \return Error code.
*
* \se \ref SETGAS if you want to type less.
*
* Time complexity: O(1).
*/
int igraph_cattribute_GAS_set(igraph_t *graph, const char *name,
const char *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *gal = &attr->gal;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j);
if (l) {
igraph_attribute_record_t *rec = VECTOR(*gal)[j];
if (rec->type != IGRAPH_ATTRIBUTE_STRING) {
IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
} else {
igraph_strvector_t *str = (igraph_strvector_t*)rec->value;
IGRAPH_CHECK(igraph_strvector_set(str, 0, value));
}
} else {
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_strvector_t *str;
if (!rec) {
IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
rec->type = IGRAPH_ATTRIBUTE_STRING;
str = igraph_Calloc(1, igraph_strvector_t);
if (!str) {
IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, str);
IGRAPH_STRVECTOR_INIT_FINALLY(str, 1);
IGRAPH_CHECK(igraph_strvector_set(str, 0, value));
rec->value = str;
IGRAPH_CHECK(igraph_vector_ptr_push_back(gal, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_VAN_set
* Set a numeric vertex attribute
*
* The attribute will be added if not present already. If present it
* will be overwritten. The same \p value is set for all vertices
* included in \p vid.
* \param graph The graph.
* \param name Name of the attribute.
* \param vid Vertices for which to set the attribute.
* \param value The (new) value of the attribute.
* \return Error code.
*
* \sa \ref SETVAN for a simpler way.
*
* Time complexity: O(n), the number of vertices if the attribute is
* new, O(|vid|) otherwise.
*/
int igraph_cattribute_VAN_set(igraph_t *graph, const char *name,
igraph_integer_t vid, igraph_real_t value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
if (l) {
igraph_attribute_record_t *rec = VECTOR(*val)[j];
if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) {
IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
} else {
igraph_vector_t *num = (igraph_vector_t*)rec->value;
VECTOR(*num)[(long int)vid] = value;
}
} else {
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_vector_t *num;
if (!rec) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
rec->type = IGRAPH_ATTRIBUTE_NUMERIC;
num = igraph_Calloc(1, igraph_vector_t);
if (!num) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, num);
IGRAPH_VECTOR_INIT_FINALLY(num, igraph_vcount(graph));
igraph_vector_fill(num, IGRAPH_NAN);
VECTOR(*num)[(long int)vid] = value;
rec->value = num;
IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_VAB_set
* Set a boolean vertex attribute
*
* The attribute will be added if not present already. If present it
* will be overwritten. The same \p value is set for all vertices
* included in \p vid.
* \param graph The graph.
* \param name Name of the attribute.
* \param vid Vertices for which to set the attribute.
* \param value The (new) value of the attribute.
* \return Error code.
*
* \sa \ref SETVAB for a simpler way.
*
* Time complexity: O(n), the number of vertices if the attribute is
* new, O(|vid|) otherwise.
*/
int igraph_cattribute_VAB_set(igraph_t *graph, const char *name,
igraph_integer_t vid, igraph_bool_t value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
if (l) {
igraph_attribute_record_t *rec = VECTOR(*val)[j];
if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) {
IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
} else {
igraph_vector_bool_t *log = (igraph_vector_bool_t*)rec->value;
VECTOR(*log)[(long int)vid] = value;
}
} else {
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_vector_bool_t *log;
if (!rec) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
rec->type = IGRAPH_ATTRIBUTE_BOOLEAN;
log = igraph_Calloc(1, igraph_vector_bool_t);
if (!log) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, log);
IGRAPH_CHECK(igraph_vector_bool_init(log, igraph_vcount(graph)));
IGRAPH_FINALLY(igraph_vector_bool_destroy, log);
igraph_vector_bool_fill(log, 0);
VECTOR(*log)[(long int)vid] = value;
rec->value = log;
IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_VAS_set
* Set a string vertex attribute
*
* The attribute will be added if not present already. If present it
* will be overwritten. The same \p value is set for all vertices
* included in \p vid.
* \param graph The graph.
* \param name Name of the attribute.
* \param vid Vertices for which to set the attribute.
* \param value The (new) value of the attribute.
* \return Error code.
*
* \sa \ref SETVAS for a simpler way.
*
* Time complexity: O(n*l), n is the number of vertices, l is the
* length of the string to set. If the attribute if not new then only
* O(|vid|*l).
*/
int igraph_cattribute_VAS_set(igraph_t *graph, const char *name,
igraph_integer_t vid, const char *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
if (l) {
igraph_attribute_record_t *rec = VECTOR(*val)[j];
if (rec->type != IGRAPH_ATTRIBUTE_STRING) {
IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
} else {
igraph_strvector_t *str = (igraph_strvector_t*)rec->value;
IGRAPH_CHECK(igraph_strvector_set(str, vid, value));
}
} else {
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_strvector_t *str;
if (!rec) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
rec->type = IGRAPH_ATTRIBUTE_STRING;
str = igraph_Calloc(1, igraph_strvector_t);
if (!str) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, str);
IGRAPH_STRVECTOR_INIT_FINALLY(str, igraph_vcount(graph));
IGRAPH_CHECK(igraph_strvector_set(str, vid, value));
rec->value = str;
IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_EAN_set
* Set a numeric edge attribute
*
* The attribute will be added if not present already. If present it
* will be overwritten. The same \p value is set for all edges
* included in \p vid.
* \param graph The graph.
* \param name Name of the attribute.
* \param eid Edges for which to set the attribute.
* \param value The (new) value of the attribute.
* \return Error code.
*
* \sa \ref SETEAN for a simpler way.
*
* Time complexity: O(e), the number of edges if the attribute is
* new, O(|eid|) otherwise.
*/
int igraph_cattribute_EAN_set(igraph_t *graph, const char *name,
igraph_integer_t eid, igraph_real_t value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
if (l) {
igraph_attribute_record_t *rec = VECTOR(*eal)[j];
if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) {
IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
} else {
igraph_vector_t *num = (igraph_vector_t*)rec->value;
VECTOR(*num)[(long int)eid] = value;
}
} else {
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_vector_t *num;
if (!rec) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
rec->type = IGRAPH_ATTRIBUTE_NUMERIC;
num = igraph_Calloc(1, igraph_vector_t);
if (!num) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, num);
IGRAPH_VECTOR_INIT_FINALLY(num, igraph_ecount(graph));
igraph_vector_fill(num, IGRAPH_NAN);
VECTOR(*num)[(long int)eid] = value;
rec->value = num;
IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_EAB_set
* Set a boolean edge attribute
*
* The attribute will be added if not present already. If present it
* will be overwritten. The same \p value is set for all edges
* included in \p vid.
* \param graph The graph.
* \param name Name of the attribute.
* \param eid Edges for which to set the attribute.
* \param value The (new) value of the attribute.
* \return Error code.
*
* \sa \ref SETEAB for a simpler way.
*
* Time complexity: O(e), the number of edges if the attribute is
* new, O(|eid|) otherwise.
*/
int igraph_cattribute_EAB_set(igraph_t *graph, const char *name,
igraph_integer_t eid, igraph_bool_t value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
if (l) {
igraph_attribute_record_t *rec = VECTOR(*eal)[j];
if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) {
IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
} else {
igraph_vector_bool_t *log = (igraph_vector_bool_t*)rec->value;
VECTOR(*log)[(long int)eid] = value;
}
} else {
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_vector_bool_t *log;
if (!rec) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
rec->type = IGRAPH_ATTRIBUTE_BOOLEAN;
log = igraph_Calloc(1, igraph_vector_bool_t);
if (!log) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, log);
IGRAPH_CHECK(igraph_vector_bool_init(log, igraph_ecount(graph)));
IGRAPH_FINALLY(igraph_vector_bool_destroy, log);
igraph_vector_bool_fill(log, 0);
VECTOR(*log)[(long int)eid] = value;
rec->value = log;
IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_EAS_set
* Set a string edge attribute
*
* The attribute will be added if not present already. If present it
* will be overwritten. The same \p value is set for all edges
* included in \p vid.
* \param graph The graph.
* \param name Name of the attribute.
* \param eid Edges for which to set the attribute.
* \param value The (new) value of the attribute.
* \return Error code.
*
* \sa \ref SETEAS for a simpler way.
*
* Time complexity: O(e*l), n is the number of edges, l is the
* length of the string to set. If the attribute if not new then only
* O(|eid|*l).
*/
int igraph_cattribute_EAS_set(igraph_t *graph, const char *name,
igraph_integer_t eid, const char *value) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
if (l) {
igraph_attribute_record_t *rec = VECTOR(*eal)[j];
if (rec->type != IGRAPH_ATTRIBUTE_STRING) {
IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);
} else {
igraph_strvector_t *str = (igraph_strvector_t*)rec->value;
IGRAPH_CHECK(igraph_strvector_set(str, eid, value));
}
} else {
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_strvector_t *str;
if (!rec) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
rec->type = IGRAPH_ATTRIBUTE_STRING;
str = igraph_Calloc(1, igraph_strvector_t);
if (!str) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, str);
IGRAPH_STRVECTOR_INIT_FINALLY(str, igraph_ecount(graph));
IGRAPH_CHECK(igraph_strvector_set(str, eid, value));
rec->value = str;
IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_VAN_setv
* Set a numeric vertex attribute for all vertices.
*
* The attribute will be added if not present yet.
* \param graph The graph.
* \param name Name of the attribute.
* \param v The new attribute values. The length of this vector must
* match the number of vertices.
* \return Error code.
*
* \sa \ref SETVANV for a simpler way.
*
* Time complexity: O(n), the number of vertices.
*/
int igraph_cattribute_VAN_setv(igraph_t *graph, const char *name,
const igraph_vector_t *v) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
/* Check length first */
if (igraph_vector_size(v) != igraph_vcount(graph)) {
IGRAPH_ERROR("Invalid vertex attribute vector length", IGRAPH_EINVAL);
}
if (l) {
/* Already present, check type */
igraph_attribute_record_t *rec = VECTOR(*val)[j];
igraph_vector_t *num = (igraph_vector_t *)rec->value;
if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) {
IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
}
igraph_vector_clear(num);
IGRAPH_CHECK(igraph_vector_append(num, v));
} else {
/* Add it */
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_vector_t *num;
if (!rec) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->type = IGRAPH_ATTRIBUTE_NUMERIC;
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
num = igraph_Calloc(1, igraph_vector_t);
if (!num) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, num);
rec->value = num;
IGRAPH_CHECK(igraph_vector_copy(num, v));
IGRAPH_FINALLY(igraph_vector_destroy, num);
IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_VAB_setv
* Set a boolean vertex attribute for all vertices.
*
* The attribute will be added if not present yet.
* \param graph The graph.
* \param name Name of the attribute.
* \param v The new attribute values. The length of this boolean vector must
* match the number of vertices.
* \return Error code.
*
* \sa \ref SETVANV for a simpler way.
*
* Time complexity: O(n), the number of vertices.
*/
int igraph_cattribute_VAB_setv(igraph_t *graph, const char *name,
const igraph_vector_bool_t *v) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
/* Check length first */
if (igraph_vector_bool_size(v) != igraph_vcount(graph)) {
IGRAPH_ERROR("Invalid vertex attribute vector length", IGRAPH_EINVAL);
}
if (l) {
/* Already present, check type */
igraph_attribute_record_t *rec = VECTOR(*val)[j];
igraph_vector_bool_t *log = (igraph_vector_bool_t *)rec->value;
if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) {
IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
}
igraph_vector_bool_clear(log);
IGRAPH_CHECK(igraph_vector_bool_append(log, v));
} else {
/* Add it */
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_vector_bool_t *log;
if (!rec) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->type = IGRAPH_ATTRIBUTE_BOOLEAN;
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
log = igraph_Calloc(1, igraph_vector_bool_t);
if (!log) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, log);
rec->value = log;
IGRAPH_CHECK(igraph_vector_bool_copy(log, v));
IGRAPH_FINALLY(igraph_vector_bool_destroy, log);
IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_VAS_setv
* Set a string vertex attribute for all vertices.
*
* The attribute will be added if not present yet.
* \param graph The graph.
* \param name Name of the attribute.
* \param sv String vector, the new attribute values. The length of this vector must
* match the number of vertices.
* \return Error code.
*
* \sa \ref SETVASV for a simpler way.
*
* Time complexity: O(n+l), n is the number of vertices, l is the
* total length of the strings.
*/
int igraph_cattribute_VAS_setv(igraph_t *graph, const char *name,
const igraph_strvector_t *sv) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
/* Check length first */
if (igraph_strvector_size(sv) != igraph_vcount(graph)) {
IGRAPH_ERROR("Invalid vertex attribute vector length", IGRAPH_EINVAL);
}
if (l) {
/* Already present, check type */
igraph_attribute_record_t *rec = VECTOR(*val)[j];
igraph_strvector_t *str = (igraph_strvector_t *)rec->value;
if (rec->type != IGRAPH_ATTRIBUTE_STRING) {
IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
}
igraph_strvector_clear(str);
IGRAPH_CHECK(igraph_strvector_append(str, sv));
} else {
/* Add it */
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_strvector_t *str;
if (!rec) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->type = IGRAPH_ATTRIBUTE_STRING;
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
str = igraph_Calloc(1, igraph_strvector_t);
if (!str) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, str);
rec->value = str;
IGRAPH_CHECK(igraph_strvector_copy(str, sv));
IGRAPH_FINALLY(igraph_strvector_destroy, str);
IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_EAN_setv
* Set a numeric edge attribute for all edges.
*
* The attribute will be added if not present yet.
* \param graph The graph.
* \param name Name of the attribute.
* \param v The new attribute values. The length of this vector must
* match the number of edges.
* \return Error code.
*
* \sa \ref SETEANV for a simpler way.
*
* Time complexity: O(e), the number of edges.
*/
int igraph_cattribute_EAN_setv(igraph_t *graph, const char *name,
const igraph_vector_t *v) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
/* Check length first */
if (igraph_vector_size(v) != igraph_ecount(graph)) {
IGRAPH_ERROR("Invalid edge attribute vector length", IGRAPH_EINVAL);
}
if (l) {
/* Already present, check type */
igraph_attribute_record_t *rec = VECTOR(*eal)[j];
igraph_vector_t *num = (igraph_vector_t *)rec->value;
if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) {
IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
}
igraph_vector_clear(num);
IGRAPH_CHECK(igraph_vector_append(num, v));
} else {
/* Add it */
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_vector_t *num;
if (!rec) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->type = IGRAPH_ATTRIBUTE_NUMERIC;
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
num = igraph_Calloc(1, igraph_vector_t);
if (!num) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, num);
rec->value = num;
IGRAPH_CHECK(igraph_vector_copy(num, v));
IGRAPH_FINALLY(igraph_vector_destroy, num);
IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_EAB_setv
* Set a boolean edge attribute for all edges.
*
* The attribute will be added if not present yet.
* \param graph The graph.
* \param name Name of the attribute.
* \param v The new attribute values. The length of this vector must
* match the number of edges.
* \return Error code.
*
* \sa \ref SETEABV for a simpler way.
*
* Time complexity: O(e), the number of edges.
*/
int igraph_cattribute_EAB_setv(igraph_t *graph, const char *name,
const igraph_vector_bool_t *v) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
/* Check length first */
if (igraph_vector_bool_size(v) != igraph_ecount(graph)) {
IGRAPH_ERROR("Invalid edge attribute vector length", IGRAPH_EINVAL);
}
if (l) {
/* Already present, check type */
igraph_attribute_record_t *rec = VECTOR(*eal)[j];
igraph_vector_bool_t *log = (igraph_vector_bool_t *)rec->value;
if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) {
IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
}
igraph_vector_bool_clear(log);
IGRAPH_CHECK(igraph_vector_bool_append(log, v));
} else {
/* Add it */
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_vector_bool_t *log;
if (!rec) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->type = IGRAPH_ATTRIBUTE_BOOLEAN;
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
log = igraph_Calloc(1, igraph_vector_bool_t);
if (!log) {
IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, log);
rec->value = log;
IGRAPH_CHECK(igraph_vector_bool_copy(log, v));
IGRAPH_FINALLY(igraph_vector_bool_destroy, log);
IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
/**
* \function igraph_cattribute_EAS_setv
* Set a string edge attribute for all edges.
*
* The attribute will be added if not present yet.
* \param graph The graph.
* \param name Name of the attribute.
* \param sv String vector, the new attribute values. The length of this vector must
* match the number of edges.
* \return Error code.
*
* \sa \ref SETEASV for a simpler way.
*
* Time complexity: O(e+l), e is the number of edges, l is the
* total length of the strings.
*/
int igraph_cattribute_EAS_setv(igraph_t *graph, const char *name,
const igraph_strvector_t *sv) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
/* Check length first */
if (igraph_strvector_size(sv) != igraph_ecount(graph)) {
IGRAPH_ERROR("Invalid edge attribute vector length", IGRAPH_EINVAL);
}
if (l) {
/* Already present, check type */
igraph_attribute_record_t *rec = VECTOR(*eal)[j];
igraph_strvector_t *str = (igraph_strvector_t *)rec->value;
if (rec->type != IGRAPH_ATTRIBUTE_STRING) {
IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);
}
igraph_strvector_clear(str);
IGRAPH_CHECK(igraph_strvector_append(str, sv));
} else {
/* Add it */
igraph_attribute_record_t *rec = igraph_Calloc(1, igraph_attribute_record_t);
igraph_strvector_t *str;
if (!rec) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, rec);
rec->type = IGRAPH_ATTRIBUTE_STRING;
rec->name = strdup(name);
if (!rec->name) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, (char*)rec->name);
str = igraph_Calloc(1, igraph_strvector_t);
if (!str) {
IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);
}
IGRAPH_FINALLY(igraph_free, str);
rec->value = str;
IGRAPH_CHECK(igraph_strvector_copy(str, sv));
IGRAPH_FINALLY(igraph_strvector_destroy, str);
IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));
IGRAPH_FINALLY_CLEAN(4);
}
return 0;
}
void igraph_i_cattribute_free_rec(igraph_attribute_record_t *rec) {
if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
igraph_vector_t *num = (igraph_vector_t*)rec->value;
igraph_vector_destroy(num);
} else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
igraph_strvector_t *str = (igraph_strvector_t*)rec->value;
igraph_strvector_destroy(str);
} else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
igraph_vector_bool_t *boolvec = (igraph_vector_bool_t*)rec->value;
igraph_vector_bool_destroy(boolvec);
}
igraph_Free(rec->name);
igraph_Free(rec->value);
igraph_Free(rec);
}
/**
* \function igraph_cattribute_remove_g
* Remove a graph attribute
*
* \param graph The graph object.
* \param name Name of the graph attribute to remove.
*
* \sa \ref DELGA for a simpler way.
*
*/
void igraph_cattribute_remove_g(igraph_t *graph, const char *name) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *gal = &attr->gal;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j);
if (l) {
igraph_i_cattribute_free_rec(VECTOR(*gal)[j]);
igraph_vector_ptr_remove(gal, j);
} else {
IGRAPH_WARNING("Cannot remove non-existent graph attribute");
}
}
/**
* \function igraph_cattribute_remove_v
* Remove a vertex attribute
*
* \param graph The graph object.
* \param name Name of the vertex attribute to remove.
*
* \sa \ref DELVA for a simpler way.
*
*/
void igraph_cattribute_remove_v(igraph_t *graph, const char *name) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *val = &attr->val;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);
if (l) {
igraph_i_cattribute_free_rec(VECTOR(*val)[j]);
igraph_vector_ptr_remove(val, j);
} else {
IGRAPH_WARNING("Cannot remove non-existent graph attribute");
}
}
/**
* \function igraph_cattribute_remove_e
* Remove an edge attribute
*
* \param graph The graph object.
* \param name Name of the edge attribute to remove.
*
* \sa \ref DELEA for a simpler way.
*
*/
void igraph_cattribute_remove_e(igraph_t *graph, const char *name) {
igraph_i_cattributes_t *attr = graph->attr;
igraph_vector_ptr_t *eal = &attr->eal;
long int j;
igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j);
if (l) {
igraph_i_cattribute_free_rec(VECTOR(*eal)[j]);
igraph_vector_ptr_remove(eal, j);
} else {
IGRAPH_WARNING("Cannot remove non-existent graph attribute");
}
}
/**
* \function igraph_cattribute_remove_all
* Remove all graph/vertex/edge attributes
*
* \param graph The graph object.
* \param g Boolean, whether to remove graph attributes.
* \param v Boolean, whether to remove vertex attributes.
* \param e Boolean, whether to remove edge attributes.
*
* \sa \ref DELGAS, \ref DELVAS, \ref DELEAS, \ref DELALL for simpler
* ways.
*/
void igraph_cattribute_remove_all(igraph_t *graph, igraph_bool_t g,
igraph_bool_t v, igraph_bool_t e) {
igraph_i_cattributes_t *attr = graph->attr;
if (g) {
igraph_vector_ptr_t *gal = &attr->gal;
long int i, n = igraph_vector_ptr_size(gal);
for (i = 0; i < n; i++) {
igraph_i_cattribute_free_rec(VECTOR(*gal)[i]);
}
igraph_vector_ptr_clear(gal);
}
if (v) {
igraph_vector_ptr_t *val = &attr->val;
long int i, n = igraph_vector_ptr_size(val);
for (i = 0; i < n; i++) {
igraph_i_cattribute_free_rec(VECTOR(*val)[i]);
}
igraph_vector_ptr_clear(val);
}
if (e) {
igraph_vector_ptr_t *eal = &attr->eal;
long int i, n = igraph_vector_ptr_size(eal);
for (i = 0; i < n; i++) {
igraph_i_cattribute_free_rec(VECTOR(*eal)[i]);
}
igraph_vector_ptr_clear(eal);
}
}