Skip to content

Commit 54b519f

Browse files
committed
Refactor/expand documentation
1 parent 4b9ffe9 commit 54b519f

File tree

1 file changed

+33
-13
lines changed

1 file changed

+33
-13
lines changed

graphconstructor/operators/enhanced_configuration_model.py

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def _neg_log_likelihood_grad(x, y, k, s):
9797
"""
9898
Analytic gradient of the negative log-likelihood w.r.t. the *bounded*
9999
parameters (x, y). Derived by differentiating formula (13).
100+
Parameters should be in their bounded form (x > 0, 0 < y < 1) for correct gradients.
100101
"""
101102
N = len(x)
102103
grad_x = np.empty(N, dtype=np.float64)
@@ -222,23 +223,40 @@ def jac(v):
222223
@dataclass(slots=True)
223224
class EnhancedConfigurationModelFilter(GraphOperator):
224225
"""
225-
Enhanced Configuration Model (ECM) filter for weighted, undirected
226-
similarity graphs.
227-
228-
Replaces the original JAX-based implementation with Numba + NumPy kernels:
229-
- @njit kernels for the negative log-likelihood, its analytic gradient,
230-
and the p-value computation.
231-
- Reparameterisation-based optimisation (no explicit bounds): the domain
232-
constraints x > 0 and 0 < y < 1 are enforced implicitly by mapping the
233-
unconstrained optimisation variables through smooth homeomorphisms before
234-
evaluating the objective — exactly as in the original MaxentGraph design.
226+
Filter an undirected weighted similarity graph using the Enhanced
227+
Configuration Model (ECM).
228+
229+
This operator fits the ECM null model to the input graph and returns a new
230+
graph whose edge weights are the ECM p-values associated with the observed
231+
edge weights. The model preserves, in expectation, both the degree sequence
232+
and the strength sequence of the input graph.
233+
234+
The implementation follows the maximum-likelihood formulation of the ECM
235+
for weighted undirected networks. Internally, it estimates the node-wise
236+
model parameters ``x`` and ``y`` by minimizing the negative log-likelihood
237+
in a reparameterized unconstrained space and then computes an ECM-based
238+
p-value for each observed edge.
239+
240+
Parameters
241+
----------
242+
x_transform_idx : int, default=0
243+
Index selecting the reparameterization used for the positive ECM
244+
parameters ``x``. The index refers to :data:`R_to_zero_to_inf`, whose
245+
entries map from the real line to the open interval ``(0, inf)``.
246+
247+
y_transform_idx : int, default=0
248+
Index selecting the reparameterization used for the bounded ECM
249+
parameters ``y``. The index refers to :data:`R_to_zero_to_one`, whose
250+
entries map from the real line to the open interval ``(0, 1)``.
235251
236252
Paper: https://arxiv.org/abs/1706.00230
237253
Code: https://gitlab.liris.cnrs.fr/coregraphie/aliplosone/-/blob/main/Backbones/ecm.py
238254
"""
239255
supported_modes = ["similarity"]
240256

241-
# Indices into R_to_zero_to_inf / R_to_zero_to_one (0 = exp/sigmoid)
257+
# Reparameterization choices for the ECM variables:
258+
# x: R -> (0, inf)
259+
# y: R -> (0, 1)
242260
x_transform_idx: int = 0
243261
y_transform_idx: int = 0
244262

@@ -276,14 +294,16 @@ def _undirected(self, G: Graph) -> Graph:
276294
y_inv_transform(v0_bounded[num_nodes:]),
277295
])
278296

279-
# ---- Objective + analytic gradient in unconstrained space ---------
297+
# ---- Objective + gradient in unconstrained space ---------
280298
fun, jac = _make_objective(
281299
num_nodes, k, s,
282300
x_transform, x_inv_transform,
283301
y_transform, y_inv_transform,
284302
)
285303

286-
# ---- Optimise (no explicit bounds — domain enforced by transforms) -
304+
# ---- Optimize in reparameterized space -----------------------------
305+
# The optimizer works on unconstrained variables; valid ECM parameter
306+
# domains are enforced by the x/y transforms before each evaluation.
287307
res = so.minimize(
288308
fun=fun,
289309
jac=jac,

0 commit comments

Comments
 (0)