# Chapter 12. Stochastic graph generators ("games")

"Games" are random graph generators, i.e. they generate a different graph every time they are called. igraph includes many such generators. Some implement stochastic graph construction processes inspired by real-world mechanics, such as preferential attachment, while others are designed to produce graphs with certain used properties (e.g. fixed number of edges, fixed degrees, etc.)

## 1. The Erdős-Rényi and related models

There are two classic random graph models referred to as the Erdős-Rényi random graph, or sometimes simply the random graph. Both fix the vertex count n, but while the G(n,m) model prescribes precisely m edges, the G(n,p) model connects all vertex pairs independently with probability p. While these models look superficially different, when n is large they behave in a similar manner. G(n,m) graphs have a density of exactly `p = m / m_max`, while G(n,p) graphs have `m = p m_max` edges on average, where `m_max` is the number of vertex pairs. Indeed, these two models turns out to be two sides of the same coin: both can be understood as maximum entropy models with a constraint on the number of edges. The G(n,m) is obtained from a sharp constraint, while G(n,p) from an average constraint (soft constraint).

The maximum entropy framework allows for rigorous generalizations of these models to various scenarios, of which igraph supports many, such as models defined over directed graphs, bipartite graphs, multigraphs, or even over edge-labelled graphs. Constraining edge counts between various subsets of vertices yields further families of related models, such as `igraph_sbm_game()` (given connection probabilities between categories) or `igraph_degree_sequence_game()` (given incident edge counts, i.e. degrees, for each vertex).

### 1.1. `igraph_erdos_renyi_game_gnm` — Generates a random (Erdős-Rényi) graph with a fixed number of edges.

    igraph_error_t igraph_erdos_renyi_game_gnm(
            igraph_t *graph,
            igraph_int_t n, igraph_int_t m,
            igraph_bool_t directed,
            igraph_edge_type_sw_t allowed_edge_types,
            igraph_bool_t edge_labeled);

In the `G(n, m)` Erdős-Rényi model, a graph with `n` vertices and `m` edges is generated uniformly at random.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`n`: | The number of vertices in the graph.
`m`: | The number of edges in the graph.
`directed`: | Whether to generate a directed graph.
`allowed_edge_types`: | Controls whether multi-edges and self-loops are generated. See `igraph_edge_type_sw_t`.
`edge_labeled`: | If true, the sampling is done uniformly from the set of ordered edge lists. See `igraph_iea_game()` for more information. Set this to `false` to select the classic Erdős-Rényi model. The constants `IGRAPH_EDGE_UNLABELED` and `IGRAPH_EDGE_LABELED` may be used instead of `false` and `true` for better readability.

Returns:

`` | Error code: `IGRAPH_EINVAL`: invalid `n` or `m` parameter. `IGRAPH_ENOMEM`: there is not enough memory for the operation.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges in the graph.

See also:

`` | `igraph_erdos_renyi_game_gnp()` to sample from the related `G(n, p)` model, which constrains the expected edge count; `igraph_iea_game()` to generate multigraph by assigning edges to vertex pairs uniformly and independently; `igraph_degree_sequence_game()` to constrain the degree sequence; `igraph_bipartite_game_gnm()` for the bipartite version of this model; `igraph_barabasi_game()` and `igraph_growing_random_game()` for other commonly used random graph models.

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

    #include <igraph.h>

    int main(void) {
        igraph_t graph;
        igraph_vector_int_t component_sizes;

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

        igraph_rng_seed(igraph_rng_default(), 42); /* make program deterministic */

        /* Sample a graph from the Erdős-Rényi G(n,m) model */

        igraph_erdos_renyi_game_gnm(
                &graph, /* n= */ 100, /* m= */ 100,
                IGRAPH_UNDIRECTED, IGRAPH_SIMPLE_SW, IGRAPH_EDGE_UNLABELED);

        /* Compute the fraction of vertices contained within the largest connected component */

        igraph_vector_int_init(&component_sizes, 0);
        igraph_connected_components(&graph, NULL, &component_sizes, NULL, IGRAPH_STRONG);

        printf(
            "Fraction of vertices in giant component: %g\n",
            ((double) igraph_vector_int_max(&component_sizes)) / igraph_vcount(&graph)
        );

        /* Clean up data structures when no longer needed */

        igraph_vector_int_destroy(&component_sizes);
        igraph_destroy(&graph);

        return 0;
    }

### 1.2. `igraph_erdos_renyi_game_gnp` — Generates a random (Erdős-Rényi) graph with fixed edge probabilities.

    igraph_error_t igraph_erdos_renyi_game_gnp(
            igraph_t *graph,
            igraph_int_t n, igraph_real_t p,
            igraph_bool_t directed,
            igraph_edge_type_sw_t allowed_edge_types,
            igraph_bool_t edge_labeled);

In the `G(n, p)` Erdős-Rényi model, also known as the Gilbert model, or Bernoulli random graph, a graph with `n` vertices is generated such that every possible edge is included in the graph independently with probability `p`. This is equivalent to a maximum entropy random graph model model with a constraint on the expected edge count. The maximum entropy view allows for extending the model to multigraphs, as discussed by Park and Newman (2004), section III.D. In this case, `p` is interpreted as the expected number of edges between any vertex pair.

Setting `p = 1/2` and `multiple = false` generates all graphs without multi-edges on `n` vertices with the same probability.

For both simple and multigraphs, the expected mean degree of the graph is approximately `p n`; set `p = k/n` when a mean degree of approximately `k` is desired. More precisely, the expected mean degree is `p(n-1)` in (undirected or directed) graphs without self-loops, `p(n+1)` in undirected graphs with self-loops, and `p n` in directed graphs with self-loops.

When generating multigraphs, the distribution of the edge multiplicities is geometric, i.e. the probability of finding `m` edges between two vertices is `q (1-q)^m`, where `q = 1 / (1+p)`.

This function uses the sequential geometric sampling technique described in Batagelj and Brandes (2005), with a modification to handle multigraphs.

References:

J. Park and M. E. J. Newman: "Statistical Mechanics of Networks". Phys. Rev. E 70, 066117 (2004). https://doi.org/10.1103/PhysRevE.70.066117

V. Batagelj and U. Brandes: "Efficient Generation of Large Random Networks". Phys. Rev. E 71, 036113 (2005). https://doi.org/10.1103/PhysRevE.71.036113

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`n`: | The number of vertices in the graph.
`p`: | The expected number of edges between any vertex pair. When multi-edges are disallowed, this is equivalent to the probability of having a connection between any two vertices.
`directed`: | Whether to generate a directed graph.
`allowed_edge_types`: | Controls whether multi-edges and self-loops are generated. See `igraph_edge_type_sw_t`.
`edge_labeled`: | If true, the model is defined over the set of ordered edge lists, i.e. over the set of edge-labeled graphs. Set it to `false` to select the classic Erdős-Rényi model. The constants `IGRAPH_EDGE_UNLABELED` and `IGRAPH_EDGE_LABELED` may be used instead of `false` and `true` for better readability.

Returns:

`` | Error code: `IGRAPH_EINVAL`: invalid `n` or `p` parameter. `IGRAPH_ENOMEM`: there is not enough memory for the operation.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges in the graph.

See also:

`` | `igraph_erdos_renyi_game_gnm()` to generate random graphs with a sharply fixed edge count; `igraph_chung_lu_game()` and `igraph_static_fitness_game()` to generate random graphs with a fixed expected degree sequence; `igraph_bipartite_game_gnm()` for the bipartite version of this model; `igraph_barabasi_game()` and `igraph_growing_random_game()` for other commonly used random graph models.

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

    #include <igraph.h>

    int main(void) {
        igraph_t graph;
        igraph_vector_int_t component_sizes;

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

        igraph_rng_seed(igraph_rng_default(), 42); /* make program deterministic */

        /* Sample a graph from the Erdős-Rényi G(n,p) model */

        igraph_erdos_renyi_game_gnp(
                &graph, /* n= */ 100, /* p= */ 0.01,
                IGRAPH_UNDIRECTED, IGRAPH_SIMPLE_SW, IGRAPH_EDGE_UNLABELED);

        /* Compute the fraction of vertices contained within the largest connected component */

        igraph_vector_int_init(&component_sizes, 0);
        igraph_connected_components(&graph, NULL, &component_sizes, NULL, IGRAPH_STRONG);

        printf(
            "Fraction of vertices in giant component: %g\n",
            ((double) igraph_vector_int_max(&component_sizes)) / igraph_vcount(&graph)
        );

        /* Clean up data structures when no longer needed */

        igraph_vector_int_destroy(&component_sizes);
        igraph_destroy(&graph);

        return 0;
    }

### 1.3. `igraph_iea_game` — Generates a random multigraph through independent edge assignment.

    igraph_error_t igraph_iea_game(
            igraph_t *graph,
            igraph_int_t n, igraph_int_t m,
            igraph_bool_t directed, igraph_bool_t loops);

### Warning

This function is experimental and its signature is not considered final yet. We reserve the right to change the function signature without changing the major version of igraph. Use it at your own risk.

This model generates random multigraphs on `n` vertices with `m` edges through independent edge assignment (IEA). Each of the `m` edges is assigned uniformly at random to an ordered vertex pair, independently of each other.

This model does not sample multigraphs uniformly. Undirected graphs are generated with probability proportional to

`(prod_(i<j) A_ij ! prod_i A_ii !!)^(-1)`,

where `A` denotes the adjacency matrix and `!!` denotes the double factorial. Here `A` is assumed to have twice the number of self-loops on its diagonal. The corresponding expression for directed graphs is

`(prod_(i,j) A_ij !)^(-1)`.

Thus the probability of all simple graphs (which only have 0s and 1s in the adjacency matrix) is the same, while that of non-simple ones depends on their edge and self-loop multiplicities.

An alternative way to think of this model is that it performs uniform sampling of edge-labeled graphs, i.e. graphs in which not only vertices, but also edges carry unique identities and are distinguishable.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`n`: | The number of vertices in the graph.
`m`: | The number of edges in the graph.
`directed`: | Whether to generate a directed graph.
`loops`: | Whether to generate self-loops.

Returns:

`` | Error code: `IGRAPH_EINVAL`: invalid `n` or `m` parameter. `IGRAPH_ENOMEM`: there is not enough memory for the operation.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges in the graph.

See also:

`` | `igraph_erdos_renyi_game_gnm()` to uniformly sample graphs with a given number of vertices and edges.

### 1.4. `igraph_sbm_game` — Sample from a stochastic block model.

    igraph_error_t igraph_sbm_game(
            igraph_t *graph,
            const igraph_matrix_t *pref_matrix,
            const igraph_vector_int_t *block_sizes,
            igraph_bool_t directed,
            igraph_edge_type_sw_t allowed_edge_types);

This function samples graphs from a stochastic block model, a generalization of the G(n,p) model where the connection probability p (or expected number of edges for multigraphs) is specified separately between and within a given group of vertices.

The order of the vertex IDs in the generated graph corresponds to the `block_sizes` argument.

Reference:

Faust, K., & Wasserman, S. (1992a). Blockmodels: Interpretation and evaluation. Social Networks, 14, 5-–61. https://doi.org/10.1016/0378-8733(92)90013-W

Arguments:

`graph`: | The output graph. This should be a pointer to an uninitialized graph.
`pref_matrix`: | The matrix giving the connection probabilities (or expected edge multiplicities for multigraphs) between groups. This is a k-by-k matrix, where k is the number of groups. The probability of creating an edge between vertices from groups i and j is given by element (i,j).
`block_sizes`: | An integer vector giving the number of vertices in each group.
`directed`: | Boolean, whether to create a directed graph. If this argument is `false`, then `pref_matrix` must be symmetric.
`allowed_edge_types`: | Controls whether multi-edges and self-loops are generated. See `igraph_edge_type_sw_t`.

Returns:

`` | Error code.

Time complexity: O(|V|+|E|+k^2), where |V| is the number of vertices, |E| is the number of edges, and k is the number of groups.

See also:

`` | `igraph_erdos_renyi_game_gnp()` for a simple Bernoulli graph.

### 1.5. `igraph_hsbm_game` — Hierarchical stochastic block model.

    igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_int_t n,
                         igraph_int_t m, const igraph_vector_t *rho,
                         const igraph_matrix_t *C, igraph_real_t p);

The function generates a random graph according to the hierarchical stochastic block model.

Arguments:

`graph`: | The generated graph is stored here.
`n`: | The number of vertices in the graph.
`m`: | The number of vertices per block. n/m must be integer.
`rho`: | The fraction of vertices per cluster, within a block. Must sum up to 1, and rho * m must be integer for all elements of rho.
`C`: | A square, symmetric numeric matrix, the Bernoulli rates for the clusters within a block. Its size must mach the size of the `rho` vector.
`p`: | The Bernoulli rate of connections between vertices in different blocks.

Returns:

`` | Error code.

See also:

`` | `igraph_sbm_game()` for the classic stochastic block model, `igraph_hsbm_list_game()` for a more general version.

### 1.6. `igraph_hsbm_list_game` — Hierarchical stochastic block model, more general version.

    igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_int_t n,
                              const igraph_vector_int_t *mlist,
                              const igraph_vector_list_t *rholist,
                              const igraph_matrix_list_t *Clist,
                              igraph_real_t p);

The function generates a random graph according to the hierarchical stochastic block model.

Arguments:

`graph`: | The generated graph is stored here.
`n`: | The number of vertices in the graph.
`mlist`: | An integer vector of block sizes.
`rholist`: | A list of rho vectors (`igraph_vector_t` objects), one for each block.
`Clist`: | A list of square matrices (`igraph_matrix_t` objects), one for each block, specifying the Bernoulli rates of connections within the block.
`p`: | The Bernoulli rate of connections between vertices in different blocks.

Returns:

`` | Error code.

See also:

`` | `igraph_sbm_game()` for the classic stochastic block model, `igraph_hsbm_game()` for a simpler general version.

### 1.7. `igraph_preference_game` — Generates a graph with vertex types and connection preferences.

    igraph_error_t igraph_preference_game(igraph_t *graph, igraph_int_t nodes,
                               igraph_int_t types,
                               const igraph_vector_t *type_dist,
                               igraph_bool_t fixed_sizes,
                               const igraph_matrix_t *pref_matrix,
                               igraph_vector_int_t *node_type_vec,
                               igraph_bool_t directed,
                               igraph_bool_t loops);

This is practically the nongrowing variant of `igraph_establishment_game()`. A given number of vertices are generated. Every vertex is assigned to a vertex type according to the given type probabilities. Finally, every vertex pair is evaluated and an edge is created between them with a probability depending on the types of the vertices involved.

In other words, this function generates a graph according to a block-model. Vertices are divided into groups (or blocks), and the probability the two vertices are connected depends on their groups only.

Arguments:

`graph`: | Pointer to an uninitialized graph.
`nodes`: | The number of vertices in the graph.
`types`: | The number of vertex types.
`type_dist`: | Vector giving the distribution of vertex types. If `NULL`, all vertex types will have equal probability. See also the `fixed_sizes` argument.
`fixed_sizes`: | Boolean. If true, then the number of vertices with a given vertex type is fixed and the `type_dist` argument gives these numbers for each vertex type. If true, and `type_dist` is `NULL`, then the function tries to make vertex groups of the same size. If this is not possible, then some groups will have an extra vertex.
`pref_matrix`: | Matrix giving the connection probabilities for different vertex types. This should be symmetric if the requested graph is undirected.
`node_type_vec`: | A vector where the individual generated vertex types will be stored. If `NULL`, the vertex types won't be saved.
`directed`: | Whether to generate a directed graph. If undirected graphs are requested, only the lower left triangle of the preference matrix is considered.
`loops`: | Whether loop edges are allowed.

Returns:

`` | Error code.

Added in version 0.3.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges in the graph.

See also:

`` | `igraph_asymmetric_preference_game()`, `igraph_establishment_game()`, `igraph_callaway_traits_game()`

### 1.8. `igraph_asymmetric_preference_game` — Generates a graph with asymmetric vertex types and connection preferences.

    igraph_error_t igraph_asymmetric_preference_game(igraph_t *graph, igraph_int_t nodes,
                                          igraph_int_t no_out_types,
                                          igraph_int_t no_in_types,
                                          const igraph_matrix_t *type_dist_matrix,
                                          const igraph_matrix_t *pref_matrix,
                                          igraph_vector_int_t *node_type_out_vec,
                                          igraph_vector_int_t *node_type_in_vec,
                                          igraph_bool_t loops);

This is the asymmetric variant of `igraph_preference_game()`. A given number of vertices are generated. Every vertex is assigned to an "outgoing" and an "incoming " vertex type according to the given joint type probabilities. Finally, every vertex pair is evaluated and a directed edge is created between them with a probability depending on the "outgoing" type of the source vertex and the "incoming" type of the target vertex.

Arguments:

`graph`: | Pointer to an uninitialized graph.
`nodes`: | The number of vertices in the graph.
`no_out_types`: | The number of vertex out-types.
`no_in_types`: | The number of vertex in-types.
`type_dist_matrix`: | Matrix of size `out_types * in_types`, giving the joint distribution of vertex types. If `NULL`, incoming and outgoing vertex types are independent and uniformly distributed.
`pref_matrix`: | Matrix of size `out_types * in_types`, giving the connection probabilities for different vertex types.
`node_type_out_vec`: | A vector where the individual generated "outgoing" vertex types will be stored. If `NULL`, the vertex types won't be saved.
`node_type_in_vec`: | A vector where the individual generated "incoming" vertex types will be stored. If `NULL`, the vertex types won't be saved.
`loops`: | Whether loop edges are allowed.

Returns:

`` | Error code.

Added in version 0.3.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges in the graph.

See also:

`` | `igraph_preference_game()`

### 1.9. `igraph_correlated_game` — Generates a random graph correlated to an existing graph.

    igraph_error_t igraph_correlated_game(igraph_t *new_graph, const igraph_t *old_graph,
                               igraph_real_t corr, igraph_real_t p,
                               const igraph_vector_int_t *permutation);

Sample a new graph by perturbing the adjacency matrix of a given simple graph and shuffling its vertices.

Arguments:

`new_graph`: | The new graph to initialize based on an existing graph.
`old_graph`: | The original graph, which must be a simple graph.
`corr`: | A value in the unit interval [0,1], the target Pearson correlation between the adjacency matrices of the original and the generated graph (the adjacency matrix being used as a vector).
`p`: | The probability of an edge between two vertices. It must in the open (0,1) interval. Typically, the density of `old_graph`.
`permutation`: | A permutation to apply to the vertices of the generated graph. The i-th element of the vector specifies the index of the vertex in the original graph that will become vertex i in the new graph. It can also be a null pointer, in which case the vertices will not be permuted.

Returns:

`` | Error code

See also:

`` | `igraph_correlated_pair_game()` for generating a pair of correlated random graphs in one go.

### 1.10. `igraph_correlated_pair_game` — Generates pairs of correlated random graphs.

    igraph_error_t igraph_correlated_pair_game(igraph_t *graph1, igraph_t *graph2,
                                    igraph_int_t n, igraph_real_t corr, igraph_real_t p,
                                    igraph_bool_t directed,
                                    const igraph_vector_int_t *permutation);

Sample two random graphs, with given correlation.

Arguments:

`graph1`: | The first graph will be stored here.
`graph2`: | The second graph will be stored here.
`n`: | The number of vertices in both graphs.
`corr`: | A scalar in the unit interval, the target Pearson correlation between the adjacency matrices of the original the generated graph (the adjacency matrix being used as a vector).
`p`: | A numeric scalar, the probability of an edge between two vertices, it must in the open (0,1) interval.
`directed`: | Whether to generate directed graphs.
`permutation`: | A permutation to apply to the vertices of the generated graph. The i-th element of the vector specifies the index of the vertex in the first graph that will become vertex i in the second graph. It can also be a null pointer, in which case the vertices will not be permuted.

Returns:

`` | Error code

See also:

`` | `igraph_correlated_game()` for generating a correlated pair to a given graph.

## 2. Preferential attachment and related models

Preferential attachment models are growing random graphs where vertices are added iteratively, and connected to previously added vertices based on dynamically changing vertex properties, such as degree or time since the vertex was added.

### 2.1. `igraph_barabasi_game` — Generates a graph based on the Barabási-Albert model.

    igraph_error_t igraph_barabasi_game(igraph_t *graph, igraph_int_t n,
                             igraph_real_t power,
                             igraph_int_t m,
                             const igraph_vector_int_t *outseq,
                             igraph_bool_t outpref,
                             igraph_real_t A,
                             igraph_bool_t directed,
                             igraph_barabasi_algorithm_t algo,
                             const igraph_t *start_from);

This function implements several variants of the preferential attachment process, including linear and non-linear varieties of the Barabási-Albert and Price models. The graph construction starts with a single vertex, or an existing graph given by the `start_from` parameter. Then new vertices are added one at a time. Each new vertex connects to `m` existing vertices, choosing them with probabilities proportional to

`d^power + A`,

where `d` is the in- or total degree of the existing vertex (controlled by the `outpref` argument), while `power` and `A` are given by parameters. The constant attractiveness `A` is used to ensure that vertices with zero in-degree can also be connected to with non-zero probability.

Barabási, A.-L. and Albert R. 1999. Emergence of scaling in random networks, Science, 286 509--512. https://doi.org/10.1126/science.286.5439.509

de Solla Price, D. J. 1965. Networks of Scientific Papers, Science, 149 510--515. https://doi.org/10.1126/science.149.3683.510

Arguments:

`graph`: | An uninitialized graph object.
`n`: | The number of vertices in the graph.
`power`: | Power of the preferential attachment. In the classic preferential attachment model `power=1`. Other values allow for sampling from a non-linear preferential attachment model. Negative values are only allowed when no zero-degree vertices are present during the construction process, i.e. when the starting graph has no isolated vertices and `outpref` is set to `true`.
`m`: | The number of outgoing edges generated for each vertex. Only used when `outseq` is `NULL`.
`outseq`: | Gives the (out-)degrees of the vertices. If this is constant, this can be a `NULL` pointer. In this case `m` contains the constant out-degree. The very first vertex has by definition no outgoing edges, so the first number in this vector is ignored.
`outpref`: | Boolean, if true not only the in- but also the out-degree of a vertex increases its citation probability. I.e., the citation probability is determined by the total degree of the vertices. Ignored and assumed to be true if the graph being generated is undirected.
`A`: | The constant attractiveness of vertices. When `outpref` is set to `false`, it should be positive to ensure that zero in-degree vertices can be connected to as well.
`directed`: | Boolean, whether to generate a directed graph. When set to `false`, outpref is assumed to be `true`.
`algo`: | The algorithm to use to generate the network. Possible values:
`IGRAPH_BARABASI_BAG` | This is the algorithm that was previously (before version 0.6) solely implemented in igraph. It works by putting the IDs of the vertices into a bag (multiset, really), exactly as many times as their (in-)degree, plus once more. Then the required number of cited vertices are drawn from the bag, with replacement. This method might generate multiple edges. It only works if power=1 and A=1.
`IGRAPH_BARABASI_PSUMTREE` | This algorithm uses a partial prefix-sum tree to generate the graph. It does not generate multiple edges and works for any power and A values.
`IGRAPH_BARABASI_PSUMTREE_MULTIPLE` | This algorithm also uses a partial prefix-sum tree to generate the graph. The difference is, that now multiple edges are allowed. This method was implemented under the name `igraph_nonlinear_barabasi_game` before version 0.6.
`start_from`: | Either a `NULL` pointer, or a graph. In the former case, the starting configuration is a clique of size `m`. In the latter case, the graph is a starting configuration. The graph must be non-empty, i.e. it must have at least one vertex. If a graph is supplied here and the `outseq` argument is also given, then `outseq` should only contain information on the vertices that are not in the `start_from` graph.

Returns:

`` | Error code: `IGRAPH_EINVAL`: invalid `n`, `m`, `A` or `outseq` parameter.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges.

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

    #include <igraph.h>

    int main(void) {

        igraph_t g;
        igraph_vector_int_t v;
        igraph_vector_int_t v2, v3;

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

        igraph_barabasi_game(&g, 10, /*power=*/ 1, 2, 0, 0, /*A=*/ 1, 1,
                             IGRAPH_BARABASI_BAG, /*start_from=*/ 0);
        if (igraph_ecount(&g) != 18) {
            return 1;
        }
        if (igraph_vcount(&g) != 10) {
            return 2;
        }
        if (!igraph_is_directed(&g)) {
            return 3;
        }

        igraph_vector_int_init(&v, 0);
        igraph_get_edgelist(&g, &v, 0);
        for (igraph_int_t i = 0; i < igraph_ecount(&g); i++) {
            if (VECTOR(v)[2 * i] <= VECTOR(v)[2 * i + 1]) {
                return 4;
            }
        }
        igraph_vector_int_destroy(&v);
        igraph_destroy(&g);

        /* out-degree sequence */
        igraph_vector_int_init_int(&v3, 10, 0, 1, 3, 3, 4, 5, 6, 7, 8, 9);

        igraph_barabasi_game(&g, 10, /*power=*/ 1, 0, &v3, 0, /*A=*/ 1, 1,
                             IGRAPH_BARABASI_BAG, /*start_from=*/ 0);
        if (igraph_ecount(&g) != igraph_vector_int_sum(&v3)) {
            return 5;
        }
        igraph_vector_int_init(&v2, 0);
        igraph_degree(&g, &v2, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS);
        for (igraph_int_t i = 0; i < igraph_vcount(&g); i++) {
            if (VECTOR(v3)[i] != VECTOR(v2)[i]) {
                igraph_vector_int_print(&v3);
                printf("\n");
                igraph_vector_int_print(&v2);
                return 6;
            }
        }
        igraph_vector_int_destroy(&v3);
        igraph_vector_int_destroy(&v2);
        igraph_destroy(&g);

        /* outpref, we cannot really test this quantitatively,
           would need to set random seed */
        igraph_barabasi_game(&g, 10, /*power=*/ 1, 2, 0, 1, /*A=*/ 1, 1,
                             IGRAPH_BARABASI_BAG, /*start_from=*/ 0);
        igraph_vector_int_init(&v, 0);
        igraph_get_edgelist(&g, &v, 0);
        for (igraph_int_t i = 0; i < igraph_ecount(&g); i++) {
            if (VECTOR(v)[2 * i] <= VECTOR(v)[2 * i + 1]) {
                return 7;
            }
        }
        if (!igraph_is_directed(&g)) {
            return 8;
        }
        igraph_vector_int_destroy(&v);
        igraph_destroy(&g);

        return 0;
    }

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

    #include <igraph.h>
    #include <stdio.h>

    int main(void) {
        igraph_t g;
        igraph_bool_t simple;

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

        igraph_barabasi_game(/* graph=    */ &g,
                                             /* n=        */ 100,
                                             /* power=    */ 1.0,
                                             /* m=        */ 2,
                                             /* outseq=   */ 0,
                                             /* outpref=  */ 0,
                                             /* A=        */ 1.0,
                                             /* directed= */ IGRAPH_DIRECTED,
                                             /* algo=     */ IGRAPH_BARABASI_PSUMTREE,
                                             /* start_from= */ 0);

        if (igraph_ecount(&g) != 197) {
            return 1;
        }
        if (igraph_vcount(&g) != 100) {
            return 2;
        }
        igraph_is_simple(&g, &simple, IGRAPH_DIRECTED);
        if (!simple) {
            return 3;
        }

        igraph_destroy(&g);

        /* ============================== */

        igraph_barabasi_game(/* graph=    */ &g,
                                             /* n=        */ 100,
                                             /* power=    */ 1.0,
                                             /* m=        */ 2,
                                             /* outseq=   */ 0,
                                             /* outpref=  */ 0,
                                             /* A=        */ 1.0,
                                             /* directed= */ IGRAPH_DIRECTED,
                                             /* algo=     */ IGRAPH_BARABASI_PSUMTREE_MULTIPLE,
                                             /* start_from= */ 0);

        if (igraph_ecount(&g) != 198) {
            return 4;
        }
        if (igraph_vcount(&g) != 100) {
            return 5;
        }
        igraph_is_simple(&g, &simple, IGRAPH_DIRECTED);
        if (simple) {
            return 6;
        }

        igraph_destroy(&g);

        /* ============================== */

        igraph_barabasi_game(/* graph=    */ &g,
                                             /* n=        */ 100,
                                             /* power=    */ 1.0,
                                             /* m=        */ 2,
                                             /* outseq=   */ 0,
                                             /* outpref=  */ 0,
                                             /* A=        */ 1.0,
                                             /* directed= */ IGRAPH_DIRECTED,
                                             /* algo=     */ IGRAPH_BARABASI_BAG,
                                             /* start_from= */ 0);

        if (igraph_ecount(&g) != 198) {
            return 7;
        }
        if (igraph_vcount(&g) != 100) {
            return 8;
        }
        igraph_is_simple(&g, &simple, IGRAPH_DIRECTED);
        if (simple) {
            return 9;
        }

        igraph_destroy(&g);

        return 0;
    }

### 2.2. `igraph_barabasi_aging_game` — Preferential attachment with aging of vertices.

    igraph_error_t igraph_barabasi_aging_game(igraph_t *graph,
                                   igraph_int_t nodes,
                                   igraph_int_t m,
                                   const igraph_vector_int_t *outseq,
                                   igraph_bool_t outpref,
                                   igraph_real_t pa_exp,
                                   igraph_real_t aging_exp,
                                   igraph_int_t aging_bins,
                                   igraph_real_t zero_deg_appeal,
                                   igraph_real_t zero_age_appeal,
                                   igraph_real_t deg_coef,
                                   igraph_real_t age_coef,
                                   igraph_bool_t directed);

This game starts with one vertex (if `nodes` > 0). In each step a new node is added, and it is connected to `m` existing nodes. Existing nodes to connect to are chosen with probability dependent on their (in-)degree (`k`) and age (`l`). The degree-dependent part is `deg_coef * k^pa_exp + zero_deg_appeal`, while the age-dependent part is `age_coef * l^aging_exp + zero_age_appeal`, which are multiplied to obtain the final weight.

The age `l` is based on the number of vertices in the network and the `aging_bins` argument: the age of a node is incremented by 1 after each `floor(nodes / aging_bins) + 1` time steps.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`nodes`: | The number of vertices in the graph.
`m`: | The number of edges to add in each time step. Ignored if `outseq` is a non-zero length vector.
`outseq`: | The number of edges to add in each time step. If it is `NULL` or a zero-length vector then it is ignored and the `m` argument is used instead.
`outpref`: | Boolean constant, whether the edges initiated by a vertex contribute to the probability to gain a new edge.
`pa_exp`: | The exponent of the preferential attachment, a small positive number usually, the value 1 yields the classic linear preferential attachment.
`aging_exp`: | The exponent of the aging, this is a negative number usually.
`aging_bins`: | Integer constant, the number of age bins to use.
`zero_deg_appeal`: | The degree dependent part of the attractiveness of the zero degree vertices.
`zero_age_appeal`: | The age dependent part of the attractiveness of the vertices of age zero. This parameter is usually zero.
`deg_coef`: | The coefficient for the degree.
`age_coef`: | The coefficient for the age.
`directed`: | Boolean constant, whether to generate a directed graph.

Returns:

`` | Error code.

Time complexity: O((|V|+|V|/aging_bins)*log(|V|)+|E|). |V| is the number of vertices, |E| the number of edges.

### 2.3. `igraph_recent_degree_game` — Stochastic graph generator based on the number of incident edges a node has gained recently.

    igraph_error_t igraph_recent_degree_game(igraph_t *graph, igraph_int_t nodes,
                                  igraph_real_t power,
                                  igraph_int_t time_window,
                                  igraph_int_t m,
                                  const igraph_vector_int_t *outseq,
                                  igraph_bool_t outpref,
                                  igraph_real_t zero_appeal,
                                  igraph_bool_t directed);

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`nodes`: | The number of vertices in the graph, this is the same as the number of time steps.
`power`: | The exponent, the probability that a node gains a new edge is proportional to the number of edges it has gained recently (in the last `window` time steps) to `power`.
`time_window`: | Integer constant, the size of the time window to use to count the number of recent edges.
`m`: | Integer constant, the number of edges to add per time step if the `outseq` parameter is a null pointer or a zero-length vector.
`outseq`: | The number of edges to add in each time step. This argument is ignored if it is a null pointer or a zero length vector. In this case the constant `m` parameter is used.
`outpref`: | Boolean constant, if true the edges originated by a vertex also count as recent incident edges. For most applications it is reasonable to set it to false.
`zero_appeal`: | Constant giving the attractiveness of the vertices which haven't gained any edge recently.
`directed`: | Boolean constant, whether to generate a directed graph.

Returns:

`` | Error code.

Time complexity: O(|V|*log(|V|)+|E|), |V| is the number of vertices, |E| is the number of edges in the graph.

### 2.4. `igraph_recent_degree_aging_game` — Preferential attachment based on the number of edges gained recently, with aging of vertices.

    igraph_error_t igraph_recent_degree_aging_game(igraph_t *graph,
                                        igraph_int_t nodes,
                                        igraph_int_t m,
                                        const igraph_vector_int_t *outseq,
                                        igraph_bool_t outpref,
                                        igraph_real_t pa_exp,
                                        igraph_real_t aging_exp,
                                        igraph_int_t aging_bins,
                                        igraph_int_t time_window,
                                        igraph_real_t zero_appeal,
                                        igraph_bool_t directed);

This game is very similar to `igraph_barabasi_aging_game()`, except that instead of the total number of incident edges the number of edges gained in the last `time_window` time steps are counted.

The degree dependent part of the attractiveness is given by k to the power of `pa_exp` plus `zero_appeal`; the age dependent part is l to the power to `aging_exp`. k is the number of edges gained in the last `time_window` time steps, l is the age of the vertex.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`nodes`: | The number of vertices in the graph.
`m`: | The number of edges to add in each time step. If the `outseq` argument is not a null vector or a zero-length vector then it is ignored.
`outseq`: | Vector giving the number of edges to add in each time step. If it is a null pointer or a zero-length vector then it is ignored and the `m` argument is used.
`outpref`: | Boolean constant, if true the edges initiated by a vertex are also counted. Normally it is false.
`pa_exp`: | The exponent for the preferential attachment.
`aging_exp`: | The exponent for the aging, normally it is negative: old vertices gain edges with less probability.
`aging_bins`: | Integer constant, the number of age bins to use.
`time_window`: | The time window to use to count the number of incident edges for the vertices.
`zero_appeal`: | The degree dependent part of the attractiveness for zero degree vertices.
`directed`: | Boolean constant, whether to create a directed graph.

Returns:

`` | Error code.

Time complexity: O((|V|+|V|/aging_bins)*log(|V|)+|E|). |V| is the number of vertices, |E| the number of edges.

### 2.5. `igraph_lastcit_game` — Simulates a citation network, based on time passed since the last citation.

    igraph_error_t igraph_lastcit_game(igraph_t *graph,
                            igraph_int_t nodes, igraph_int_t edges_per_node,
                            igraph_int_t agebins,
                            const igraph_vector_t *preference,
                            igraph_bool_t directed);

This is a quite special stochastic graph generator, it models an evolving graph. In each time step a single vertex is added to the network and it cites a number of other vertices (as specified by the `edges_per_step` argument). The cited vertices are selected based on the last time they were cited. Time is measured by the addition of vertices and it is binned into `agebins` bins. So if the current time step is `t` and the last citation to a given `i` vertex was made in time step `t0`, then `(t-t0) / binwidth` is calculated where binwidth is `nodes/agebins + 1`, in the last expression '/' denotes integer division, so the fraction part is omitted.

The `preference` argument specifies the preferences for the citation lags, i.e. its first elements contains the attractivity of the very recently cited vertices, etc. The last element is special, it contains the attractivity of the vertices which were never cited. This element should be bigger than zero.

Note that this function generates networks with multiple edges if `edges_per_step` is bigger than one, call `igraph_simplify()` on the result to get rid of these edges.

Arguments:

`graph`: | Pointer to an uninitialized graph object, the result will be stored here.
`nodes`: | The number of vertices in the network.
`edges_per_node`: | The number of edges to add in each time step.
`agebins`: | The number of age bins to use.
`preference`: | Pointer to an initialized vector of length `agebins + 1`. This contains the "attractivity" of the various age bins, the last element is the attractivity of the vertices which were never cited, and it should be greater than zero. It is a good idea to have all positive values in this vector. Preferences cannot be negative.
`directed`: | Boolean constant, whether to create directed networks.

Returns:

`` | Error code.

See also:

`` | `igraph_barabasi_aging_game()`.

Time complexity: O(|V|*a+|E|*log|V|), |V| is the number of vertices, |E| is the total number of edges, a is the `agebins` parameter.

## 3. Growing random graph models

In growing random graphs, vertices are added iteratively, and connected based on various rules. Preferential attachment models are documented in their own section.

### 3.1. `igraph_growing_random_game` — Generates a growing random graph.

    igraph_error_t igraph_growing_random_game(igraph_t *graph, igraph_int_t n,
                                   igraph_int_t m, igraph_bool_t directed,
                                   igraph_bool_t citation);

This function simulates a growing random graph. We start out with one vertex. In each step a new vertex is added and a number of new edges are also added. These graphs are known to be different from standard (not growing) random graphs.

Arguments:

`graph`: | Uninitialized graph object.
`n`: | The number of vertices in the graph.
`m`: | The number of edges to add in a time step (i.e. after adding a vertex).
`directed`: | Boolean, whether to generate a directed graph.
`citation`: | Boolean, if `true`, the edges always originate from the most recently added vertex and are connected to a previous vertex.

Returns:

`` | Error code: `IGRAPH_EINVAL`: invalid `n` or `m` parameter.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges.

### 3.2. `igraph_callaway_traits_game` — Simulates a growing network with vertex types.

    igraph_error_t igraph_callaway_traits_game(igraph_t *graph, igraph_int_t nodes,
                                    igraph_int_t types, igraph_int_t edges_per_step,
                                    const igraph_vector_t *type_dist,
                                    const igraph_matrix_t *pref_matrix,
                                    igraph_bool_t directed,
                                    igraph_vector_int_t *node_type_vec);

The different types of vertices prefer to connect other types of vertices with a given probability.

The simulation goes like this: in each discrete time step a new vertex is added to the graph. The type of this vertex is generated based on `type_dist`. Then two vertices are selected uniformly randomly from the graph. The probability that they will be connected depends on the types of these vertices and is taken from `pref_matrix`. Then another two vertices are selected and this is repeated `edges_per_step` times in each time step.

References:

D. S. Callaway, J. E. Hopcroft, J. M. Kleinberg, M. E. J. Newman, and S. H. Strogatz, Are randomly grown graphs really random? Phys. Rev. E 64, 041902 (2001). https://doi.org/10.1103/PhysRevE.64.041902

Arguments:

`graph`: | Pointer to an uninitialized graph.
`nodes`: | The number of nodes in the graph.
`types`: | Number of node types.
`edges_per_step`: | The number of connections tried in each time step.
`type_dist`: | Vector giving the distribution of the vertex types. If `NULL`, the distribution is assumed to be uniform.
`pref_matrix`: | Matrix giving the connection probabilities for the vertex types.
`directed`: | Whether to generate a directed graph.
`node_type_vec`: | An initialized vector or `NULL`. If not `NULL`, the type of each node will be stored here.

Returns:

`` | Error code.

Added in version 0.2.

Time complexity: O(|V|*k*log(|V|)), |V| is the number of vertices, k is `edges_per_step`.

### 3.3. `igraph_establishment_game` — Generates a graph with a simple growing model with vertex types.

    igraph_error_t igraph_establishment_game(igraph_t *graph, igraph_int_t nodes,
                                  igraph_int_t types, igraph_int_t k,
                                  const igraph_vector_t *type_dist,
                                  const igraph_matrix_t *pref_matrix,
                                  igraph_bool_t directed,
                                  igraph_vector_int_t *node_type_vec);

The simulation goes like this: a single vertex is added at each time step. This new vertex tries to connect to `k` vertices in the graph. The probability that such a connection is realized depends on the types of the vertices involved.

Arguments:

`graph`: | Pointer to an uninitialized graph.
`nodes`: | The number of vertices in the graph.
`types`: | The number of vertex types.
`k`: | The number of connections tried in each time step.
`type_dist`: | Vector giving the distribution of vertex types. If `NULL`, the distribution is assumed to be uniform.
`pref_matrix`: | Matrix giving the connection probabilities for different vertex types.
`directed`: | Whether to generate a directed graph.
`node_type_vec`: | An initialized vector or `NULL`. If not `NULL`, the type of each node will be stored here.

Returns:

`` | Error code.

Added in version 0.2.

Time complexity: O(|V|*k*log(|V|)), |V| is the number of vertices and k is the `k` parameter.

### 3.4. `igraph_cited_type_game` — Simulates a citation based on vertex types.

    igraph_error_t igraph_cited_type_game(igraph_t *graph, igraph_int_t nodes,
                               const igraph_vector_int_t *types,
                               const igraph_vector_t *pref,
                               igraph_int_t edges_per_step,
                               igraph_bool_t directed);

Function to create a network based on some vertex categories. This function creates a citation network: in each step a single vertex and `edges_per_step` citing edges are added. Nodes with different categories may have different probabilities to get cited, as given by the `pref` vector.

Note that this function might generate networks with multiple edges if `edges_per_step` is greater than one. You might want to call `igraph_simplify()` on the result to remove multiple edges.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`nodes`: | The number of vertices in the network.
`types`: | Numeric vector giving the categories of the vertices, so it should contain `nodes` non-negative integer numbers. Types are numbered from zero.
`pref`: | The attractivity of the different vertex categories in a vector. Its length should be the maximum element in `types` plus one (types are numbered from zero).
`edges_per_step`: | Integer constant, the number of edges to add in each time step.
`directed`: | Boolean constant, whether to create a directed network.

Returns:

`` | Error code.

See also:

`` | `igraph_citing_cited_type_game()` for a bit more general game.

Time complexity: O((|V|+|E|)log|V|), |V| and |E| are number of vertices and edges, respectively.

### 3.5. `igraph_citing_cited_type_game` — Simulates a citation network based on vertex types.

    igraph_error_t igraph_citing_cited_type_game(igraph_t *graph, igraph_int_t nodes,
                                      const igraph_vector_int_t *types,
                                      const igraph_matrix_t *pref,
                                      igraph_int_t edges_per_step,
                                      igraph_bool_t directed);

This game is similar to `igraph_cited_type_game()` but here the category of the citing vertex is also considered.

An evolving citation network is modeled here, a single vertex and its `edges_per_step` citation are added in each time step. The odds the a given vertex is cited by the new vertex depends on the category of both the citing and the cited vertex and is given in the `pref` matrix. The categories of the citing vertex correspond to the rows, the categories of the cited vertex to the columns of this matrix. I.e. the element in row `i` and column `j` gives the probability that a `j` vertex is cited, if the category of the citing vertex is `i`.

Note that this function might generate networks with multiple edges if `edges_per_step` is greater than one. You might want to call `igraph_simplify()` on the result to remove multiple edges.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`nodes`: | The number of vertices in the network.
`types`: | A numeric vector of length `nodes`, containing the categories of the vertices. The categories are numbered from zero.
`pref`: | The preference matrix, a square matrix is required, both the number of rows and columns should be the maximum element in `types` plus one (types are numbered from zero).
`edges_per_step`: | Integer constant, the number of edges to add in each time step.
`directed`: | Boolean constant, whether to create a directed network.

Returns:

`` | Error code.

Time complexity: O((|V|+|E|)log|V|), |V| and |E| are number of vertices and edges, respectively.

### 3.6. `igraph_forest_fire_game` — Generates a network according to the “forest fire game”.

    igraph_error_t igraph_forest_fire_game(igraph_t *graph, igraph_int_t nodes,
                                igraph_real_t fw_prob, igraph_real_t bw_factor,
                                igraph_int_t pambs, igraph_bool_t directed);

The forest fire model intends to reproduce the following network characteristics, observed in real networks:

- Heavy-tailed in- and out-degree distributions.

- Community structure.

- Densification power-law. The network is densifying in time, according to a power-law rule.

- Shrinking diameter. The diameter of the network decreases in time.

The network is generated in the following way. One vertex is added at a time. This vertex connects to (cites) `ambs` vertices already present in the network, chosen uniformly random. Now, for each cited vertex `v` we do the following procedure:

1. We generate two random numbers, `x` and `y`, that are geometrically distributed with means `p/(1-p)` and `rp(1-rp)`. (`p` is `fw_prob`, `r` is `bw_factor`.) The new vertex cites `x` outgoing neighbors and `y` incoming neighbors of `v`, from those which are not yet cited by the new vertex. If there are less than `x` or `y` such vertices available then we cite all of them.

2. The same procedure is applied to all the newly cited vertices.

See also: Jure Leskovec, Jon Kleinberg and Christos Faloutsos. Graphs over time: densification laws, shrinking diameters and possible explanations. KDD '05: Proceeding of the eleventh ACM SIGKDD international conference on Knowledge discovery in data mining , 177--187, 2005.

Note however, that the version of the model in the published paper is incorrect in the sense that it cannot generate the kind of graphs the authors claim. A corrected version is available from https://www.cs.cmu.edu/~jure/pubs/powergrowth-tkdd.pdf, our implementation is based on this.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`nodes`: | The number of vertices in the graph.
`fw_prob`: | The forward burning probability.
`bw_factor`: | The backward burning ratio. The backward burning probability is calculated as `bw_factor * fw_prob`.
`pambs`: | The number of ambassador vertices.
`directed`: | Whether to create a directed graph.

Returns:

`` | Error code.

Time complexity: TODO.

## 4. Degree-constrained models

Random graph models with hard or soft degree constraints.

### 4.1. `igraph_degree_sequence_game` — Generates a random graph with a given degree sequence.

    igraph_error_t igraph_degree_sequence_game(
            igraph_t *graph,
            const igraph_vector_int_t *out_degrees,
            const igraph_vector_int_t *in_degrees,
            igraph_degseq_t method);

This function generates random graphs with a prescribed degree sequence. Several sampling methods are available, which respect different constraints (simple graph or multigraphs, connected graphs, etc.), and provide different tradeoffs between performance and unbiased sampling. See Section 2.1 of Horvát and Modes (2021) for an overview of sampling techniques for graphs with fixed degrees.

References:

Fabien Viger, and Matthieu Latapy: Efficient and Simple Generation of Random Simple Connected Graphs with Prescribed Degree Sequence, Journal of Complex Networks 4, no. 1, pp. 15–37 (2015). https://doi.org/10.1093/comnet/cnv013.

Szabolcs Horvát, and Carl D Modes: Connectedness Matters: Construction and Exact Random Sampling of Connected Networks, Journal of Physics: Complexity 2, no. 1, pp. 015008 (2021). https://doi.org/10.1088/2632-072x/abced5.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`out_degrees`: | A vector of integers specifying the degree sequence for undirected graphs or the out-degree sequence for directed graphs.
`in_degrees`: | A vector of integers specifying the in-degree sequence for directed graphs. For undirected graphs, it must be `NULL`.
`method`: | The method to generate the graph. Possible values:
`IGRAPH_DEGSEQ_CONFIGURATION` | This method implements the configuration model. For undirected graphs, it puts all vertex IDs in a bag such that the multiplicity of a vertex in the bag is the same as its degree. Then it draws pairs from the bag until the bag becomes empty. This method may generate both loop (self) edges and multiple edges. For directed graphs, the algorithm is basically the same, but two separate bags are used for the in- and out-degrees. Undirected graphs are generated with probability proportional to `(\prod_{i<j} A_{ij} ! \prod_i A_{ii} !!)^{-1}`, where `A` denotes the adjacency matrix and `!!` denotes the double factorial. Here `A` is assumed to have twice the number of self-loops on its diagonal. The corresponding expression for directed graphs is `(\prod_{i,j} A_{ij}!)^{-1}`. Thus the probability of all simple graphs (which only have 0s and 1s in the adjacency matrix) is the same, while that of non-simple ones depends on their edge and self-loop multiplicities.
`IGRAPH_DEGSEQ_CONFIGURATION_SIMPLE` | This method is identical to `IGRAPH_DEGSEQ_CONFIGURATION`, but if the generated graph is not simple, it rejects it and re-starts the generation. It generates all simple graphs with the same probability.
`IGRAPH_DEGSEQ_FAST_HEUR_SIMPLE` | This method generates simple graphs. It is similar to `IGRAPH_DEGSEQ_CONFIGURATION` but tries to avoid multiple and loop edges and restarts the generation from scratch if it gets stuck. It can generate all simple realizations of a degree sequence, but it is not guaranteed to sample them uniformly. This method is relatively fast and it will eventually succeed if the provided degree sequence is graphical, but there is no upper bound on the number of iterations.
`IGRAPH_DEGSEQ_EDGE_SWITCHING_SIMPLE` | This is an MCMC sampler based on degree-preserving edge switches. It generates simple undirected or directed graphs. It uses `igraph_realize_degree_sequence()` to construct an initial graph, then rewires it using `igraph_rewire()`.
`IGRAPH_DEGSEQ_VL` | This method samples undirected connected graphs approximately uniformly. It is a Monte Carlo method based on degree-preserving edge switches. This generator should be favoured if undirected and connected graphs are to be generated and execution time is not a concern. igraph uses the original implementation of Fabien Viger; for the algorithm, see https://www-complexnetworks.lip6.fr/~latapy/FV/generation.html and the paper https://arxiv.org/abs/cs/0502085

Returns:

`` | Error code: `IGRAPH_ENOMEM`: there is not enough memory to perform the operation. `IGRAPH_EINVAL`: invalid method parameter, or invalid in- and/or out-degree vectors. The degree vectors should be non-negative, `out_deg` should sum up to an even integer for undirected graphs; the length and sum of `out_deg` and `in_deg` should match for directed graphs.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges for `IGRAPH_DEGSEQ_CONFIGURATION` and `IGRAPH_DEGSEQ_EDGE_SWITCHING_SIMPLE`. The time complexity of the other modes is not known.

See also:

`` | `igraph_is_graphical()` to determine if there exist graphs with a certain degree sequence; `igraph_erdos_renyi_game_gnm()` to generate graphs with a fixed number of edges, without any degree constraints; `igraph_chung_lu_game()` and `igraph_static_fitness_game()` to sample random graphs with a prescribed expected degree sequence (but variable actual degrees); `igraph_realize_degree_sequence()` and `igraph_realize_bipartite_degree_sequence()` to generate a single (non-random) graph with given degrees.

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

    #include <igraph.h>

    int main(void) {
        igraph_t g;
        igraph_vector_int_t outdeg, indeg;
        igraph_vector_int_t vec;
        igraph_bool_t is_simple;

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

        /* Set random seed for reproducibility */
        igraph_rng_seed(igraph_rng_default(), 42);

        igraph_vector_int_init_int(&outdeg, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3);
        igraph_vector_int_init_int(&indeg, 10, 4, 4, 2, 2, 4, 4, 2, 2, 3, 3);
        igraph_vector_int_init(&vec, 0);

        /* checking the configuration model, undirected graphs */
        igraph_degree_sequence_game(&g, &outdeg, 0, IGRAPH_DEGSEQ_CONFIGURATION);
        if (igraph_is_directed(&g) || igraph_vcount(&g) != 10) {
            return 1;
        }
        if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS)) {
            return 2;
        }
        igraph_vector_int_print(&vec);
        igraph_destroy(&g);

        /* checking the Viger-Latapy method, undirected graphs */
        igraph_degree_sequence_game(&g, &outdeg, 0, IGRAPH_DEGSEQ_VL);
        if (igraph_is_directed(&g) || igraph_vcount(&g) != 10) {
            return 3;
        }
        if (igraph_is_simple(&g, &is_simple, IGRAPH_DIRECTED) || !is_simple) {
            return 4;
        }
        if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_OUT, IGRAPH_NO_LOOPS)) {
            return 5;
        }
        igraph_vector_int_print(&vec);
        igraph_destroy(&g);

        /* checking the configuration model, directed graphs */
        igraph_degree_sequence_game(&g, &outdeg, &indeg, IGRAPH_DEGSEQ_CONFIGURATION);
        if (!igraph_is_directed(&g) || igraph_vcount(&g) != 10) {
            return 6;
        }
        if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS)) {
            return 7;
        }
        igraph_vector_int_print(&vec);
        if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS)) {
            return 8;
        }
        igraph_vector_int_print(&vec);
        igraph_destroy(&g);

        /* checking the fast heuristic method, undirected graphs */
        igraph_degree_sequence_game(&g, &outdeg, 0, IGRAPH_DEGSEQ_FAST_HEUR_SIMPLE);
        if (igraph_is_directed(&g) || igraph_vcount(&g) != 10) {
            return 9;
        }
        if (igraph_is_simple(&g, &is_simple, IGRAPH_DIRECTED) || !is_simple) {
            return 10;
        }
        if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS)) {
            return 11;
        }
        igraph_vector_int_print(&vec);
        igraph_destroy(&g);

        /* checking the fast heuristic method, directed graphs */
        igraph_degree_sequence_game(&g, &outdeg, &indeg, IGRAPH_DEGSEQ_FAST_HEUR_SIMPLE);
        if (!igraph_is_directed(&g) || igraph_vcount(&g) != 10) {
            return 12;
        }
        if (igraph_is_simple(&g, &is_simple, IGRAPH_DIRECTED) || !is_simple) {
            return 13;
        }
        if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS)) {
            return 14;
        }
        igraph_vector_int_print(&vec);
        if (igraph_degree(&g, &vec, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS)) {
            return 15;
        }
        igraph_vector_int_print(&vec);
        igraph_destroy(&g);

        igraph_vector_int_destroy(&vec);
        igraph_vector_int_destroy(&outdeg);
        igraph_vector_int_destroy(&indeg);

        return 0;
    }

### 4.2. `igraph_k_regular_game` — Generates a random graph where each vertex has the same degree.

    igraph_error_t igraph_k_regular_game(igraph_t *graph,
                              igraph_int_t no_of_nodes, igraph_int_t k,
                              igraph_bool_t directed, igraph_bool_t multiple);

This game generates a directed or undirected random graph where the degrees of vertices are equal to a predefined constant k. For undirected graphs, at least one of k and the number of vertices must be even.

Currently, this game simply uses `igraph_degree_sequence_game` with the `IGRAPH_DEGSEQ_CONFIGURATION` or the `IGRAPH_DEGSEQ_FAST_SIMPLE` method and appropriately constructed degree sequences. Thefore, it does not sample uniformly: while it can generate all k-regular graphs with the given number of vertices, it does not generate each one with the same probability.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`no_of_nodes`: | The number of nodes in the generated graph.
`k`: | The degree of each vertex in an undirected graph, or the out-degree and in-degree of each vertex in a directed graph.
`directed`: | Whether the generated graph will be directed.
`multiple`: | Whether to allow multiple edges in the generated graph.

Returns:

`` | Error code: `IGRAPH_EINVAL`: invalid parameter; e.g., negative number of nodes, or odd number of nodes and odd k for undirected graphs. `IGRAPH_ENOMEM`: there is not enough memory for the operation.

Time complexity: O(|V|+|E|) if `multiple` is true, otherwise not known.

### 4.3. `igraph_rewire` — Randomly rewires a graph while preserving its degree sequence.

    igraph_error_t igraph_rewire(igraph_t *graph, igraph_int_t n, igraph_edge_type_sw_t allowed_edge_types, igraph_rewiring_stats_t *stats);

This function generates a new graph based on the original one by randomly "rewriting" edges while preserving the original graph's degree sequence. The rewiring is done "in place", so no new graph will be allocated. If you would like to keep the original graph intact, use `igraph_copy()` beforehand. All graph attributes will be lost.

The rewiring is performed with degree-preserving edge switches: Two arbitrary edges are picked uniformly at random, namely `(a, b)` and `(c, d)`, then they are replaced by `(a, d)` and `(b, c)` if this preserves the constraints specified by `mode`.

Arguments:

`graph`: | The graph object to be rewired.
`n`: | Number of rewiring trials to perform.
`allowed_edge_types`: | The types of edges that rewiring may create in the graph. See `igraph_edge_type_sw_t` for details. Currently, the following are implemented:
`IGRAPH_SIMPLE_SW` | simple graphs (i.e. no self-loops or multi-edges allowed).
`IGRAPH_LOOPS_SW` | single self-loops are allowed, but not multi-edges.
Multigraphs are not yet supported.
`stats`: | Counts of the number of different operations performed by the algorithm are stored here.

Returns:

`` | Error code:
`IGRAPH_EINVMODE` | Invalid rewiring mode.
`IGRAPH_ENOMEM` | Not enough memory for temporary data.

Time complexity: TODO.

### 4.4. `igraph_chung_lu_game` — Samples graphs from the Chung-Lu model.

    igraph_error_t igraph_chung_lu_game(igraph_t *graph,
                                        const igraph_vector_t *out_weights,
                                        const igraph_vector_t *in_weights,
                                        igraph_bool_t loops,
                                        igraph_chung_lu_t variant);

### Warning

This function is experimental and its signature is not considered final yet. We reserve the right to change the function signature without changing the major version of igraph. Use it at your own risk.

The Chung-Lu model is useful for generating random graphs with fixed expected degrees. This function implements both the original model of Chung and Lu, as well as some additional variants with useful properties.

In the original Chung-Lu model, each pair of vertices `i` and `j` is connected with independent probability `p_ij = w_i w_j / S`, where `w_i` is a weight associated with vertex `i` and `S = sum_k w_k` is the sum of weights. In the directed variant, vertices have both out-weights, `w^out`, and in-weights, `w^in`, with equal sums, `S = sum_k w^out_k = sum_k w^in_k`. The connection probability between `i` and `j` is `p_ij = w^out_i w^in_j / S`.

This model is commonly used to create random graphs with a fixed expected degree sequence. The expected degree of vertex `i` is approximately equal to the weight `w_i`. Specifically, if the graph is directed and self-loops are allowed, then the expected out- and in-degrees are precisely `w^out` and `w^in`. If self-loops are disallowed, then the expected out- and in-degrees are `w^out (S - w^in) / S` and `w^in (S - w^out) / S`, respectively. If the graph is undirected, then the expected degrees with and without self-loops are `w (S + w) / S` and `w (S - w) / S`, respectively.

A limitation of the original Chung-Lu model is that when some of the weights are large, the formula for `p_ij` yields values larger than 1. Chung and Lu's original paper excludes the use of such weights. When `p_ij > 1`, this function simply issues a warning and creates a connection between `i` and `j`. However, in this case the expected degrees will no longer relate to the weights in the manner stated above. Thus the original Chung-Lu model cannot produce certain (large) expected degrees.

The overcome this limitation, this function implements additional variants of the model, with modified expressions for the connection probability `p_ij` between vertices `i` and `j`. Let `q_ij = w_i w_j / S`, or `q_ij = w^out_i w^in_j / S` in the directed case. All model variants become equivalent in the limit of sparse graphs where `q_ij` approaches zero. In the original Chung-Lu model, selectable by setting `variant` to `IGRAPH_CHUNG_LU_ORIGINAL`, `p_ij = min(q_ij, 1)`. The `IGRAPH_CHUNG_LU_MAXENT` variant, sometiems referred to a the generalized random graph, uses `p_ij = q_ij / (1 + q_ij)`, and is equivalent to a maximum entropy model (i.e. exponential random graph model) with a constraint on expected degrees; see Park and Newman (2004), Section B, setting `exp(-Theta_ij) = w_i w_j / S`. This model is also discussed by Britton, Deijfen and Martin-Löf (2006). By virtue of being a degree-constrained maximum entropy model, it produces graphs with the same degree sequence with the same probability. A third variant can be requested with `IGRAPH_CHUNG_LU_NR`, and uses `p_ij = 1 - exp(-q_ij)`. This is the underlying simple graph of a multigraph model introduced by Norros and Reittu (2006). For a discussion of these three model variants, see Section 16.4 of Bollobás, Janson, Riordan (2007), as well as Van Der Hofstad (2013).

References:

Chung F and Lu L: Connected components in a random graph with given degree sequences. Annals of Combinatorics 6, 125-145 (2002). https://doi.org/10.1007/PL00012580

Miller JC and Hagberg A: Efficient Generation of Networks with Given Expected Degrees (2011). https://doi.org/10.1007/978-3-642-21286-4_10

Park J and Newman MEJ: Statistical mechanics of networks. Physical Review E 70, 066117 (2004). https://doi.org/10.1103/PhysRevE.70.066117

Britton T, Deijfen M, Martin-Löf A: Generating Simple Random Graphs with Prescribed Degree Distribution. J Stat Phys 124, 1377–1397 (2006). https://doi.org/10.1007/s10955-006-9168-x

Norros I and Reittu H: On a conditionally Poissonian graph process. Advances in Applied Probability 38, 59–75 (2006). https://doi.org/10.1239/aap/1143936140

Bollobás B, Janson S, Riordan O: The phase transition in inhomogeneous random graphs. Random Struct Algorithms 31, 3–122 (2007). https://doi.org/10.1002/rsa.20168

Van Der Hofstad R: Critical behavior in inhomogeneous random graphs. Random Struct Algorithms 42, 480–508 (2013). https://doi.org/10.1002/rsa.20450

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`out_weights`: | A vector of non-negative vertex weights (or out-weights). In sparse graphs these will be approximately equal to the expected (out-)degrees.
`in_weights`: | A vector of non-negative in-weights, approximately equal to the expected in-degrees in sparse graphs. May be set to `NULL`, in which case undirected graphs are generated.
`loops`: | Whether to allow the creation of self-loops. Since vertex pairs are connected independently, setting this to false is equivalent to simply discarding self-loops from an existing loopy Chung-Lu graph.
`variant`: | The model variant to sample from, with different definitions of the connection probability between vertices `i` and `j`. Given `q_ij = w_i w_j / S`, the following formulations are available:
`IGRAPH_CHUNG_LU_ORIGINAL` | the original Chung-Lu model, `p_ij = min(q_ij, 1)`.
`IGRAPH_CHUNG_LU_MAXENT` | maximum entropy model with fixed expected degrees, `p_ij = q_ij / (1 + q_ij)`.
`IGRAPH_CHUNG_LU_NR` | Norros and Reittu's model, `p_ij = 1 - exp(-q_ij)`.

Returns:

`` | Error code.

See also:

`` | `igraph_static_fitness_game()` implements a similar model with a sharp constraint on the number of edges; `igraph_degree_sequence_game()` samples random graphs with sharply specified degrees; `igraph_erdos_renyi_game_gnp()` creates random graphs with a fixed connection probability `p` between all vertex pairs.

Time complexity: O(|E| + |V|), linear in the number of edges.

### 4.5. `igraph_static_fitness_game` — Non-growing random graph with edge probabilities proportional to node fitness scores.

    igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_int_t no_of_edges,
                                   const igraph_vector_t *fitness_out, const igraph_vector_t *fitness_in,
                                   igraph_edge_type_sw_t allowed_edge_types);

This game generates a directed or undirected random graph where the probability of an edge between vertices `i` and `j` depends on the fitness scores of the two vertices involved. For undirected graphs, each vertex has a single fitness score. For directed graphs, each vertex has an out- and an in-fitness, and the probability of an edge from `i` to `j` depends on the out-fitness of vertex `i` and the in-fitness of vertex `j`.

The generation process goes as follows. We start from `N` disconnected nodes (where `N` is given by the length of the fitness vector). Then we randomly select two vertices `i` and `j`, with probabilities proportional to their fitnesses. (When the generated graph is directed, `i` is selected according to the out-fitnesses and `j` is selected according to the in-fitnesses). If the vertices are not connected yet (or if multiple edges are allowed), we connect them; otherwise we select a new pair. This is repeated until the desired number of links are created.

The expected degree (though not the actual degree) of each vertex will be proportional to its fitness. This is exactly true when self-loops and multi-edges are allowed, and approximately true otherwise. If you need to generate a graph with an exact degree sequence, consider `igraph_degree_sequence_game()` and `igraph_realize_degree_sequence()` instead.

To generate random undirected graphs with a given expected degree sequence, set `fitness_out` (and in the directed case `fitness_out`) to the desired expected degrees, and `no_of_edges` to the corresponding edge count, i.e. half the sum of expected degrees in the undirected case, and the sum of out- or in-degrees in the directed case.

This model is similar to the better-known Chung-Lu model, implemented in igraph as `igraph_chung_lu_game()`, but with a sharply fixed edge count.

This model is commonly used to generate static scale-free networks. To achieve this, you have to draw the fitness scores from the desired power-law distribution. Alternatively, you may use `igraph_static_power_law_game()` which generates the fitnesses for you with a given exponent.

Reference:

Goh K-I, Kahng B, Kim D: Universal behaviour of load distribution in scale-free networks. Phys Rev Lett 87(27):278701, 2001 https://doi.org/10.1103/PhysRevLett.87.278701.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`no_of_edges`: | The number of edges in the generated graph.
`fitness_out`: | A numeric vector containing the fitness of each vertex. For directed graphs, this specifies the out-fitness of each vertex.
`fitness_in`: | If `NULL`, the generated graph will be undirected. If not `NULL`, this argument specifies the in-fitness of each vertex.
`allowed_edge_types`: | Controls whether multi-edges and self-loops are allowed in the generated graph. See `igraph_edge_type_sw_t`.

Returns:

`` | Error code: `IGRAPH_EINVAL`: invalid parameter `IGRAPH_ENOMEM`: there is not enough memory for the operation.

See also:

`` | `igraph_static_power_law_game()`, `igraph_chung_lu_game()`, `igraph_degree_sequence_game()`

Time complexity: O(|V| + |E| log |E|).

### 4.6. `igraph_static_power_law_game` — Generates a non-growing random graph with expected power-law degree distributions.

    igraph_error_t igraph_static_power_law_game(igraph_t *graph,
                                     igraph_int_t no_of_nodes, igraph_int_t no_of_edges,
                                     igraph_real_t exponent_out, igraph_real_t exponent_in,
                                     igraph_edge_type_sw_t allowed_edge_types,
                                     igraph_bool_t finite_size_correction);

This game generates a directed or undirected random graph where the degrees of vertices follow power-law distributions with prescribed exponents. For directed graphs, the exponents of the in- and out-degree distributions may be specified separately.

The game simply uses `igraph_static_fitness_game()` with appropriately constructed fitness vectors. In particular, the fitness of vertex `i` is `i^(-alpha)`, where `alpha = 1/(gamma-1)` and `gamma` is the exponent given in the arguments.

To remove correlations between in- and out-degrees in case of directed graphs, the in-fitness vector will be shuffled after it has been set up and before `igraph_static_fitness_game()` is called.

Note that significant finite size effects may be observed for exponents smaller than 3 in the original formulation of the game. This function provides an argument that lets you remove the finite size effects by assuming that the fitness of vertex `i` is `(i+i0-1)^(-alpha)`, where `i0` is a constant chosen appropriately to ensure that the maximum degree is less than the square root of the number of edges times the average degree; see the paper of Chung and Lu, and Cho et al for more details.

References:

Goh K-I, Kahng B, Kim D: Universal behaviour of load distribution in scale-free networks. Phys Rev Lett 87(27):278701, 2001. https://doi.org/10.1103/PhysRevLett.87.278701

Chung F and Lu L: Connected components in a random graph with given degree sequences. Annals of Combinatorics 6, 125-145, 2002. https://doi.org/10.1007/PL00012580

Cho YS, Kim JS, Park J, Kahng B, Kim D: Percolation transitions in scale-free networks under the Achlioptas process. Phys Rev Lett 103:135702, 2009. https://doi.org/10.1103/PhysRevLett.103.135702

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`no_of_nodes`: | The number of nodes in the generated graph.
`no_of_edges`: | The number of edges in the generated graph.
`exponent_out`: | The power law exponent of the degree distribution. For directed graphs, this specifies the exponent of the out-degree distribution. It must be greater than or equal to 2. If you pass `IGRAPH_INFINITY` here, you will get back an Erdős-Rényi random network.
`exponent_in`: | If negative, the generated graph will be undirected. If greater than or equal to 2, this argument specifies the exponent of the in-degree distribution. If non-negative but less than 2, an error will be generated.
`allowed_edge_types`: | Controls whether multi-edges and self-loops are allowed in the generated graph. See `igraph_edge_type_sw_t`.
`finite_size_correction`: | Whether to use the proposed finite size correction of Cho et al.

Returns:

`` | Error code: `IGRAPH_EINVAL`: invalid parameter `IGRAPH_ENOMEM`: there is not enough memory for the operation.

Time complexity: O(|V| + |E| log |E|).

## 5. Edge rewiring models

### 5.1. `igraph_watts_strogatz_game` — The Watts-Strogatz small-world model.

    igraph_error_t igraph_watts_strogatz_game(
            igraph_t *graph, igraph_int_t dim,
            igraph_int_t size, igraph_int_t nei,
            igraph_real_t p,
            igraph_edge_type_sw_t allowed_edge_types);

This function generates networks with the small-world property based on a variant of the Watts-Strogatz model. The network is obtained by first creating a periodic undirected lattice, then rewiring both endpoints of each edge with probability `p`, while avoiding the creation of multi-edges.

This process differs from the original model of Watts and Strogatz (see reference) in that it rewires both endpoints of edges. Thus in the limit of `p=1`, we obtain a G(n,m) random graph with the same number of vertices and edges as the original lattice. In comparison, the original Watts-Strogatz model only rewires a single endpoint of each edge, thus the network does not become fully random even for `p=1`. For appropriate choices of `p`, both models exhibit the property of simultaneously having short path lengths and high clustering.

Reference:

Duncan J Watts and Steven H Strogatz: Collective dynamics of “small world” networks, Nature 393, 440-442, 1998. https://doi.org/10.1038/30918

Arguments:

`graph`: | The graph to initialize.
`dim`: | The dimension of the lattice.
`size`: | The size of the lattice along each dimension.
`nei`: | The size of the neighborhood for each vertex. This is the same as the `order` argument of `igraph_connect_neighborhood()`.
`p`: | The rewiring probability. A real number between zero and one (inclusive).
`allowed_edge_types`: | Controls whether multi-edges and self-loops are allowed in the generated graph. See `igraph_edge_type_sw_t`.

Returns:

`` | Error code.

See also:

`` | `igraph_square_lattice()`, `igraph_connect_neighborhood()` and `igraph_rewire_edges()` can be used if more flexibility is needed, e.g. a different type of lattice.

Time complexity: O(|V|*d^o+|E|), |V| and |E| are the number of vertices and edges, d is the average degree, o is the `nei` argument.

### 5.2. `igraph_rewire_edges` — Rewires the edges of a graph with constant probability.

    igraph_error_t igraph_rewire_edges(igraph_t *graph, igraph_real_t prob,
                                       igraph_edge_type_sw_t allowed_edge_types);

This function rewires the edges of a graph with a constant probability. More precisely each end point of each edge is rewired to a uniformly randomly chosen vertex with constant probability `prob`.

Note that this function modifies the input `graph`, call `igraph_copy()` if you want to keep it.

Arguments:

`graph`: | The input graph, this will be rewired, it can be directed or undirected.
`prob`: | The rewiring probability a constant between zero and one (inclusive).
`allowed_edge_types`: | Controls whether multi-edges and self-loops are allowed in the new graph. See `igraph_edge_type_sw_t`.

Returns:

`` | Error code.

See also:

`` | `igraph_watts_strogatz_game()` uses this function for the rewiring.

Time complexity: O(|V|+|E|).

### 5.3. `igraph_rewire_directed_edges` — Rewires the chosen endpoint of directed edges.

    igraph_error_t igraph_rewire_directed_edges(igraph_t *graph, igraph_real_t prob,
                                     igraph_bool_t loops, igraph_neimode_t mode);

This function rewires either the start or end of directed edges in a graph with a constant probability. Correspondingly, either the in-degree sequence or the out-degree sequence of the graph will be preserved.

Note that this function modifies the input `graph`, call `igraph_copy()` if you want to keep it.

This function can produce multiple edges between two vertices.

Arguments:

`graph`: | The input graph, this will be rewired, it can be directed or undirected. If it is undirected or `mode` is set to IGRAPH_ALL, `igraph_rewire_edges()` will be called.
`prob`: | The rewiring probability, a constant between zero and one (inclusive).
`loops`: | Boolean, whether loop edges are allowed in the new graph, or not.
`mode`: | The endpoints of directed edges to rewire. It is ignored for undirected graphs. Possible values:
`IGRAPH_OUT` | rewire the end of each directed edge
`IGRAPH_IN` | rewire the start of each directed edge
`IGRAPH_ALL` | rewire both endpoints of each edge

Returns:

`` | Error code.

See also:

`` | `igraph_rewire_edges()`, `igraph_rewire()`

Time complexity: O(|E|).

## 6. Other random graphs

### 6.1. `igraph_grg_game` — Generates a geometric random graph.

    igraph_error_t igraph_grg_game(igraph_t *graph, igraph_int_t nodes,
                        igraph_real_t radius, igraph_bool_t torus,
                        igraph_vector_t *x, igraph_vector_t *y);

A geometric random graph is created by dropping points (i.e. vertices) randomly on the unit square and then connecting all those pairs which are strictly less than `radius` apart in Euclidean distance.

Original code contributed by Keith Briggs, thanks Keith.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`nodes`: | The number of vertices in the graph.
`radius`: | The radius within which the vertices will be connected.
`torus`: | Boolean constant. If true, periodic boundary conditions will be used, i.e. the vertices are assumed to be on a torus instead of a square.
`x`: | An initialized vector or `NULL`. If not `NULL`, the points' x coordinates will be returned here.
`y`: | An initialized vector or `NULL`. If not `NULL`, the points' y coordinates will be returned here.

Returns:

`` | Error code.

Time complexity: TODO, less than O(|V|^2+|E|).

Example 12.6. File `examples/simple/igraph_grg_game.c`

    #include <igraph.h>
    #include <math.h>

    int main(void) {
        igraph_t graph;
        igraph_vector_t x, y;
        igraph_vector_t weights;
        igraph_eit_t eit;
        igraph_real_t avg_dist;

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

        /* Set random seed for reproducible results */

        igraph_rng_seed(igraph_rng_default(), 42);

        /* Create a random geometric graph and retrieve vertex coordinates */

        igraph_vector_init(&x, 0);
        igraph_vector_init(&y, 0);

        igraph_grg_game(&graph, 200, 0.1, /* torus */ false, &x, &y);

        /* Compute edge weights as geometric distance */

        igraph_vector_init(&weights, igraph_ecount(&graph));
        igraph_eit_create(&graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), &eit);
        for (; ! IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {
            igraph_int_t e = IGRAPH_EIT_GET(eit);
            igraph_int_t u = IGRAPH_FROM(&graph, e);
            igraph_int_t v = IGRAPH_TO(&graph, e);

            VECTOR(weights)[e] = hypot(VECTOR(x)[u] - VECTOR(x)[v], VECTOR(y)[u] - VECTOR(y)[v]);
        }
        igraph_eit_destroy(&eit);

        /* Compute average path length */

        igraph_average_path_length(&graph, &weights, &avg_dist, NULL, IGRAPH_UNDIRECTED, /* unconn */ true);

        printf("Average distance in the geometric graph: %g.\n", avg_dist);

        /* Destroy data structures when no longer needed */

        igraph_vector_destroy(&weights);
        igraph_destroy(&graph);
        igraph_vector_destroy(&x);
        igraph_vector_destroy(&y);

        return 0;
    }

### 6.2. `igraph_dot_product_game` — Generates a random dot product graph.

    igraph_error_t igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *vecs,
                                igraph_bool_t directed);

In this model, each vertex is represented by a latent position vector. Probability of an edge between two vertices are given by the dot product of their latent position vectors.

See also Christine Leigh Myers Nickel: Random dot product graphs, a model for social networks. Dissertation, Johns Hopkins University, Maryland, USA, 2006.

Arguments:

`graph`: | The output graph is stored here.
`vecs`: | A matrix in which each latent position vector is a column. The dot product of the latent position vectors should be in the [0,1] interval, otherwise a warning is given. For negative dot products, no edges are added; dot products that are larger than one always add an edge.
`directed`: | Should the generated graph be directed?

Returns:

`` | Error code.

Time complexity: O(n*n*m), where n is the number of vertices, and m is the length of the latent vectors.

See also:

`` | `igraph_rng_sample_dirichlet()`, `igraph_rng_sample_sphere_volume()`, `igraph_rng_sample_sphere_surface()` for functions to generate the latent vectors.

### 6.3. `igraph_simple_interconnected_islands_game` — Generates a random graph made of several interconnected islands, each island being a random graph.

    igraph_error_t igraph_simple_interconnected_islands_game(
            igraph_t *graph,
            igraph_int_t islands_n,
            igraph_int_t islands_size,
            igraph_real_t islands_pin,
            igraph_int_t n_inter);

All islands are of the same size. Within an island, each edge is generated with the same probability. A fixed number of additional edges are then generated for each unordered pair of islands to connect them. The generated graph is guaranteed to be simple.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`islands_n`: | The number of islands in the graph.
`islands_size`: | The size of islands in the graph.
`islands_pin`: | The probability to create each possible edge within islands.
`n_inter`: | The number of edges to create between two islands. It may be larger than `islands_size` squared, but in this case it is assumed to be `islands_size` squared.

Returns:

`` | Error code: `IGRAPH_EINVAL`: invalid parameter `IGRAPH_ENOMEM`: there is not enough memory for the operation.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges in the graph.

### 6.4. `igraph_tree_game` — Generates a random tree with the given number of nodes.

    igraph_error_t igraph_tree_game(igraph_t *graph, igraph_int_t n, igraph_bool_t directed, igraph_random_tree_t method);

This function samples uniformly from the set of labelled trees, i.e. it generates each labelled tree with the same probability.

Note that for `n=0`, the null graph is returned, which is not considered to be a tree by `igraph_is_tree()`.

Arguments:

`graph`: | Pointer to an uninitialized graph object.
`n`: | The number of nodes in the tree.
`directed`: | Whether to create a directed tree. The edges are oriented away from the root.
`method`: | The algorithm to use to generate the tree. Possible values:
`IGRAPH_RANDOM_TREE_PRUFER` | This algorithm samples Prüfer sequences uniformly, then converts them to trees. Directed trees are not currently supported.
`IGRAPH_RANDOM_LERW` | This algorithm effectively performs a loop-erased random walk on the complete graph to uniformly sample its spanning trees (Wilson's algorithm).

Returns:

`` | Error code: `IGRAPH_ENOMEM`: there is not enough memory to perform the operation. `IGRAPH_EINVAL`: invalid tree size

See also:

`` | `igraph_from_prufer()`

## 7. Common types and constants

### 7.1. `igraph_edge_type_sw_t` — What types of non-simple edges to allow?

    typedef unsigned int igraph_edge_type_sw_t;

This type is used with multiple functions to specify what types of non-simple edges to allow, create or consider a graph. The constants below are treated as "switches" that can be turned on individually and combined using the bitwise-or operator. For example, `IGRAPH_LOOPS_SW` allows only self-loops but not multi-edges, while `IGRAPH_LOOPS_SW | IGRAPH_MULTI_SW` allows both.

Values:

`IGRAPH_SIMPLE_SW`: | A shorthand for simple graphs only, which is the default assumption.
`IGRAPH_LOOPS_SW`: | Allow or consider self-loops.
`IGRAPH_MULTI_SW`: | Allow or consider multi-edges.