Skip to content

Commit b0005fa

Browse files
Copilotfermga
andcommitted
Implement NUL operator canonical ΔNFR densification dynamics
Co-authored-by: fermga <203334638+fermga@users.noreply.github.com>
1 parent b1a3205 commit b0005fa

File tree

4 files changed

+367
-5
lines changed

4 files changed

+367
-5
lines changed

src/tnfr/config/defaults_core.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ class CoreDefaults:
9595
# This preserves structural identity at boundary (EPI_MAX as identity frontier).
9696
"VAL_scale": 1.05,
9797
"NUL_scale": 0.85,
98+
# NUL canonical ΔNFR densification factor: implements structural pressure
99+
# concentration due to volume reduction. When V' = V × 0.85, density increases
100+
# by ~1.176× geometrically. Canonical value 1.35 accounts for nonlinear
101+
# structural effects at smaller scales, per TNFR theory.
102+
"NUL_densification_factor": 1.35,
98103
"THOL_accel": 0.10,
99104
"ZHIR_theta_shift": 1.57079632679,
100105
"NAV_jitter": 0.05,

src/tnfr/operators/__init__.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,37 @@ def _op(node: NodeProtocol, gf: GlyphFactors) -> None:
12231223
# Always scale νf (existing behavior)
12241224
_op_scale(node, factor)
12251225

1226+
# NUL canonical ΔNFR densification (implements structural pressure concentration)
1227+
if glyph is Glyph.NUL:
1228+
# Volume reduction: V' = V · scale_factor (where scale_factor < 1.0)
1229+
# Density increase: ρ_ΔNFR = ΔNFR / V' = ΔNFR / (V · scale_factor)
1230+
# Result: ΔNFR' = ΔNFR · densification_factor
1231+
#
1232+
# Physics: When volume contracts by factor λ < 1, structural pressure
1233+
# concentrates by factor 1/λ > 1. For NUL_scale = 0.85, densification ≈ 1.176
1234+
#
1235+
# Default densification_factor from config (typically 1.3-1.5) provides
1236+
# additional canonical amplification beyond geometric 1/λ to account for
1237+
# nonlinear structural effects at smaller scales.
1238+
densification_key = "NUL_densification_factor"
1239+
densification_default = 1.35 # Canonical default: moderate amplification
1240+
densification_factor = get_factor(gf, densification_key, densification_default)
1241+
1242+
# Apply densification to ΔNFR (use lowercase dnfr for NodeProtocol)
1243+
current_dnfr = node.dnfr
1244+
node.dnfr = current_dnfr * densification_factor
1245+
1246+
# Record densification telemetry for traceability
1247+
telemetry = node.graph.setdefault("nul_densification_log", [])
1248+
telemetry.append(
1249+
{
1250+
"dnfr_before": current_dnfr,
1251+
"dnfr_after": float(node.dnfr),
1252+
"densification_factor": densification_factor,
1253+
"contraction_scale": factor,
1254+
}
1255+
)
1256+
12261257
# Edge-aware EPI scaling (new behavior) if enabled
12271258
edge_aware_enabled = bool(
12281259
node.graph.get(

src/tnfr/operators/metrics.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,7 +1292,7 @@ def expansion_metrics(
12921292
def contraction_metrics(
12931293
G: TNFRGraph, node: NodeId, vf_before: float, epi_before: float
12941294
) -> dict[str, Any]:
1295-
"""NUL - Contraction metrics: νf decrease, core concentration.
1295+
"""NUL - Contraction metrics: νf decrease, core concentration, ΔNFR densification.
12961296
12971297
Parameters
12981298
----------
@@ -1308,22 +1308,43 @@ def contraction_metrics(
13081308
Returns
13091309
-------
13101310
dict
1311-
Contraction-specific metrics including structural compression
1311+
Contraction-specific metrics including structural compression and
1312+
canonical ΔNFR densification tracking.
13121313
"""
13131314
vf_after = _get_node_attr(G, node, ALIAS_VF)
13141315
epi_after = _get_node_attr(G, node, ALIAS_EPI)
1315-
dnfr = _get_node_attr(G, node, ALIAS_DNFR)
1316+
dnfr_after = _get_node_attr(G, node, ALIAS_DNFR)
13161317

1317-
return {
1318+
# Extract densification telemetry if available
1319+
densification_log = G.graph.get("nul_densification_log", [])
1320+
densification_factor = None
1321+
dnfr_before = None
1322+
if densification_log:
1323+
# Get the most recent densification entry for this node
1324+
last_entry = densification_log[-1]
1325+
densification_factor = last_entry.get("densification_factor")
1326+
dnfr_before = last_entry.get("dnfr_before")
1327+
1328+
metrics = {
13181329
"operator": "Contraction",
13191330
"glyph": "NUL",
13201331
"vf_decrease": vf_before - vf_after,
13211332
"vf_final": vf_after,
13221333
"delta_epi": epi_after - epi_before,
13231334
"epi_final": epi_after,
1324-
"dnfr_final": dnfr,
1335+
"dnfr_final": dnfr_after,
13251336
"contraction_factor": vf_after / vf_before if vf_before > 0 else 1.0,
13261337
}
1338+
1339+
# Add densification metrics if available
1340+
if densification_factor is not None:
1341+
metrics["densification_factor"] = densification_factor
1342+
metrics["dnfr_densified"] = True
1343+
if dnfr_before is not None:
1344+
metrics["dnfr_before"] = dnfr_before
1345+
metrics["dnfr_increase"] = dnfr_after - dnfr_before if dnfr_before else 0.0
1346+
1347+
return metrics
13271348

13281349

13291350
def self_organization_metrics(

0 commit comments

Comments
 (0)