@@ -1294,6 +1294,9 @@ def contraction_metrics(
12941294) -> dict [str , Any ]:
12951295 """NUL - Contraction metrics: νf decrease, core concentration, ΔNFR densification.
12961296
1297+ Collects comprehensive contraction metrics including structural density dynamics
1298+ that validate canonical NUL behavior and enable early warning for over-compression.
1299+
12971300 Parameters
12981301 ----------
12991302 G : TNFRGraph
@@ -1308,9 +1311,52 @@ def contraction_metrics(
13081311 Returns
13091312 -------
13101313 dict
1311- Contraction-specific metrics including structural compression and
1312- canonical ΔNFR densification tracking.
1314+ Contraction-specific metrics including:
1315+
1316+ **Basic metrics:**
1317+
1318+ - operator: "Contraction"
1319+ - glyph: "NUL"
1320+ - vf_decrease: Absolute reduction in νf
1321+ - vf_final: Post-contraction νf
1322+ - delta_epi: EPI change
1323+ - epi_final: Post-contraction EPI
1324+ - dnfr_final: Post-contraction ΔNFR
1325+ - contraction_factor: Ratio of vf_after / vf_before
1326+
1327+ **Densification metrics (if available):**
1328+
1329+ - densification_factor: ΔNFR amplification factor (typically 1.35)
1330+ - dnfr_densified: Boolean indicating densification occurred
1331+ - dnfr_before: ΔNFR value before contraction
1332+ - dnfr_increase: Absolute ΔNFR change (dnfr_after - dnfr_before)
1333+
1334+ **Structural density metrics (NEW):**
1335+
1336+ - density_before: |ΔNFR| / max(EPI, ε) before contraction
1337+ - density_after: |ΔNFR| / max(EPI, ε) after contraction
1338+ - densification_ratio: density_after / density_before
1339+ - is_critical_density: Warning flag (density > threshold)
1340+
1341+ Notes
1342+ -----
1343+ **Structural Density**: Defined as ρ = |ΔNFR| / max(EPI, ε) where ε = 1e-9.
1344+ This captures the concentration of reorganization pressure per unit structure.
1345+
1346+ **Critical Density**: When density exceeds CRITICAL_DENSITY_THRESHOLD (default: 5.0),
1347+ it indicates over-compression risk where the node may become unstable.
1348+
1349+ **Densification Ratio**: Quantifies how much density increased during contraction.
1350+ Canonical NUL should produce densification_ratio ≈ densification_factor / contraction_factor.
1351+
1352+ See Also
1353+ --------
1354+ Contraction : NUL operator implementation
1355+ validate_contraction : Preconditions for safe contraction
13131356 """
1357+ # Small epsilon for numerical stability
1358+ EPSILON = 1e-9
1359+
13141360 vf_after = _get_node_attr (G , node , ALIAS_VF )
13151361 epi_after = _get_node_attr (G , node , ALIAS_EPI )
13161362 dnfr_after = _get_node_attr (G , node , ALIAS_DNFR )
@@ -1325,6 +1371,18 @@ def contraction_metrics(
13251371 densification_factor = last_entry .get ("densification_factor" )
13261372 dnfr_before = last_entry .get ("dnfr_before" )
13271373
1374+ # Calculate structural density before and after
1375+ # Density = |ΔNFR| / max(EPI, ε)
1376+ density_before = abs (dnfr_before ) / max (abs (epi_before ), EPSILON ) if dnfr_before is not None else 0.0
1377+ density_after = abs (dnfr_after ) / max (abs (epi_after ), EPSILON )
1378+
1379+ # Calculate densification ratio (how much density increased)
1380+ densification_ratio = density_after / density_before if density_before > EPSILON else float ('inf' )
1381+
1382+ # Get critical density threshold from graph config or use default
1383+ critical_density_threshold = float (G .graph .get ("CRITICAL_DENSITY_THRESHOLD" , 5.0 ))
1384+ is_critical_density = density_after > critical_density_threshold
1385+
13281386 metrics = {
13291387 "operator" : "Contraction" ,
13301388 "glyph" : "NUL" ,
@@ -1344,6 +1402,12 @@ def contraction_metrics(
13441402 metrics ["dnfr_before" ] = dnfr_before
13451403 metrics ["dnfr_increase" ] = dnfr_after - dnfr_before if dnfr_before else 0.0
13461404
1405+ # Add NEW structural density metrics
1406+ metrics ["density_before" ] = density_before
1407+ metrics ["density_after" ] = density_after
1408+ metrics ["densification_ratio" ] = densification_ratio
1409+ metrics ["is_critical_density" ] = is_critical_density
1410+
13471411 return metrics
13481412
13491413
0 commit comments