Stochastic Block Model Prior
The MFM-SBM (mixture of finite mixtures – stochastic block model) edge prior assigns variables to latent clusters and uses cluster-structured inclusion probabilities. The implementation is a translation of the R code accompanying Geng et al. (2019), adapted for the bgms sampler architecture. For the statistical background and usage guidance, see Edge Clustering. Source: src/priors/sbm_edge_prior.h and sbm_edge_prior.cpp.
MFM-SBM formulation
The prior has three levels:
Cluster count — The number of clusters \(K\) follows a shifted-Poisson prior, \(K - 1 \sim \text{Poisson}(\lambda)\) (prior expectation \(1 + \lambda\) clusters), with a mixture-of-finite-mixtures (MFM) correction that accounts for the combinatorial allocation structure.
Cluster assignments — Each variable \(i\) is assigned to cluster \(z_i \in \{1, \ldots, K\}\) with a symmetric Dirichlet prior (concentration \(\alpha_D\)) on the cluster proportions.
Block inclusion probabilities — The inclusion probability for edge \((i, j)\) depends on whether variables \(i\) and \(j\) are in the same cluster:
\[ \pi_{ij} = \begin{cases} \pi_{\text{within}} & \text{if } z_i = z_j \\ \pi_{\text{between}} & \text{if } z_i \neq z_j \end{cases} \]
Within-block and between-block probabilities are drawn from Beta distributions with separate hyperparameters.
Gibbs updates
The update() method in StochasticBlockEdgePrior runs three sequential Gibbs steps:
1. Cluster allocations
block_allocations_mfm_sbm() updates each variable’s cluster assignment \(z_i\) by collapsed Gibbs sampling. For each variable \(i\):
- Remove variable \(i\) from its current cluster
- For each possible cluster \(k\) (including a new cluster), compute the conditional probability based on:
- The MFM allocation prior (CRP-like with log-partition coefficients \(\log V_n\))
- The likelihood of the observed edge indicators between variable \(i\) and all other variables, given the block probabilities
- Sample \(z_i\) from the resulting categorical distribution
The allocation weights are accumulated in log space and max-shifted at the draw for numerical stability. Empty clusters are removed, and the cluster labels are relabeled to be contiguous.
2. Block probabilities
block_probs_mfm_sbm() draws new within-block and between-block inclusion probabilities from their Beta full conditionals:
\[ \pi_{kl} \sim \text{Beta}\bigl(\alpha_{kl} + e_{kl},\; \beta_{kl} + m_{kl} - e_{kl}\bigr) \]
where \(e_{kl}\) is the number of included edges between clusters \(k\) and \(l\), and \(m_{kl}\) is the total number of possible edges. The hyperparameters \(\alpha_{kl}\) and \(\beta_{kl}\) differ for within-block (\(k = l\)) and between-block (\(k \neq l\)) pairs.
3. Inclusion probability matrix
The updated block probabilities are broadcast to the full \(p \times p\) inclusion probability matrix based on the current cluster assignments.
Corrected sweeps on continuous data
On continuous (GGM) and mixed models under the joint graph specification, the sweeps above run in a corrected form: the determinant-tilted precision prior reweights the graph marginal, so the plain collapsed updates would target the wrong block structure (see Edge Priors — Normalizing-constant corrections). The correction enters the SBM locally:
- each allocation move adds a per-edge tilt term, the slope \(f'(d)\) of the correction curve evaluated at a local density \(d\): each endpoint of the edge has an expected degree density under the current block probabilities, and the smaller of the two is the one read;
- the new-cluster collapsed marginal integrates the corrected per-pair curve \(f(\theta)\) over a quadrature grid instead of the plain Beta marginal.
On mixed data the tilt acts on the continuous block only, so the correction terms read continuous-continuous pairs exclusively (a per-node continuous mask is attached); with fewer than two continuous variables the sweeps reduce to the plain updates. Discrete models always use the plain updates. In bgmCompare(), the SBM difference prior is always uncorrected — there is no precision matrix, hence no tilt.
Log partition coefficients
compute_Vn_mfm_sbm() precomputes the log-partition function \(\log V_n(t)\) for \(t = 1, \ldots, t_{\max}\). These coefficients encode the MFM prior on the number of occupied clusters and appear in the allocation Gibbs step. They are computed once at initialization.
The computation involves:
- Poisson probabilities for the total number of components
- Rising factorials (Pochhammer symbols) for the Dirichlet-multinomial allocation counts
- Log-sum-exp accumulation for numerical stability
Hyperparameters
The six SBM hyperparameters are set via the sbm_prior() constructor passed to edge_prior in bgm() or difference_prior in bgmCompare():
| Parameter | sbm_prior() argument |
Default | Role |
|---|---|---|---|
| \(\alpha_w\) | alpha |
1 | Beta shape for within-block inclusion |
| \(\beta_w\) | beta |
1 | Beta shape for within-block inclusion |
| \(\alpha_b\) | alpha_between |
1 | Beta shape for between-block inclusion |
| \(\beta_b\) | beta_between |
1 | Beta shape for between-block inclusion |
| \(\alpha_D\) | dirichlet_alpha |
1 | Dirichlet concentration for cluster proportions |
| \(\lambda\) | lambda |
1 | Rate of the shifted-Poisson prior on the number of clusters (\(K - 1 \sim \text{Poisson}(\lambda)\)) |
All six hyperparameters default to 1; sbm_prior() with no arguments is valid. Validation enforces that all values are positive and finite.
In bgmCompare(), the SBM governs the off-diagonal (pairwise) difference inclusions; the diagonal (main-effect difference inclusions, when main_difference_selection = TRUE) follows a separate Beta-Bernoulli update using the within-cluster alpha and beta. This is the canonical statement of that behavior — the bgmCompare Engine page describes the update mechanics.
Prior simulation
Two exported functions draw from the SBM prior without data:
sample_sbm_prior()makes ancestral draws from the hyperprior alone — a shifted-Poisson number of components, Dirichlet-weighted allocation, and Beta-distributed within/between block probabilities — returning allocations, occupied-block counts, and the implied pair-inclusion probabilities.sample_graph_prior()withedge_prior = sbm_prior(...)additionally draws the edge indicators, either ancestrally (hierarchical specification: the graph marginal is exactly the SBM) or through the zero-data chain (joint specification: the marginal is reweighted by the per-graph normalizer, with the corrected sweeps above).
These are useful for checking what a hyperparameter choice implies about cluster counts and edge densities before fitting.
Output
The cluster allocations at each post-warmup iteration are stored in ChainResult::allocation_samples and accessible via extract_sbm() in R (works on both bgms and bgmCompare fits), which returns:
posterior_num_blocks— posterior distribution over the number of clusters, computed from the sampled allocations through the MFM conditional under the shifted-Poisson priorposterior_mean_allocations— posterior mean cluster assignmentsposterior_mode_allocations— posterior mode cluster assignmentsposterior_mean_coclustering_matrix— proportion of iterations where each pair of variables was in the same cluster