Which null model should I use?

The package implements nine maximum-entropy null models. They differ in the type of network they apply to (undirected/directed/bipartite, binary/weighted) and in the structural information they preserve (degrees, strengths, reciprocity). This page helps you pick the right one; the individual model pages document the mathematics and the API.

Decision tree

  1. Is the network bipartite?BiCM (binary; project afterwards with project).
  2. Is the network undirected?
    • binary → UBCM (degree sequence);
    • weighted, integer weights, degrees and strengths matter → UECM;
    • weighted, continuous weights, strengths conditional on the topology → CReM.
  3. Is the network directed and binary?
    • reciprocity is not a feature you need to preserve → DBCM (out-/in-degree sequences);
    • reciprocity is structurally important → RBCM (non-reciprocated out-/in-degrees and reciprocated degrees).
  4. Is the network directed and weighted?
    • integer weights, degrees and strengths matter → DECM (out-/in-degrees and out-/in-strengths, jointly);
    • continuous weights, reciprocity is not a feature you need to preserve → DCReM (out-/in-strengths conditional on a DBCM topology);
    • continuous weights, reciprocity is structurally important → CRWCM (the four reciprocal strength sequences conditional on an RBCM topology).

Does reciprocity matter for my network?

Directed networks range from fully anti-reciprocal (e.g. food webs, $r_t \approx 0.03$$0.1$ for the bundled demo food webs) to fully reciprocal (e.g. the taro_exchange() gift network, $r_t = 1$). Two quick diagnostics:

using MaxEntropyGraphs
G = MaxEntropyGraphs.Graphs.SimpleDiGraph(rhesus_macaques())

# 1. compare the observed reciprocity with the DBCM baseline
r_obs = reciprocity(G)                     # 0.757
model = DBCM(G); solve_model!(model)
r_dbcm = reciprocity(model)                # 0.561 -> the DBCM *underestimates* reciprocity

# 2. compare information criteria (same n = N(N-1) observations, directly comparable)
rmodel = RBCM(G); solve_model!(rmodel)
AICc(rmodel) < AICc(model)                 # true -> the RBCM wins despite its extra N parameters

If the observed reciprocity sits far from the DBCM expectation (or the RBCM wins on AICc), dyadic patterns are a genuine feature of your network and higher-order analyses (e.g. triadic motifs) should use the reciprocal models — Squartini & Garlaschelli (2011) and Di Vece et al. (2023) show that motif profiles change qualitatively between the DBCM and RBCM benchmarks. The same reasoning carries over to the weighted pair DCReM/CRWCM through the weighted reciprocity $r_w$ (weighted_reciprocity).

Model overview

ModelNetworkConstraints# parameters$a_{ij} \perp a_{ji}$?Weights
UBCMundirected, binary$k_i$$N$(symmetric)
DBCMdirected, binary$k^{out}_i, k^{in}_i$$2N$yes
RBCMdirected, binary$k^{→}_i, k^{←}_i, k^{↔}_i$$3N$no
BiCMbipartite, binary$k_i$ (both layers)$N_⊥ + N_⊤$yes
UECMundirected, weighted$k_i, s_i$$2N$(symmetric)integer
DECMdirected, weighted$k^{out}_i, k^{in}_i, s^{out}_i, s^{in}_i$$4N$yesinteger
CReMundirected, weighted$s_i$ (conditional on UBCM topology)$N$(symmetric)continuous
DCReMdirected, weighted$s^{out}_i, s^{in}_i$ (cond. on DBCM)$2N$yescontinuous
CRWCMdirected, weighted$s^{→}_i, s^{←}_i, s^{↔,out}_i, s^{↔,in}_i$ (cond. on RBCM)$4N$nocontinuous
Conditional (two-step) models

The CReM, DCReM and CRWCM are conditional models: a binary layer (UBCM/DBCM/RBCM respectively) fixes the topology, and the weighted layer places weights on the realised links. Their likelihoods — and therefore their AIC/AICc/BIC values — are conditional on the binary layer, so compare information criteria only within the conditional family (e.g. DCReM vs CRWCM), not against the fully joint UECM/DECM.

Dyadic dependence

Under the RBCM and CRWCM the two directions of a dyad are correlated ($\mathrm{Cov}(a_{ij}, a_{ji}) = p^{↔}_{ij} - \langle a_{ij}\rangle\langle a_{ji}\rangle \neq 0$, and similarly for the weights). The package handles this everywhere it matters: motif expectations are evaluated from the dyadic probabilities (not from Ĝ), the delta-method σₓ includes the covariance cross-terms, and sampling draws whole dyads. Ĝ-based shortcuts that are exact for the independent models would silently be wrong here — which is why e.g. rand(m::RBCM, precomputed=true) is not supported.

Higher-order analysis

Once a model is chosen and solved, the typical pattern-detection workflow is:

  • Binary triadic motifs: observed motifs(G) vs the model expectation motifs(model) (exact for DBCM and RBCM) with analytical z-scores via σₓ, or sampling-based z-scores via motif_zscores.
  • Triadic fluxes (weight circulating on motifs): observed motif_fluxes(G) vs the exact expectation motif_fluxes(model) (DCReM/CRWCM), with sampling z-scores via flux_zscores.
  • Triadic intensities (motif_intensities): observed values plus sampling z-scores via ensemble_zscores (no closed-form expectation exists).

See the Metrics pages for the full analytical/simulation toolkit.

References