Source code for orc_bound.core.measures
"""
k-hop lazy random walk measures.
mu_x^(k) = alpha * delta_x + (1 - alpha) * (k-step random walk distribution)
"""
from __future__ import annotations
import numpy as np
import networkx as nx
from typing import Dict
[docs]
def build_lazy_measures_k(
G: nx.Graph,
alpha_lazy: float,
k: int,
) -> Dict[int, Dict[int, float]]:
"""
Build k-hop lazy random walk probability measures for all nodes.
For each node x, the measure is:
mu_x^(k)[y] = alpha_lazy * delta_x(y) + (1 - alpha_lazy) * P^k(x, y)
Parameters
----------
G : nx.Graph
Input graph.
alpha_lazy : float
Lazy mixing parameter in [0, 1]. Higher values weight the
stationary distribution more heavily.
k : int
Number of random walk steps (k-hop neighborhood).
Returns
-------
mu_dict : Dict[int, Dict[int, float]]
Dictionary mapping each node to its mass dictionary, where
keys are neighbor nodes and values are probabilities.
Examples
--------
>>> import networkx as nx
>>> G = nx.path_graph(5)
>>> mu = build_lazy_measures_k(G, alpha_lazy=0.0, k=2)
>>> abs(sum(mu[0].values()) - 1.0) < 1e-10
True
"""
nodes = list(G.nodes())
idx = {u: i for i, u in enumerate(nodes)}
n = len(nodes)
# Build transition matrix P
P = np.zeros((n, n), dtype=np.float64)
for u in nodes:
i = idx[u]
nbrs = list(G.neighbors(u))
if len(nbrs) == 0:
P[i, i] = 1.0
else:
p = 1.0 / len(nbrs)
for v in nbrs:
P[i, idx[v]] = p
# Compute P^k via matrix power
Pk = np.linalg.matrix_power(P, k)
mu_dict: Dict[int, Dict[int, float]] = {}
for u in nodes:
i = idx[u]
d: Dict[int, float] = {}
# Delta mass at u
d[u] = alpha_lazy
# k-step random walk mass
for v in nodes:
mass = (1.0 - alpha_lazy) * Pk[i, idx[v]]
if mass > 1e-14:
d[v] = d.get(v, 0.0) + mass
mu_dict[u] = d
return mu_dict