# Chapter 12. Graph, vertex and edge attributes

Attributes are numbers, boolean values or strings associated with the vertices or edges of a graph, or with the graph itself. E.g. you may label vertices with symbolic names or attach numeric weights to the edges of a graph. In addition to these three basic types, a custom object type is supported as well.

igraph attributes are designed to be flexible and extensible. In igraph attributes are implemented via an interface abstraction: any type implementing the functions in the interface, can be used for storing vertex, edge and graph attributes. This means that different attribute implementations can be used together with igraph. This is reasonable: if igraph is used from Python attributes can be of any Python type, from R all R types are allowed. There is also an experimental attribute implementation to be used when programming in C, but by default it is currently turned off.

First we briefly look over how attribute handlers can be implemented. This is not something a user does every day. It is rather typically the job of the high level interface writers. (But it is possible to write an interface without implementing attributes.) Then we show the experimental C attribute handler.

## 1. The Attribute Handler Interface

It is possible to attach an attribute handling interface to igraph. This is simply a table of functions, of type `igraph_attribute_table_t`. These functions are invoked to notify the attribute handling code about the structural changes in a graph. See the documentation of this type for details.

By default there is no attribute interface attached to igraph. To attach one, call `igraph_set_attribute_table` with your new table. This is normally done on program startup, and is kept untouched for the program's lifetime. It must be done before any graph object is created, as graphs created with a given attribute handler cannot be manipulated while a different attribute handler is active.

### 1.1. `igraph_attribute_table_t` — Table of functions to perform operations on attributes.

    typedef struct igraph_attribute_table_t {
        igraph_error_t (*init)(igraph_t *graph, igraph_vector_ptr_t *attr);
        void           (*destroy)(igraph_t *graph);
        igraph_error_t (*copy)(igraph_t *to, const igraph_t *from, igraph_bool_t ga,
                               igraph_bool_t va, igraph_bool_t ea);
        igraph_error_t (*add_vertices)(igraph_t *graph, igraph_integer_t nv, igraph_vector_ptr_t *attr);
        igraph_error_t (*permute_vertices)(const igraph_t *graph,
                                           igraph_t *newgraph,
                                           const igraph_vector_int_t *idx);
        igraph_error_t (*combine_vertices)(const igraph_t *graph,
                                           igraph_t *newgraph,
                                           const igraph_vector_int_list_t *merges,
                                           const igraph_attribute_combination_t *comb);
        igraph_error_t (*add_edges)(igraph_t *graph, const igraph_vector_int_t *edges,
                                    igraph_vector_ptr_t *attr);
        igraph_error_t (*permute_edges)(const igraph_t *graph,
                                        igraph_t *newgraph, const igraph_vector_int_t *idx);
        igraph_error_t (*combine_edges)(const igraph_t *graph,
                                        igraph_t *newgraph,
                                        const igraph_vector_int_list_t *merges,
                                        const igraph_attribute_combination_t *comb);
        igraph_error_t (*get_info)(const igraph_t *graph,
                                   igraph_strvector_t *gnames, igraph_vector_int_t *gtypes,
                                   igraph_strvector_t *vnames, igraph_vector_int_t *vtypes,
                                   igraph_strvector_t *enames, igraph_vector_int_t *etypes);
        igraph_bool_t (*has_attr)(const igraph_t *graph, igraph_attribute_elemtype_t type,
                                  const char *name);
        igraph_error_t (*gettype)(const igraph_t *graph, igraph_attribute_type_t *type,
                                  igraph_attribute_elemtype_t elemtype, const char *name);
        igraph_error_t (*get_numeric_graph_attr)(const igraph_t *graph, const char *name,
                                                 igraph_vector_t *value);
        igraph_error_t (*get_string_graph_attr)(const igraph_t *graph, const char *name,
                                                igraph_strvector_t *value);
        igraph_error_t (*get_bool_graph_attr)(const igraph_t *igraph, const char *name,
                                              igraph_vector_bool_t *value);
        igraph_error_t (*get_numeric_vertex_attr)(const igraph_t *graph, const char *name,
                                                  igraph_vs_t vs,
                                                  igraph_vector_t *value);
        igraph_error_t (*get_string_vertex_attr)(const igraph_t *graph, const char *name,
                                                 igraph_vs_t vs,
                                                 igraph_strvector_t *value);
        igraph_error_t (*get_bool_vertex_attr)(const igraph_t *graph, const char *name,
                                               igraph_vs_t vs,
                                               igraph_vector_bool_t *value);
        igraph_error_t (*get_numeric_edge_attr)(const igraph_t *graph, const char *name,
                                                igraph_es_t es,
                                                igraph_vector_t *value);
        igraph_error_t (*get_string_edge_attr)(const igraph_t *graph, const char *name,
                                               igraph_es_t es,
                                               igraph_strvector_t *value);
        igraph_error_t (*get_bool_edge_attr)(const igraph_t *graph, const char *name,
                                             igraph_es_t es,
                                             igraph_vector_bool_t *value);
    } igraph_attribute_table_t;

This type collects the functions defining an attribute handler. It has the following members:

Values:

`init`: | This function is called whenever a new graph object is created, right after it is created but before any vertices or edges are added. It is supposed to set the `attr` member of the `igraph_t` object, which is guaranteed to be set to a null pointer before this function is called. It is expected to return an error code.
`destroy`: | This function is called whenever the graph object is destroyed, right before freeing the allocated memory. It is supposed to do any cleanup operations that are need to dispose of the `attr` member of the `igraph_t` object properly. The caller will set the `attr` member to a null pointer after this function returns.
`copy`: | This function is called when copying a graph with `igraph_copy`, after the structure of the graph has been already copied. It is supposed to populate the `attr` member of the target `igraph_t` object. The `attr` member of the target is guaranteed to be set to a null pointer before this function is called. It is expected to return an error code.
`add_vertices`: | Called when vertices are added to a graph, before adding the vertices themselves. The number of vertices to add is supplied as an argument. Expected to return an error code.

`permute_vertices`:

Called when a new graph is created based on an existing one such that there is a mapping from the vertices of the new graph back to the vertices of the old graph (e.g. if vertices are removed from a graph). The supplied index vector defines which old vertex a new vertex corresponds to. Its length must be the same as the number of vertices in the new graph. Note that the old and the new graph may be the same. If the two graph instances are not the same, implementors may safely assume that the new graph has no vertex attributes yet (but it may already have graph or edge attributes by the time this function is called).

`combine_vertices`:

This function is called when the creation of a new graph involves a merge (contraction, etc.) of vertices from another graph. The function is after the new graph was created. An argument specifies how several vertices from the old graph map to a single vertex in the new graph. It is guaranteed that the old and the new graph instances are different when this callback is called. Implementors may safely assume that the new graph has no vertex attributes yet (but it may already have graph or edge attributes by the time this function is called).

`add_edges`: | Called when new edges have been added. The number of new edges are supplied as well. It is expected to return an error code.

`permute_edges`:

Called when a new graph is created and some of the new edges should carry the attributes of some of the old edges. The idx vector shows the mapping between the old edges and the new ones. Its length is the same as the number of edges in the new graph, and for each edge it gives the ID of the old edge (the edge in the old graph). Note that the old and the new graph instances may be the same. If the two graph instances are not the same, implementors may safely assume that the new graph has no edge attributes yet (but it may already have graph or vertex attributes by the time this function is called).

`combine_edges`:

This function is called when the creation of a new graph involves a merge (contraction, etc.) of edges from another graph. The function is after the new graph was created. An argument specifies how several edges from the old graph map to a single edge in the new graph. It is guaranteed that the old and the new graph instances are different when this callback is called. Implementors may safely assume that the new graph has no edge attributes yet (but it may already have graph or vertex attributes by the time this function is called).

`get_info`: | Query the attributes of a graph, the names and types should be returned.
`has_attr`: | Check whether a graph has the named graph/vertex/edge attribute.
`gettype`: | Query the type of a graph/vertex/edge attribute.
`get_numeric_graph_attr`: | Query a numeric graph attribute. The value should be placed as the first element of the `value` vector.
`get_string_graph_attr`: | Query a string graph attribute. The value should be placed as the first element of the `value` string vector.
`get_bool_graph_attr`: | Query a boolean graph attribute. The value should be placed as the first element of the `value` boolean vector.
`get_numeric_vertex_attr`: | Query a numeric vertex attribute, for the vertices included in `vs`.
`get_string_vertex_attr`: | Query a string vertex attribute, for the vertices included in `vs`.
`get_bool_vertex_attr`: | Query a boolean vertex attribute, for the vertices included in `vs`.
`get_numeric_edge_attr`: | Query a numeric edge attribute, for the edges included in `es`.
`get_string_edge_attr`: | Query a string edge attribute, for the edges included in `es`.
`get_bool_edge_attr`: | Query a boolean edge attribute, for the edges included in `es`.

Note that the `get_*_*_attr` are allowed to convert the attributes to numeric or string. E.g. if a vertex attribute is a GNU R complex data type, then `get_string_vertex_attribute` may serialize it into a string, but this probably makes sense only if `add_vertices` is able to deserialize it.

### 1.2. `igraph_set_attribute_table` — Attach an attribute table.

    igraph_attribute_table_t *
    igraph_set_attribute_table(const igraph_attribute_table_t * table);

This function attaches attribute handling code to the igraph library. Note that the attribute handler table is not thread-local even if igraph is compiled in thread-local mode. In the vast majority of cases, this is not a significant restriction.

Attribute handlers are normally attached on program startup, and are left active for the program's lifetime. This is because a graph object created with a given attribute handler must not be manipulated while a different attribute handler is active.

Arguments:

`table`: | Pointer to an `igraph_attribute_table_t` object containing the functions for attribute manipulation. Supply `NULL` here if you don't want attributes.

Returns:

`` | Pointer to the old attribute handling table.

Time complexity: O(1).

### 1.3. `igraph_attribute_type_t` — The possible types of the attributes.

    typedef enum { IGRAPH_ATTRIBUTE_UNSPECIFIED = 0,
                   IGRAPH_ATTRIBUTE_DEFAULT IGRAPH_DEPRECATED_ENUMVAL = IGRAPH_ATTRIBUTE_UNSPECIFIED,
                   IGRAPH_ATTRIBUTE_NUMERIC = 1,
                   IGRAPH_ATTRIBUTE_BOOLEAN = 2,
                   IGRAPH_ATTRIBUTE_STRING = 3,
                   IGRAPH_ATTRIBUTE_OBJECT = 127
                 } igraph_attribute_type_t;

Note that this is only the type communicated by the attribute interface towards igraph functions. E.g. in the R attribute handler, it is safe to say that all complex R object attributes are strings, as long as this interface is able to serialize them into strings. See also `igraph_attribute_table_t`.

Values:

`IGRAPH_ATTRIBUTE_UNSPECIFIED`: | Currently used internally as a "null value" or "placeholder value" in some algorithms. Attribute records with this type must not be passed to igraph functions.
`IGRAPH_ATTRIBUTE_NUMERIC`: | Numeric attribute.
`IGRAPH_ATTRIBUTE_BOOLEAN`: | Logical values, true or false.
`IGRAPH_ATTRIBUTE_STRING`: | Attribute that can be converted to a string.
`IGRAPH_ATTRIBUTE_OBJECT`: | Custom attribute type, to be used for special data types by client applications. The R and Python interfaces use this for attributes that hold R or Python objects. Usually ignored by igraph functions.

## 2. Handling attribute combination lists

Several graph operations may collapse multiple vertices or edges into a single one. Attribute combination lists are used to indicate to the attribute handler how to combine the attributes of the original vertices or edges and how to derive the final attribute value that is to be assigned to the collapsed vertex or edge. For example, `igraph_simplify()` removes loops and combines multiple edges into a single one; in case of a graph with an edge attribute named `weight` the attribute combination list can tell the attribute handler whether the weight of a collapsed edge should be the sum, the mean or some other function of the weights of the original edges that were collapsed into one.

One attribute combination list may contain several attribute combination records, one for each vertex or edge attribute that is to be handled during the operation.

### 2.1. `igraph_attribute_combination_init` — Initialize attribute combination list.

    igraph_error_t igraph_attribute_combination_init(igraph_attribute_combination_t *comb);

Arguments:

`comb`: | The uninitialized attribute combination list.

Returns:

`` | Error code.

Time complexity: O(1)

### 2.2. `igraph_attribute_combination_add` — Add combination record to attribute combination list.

    igraph_error_t igraph_attribute_combination_add(igraph_attribute_combination_t *comb,
                                         const char *name,
                                         igraph_attribute_combination_type_t type,
                                         igraph_function_pointer_t func);

Arguments:

`comb`: | The attribute combination list.
`name`: | The name of the attribute. If the name already exists the attribute combination record will be replaced. Use NULL to add a default combination record for all atributes not in the list.
`type`: | The type of the attribute combination. See `igraph_attribute_combination_type_t` for the options.

`func`:

Function to be used if `type` is `IGRAPH_ATTRIBUTE_COMBINE_FUNCTION`. This function is called by the concrete attribute handler attached to igraph, and its calling signature depends completely on the attribute handler. For instance, if you are using attributes from C and you have attached the C attribute handler, you need to follow the documentation of the C attribute handler for more details.

Returns:

`` | Error code.

Time complexity: O(n), where n is the number of current attribute combinations.

### 2.3. `igraph_attribute_combination_remove` — Remove a record from an attribute combination list.

    igraph_error_t igraph_attribute_combination_remove(igraph_attribute_combination_t *comb,
                                            const char *name);

Arguments:

`comb`: | The attribute combination list.
`name`: | The attribute name of the attribute combination record to remove. It will be ignored if the named attribute does not exist. It can be NULL to remove the default combination record.

Returns:

`` | Error code. This currently always returns IGRAPH_SUCCESS.

Time complexity: O(n), where n is the number of records in the attribute combination list.

### 2.4. `igraph_attribute_combination_destroy` — Destroy attribute combination list.

    void igraph_attribute_combination_destroy(igraph_attribute_combination_t *comb);

Arguments:

`comb`: | The attribute combination list.

Time complexity: O(n), where n is the number of records in the attribute combination list.

### 2.5. `igraph_attribute_combination_type_t` — The possible types of attribute combinations.

    typedef enum {
        IGRAPH_ATTRIBUTE_COMBINE_IGNORE = 0,
        IGRAPH_ATTRIBUTE_COMBINE_DEFAULT = 1,
        IGRAPH_ATTRIBUTE_COMBINE_FUNCTION = 2,
        IGRAPH_ATTRIBUTE_COMBINE_SUM = 3,
        IGRAPH_ATTRIBUTE_COMBINE_PROD = 4,
        IGRAPH_ATTRIBUTE_COMBINE_MIN = 5,
        IGRAPH_ATTRIBUTE_COMBINE_MAX = 6,
        IGRAPH_ATTRIBUTE_COMBINE_RANDOM = 7,
        IGRAPH_ATTRIBUTE_COMBINE_FIRST = 8,
        IGRAPH_ATTRIBUTE_COMBINE_LAST = 9,
        IGRAPH_ATTRIBUTE_COMBINE_MEAN = 10,
        IGRAPH_ATTRIBUTE_COMBINE_MEDIAN = 11,
        IGRAPH_ATTRIBUTE_COMBINE_CONCAT = 12
    } igraph_attribute_combination_type_t;

Values:

`IGRAPH_ATTRIBUTE_COMBINE_IGNORE`: | Ignore old attributes, use an empty value.
`IGRAPH_ATTRIBUTE_COMBINE_DEFAULT`: | Use the default way to combine attributes (decided by the attribute handler implementation).
`IGRAPH_ATTRIBUTE_COMBINE_FUNCTION`: | Supply your own function to combine attributes.
`IGRAPH_ATTRIBUTE_COMBINE_SUM`: | Take the sum of the attributes.
`IGRAPH_ATTRIBUTE_COMBINE_PROD`: | Take the product of the attributes.
`IGRAPH_ATTRIBUTE_COMBINE_MIN`: | Take the minimum attribute.
`IGRAPH_ATTRIBUTE_COMBINE_MAX`: | Take the maximum attribute.
`IGRAPH_ATTRIBUTE_COMBINE_RANDOM`: | Take a random attribute.
`IGRAPH_ATTRIBUTE_COMBINE_FIRST`: | Take the first attribute.
`IGRAPH_ATTRIBUTE_COMBINE_LAST`: | Take the last attribute.
`IGRAPH_ATTRIBUTE_COMBINE_MEAN`: | Take the mean of the attributes.
`IGRAPH_ATTRIBUTE_COMBINE_MEDIAN`: | Take the median of the attributes.
`IGRAPH_ATTRIBUTE_COMBINE_CONCAT`: | Concatenate the attributes.

### 2.6. `igraph_attribute_combination` — Initialize attribute combination list and add records.

    igraph_error_t igraph_attribute_combination(
            igraph_attribute_combination_t *comb, ...);

Arguments:

`comb`: | The uninitialized attribute combination list.
`...`: | A list of 'name, type[, func]', where:
`name`: | The name of the attribute. If the name already exists the attribute combination record will be replaced. Use NULL to add a default combination record for all atributes not in the list.
`type`: | The type of the attribute combination. See `igraph_attribute_combination_type_t` for the options.
`func`: | Function to be used if `type` is `IGRAPH_ATTRIBUTE_COMBINE_FUNCTION`. The list is closed by setting the name to `IGRAPH_NO_MORE_ATTRIBUTES`.

Returns:

`` | Error code.

Time complexity: O(n^2), where n is the number attribute combinations records to add.

Example 12.1. File `examples/simple/igraph_attribute_combination.c`

    #include <igraph.h>

    int main(void) {
        igraph_t graph;

        igraph_attribute_combination_t comb;

        igraph_set_attribute_table(&igraph_cattribute_table);

        igraph_small(&graph, 2, IGRAPH_DIRECTED,
                     0,1, 0,1,
                     -1);

        SETEAB(&graph, "type", 0, true);
        SETEAB(&graph, "type", 1, false);

        igraph_attribute_combination(&comb,
                                     "weight", IGRAPH_ATTRIBUTE_COMBINE_SUM,
                                     "type",   IGRAPH_ATTRIBUTE_COMBINE_FIRST,
                                     "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE,
                                     IGRAPH_NO_MORE_ATTRIBUTES);
        igraph_simplify(&graph, /*multiple=*/ true, /*loops=*/ true, &comb);
        igraph_write_graph_graphml(&graph, stdout, /*prefixattr=*/ true);

        igraph_destroy(&graph);
        igraph_attribute_combination_destroy(&comb);

        return 0;
    }

## 3. Accessing attributes from C

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:

    igraph_set_attribute_table(&igraph_cattribute_table);

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 `main()` and never touch it again. Detaching the attribute handler might lead to memory leaks.

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. This also applies to the default case when there is no attribute handler at all.

The C attribute handler supports attaching real numbers, boolean values and character strings as attributes. No vector values are allowed. For example, vertices have a `name` attribute holding a single string value for each vertex, but it is not possible to have a `coords` attribute which is a vector of numbers per vertex.

The functions documented in this section are specific to the C attribute handler. Code using these functions will not function when a different attribute handler is attached.

Example 12.2. File `examples/simple/cattributes.c`

    #include <igraph.h>
    #include <string.h>
    #include <stdlib.h>

    /* Prints graph, vertex and edge attributes stored in a graph. */
    void print_attributes(const igraph_t *g) {
        igraph_vector_int_t gtypes, vtypes, etypes;
        igraph_strvector_t gnames, vnames, enames;
        igraph_integer_t i, j;

        igraph_vector_int_init(&gtypes, 0);
        igraph_vector_int_init(&vtypes, 0);
        igraph_vector_int_init(&etypes, 0);
        igraph_strvector_init(&gnames, 0);
        igraph_strvector_init(&vnames, 0);
        igraph_strvector_init(&enames, 0);

        igraph_cattribute_list(g,
                               &gnames, &gtypes,
                               &vnames, &vtypes,
                               &enames, &etypes);

        /* graph attributes */
        for (i = 0; i < igraph_strvector_size(&gnames); i++) {
            printf("%s=", igraph_strvector_get(&gnames, i));
            if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
                igraph_real_printf(GAN(g, igraph_strvector_get(&gnames, i)));
                putchar(' ');
            } else {
                printf("\"%s\" ", GAS(g, igraph_strvector_get(&gnames, i)));
            }
        }
        printf("\n");

        /* vertex attributes */
        for (i = 0; i < igraph_vcount(g); i++) {
            printf("Vertex %" IGRAPH_PRId ": ", i);
            for (j = 0; j < igraph_strvector_size(&vnames); j++) {
                printf("%s=", igraph_strvector_get(&vnames, j));
                if (VECTOR(vtypes)[j] == IGRAPH_ATTRIBUTE_NUMERIC) {
                    igraph_real_printf(VAN(g, igraph_strvector_get(&vnames, j), i));
                    putchar(' ');
                } else {
                    printf("\"%s\" ", VAS(g, igraph_strvector_get(&vnames, j), i));
                }
            }
            printf("\n");
        }

        /* edge attributes */
        for (i = 0; i < igraph_ecount(g); i++) {
            printf("Edge %" IGRAPH_PRId " (%" IGRAPH_PRId "-%" IGRAPH_PRId "): ", i, IGRAPH_FROM(g, i), IGRAPH_TO(g, i));
            for (j = 0; j < igraph_strvector_size(&enames); j++) {
                printf("%s=", igraph_strvector_get(&enames, j));
                if (VECTOR(etypes)[j] == IGRAPH_ATTRIBUTE_NUMERIC) {
                    igraph_real_printf(EAN(g, igraph_strvector_get(&enames, j), i));
                    putchar(' ');
                } else {
                    printf("\"%s\" ", EAS(g, igraph_strvector_get(&enames, j), i));
                }
            }
            printf("\n");
        }

        igraph_strvector_destroy(&enames);
        igraph_strvector_destroy(&vnames);
        igraph_strvector_destroy(&gnames);
        igraph_vector_int_destroy(&etypes);
        igraph_vector_int_destroy(&vtypes);
        igraph_vector_int_destroy(&gtypes);
    }

    int main(void) {
        igraph_t graph;
        igraph_vector_t y;

        /* Turn on attribute handling. */
        igraph_set_attribute_table(&igraph_cattribute_table);

        igraph_small(&graph, 3, IGRAPH_DIRECTED, 0,1, 1,2, -1);

        /* Set graph attributes. */
        /* numeric */
        SETGAN(&graph, "id", 10);
        /* string */
        SETGAS(&graph, "name", "toy");
        /* boolean */
        SETGAB(&graph, "is_regular", false);

        /* Set edge string attribute. */
        SETEAS(&graph, "color", 1, "RED");

        /* Set vertex attributes as vector. */
        igraph_vector_init(&y, igraph_vcount(&graph));
        igraph_vector_fill(&y, 1.23);
        SETVANV(&graph, "y", &y);
        igraph_vector_destroy(&y);

        /* Set single vertex numeric attribute. */
        SETVAN(&graph, "y", 0, -1);

        /* Delete graph attribute. */
        DELGA(&graph, "is_regular");

        /* Print the final result. */
        print_attributes(&graph);

        /* Delete all remaining attributes. */
        DELALL(&graph);

        /* Destroy the graph. */
        igraph_destroy(&graph);

        return 0;
    }

Example 12.3. File `examples/simple/cattributes2.c`

    #include <igraph.h>

    int main(void) {

        igraph_t g;
        igraph_vector_t y;
        igraph_warning_handler_t* oldwarnhandler;

        /* Turn on attribute handling. */
        igraph_set_attribute_table(&igraph_cattribute_table);

        /* Create a graph, add some attributes and save it as a GraphML file. */
        igraph_famous(&g, "Petersen");
        SETGAS(&g, "name", "Petersen's graph");
        SETGAN(&g, "vertices", igraph_vcount(&g));
        SETGAN(&g, "edges", igraph_ecount(&g));
        SETGAB(&g, "famous", true);

        igraph_vector_init_range(&y, 1, igraph_vcount(&g) + 1);
        SETVANV(&g, "id", &y);
        igraph_vector_destroy(&y);

        SETVAS(&g, "name", 0, "foo");
        SETVAS(&g, "name", 1, "foobar");

        SETVAB(&g, "is_first", 0, true);

        igraph_vector_init_range(&y, 1, igraph_ecount(&g) + 1);
        SETEANV(&g, "id", &y);
        igraph_vector_destroy(&y);

        SETEAS(&g, "name", 0, "FOO");
        SETEAS(&g, "name", 1, "FOOBAR");

        SETEAB(&g, "is_first", 0, true);

        /* Turn off the warning handler temporarily because the GML writer will
         * print warnings about boolean attributes being converted to numbers, and
         * we don't care about these. */
        oldwarnhandler = igraph_set_warning_handler(igraph_warning_handler_ignore);
        igraph_write_graph_gml(&g, stdout, IGRAPH_WRITE_GML_DEFAULT_SW, 0, "");
        igraph_set_warning_handler(oldwarnhandler);

        /* Back to business. */
        igraph_write_graph_graphml(&g, stdout, /*prefixattr=*/ true);

        igraph_destroy(&g);

        return 0;
    }

Example 12.4. File `examples/simple/cattributes3.c`

    #include <igraph.h>

    igraph_error_t mf(const igraph_vector_t *input, igraph_real_t *output) {
        *output = 0.0;
        return IGRAPH_SUCCESS;
    }

    static void simplify_write_destroy(igraph_t *g, igraph_attribute_combination_t *comb) {
        igraph_simplify(g, /*multiple=*/ true, /*loops=*/ true, comb);
        igraph_write_graph_graphml(g, stdout, /*prefixattr=*/ true);
        igraph_attribute_combination_destroy(comb);
        igraph_destroy(g);
    }

    static void weight_test(igraph_t *g, igraph_attribute_combination_type_t weight_attr) {
        igraph_t g2;
        igraph_attribute_combination_t comb;

        igraph_copy(&g2, g);
        igraph_attribute_combination(&comb,
                                     "weight", weight_attr,
                                     "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE,
                                     IGRAPH_NO_MORE_ATTRIBUTES);
        simplify_write_destroy(&g2, &comb);
    }

    int main(void) {

        igraph_t g, g2;
        igraph_vector_t weight;
        igraph_attribute_combination_t comb;

        igraph_set_attribute_table(&igraph_cattribute_table);

        igraph_small(&g, 4, IGRAPH_DIRECTED,
                     0, 1, 0, 1, 0, 1,
                     1, 2, 2, 3,
                     -1);

        igraph_vector_init_range(&weight, 1, igraph_ecount(&g) + 1);
        SETEANV(&g, "weight", &weight);
        igraph_vector_destroy(&weight);

        weight_test(&g, IGRAPH_ATTRIBUTE_COMBINE_SUM);
        weight_test(&g, IGRAPH_ATTRIBUTE_COMBINE_PROD);
        weight_test(&g, IGRAPH_ATTRIBUTE_COMBINE_MIN);
        weight_test(&g, IGRAPH_ATTRIBUTE_COMBINE_MAX);
        weight_test(&g, IGRAPH_ATTRIBUTE_COMBINE_FIRST);
        weight_test(&g, IGRAPH_ATTRIBUTE_COMBINE_LAST);
        weight_test(&g, IGRAPH_ATTRIBUTE_COMBINE_MEAN);

        /* ****************************************************** */

        igraph_copy(&g2, &g);
        igraph_attribute_combination(&comb,
                                     "weight", IGRAPH_ATTRIBUTE_COMBINE_FUNCTION, mf,
                                     "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE,
                                     IGRAPH_NO_MORE_ATTRIBUTES);
        simplify_write_destroy(&g2, &comb);

        /* ****************************************************** */

        igraph_copy(&g2, &g);
        igraph_attribute_combination(&comb,
                                     "",       IGRAPH_ATTRIBUTE_COMBINE_MEAN,
                                     IGRAPH_NO_MORE_ATTRIBUTES);
        simplify_write_destroy(&g2, &comb);

        /* ****************************************************** */

        igraph_destroy(&g);

        return 0;
    }

Example 12.5. File `examples/simple/cattributes4.c`

    #include <igraph.h>

    static void simplify_write_destroy(igraph_t *g, igraph_attribute_combination_t *comb) {
        igraph_simplify(g, /*multiple=*/ true, /*loops=*/ true, comb);
        igraph_write_graph_graphml(g, stdout, /*prefixattr=*/ true);
        igraph_attribute_combination_destroy(comb);
        igraph_destroy(g);
    }

    int main(void) {

        igraph_t g, g2;
        igraph_attribute_combination_t comb;

        igraph_set_attribute_table(&igraph_cattribute_table);

        igraph_small(&g, 4, IGRAPH_DIRECTED,
                     0, 1, 0, 1, 0, 1,
                     1, 2, 2, 3,
                     -1);

        SETEAS(&g, "color", 0, "green");
        SETEAS(&g, "color", 1, "red");
        SETEAS(&g, "color", 2, "blue");
        SETEAS(&g, "color", 3, "white");
        SETEAS(&g, "color", 4, "black");

        /* ****************************************************** */

        igraph_copy(&g2, &g);
        igraph_attribute_combination(&comb,
                                     "weight", IGRAPH_ATTRIBUTE_COMBINE_SUM,
                                     "color",  IGRAPH_ATTRIBUTE_COMBINE_FIRST,
                                     "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE,
                                     IGRAPH_NO_MORE_ATTRIBUTES);
        simplify_write_destroy(&g2, &comb);

        /* ****************************************************** */

        igraph_copy(&g2, &g);
        igraph_attribute_combination(&comb,
                                     "",       IGRAPH_ATTRIBUTE_COMBINE_LAST,
                                     IGRAPH_NO_MORE_ATTRIBUTES);
        simplify_write_destroy(&g2, &comb);

        /* ****************************************************** */

        igraph_copy(&g2, &g);
        igraph_attribute_combination(&comb,
                                     "",       IGRAPH_ATTRIBUTE_COMBINE_IGNORE,
                                     "color",  IGRAPH_ATTRIBUTE_COMBINE_CONCAT,
                                     IGRAPH_NO_MORE_ATTRIBUTES);
        simplify_write_destroy(&g2, &comb);

        /* ****************************************************** */

        igraph_destroy(&g);

        return 0;
    }

### 3.1. Query attributes

#### 3.1.1. `igraph_cattribute_list` — List all attributes.

    igraph_error_t igraph_cattribute_list(const igraph_t *graph,
                               igraph_strvector_t *gnames, igraph_vector_int_t *gtypes,
                               igraph_strvector_t *vnames, igraph_vector_int_t *vtypes,
                               igraph_strvector_t *enames, igraph_vector_int_t *etypes);

See `igraph_attribute_type_t` for the various attribute types.

Arguments:

`graph`: | The input graph.
`gnames`: | String vector, the names of the graph attributes.
`gtypes`: | Numeric vector, the types of the graph attributes.
`vnames`: | String vector, the names of the vertex attributes.
`vtypes`: | Numeric vector, the types of the vertex attributes.
`enames`: | String vector, the names of the edge attributes.
`etypes`: | Numeric vector, the types of the edge attributes.

Returns:

`` | 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.

#### 3.1.2. `igraph_cattribute_has_attr` — Checks whether a (graph, vertex or edge) attribute exists.

    igraph_bool_t igraph_cattribute_has_attr(const igraph_t *graph,
            igraph_attribute_elemtype_t type,
            const char *name);

Arguments:

`graph`: | The graph.
`type`: | The type of the attribute, `IGRAPH_ATTRIBUTE_GRAPH`, `IGRAPH_ATTRIBUTE_VERTEX` or `IGRAPH_ATTRIBUTE_EDGE`.
`name`: | Character constant, the name of the attribute.

Returns:

`` | 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.

#### 3.1.3. `igraph_cattribute_GAN` — Query a numeric graph attribute.

    igraph_real_t igraph_cattribute_GAN(const igraph_t *graph, const char *name);

Returns the value of the given numeric graph attribute. If the attribute does not exist, a warning is issued and NaN is returned.

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute to query.

Returns:

`` | The value of the attribute.

See also:

`` | `GAN` for a simpler interface.

Time complexity: O(Ag), the number of graph attributes.

#### 3.1.4. `GAN` — Query a numeric graph attribute.

    #define GAN(graph,n)

This is shorthand for `igraph_cattribute_GAN()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.

Returns:

`` | The value of the attribute.

#### 3.1.5. `igraph_cattribute_GAB` — Query a boolean graph attribute.

    igraph_bool_t igraph_cattribute_GAB(const igraph_t *graph, const char *name);

Returns the value of the given boolean graph attribute. If the attribute does not exist, a warning is issued and false is returned.

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute to query.

Returns:

`` | The value of the attribute.

See also:

`` | `GAB` for a simpler interface.

Time complexity: O(Ag), the number of graph attributes.

#### 3.1.6. `GAB` — Query a boolean graph attribute.

    #define GAB(graph,n)

This is shorthand for `igraph_cattribute_GAB()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.

Returns:

`` | The value of the attribute.

#### 3.1.7. `igraph_cattribute_GAS` — Query a string graph attribute.

    const char *igraph_cattribute_GAS(const igraph_t *graph, const char *name);

Returns a const pointer to the string graph attribute specified in `name`. The value must not be modified. If the attribute does not exist, a warning is issued and an empty string is returned.

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute to query.

Returns:

`` | The value of the attribute.

See also:

`` | `GAS` for a simpler interface.

Time complexity: O(Ag), the number of graph attributes.

#### 3.1.8. `GAS` — Query a string graph attribute.

    #define GAS(graph,n)

This is shorthand for `igraph_cattribute_GAS()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.

Returns:

`` | The value of the attribute.

#### 3.1.9. `igraph_cattribute_VAN` — Query a numeric vertex attribute.

    igraph_real_t igraph_cattribute_VAN(const igraph_t *graph, const char *name,
                                        igraph_integer_t vid);

If the attribute does not exist, a warning is issued and NaN is returned. See `igraph_cattribute_VANV()` for an error-checked version.

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`vid`: | The id of the queried vertex.

Returns:

`` | The value of the attribute.

See also:

`` | `VAN` macro for a simpler interface.

Time complexity: O(Av), the number of vertex attributes.

#### 3.1.10. `VAN` — Query a numeric vertex attribute.

    #define VAN(graph,n,v)

This is shorthand for `igraph_cattribute_VAN()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`v`: | The id of the vertex.

Returns:

`` | The value of the attribute.

#### 3.1.11. `igraph_cattribute_VANV` — Query a numeric vertex attribute for many vertices.

    igraph_error_t igraph_cattribute_VANV(const igraph_t *graph, const char *name,
                               igraph_vs_t vids, igraph_vector_t *result);

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`vids`: | The vertices to query.
`result`: | Pointer to an initialized vector, the result is stored here. It will be resized, if needed.

Returns:

`` | Error code.

Time complexity: O(v), where v is the number of vertices in 'vids'.

#### 3.1.12. `VANV` — Query a numeric vertex attribute for all vertices.

    #define VANV(graph,n,vec)

This is a shorthand for `igraph_cattribute_VANV()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`vec`: | Pointer to an initialized vector, the result is stored here. It will be resized, if needed.

Returns:

`` | Error code.

#### 3.1.13. `igraph_cattribute_VAB` — Query a boolean vertex attribute.

    igraph_bool_t igraph_cattribute_VAB(const igraph_t *graph, const char *name,
                                        igraph_integer_t vid);

If the vertex attribute does not exist, a warning is issued and false is returned. See `igraph_cattribute_VABV()` for an error-checked version.

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`vid`: | The id of the queried vertex.

Returns:

`` | The value of the attribute.

See also:

`` | `VAB` macro for a simpler interface.

Time complexity: O(Av), the number of vertex attributes.

#### 3.1.14. `VAB` — Query a boolean vertex attribute.

    #define VAB(graph,n,v)

This is shorthand for `igraph_cattribute_VAB()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`v`: | The id of the vertex.

Returns:

`` | The value of the attribute.

#### 3.1.15. `igraph_cattribute_VABV` — Query a boolean vertex attribute for many vertices.

    igraph_error_t igraph_cattribute_VABV(const igraph_t *graph, const char *name,
                               igraph_vs_t vids, igraph_vector_bool_t *result);

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`vids`: | The vertices to query.
`result`: | Pointer to an initialized boolean vector, the result is stored here. It will be resized, if needed.

Returns:

`` | Error code.

Time complexity: O(v), where v is the number of vertices in 'vids'.

#### 3.1.16. `VABV` — Query a boolean vertex attribute for all vertices.

    #define VABV(graph,n,vec)

This is a shorthand for `igraph_cattribute_VABV()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`vec`: | Pointer to an initialized boolean vector, the result is stored here. It will be resized, if needed.

Returns:

`` | Error code.

#### 3.1.17. `igraph_cattribute_VAS` — Query a string vertex attribute.

    const char *igraph_cattribute_VAS(const igraph_t *graph, const char *name,
                                      igraph_integer_t vid);

Returns a const pointer to the string vertex attribute specified in `name`. The value must not be modified. If the vertex attribute does not exist, a warning is issued and an empty string is returned. See `igraph_cattribute_VASV()` for an error-checked version.

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`vid`: | The id of the queried vertex.

Returns:

`` | The value of the attribute.

See also:

`` | The macro `VAS` for a simpler interface.

Time complexity: O(Av), the number of vertex attributes.

#### 3.1.18. `VAS` — Query a string vertex attribute.

    #define VAS(graph,n,v)

This is shorthand for `igraph_cattribute_VAS()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`v`: | The id of the vertex.

Returns:

`` | The value of the attribute.

#### 3.1.19. `igraph_cattribute_VASV` — Query a string vertex attribute for many vertices.

    igraph_error_t igraph_cattribute_VASV(const igraph_t *graph, const char *name,
                               igraph_vs_t vids, igraph_strvector_t *result);

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`vids`: | The vertices to query.
`result`: | Pointer to an initialized string vector, the result is stored here. It will be resized, if needed.

Returns:

`` | 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.)

#### 3.1.20. `VASV` — Query a string vertex attribute for all vertices.

    #define VASV(graph,n,vec)

This is a shorthand for `igraph_cattribute_VASV()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`vec`: | Pointer to an initialized string vector, the result is stored here. It will be resized, if needed.

Returns:

`` | Error code.

#### 3.1.21. `igraph_cattribute_EAN` — Query a numeric edge attribute.

    igraph_real_t igraph_cattribute_EAN(const igraph_t *graph, const char *name,
                                        igraph_integer_t eid);

If the attribute does not exist, a warning is issued and NaN is returned. See `igraph_cattribute_EANV()` for an error-checked version.

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`eid`: | The id of the queried edge.

Returns:

`` | The value of the attribute.

See also:

`` | `EAN` for an easier interface.

Time complexity: O(Ae), the number of edge attributes.

#### 3.1.22. `EAN` — Query a numeric edge attribute.

    #define EAN(graph,n,e)

This is shorthand for `igraph_cattribute_EAN()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`e`: | The id of the edge.

Returns:

`` | The value of the attribute.

#### 3.1.23. `igraph_cattribute_EANV` — Query a numeric edge attribute for many edges.

    igraph_error_t igraph_cattribute_EANV(const igraph_t *graph, const char *name,
                               igraph_es_t eids, igraph_vector_t *result);

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`eids`: | The edges to query.
`result`: | Pointer to an initialized vector, the result is stored here. It will be resized, if needed.

Returns:

`` | Error code.

Time complexity: O(e), where e is the number of edges in 'eids'.

#### 3.1.24. `EANV` — Query a numeric edge attribute for all edges.

    #define EANV(graph,n,vec)

This is a shorthand for `igraph_cattribute_EANV()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`vec`: | Pointer to an initialized vector, the result is stored here. It will be resized, if needed.

Returns:

`` | Error code.

#### 3.1.25. `igraph_cattribute_EAB` — Query a boolean edge attribute.

    igraph_bool_t igraph_cattribute_EAB(const igraph_t *graph, const char *name,
                                        igraph_integer_t eid);

If the edge attribute does not exist, a warning is issued and false is returned. See `igraph_cattribute_EABV()` for an error-checked version.

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`eid`: | The id of the queried edge.

Returns:

`` | The value of the attribute.

See also:

`` | `EAB` for an easier interface.

Time complexity: O(Ae), the number of edge attributes.

#### 3.1.26. `EAB` — Query a boolean edge attribute.

    #define EAB(graph,n,e)

This is shorthand for `igraph_cattribute_EAB()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`e`: | The id of the edge.

Returns:

`` | The value of the attribute.

#### 3.1.27. `igraph_cattribute_EABV` — Query a boolean edge attribute for many edges.

    igraph_error_t igraph_cattribute_EABV(const igraph_t *graph, const char *name,
                               igraph_es_t eids, igraph_vector_bool_t *result);

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`eids`: | The edges to query.
`result`: | Pointer to an initialized boolean vector, the result is stored here. It will be resized, if needed.

Returns:

`` | Error code.

Time complexity: O(e), where e is the number of edges in 'eids'.

#### 3.1.28. `EABV` — Query a boolean edge attribute for all edges.

    #define EABV(graph,n,vec)

This is a shorthand for `igraph_cattribute_EABV()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`vec`: | Pointer to an initialized vector, the result is stored here. It will be resized, if needed.

Returns:

`` | Error code.

#### 3.1.29. `igraph_cattribute_EAS` — Query a string edge attribute.

    const char *igraph_cattribute_EAS(const igraph_t *graph, const char *name,
                                      igraph_integer_t eid);

Returns a const pointer to the string edge attribute specified in `name`. The value must not be modified. If the edge attribute does not exist, a warning is issued and an empty string is returned. See `igraph_cattribute_EASV()` for an error-checked version.

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`eid`: | The id of the queried edge.

Returns:

`` | The value of the attribute.

\se `EAS` if you want to type less. Time complexity: O(Ae), the number of edge attributes.

#### 3.1.30. `EAS` — Query a string edge attribute.

    #define EAS(graph,n,e)

This is shorthand for `igraph_cattribute_EAS()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`e`: | The id of the edge.

Returns:

`` | The value of the attribute.

#### 3.1.31. `igraph_cattribute_EASV` — Query a string edge attribute for many edges.

    igraph_error_t igraph_cattribute_EASV(const igraph_t *graph, const char *name,
                               igraph_es_t eids, igraph_strvector_t *result);

Arguments:

`graph`: | The input graph.
`name`: | The name of the attribute.
`vids`: | The edges to query.
`result`: | Pointer to an initialized string vector, the result is stored here. It will be resized, if needed.

Returns:

`` | 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.)

#### 3.1.32. `EASV` — Query a string edge attribute for all edges.

    #define EASV(graph,n,vec)

This is a shorthand for `igraph_cattribute_EASV()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`vec`: | Pointer to an initialized string vector, the result is stored here. It will be resized, if needed.

Returns:

`` | Error code.

### 3.2. Set attributes

#### 3.2.1. `igraph_cattribute_GAN_set` — Set a numeric graph attribute.

    igraph_error_t igraph_cattribute_GAN_set(igraph_t *graph, const char *name,
                                  igraph_real_t value);

Arguments:

`graph`: | The graph.
`name`: | Name of the graph attribute. If there is no such attribute yet, then it will be added.
`value`: | The (new) value of the graph attribute.

Returns:

`` | Error code.

\se `SETGAN` if you want to type less. Time complexity: O(1).

#### 3.2.2. `SETGAN` — Set a numeric graph attribute

    #define SETGAN(graph,n,value)

This is a shorthand for `igraph_cattribute_GAN_set()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`value`: | The new value of the attribute.

Returns:

`` | Error code.

#### 3.2.3. `igraph_cattribute_GAB_set` — Set a boolean graph attribute.

    igraph_error_t igraph_cattribute_GAB_set(igraph_t *graph, const char *name,
                                  igraph_bool_t value);

Arguments:

`graph`: | The graph.
`name`: | Name of the graph attribute. If there is no such attribute yet, then it will be added.
`value`: | The (new) value of the graph attribute.

Returns:

`` | Error code.

\se `SETGAN` if you want to type less. Time complexity: O(1).

#### 3.2.4. `SETGAB` — Set a boolean graph attribute

    #define SETGAB(graph,n,value)

This is a shorthand for `igraph_cattribute_GAB_set()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`value`: | The new value of the attribute.

Returns:

`` | Error code.

#### 3.2.5. `igraph_cattribute_GAS_set` — Set a string graph attribute.

    igraph_error_t igraph_cattribute_GAS_set(igraph_t *graph, const char *name,
                                  const char *value);

Arguments:

`graph`: | The graph.
`name`: | Name of the graph attribute. If there is no such attribute yet, then it will be added.
`value`: | The (new) value of the graph attribute. It will be copied.

Returns:

`` | Error code.

\se `SETGAS` if you want to type less. Time complexity: O(1).

#### 3.2.6. `SETGAS` — Set a string graph attribute

    #define SETGAS(graph,n,value)

This is a shorthand for `igraph_cattribute_GAS_set()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`value`: | The new value of the attribute.

Returns:

`` | Error code.

#### 3.2.7. `igraph_cattribute_VAN_set` — Set a numeric vertex attribute.

    igraph_error_t igraph_cattribute_VAN_set(igraph_t *graph, const char *name,
                                  igraph_integer_t vid, igraph_real_t value);

The attribute will be added if not present already. If present it will be overwritten. The same `value` is set for all vertices included in `vid`.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`vid`: | Vertices for which to set the attribute.
`value`: | The (new) value of the attribute.

Returns:

`` | Error code.

See also:

`` | `SETVAN` for a simpler way.

Time complexity: O(n), the number of vertices if the attribute is new, O(|vid|) otherwise.

#### 3.2.8. `SETVAN` — Set a numeric vertex attribute

    #define SETVAN(graph,n,vid,value)

This is a shorthand for `igraph_cattribute_VAN_set()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`vid`: | Ids of the vertices to set.
`value`: | The new value of the attribute.

Returns:

`` | Error code.

#### 3.2.9. `igraph_cattribute_VAB_set` — Set a boolean vertex attribute.

    igraph_error_t igraph_cattribute_VAB_set(igraph_t *graph, const char *name,
                                  igraph_integer_t vid, igraph_bool_t value);

The attribute will be added if not present already. If present it will be overwritten. The same `value` is set for all vertices included in `vid`.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`vid`: | Vertices for which to set the attribute.
`value`: | The (new) value of the attribute.

Returns:

`` | Error code.

See also:

`` | `SETVAB` for a simpler way.

Time complexity: O(n), the number of vertices if the attribute is new, O(|vid|) otherwise.

#### 3.2.10. `SETVAB` — Set a boolean vertex attribute

    #define SETVAB(graph,n,vid,value)

This is a shorthand for `igraph_cattribute_VAB_set()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`vid`: | Ids of the vertices to set.
`value`: | The new value of the attribute.

Returns:

`` | Error code.

#### 3.2.11. `igraph_cattribute_VAS_set` — Set a string vertex attribute.

    igraph_error_t igraph_cattribute_VAS_set(igraph_t *graph, const char *name,
                                  igraph_integer_t vid, const char *value);

The attribute will be added if not present already. If present it will be overwritten. The same `value` is set for all vertices included in `vid`.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`vid`: | Vertices for which to set the attribute.
`value`: | The (new) value of the attribute.

Returns:

`` | Error code.

See also:

`` | `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).

#### 3.2.12. `SETVAS` — Set a string vertex attribute

    #define SETVAS(graph,n,vid,value)

This is a shorthand for `igraph_cattribute_VAS_set()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`vid`: | Ids of the vertices to set.
`value`: | The new value of the attribute.

Returns:

`` | Error code.

#### 3.2.13. `igraph_cattribute_EAN_set` — Set a numeric edge attribute.

    igraph_error_t igraph_cattribute_EAN_set(igraph_t *graph, const char *name,
                                  igraph_integer_t eid, igraph_real_t value);

The attribute will be added if not present already. If present it will be overwritten. The same `value` is set for all edges included in `vid`.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`eid`: | Edges for which to set the attribute.
`value`: | The (new) value of the attribute.

Returns:

`` | Error code.

See also:

`` | `SETEAN` for a simpler way.

Time complexity: O(e), the number of edges if the attribute is new, O(|eid|) otherwise.

#### 3.2.14. `SETEAN` — Set a numeric edge attribute

    #define SETEAN(graph,n,eid,value)

This is a shorthand for `igraph_cattribute_EAN_set()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`eid`: | Ids of the edges to set.
`value`: | The new value of the attribute.

Returns:

`` | Error code.

#### 3.2.15. `igraph_cattribute_EAB_set` — Set a boolean edge attribute.

    igraph_error_t igraph_cattribute_EAB_set(igraph_t *graph, const char *name,
                                  igraph_integer_t eid, igraph_bool_t value);

The attribute will be added if not present already. If present it will be overwritten. The same `value` is set for all edges included in `vid`.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`eid`: | Edges for which to set the attribute.
`value`: | The (new) value of the attribute.

Returns:

`` | Error code.

See also:

`` | `SETEAB` for a simpler way.

Time complexity: O(e), the number of edges if the attribute is new, O(|eid|) otherwise.

#### 3.2.16. `SETEAB` — Set a boolean edge attribute

    #define SETEAB(graph,n,eid,value)

This is a shorthand for `igraph_cattribute_EAB_set()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`eid`: | Ids of the edges to set.
`value`: | The new value of the attribute.

Returns:

`` | Error code.

#### 3.2.17. `igraph_cattribute_EAS_set` — Set a string edge attribute.

    igraph_error_t igraph_cattribute_EAS_set(igraph_t *graph, const char *name,
                                  igraph_integer_t eid, const char *value);

The attribute will be added if not present already. If present it will be overwritten. The same `value` is set for all edges included in `vid`.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`eid`: | Edges for which to set the attribute.
`value`: | The (new) value of the attribute.

Returns:

`` | Error code.

See also:

`` | `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).

#### 3.2.18. `SETEAS` — Set a string edge attribute

    #define SETEAS(graph,n,eid,value)

This is a shorthand for `igraph_cattribute_EAS_set()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`eid`: | Ids of the edges to set.
`value`: | The new value of the attribute.

Returns:

`` | Error code.

#### 3.2.19. `igraph_cattribute_VAN_setv` — Set a numeric vertex attribute for all vertices.

    igraph_error_t igraph_cattribute_VAN_setv(igraph_t *graph, const char *name,
                                   const igraph_vector_t *v);

The attribute will be added if not present yet.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`v`: | The new attribute values. The length of this vector must match the number of vertices.

Returns:

`` | Error code.

See also:

`` | `SETVANV` for a simpler way.

Time complexity: O(n), the number of vertices.

#### 3.2.20. `SETVANV` — Set a numeric vertex attribute for all vertices

    #define SETVANV(graph,n,v)

This is a shorthand for `igraph_cattribute_VAN_setv()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`v`: | Vector containing the new values of the attributes.

Returns:

`` | Error code.

#### 3.2.21. `igraph_cattribute_VAB_setv` — Set a boolean vertex attribute for all vertices.

    igraph_error_t igraph_cattribute_VAB_setv(igraph_t *graph, const char *name,
                                   const igraph_vector_bool_t *v);

The attribute will be added if not present yet.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`v`: | The new attribute values. The length of this boolean vector must match the number of vertices.

Returns:

`` | Error code.

See also:

`` | `SETVANV` for a simpler way.

Time complexity: O(n), the number of vertices.

#### 3.2.22. `SETVABV` — Set a boolean vertex attribute for all vertices

    #define SETVABV(graph,n,v)

This is a shorthand for `igraph_cattribute_VAB_setv()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`v`: | Vector containing the new values of the attributes.

Returns:

`` | Error code.

#### 3.2.23. `igraph_cattribute_VAS_setv` — Set a string vertex attribute for all vertices.

    igraph_error_t igraph_cattribute_VAS_setv(igraph_t *graph, const char *name,
                                   const igraph_strvector_t *sv);

The attribute will be added if not present yet.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`sv`: | String vector, the new attribute values. The length of this vector must match the number of vertices.

Returns:

`` | Error code.

See also:

`` | `SETVASV` for a simpler way.

Time complexity: O(n+l), n is the number of vertices, l is the total length of the strings.

#### 3.2.24. `SETVASV` — Set a string vertex attribute for all vertices

    #define SETVASV(graph,n,v)

This is a shorthand for `igraph_cattribute_VAS_setv()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`v`: | Vector containing the new values of the attributes.

Returns:

`` | Error code.

#### 3.2.25. `igraph_cattribute_EAN_setv` — Set a numeric edge attribute for all edges.

    igraph_error_t igraph_cattribute_EAN_setv(igraph_t *graph, const char *name,
                                   const igraph_vector_t *v);

The attribute will be added if not present yet.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`v`: | The new attribute values. The length of this vector must match the number of edges.

Returns:

`` | Error code.

See also:

`` | `SETEANV` for a simpler way.

Time complexity: O(e), the number of edges.

#### 3.2.26. `SETEANV` — Set a numeric edge attribute for all edges

    #define SETEANV(graph,n,v)

This is a shorthand for `igraph_cattribute_EAN_setv()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`v`: | Vector containing the new values of the attributes.

#### 3.2.27. `igraph_cattribute_EAB_setv` — Set a boolean edge attribute for all edges.

    igraph_error_t igraph_cattribute_EAB_setv(igraph_t *graph, const char *name,
                                   const igraph_vector_bool_t *v);

The attribute will be added if not present yet.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`v`: | The new attribute values. The length of this vector must match the number of edges.

Returns:

`` | Error code.

See also:

`` | `SETEABV` for a simpler way.

Time complexity: O(e), the number of edges.

#### 3.2.28. `SETEABV` — Set a boolean edge attribute for all edges

    #define SETEABV(graph,n,v)

This is a shorthand for `igraph_cattribute_EAB_setv()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`v`: | Vector containing the new values of the attributes.

#### 3.2.29. `igraph_cattribute_EAS_setv` — Set a string edge attribute for all edges.

    igraph_error_t igraph_cattribute_EAS_setv(igraph_t *graph, const char *name,
                                   const igraph_strvector_t *sv);

The attribute will be added if not present yet.

Arguments:

`graph`: | The graph.
`name`: | Name of the attribute.
`sv`: | String vector, the new attribute values. The length of this vector must match the number of edges.

Returns:

`` | Error code.

See also:

`` | `SETEASV` for a simpler way.

Time complexity: O(e+l), e is the number of edges, l is the total length of the strings.

#### 3.2.30. `SETEASV` — Set a string edge attribute for all edges

    #define SETEASV(graph,n,v)

This is a shorthand for `igraph_cattribute_EAS_setv()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute.
`v`: | Vector containing the new values of the attributes.

### 3.3. Remove attributes

#### 3.3.1. `igraph_cattribute_remove_g` — Remove a graph attribute.

    void igraph_cattribute_remove_g(igraph_t *graph, const char *name);

Arguments:

`graph`: | The graph object.
`name`: | Name of the graph attribute to remove.

See also:

`` | `DELGA` for a simpler way.

#### 3.3.2. `DELGA` — Remove a graph attribute.

    #define DELGA(graph,n)

A shorthand for `igraph_cattribute_remove_g()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute to remove.

#### 3.3.3. `igraph_cattribute_remove_v` — Remove a vertex attribute.

    void igraph_cattribute_remove_v(igraph_t *graph, const char *name);

Arguments:

`graph`: | The graph object.
`name`: | Name of the vertex attribute to remove.

See also:

`` | `DELVA` for a simpler way.

#### 3.3.4. `DELVA` — Remove a vertex attribute.

    #define DELVA(graph,n)

A shorthand for `igraph_cattribute_remove_v()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute to remove.

#### 3.3.5. `igraph_cattribute_remove_e` — Remove an edge attribute.

    void igraph_cattribute_remove_e(igraph_t *graph, const char *name);

Arguments:

`graph`: | The graph object.
`name`: | Name of the edge attribute to remove.

See also:

`` | `DELEA` for a simpler way.

#### 3.3.6. `DELEA` — Remove an edge attribute.

    #define DELEA(graph,n)

A shorthand for `igraph_cattribute_remove_e()`.

Arguments:

`graph`: | The graph.
`n`: | The name of the attribute to remove.

#### 3.3.7. `igraph_cattribute_remove_all` — Remove all graph/vertex/edge attributes.

    void igraph_cattribute_remove_all(igraph_t *graph, igraph_bool_t g,
                                      igraph_bool_t v, igraph_bool_t e);

Arguments:

`graph`: | The graph object.
`g`: | Boolean, whether to remove graph attributes.
`v`: | Boolean, whether to remove vertex attributes.
`e`: | Boolean, whether to remove edge attributes.

See also:

`` | `DELGAS`, `DELVAS`, `DELEAS`, `DELALL` for simpler ways.

#### 3.3.8. `DELGAS` — Remove all graph attributes.

    #define DELGAS(graph)

Calls `igraph_cattribute_remove_all()`.

Arguments:

`graph`: | The graph.

#### 3.3.9. `DELVAS` — Remove all vertex attributes.

    #define DELVAS(graph)

Calls `igraph_cattribute_remove_all()`.

Arguments:

`graph`: | The graph.

#### 3.3.10. `DELEAS` — Remove all edge attributes.

    #define DELEAS(graph)

Calls `igraph_cattribute_remove_all()`.

Arguments:

`graph`: | The graph.

#### 3.3.11. `DELALL` — Remove all attributes.

    #define DELALL(graph)

All graph, vertex and edges attributes will be removed. Calls `igraph_cattribute_remove_all()`.

Arguments:

`graph`: | The graph.

### 3.4. Custom attribute combination functions

The C attribute handler supports combining the attributes of multiple vertices of edges into a single attribute during a vertex or edge contraction operation via a user-defined function. This is achieved by setting the type of the attribute combination to `IGRAPH_ATTRIBUTE_COMBINE_FUNCTION` and passing in a pointer to the custom combination function when specifying attribute combinations in `igraph_attribute_combination()` or `igraph_attribute_combination_add()` . For the C attribute handler, the signature of the function depends on the type of the underlying attribute. For numeric attributes, use:

     igraph_error_t function(const igraph_vector_t *input, igraph_real_t *output);

where `input` will receive a vector containing the value of the attribute for all the vertices or edges being combined, and `output` must be filled by the function to the combined value. Similarly, for Boolean attributes, the function takes a boolean vector in `input` and must return the combined Boolean value in `output`:

     igraph_error_t function(const igraph_vector_bool_t *input, igraph_bool_t *output);

For string attributes, the signature is slightly different:

     igraph_error_t function(const igraph_strvector_t *input, char **output);

In case of strings, all strings in the input vector are owned by igraph and must not be modified or freed in the combination handler. The string returned to the caller in `output` remains owned by the caller; igraph will make a copy it and store the copy in the appropriate part of the data structure holding the vertex or edge attributes.