# Chapter 24. Vertex separators

## 1. `igraph_is_separator` — Would removing this set of vertices disconnect the graph?

    igraph_error_t igraph_is_separator(const igraph_t *graph,
                                       const igraph_vs_t candidate,
                                       igraph_bool_t *res);

A vertex set `S` is a separator if there are vertices `u` and `v` in the graph such that all paths between `u` and `v` pass through some vertices in `S`.

Arguments:

`graph`: | The input graph. It may be directed, but edge directions are ignored.
`candidate`: | The candidate separator.
`res`: | Pointer to a boolean variable, the result is stored here.

Returns:

`` | Error code.

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

Example 24.1. File `examples/simple/igraph_is_separator.c`

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

    #define FAIL(msg, error) do { printf(msg "\n") ; return error; } while (0)

    int main(void) {

        igraph_t graph;
        igraph_vector_int_t sep;
        igraph_bool_t result;

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

        /* Simple star graph, remove the center */
        igraph_star(&graph, 10, IGRAPH_STAR_UNDIRECTED, 0);
        igraph_is_separator(&graph, igraph_vss_1(0), &result);
        if (!result) {
            FAIL("Center of star graph failed.", 1);
        }

        /* Same graph, but another vertex */
        igraph_is_separator(&graph, igraph_vss_1(6), &result);
        if (result) {
            FAIL("Non-center of star graph failed.", 2);
        }

        /* Same graph, all vertices but the center */
        igraph_is_separator(&graph, igraph_vss_range(1, 10), &result);
        if (result) {
            FAIL("All non-central vertices of star graph failed.", 5);
        }

        /* Same graph, all vertices */
        igraph_is_separator(&graph, igraph_vss_range(0, 10), &result);
        if (result) {
            FAIL("All vertices of star graph failed.", 6);
        }
        igraph_destroy(&graph);

        /* Karate club */
        igraph_famous(&graph, "zachary");
        igraph_vector_int_init(&sep, 0);
        igraph_vector_int_push_back(&sep, 32);
        igraph_vector_int_push_back(&sep, 33);
        igraph_is_separator(&graph, igraph_vss_vector(&sep), &result);
        if (!result) {
            FAIL("Karate network (32,33) failed", 3);
        }

        igraph_vector_int_resize(&sep, 5);
        VECTOR(sep)[0] = 8;
        VECTOR(sep)[1] = 9;
        VECTOR(sep)[2] = 19;
        VECTOR(sep)[3] = 30;
        VECTOR(sep)[4] = 31;
        igraph_is_separator(&graph, igraph_vss_vector(&sep), &result);
        if (result) {
            FAIL("Karate network (8,9,19,30,31) failed", 4);
        }

        igraph_destroy(&graph);
        igraph_vector_int_destroy(&sep);

        return 0;
    }

## 2. `igraph_is_minimal_separator` — Decides whether a set of vertices is a minimal separator.

    igraph_error_t igraph_is_minimal_separator(const igraph_t *graph,
                                               const igraph_vs_t candidate,
                                               igraph_bool_t *res);

A vertex separator `S` is minimal is no proper subset of `S` is also a separator.

Arguments:

`graph`: | The input graph. It may be directed, but edge directions are ignored.
`candidate`: | The candidate minimal separators.
`res`: | Pointer to a boolean variable, the result is stored here.

Returns:

`` | Error code.

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

Example 24.2. File `examples/simple/igraph_is_minimal_separator.c`

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

    #define FAIL(msg, error) do { printf(msg "\n") ; return error; } while (0)

    int main(void) {

        igraph_t graph;
        igraph_vector_int_t sep;
        igraph_bool_t result;

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

        /* Simple star graph, remove the center */
        igraph_star(&graph, 10, IGRAPH_STAR_UNDIRECTED, 0);
        igraph_is_minimal_separator(&graph, igraph_vss_1(0), &result);
        if (!result) {
            FAIL("Center of star graph failed.", 1);
        }

        /* Same graph, but another vertex */
        igraph_is_minimal_separator(&graph, igraph_vss_1(6), &result);
        if (result) {
            FAIL("Non-center of star graph failed.", 2);
        }
        igraph_destroy(&graph);

        /* Karate club */
        igraph_famous(&graph, "zachary");
        igraph_vector_int_init(&sep, 0);
        igraph_vector_int_push_back(&sep, 32);
        igraph_vector_int_push_back(&sep, 33);
        igraph_is_minimal_separator(&graph, igraph_vss_vector(&sep), &result);
        if (!result) {
            FAIL("Karate network (32,33) failed", 3);
        }

        igraph_vector_int_resize(&sep, 5);
        VECTOR(sep)[0] = 8;
        VECTOR(sep)[1] = 9;
        VECTOR(sep)[2] = 19;
        VECTOR(sep)[3] = 30;
        VECTOR(sep)[4] = 31;
        igraph_is_minimal_separator(&graph, igraph_vss_vector(&sep), &result);
        if (result) {
            FAIL("Karate network (8,9,19,30,31) failed", 4);
        }

        igraph_destroy(&graph);
        igraph_vector_int_destroy(&sep);

        return 0;
    }

## 3. `igraph_all_minimal_st_separators` — List all vertex sets that are minimal (s,t) separators for some s and t.

    igraph_error_t igraph_all_minimal_st_separators(
        const igraph_t *graph, igraph_vector_int_list_t *separators
    );

This function lists all vertex sets that are minimal (s,t) separators for some (s,t) vertex pair.

Note that some vertex sets returned by this function may not be minimal with respect to disconnecting the graph (or increasing the number of connected components). Take for example the 5-vertex graph with edges `0-1-2-3-4-1`. This function returns the vertex sets `{1}`, `{2,4}` and `{1,3}`. Notice that `{1,3}` is not minimal with respect to disconnecting the graph, as `{1}` would be sufficient for that. However, it is minimal with respect to separating vertices `2` and `4`.

See more about the implemented algorithm in Anne Berry, Jean-Paul Bordat and Olivier Cogis: Generating All the Minimal Separators of a Graph, In: Peter Widmayer, Gabriele Neyer and Stephan Eidenbenz (editors): Graph-theoretic concepts in computer science, 1665, 167--172, 1999. Springer. https://doi.org/10.1007/3-540-46784-X_17

Arguments:

`graph`: | The input graph. It may be directed, but edge directions are ignored.
`separators`: | Pointer to a list of integer vectors, the separators will be stored here.

Returns:

`` | Error code.

See also:

`` | `igraph_minimum_size_separators()`

Time complexity: O(n|V|^3), |V| is the number of vertices, n is the number of separators.

Example 24.3. File `examples/simple/igraph_minimal_separators.c`

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

    int main(void) {
        igraph_t graph;
        igraph_vector_int_list_t separators;
        igraph_int_t i, n;

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

        igraph_famous(&graph, "zachary");
        igraph_vector_int_list_init(&separators, 0);
        igraph_all_minimal_st_separators(&graph, &separators);

        n = igraph_vector_int_list_size(&separators);
        for (i = 0; i < n; i++) {
            igraph_bool_t res;
            igraph_vector_int_t *sep = igraph_vector_int_list_get_ptr(&separators, i);

            igraph_is_separator(&graph, igraph_vss_vector(sep), &res);
            if (!res) {
                printf("Vertex set %" IGRAPH_PRId " is not a separator!\n", i);
                igraph_vector_int_print(sep);
                return 1;
            }
        }

        igraph_destroy(&graph);
        igraph_vector_int_list_destroy(&separators);

        return 0;
    }

## 4. `igraph_minimum_size_separators` — Find all minimum size separating vertex sets.

    igraph_error_t igraph_minimum_size_separators(
        const igraph_t *graph, igraph_vector_int_list_t *separators
    );

This function lists all separator vertex sets of minimum size. A vertex set is a separator if its removal disconnects the graph.

If the graph is already disconnected, no separators are returned. Note that this convention differs from that used by some other funtions such as `igraph_all_minimal_st_separators()`.

Complete graphs have no vertex separators.

The implementation is based on the following paper: Arkady Kanevsky: Finding all minimum-size separating vertex sets in a graph, Networks 23, 533--541, 1993. https://doi.org/10.1002/net.3230230604

Arguments:

`graph`: | The input graph, which must be undirected.
`separators`: | An initialized list of integer vectors, the separators are stored here. It is a list of pointers to igraph_vector_int_t objects. Each vector will contain the IDs of the vertices in the separator. The separators are returned in an arbitrary order.

Returns:

`` | Error code.

Time complexity: TODO.

Example 24.4. File `examples/simple/igraph_minimum_size_separators.c`

    #include <igraph.h>

    int main(void) {
        igraph_setup();
        igraph_t g;
        igraph_vector_int_list_t sep;

        igraph_small(&g, 7, IGRAPH_UNDIRECTED,
                     1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0,
                     -1);
        igraph_vector_int_list_init(&sep, 0);
        igraph_minimum_size_separators(&g, &sep);

        for (igraph_int_t i = 0; i < igraph_vector_int_list_size(&sep); i++) {
            igraph_vector_int_t* v = igraph_vector_int_list_get_ptr(&sep, i);
            igraph_vector_int_print(v);
        }

        igraph_vector_int_list_destroy(&sep);
        igraph_destroy(&g);

        return 0;
    }

## 5. `igraph_even_tarjan_reduction` — Even-Tarjan reduction of a graph.

    igraph_error_t igraph_even_tarjan_reduction(const igraph_t *graph, igraph_t *graphbar,
            igraph_vector_t *capacity);

A digraph is created with twice as many vertices and edges. For each original vertex `i`, two vertices `i' = i` and `i'' = i' + n` are created, with a directed edge from `i'` to `i''`. For each original directed edge from `i` to `j`, two new edges are created, from `i'` to `j''` and from `i''` to `j'`.

This reduction is used in the paper (observation 2): Arkady Kanevsky: Finding all minimum-size separating vertex sets in a graph, Networks 23, 533--541, 1993.

The original paper where this reduction was conceived is Shimon Even and R. Endre Tarjan: Network Flow and Testing Graph Connectivity, SIAM J. Comput., 4(4), 507–518. https://doi.org/10.1137/0204043

Arguments:

`graph`: | A graph. Although directness is not checked, this function is commonly used only on directed graphs.
`graphbar`: | Pointer to a new directed graph that will contain the reduction, with twice as many vertices and edges.
`capacity`: | Pointer to an initialized vector or a null pointer. If not a null pointer, then it will be filled the capacity from the reduction: the first |E| elements are 1, the remaining |E| are equal to |V| (which is used to indicate infinity).

Returns:

`` | Error code.

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

Example 24.5. File `examples/simple/even_tarjan.c`

    #include <igraph.h>
    #include <limits.h>

    int main(void) {

        igraph_t g, gbar;
        igraph_int_t k1, k2 = INT_MAX;
        igraph_real_t tmpk;
        igraph_int_t i, j, n;
        igraph_maxflow_stats_t stats;

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

        igraph_famous(&g, "meredith");
        igraph_even_tarjan_reduction(&g, &gbar, /*capacity=*/ NULL);

        igraph_vertex_connectivity(&g, &k1, /* checks= */ false);

        n = igraph_vcount(&g);
        for (i = 0; i < n; i++) {
            for (j = i + 1; j < n; j++) {
                igraph_bool_t conn;
                igraph_are_adjacent(&g, i, j, &conn);
                if (conn) {
                    continue;
                }
                igraph_maxflow_value(&gbar, &tmpk,
                                     /* source= */ i + n,
                                     /* target= */ j,
                                     /* capacity= */ 0,
                                     &stats);
                if (tmpk < k2) {
                    k2 = tmpk;
                }
            }
        }

        igraph_destroy(&gbar);
        igraph_destroy(&g);

        if (k1 != k2) {
            printf("k1 = %" IGRAPH_PRId " while k2 = %" IGRAPH_PRId "\n", k1, k2);
            return 1;
        }

        return 0;
    }