Skip to content

Commit 9f4bd4b

Browse files
Copilotfermga
andcommitted
Refactor UM and THOL operators to use unified phase compatibility functions
Co-authored-by: fermga <203334638+fermga@users.noreply.github.com>
1 parent e164318 commit 9f4bd4b

File tree

3 files changed

+27
-16
lines changed

3 files changed

+27
-16
lines changed

src/tnfr/metrics/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
compute_learning_plasticity,
3333
glyph_history_to_operator_names,
3434
)
35+
from .phase_compatibility import (
36+
compute_network_phase_alignment,
37+
compute_phase_coupling_strength,
38+
is_phase_compatible,
39+
)
3540
from .reporting import (
3641
Tg_by_node,
3742
Tg_global,
@@ -68,4 +73,7 @@
6873
"compute_bifurcation_rate",
6974
"compute_metabolic_efficiency",
7075
"compute_emergence_index",
76+
"compute_phase_coupling_strength",
77+
"is_phase_compatible",
78+
"compute_network_phase_alignment",
7179
)

src/tnfr/operators/__init__.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -741,10 +741,11 @@ def _op_UM(node: NodeProtocol, gf: GlyphFactors) -> None: # UM — Coupling
741741

742742
# Compute phase alignments with each neighbor
743743
phase_alignments = []
744+
# Compute phase alignment using canonical formula
745+
from ..metrics.phase_compatibility import compute_phase_coupling_strength
746+
744747
for neighbor in neighbors:
745-
dphi = abs(angle_diff(neighbor.theta, node.theta))
746-
# alignment: 1.0 (perfectly aligned) to 0.0 (opposite phases)
747-
alignment = 1.0 - dphi / math.pi
748+
alignment = compute_phase_coupling_strength(node.theta, neighbor.theta)
748749
phase_alignments.append(alignment)
749750

750751
# Mean alignment represents coupling strength
@@ -772,13 +773,17 @@ def _op_UM(node: NodeProtocol, gf: GlyphFactors) -> None: # UM — Coupling
772773
)
773774

774775
for j in candidates:
775-
th_j = j.theta
776-
dphi = abs(angle_diff(th_j, th_i)) / math.pi
776+
# Use canonical phase coupling strength formula
777+
from ..metrics.phase_compatibility import compute_phase_coupling_strength
778+
779+
phase_coupling = compute_phase_coupling_strength(th_i, j.theta)
780+
777781
epi_j = j.EPI
778782
si_j = j.Si
779783
epi_sim = 1.0 - abs(epi_i - epi_j) / (abs(epi_i) + abs(epi_j) + 1e-9)
780784
si_sim = 1.0 - abs(si_i - si_j)
781-
compat = (1 - dphi) * 0.5 + 0.25 * epi_sim + 0.25 * si_sim
785+
# Compatibility combines phase coupling (50%), EPI similarity (25%), Si similarity (25%)
786+
compat = phase_coupling * 0.5 + 0.25 * epi_sim + 0.25 * si_sim
782787
if compat >= thr:
783788
node.add_edge(j, compat)
784789

src/tnfr/operators/metabolism.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def capture_network_signals(G: TNFRGraph, node: NodeId) -> dict[str, Any] | None
9797
0.45
9898
"""
9999
np = get_numpy()
100+
from ..metrics.phase_compatibility import compute_phase_coupling_strength
100101

101102
neighbors = list(G.neighbors(node))
102103
if not neighbors:
@@ -117,12 +118,9 @@ def capture_network_signals(G: TNFRGraph, node: NodeId) -> dict[str, Any] | None
117118
neighbor_epis.append(n_epi)
118119
neighbor_thetas.append(n_theta)
119120

120-
# Coupling strength based on phase alignment
121-
phase_diff = abs(n_theta - node_theta)
122-
# Normalize to [0, π]
123-
if phase_diff > math.pi:
124-
phase_diff = 2 * math.pi - phase_diff
125-
coupling_strength = 1.0 - (phase_diff / math.pi)
121+
# Coupling strength using canonical phase compatibility formula
122+
# (unified across UM, RA, THOL operators - see phase_compatibility module)
123+
coupling_strength = compute_phase_coupling_strength(node_theta, n_theta)
126124
coupling_strengths.append(coupling_strength)
127125

128126
# Compute structural gradients
@@ -282,7 +280,7 @@ def propagate_subepi_to_network(
282280
(1, 0.105) # 70% attenuation
283281
"""
284282
from ..alias import set_attr
285-
from ..utils.numeric import angle_diff
283+
from ..metrics.phase_compatibility import compute_phase_coupling_strength
286284

287285
neighbors = list(G.neighbors(parent_node))
288286
if not neighbors:
@@ -300,9 +298,9 @@ def propagate_subepi_to_network(
300298
for neighbor in neighbors:
301299
neighbor_theta = float(get_attr(G.nodes[neighbor], ALIAS_THETA, 0.0))
302300

303-
# Compute coupling strength (phase alignment)
304-
phase_diff = abs(angle_diff(neighbor_theta, parent_theta))
305-
coupling_strength = 1.0 - (phase_diff / math.pi)
301+
# Compute coupling strength using canonical phase compatibility formula
302+
# (unified across UM, RA, THOL operators - see phase_compatibility module)
303+
coupling_strength = compute_phase_coupling_strength(parent_theta, neighbor_theta)
306304

307305
# Propagate only if sufficiently coupled
308306
if coupling_strength >= min_coupling_strength:

0 commit comments

Comments
 (0)