# Chapter 10. 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, const igraph_attribute_record_list_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_int_t nv,
            const igraph_attribute_record_list_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,
            const igraph_attribute_record_list_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 (*get_type)(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 set the `attr` member to a non-null value or return an error code. Leaving the `attr` member at a null value while returning success is invalid and will trigger an error in the C core of igraph itself.

`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 the C core wants to populate the attributes of a graph from another graph. The structure of the target graph is already initialized by the time this function is called, and the `attr` member of the graph is set to a null pointer. The function is supposed to populate the `attr` member of the target `igraph_t` object to a non-null value or return an error code. Leaving the `attr` member at a null value while returning success is invalid and will trigger an error in the C core of igraph itself.

`add_vertices`: | Called when vertices are added to a graph, after the base data structure was modified. The number of vertices that were added is supplied as an argument. The function is supposed to set up default values for each vertex attribute that is currently registered on the graph, for all the newly added vertices. 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 is the same as the number of vertices in the new graph, and for each new vertex it provides the ID of the corresponding vertex in the old graph. The function is supposed to set up the values of the vertex attributes of the new graph based on the attributes of the old graph and the provided index vector. Note that the old and the new graph may be the same, in which case it is the responsibility of the function to ensure that the operation can safely be performed in-place. 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 called 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 are added to a graph, after the base data structure was modified. A vector containing the endpoints of the new edges are supplied as an argument. The function is supposed to set up default values for each edge attribute that is currently registered on the graph, for all the newly added edges. Expected to return an error code.

`permute_edges`:

Called when a new graph is created based on an existing one such that some of the edges in the new graph should copy the attributes of some edges from the old graph (this also includes the deletion of edges). The supplied index vector defines which old edge a new edge corresponds to. Its length is the same as the number of edges in the new graph, and for each edge it provides the ID of the corresponding edge in the old graph. The function is supposed to set up the values of the edge attributes of the new graph based on the attributes of the old graph and the provided index vector. Note that the old and the new graph may be the same, in which case it is the responsibility of the function to ensure that the operation can safely be performed in-place. 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.
`get_type`: | Query the type of a graph/vertex/edge attribute.
`get_numeric_graph_attr`: | Query a numeric graph attribute. The value should be appended to the provided `value` vector. No assumptions should be made about the initial contents of the `value` vector and it is not guaranteed to be empty.
`get_string_graph_attr`: | Query a string graph attribute. The value should be appended to the provided `value` vector. No assumptions should be made about the initial contents of the `value` vector and it is not guaranteed to be empty.
`get_bool_graph_attr`: | Query a boolean graph attribute. The value should be appended to the provided `value` vector. No assumptions should be made about the initial contents of the `value` vector and it is not guaranteed to be empty.
`get_numeric_vertex_attr`: | Query a numeric vertex attribute, for the vertices included in `vs`. The attribute values should be appended to the provided `value` vector. No assumptions should be made about the initial contents of the `value` vector and it is not guaranteed to be empty.
`get_string_vertex_attr`: | Query a string vertex attribute, for the vertices included in `vs`. The attribute values should be appended to the provided `value` vector. No assumptions should be made about the initial contents of the `value` vector and it is not guaranteed to be empty.
`get_bool_vertex_attr`: | Query a boolean vertex attribute, for the vertices included in `vs`. The attribute values should be appended to the provided `value` vector. No assumptions should be made about the initial contents of the `value` vector and it is not guaranteed to be empty.
`get_numeric_edge_attr`: | Query a numeric edge attribute, for the edges included in `es`. The attribute values should be appended to the provided `value` vector. No assumptions should be made about the initial contents of the `value` vector and it is not guaranteed to be empty.
`get_string_edge_attr`: | Query a string edge attribute, for the the edges included in `es`. The attribute values should be appended to the provided `value` vector. No assumptions should be made about the initial contents of the `value` vector and it is not guaranteed to be empty.
`get_bool_edge_attr`: | Query a boolean edge attribute, for the the edges included in `es`. The attribute values should be appended to the provided `value` vector. No assumptions should be made about the initial contents of the `value` vector and it is not guaranteed to be empty.

### 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_NUMERIC = 1,
        IGRAPH_ATTRIBUTE_BOOLEAN = 2,
        IGRAPH_ATTRIBUTE_STRING = 3,
        IGRAPH_ATTRIBUTE_OBJECT = 127
    } igraph_attribute_type_t;

Values of this enum are used by the attribute interface to communicate the type of an attribute to igraph's C core. When igraph is integrated in a high-level language, the attribute type reported by the interface may not necessarily have to match the exact data type in the high-level language as long as the attribute interface can provide a conversion from the native high-level attribute value to one of the data types listed here. When the high-level data type is complex and has no suitable conversion to one of the atomic igraph attribute types (numeric, string or Boolean), the attribute interface should report the attribute as having an "object" type, which is ignored by the C core. 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`: | String attribute.
`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.

### 1.4. `igraph_attribute_elemtype_t` — Types of objects to which attributes can be attached.

    typedef enum {
        IGRAPH_ATTRIBUTE_GRAPH = 0,
        IGRAPH_ATTRIBUTE_VERTEX,
        IGRAPH_ATTRIBUTE_EDGE
    } igraph_attribute_elemtype_t;

Values:

`IGRAPH_ATTRIBUTE_GRAPH`: | Denotes that an attribute belongs to the entire graph.
`IGRAPH_ATTRIBUTE_VERTEX`: | Denotes that an attribute belongs to the vertices of a graph.
`IGRAPH_ATTRIBUTE_EDGE`: | Denotes that an attribute belongs to the edges of a graph.

## 2. Attribute records

Functions in the attribute handler interface may refer to "attribute records" or "attribute record lists". An attribute record is simply a triplet consisting of an attribute name, an attribute type and a vector containing the values of the attribute. Attribute record lists are typed containers that contain a sequence of attribute records. Attribute record lists own the attribute records that they contain, and similarly, attribute records own the vectors contained in them. Destroying an attribute record destroys the vector of values inside it, and destroying an attribute record list destroys all attribute records in the list.

### 2.1. `igraph_attribute_record_t` — An attribute record holding the name, type and values of an attribute.

    typedef struct igraph_attribute_record_t {
        char *name;

This composite data type is used in the attribute interface to specify a name-type-value triplet where the name is the name of a graph, vertex or edge attribute, the type is the corresponding igraph type of the attribute and the value is a vector of attribute values. Note that for graph attributes we use a vector of length 1. The type of the vector depends on the attribute type: it is `igraph_vector_t` for numeric attributes, `igraph_strvector_t` for string attributes and `igraph_vector_bool_t` for Boolean attributes.

The record also stores default values for the attribute. The default values are used when the value vector of the record is resized with `igraph_attribute_record_resize()`. It is important that the record stores one default value only, corresponding to the type of the attribute record. The default value is cleared when the type of the record is changed.

### 2.2. `igraph_attribute_record_init` — Initializes an attribute record with a given name and type.

    igraph_error_t igraph_attribute_record_init(
        igraph_attribute_record_t *attr, const char *name, igraph_attribute_type_t type
    );

Arguments:

`attr`: | the attribute record to initialize
`name`: | name of the attribute
`type`: | type of the attribute

Returns:

`` | Error code: `IGRAPH_ENOMEM` if there is not enough memory.

Time complexity: O(1).

### 2.3. `igraph_attribute_record_init_copy` — Initializes an attribute record by copying another record.

    igraph_error_t igraph_attribute_record_init_copy(
        igraph_attribute_record_t *to, const igraph_attribute_record_t *from
    );

Copies made by this function are deep copies: a full copy of the value vector contained in the record is placed in the new record so they become independent of each other.

Arguments:

`to`: | the attribute record to initialize
`from`: | the attribute record to copy data from

Returns:

`` | Error code: `IGRAPH_ENOMEM` if there is not enough memory.

Time complexity: operating system dependent, usually O(n), where n is the size of the value vector in the attribute record.

### 2.4. `igraph_attribute_record_size` — Returns the size of the value vector in an attribute record.

    igraph_int_t igraph_attribute_record_size(const igraph_attribute_record_t *attr);

Arguments:

`attr`: | the attribute record to query

Returns:

`` | the number of elements in the value vector of the attribute record

### 2.5. `igraph_attribute_record_resize` — Resizes the value vector in an attribute record.

    igraph_error_t igraph_attribute_record_resize(
        igraph_attribute_record_t *attr, igraph_int_t new_size
    );

When the value vector is shorter than the desired length, it will be expanded with `IGRAPH_NAN` for numeric vectors, `false` for Boolean vectors and empty strings for string vectors.

Arguments:

`attr`: | the attribute record to update
`new_size`: | the new size of the value vector

Returns:

`` | Error code: `IGRAPH_ENOMEM` if there is not enough memory. `IGRAPH_EINVAL` if the type of the attribute record is not specified yet.

### 2.6. `igraph_attribute_record_set_name` — Sets the attribute name in an attribute record.

    igraph_error_t igraph_attribute_record_set_name(
        igraph_attribute_record_t *attr, const char *name
    );

Arguments:

`attr`: | the attribute record to update
`name`: | the new name

Returns:

`` | Error code: `IGRAPH_ENOMEM` if there is not enough memory.

### 2.7. `igraph_attribute_record_set_type` — Sets the type of an attribute record.

    igraph_error_t igraph_attribute_record_set_type(
        igraph_attribute_record_t *attr, igraph_attribute_type_t type
    );

When the new type being set is different from the old type, any values already stored in the attribute record will be destroyed and a new, empty attribute value vector will be allocated. When the new type is the same as the old type, this function is a no-op.

Arguments:

`attr`: | the attribute record to update
`type`: | the new type

Returns:

`` | Error code: `IGRAPH_ENOMEM` if there is not enough memory.

### 2.8. `igraph_attribute_record_set_default_numeric` — Sets the default value of the attribute to the given number.

    igraph_error_t igraph_attribute_record_set_default_numeric(
        igraph_attribute_record_t *attr, igraph_real_t value
    );

This function must be called for numeric attribute records only. When not specified, the default value of numeric attributes is NaN.

Arguments:

`attr`: | the attribute record to update
`value`: | the new default value

Returns:

`` | Error code: `IGRAPH_EINVAL` if the attribute record has a non-numeric type

### 2.9. `igraph_attribute_record_set_default_string` — Sets the default value of the attribute to the given string.

    igraph_error_t igraph_attribute_record_set_default_string(
        igraph_attribute_record_t *attr, const char* value
    );

This function must be called for string attribute records only. When not specified, the default value of string attributes is an empty string.

Arguments:

`attr`: | the attribute record to update
`value`: | the new default value. `NULL` means an empty string.

Returns:

`` | Error code: `IGRAPH_ENOMEM` if there is not enough memory `IGRAPH_EINVAL` if the attribute record is not of string type

### 2.10. `igraph_attribute_record_set_default_boolean` — Sets the default value of the attribute to the given logical value.

    igraph_error_t igraph_attribute_record_set_default_boolean(
        igraph_attribute_record_t *attr, igraph_bool_t value
    );

This function must be called for Boolean attribute records only. When not specified, the default value of Boolean attributes is `false`.

Arguments:

`attr`: | the attribute record to update
`value`: | the new default value

Returns:

`` | Error code: `IGRAPH_EINVAL` if the attribute record is not of Boolean type

### 2.11. `igraph_attribute_record_destroy` — Destroys an attribute record.

    void igraph_attribute_record_destroy(igraph_attribute_record_t *attr);

Arguments:

`attr`: | the previously initialized attribute record to destroy.

Time complexity: operating system dependent.

## 3. 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.

### 3.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)

### 3.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.

### 3.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.

### 3.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.

### 3.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.

### 3.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 10.1. File `examples/simple/igraph_attribute_combination.c`

    #include <igraph.h>

    int main(void) {
        igraph_t graph;
        igraph_attribute_combination_t comb;

        /* Initialize the library. */
        igraph_setup();

        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, /*remove_multiple=*/ true, /*remove_loops=*/ true, &comb);
        igraph_write_graph_graphml(&graph, stdout, /*prefixattr=*/ true);

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

        return 0;
    }

## 4. 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 10.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_int_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;

        /* Initialize the library. */
        igraph_setup();

        /* 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 10.3. File `examples/simple/cattributes2.c`

    #include <igraph.h>

    int main(void) {

        igraph_t g;
        igraph_vector_t y;
        igraph_warning_handler_t* oldwarnhandler;

        /* Initialize the library. */
        igraph_setup();

        /* 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 10.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, /*remove_multiple=*/ true, /*remove_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;

        /* Initialize the library. */
        igraph_setup();

        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 10.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, /*remove_multiple=*/ true, /*remove_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;

        /* Initialize the library. */
        igraph_setup();

        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;
    }

### 4.1. Query attributes

#### 4.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.

#### 4.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:

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

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

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

    igraph_real_t igraph_cattribute_VAN(const igraph_t *graph, const char *name,
                                        igraph_int_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.

#### 4.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.

#### 4.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'.

#### 4.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.

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

    igraph_bool_t igraph_cattribute_VAB(const igraph_t *graph, const char *name,
                                        igraph_int_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.

#### 4.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.

#### 4.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'.

#### 4.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.

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

    const char *igraph_cattribute_VAS(const igraph_t *graph, const char *name,
                                      igraph_int_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.

#### 4.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.

#### 4.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.)

#### 4.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.

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

    igraph_real_t igraph_cattribute_EAN(const igraph_t *graph, const char *name,
                                        igraph_int_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.

#### 4.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.

#### 4.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'.

#### 4.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.

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

    igraph_bool_t igraph_cattribute_EAB(const igraph_t *graph, const char *name,
                                        igraph_int_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.

#### 4.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.

#### 4.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'.

#### 4.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.

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

    const char *igraph_cattribute_EAS(const igraph_t *graph, const char *name,
                                      igraph_int_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.

#### 4.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.

#### 4.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.
`eids`: | 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.)

#### 4.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.

### 4.2. Set attributes

#### 4.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).

#### 4.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.

#### 4.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).

#### 4.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.

#### 4.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).

#### 4.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.

#### 4.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_int_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.

#### 4.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.

#### 4.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_int_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.

#### 4.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.

#### 4.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_int_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).

#### 4.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.

#### 4.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_int_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.

#### 4.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.

#### 4.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_int_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.

#### 4.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.

#### 4.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_int_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).

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

### 4.3. Remove attributes

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

#### 4.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.

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

    #define DELGAS(graph)

Calls `igraph_cattribute_remove_all()`.

Arguments:

`graph`: | The graph.

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

    #define DELVAS(graph)

Calls `igraph_cattribute_remove_all()`.

Arguments:

`graph`: | The graph.

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

    #define DELEAS(graph)

Calls `igraph_cattribute_remove_all()`.

Arguments:

`graph`: | The graph.

#### 4.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.

### 4.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.