@@ -768,37 +768,194 @@ def _op_UM(node: NodeProtocol, gf: GlyphFactors) -> None: # UM — Coupling
768768
769769
770770def _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 (always active):**
779+
780+ - **EPI Propagation**: Diffuses EPI to neighbors (identity-preserving)
781+ - **νf Amplification**: Increases structural frequency when propagating coherence
782+ - **Phase Alignment**: Strengthens phase synchrony across propagation path
783+ - **Network C(t)**: Contributes to global coherence increase
784+ - **Identity Preservation**: Maintains structural identity during propagation
776785
777786 Parameters
778787 ----------
779788 node : NodeProtocol
780789 Node harmonising with its neighbourhood.
781790 gf : GlyphFactors
782- Provides ``RA_epi_diff`` as the mixing coefficient.
791+ Provides ``RA_epi_diff`` (mixing coefficient, default 0.15),
792+ ``RA_vf_amplification`` (νf boost factor, default 0.05), and
793+ ``RA_phase_coupling`` (phase alignment factor, default 0.10).
794+
795+ Notes
796+ -----
797+ **νf Amplification (Canonical)**: When neighbors have coherence (|epi_bar| > 1e-9),
798+ node.vf is multiplied by (1.0 + RA_vf_amplification). This reflects
799+ the canonical TNFR property that resonance amplifies collective νf.
800+ This is NOT optional - it is a fundamental property of resonance per TNFR theory.
801+
802+ **Phase Alignment Strengthening (Canonical)**: RA strengthens phase alignment
803+ with neighbors by applying a small phase correction toward the network mean.
804+ This ensures that "Phase alignment: Strengthens across propagation path" as
805+ stated in the theoretical foundations. Uses existing phase utility functions
806+ to avoid code duplication.
807+
808+ **Network Coherence Tracking (Optional)**: If ``TRACK_NETWORK_COHERENCE`` is enabled,
809+ global C(t) is measured before/after RA application to quantify network-level
810+ coherence increase.
811+
812+ **Identity Preservation (Canonical)**: EPI structure (kind and sign) are preserved
813+ during propagation to ensure structural identity is maintained as required by theory.
783814
784815 Examples
785816 --------
786817 >>> class MockNode:
787818 ... def __init__(self, epi, neighbors):
788819 ... self.EPI = epi
789820 ... self.epi_kind = "seed"
821+ ... self.vf = 1.0
822+ ... self.theta = 0.0
790823 ... self.graph = {}
791824 ... self._neighbors = neighbors
792825 ... def neighbors(self):
793826 ... return self._neighbors
794827 >>> neighbor = MockNode(1.0, [])
828+ >>> neighbor.theta = 0.1
795829 >>> node = MockNode(0.2, [neighbor])
796- >>> _op_RA(node, {"RA_epi_diff": 0.25})
830+ >>> _op_RA(node, {"RA_epi_diff": 0.25, "RA_vf_amplification": 0.05 })
797831 >>> round(node.EPI, 2)
798832 0.4
833+ >>> node.vf # Amplified due to neighbor coherence (canonical effect)
834+ 1.05
799835 """
836+ # Get configuration factors
800837 diff = get_factor (gf , "RA_epi_diff" , 0.15 )
801- _mix_epi_with_neighbors (node , diff , Glyph .RA )
838+ vf_boost = get_factor (gf , "RA_vf_amplification" , 0.05 )
839+ phase_coupling = get_factor (gf , "RA_phase_coupling" , 0.10 ) # Canonical phase strengthening
840+
841+ # Track network C(t) before RA if enabled (optional telemetry)
842+ track_coherence = bool (node .graph .get ("TRACK_NETWORK_COHERENCE" , False ))
843+ c_before = None
844+ if track_coherence and hasattr (node , "G" ):
845+ try :
846+ from ..metrics .coherence import compute_network_coherence
847+ c_before = compute_network_coherence (node .G )
848+ if "_ra_c_tracking" not in node .graph :
849+ node .graph ["_ra_c_tracking" ] = []
850+ except ImportError :
851+ pass # Metrics module not available
852+
853+ # Capture state before for metrics
854+ vf_before = node .vf
855+ epi_before = node .EPI
856+ kind_before = node .epi_kind
857+ theta_before = node .theta if hasattr (node , "theta" ) else None
858+
859+ # EPI diffusion (existing behavior)
860+ neigh , epi_bar = get_neighbor_epi (node )
861+ epi_bar_result , kind_result = _mix_epi_with_neighbors (node , diff , Glyph .RA )
862+
863+ # CANONICAL EFFECT 1: νf amplification through resonance
864+ # This is always active - it's a fundamental property of resonance per TNFR theory
865+ # Only amplify if neighbors have coherence to propagate
866+ if abs (epi_bar_result ) > 1e-9 and len (neigh ) > 0 :
867+ node .vf *= (1.0 + vf_boost )
868+
869+ # CANONICAL EFFECT 2: Phase alignment strengthening
870+ # Per theory: "Phase alignment: Strengthens across propagation path"
871+ # Uses existing phase locking logic from IL operator (avoid duplication)
872+ phase_strengthened = False
873+ if len (neigh ) > 0 and hasattr (node , "theta" ) and hasattr (node , "G" ):
874+ try :
875+ # Use existing phase locking utility from IL operator
876+ from ..alias import get_attr
877+ from ..constants .aliases import ALIAS_THETA
878+ import cmath
879+ import math
880+
881+ # Get neighbor phases using existing utilities
882+ neighbor_phases = []
883+ for n in neigh :
884+ try :
885+ theta_n = float (get_attr (n , ALIAS_THETA , 0.0 ))
886+ neighbor_phases .append (theta_n )
887+ except (KeyError , ValueError , TypeError ):
888+ continue
889+
890+ if neighbor_phases :
891+ # Circular mean using the same method as in phase_coherence.py
892+ complex_phases = [cmath .exp (1j * theta ) for theta in neighbor_phases ]
893+ mean_real = sum (z .real for z in complex_phases ) / len (complex_phases )
894+ mean_imag = sum (z .imag for z in complex_phases ) / len (complex_phases )
895+ mean_complex = complex (mean_real , mean_imag )
896+ mean_phase = cmath .phase (mean_complex )
897+
898+ # Ensure positive phase [0, 2π]
899+ if mean_phase < 0 :
900+ mean_phase += 2 * math .pi
901+
902+ # Calculate phase difference (shortest arc)
903+ delta_theta = mean_phase - node .theta
904+ if delta_theta > math .pi :
905+ delta_theta -= 2 * math .pi
906+ elif delta_theta < - math .pi :
907+ delta_theta += 2 * math .pi
908+
909+ # Apply phase strengthening (move toward network mean)
910+ # Same approach as IL operator phase locking
911+ node .theta = node .theta + phase_coupling * delta_theta
912+
913+ # Normalize to [0, 2π]
914+ node .theta = node .theta % (2 * math .pi )
915+ phase_strengthened = True
916+ except (AttributeError , ImportError ):
917+ pass # Phase alignment not possible in this context
918+
919+ # Track identity preservation (canonical validation)
920+ identity_preserved = (
921+ (kind_result == kind_before or kind_result == Glyph .RA .value )
922+ and (float (epi_before ) * float (node .EPI ) >= 0 ) # Sign preserved
923+ )
924+
925+ # Collect propagation metrics if enabled (optional telemetry)
926+ collect_metrics = bool (node .graph .get ("COLLECT_RA_METRICS" , False ))
927+ if collect_metrics :
928+ metrics = {
929+ "operator" : "RA" ,
930+ "epi_propagated" : epi_bar_result ,
931+ "vf_amplification" : node .vf / vf_before if vf_before > 0 else 1.0 ,
932+ "neighbors_influenced" : len (neigh ),
933+ "identity_preserved" : identity_preserved ,
934+ "epi_before" : epi_before ,
935+ "epi_after" : float (node .EPI ),
936+ "vf_before" : vf_before ,
937+ "vf_after" : node .vf ,
938+ "phase_before" : theta_before ,
939+ "phase_after" : node .theta if hasattr (node , "theta" ) else None ,
940+ "phase_alignment_strengthened" : phase_strengthened ,
941+ }
942+ if "ra_metrics" not in node .graph :
943+ node .graph ["ra_metrics" ] = []
944+ node .graph ["ra_metrics" ].append (metrics )
945+
946+ # Track network C(t) after RA if enabled (optional telemetry)
947+ if track_coherence and c_before is not None and hasattr (node , "G" ):
948+ try :
949+ from ..metrics .coherence import compute_network_coherence
950+ c_after = compute_network_coherence (node .G )
951+ node .graph ["_ra_c_tracking" ].append ({
952+ "node" : getattr (node , "n" , None ),
953+ "c_before" : c_before ,
954+ "c_after" : c_after ,
955+ "c_delta" : c_after - c_before ,
956+ })
957+ except ImportError :
958+ pass
802959
803960
804961def _op_SHA (node : NodeProtocol , gf : GlyphFactors ) -> None : # SHA — Silence
0 commit comments