Skip to content

Commit b0876d7

Browse files
Copilotfermga
andcommitted
Add νf amplification and metrics to RA operator
- Enhanced _op_RA with νf amplification (RA_vf_amplification factor) - Added propagation metrics collection (COLLECT_RA_METRICS flag) - Added network C(t) tracking (TRACK_NETWORK_COHERENCE flag) - Added identity preservation validation in metrics - Added RA_vf_amplification to GLYPH_FACTORS defaults (0.05) - Created comprehensive test suite for RA enhancements - Tests validate νf amplification, metrics collection, backward compatibility Co-authored-by: fermga <203334638+fermga@users.noreply.github.com>
1 parent 00990dd commit b0876d7

File tree

3 files changed

+518
-7
lines changed

3 files changed

+518
-7
lines changed

src/tnfr/config/defaults_core.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class CoreDefaults:
8686
"UM_vf_sync": 0.10,
8787
"UM_dnfr_reduction": 0.15,
8888
"RA_epi_diff": 0.15,
89+
"RA_vf_amplification": 0.05,
8990
"SHA_vf_factor": 0.85,
9091
# Conservative scaling (1.05) prevents EPI overflow near boundaries
9192
# while maintaining meaningful expansion capacity. Critical threshold:

src/tnfr/operators/__init__.py

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -768,37 +768,127 @@ def _op_UM(node: NodeProtocol, gf: GlyphFactors) -> None: # UM — Coupling
768768

769769

770770
def _op_RA(node: NodeProtocol, gf: GlyphFactors) -> None: # RA — Resonance
771-
"""Diffuse EPI to the node through the Resonance glyph.
771+
"""Propagate coherence through resonance with νf amplification.
772772
773-
Resonance propagates EPI along existing couplings without affecting νf,
774-
ΔNFR, or phase. The glyph nudges the node towards the neighbour mean using
775-
``RA_epi_diff``.
773+
Resonance (RA) propagates EPI along existing couplings while amplifying
774+
the structural frequency (νf) to reflect network coherence propagation.
775+
According to TNFR theory, RA creates "resonant cascades" where coherence
776+
amplifies across the network, increasing collective νf and global C(t).
777+
778+
**Canonical Effects:**
779+
780+
- **EPI Propagation**: Diffuses EPI to neighbors (identity-preserving)
781+
- **νf Amplification**: Increases structural frequency when propagating coherence
782+
- **Network C(t)**: Contributes to global coherence increase
783+
- **Identity Preservation**: Maintains structural identity during propagation
776784
777785
Parameters
778786
----------
779787
node : NodeProtocol
780788
Node harmonising with its neighbourhood.
781789
gf : GlyphFactors
782-
Provides ``RA_epi_diff`` as the mixing coefficient.
790+
Provides ``RA_epi_diff`` (mixing coefficient, default 0.15) and
791+
``RA_vf_amplification`` (νf boost factor, default 0.05).
792+
793+
Notes
794+
-----
795+
**νf Amplification**: When neighbors have coherence (|epi_bar| > 1e-9),
796+
node.vf is multiplied by (1.0 + RA_vf_amplification). This reflects
797+
the canonical TNFR property that resonance amplifies collective νf.
798+
799+
**Network Coherence Tracking**: If ``TRACK_NETWORK_COHERENCE`` is enabled,
800+
global C(t) is measured before/after RA application to quantify network-level
801+
coherence increase.
802+
803+
**Identity Preservation**: EPI structure (kind and sign) are preserved during
804+
propagation to ensure structural identity is maintained as required by theory.
783805
784806
Examples
785807
--------
786808
>>> class MockNode:
787809
... def __init__(self, epi, neighbors):
788810
... self.EPI = epi
789811
... self.epi_kind = "seed"
812+
... self.vf = 1.0
790813
... self.graph = {}
791814
... self._neighbors = neighbors
792815
... def neighbors(self):
793816
... return self._neighbors
794817
>>> neighbor = MockNode(1.0, [])
795818
>>> node = MockNode(0.2, [neighbor])
796-
>>> _op_RA(node, {"RA_epi_diff": 0.25})
819+
>>> _op_RA(node, {"RA_epi_diff": 0.25, "RA_vf_amplification": 0.05})
797820
>>> round(node.EPI, 2)
798821
0.4
822+
>>> node.vf # Amplified due to neighbor coherence
823+
1.05
799824
"""
825+
# Get configuration factors
800826
diff = get_factor(gf, "RA_epi_diff", 0.15)
801-
_mix_epi_with_neighbors(node, diff, Glyph.RA)
827+
vf_boost = get_factor(gf, "RA_vf_amplification", 0.05)
828+
829+
# Track network C(t) before RA if enabled
830+
track_coherence = bool(node.graph.get("TRACK_NETWORK_COHERENCE", False))
831+
c_before = None
832+
if track_coherence and hasattr(node, "G"):
833+
try:
834+
from ..metrics.coherence import compute_network_coherence
835+
c_before = compute_network_coherence(node.G)
836+
if "_ra_c_tracking" not in node.graph:
837+
node.graph["_ra_c_tracking"] = []
838+
except ImportError:
839+
pass # Metrics module not available
840+
841+
# Capture state before for metrics
842+
vf_before = node.vf
843+
epi_before = node.EPI
844+
kind_before = node.epi_kind
845+
846+
# EPI diffusion (existing behavior)
847+
neigh, epi_bar = get_neighbor_epi(node)
848+
epi_bar_result, kind_result = _mix_epi_with_neighbors(node, diff, Glyph.RA)
849+
850+
# νf amplification through resonance (NEW)
851+
# Only amplify if neighbors have coherence to propagate
852+
if abs(epi_bar_result) > 1e-9 and len(neigh) > 0:
853+
node.vf *= (1.0 + vf_boost)
854+
855+
# Track identity preservation
856+
identity_preserved = (
857+
(kind_result == kind_before or kind_result == Glyph.RA.value)
858+
and (epi_before * node.EPI >= 0) # Sign preserved
859+
)
860+
861+
# Collect propagation metrics if enabled
862+
collect_metrics = bool(node.graph.get("COLLECT_RA_METRICS", False))
863+
if collect_metrics:
864+
metrics = {
865+
"operator": "RA",
866+
"epi_propagated": epi_bar_result,
867+
"vf_amplification": node.vf / vf_before if vf_before > 0 else 1.0,
868+
"neighbors_influenced": len(neigh),
869+
"identity_preserved": identity_preserved,
870+
"epi_before": epi_before,
871+
"epi_after": float(node.EPI),
872+
"vf_before": vf_before,
873+
"vf_after": node.vf,
874+
}
875+
if "ra_metrics" not in node.graph:
876+
node.graph["ra_metrics"] = []
877+
node.graph["ra_metrics"].append(metrics)
878+
879+
# Track network C(t) after RA if enabled
880+
if track_coherence and c_before is not None and hasattr(node, "G"):
881+
try:
882+
from ..metrics.coherence import compute_network_coherence
883+
c_after = compute_network_coherence(node.G)
884+
node.graph["_ra_c_tracking"].append({
885+
"node": getattr(node, "n", None),
886+
"c_before": c_before,
887+
"c_after": c_after,
888+
"c_delta": c_after - c_before,
889+
})
890+
except ImportError:
891+
pass
802892

803893

804894
def _op_SHA(node: NodeProtocol, gf: GlyphFactors) -> None: # SHA — Silence

0 commit comments

Comments
 (0)