# Introducing Graphettes

    library(igraph)
    #>
    #> Attaching package: 'igraph'
    #> The following objects are masked from 'package:stats':
    #>
    #>     decompose, spectrum
    #> The following object is masked from 'package:base':
    #>
    #>     union
    library(graphonmix)
    library(ggplot2)

Graphettes are a graph generation methodology proposed in (Wijesinghe et al. 2026). A graphette has 3 components: a graphon \(W\), a sequence \(\{\rho_n\}_n\) and a graph edit function \(f\). We can generate dense or sparse graphs from a graphette. On the sparse graph front, we can generate diverse sparse graphs, such as ring-added graphs that have bounded degree or graphs with large hubs like this social networks. We can generate trees as well. Let’s look at some examples.

# Dense graphs from graphons and graphettes

Let’s start with a stochastic block model graphon.

    mat <- matrix(c(0.9, 0.01, 0.02,
                    0.01, 0.8, 0.03,
                    0.02, 0.03, 0.7), nrow = 3, byrow = TRUE)
    W <- sbm_graphon(mat, 100)
    plot_graphon(W) +  coord_fixed(ratio = 1)

## Using the graphon

Without using graphettes we can sample from this graphon as follows:

    gr <- sample_graphon(W, 100)
    plot(gr, vertex.size = 3, vertex.label = NA, main = "Graphon sampling")

## Using the graphette

To generate dense graphs from the graphette we set \(\rho_n = 1\) for all \(n\) and the graph edit function \(f\) to the identity function. In the function call sample_graphette we set \(\rho_n\) = NULL and graph_edit_function = NULL. That way, we get are actually sampling from the graphon \(W\) without sparsifying it.

    gr1 <- sample_graphette(W, n= 100)
    plot(gr1, vertex.size = 3, vertex.label = NA, main = "Graphette sampling")

As you can see, in this instance sampling from the graphon or the graphette gives similar graphs.

# Sparse graphs using \(\rho_n\)

Consider the same SBM graphon. We can sparsify it by considering \(W_n = \rho_n W\) where \(\rho_n \to 0\). And then we sample a graph \(G_n\) with \(n\) nodes from \(W_n\). As \(n \to \infty\) the edge density goes to zero making this graph sequence sparse. Let’s see how this works.

## Using the standard graphon and \(\rho_n\) separately

    rho_n <- function(n) exp( -((n-100)/50 ))

    W250 <- rho_n(250)*W
    W300 <- rho_n(300)*W

    gr1 <- sample_graphon(W, 100)
    gr2 <- sample_graphon(W250, 250)
    gr3 <- sample_graphon(W300, 300)

    g1 <- plot_graphon(W) +  coord_fixed(ratio = 1)
    g2 <- plot_graphon(W250) +  coord_fixed(ratio = 1)
    g3 <- plot_graphon(W300) + coord_fixed(ratio = 1)

    gridExtra::grid.arrange(g1, g2, g3, nrow = 1)

The three graphons are shown above and we see the colours get greyed out as \(\rho_n\) goes to zero. Let’s plot the graphs sampled from the two graphons.

    par(mfrow = c(1,3))
    plot(gr1, vertex.size = 3, vertex.label = NA, main = "From W")
    plot(gr2, vertex.size = 3, vertex.label = NA, main = "From W250")
    plot(gr3, vertex.size = 3, vertex.label = NA, main = "From W300")

    par(mfrow = c(1,1))

We see the graphs getting sparser.

## Using the function sample_sparse_graphon

The function sample_sparse_graphon has a function parameter that can be used for \(\rho_n\).

    gr4 <- sample_sparse_graphon(W, rho_n, n = 250)
    gr5 <- sample_sparse_graphon(W, rho_n, n = 300)

    par(mfrow = c(1,2))
    plot(gr4, vertex.size = 3, vertex.label = NA, main = "n = 250")
    plot(gr5, vertex.size = 3, vertex.label = NA, main = "n = 300")

    par(mfrow = c(1,1))

## Using the graphette

We can use the sample_graphette to get the same functionality by setting *graph_edit_f = $NULL.

    gr6 <- sample_graphette(W, rho_n, n = 250)
    gr7 <- sample_graphette(W, rho_n, n = 300)

    par(mfrow = c(1,2))
    plot(gr6, vertex.size = 3, vertex.label = NA, main = "n = 250")
    plot(gr7, vertex.size = 3, vertex.label = NA, main = "n = 300")

    par(mfrow = c(1,1))

# Sparse graphs using \(\rho_n\) and the graph edit function

We have the functionality to add stars, add rings and remove cycles using the graph edit function.

## Adding stars

The functions star_f1, star_f2, star_f3, star_f4 and star_f5 can be used to add stars. While there are slight differences, all of these functions use a Poisson process to add additional connections to each node. The parameter \(t_or_p\) controls the intensity of the Poisson process.

    gr8 <- sample_graphette(W, rho_n, "star_f1", n = 250, t_or_p = 2)
    gr9 <- sample_graphette(W, rho_n, "star_f1", n = 300, t_or_p = 2)

    par(mfrow = c(1,2))
    plot(gr8, vertex.size = 3, vertex.label = NA, main = "n = 250")
    plot(gr9, vertex.size = 3, vertex.label = NA, main = "n = 300")

    par(mfrow = c(1,1))

In the above example \(\rho_n\) goes to 0 very fast. Let us use something a bit different

    rho2 <- function(n)10/n
    gr10 <- sample_graphette(W, rho2, "star_f1", n = 250, t_or_p = 2)
    gr11 <- sample_graphette(W, rho2, "star_f1", n = 300, t_or_p = 2)

    par(mfrow = c(1,2))
    plot(gr10, vertex.size = 3, vertex.label = NA, main = "n = 250")
    plot(gr11, vertex.size = 3, vertex.label = NA, main = "n = 300")

    par(mfrow = c(1,1))

## Adding rings

To add rings to the graph, use add_rings as the graph edit function. The parameter t_or_p gives the proportion of nodes to which rings are added. The default ring size is 5 or 6, but this can be changed.

    gr <- sample_graphette(W, rho_n, "add_rings", n = 100, t_or_p = 0.5, ring_sizes = c(10:15))

    plot(gr, vertex.size = 3, vertex.label = NA)

## Removing cycles

To remove cycles from a graph, use remove_cycles as the graph edit function.

    gr <- sample_graphette(W, rho_n, "remove_cycles", n = 200)

    plot(gr, vertex.size = 3, vertex.label = NA)

## References

Wijesinghe, Asiri, Sevvandi Kandanaarachchi, Daniel M Steinberg, and Cheng Soon Ong. 2026. “Flowette: Flow Matching with Graphette Priors for Graph Generation.” arXiv Preprint arXiv:2602.23566.