## ----include = FALSE----------------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  message = FALSE,
  warning = FALSE
)

## ----setup--------------------------------------------------------------------
library(cograph)
data(student_interactions)

## -----------------------------------------------------------------------------
centrality(student_interactions)

## ----records, echo = FALSE----------------------------------------------------
rec <- function(family, title, key, concept, math, args, meaning,
                grp = FALSE, via_measures = FALSE) {
  ex <- if (key == "bridging_capital") {
    "centrality_bridging_capital(student_interactions, weighted = FALSE)"
  } else if (via_measures) {
    sprintf('centrality(student_interactions, measures = "%s")', key)
  } else {
    sprintf("centrality_%s(student_interactions%s)", key,
            if (grp) ", membership = groups" else "")
  }
  list(family = family, title = title, key = key, concept = concept,
       math = math, args = args, meaning = meaning, example = ex)
}

records <- list(
  rec("Spectral, walk and influence",
      "Trust-PageRank", "trust_pagerank",
      "Replace PageRank's even split of a node's score among its neighbours by a trust-value that mixes how similar the two nodes are with how large the receiver's degree is.",
      r"(TPR_i=\frac{1-\alpha}{n}+\alpha\sum_{j\in N_i}T(i,j)TPR_j,\qquad T(i,j)=(1-k)\frac{s(i,j)}{\sum_{l\in N_j}s(j,l)}+k\frac{d_i}{\sum_{l\in N_j}d_l})",
      "`tpr_alpha`, `tpr_k`, `tpr_decay`, `tpr_tol`, `tpr_max_iter`, `normalized`",
      "A high value indicates a node that receives a large share of a PageRank-style flow in which each node passes more of its score to neighbours that are similar to it and well connected. `tpr_k` sets the balance between similarity and degree, and `tpr_alpha` is the damping factor. A component without triangles returns `NA` with a warning, because the similarity is undefined there."),
  rec("Shortest-path brokerage and flow",
      "Randomized shortest paths (RSP) betweenness", "rsp_betweenness",
      "Count the visits a node gets from walks that lie between shortest paths and pure random walks, with one parameter setting the balance.",
      r"(bet_i=\sum_{s=1}^{n}\sum_{t=1}^{n}\Bigl(\frac{z_{si}}{z_{st}}-\frac{z_{ti}}{z_{tt}}\Bigr)z_{it},\qquad \mathbf{Z}=(\mathbf{I}-\mathbf{W})^{-1},\quad \mathbf{W}=(\mathbf{D}^{-1}\mathbf{A})\circ\exp(-\beta\mathbf{C}))",
      "`rsp_beta`, `rsp_cost`, `normalized`",
      "A high value indicates a node that walks between other pairs of nodes pass through often. `rsp_beta` moves the measure between a random walk (small values; the default 0.01 lies near this end) and shortest-path betweenness (large values). `rsp_cost` sets whether a weight is read as an affinity or as a distance."),
  rec("Neighbourhood structure and cohesion",
      "Degree and importance of lines (DIL)", "dil",
      "Add to a node's degree the share it can claim of the importance of the lines that touch it, where a line matters when its endpoints reach far beyond it and few triangles offer a way round.",
      r"(L_{v_i}=k_i+\sum_{v_j\in\Gamma_i}W_{v_iv_j},\qquad W_{v_iv_j}=I_{e_{ij}}\frac{k_i-1}{k_i+k_j-2},\qquad I_{e_{mn}}=\frac{(k_m-p-1)(k_n-p-1)}{p/2+1})",
      "`normalized`",
      "A high value indicates a node with many ties, several of them important: ties whose endpoints reach far beyond them and that few triangles bypass. The score is at least the node's degree, and equals it in complete graphs and stars."),
  rec("Neighbourhood structure and cohesion",
      "Lhc index", "lhc",
      "Score a node by how much degree, inflated by each contributor's share of the network's triangles, sits within a couple of steps of its neighbours.",
      r"(Lhc(v)=\sum_{w\in\tau(v)}C(w),\qquad C(v)=\sum_{u\in\Phi(v)}\frac{k_u\bigl(1+TP(u)\bigr)}{d^{2}(uv)},\qquad TP(u)=\frac{NTS(u)}{TNTS})",
      "`lhc_radius`, `normalized`",
      "A high value indicates a node whose surroundings, within `lhc_radius` steps (default 2), hold many well-connected nodes that sit on many triangles. A node of modest degree can therefore outscore a busier one if its neighbours are well embedded. On a graph without triangles the index reduces to a distance-discounted sum of degrees."),
  rec("Neighbourhood structure and cohesion",
      "Hybrid characteristic centrality (HCC)", "hcc",
      "Add a node's blended local degree to how late a repeated minimum-degree peel gets round to removing it.",
      r"(HCC(u)=\frac{k^{ex}(u)}{k^{ex}_{\max}}+\frac{pos(u)}{pos_{\max}},\qquad k^{ex}(u)=\delta k(u)+(1-\delta)\!\!\sum_{v\in\phi(u)}\!\!k(v))",
      "`hcc_delta`, `normalized`",
      "A high value indicates a node that combines a high degree, blended with its neighbours' degrees, with a position deep in the network, reached late when low-degree nodes are repeatedly peeled away. `hcc_delta` (default 0.5) weights the node's own degree against its neighbours'. Scores range from 0 to 2."),
  rec("Neighbourhood structure and cohesion",
      "Extended hybrid characteristic centrality (EHCC)", "ehcc",
      "Collect a node's own hybrid characteristic score together with every neighbour's.",
      r"(EHCC(u)=HCC(u)+\sum_{v\in\phi(u)}HCC(v))",
      "`hcc_delta`, `normalized`",
      "A high value indicates a node that, together with its neighbours, scores highly on hybrid characteristic centrality. It rewards nodes with well-connected, deeply embedded neighbours, whatever the node's own position. An isolate scores its own hybrid characteristic centrality."),
  rec("Neighbourhood structure and cohesion",
      "KED method", "ked",
      "Weight the degree by how evenly a node's neighbours carry its local paths, then by how many second-step paths there are.",
      r"(KED(i)=k_i\bigl(1+H_i\bigr)\exp\!\Bigl(\frac{K_i}{N}\Bigr),\qquad H_i=\frac{\sum_{j\in N(i)}-p_j\log p_j}{\log k_i},\quad p_j=\frac{k_j}{K_i},\quad K_i=\sum_{j\in N(i)}k_j)",
      "`normalized`",
      "A high value indicates a node with many neighbours whose onward connections are numerous and evenly spread among them. Scores depend on the number of nodes in the whole graph, so only rankings are comparable across graphs of different size."),
  rec("Neighbourhood structure and cohesion",
      "Local neighbor contribution (LNC)", "lnc",
      "Multiply what a node contributes on its own by what its neighbourhood contributes to it.",
      r"(LNC(i)=\underbrace{d_i\bigl(1-1/d_i\bigr)^{d_i-1}}_{ownCon(i)}\cdot\underbrace{d_i^{2}\frac{\sum_{j\in N(i)}d_j}{n-1}}_{neiCon(i)},\qquad 0^0:=1)",
      "`normalized`",
      "A high value indicates a node with many neighbours that are themselves well connected. A node with a single neighbour scores its neighbour's degree centrality. Scores depend on the number of nodes in the whole graph, so only rankings are comparable across graphs of different size."),
  rec("Spectral, walk and influence",
      "Iterative resource allocation (IRA)", "ira",
      "Give every node one unit of resource, hand it repeatedly to neighbours in proportion to the receiver's centrality, and read the steady state.",
      r"(I(t+1)=AI(t),\quad a_{ij}=\frac{\theta_i^{\alpha}}{\sum_{u\in\Gamma(j)}\theta_u^{\alpha}}\delta_{ij},\quad I(0)=\mathbf{1})",
      "`ira_mass`, `ira_alpha`, `ira_tol`, `ira_max_iter`, `normalized`",
      "A high value indicates a node that accumulates resource when every node repeatedly passes its resource to its neighbours in proportion to their centrality (`ira_mass`, default coreness). The scores of a connected component sum to its number of nodes. On a bipartite component with unequal sides the iteration oscillates, and a warning is raised."),
  rec("Spectral, walk and influence",
      "Improved iterative resource allocation (IIRA)", "iira",
      "The same resource iteration, with each node's share scaled by how much of a spreading process it could actually carry.",
      r"(a_{ij}=\bigl[1-(1-\beta)^{k_i}\bigr]\theta_i\Bigl(\sum_{u\in\Gamma(j)}\theta_u\Bigr)^{-1}\delta_{ij},\quad I(t)=A^{t}\mathbf{1})",
      "`ira_mass`, `iira_beta`, `iira_steps`, `normalized`",
      "A high value indicates a node that accumulates resource when resource is passed to neighbours in proportion to their centrality and to their chance of being reached by a spreading process at rate `iira_beta`. The resource decays over the `iira_steps` iterations, so only the ranking is meaningful, and only within a connected component."),
  rec("Neighbourhood structure and cohesion",
      "Neighborhood (neighbor distance) centrality", "neighbor_distance",
      "Add up a benchmark centrality over the non-backtracking walks that leave the node, discounted once per step.",
      r"(C^n_i(\theta)=\theta_i+\sum_{k=1}^{n}a^k\!\!\sum_{w\in W_k(i)}\!\!\theta_{\mathrm{end}(w)},\quad W_k(i)=\{\text{non-backtracking walks of length }k\text{ from }i\})",
      "`nd_order`, `nd_decay`, `nd_mass`, `normalized`",
      "A high value indicates a node that reaches many central nodes, by `nd_mass` (default degree), within a few steps. Each step of distance is discounted by `nd_decay` (default 0.2), up to `nd_order` steps (default 2). With either set to zero, the score is the base centrality itself."),
  rec("Shortest-path brokerage and flow",
      "Relative-entropy integrated evaluation", "relative_entropy",
      "Turn several indexes into distributions and take the distribution closest to all of them.",
      r"(u_{ji}=C_j(i)/\textstyle\sum_k C_j(k)\ \text{or}\ (1-C_j(i)/\sum_k C_j(k))/\sum_l(1-C_j(l)/\sum_k C_j(k)),\quad w_i=\prod_{j=1}^{m}u_{ji}^{1/m}\Big/\sum_{i}\prod_{j=1}^{m}u_{ji}^{1/m})",
      "`re_indexes`, `re_negative`, `normalized`",
      "A high value indicates a node that ranks highly on several centrality indexes at once. The score is the normalised geometric mean of the indexes chosen with `re_indexes`, and it sums to one over the nodes. A node that scores zero on any one index scores zero overall."),
  rec("Shortest-path brokerage and flow",
      "DK-based gravity model", "dkgm",
      "Degree, k-shell and the stage at which peeling reached the node act together as gravitational mass.",
      r"(k_s^*(i)=k_s(i)+p(i)/(\max_k q(k)+1),\quad DK(i)=k(i)+k_s^*(i),\quad DKGM_i=\sum_{j\ne i,\,d(i,j)\le R}DK(i)DK(j)/d(i,j)^2)",
      "`dkgm_radius`, `normalized`",
      "A high value indicates a node of large mass lying close to other nodes of large mass, where mass combines degree, k-shell and how late in the peeling the node was removed. Only nodes within `dkgm_radius` steps (default 2) contribute. The score depends on the whole graph, so adding a component can change it."),
  rec("Shortest-path brokerage and flow",
      "Mixed gravitational centrality", "mixed_gravity",
      "Core-number mass at the source interacts with degree mass at nearby nodes.",
      r"(MGC_i=k_s(i)\sum_{j:0<d(i,j)\le r}k(j)/d(i,j)^2)",
      "`gravity_radius`, `normalized`",
      "A high value indicates a node deep in the network's core that lies close to many high-degree nodes: the node's own mass is its coreness and its partners' mass is their degree. Only nodes within `gravity_radius` steps (default 3) contribute; a radius of 1 restricts the sum to neighbours."),
  rec("Shortest-path brokerage and flow",
      "Extended mixed gravitational centrality", "extended_mixed_gravity",
      "Sum immediate neighbors' raw mixed gravitational scores.",
      r"(EMGC_i=\sum_{j\in N(i)}k_s(j)\sum_{l:0<d(j,l)\le r}k(l)/d(j,l)^2)",
      "`gravity_radius`, `normalized`",
      "A high value indicates a node whose neighbours have high mixed gravitational centrality. Because the radius is measured from each neighbour, contributions can come from up to `gravity_radius` + 1 steps away (default 3)."),
  rec("Spectral, walk and influence",
      "Multi-characteristics gravity model", "mcgm",
      "Combine degree, coreness and eigenvector features in distance-decaying node interactions.",
      r"(m_i=K_i+\alpha S_i+X_i,\quad \alpha=\max\{\mathrm{med}(K),\mathrm{med}(X)\}/\mathrm{med}(S),\quad MCGM_i=\sum_{j:0<d(i,j)\le R}m_i m_j/d(i,j)^2)",
      "`mcgm_radius`, `mcgm_alpha`, `normalized`",
      "A high value indicates a node of large mass lying close to other nodes of large mass, where mass combines degree, coreness and eigenvector centrality, each scaled to its maximum. `mcgm_alpha` sets the weight of coreness, and only nodes within `mcgm_radius` steps (default 2) contribute."),
  rec("Spectral, walk and influence",
      "SpectralRank", "spectralrank",
      "Outgoing influence after adding a ground node and optional node priors.",
      r"(B=\begin{pmatrix}A+\operatorname{diag}(p)&\mathbf{1}\\\mathbf{1}^{T}&0\end{pmatrix},\quad Bs=\rho(B)s,\quad SR_i=s_i/\max_{j\le n+1}s_j)",
      "`sr_prior`, `directed`, `weighted`, `simplify`, `normalized`",
      "A high value indicates a node with strong outgoing influence, measured by the leading eigenvector of the network augmented with a ground node linked to every node. `sr_prior` adds optional prior information for each node; with the default of zero the score is plain SpectralRank. Transpose the input to measure incoming influence."),
  rec("Spectral, walk and influence",
      "ControlRank", "controlrank",
      "Smallest grounded eigenvalue after pinning each node in turn.",
      r"(CR_i=\lambda_{\min}(((L+L^T)/2)_{-i,-i}),\quad L=\operatorname{diag}(A\mathbf{1})-A)",
      "`directed`, `weighted`, `simplify`, `normalized`",
      "A high value indicates a node whose grounding leaves the rest of the network most tightly coupled, as measured by the smallest eigenvalue of the Laplacian with that node removed. Disconnected undirected graphs score zero at every node."),
  rec("Community and group-based",
      "Map equation centrality", "map_equation",
      "Bits saved by redesigning a fixed module's codebook after silencing a node.",
      r"(MEC(i)=-(s_m-p_i)\log_2((s_m-p_i)/s_m),\quad s_m=\sum_{j\in m}p_j+q_m)",
      "`membership`, `map_flow`, `map_convention`, `damping`, `weighted`, `simplify`, `normalized`",
      "A high value indicates a node whose flow matters to the description of its module: removing it saves many bits in the module's codebook. The partition is supplied through `membership` (one module when `NULL`) and held fixed. `map_convention` sets whether module-exit flow is included, and the conventions can rank nodes differently."),
  rec("Spectral, walk and influence",
      "Node and Neighbor Layer Information", "ninl",
      "Propagate degree volume through a chosen number of neighbor steps.",
      r"(b_i=\sum_{j:d(i,j)\le r}d_j,\quad r=\lceil L\rceil,\quad NINL_p=A^p b)",
      "`ninl_order`, `ninl_radius`, `normalized`",
      "A high value indicates a node surrounded by high-degree nodes. Degrees are first summed within a radius and then propagated through `ninl_order` steps (default 3). With order 0 the score is the total degree of the node's neighbourhood."),
  rec("Shortest-path brokerage and flow",
      "Localized bridging centrality", "localized_bridging",
      "Brokerage in the one-hop ego network, adjusted for neighbor degrees.",
      r"(LBC(v)=B_{G[N_{\leq1}(v)]}(v)\,\frac{1/d_v}{\sum_{u\in N(v)}1/d_u})",
      "`normalized`",
      "A high value indicates a node that brokers among its immediate neighbours and has few ties itself while its neighbours have many. The score is betweenness within the node's one-step neighbourhood, multiplied by the bridging coefficient. Isolates and leaves score zero."),
  rec("Shortest-path brokerage and flow",
      "Extended local bridging centrality", "extended_local_bridging",
      "Brokerage in the two-hop ego network, adjusted for neighbor degrees.",
      r"(LBC_2(v)=B_{G[N_{\leq2}(v)]}(v)\,\frac{1/d_v}{\sum_{u\in N(v)}1/d_u})",
      "`normalized`",
      "A high value indicates a node that brokers within its two-step neighbourhood and has few ties itself while its neighbours have many. The score is betweenness within the subgraph of nodes up to two steps away, multiplied by the bridging coefficient."),
  rec("Directed prestige and hierarchy",
      "BG-index (beta power)", "beta_measure",
      "Expected number of times a node is selected as a predecessor.",
      r"(\beta^+(i)=\sum_{i\to j}1/d^-(j),\quad\beta^-(i)=\sum_{j\to i}1/d^+(j))",
      "`beta_direction`, `normalized`",
      "A high value indicates a node that is the sole predecessor, or one of few, of many others: each node divides one unit equally among the nodes that point to it. The default credits senders; `beta_direction = \"negative\"` credits receivers. The two coincide on undirected graphs."),
  rec("Spectral, walk and influence",
      "Expected Force", "expected_force",
      "Entropy of onward transmission opportunities after two infection events.",
      r"(ExF(i)=-\sum_{j=1}^{J}p_j\log p_j,\quad p_j=D_j/\sum_kD_k)",
      "`normalized`",
      "A high value indicates a node from which an infection has many, and varied, ways to spread after its first two transmissions. The score is the entropy of these spreading opportunities."),
  rec("Spectral, walk and influence",
      "Modified Expected Force", "modified_expected_force",
      "Expected Force adjusted for the seed degree.",
      r"(ExF^M(i)=\log(\alpha d_i)ExF(i),\quad\alpha>1)",
      "`exf_alpha`, `normalized`",
      "Expected force weighted by the logarithm of the node's degree, so that among nodes with similar spreading opportunities the better-connected one scores higher. `exf_alpha` (default 2, and greater than 1) scales the degree inside the logarithm."),
  rec("Shortest-path brokerage and flow",
      "Proximal betweenness", "proximal_betweenness",
      "Brokerage at the first or last intermediate vertex of shortest paths.",
      r"(C_{ps}(v)=\sum_{s,t:(v,t)\in E}\sigma_{st}(v)/\sigma_{st})",
      "`proximal_variant`, `normalized`",
      "A high value indicates a node that often lies on shortest paths directly next to one of the endpoints. By default a node is counted as the last intermediary before the destination; `proximal_variant` selects the first after the origin, or both."),
  rec("Spectral, walk and influence",
      "Bridging capital", "bridging_capital",
      "Loss of valued information walks after deleting each outgoing matrix entry.",
      r"(Brid_i=\sum_j\sum_{s,t}v_{st}\sum_{h=1}^{T}[P^h-(P-P_{ij}E_{ij})^h]_{st})",
      "`bridging_steps`, `bridging_values`, `weighted`, `loops`, `simplify`, `normalized`",
      "A high value indicates a node whose outgoing ties carry many of the network's valued information walks, measured by the loss when each tie is removed in turn. Walks of up to `bridging_steps` steps (default 2) are counted, and `bridging_values` weights source-destination pairs. Edge weights are read as transmission probabilities."),
  rec("Neighbourhood structure and cohesion",
      "Coleman-Theil hierarchy", "coleman_theil",
      "Concentration of Burt's dyadic constraints over a node's contacts.",
      r"(H_i=\frac{\sum_{j\in N(i)}r_{ij}\log(r_{ij})}{d_i\log d_i},\quad r_{ij}=c_{ij}/\operatorname{mean}_{k\in N(i)}c_{ik})",
      "`weighted`, `simplify`, `normalized`",
      "A high value indicates that the constraint on a node is concentrated in a few of its contacts. Scores lie between 0 and 1; a node with one contact scores 1 and an isolate 0."),
  rec("Degree, strength and local connectivity",
      "X-degree", "x_degree",
      "Nonbacktracking four-edge walks centered at each node.",
      r"(Xdeg(i)=\left[\sum_{j\in N(i)}(d_j-1)\right]^2-\sum_{j\in N(i)}(d_j-1)^2)",
      "`normalized`",
      "A high value indicates a node at the centre of many non-backtracking four-step walks, a sign that its neighbours connect it to the wider network. Isolates, leaves and every node of a star score zero."),
  rec("Spectral, walk and influence",
      "LineRank", "linerank",
      "Stationary edge-state probabilities aggregated at original endpoints.",
      r"(p=cQ^T p+(1-c)\mathbf{1}/m,\quad LR_v=\sum_{e\text{ incident to }v}p_e)",
      "`damping`, `linerank_aggregation`, `weighted`, `loops`, `simplify`, `normalized`",
      "A high value indicates a node whose ties are visited often by a random walk that moves from tie to tie. Tie probabilities are summed at their end nodes; `linerank_aggregation = \"weight\"` also multiplies them by the tie weights. `damping` is the usual random-walk damping factor."),
  rec("Spectral, walk and influence",
      "Random walk decay", "random_walk_decay",
      "Discounted first arrival at each node, summed over starting-node weights.",
      r"(RWD_v=\sum_u b_u\,\mathbb{E}_u[a^{T_v};T_v<\infty],\quad 0\leq a<1)",
      "`rwd_decay`, `rwd_node_weights`, `weighted`, `loops`, `simplify`, `normalized`",
      "A high value indicates a node that random walks starting elsewhere reach early. Each first arrival is discounted by `rwd_decay` (default 0.5) per step, and starting nodes can be weighted with `rwd_node_weights`. A node's own outgoing ties cannot change its own score."),
  rec("Spectral, walk and influence",
      "Graph regularization centrality", "graph_regularization",
      "Reciprocal retention of a unit impulse under weighted Laplacian smoothing.",
      r"(GRC_i=1/[(I+\gamma L)^{-1}]_{ii},\quad L=D-W,\quad \gamma\geq0)",
      "`grc_gamma`, `weighted`, `normalized`",
      "A high value indicates a node whose signal spreads quickly across the network under Laplacian smoothing, so that little of it is retained at the node. `grc_gamma` (default 1) sets the strength of smoothing. Scores range from 1 to the size of the node's component, and isolates score 1."),
  rec("Spectral, walk and influence",
      "Adaptive LeaderRank", "adaptive_leaderrank",
      "Stationary resource scores with every destination weighted by its original H-index and a ground node with H-index one.",
      r"(h_g=1,\quad w_{ji}=a_{ji}h_i,\quad s_i=\sum_j\frac{w_{ji}}{\sum_k w_{jk}}s_j,\quad \sum_{i\cup g}s_i=N)",
      "`alr_h_mode`, `normalized`",
      "A high value indicates a node that attracts a large share of a random resource flow in which each node sends more to neighbours with a high H-index. `alr_h_mode` sets how H-indices are computed on directed graphs."),
  rec("Spectral, walk and influence",
      "Weighted LeaderRank", "weighted_leaderrank",
      "Stationary resource scores with a ground node that distributes according to original in-degree powers.",
      r"(w_{gi}=(k_i^{in})^{\alpha},\quad w_{ig}=1,\quad s_i=\sum_j\frac{w_{ji}}{\sum_l w_{jl}}s_j,\quad \sum_{i\cup g}s_i=N+1)",
      "`wlr_alpha`, `normalized`",
      "A high value indicates a node that attracts a large share of a random resource flow in which a ground node, linked to every node, sends more to nodes with high in-degree. `wlr_alpha` sets how strongly in-degree is favoured; at zero the measure is ordinary LeaderRank."),
  rec("Distance and closeness",
      "Improved Global Structure Model", "improved_global_structure",
      "Focal degree influence combined with degrees of reachable partners and a distance exponent set by global mean degree.",
      r"(IGSM_i=e^{k_i/N}\sum_{j\ne i}\frac{k_j}{d_{ij}^{a}},\quad a=\lceil\log_2\overline{k}\rceil)",
      "`normalized`",
      "A high value indicates a high-degree node lying close to other high-degree nodes. The distance penalty is set from the network's mean degree, so it is steeper in denser networks. Only reachable nodes contribute."),
  rec("Distance and closeness",
      "Global Structure Model", "global_structure",
      "Focal coreness combined with distance-discounted coreness of all reachable partners.",
      r"(GSM_i=e^{k_s(i)/N}\sum_{j\ne i}\frac{k_s(j)}{d_{ij}})",
      "`normalized`",
      "A high value indicates a node in the network's core that lies close to many other core nodes. Every reachable node contributes, discounted by distance. Isolates score zero."),
  rec("Distance and closeness",
      "Hybrid Global Structure Model", "hybrid_global_structure",
      "Exponential degree-coreness influences with a distance penalty set by their global mean.",
      r"(s_i=e^{k_s(i)k_i/N},\quad a=\lceil\log_2\overline{s}\rceil,\quad H\!GSM_i=s_i\sum_{j\ne i}\frac{s_j}{d_{ij}^{a}})",
      "`normalized`",
      "A high value indicates a node that combines high degree and coreness and lies close to other such nodes. The distance penalty is set from the network's average of these combined masses. Only reachable nodes contribute."),
  rec("Distance and closeness",
      "Exogenous Centrality", "exogenous",
      "Contribution of a node to the base centrality of all other nodes, measured by deleting it.",
      r"(E_i=\sum_{j\ne i}\left[C_G(j)-C_{G-i}(j)\right])",
      "`exogenous_base`, `mode`, `normalized`",
      "A high value indicates a node that contributes much to the centrality of others: removing it lowers their centrality most. The base measure is set with `exogenous_base` (reverse closeness by default, or degree or betweenness). With betweenness, removing a node can raise other scores, so values can be negative."),
  rec("Distance and closeness",
      "Improved Closeness Centrality", "improved_closeness",
      "Closeness adjusted for the number of shortest paths connecting each pair of nodes.",
      r"(ICC_i=\frac{n-1}{\sum_{j\ne i}d_{ij}/\sigma_{ij}^{\alpha}},\quad 0\le\alpha\le1)",
      "`icc_alpha`, `normalized`",
      "A high value indicates a node that is close to others and joined to them by many shortest paths. `icc_alpha` (default 0.2) sets how much multiple shortest paths shorten the effective distance; at 0 the measure is ordinary closeness. Disconnected graphs score zero at every node."),
  rec("Degree, strength and local connectivity",
      "Clustering Degree Algorithm", "cda",
      "Degree and strength adjusted by Barrat weighted clustering, plus weighted contributions from immediate neighbors.",
      r"(PC_i=CD_i+\sum_j\frac{w_{ij}}{w_{\max}}CD_j,\quad CD_i=\frac{\alpha d_i+(1-\alpha)s_i}{1+e^{-C_i^w}})",
      "`cda_alpha`, `weighted`, `simplify`",
      "A high value indicates a node that is well connected and clustered, with neighbours that are too. `cda_alpha` (default 0.5) balances degree against strength. Because weights enter directly, their units matter."),

  rec("Degree, strength and local connectivity",
      "Extended Neighborhood Coreness", "extended_coreness",
      "The sum of neighbors' neighborhood-coreness scores, using core numbers from the original simple undirected graph.",
      r"(C_{nc+}(i)=\sum_{j\in N(i)}\sum_{l\in N(j)}k_s(l)=(A^2 k_s)_i)",
      "—",
      "Rewards access to core-rich neighborhoods. Every length-two walk contributes, including returns to the focal node and multiple walks reaching the same endpoint. Isolates score zero; on a regular graph of degree d it equals d cubed. Other inputs are projected to the simple undirected skeleton."),

  rec("Distance and closeness",
      "Extended Gravity Centrality", "extended_gravity",
      "The sum of immediate neighbors' raw gravity scores, with k-shell masses and hop distances.",
      r"(G^+(i)=\sum_{j\in N(i)}\sum_{l:0<d(j,l)\le r}\frac{k_s(j)k_s(l)}{d(j,l)^2})",
      "`gravity_radius`",
      "A high value indicates a node whose neighbours have high gravity centrality. Because the radius (`gravity_radius`, default 3) is measured from each neighbour, contributions can come from one step beyond it."),

  rec("Spectral, walk and influence",
      "Node Resistance Curvature", "resistance_curvature",
      "A geometric descriptor based on electrical resistance, evaluated separately within each connected component.",
      r"(p_i=1-\frac{1}{2}\sum_{j\sim i}w_{ij}R_{ij})",
      "`weighted`, `simplify`",
      "Low or negative values identify tree-like junctions that hold parts of the network together; higher values indicate nodes with redundant connections. Edge weights are read as conductances. The scores within each connected component sum to one."),

  rec("Spectral, walk and influence",
      "Dynamics-Sensitive Centrality", "dynamics_sensitive",
      "A finite-time linearized spreading score with explicit spreading and recovery rates, on the simple undirected skeleton.",
      r"(S(T)=\sum_{r=0}^{T-1}\beta A[\beta A+(1-\mu)I]^r\mathbf{1})",
      "`ds_beta`, `ds_mu`, `ds_steps`",
      "Higher scores indicate more cumulative spreading activity in this approximation. Values can exceed the number of nodes. Defaults are beta=0.1, mu=1, T=5. Recovery mu=1 recovers finite diffusion; mu=0 selects the SI case. Isolates and horizon zero score zero; overflow raises an error."),

  rec("Degree, strength and local connectivity",
      "Malatya Centrality", "malatya",
      "The sum of a node's degree divided by each neighbour's degree, calculated on the original simple undirected graph.",
      r"(M(i)=\sum_{j\in N(i)}\frac{d_i}{d_j})",
      "—",
      "Favours nodes with many low-degree neighbours. Isolates score zero. On nonisolated vertices the score is exactly the reciprocal of the bridging coefficient; on a regular graph it equals degree."),

  rec("Spectral, walk and influence",
      "Finite-Horizon Diffusion Centrality", "diffusion_centrality",
      "Total weighted walks of lengths 1 through T starting at a node, allowing repeated visits and returns.",
      r"(DC(A;q,T) = \sum_{t=1}^{T}(qA)^t\mathbf{1})",
      "`diffusion_q`, `diffusion_steps`, `weighted`, `loops`, `simplify`",
      "High values indicate more weighted walk activity from the source. Probability interpretation requires entries of qA in [0,1]. Defaults q=1 and T=3 are cograph choices. Directed arcs carry information outwards. Overflow raises an error."),

  rec("Spectral, walk and influence",
      "Dynamical Importance", "dynamical_importance",
      "Relative loss of adjacency spectral radius after removing the node, recomputed directly for each deletion.",
      r"(I_i = \frac{\rho(A)-\rho(A_{-i})}{\rho(A)})",
      "`weighted`, `simplify`",
      "A high value indicates a node whose removal most reduces the network's spectral radius, which governs how easily spreading processes take off. Each deletion is recomputed exactly."),

  rec("Neighbourhood structure and cohesion",
      "Maximal Clique Centrality", "mcc",
      "Sum of factorial contributions from maximal cliques containing the node, on the simple undirected skeleton.",
      r"(MCC(v) = \sum_{C\in\mathcal{M}(v),\,|C|\geq2} (|C|-1)!)",
      "—",
      "Larger cliques contribute much more than edges or triangles. Contained cliques are excluded. Isolates score 0 by explicit convention. Exponential enumeration is held back from the default all tier; raw-score overflow raises an error."),

  rec("Degree, strength and local connectivity",
      "Volume Centrality", "volume",
      "The total original-graph degree inside a closed hop neighbourhood, including its centre.",
      r"(V_r(i) = \sum_{j:\,d(i,j)\leq r,\ d(i,j)<\infty} k_j)",
      "`volume_radius`",
      "Measures connectivity within and leaving the neighbourhood. Radius 0 gives degree, default 2 uses two hops, and infinite radius gives twice the component's edge count. Uses the simple undirected skeleton."),

  rec("Neighbourhood structure and cohesion",
      "Node Truss Number", "truss",
      "The largest truss number of an incident edge, on the simple undirected skeleton.",
      r"(t(v) = \max\{k : v \in V(T_k)\},\quad T_k:\ \text{each edge has at least } k-2\text{ triangles})",
      "—",
      "Higher values indicate triangle-supported cohesion. Tree vertices score 2, a k-clique scores k, and isolates score 0."),

  rec("Neighbourhood structure and cohesion",
      "Mixed Degree Decomposition", "mdd",
      "Shell thresholds from residual degree plus attenuated exhausted degree.",
      r"(k_i^{m} = k_i^{r} + \lambda k_i^{e})",
      "`mdd_lambda`",
      "Higher means membership of a stronger mixed-degree shell. Lambda 0 gives coreness; lambda 1 gives degree. Default 0.7; scores can be fractional."),

  rec("Neighbourhood structure and cohesion",
      "Bridging Coefficient", "bridging_coefficient",
      "The reciprocal-degree ratio before multiplication by betweenness.",
      r"(B(i) = \frac{1/k_i}{\sum_{j\in N(i)}1/k_j})",
      "—",
      "Higher values identify low-degree nodes adjacent to high-degree nodes. Isolates score 0. Uses the simple undirected skeleton."),

  rec("Neighbourhood structure and cohesion",
      "Godfather Index", "godfather",
      "The number of unconnected unordered pairs of a node's neighbours.",
      r"(GF(i) = {k_i\choose 2} - t_i)",
      "—",
      "Higher values indicate more local brokerage opportunities. Here t_i counts focal triangles. Uses the simple undirected skeleton."),

  rec("Neighbourhood structure and cohesion",
      "Supported Relationships", "support",
      "The number of neighbours sharing at least one common neighbour with the node.",
      r"(S(i) = |\{j\in N(i):(A^2)_{ij}>0\}|)",
      "—",
      "Higher values mean more triangle-supported relationships; a relationship counts once even if several common neighbours support it. Uses the simple undirected skeleton."),


  ## ---- Family 1: Degree, strength and local connectivity ----
  rec("Degree, strength and local connectivity",
      "Degree Centrality", "degree",
      "Degree centrality counts the number of direct ties incident on a node. In directed graphs, it can be separated into incoming and outgoing ties.",
      r"(C_D(v) = \sum_{u \in V} a_{vu} = k_v)",
      r"(`mode`, `loops`)",
      "A high degree value indicates many direct observed connections. It is a local measure of connectivity."),

  rec("Degree, strength and local connectivity",
      "Indegree Centrality", "indegree",
      "Indegree counts ties pointing into a node under a directed interpretation.",
      r"(k_v^{\mathrm{in}} = \sum_{u \in V} a_{uv})",
      r"(—)",
      "A high indegree value indicates many incoming observed ties. Its substantive meaning depends on what edge direction represents."),

  rec("Degree, strength and local connectivity",
      "Outdegree Centrality", "outdegree",
      "Outdegree counts ties leaving a node under a directed interpretation.",
      r"(k_v^{\mathrm{out}} = \sum_{u \in V} a_{vu})",
      r"(—)",
      "A high outdegree value indicates many outgoing observed ties. In transition networks, this can mean many possible next states."),

  rec("Degree, strength and local connectivity",
      "Strength Centrality", "strength",
      "Strength centrality is weighted degree: it sums edge weights instead of counting edges.",
      r"(s(v) = \sum_{u \in V} w_{vu})",
      r"(`mode`)",
      "A high strength value indicates high total incident edge weight. This should be interpreted according to how weights were defined."),

  rec("Degree, strength and local connectivity",
      "Instrength Centrality", "instrength",
      "Instrength sums incoming edge weights.",
      r"(s^{\mathrm{in}}(v) = \sum_{u \in V} w_{uv})",
      r"(—)",
      "A high instrength value indicates high total incoming weight. It is a weighted incoming-connectivity measure."),

  rec("Degree, strength and local connectivity",
      "Outstrength Centrality", "outstrength",
      "Outstrength sums outgoing edge weights.",
      r"(s^{\mathrm{out}}(v) = \sum_{u \in V} w_{vu})",
      r"(—)",
      "A high outstrength value indicates high total outgoing weight. Diversity describes how that weight is spread across ties."),

  rec("Degree, strength and local connectivity",
      "Expected Centrality", "expected",
      "Expected centrality sums the degrees of a node's neighbours.",
      r"(C_{\mathrm{exp}}(v) = \sum_{u \in N(v)} k_u)",
      r"(`mode`)",
      "A high value indicates adjacency to well-connected nodes."),

  rec("Degree, strength and local connectivity",
      "Leverage Centrality", "leverage",
      "Leverage centrality compares a node's degree with the degrees of its neighbours.",
      r"(\ell(v) = \frac{1}{k_v} \sum_{u \in N(v)} \frac{k_v - k_u}{k_v + k_u})",
      r"(`mode`)",
      "A positive high value indicates that the node is more connected than its neighbours under this degree comparison."),

  rec("Degree, strength and local connectivity",
      "Lobby Centrality", "lobby",
      "Lobby centrality is the h-index of neighbour degrees.",
      r"(h(v) = \max\bigl\{ h : |\{ u \in \{v\} \cup N(v) : k_u \ge h \}| \ge h \bigr\})",
      r"(`mode`)",
      "A high value indicates many neighbours that themselves have reasonably high degree."),

  rec("Degree, strength and local connectivity",
      "H-Index Strength Centrality", "hindex_strength",
      "H-index strength is a weighted h-index-style neighbourhood measure.",
      r"(h_s(v) = \max\bigl\{ h : |\{ u \in \{v\} \cup N(v) : s(u) \ge h \}| \ge h \bigr\})",
      r"(`mode`)",
      "A high value indicates strong ties to neighbours meeting a weighted connectivity threshold.",
      via_measures = TRUE),

  rec("Degree, strength and local connectivity",
      "Local H-Index Centrality", "local_hindex",
      "Local h-index centrality iteratively applies h-index logic to local neighbourhoods.",
      r"(h^{(t+1)}(v) = \mathcal{H}\bigl(\{ h^{(t)}(u) : u \in N(v) \}\bigr), \quad h^{(0)}(v) = k_v)",
      r"(via `centrality(measures = ...)`)",
      "A high value indicates a locally robust neighbourhood position under the h-index updating rule.",
      via_measures = TRUE),

  rec("Degree, strength and local connectivity",
      "Semi-Local Centrality", "semilocal",
      "Semi-local centrality extends degree-like counting beyond immediate neighbours.",
      r"(C_{SL}(v) = \sum_{u \in N(v)} \sum_{w \in N(u)} \bigl| \{\, x : d(w, x) \le 2 \,\} \bigr|)",
      r"(`mode`)",
      "A high value indicates proximity to a locally well-connected neighbourhood."),

  rec("Degree, strength and local connectivity",
      "ClusterRank Centrality", "clusterrank",
      "ClusterRank combines neighbour degree information with local clustering.",
      r"(C_{CR}(v) = c(v) \sum_{u \in N(v)} \bigl( k_u + 1 \bigr), \quad c(v) = \text{local clustering coefficient})",
      r"(`mode`)",
      "A high value indicates local connectedness adjusted for clustering-related redundancy."),

  rec("Degree, strength and local connectivity",
      "Collective Influence Centrality", "collective_influence",
      "Collective influence combines a node's excess degree with excess degree on a local boundary.",
      r"(\mathrm{CI}_\ell(v) = (k_v - 1) \sum_{u \,\in\, \partial B(v, \ell)} (k_u - 1), \quad \ell = 2)",
      r"(via `centrality(measures = ...)`)",
      "A high value indicates potential importance under the collective influence model.",
      via_measures = TRUE),

  rec("Degree, strength and local connectivity",
      "MNC Centrality", "mnc",
      "Maximum neighbourhood component centrality is the size of the largest connected component in a node's neighbourhood.",
      r"(\mathrm{MNC}(v) = \max_{C \,\in\, \mathcal{C}(G[N(v)])} |C|)",
      r"(`mode`)",
      "A high value indicates that many neighbours belong to one connected local component."),

  rec("Degree, strength and local connectivity",
      "DMNC Centrality", "dmnc",
      "DMNC is a density-adjusted version of maximum neighbourhood component centrality.",
      r"(\mathrm{DMNC}(v) = \frac{E_c}{N_c^{\,\varepsilon}}, \quad \varepsilon = 1.7)",
      r"(`mode`, `dmnc_epsilon`)",
      "A high value indicates a large and dense local neighbour component under the chosen density exponent. Here $E_c$ and $N_c$ are the edges and nodes of the largest component of $G[N(v)]$."),

  rec("Degree, strength and local connectivity",
      "LAC Centrality", "lac",
      "LAC, or local average connectivity, measures connectivity in a node's neighbourhood.",
      r"(\mathrm{LAC}(v) = \frac{1}{k_v} \sum_{u \in N(v)} \deg_{G[N(v)]}(u))",
      r"(`mode`)",
      "A high value indicates that the node's neighbours form a relatively connected local structure."),

  rec("Degree, strength and local connectivity",
      "Gravity Centrality", "gravity",
      "Gravity centrality treats each node's mass as attracting the mass of others over graph distance, and can be truncated at a radius.",
      r"(G(v) = \sum_{u \ne v,\; d(u,v) \le R} \frac{m_v\, m_u}{d(u, v)^2}, \quad m = \text{k-shell or degree})",
      r"(`mode`, `gravity_mass`, `gravity_radius`)",
      "A high value indicates proximity to massive nodes. By default mass is the k-shell and only nodes within three steps contribute; `gravity_mass = \"degree\", gravity_radius = NULL` gives the degree-based gravity model over all reachable nodes, and `gravity_radius = \"auto\"` sets the radius from the network."),

  rec("Degree, strength and local connectivity",
      "Neighborhood Connectivity", "neighborhood_connectivity",
      "Neighborhood connectivity is the mean degree of a node's neighbours (average neighbour degree).",
      r"(C_{NC}(v) = \frac{1}{k_v} \sum_{u \in N(v)} k_u)",
      r"(`mode`)",
      "A high value indicates attachment to hubs. Isolates score 0. Direction is respected under `mode`."),

  rec("Degree, strength and local connectivity",
      "Entropy Variation, Degree", "entropy_variation_degree",
      "Entropy variation is the drop in the Shannon entropy of the degree distribution when the node and its links are removed.",
      r"(EnV_k(i) = I_k(G) - I_k(G - i), \quad I_k(G) = -\sum_j \frac{k_j}{\sum_l k_l} \ln \frac{k_j}{\sum_l k_l})",
      r"(`mode`)",
      "A high value indicates a node whose removal makes the remaining degree distribution more concentrated. Signed; negative values occur.",
      via_measures = TRUE),

  rec("Degree, strength and local connectivity",
      "Flow Coefficient", "flow_coefficient",
      "The flow coefficient is the share of a node's neighbour pairs that are connected only through the node.",
      r"(fc(v) = \frac{|\{(j, k) : j \to v \to k,\ j \not\to k\}|}{k_v (k_v - 1)})",
      r"(—)",
      "A high value indicates a node that mediates local flow. On an undirected graph it equals one minus the clustering coefficient."),

  rec("Degree, strength and local connectivity",
      "Local Entropy", "local_entropy",
      r"(Local entropy sums $-k \log k$ over a node's neighbours.)",
      r"(LE(v) = -\sum_{u \in N(v)} k_u \ln k_u)",
      r"(`mode`)",
      "Always non-positive; a lower (more negative) value indicates a larger, denser neighbourhood. Isolates score 0."),

  rec("Degree, strength and local connectivity",
      "Weighted h-index", "weighted_h_index",
      "The weighted h-index takes the h-index over topological link weights, each neighbour's weight repeated by its degree.",
      r"(h^w_v = H\big(\{k_v k_u \text{ repeated } k_u \text{ times} : u \in N(v)\}\big))",
      r"(`mode`)",
      "A high value indicates a node with many well-connected neighbours. Input edge weights are ignored."),

  rec("Degree, strength and local connectivity",
      "Redundancy", "redundancy",
      "Redundancy is the mean degree of a node's neighbours inside its ego network.",
      r"(r(v) = \frac{2 t_v}{k_v} = k_v - \text{effective size}(v))",
      r"(—)",
      "A high value indicates neighbours that are connected to each other, so fewer structural holes."),

  ## ---- Family 2: Distance and closeness ----
  rec("Distance and closeness",
      "Closeness Centrality", "closeness",
      "Closeness centrality summarises how short a node's paths are to other reachable nodes.",
      r"(C_C(v) = \frac{1}{\sum_{u \ne v} d(v, u)})",
      r"(`mode`)",
      "A high value indicates short graph distances to other nodes. In disconnected graphs, harmonic centrality may be easier to interpret."),

  rec("Distance and closeness",
      "Incloseness Centrality", "incloseness",
      "Incloseness computes closeness over incoming directed paths.",
      r"(C_C^{\mathrm{in}}(v) = \frac{1}{\sum_{u \ne v} d(u, v)})",
      r"(—)",
      "A high value indicates that other nodes can reach the focal node through short directed paths."),

  rec("Distance and closeness",
      "Outcloseness Centrality", "outcloseness",
      "Outcloseness computes closeness over outgoing directed paths.",
      r"(C_C^{\mathrm{out}}(v) = \frac{1}{\sum_{u \ne v} d(v, u)})",
      r"(—)",
      "A high value indicates that the focal node can reach other nodes through short directed paths."),

  rec("Distance and closeness",
      "Harmonic Centrality", "harmonic",
      "Harmonic centrality sums reciprocal shortest-path distances. Unreachable nodes contribute zero.",
      r"(C_H(v) = \sum_{u \ne v} \frac{1}{d(v, u)})",
      r"(`mode`)",
      "A high value indicates broad reach through short paths while handling disconnected components more gracefully than classical closeness."),

  rec("Distance and closeness",
      "Inharmonic Centrality", "inharmonic",
      "Inharmonic centrality computes harmonic centrality over incoming directed paths.",
      r"(C_H^{\mathrm{in}}(v) = \sum_{u \ne v} \frac{1}{d(u, v)})",
      r"(—)",
      "A high value indicates that the node is reachable from many others through short directed paths."),

  rec("Distance and closeness",
      "Outharmonic Centrality", "outharmonic",
      "Outharmonic centrality computes harmonic centrality over outgoing directed paths.",
      r"(C_H^{\mathrm{out}}(v) = \sum_{u \ne v} \frac{1}{d(v, u)})",
      r"(—)",
      "A high value indicates that many nodes can be reached from the focal node through short directed paths."),

  rec("Distance and closeness",
      "Residual Closeness Centrality", "residual_closeness",
      "Residual closeness sums $1 / 2^d$ over shortest-path distances (the focal node contributes $1$).",
      r"(C_R(v) = \sum_{u \in V} 2^{-d(v, u)})",
      r"(`mode`)",
      "A high value indicates many close reachable nodes with rapid distance decay."),

  rec("Distance and closeness",
      "Dangalchev Closeness Centrality", "dangalchev",
      "Dangalchev closeness is the residual-closeness distance-decay measure.",
      r"(C_D(v) = \sum_{u \in V} 2^{-d(v, u)})",
      r"(`mode`)",
      "A high value indicates short-distance reach with distant nodes down-weighted."),

  rec("Distance and closeness",
      "Generalized Closeness Centrality", "generalized_closeness",
      r"(Generalized closeness sums $\\alpha^d$, where $d$ is the shortest-path distance.)",
      r"(C_G(v) = \sum_{u \in V} \alpha^{\,d(v, u)}, \quad \alpha = 0.5)",
      r"(`mode`, `decay_parameter`)",
      "A high value indicates reach under the chosen distance-decay parameter."),

  rec("Distance and closeness",
      "Harary Centrality", "harary",
      "Harary centrality sums inverse squared shortest-path distances.",
      r"(C_{\mathrm{Har}}(v) = \sum_{u \ne v} \frac{1}{d(v, u)^2})",
      r"(`mode`)",
      "A high value indicates many nearby reachable nodes, with distant nodes strongly down-weighted."),

  rec("Distance and closeness",
      "Average Distance Centrality", "average_distance",
      "Average distance centrality summarises mean shortest-path distance from a node (the focal node's $d = 0$ term is included; the centiserve convention divides by $n + 1$).",
      r"(\bar{d}(v) = \frac{\sum_{u \in V} d(v, u)}{n + 1})",
      r"(`mode`)",
      "Lower values indicate shorter average graph distance. The direction of interpretation should be checked because it is a distance quantity."),

  rec("Distance and closeness",
      "Barycenter Centrality", "barycenter",
      "Barycenter centrality is the inverse of the sum of shortest-path distances.",
      r"(C_{\mathrm{Bary}}(v) = \frac{1}{\sum_{u \ne v} d(v, u)})",
      r"(`mode`)",
      "A high value indicates a small total distance to other reachable nodes."),

  rec("Distance and closeness",
      "Wiener Centrality", "wiener",
      "Wiener centrality records total shortest-path distance from a node (unreachable pairs contribute zero).",
      r"(W(v) = \sum_{u \ne v} d(v, u))",
      r"(`mode`)",
      "Lower values indicate shorter total distance. It is better read as distance burden than influence."),

  rec("Distance and closeness",
      "Lin Centrality", "lin",
      "Lin centrality combines reachable nodes and total distance to those nodes.",
      r"(C_{\mathrm{Lin}}(v) = \frac{|R(v)|^2}{\sum_{u \in R(v)} d(v, u)}, \quad R(v) = \{ u \ne v : d(v,u) < \infty \})",
      r"(`mode`)",
      "A high value indicates many reachable nodes through relatively short paths."),

  rec("Distance and closeness",
      "Decay Centrality", "decay",
      "Decay centrality sums reach discounted by distance (the focal node contributes $1$).",
      r"(C_{\delta}(v) = \sum_{u \in V} \delta^{\,d(v, u)}, \quad \delta = 0.5)",
      r"(`mode`, `decay_parameter`)",
      "A high value indicates access to many nodes, especially nearby nodes. The value depends on the decay parameter."),

  rec("Distance and closeness",
      "Radiality Centrality", "radiality",
      "Radiality compares node distances to the graph diameter.",
      r"(\mathrm{Rad}(v) = \frac{\sum_{u \ne v} \bigl( \Delta + 1 - d(v, u) \bigr)}{n - 1})",
      r"(`mode`)",
      "A high value indicates short distances to others relative to overall graph diameter."),

  rec("Distance and closeness",
      "Gil-Schmidt Centrality", "gilschmidt",
      "Gil-Schmidt centrality sums reciprocal distances and normalises by graph size.",
      r"(C_{GS}(v) = \frac{1}{n - 1} \sum_{u \ne v} \frac{1}{d(v, u)})",
      r"(`mode`)",
      "A high value indicates broad reciprocal-distance access to the network."),

  rec("Distance and closeness",
      "Integration Centrality", "integration",
      "Integration centrality is a distance-based measure of how integrated a node is within the graph.",
      r"(\mathrm{Int}(v) = \sum_{u \ne v} \left( 1 - \frac{d(v, u) - 1}{d_{\max}} \right), \quad d(v,u) = d_{\max} + 1 \text{ if unreachable})",
      r"(`mode`)",
      "A high value indicates broad distance-based access to the network."),

  rec("Distance and closeness",
      "Eccentricity Centrality", "eccentricity",
      "Eccentricity is the maximum shortest-path distance from a node to any reachable node.",
      r"(\varepsilon(v) = \max_{u \in V} d(v, u))",
      r"(`mode`)",
      "Lower eccentricity generally indicates smaller worst-case distance. A high value means at least one reachable node is far away."),

  rec("Distance and closeness",
      "Ineccentricity Centrality", "ineccentricity",
      "Ineccentricity computes eccentricity over incoming directed paths.",
      r"(\varepsilon^{\mathrm{in}}(v) = \max_{u \in V} d(u, v))",
      r"(—)",
      "It summarises the largest directed distance from other nodes into the focal node."),

  rec("Distance and closeness",
      "Outeccentricity Centrality", "outeccentricity",
      "Outeccentricity computes eccentricity over outgoing directed paths.",
      r"(\varepsilon^{\mathrm{out}}(v) = \max_{u \in V} d(v, u))",
      r"(—)",
      "It summarises the largest directed distance from the focal node to reachable others."),

  rec("Distance and closeness",
      "Closeness Vitality", "closeness_vitality",
      r"(Closeness vitality measures how total network distance changes when a node is removed, using the Wiener index $W(G) = \\sum_{s, t} d(s, t)$.)",
      r"(\mathrm{CV}(v) = W(G) - W(G \setminus v))",
      r"(`mode`)",
      "A high value indicates that removing the node substantially changes shortest-path structure."),

  rec("Distance and closeness",
      "Entropy Centrality", "entropy",
      "Entropy centrality measures the change in graph entropy associated with a node, from the distribution of finite shortest-path distances after the node is removed.",
      r"(H(v) = -\sum_{w} Y_w \log_2 Y_w, \quad Y_w = \frac{|\{ x : d(w, x) < \infty \}|}{\sum_{w'} |\{ x : d(w', x) < \infty \}|})",
      r"(`mode`)",
      "A high value indicates strong contribution under the graph entropy definition being used."),

  rec("Distance and closeness",
      "Centroid Centrality", "centroid",
      "Centroid centrality compares distance dominance between pairs of nodes.",
      r"(f(v, u) = \gamma(v, u) - \gamma(u, v), \quad \gamma(v, u) = |\{ w : d(v, w) < d(u, w) \}|, \quad C_{\mathrm{cen}}(v) = \min_{u \ne v} f(v, u))",
      r"(`mode`)",
      "A high value indicates a favourable position in pairwise distance comparisons."),

  rec("Distance and closeness",
      "Distance Entropy", "distance_entropy",
      "Distance entropy is the normalised Shannon entropy of a node's hop-distance profile, so it summarises the spread of distances where closeness summarises their mean.",
      r"(h(v) = -\frac{1}{\log(M_v - m_v + 1)} \sum_{k = m_v}^{M_v} p_k \log p_k, \quad p_k = \frac{n_k(v)}{R_v})",
      r"(`mode`)",
      "A high value (up to 1) indicates reach spread evenly across many network layers; 0 means every reachable node sits at the same distance. Hop counts only; weights are ignored."),

  rec("Distance and closeness",
      "Local Dimension", "local_dimension",
      "Local dimension is the growth exponent of the ball around a node: how fast the number of nodes within $r$ hops grows with $r$.",
      r"(D_v = \frac{d \ln B_v(r)}{d \ln r}, \quad B_v(r) = 1 + |\{u : d(v, u) \le r\}|, \; r = 1, \ldots, d_{\max}(v))",
      r"(`mode`)",
      r"(A low value indicates a node that reaches most of the network within a few hops, so lower is more influential. With a single radius the discretised derivative $r\, n_v(r) / B_v(r)$ is reported.)"),

  rec("Distance and closeness",
      "Local Information Dimensionality", "local_information_dimension",
      "Local information dimensionality replaces the ball count of local dimension by its Shannon information and grows the box only to half the node's eccentricity.",
      r"(D^I_v = -\frac{d I_v(l)}{d \ln l}, \quad I_v(l) = -p_v(l) \ln p_v(l), \; p_v(l) = \frac{B_v(l)}{n}, \; l = 1, \ldots, \lceil d_{\max}(v) / 2 \rceil)",
      r"(`mode`)",
      r"(A high value indicates a more influential node. With a single box size the discretised derivative $l (1 + \ln p_v(l))\, n_v(l) / n$ is reported.)"),

  rec("Distance and closeness",
      "Access Information", "access_information",
      "Access information is the mean number of bits a map-less walker needs to reach every other node along shortest paths.",
      r"(A_i = \frac{1}{N} \sum_j S(i \to j), \quad S(i \to j) = -\log_2 \sum_{p(i, j)} \frac{1}{k_i} \prod_{l \in p,\, l \ne i, j} \frac{1}{k_l - 1})",
      r"(—)",
      "A low value indicates a node that reaches the network with few decisions. Hubs score high, because a walker leaving a hub has many links to choose from."),

  rec("Distance and closeness",
      "Hide Information", "hide_information",
      "Hide information is the mean number of bits the rest of the network needs to locate a node.",
      r"(H_i = \frac{1}{N} \sum_j S(j \to i))",
      r"(—)",
      "A high value indicates a hidden, peripheral node; hubs have low hide information."),

  rec("Distance and closeness",
      "Local Dimension, Fixed Radius", "local_dimension_fixed",
      "The Silva-Costa local dimension is the discretised growth exponent of the ball around a node at one chosen radius.",
      r"(D_v(r) = \frac{r\, n_v(r)}{B_v(r)})",
      r"(`mode`, `ld_radius`)",
      "A structural descriptor: higher values mean the neighbourhood is still growing fast at that radius. Nodes with eccentricity below the radius score 0."),

  rec("Distance and closeness",
      "Fuzzy Local Dimension", "fuzzy_local_dimension",
      "Fuzzy local dimension replaces the ball count by a Gaussian-weighted average and takes its log-log slope.",
      r"(N_v(r) = \frac{\sum_{d_{vu} \le r} e^{-d_{vu}^2 / r^2}}{|\{u : d_{vu} \le r\}|}, \quad FLD(v) = \frac{d \log N_v(r)}{d \log r})",
      r"(`mode`)",
      "A high value indicates a more influential node (the opposite orientation to the rest of the dimension family)."),

  rec("Distance and closeness",
      "Local Volume Dimension", "local_volume_dimension",
      "Local volume dimension is the log-log slope of the total degree inside the ball around a node.",
      r"(V_v(l) = \sum_{d_{vu} \le l} k_u, \quad LVD(v) = \frac{d \ln V_v(l)}{d \ln l})",
      r"(`mode`)",
      "A low value indicates a more important node. The source article is closed access; the definition follows the authors' later preprint."),

  rec("Distance and closeness",
      "Heatmap Centrality", "heatmap",
      "Heatmap centrality is a node's farness minus the mean farness of its neighbours.",
      r"(C_{HM}(v) = f(v) - \frac{1}{k_v} \sum_{u \in N(v)} f(u))",
      r"(`mode`)",
      "A low (more negative) value indicates a more central node. Isolates are undefined."),

  rec("Distance and closeness",
      "Geodesic k-path", "geodesic_kpath",
      "Geodesic k-path centrality counts the shortest paths of length at most $k$ that start at a node, with multiplicity.",
      r"(C_k(v) = \sum_{0 < d(v, u) \le k} \sigma(v, u))",
      r"(`mode`, `kpath_k`)",
      "A high value indicates many short geodesics leaving the node. Counting nodes instead of paths gives m-reach, which is what `centiserve::geokpath` computes."),

  rec("Distance and closeness",
      "k-path Census", "kpath",
      "The k-path census counts the simple paths of length at most $k$ that a node lies on, endpoints included.",
      r"(C_{kP}(v) = |\{\, P : |P| \le k,\; v \in P \,\}|)",
      r"(`mode`, `kpath_len`)",
      "A high value indicates a node embedded in many short walks. Length 1 alone reproduces degree. Enumeration is exhaustive, so cost grows with the branching factor to the power $k$."),

  rec("Distance and closeness",
      "Distance-weighted Fragmentation", "fragmentation",
      "Distance-weighted fragmentation asks how much worse the network communicates once a node is deleted.",
      r"(F_d(v) = 1 - \frac{\sum_{i \ne j \ne v} 1 / d_{ij}^{\,G - v}}{(n-1)(n-2)})",
      r"(`mode`)",
      "A high value indicates a node whose removal fragments the network or stretches its distances. A node inside a clique scores near 0."),

  rec("Distance and closeness",
      "Geodesic Power Closeness", "delta_closeness",
      "Geodesic power closeness raises every distance to a negative power, so one exponent moves the measure between a local and a global reading.",
      r"(c_\delta(i) = \frac{1}{n-1} \sum_{j \ne i} d_{ij}^{-\delta})",
      r"(`mode`, `closeness_delta`)",
      r"(A high value indicates a node close to many others. The exponent spans the family: $\delta = 1$ is harmonic centrality over $n-1$, $\delta = 2$ is the inverse-square sum, a large $\delta$ approaches degree, and $\delta = 0$ counts the reachable set. Unreachable nodes contribute nothing but stay in the denominator.)"),

  ## ---- Family 3: Shortest-path brokerage and flow ----
  rec("Shortest-path brokerage and flow",
      "Betweenness Centrality", "betweenness",
      "Betweenness centrality measures how often a node lies on shortest paths between other pairs of nodes.",
      r"(C_B(v) = \sum_{s \ne v \ne t} \frac{\sigma_{st}(v)}{\sigma_{st}})",
      r"(—)",
      "A high value is consistent with a bridge or brokerage position under the shortest-path model."),

  rec("Shortest-path brokerage and flow",
      "Stress Centrality", "stress",
      "Stress centrality counts shortest paths passing through a node without fractional normalization across tied paths.",
      r"(C_S(v) = \sum_{s \ne v \ne t} \sigma_{st}(v))",
      r"(—)",
      "A high value indicates that many shortest paths include the node."),

  rec("Shortest-path brokerage and flow",
      "Load Centrality", "load",
      "Load centrality distributes shortest-path load across alternative shortest routes: at each branch point a unit packet is split evenly among next hops on shortest paths.",
      r"(C_L(v) = \sum_{s \ne v \ne t} \mathrm{load}_{st}(v))",
      r"(—)",
      "A high value indicates that a node carries a large share of geodesic routing load."),

  rec("Shortest-path brokerage and flow",
      "Length-scaled Betweenness", "length_scaled_betweenness",
      "Length-scaled betweenness counts the same brokered pairs as betweenness but weights each pair by the reciprocal of its distance.",
      r"(C_{LS}(v) = \sum_{s \ne v \ne t} \frac{1}{d(s,t)} \cdot \frac{\sigma_{st}(v)}{\sigma_{st}})",
      r"(—)",
      "A high value indicates brokerage between pairs that were already close, which ordinary betweenness treats the same as brokerage across the graph."),

  rec("Shortest-path brokerage and flow",
      "Distance-decayed Betweenness", "delta_betweenness",
      "Distance-decayed betweenness discounts each brokered pair by a power of its distance, so the exponent tunes how local the measure is.",
      r"(C_\delta(v) = \sum_{s \ne v \ne t} (d(s,t) - 1)^{-\delta} \cdot \frac{\sigma_{st}(v)}{\sigma_{st}})",
      r"(`betweenness_delta`)",
      "A high value indicates brokerage concentrated among nearby pairs. At $\\delta = 0$ the measure is ordinary betweenness. Adjacent pairs have no intermediary, so the singularity at $d = 1$ is avoided."),

  rec("Shortest-path brokerage and flow",
      "Ego Betweenness", "ego_betweenness",
      "Ego betweenness is betweenness computed inside a node's own ego network.",
      r"(C_{EB}(v) = \sum_{i < j \in N(v),\; A_{ij} = 0} \frac{1}{(A^2)_{ij}})",
      r"(—)",
      "A high value indicates a node that brokers among its own neighbours, which is what an egocentric survey can measure. A node with fewer than two neighbours scores 0."),

  rec("Shortest-path brokerage and flow",
      "Bottleneck Centrality", "bottleneck",
      "Bottleneck centrality counts cases where a node is critical in shortest-path tree structures.",
      r"(\mathrm{BN}(v) = \sum_{s \in V} p_s(v), \quad p_s(v) = 1 \text{ if } v \text{ carries} > \tfrac{n}{4} \text{ of the shortest-path tree } T_s)",
      r"(`mode`)",
      "A high value indicates frequent bottleneck position in local shortest-path trees."),

  rec("Shortest-path brokerage and flow",
      "Bridging Centrality", "bridging",
      "Bridging centrality combines betweenness with a bridging coefficient.",
      r"(\mathrm{Br}(v) = C_B(v) \cdot \beta(v), \quad \beta(v) = \frac{1/k_v}{\sum_{u \in N(v)} 1/k_u})",
      r"(—)",
      "A high value indicates a possible bridge position between locally distinct areas."),

  rec("Shortest-path brokerage and flow",
      "Local bridging (legacy degree product)", "local_bridging",
      "Inverse focal degree multiplied by the bridging coefficient.",
      r"(\mathrm{LBr}(v) = \frac{1}{k_v} \cdot \beta(v), \quad \beta(v) = \frac{1/k_v}{\sum_{u \in N(v)} 1/k_u})",
      r"(—)",
      "Retains the original cograph degree-only score. The formula uses degrees only."),

  rec("Shortest-path brokerage and flow",
      "Percolation Centrality", "percolation",
      "Percolation centrality weights shortest-path brokerage by node states in a percolation process.",
      r"(\mathrm{PC}(v) = \frac{1}{n - 2} \sum_{s \ne v \ne t} \frac{\sigma_{st}(v)}{\sigma_{st}} \cdot \frac{x_s}{\sum_{i \ne v} x_i})",
      r"(`states`)",
      "A high value indicates state-dependent path importance under the supplied state vector $x$."),

  rec("Shortest-path brokerage and flow",
      "Flow Betweenness Centrality", "flow_betweenness",
      "Flow betweenness measures brokerage through maximum flows between pairs of nodes.",
      r"(C_{FB}(v) = \sum_{s \ne v \ne t} f_{st}(v), \quad f_{st}(v) = \text{flow through } v \text{ in a max } s\text{-}t \text{ flow})",
      r"(—)",
      "A high value indicates importance for potential flow capacity between other nodes under the graph model."),

  rec("Shortest-path brokerage and flow",
      "Current-Flow Betweenness Centrality", "current_flow_betweenness",
      "Current-flow betweenness measures how much electrical current between node pairs passes through a node.",
      r"(C_{CFB}(v) = \frac{1}{(n - 1)(n - 2)} \sum_{s \ne t} \tau_{st}(v), \quad \tau_{st}(v) = \text{current through } v)",
      r"(—)",
      "A high value indicates an intermediary position under an all-path current-flow model."),

  rec("Shortest-path brokerage and flow",
      "Current-Flow Closeness Centrality", "current_flow_closeness",
      "Current-flow closeness measures closeness with effective-resistance distances, treating the network as an electrical circuit.",
      r"(C_{CFC}(v) = \frac{n - 1}{\sum_{u \ne v} R_{vu}}, \quad R_{vu} = \text{effective resistance between } v \text{ and } u)",
      r"(—)",
      "A high value indicates closeness under an all-path flow model. It generally requires connected graphs."),

  rec("Shortest-path brokerage and flow",
      "Entropy Variation, Betweenness", "entropy_variation_betweenness",
      "Entropy variation of the betweenness distribution: the drop in its Shannon entropy when the node is removed.",
      r"(EnV_b(i) = I_b(G) - I_b(G - i))",
      r"(—)",
      "A high value indicates a node whose removal concentrates shortest-path traffic on fewer nodes. Betweenness is recomputed per removal.",
      via_measures = TRUE),

  ## ---- Family 4: Spectral, walk and influence ----
  rec("Spectral, walk and influence",
      "Eigenvector Centrality", "eigenvector",
      "Eigenvector centrality gives high scores to nodes connected to other high-scored nodes.",
      r"(A\,\mathbf{x} = \lambda_{\max}\,\mathbf{x}, \quad C_E(v) = x_v)",
      r"(—)",
      "A high value indicates embeddedness in a central neighbourhood. Reading it as influence requires a relation that transmits influence."),

  rec("Spectral, walk and influence",
      "PageRank Centrality", "pagerank",
      "PageRank is a damped random-walk centrality. Nodes score highly when a random walker reaches them often.",
      r"(\mathrm{PR}(v) = \frac{1 - \alpha}{n} + \alpha \sum_{u \,:\, u \to v} \frac{\mathrm{PR}(u)}{k_u^{\mathrm{out}}}, \quad \alpha = 0.85)",
      r"(`damping`, `personalized`)",
      "A high value indicates random-walk prominence under the chosen damping, direction, and weight conventions."),

  rec("Spectral, walk and influence",
      "Authority Centrality", "authority",
      "Authority centrality is part of HITS. Authorities are nodes pointed to by good hubs.",
      r"(\mathbf{a} = A^{\top} \mathbf{h}, \quad \mathbf{h} = A\,\mathbf{a} \;\Rightarrow\; \mathbf{a} = \text{principal eigenvector of } A^{\top} A)",
      r"(—)",
      "A high value indicates incoming support from nodes that point to good authorities."),

  rec("Spectral, walk and influence",
      "Hub Centrality", "hub",
      "Hub centrality is the HITS counterpart to authority. Hubs point to good authorities.",
      r"(\mathbf{h} = \text{principal eigenvector of } A\,A^{\top})",
      r"(—)",
      "A high value indicates outgoing ties to high-authority nodes."),

  rec("Spectral, walk and influence",
      "SALSA Centrality", "salsa",
      "SALSA is a stochastic link-analysis method related to HITS for directed graphs.",
      r"(\mathbf{a} = \text{principal eigenvector of } A_c^{\top} A_r, \quad A_r, A_c = \text{row- and column-normalised } A)",
      r"(—)",
      "A high value indicates directed authority under the SALSA random-walk model."),

  rec("Spectral, walk and influence",
      "LeaderRank Centrality", "leaderrank",
      "LeaderRank is a PageRank-like directed ranking method that adds a ground node $g$ linked both ways to every node; the stationary random-walk mass on $g$ is then redistributed equally.",
      r"(\mathbf{s}^{*} = \text{stationary distribution of the walk on } G \cup \{g\}, \quad C(v) = s^{*}_v + \tfrac{1}{n} s^{*}_g)",
      r"(—)",
      "A high value indicates directed prestige under the LeaderRank model."),

  rec("Spectral, walk and influence",
      "Alpha Centrality", "alpha",
      "Alpha centrality is an eigenvector-like measure that includes exogenous input.",
      r"(\mathbf{x} = (I - \alpha A^{\top})^{-1} \mathbf{e})",
      r"(`mode`)",
      "A high value indicates recursive prominence under the chosen attenuation and exogenous assumptions."),

  rec("Spectral, walk and influence",
      "Bonacich Power Centrality", "power",
      r"(Bonacich power centrality scores nodes using the centrality of their neighbours and a parameter $\\beta$ controlling dependence.)",
      r"(\mathbf{c}(\alpha, \beta) = \alpha (I - \beta A)^{-1} A\,\mathbf{1})",
      r"(`mode`)",
      "A high value indicates a favourable recursive position under the selected Bonacich parameterization."),

  rec("Spectral, walk and influence",
      "Katz Centrality", "katz",
      "Katz centrality counts walks from all nodes to a focal node, attenuating longer walks.",
      r"(\mathbf{x} = (I - \alpha A^{\top})^{-1} \mathbf{1}, \quad \alpha = 0.1)",
      r"(`katz_alpha`)",
      "A high value indicates that many short and longer walks reach the node. The attenuation parameter must be valid for the graph."),

  rec("Spectral, walk and influence",
      "Hubbell Centrality", "hubbell",
      "Hubbell centrality is an input-output centrality where status is recursively reinforced through ties.",
      r"(\mathbf{x} = (I - w W)^{-1} \mathbf{1}, \quad w = 0.5,\; W = \text{weighted adjacency})",
      r"(`hubbell_weight`)",
      "A high value indicates recursive prominence under the chosen weight factor. Some parameter settings make the system singular."),

  rec("Spectral, walk and influence",
      "Subgraph Centrality", "subgraph",
      "Subgraph centrality measures participation in closed walks, with shorter closed walks weighted more strongly.",
      r"(\mathrm{SC}(v) = \sum_{k=0}^{\infty} \frac{(A^k)_{vv}}{k!} = (e^{A})_{vv})",
      r"(—)",
      "A high value indicates embeddedness in many closed walk structures."),

  rec("Spectral, walk and influence",
      "Laplacian Centrality", "laplacian",
      "Laplacian centrality measures a node's contribution to the graph's Laplacian energy.",
      r"(C_L(v) = \frac{E_L(G) - E_L(G \setminus v)}{E_L(G)}, \quad E_L(G) = \sum_i \mu_i^2 \;\; (\mu_i = \text{Laplacian eigenvalues}))",
      r"(—)",
      "A high value indicates a large local structural contribution under the Laplacian energy definition."),

  rec("Spectral, walk and influence",
      "Communicability Centrality", "communicability",
      "Communicability centrality uses the matrix exponential to summarise walk-based communication potential.",
      r"(C_{\mathrm{Comm}}(v) = \sum_{u \in V} (e^{A})_{vu})",
      r"(—)",
      "A high value indicates many walk-based routes to other nodes, with shorter walks weighted more strongly."),

  rec("Spectral, walk and influence",
      "Communicability Betweenness Centrality", "communicability_betweenness",
      "Communicability betweenness measures walk-based communicability between other pairs through a node.",
      r"(C_{CB}(v) = \frac{1}{(n-1)(n-2)} \sum_{s \ne t \ne v} \frac{G_{st} - G_{st}^{(v)}}{G_{st}}, \quad G = e^{A})",
      r"(—)",
      "A high value indicates a node that lies on many walks between other nodes. $G^{(v)}$ is computed with $v$ removed."),

  rec("Spectral, walk and influence",
      "Random Walk Centrality", "random_walk",
      "Random walk centrality uses expected random-walk access times as distances.",
      r"(C_{RW}(v) = \frac{1}{\sum_{u \ne v} \tilde{m}_{vu}}, \quad \tilde{m}_{vu} = \tfrac{1}{2}\bigl( m_{vu} + m_{uv} \bigr))",
      r"(—)",
      "A high value indicates that the node is reached efficiently under a random-walk process. $m_{uv}$ is the mean first-passage time."),

  rec("Spectral, walk and influence",
      "Markov Centrality", "markov",
      "Markov centrality is based on mean first-passage times in a Markov process on the graph.",
      r"(C_{\mathrm{Mk}}(v) = \frac{1}{\frac{1}{n} \sum_{u} m_{uv}}, \quad m_{uv} = \text{mean first-passage time } u \to v)",
      r"(—)",
      "A high value indicates that the node is reached quickly on average under the Markov process."),

  rec("Spectral, walk and influence",
      "Immediate Effects Centrality (IEC)", "iec",
      "Score a node by how quickly everyone else's influence reaches it, along a chain in which every actor also listens to itself.",
      r"(c_{IEC}(j)=\Bigl(\frac{\sum_{i \ne j} m_{ij}}{n-1}\Bigr)^{-1},\qquad \mathbf{M}=(\mathbf{I}-\mathbf{Z}+\mathbf{E}\mathbf{Z}_{dg})\operatorname{diag}(1/c),\qquad \mathbf{Z}=(\mathbf{I}-\mathbf{W}+\mathbf{1}c')^{-1})",
      "`normalized`",
      "A high value indicates a node that the influence of all other nodes reaches quickly, through short chains of influence. The score is defined only when every node can reach every other; otherwise every node returns `NA` with a warning."),

  rec("Spectral, walk and influence",
      "Second-Order Centrality", "second_order",
      "Second-order centrality summarises variability in random-walk return times.",
      r"(\mathrm{SO}(v) = \operatorname{sd}_{u}\bigl( m_{uv} \bigr))",
      r"(via `centrality(measures = ...)`)",
      "The statistic describes the variability of a random walk's return times to the node; lower values are more central.",
      via_measures = TRUE),

  rec("Spectral, walk and influence",
      "Information Centrality", "information",
      "Information centrality measures centrality through resistance distance, the information carried by all paths between two nodes.",
      r"(C_I(v) = \left( C_{vv} + \frac{T - 2 R_v}{n} \right)^{-1}, \quad C = (D - A + J)^{-1},\; T = \operatorname{tr} C,\; R_v = \textstyle\sum_j C_{vj})",
      r"(—)",
      "A high value indicates a central position under the information-flow model."),

  rec("Spectral, walk and influence",
      "Nonbacktracking Centrality", "nonbacktracking",
      "Nonbacktracking centrality scores nodes using walks that do not immediately return along the edge just traversed (the Hashimoto matrix $B$).",
      r"(B_{(i \to j),\,(k \to l)} = \delta_{jk}\,(1 - \delta_{il}), \quad C(v) \propto \text{aggregated leading eigenvector of } B)",
      r"(via `centrality(measures = ...)`)",
      "A high value indicates walk-based prominence after reducing immediate backtracking inflation.",
      via_measures = TRUE),

  rec("Spectral, walk and influence",
      "Diffusion Degree", "diffusion",
      "The default method adds the scaled degree of the focal node and its neighbours. On a simple undirected graph:",
      r"(DD(i) = \lambda\left(k_i + \sum_{j\in N(i)} k_j\right))",
      r"(`mode`, `lambda`, `diffusion_method`)",
      "High values indicate local connectivity through the node and its neighbours. With `diffusion_method = \"power_series\"` (automatic for TNA inputs), the function instead returns row sums of W + W^2 + ... + W^n. That variant fixes the horizon at n and ignores `lambda` and `mode`."),

  rec("Spectral, walk and influence",
      "Infection Centrality", "infection",
      "Infection centrality estimates spreading potential through infection-style self-avoiding walks with attenuation.",
      r"(\mathrm{Inf}(v) = \sum_{d=1}^{L} \beta^{\,d+1} (1 - \mu)^{d}\, w_d(v), \quad \beta = 0.8,\; \mu = 0,\; L = 6)",
      r"(via `centrality(measures = ...)`)",
      "A high value indicates a favourable position under the assumed infection process. $w_d(v)$ counts length-$d$ self-avoiding walks from $v$.",
      via_measures = TRUE),

  rec("Spectral, walk and influence",
      "Edge Percolated Component", "epc",
      "The edge percolated component averages the size of the component a node ends up in when edges survive at random.",
      r"(\mathrm{EPC}(v) = \frac{1}{R\,n} \sum_{r=1}^{R} |C_r(v)|, \quad \Pr(\text{edge survives}) = 1 - t)",
      r"(`epc_threshold`, `epc_runs`, `epc_seed`)",
      "A high value indicates a node that stays connected to a large share of the network under random link failure. The value is a Monte Carlo estimate; set `epc_seed` to make it reproducible."),

  rec("Spectral, walk and influence",
      "VoteRank Centrality", "voterank",
      "VoteRank is an iterative voting algorithm for ranking spreader candidates: each round the highest-voted node is selected, its voting ability is zeroed, and its neighbours' voting abilities are reduced.",
      r"()",
      r"(—)",
      "A high value indicates early selection by the VoteRank rule."),

  rec("Spectral, walk and influence",
      "Expected Influence 1-Step", "expected_influence_1",
      "Expected influence 1-step sums signed edge weights adjacent to a node.",
      r"(\mathrm{EI}_1(v) = \sum_{u \in V} W_{vu}, \quad W = \text{signed weight matrix})",
      r"(`mode`)",
      "A high positive value indicates strong positive immediate signed connectivity. This is mainly meaningful for signed networks."),

  rec("Spectral, walk and influence",
      "Expected Influence 2-Step", "expected_influence_2",
      "Expected influence 2-step extends signed influence to one- and two-step paths.",
      r"(\mathrm{EI}_2(v) = \mathrm{EI}_1(v) + \sum_{u \in V} W_{vu}\,\mathrm{EI}_1(u))",
      r"(`mode`)",
      "A high positive value indicates positive signed connectivity through direct and indirect paths. Interpretation requires a signed network."),

  rec("Spectral, walk and influence",
      "Spanning Tree Centrality", "spanning_tree",
      "Spanning tree centrality summarises a node's contribution across spanning-tree structures via the Laplacian pseudoinverse $L^{+}$.",
      r"(\mathrm{ST}(v) = \frac{1}{L^{+}_{vv}}, \quad L^{+} = \text{Moore-Penrose pseudoinverse of } L)",
      r"(via `centrality(measures = ...)`)",
      "A high value indicates structural participation across many tree-like ways of connecting the graph.",
      via_measures = TRUE),

  rec("Spectral, walk and influence",
      "Shapley Value, Game 1", "shapley_game1",
      "Shapley value of the node in the coalition game whose worth is the number of nodes a coalition covers within one hop.",
      r"(SV_1(v) = \sum_{u \in \{v\} \cup N(v)} \frac{1}{1 + k_u})",
      r"(—)",
      "A high value indicates a node whose presence adds much one-hop coverage to a typical coalition. Values sum to $n$."),

  rec("Spectral, walk and influence",
      "Shapley Value, Game 2", "shapley_game2",
      "Shapley value in the game where a node is covered once at least $k$ coalition members are adjacent to it.",
      r"(SV_2(v) = \min\!\left(1, \frac{k}{1 + k_v}\right) + \sum_{u \in N(v)} \max\!\left(0, \frac{k_u - k + 1}{k_u (1 + k_u)}\right))",
      r"(`shapley_k`)",
      "A high value indicates a node that helps push many neighbours over the $k$-neighbour threshold. With $k = 1$ this is game 1."),

  rec("Spectral, walk and influence",
      "Shapley Value, Game 3", "shapley_game3",
      "Shapley value in the game where a coalition covers every node within a hop cutoff.",
      r"(SV_3(v) = \sum_{u \in \{v\} \cup N_d(v)} \frac{1}{1 + |N_d(u)|}, \quad N_d(u) = \{w : d(u, w) \le d_{cut}\})",
      r"(`shapley_cutoff`)",
      "A high value indicates a node that reaches many otherwise hard-to-reach nodes within the cutoff. With cutoff 1 this is game 1."),

  rec("Spectral, walk and influence",
      "Rumor Centrality", "rumor",
      "Rumor centrality counts the spreading orders that could have started at a node; on a general graph it is evaluated on the node's breadth-first tree.",
      r"(\log R(v) = \log N! - \sum_{u} \log T^v_u)",
      r"(—)",
      "A high value indicates a plausible origin of a spread, typically a node near the centre. Returned on the log scale."),

  rec("Spectral, walk and influence",
      "DegreeDiscountIC", "degree_discount",
      "DegreeDiscountIC is the greedy seed-selection order under degree discounting for the independent-cascade model.",
      r"(dd_v = d_v - 2 t_v - (d_v - t_v)\, t_v\, p)",
      r"(`discount_p`)",
      "A high score indicates an early selection: the first node selected scores 1, the last $1/n$. Ties follow node order."),

  rec("Spectral, walk and influence",
      "SingleDiscount", "single_discount",
      "SingleDiscount is the greedy seed-selection order where each neighbour of a new seed discounts its degree by one.",
      r"(dd_v = d_v - t_v)",
      r"(—)",
      "A high score indicates an early selection. Equivalent to repeatedly removing the highest-degree node."),

  rec("Spectral, walk and influence",
      "NCVoteRank", "ncvoterank",
      "NCVoteRank is VoteRank with each voter's ability weighted by its normalised neighbourhood coreness, and two-hop weakening after each election.",
      r"(s_u = \sum_{v \in N(u)} va_v \,[\theta + (1 - \theta)\, nc_v])",
      r"(`ncvote_theta`)",
      "A high score indicates an early election. With $\\theta = 1$ and two-hop weakening switched off, this is VoteRank."),

  rec("Spectral, walk and influence",
      "WVoteRank", "wvoterank",
      "WVoteRank is VoteRank for weighted graphs: votes are weighted by edge weight and the score takes a square root.",
      r"(s_v = \sqrt{k_v \sum_{u \in N(v)} va_u w_{vu}})",
      r"(—)",
      r"(A high score indicates an early election. Neighbours of an elected node lose $1/\langle w \rangle$, with $\langle w \rangle$ the average strength.)"),

  rec("Spectral, walk and influence",
      "EnRenew", "enrenew",
      "EnRenew elects the node whose neighbours supply the most entropy, then renews the entropies around it.",
      r"(E_v = \sum_{u \in N(v)} -p_{uv} \ln p_{uv}, \quad p_{uv} = \frac{k_u}{\sum_{l \in N(v)} k_l})",
      r"(`enrenew_depth`)",
      r"(A high score indicates an early election. Terms within the renewal radius are scaled by $1 - 1/(2^{d-1} \ln\langle k \rangle)$.)"),

  rec("Spectral, walk and influence",
      "VoteRank++", "voterank_plus",
      "VoteRank++ starts abilities from degree, splits votes in proportion to neighbour degree, and suppresses abilities multiplicatively after each election.",
      r"(s_v = \sqrt{k_v \sum_{u \in N(v)} va_u\, w_{u \to v}}, \quad va_v^{(0)} = \ln(1 + k_v / k_{\max}))",
      r"(`voterank_lambda`)",
      r"(A high score indicates an early election. Abilities are multiplied by $\lambda$ one step away and $\sqrt{\lambda}$ two steps away.)"),

  rec("Spectral, walk and influence",
      "Node Contraction", "node_contraction",
      "Node contraction importance measures how much the network's cohesion rises when a node and its neighbours are merged into one.",
      r"(IMC(v) = 1 - \frac{\partial(G)}{\partial(G_v)}, \quad \partial(G) = \frac{1}{N \bar{L}})",
      r"(—)",
      "A high value indicates a node whose contraction shortens paths most."),

  rec("Spectral, walk and influence",
      "Improved Node Contraction", "node_contraction_improved",
      "Improved node contraction adds the contraction scores of a node's edges, computed on the line graph.",
      r"(IIMC(v) = \alpha\, IMC(v) + \beta \sum_{e \ni v} IMC_{L(G)}(e), \quad \alpha / \beta = 5)",
      r"(`contraction_rho`)",
      "A high value indicates a node that is important both itself and through its edges. Values can exceed 1."),

  rec("Spectral, walk and influence",
      "Two-Way Random Walk Betweenness", "two_way_rw",
      "Two-way random walk betweenness counts, over all node pairs, how often a node lies on the most likely two-step out-and-back route.",
      r"(T_{ij}[t, k] = P_{itj} P_{jki}, \quad P_{itj} = \frac{w_{it} w_{tj}}{d_i d_j})",
      r"(—)",
      "A high count indicates a node on many dominant two-way routes. Cost grows as $n^4$."),

  ## ---- Family 5: Neighbourhood structure and cohesion ----
  rec("Neighbourhood structure and cohesion",
      "Transitivity Centrality", "transitivity",
      "Transitivity measures local clustering: whether a node's neighbours are connected to each other.",
      r"(c(v) = \frac{2\, t_v}{k_v (k_v - 1)}, \quad t_v = \text{number of triangles through } v)",
      r"(`transitivity_type`, `isolates`)",
      "A high value indicates locally closed neighbourhoods. This can represent cohesion or redundancy, depending on the relation."),

  rec("Neighbourhood structure and cohesion",
      "Constraint Centrality", "constraint",
      "Constraint measures how redundant a node's contacts are, following Burt's structural holes framework.",
      r"(C(v) = \sum_{u \in N(v)} \left( p_{vu} + \sum_{q \ne v, u} p_{vq}\, p_{qu} \right)^2, \quad p_{vu} = \text{proportional tie strength})",
      r"(—)",
      "A high value indicates a locally constrained ego network. Lower constraint may indicate structural holes, depending on theory and relation type."),

  rec("Neighbourhood structure and cohesion",
      "Effective Size Centrality", "effective_size",
      "Effective size estimates the number of nonredundant contacts in a node's ego network (Burt).",
      r"(\mathrm{ES}(v) = k_v - \frac{1}{k_v} \sum_{u \in N(v)} |N(v) \cap N(u)|)",
      r"(—)",
      "A high value indicates relatively nonoverlapping contacts."),

  rec("Neighbourhood structure and cohesion",
      "Topological Coefficient Centrality", "topological_coefficient",
      "Topological coefficient centrality measures shared-neighbour overlap.",
      r"(T(v) = \frac{\operatorname{avg}_{u}\, J(v, u)}{k_v}, \quad J(v, u) = \text{number of neighbours shared by } v \text{ and } u)",
      r"(—)",
      "A high value indicates neighbourhood overlap or topological similarity."),

  rec("Neighbourhood structure and cohesion",
      "Diversity Centrality", "diversity",
      "Diversity centrality measures entropy in the distribution of edge weights around a node.",
      r"(\mathrm{Div}(v) = \frac{-\sum_{u \in N(v)} p_{vu} \log_2 p_{vu}}{\log_2 k_v}, \quad p_{vu} = \frac{w_{vu}}{\sum_{u'} w_{vu'}})",
      r"(—)",
      "A high value indicates that weighted ties are relatively evenly distributed."),

  rec("Neighbourhood structure and cohesion",
      "Cross-Clique Centrality", "cross_clique",
      "Cross-clique centrality counts how many cliques contain a node.",
      r"(X(v) = |\{\, Q \in \mathcal{Q}(G) : v \in Q \,\}|, \quad \mathcal{Q}(G) = \text{set of cliques})",
      r"(—)",
      "A high value indicates participation in many fully connected local groups."),

  rec("Neighbourhood structure and cohesion",
      "Coreness Centrality", "coreness",
      "Coreness assigns nodes to k-core shells.",
      r"(C_{\mathrm{core}}(v) = \max \{\, k : v \in (k\text{-core of } G) \,\})",
      r"(`mode`)",
      "A high value indicates membership in a dense core."),

  rec("Neighbourhood structure and cohesion",
      "Onion Centrality", "onion",
      "Onion centrality assigns nodes to layers from onion decomposition, a fine-grained extension of k-core decomposition.",
      r"(\text{layer}(v) = \text{iteration index at which } v \text{ is peeled by the onion decomposition})",
      r"(via `centrality(measures = ...)`)",
      "A high layer indicates that the node remains until later stages of the peeling process.",
      via_measures = TRUE),

  rec("Neighbourhood structure and cohesion",
      "K-Reach Centrality", "kreach",
      "K-reach centrality counts nodes reachable within path length $k$.",
      r"(C_{kR}(v) = |\{\, u : 0 < d(v, u) \le k \,\}|, \quad k = 3)",
      r"(`mode`, `k`)",
      "A high value indicates broad reach within a fixed local radius. Results depend on the chosen $k$."),

  rec("Neighbourhood structure and cohesion",
      "s-shell Index", "s_shell",
      "The s-shell index peels the graph by node strength built from asymmetric topological link weights, generalising k-shell.",
      r"(w_{ij} = 1 + (k_i\, k^{out}_j)^a, \quad s_i = \sum_{j \in N(i)} w_{ij})",
      r"(`s_shell_a`)",
      "A high shell index indicates a node deep in the strength-based core. With $a = 0$ the shells are the dense ranks of k-core."),

  rec("Neighbourhood structure and cohesion",
      "Weighted k-shell", "weighted_kshell",
      "The weighted k-shell peels the graph by a generalised degree that mixes degree and strength.",
      r"(k'_v = \big(k_v^{\alpha} s_v^{\beta}\big)^{1 / (\alpha + \beta)})",
      r"(`wks_alpha`, `wks_beta`)",
      "A high shell index indicates a node deep in the weighted core. Unit weights give the k-core number."),

  rec("Neighbourhood structure and cohesion",
      "Renewed Coreness", "renewed_coreness",
      "Renewed coreness is the k-core number after removing links that lead nowhere new.",
      r"(D_{ij} = \frac{|N(j) \setminus N[i]| + |N(i) \setminus N[j]|}{2}, \quad \text{keep } D_{ij} \ge 2)",
      r"(`renewed_threshold`)",
      "A high value indicates a core node whose links reach beyond shared neighbourhoods. An isolated clique scores 0."),

  rec("Neighbourhood structure and cohesion",
      "s-core Index", "s_core",
      "The s-core index is the weighted k-core: the largest strength threshold whose core still contains the node.",
      r"(s\text{-core}(s) = \text{maximal } H \subseteq G \text{ with } s_i^H \ge s \;\; \forall i \in H)",
      r"(—)",
      "A high value indicates a node deep in the strength-based core. Unit weights give the k-core number exactly."),

  rec("Neighbourhood structure and cohesion",
      "Local Efficiency", "local_efficiency",
      "Local efficiency is how well a node's neighbours still communicate once the node itself is gone, using only the links among them.",
      r"(E_{loc}(v) = \frac{1}{k_v (k_v - 1)} \sum_{i \ne j \in N(v)} \frac{1}{d_{ij}^{\,G_v}})",
      r"(`mode`)",
      "A high value indicates a fault-tolerant neighbourhood; a node whose neighbours are mutually unconnected scores 0. Note that `igraph::local_efficiency()` measures those distances through the rest of the network instead, so it reports larger values."),

  ## ---- Family 6: Directed prestige and hierarchy ----
  rec("Directed prestige and hierarchy",
      "Prestige Domain Centrality", "prestige_domain",
      "Prestige domain centrality counts how many nodes can reach a focal node in a directed graph.",
      r"(P(v) = |\{\, u \ne v : u \rightsquigarrow v \,\}|)",
      r"(—)",
      "A high value indicates a large incoming reach domain."),

  rec("Directed prestige and hierarchy",
      "Prestige Domain Proximity Centrality", "prestige_domain_proximity",
      "Prestige domain proximity measures how close nodes in the prestige domain are to the focal node.",
      r"(C(v) = \frac{|R^{-}(v)|^2}{(n - 1) \sum_{u \in R^{-}(v)} d(u, v)}, \quad R^{-}(v) = \{ u \ne v : u \rightsquigarrow v \})",
      r"(—)",
      "A high value indicates that many predecessors can reach the node through short directed paths."),

  rec("Directed prestige and hierarchy",
      "Local Reaching Centrality", "reaching_local",
      "Local reaching centrality measures how much of the network is reachable from a node through directed paths.",
      r"(\mathrm{LRC}(v) = \frac{|\{\, u : v \rightsquigarrow u \,\}|}{n - 1})",
      r"(`mode`)",
      "A high value indicates broad directed reach from the node."),

  rec("Directed prestige and hierarchy",
      "Pairwise Disconnectivity Centrality", "pairwisedis",
      "Pairwise disconnectivity measures how directed reachability between pairs changes when a node is removed.",
      r"(\mathrm{Dis}(v) = \frac{P(G) - P(G \setminus v)}{P(G)}, \quad P(G) = |\{ (s, t) : s \rightsquigarrow t \}|)",
      r"(—)",
      "A high value indicates structural importance for preserving directed reachability."),

  rec("Directed prestige and hierarchy",
      "Trophic Level Centrality", "trophic_level",
      "Trophic level estimates hierarchical position in a directed flow network.",
      r"((I - W)\,\mathbf{s} = \mathbf{1}, \quad W_{ji} = \frac{a_{ij}}{k_j^{\mathrm{in}}}, \quad \text{basal nodes have level } 1)",
      r"(via `centrality(measures = ...)`)",
      "A higher value indicates a higher position in the inferred directed hierarchy. This is appropriate only for flow-like relations.",
      via_measures = TRUE),

  ## ---- Family 7: Community and group-based ----
  rec("Community and group-based",
      "Participation Coefficient", "participation",
      "Participation coefficient measures how evenly a node's ties are distributed across communities.",
      r"(P(v) = 1 - \sum_{m} \left( \frac{k_v^{(m)}}{k_v} \right)^2, \quad k_v^{(m)} = \text{ties from } v \text{ to module } m)",
      r"(`membership`, `mode`)",
      "A high value indicates ties spread across multiple communities. It requires a meaningful membership vector.",
      grp = TRUE),

  rec("Community and group-based",
      "Within-Module Z Centrality", "within_module_z",
      "Within-module z centrality standardises a node's within-community degree against other nodes in the same community.",
      r"(z(v) = \frac{k_v^{(m_v)} - \mu_{m_v}}{\sigma_{m_v}}, \quad m_v = \text{community of } v)",
      r"(`membership`, `mode`)",
      "A high value indicates unusually high within-module connectivity.",
      grp = TRUE),

  rec("Community and group-based",
      "Gateway Centrality", "gateway",
      "Gateway centrality measures inter-community brokerage weighted by centrality of communities or nodes involved.",
      r"(g(v) = 1 - \frac{1}{k_v^2} \sum_{s} k_{vs}^2\, \gamma_{vs}^2, \quad k_{vs} = \text{ties from } v \text{ to module } s)",
      r"(`membership`, `mode`)",
      "A high value indicates a structurally prominent position between communities.",
      grp = TRUE),

  rec("Community and group-based",
      "Brokerage Coordinator Centrality", "brokerage_coordinator",
      r"(Coordinator brokerage occurs when a node mediates between two nodes in its own group. It counts open directed two-paths $a \\to v \\to c$ (with no direct $a \\to c$).)",
      r"(\mathrm{Coord}(v) = |\{\, a \to v \to c : g(a) = g(v) = g(c) \,\}|)",
      r"(`membership`)",
      "A high value indicates within-group mediation under the supplied membership vector.",
      grp = TRUE),

  rec("Community and group-based",
      "Brokerage Itinerant Centrality", "brokerage_itinerant",
      "Itinerant brokerage occurs when a node mediates between two nodes in another group.",
      r"(\mathrm{Itin}(v) = |\{\, a \to v \to c : g(a) = g(c) \ne g(v) \,\}|)",
      r"(`membership`)",
      "A high value indicates brokerage among members outside the node's own group.",
      grp = TRUE),

  rec("Community and group-based",
      "Brokerage Representative Centrality", "brokerage_representative",
      "Representative brokerage occurs when a node mediates from its own group to another group.",
      r"(\mathrm{Rep}(v) = |\{\, a \to v \to c : g(a) = g(v) \ne g(c) \,\}|)",
      r"(`membership`)",
      "A high value indicates outward brokerage from the node's group.",
      grp = TRUE),

  rec("Community and group-based",
      "Brokerage Gatekeeper Centrality", "brokerage_gatekeeper",
      "Gatekeeper brokerage occurs when a node mediates from another group into its own group.",
      r"(\mathrm{Gate}(v) = |\{\, a \to v \to c : g(a) \ne g(v) = g(c) \,\}|)",
      r"(`membership`)",
      "A high value indicates inward brokerage into the node's group.",
      grp = TRUE),

  rec("Community and group-based",
      "Brokerage Liaison Centrality", "brokerage_liaison",
      "Liaison brokerage occurs when a node mediates between two groups, both different from its own.",
      r"(\mathrm{Liai}(v) = |\{\, a \to v \to c : g(a),\, g(v),\, g(c) \text{ all distinct} \,\}|)",
      r"(`membership`)",
      "A high value indicates between-group brokerage outside the node's own group.",
      grp = TRUE),

  rec("Community and group-based",
      "Modularity Vitality", "modularity_vitality",
      "Modularity vitality is the drop in Newman modularity when a node is deleted and the remaining nodes keep their communities.",
      r"(V_Q(v) = Q(G, C) - Q(G - v,\; C \setminus \{v\}))",
      r"(`membership`)",
      "A positive value indicates a community hub; a negative value indicates a bridge whose removal sharpens the partition. Weighted and directed graphs use the corresponding modularity.",
      grp = TRUE),

  rec("Community and group-based",
      "Community Hub-Bridge", "community_hub_bridge",
      "Community hub-bridge scores nodes that are hubs inside their community and bridges between communities.",
      r"(CHB(v) = |C_v|\, k^{intra}_v + NNC_v\, k^{inter}_v)",
      r"(`membership`, `mode`)",
      "A high value indicates a node with many intra-community links in a large community and links into several other communities.",
      grp = TRUE),

  rec("Community and group-based",
      "Community-Based Centrality", "community_based",
      "Community-based centrality weights every link of a node by the size of the community it lands in.",
      r"(CbC(v) = \frac{1}{N} \sum_w d_{vw} S_w)",
      r"(`membership`, `mode`)",
      "A high value indicates many links into large communities.",
      grp = TRUE),

  rec("Community and group-based",
      "Comm Centrality", "comm_centrality",
      "Comm centrality combines a node's scaled intra-community degree with the square of its scaled inter-community degree, weighted by how outward-looking its community is.",
      r"(CC(v) = (1 + \mu_C)\,\frac{k^{in}_v}{\max_{u \in C} k^{in}_u} R + (1 - \mu_C)\left(\frac{k^{out}_v}{\max_{u \in C} k^{out}_u} R\right)^2)",
      r"(`membership`, `mode`, `comm_r`)",
      "A high value indicates a node that is central within its community and well linked outside it. $R$ defaults to the community's maximum intra-degree.",
      grp = TRUE),

  rec("Community and group-based",
      "Community-Based Mediator", "community_mediator",
      "The community-based mediator score is the entropy of a node's link distribution over communities times its share of total degree.",
      r"(CbM(v) = H_v \frac{d_v}{\sum_u d_u}, \quad H_v = -\sum_k p_{vk} \log_2 p_{vk})",
      r"(`membership`, `mode`)",
      "A high value indicates a well-connected node whose links are spread over several communities; nodes linked to one community score 0.",
      grp = TRUE)
)

family_order <- c(
  "Degree, strength and local connectivity",
  "Distance and closeness",
  "Shortest-path brokerage and flow",
  "Spectral, walk and influence",
  "Neighbourhood structure and cohesion",
  "Directed prestige and hierarchy",
  "Community and group-based"
)
stopifnot(all(vapply(records, function(r) r$family, character(1)) %in%
                family_order))

emit_measure <- function(r) {
  cat("\n### ", r$title, " {#cent-", r$key, "}\n\n", sep = "")
  cat(r$concept, "\n\n", sep = "")
  if (nzchar(r$math)) cat("$$\n", r$math, "\n$$\n\n", sep = "")
  cat("**Meaning.** ", r$meaning, "\n\n", sep = "")
  cat("```r\n", r$example, "\n```\n\n", sep = "")
}

emit_family <- function(fam) {
  cat("\n## ", fam, "\n\n", sep = "")
  for (r in records) if (identical(r$family, fam)) emit_measure(r)
}

## ----index, results = 'asis', echo = FALSE------------------------------------
cat("<div class=\"cg-fam-index\">\n\n")
for (fam in family_order) {
  cat("**", fam, "**\n\n", sep = "")
  items <- Filter(function(r) identical(r$family, fam), records)
  links <- vapply(items, function(r) sprintf("[%s](#cent-%s)", r$title, r$key),
                  character(1))
  cat(paste(links, collapse = " · "), "\n\n")
}
cat("</div>\n\n")

## ----families_1_6, results = 'asis', echo = FALSE-----------------------------
for (fam in family_order[1:6]) emit_family(fam)

## ----groups-------------------------------------------------------------------
comm   <- detect_communities(student_interactions, method = "walktrap")
groups <- setNames(comm$community, comm$node)
centrality_participation(student_interactions, membership = groups)

## ----families_7, results = 'asis', echo = FALSE-------------------------------
emit_family(family_order[7])

