Skip to content

Commit 8ac1e19

Browse files
Copilotfermga
andcommitted
Implement enhanced canonical preconditions, metrics and tests for VAL operator
Co-authored-by: fermga <203334638+fermga@users.noreply.github.com>
1 parent 336757e commit 8ac1e19

File tree

3 files changed

+546
-9
lines changed

3 files changed

+546
-9
lines changed

src/tnfr/operators/metrics.py

Lines changed: 129 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,14 @@ def silence_metrics(
10801080
def expansion_metrics(
10811081
G: TNFRGraph, node: NodeId, vf_before: float, epi_before: float
10821082
) -> dict[str, Any]:
1083-
"""VAL - Expansion metrics: νf increase, volume exploration.
1083+
"""VAL - Enhanced expansion metrics with structural fidelity indicators.
1084+
1085+
Collects comprehensive metrics that reflect canonical VAL effects:
1086+
- **Structural dilation**: EPI and νf increases
1087+
- **Bifurcation risk**: ∂²EPI/∂t² threshold monitoring
1088+
- **Coherence gradient**: Impact on local/global coherence
1089+
- **Network impact**: Affected neighbors and coupling changes
1090+
- **Fractality preservation**: Structural complexity indicators
10841091
10851092
Parameters
10861093
----------
@@ -1096,19 +1103,136 @@ def expansion_metrics(
10961103
Returns
10971104
-------
10981105
dict
1099-
Expansion-specific metrics including structural dilation
1106+
Comprehensive expansion metrics including:
1107+
1108+
**Core Metrics**:
1109+
- operator, glyph: Identification
1110+
- vf_increase, vf_final: Frequency changes
1111+
- delta_epi, epi_final: EPI changes
1112+
- expansion_factor: Relative νf increase
1113+
1114+
**Structural Metrics** (NEW):
1115+
- dnfr_final: Final reorganization gradient
1116+
- d2epi: EPI acceleration (∂²EPI/∂t²)
1117+
- bifurcation_risk: Boolean flag if d²EPI/dt² > τ
1118+
- coherence_local: Local coherence after expansion
1119+
- phase_final: Final phase alignment
1120+
1121+
**Network Metrics** (NEW):
1122+
- neighbor_count: Number of connected neighbors
1123+
- network_impact_radius: Boolean if has neighbors
1124+
- degree_change: Change in node degree (if applicable)
1125+
1126+
**Fractality Indicators** (NEW):
1127+
- structural_complexity_increase: Relative EPI growth
1128+
- frequency_complexity_ratio: νf/EPI growth ratio
1129+
- expansion_quality: "coherent" if metrics healthy, else "unstable"
1130+
1131+
Examples
1132+
--------
1133+
>>> from tnfr.structural import create_nfr, run_sequence
1134+
>>> from tnfr.operators.definitions import Expansion
1135+
>>>
1136+
>>> G, node = create_nfr("test", epi=0.5, vf=2.0)
1137+
>>> G.graph["COLLECT_OPERATOR_METRICS"] = True
1138+
>>> G.nodes[node]['delta_nfr'] = 0.1
1139+
>>>
1140+
>>> # Apply expansion
1141+
>>> Expansion()(G, node, collect_metrics=True)
1142+
>>>
1143+
>>> # Metrics include bifurcation_risk, coherence_local, etc.
1144+
1145+
Notes
1146+
-----
1147+
These metrics enable monitoring of:
1148+
1. **Bifurcation readiness**: d²EPI/dt² > τ signals reorganization threshold
1149+
2. **Coherence preservation**: Expansion should maintain or increase coherence
1150+
3. **Fractality**: Self-similar growth patterns indicated by complexity ratios
1151+
4. **Network coupling**: Impact on surrounding nodes
1152+
1153+
See Also
1154+
--------
1155+
Expansion : VAL operator that produces these metrics
1156+
validate_expansion : Preconditions ensuring valid expansion
11001157
"""
1158+
# Existing metrics
11011159
vf_after = _get_node_attr(G, node, ALIAS_VF)
11021160
epi_after = _get_node_attr(G, node, ALIAS_EPI)
1103-
1161+
1162+
# NEW: Additional structural parameters
1163+
dnfr = _get_node_attr(G, node, ALIAS_DNFR)
1164+
d2epi = _get_node_attr(G, node, ALIAS_D2EPI)
1165+
theta = _get_node_attr(G, node, ALIAS_THETA)
1166+
1167+
# NEW: Bifurcation risk assessment
1168+
tau = float(G.graph.get("BIFURCATION_THRESHOLD_TAU", 0.5))
1169+
bifurcation_risk = abs(d2epi) > tau
1170+
1171+
# NEW: Network impact metrics
1172+
neighbors = list(G.neighbors(node))
1173+
neighbor_count = len(neighbors)
1174+
network_impact_radius = neighbor_count > 0
1175+
1176+
# NEW: Coherence metrics (if available)
1177+
try:
1178+
from ..telemetry import compute_local_coherence
1179+
coherence_local = compute_local_coherence(G, node)
1180+
except (ImportError, AttributeError):
1181+
# Fallback if telemetry not available
1182+
coherence_local = None
1183+
1184+
# NEW: Fractality and complexity indicators
1185+
delta_epi = epi_after - epi_before
1186+
delta_vf = vf_after - vf_before
1187+
1188+
structural_complexity_increase = (
1189+
(delta_epi / epi_before) if epi_before > 0 else 0.0
1190+
)
1191+
1192+
frequency_complexity_ratio = (
1193+
(delta_vf / delta_epi) if delta_epi > 0 else 0.0
1194+
)
1195+
1196+
# NEW: Expansion quality assessment
1197+
expansion_quality = "coherent"
1198+
if bifurcation_risk:
1199+
expansion_quality = "threshold" # At bifurcation point
1200+
if dnfr < 0:
1201+
expansion_quality = "unstable" # Negative ΔNFR (shouldn't happen)
1202+
if delta_epi <= 0 or delta_vf <= 0:
1203+
expansion_quality = "ineffective" # No actual expansion occurred
1204+
11041205
return {
1206+
# Core identification
11051207
"operator": "Expansion",
11061208
"glyph": "VAL",
1107-
"vf_increase": vf_after - vf_before,
1209+
1210+
# Existing metrics
1211+
"vf_increase": delta_vf,
11081212
"vf_final": vf_after,
1109-
"delta_epi": epi_after - epi_before,
1213+
"delta_epi": delta_epi,
11101214
"epi_final": epi_after,
11111215
"expansion_factor": vf_after / vf_before if vf_before > 0 else 1.0,
1216+
1217+
# NEW: Structural metrics
1218+
"dnfr_final": dnfr,
1219+
"d2epi": d2epi,
1220+
"bifurcation_risk": bifurcation_risk,
1221+
"bifurcation_threshold": tau,
1222+
"coherence_local": coherence_local,
1223+
"phase_final": theta,
1224+
1225+
# NEW: Network impact
1226+
"neighbor_count": neighbor_count,
1227+
"network_impact_radius": network_impact_radius,
1228+
1229+
# NEW: Fractality indicators
1230+
"structural_complexity_increase": structural_complexity_increase,
1231+
"frequency_complexity_ratio": frequency_complexity_ratio,
1232+
"expansion_quality": expansion_quality,
1233+
1234+
# Metadata
1235+
"metrics_version": "2.0_canonical",
11121236
}
11131237

11141238

src/tnfr/operators/preconditions/__init__.py

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,23 @@ def validate_silence(G: "TNFRGraph", node: "NodeId") -> None:
488488

489489

490490
def validate_expansion(G: "TNFRGraph", node: "NodeId") -> None:
491-
"""VAL - Expansion requires vf below maximum threshold.
492-
491+
"""VAL - Expansion requires comprehensive canonical preconditions.
492+
493+
Canonical Requirements (TNFR Physics):
494+
1. **νf < max_vf**: Structural frequency below saturation
495+
2. **ΔNFR > 0**: Positive reorganization gradient (growth pressure)
496+
3. **EPI >= min_epi**: Sufficient base coherence for expansion
497+
4. **(Optional) Network capacity**: Check if network can support expansion
498+
499+
Physical Basis:
500+
----------------
501+
From nodal equation: ∂EPI/∂t = νf · ΔNFR(t)
502+
503+
For coherent expansion:
504+
- ΔNFR > 0 required: expansion needs outward pressure
505+
- EPI > threshold: must have coherent base to expand from
506+
- νf < max: must have capacity for increased reorganization
507+
493508
Parameters
494509
----------
495510
G : TNFRGraph
@@ -500,15 +515,90 @@ def validate_expansion(G: "TNFRGraph", node: "NodeId") -> None:
500515
Raises
501516
------
502517
OperatorPreconditionError
503-
If structural frequency already at maximum
518+
If any precondition fails:
519+
- Structural frequency at maximum
520+
- ΔNFR non-positive (no growth pressure)
521+
- EPI below minimum (insufficient coherence base)
522+
- (Optional) Network at capacity
523+
524+
Configuration Parameters
525+
------------------------
526+
VAL_MAX_VF : float, default 10.0
527+
Maximum structural frequency threshold
528+
VAL_MIN_DNFR : float, default 0.01
529+
Minimum ΔNFR for expansion (must be positive)
530+
VAL_MIN_EPI : float, default 0.2
531+
Minimum EPI for coherent expansion
532+
VAL_CHECK_NETWORK_CAPACITY : bool, default False
533+
Enable network capacity validation
534+
VAL_MAX_NETWORK_SIZE : int, default 1000
535+
Maximum network size if capacity checking enabled
536+
537+
Examples
538+
--------
539+
>>> from tnfr.structural import create_nfr
540+
>>> from tnfr.operators.preconditions import validate_expansion
541+
>>>
542+
>>> # Valid node for expansion
543+
>>> G, node = create_nfr("expanding", epi=0.5, vf=2.0)
544+
>>> G.nodes[node]['delta_nfr'] = 0.1 # Positive ΔNFR
545+
>>> validate_expansion(G, node) # Passes
546+
>>>
547+
>>> # Invalid: negative ΔNFR
548+
>>> G.nodes[node]['delta_nfr'] = -0.1
549+
>>> validate_expansion(G, node) # Raises OperatorPreconditionError
550+
551+
Notes
552+
-----
553+
VAL increases both EPI magnitude and νf, enabling exploration of new
554+
structural configurations while maintaining core identity (fractality).
555+
556+
See Also
557+
--------
558+
Expansion : VAL operator implementation
559+
validate_contraction : NUL preconditions (inverse operation)
504560
"""
561+
# 1. νf below maximum (existing check)
505562
vf = _get_node_attr(G, node, ALIAS_VF)
506563
max_vf = float(G.graph.get("VAL_MAX_VF", 10.0))
507564
if vf >= max_vf:
508565
raise OperatorPreconditionError(
509566
"Expansion",
510-
f"Structural frequency at maximum (νf={vf:.3f} >= {max_vf:.3f})",
567+
f"Structural frequency at maximum (νf={vf:.3f} >= {max_vf:.3f}). "
568+
f"Node at reorganization capacity limit.",
569+
)
570+
571+
# 2. ΔNFR positivity check (NEW - CRITICAL)
572+
dnfr = _get_node_attr(G, node, ALIAS_DNFR)
573+
min_dnfr = float(G.graph.get("VAL_MIN_DNFR", 0.01))
574+
if dnfr < min_dnfr:
575+
raise OperatorPreconditionError(
576+
"Expansion",
577+
f"ΔNFR must be positive for expansion (ΔNFR={dnfr:.3f} < {min_dnfr:.3f}). "
578+
f"No outward growth pressure detected. Consider OZ (Dissonance) to generate ΔNFR.",
579+
)
580+
581+
# 3. EPI minimum check (NEW - IMPORTANT)
582+
epi = _get_node_attr(G, node, ALIAS_EPI)
583+
min_epi = float(G.graph.get("VAL_MIN_EPI", 0.2))
584+
if epi < min_epi:
585+
raise OperatorPreconditionError(
586+
"Expansion",
587+
f"EPI too low for coherent expansion (EPI={epi:.3f} < {min_epi:.3f}). "
588+
f"Insufficient structural base. Consider AL (Emission) to activate node first.",
511589
)
590+
591+
# 4. Network capacity check (OPTIONAL - for large-scale systems)
592+
check_capacity = bool(G.graph.get("VAL_CHECK_NETWORK_CAPACITY", False))
593+
if check_capacity:
594+
max_network_size = int(G.graph.get("VAL_MAX_NETWORK_SIZE", 1000))
595+
current_size = G.number_of_nodes()
596+
if current_size >= max_network_size:
597+
raise OperatorPreconditionError(
598+
"Expansion",
599+
f"Network at capacity (n={current_size} >= {max_network_size}). "
600+
f"Cannot support further expansion. Set VAL_CHECK_NETWORK_CAPACITY=False to disable.",
601+
)
512602

513603

514604
def validate_contraction(G: "TNFRGraph", node: "NodeId") -> None:

0 commit comments

Comments
 (0)