Skip to contents

Alternative to [moneca::moneca_fast()] and [moneca_sbm()] that replaces the clique / SBM step with Infomap (Rosvall & Bergstrom 2008). The Map Equation treats the graph as a stationary random walk and extracts modules that trap flow, which is a natural fit for mobility data where edges are directed transition counts.

Usage

moneca_flow(
  mx,
  backend = "igraph",
  depth = 2L,
  nb_trials = 10L,
  directed = TRUE,
  symmetric_method = c("none", "sum", "min"),
  small.cell.reduction = 0,
  zero_diagonal = TRUE,
  segment.levels = NULL,
  auto_method = c("mdl", "mi_plateau"),
  seed = NULL,
  has_margins = "auto",
  verbose = FALSE,
  ...
)

Arguments

mx

A square mobility matrix, optionally with margins as the last row and column (auto-detected via `has_margins = "auto"`). Sparse `dgCMatrix` input is accepted and converted to dense for the igraph call.

backend

Currently only `"igraph"`. Reserved for a future `"infomap_cpp"` backend that invokes the standalone Infomap C++ binary for true hierarchical optimisation.

depth

Integer in `1:3`. Number of recursion levels to build. `1` is flat; `2` (default) adds one level of within-module re-clustering; `3` adds a further level.

nb_trials

Integer. Number of Infomap trials per call, passed through to `igraph::cluster_infomap()`. Higher values reduce stochastic variation at linear cost.

directed

Logical. If `TRUE` (default), treat the graph as directed (mobility has intrinsic direction). If `FALSE`, the graph is undirected; combine with `symmetric_method = "sum"` or `"min"` to symmetrise the weights explicitly.

symmetric_method

One of `"none"` (default; keep directed), `"sum"` (`mx + t(mx)`), or `"min"` (`2 * pmin(mx, t(mx))`). Applied to the core before the igraph fit.

small.cell.reduction

Numeric. Cells in the core matrix below this value are zeroed before the fit. Mirrors [moneca::moneca_fast()].

zero_diagonal

Logical. If `TRUE` (default), the diagonal of the core is zeroed before the fit (self-loops removed). Set to `FALSE` to preserve self-flows.

segment.levels

Integer, `NULL`, or the string `"auto"`. If `NULL` (default), all levels produced by the recursion are kept. If an integer, the hierarchy is truncated to that many levels. If `"auto"`, the full hierarchy is fit and then [auto_segment_levels()] picks a single preferred level via `auto_method`; the object is trimmed to that level and carries the picker result under `$auto_level`.

auto_method

One of `"mdl"` (default) or `"mi_plateau"`. Ignored unless `segment.levels = "auto"`. With `"mdl"` the criterion is applied to the codelength trace under the hood.

seed

Integer seed for reproducible inference.

has_margins

One of `"auto"` (default), `TRUE`, or `FALSE`. Controls margin detection and appending.

verbose

Logical. If `TRUE`, prints per-level progress messages.

...

Reserved for forward compatibility.

Value

An object of class `"moneca"` with the same structure as [moneca::moneca_fast()] output, plus an extra slot `$flow_diagnostics` describing the backend used, the number of blocks per level, and the codelength trace. The diagnostics slot also carries `mdl_per_level` as an alias of `codelength_per_level` so downstream tooling that keys on `$mdl_per_level` can consume flow output unchanged.

Details

`igraph::cluster_infomap()` returns a flat partition. To expose a hierarchy compatible with moneca's multi-level segment contract, a recursive wrapper re-runs the flat algorithm on each module's induced subgraph for level 2, and optionally once more for level 3 when `depth = 3L`. This is an *approximate* hierarchy: it does not jointly optimise a single hierarchical map equation. For joint-MDL optimisation use the standalone C++ Infomap binary (planned as an optional backend in a future release).

Input is raw mobility counts. No relative-risk transformation is applied; users who want RR-weighted flow clustering should preprocess the matrix themselves, or use [moneca_sbm()] which consumes RR natively via the DC-SBM bridge.

The codelength per level is computed directly from the map equation on the full graph (PageRank-based stationary distribution plus module exit probabilities), not inferred from the sub-module Infomap runs. This ensures `codelength_per_level` is comparable across levels of the recursive hierarchy.

References

Rosvall, M. and Bergstrom, C. T. (2008). Maps of random walks on complex networks reveal community structure. *PNAS*, 105(4), 1118-1123.

See also

[moneca_sbm()], [moneca_bipartite()], [auto_segment_levels()], [moneca::moneca_fast()].

Examples

if (requireNamespace("igraph", quietly = TRUE)) {
  # Small planted-community fixture
  set.seed(42)
  n <- 20
  block <- rep(1:4, each = 5)
  mx <- matrix(rpois(n * n, 0.2), n, n)
  for (k in 1:4) {
    idx <- which(block == k)
    mx[idx, idx] <- mx[idx, idx] + rpois(length(idx)^2, 3)
  }
  diag(mx) <- 0
  fit <- moneca_flow(mx, depth = 2L, seed = 1L)
  fit$flow_diagnostics$codelength_per_level
}
#> [1] 3.766350 3.308539