tnfr 4.5.2__py3-none-any.whl → 8.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tnfr might be problematic. Click here for more details.
- tnfr/__init__.py +334 -50
- tnfr/__init__.pyi +33 -0
- tnfr/_compat.py +10 -0
- tnfr/_generated_version.py +34 -0
- tnfr/_version.py +49 -0
- tnfr/_version.pyi +7 -0
- tnfr/alias.py +214 -37
- tnfr/alias.pyi +108 -0
- tnfr/backends/__init__.py +354 -0
- tnfr/backends/jax_backend.py +173 -0
- tnfr/backends/numpy_backend.py +238 -0
- tnfr/backends/optimized_numpy.py +420 -0
- tnfr/backends/torch_backend.py +408 -0
- tnfr/cache.py +149 -556
- tnfr/cache.pyi +13 -0
- tnfr/cli/__init__.py +51 -16
- tnfr/cli/__init__.pyi +26 -0
- tnfr/cli/arguments.py +344 -32
- tnfr/cli/arguments.pyi +29 -0
- tnfr/cli/execution.py +676 -50
- tnfr/cli/execution.pyi +70 -0
- tnfr/cli/interactive_validator.py +614 -0
- tnfr/cli/utils.py +18 -3
- tnfr/cli/utils.pyi +7 -0
- tnfr/cli/validate.py +236 -0
- tnfr/compat/__init__.py +85 -0
- tnfr/compat/dataclass.py +136 -0
- tnfr/compat/jsonschema_stub.py +61 -0
- tnfr/compat/matplotlib_stub.py +73 -0
- tnfr/compat/numpy_stub.py +155 -0
- tnfr/config/__init__.py +224 -0
- tnfr/config/__init__.pyi +10 -0
- tnfr/{constants_glyphs.py → config/constants.py} +26 -20
- tnfr/config/constants.pyi +12 -0
- tnfr/config/defaults.py +54 -0
- tnfr/{constants/core.py → config/defaults_core.py} +59 -6
- tnfr/config/defaults_init.py +33 -0
- tnfr/config/defaults_metric.py +104 -0
- tnfr/config/feature_flags.py +81 -0
- tnfr/config/feature_flags.pyi +16 -0
- tnfr/config/glyph_constants.py +31 -0
- tnfr/config/init.py +77 -0
- tnfr/config/init.pyi +8 -0
- tnfr/config/operator_names.py +254 -0
- tnfr/config/operator_names.pyi +36 -0
- tnfr/config/physics_derivation.py +354 -0
- tnfr/config/presets.py +83 -0
- tnfr/config/presets.pyi +7 -0
- tnfr/config/security.py +927 -0
- tnfr/config/thresholds.py +114 -0
- tnfr/config/tnfr_config.py +498 -0
- tnfr/constants/__init__.py +51 -133
- tnfr/constants/__init__.pyi +92 -0
- tnfr/constants/aliases.py +33 -0
- tnfr/constants/aliases.pyi +27 -0
- tnfr/constants/init.py +3 -1
- tnfr/constants/init.pyi +12 -0
- tnfr/constants/metric.py +9 -15
- tnfr/constants/metric.pyi +19 -0
- tnfr/core/__init__.py +33 -0
- tnfr/core/container.py +226 -0
- tnfr/core/default_implementations.py +329 -0
- tnfr/core/interfaces.py +279 -0
- tnfr/dynamics/__init__.py +213 -633
- tnfr/dynamics/__init__.pyi +83 -0
- tnfr/dynamics/adaptation.py +267 -0
- tnfr/dynamics/adaptation.pyi +7 -0
- tnfr/dynamics/adaptive_sequences.py +189 -0
- tnfr/dynamics/adaptive_sequences.pyi +14 -0
- tnfr/dynamics/aliases.py +23 -0
- tnfr/dynamics/aliases.pyi +19 -0
- tnfr/dynamics/bifurcation.py +232 -0
- tnfr/dynamics/canonical.py +229 -0
- tnfr/dynamics/canonical.pyi +48 -0
- tnfr/dynamics/coordination.py +385 -0
- tnfr/dynamics/coordination.pyi +25 -0
- tnfr/dynamics/dnfr.py +2699 -398
- tnfr/dynamics/dnfr.pyi +26 -0
- tnfr/dynamics/dynamic_limits.py +225 -0
- tnfr/dynamics/feedback.py +252 -0
- tnfr/dynamics/feedback.pyi +24 -0
- tnfr/dynamics/fused_dnfr.py +454 -0
- tnfr/dynamics/homeostasis.py +157 -0
- tnfr/dynamics/homeostasis.pyi +14 -0
- tnfr/dynamics/integrators.py +496 -102
- tnfr/dynamics/integrators.pyi +36 -0
- tnfr/dynamics/learning.py +310 -0
- tnfr/dynamics/learning.pyi +33 -0
- tnfr/dynamics/metabolism.py +254 -0
- tnfr/dynamics/nbody.py +796 -0
- tnfr/dynamics/nbody_tnfr.py +783 -0
- tnfr/dynamics/propagation.py +326 -0
- tnfr/dynamics/runtime.py +908 -0
- tnfr/dynamics/runtime.pyi +77 -0
- tnfr/dynamics/sampling.py +10 -5
- tnfr/dynamics/sampling.pyi +7 -0
- tnfr/dynamics/selectors.py +711 -0
- tnfr/dynamics/selectors.pyi +85 -0
- tnfr/dynamics/structural_clip.py +207 -0
- tnfr/errors/__init__.py +37 -0
- tnfr/errors/contextual.py +492 -0
- tnfr/execution.py +77 -55
- tnfr/execution.pyi +45 -0
- tnfr/extensions/__init__.py +205 -0
- tnfr/extensions/__init__.pyi +18 -0
- tnfr/extensions/base.py +173 -0
- tnfr/extensions/base.pyi +35 -0
- tnfr/extensions/business/__init__.py +71 -0
- tnfr/extensions/business/__init__.pyi +11 -0
- tnfr/extensions/business/cookbook.py +88 -0
- tnfr/extensions/business/cookbook.pyi +8 -0
- tnfr/extensions/business/health_analyzers.py +202 -0
- tnfr/extensions/business/health_analyzers.pyi +9 -0
- tnfr/extensions/business/patterns.py +183 -0
- tnfr/extensions/business/patterns.pyi +8 -0
- tnfr/extensions/medical/__init__.py +73 -0
- tnfr/extensions/medical/__init__.pyi +11 -0
- tnfr/extensions/medical/cookbook.py +88 -0
- tnfr/extensions/medical/cookbook.pyi +8 -0
- tnfr/extensions/medical/health_analyzers.py +181 -0
- tnfr/extensions/medical/health_analyzers.pyi +9 -0
- tnfr/extensions/medical/patterns.py +163 -0
- tnfr/extensions/medical/patterns.pyi +8 -0
- tnfr/flatten.py +29 -50
- tnfr/flatten.pyi +21 -0
- tnfr/gamma.py +66 -53
- tnfr/gamma.pyi +36 -0
- tnfr/glyph_history.py +144 -57
- tnfr/glyph_history.pyi +35 -0
- tnfr/glyph_runtime.py +19 -0
- tnfr/glyph_runtime.pyi +8 -0
- tnfr/immutable.py +70 -30
- tnfr/immutable.pyi +36 -0
- tnfr/initialization.py +22 -16
- tnfr/initialization.pyi +65 -0
- tnfr/io.py +5 -241
- tnfr/io.pyi +13 -0
- tnfr/locking.pyi +7 -0
- tnfr/mathematics/__init__.py +79 -0
- tnfr/mathematics/backend.py +453 -0
- tnfr/mathematics/backend.pyi +99 -0
- tnfr/mathematics/dynamics.py +408 -0
- tnfr/mathematics/dynamics.pyi +90 -0
- tnfr/mathematics/epi.py +391 -0
- tnfr/mathematics/epi.pyi +65 -0
- tnfr/mathematics/generators.py +242 -0
- tnfr/mathematics/generators.pyi +29 -0
- tnfr/mathematics/metrics.py +119 -0
- tnfr/mathematics/metrics.pyi +16 -0
- tnfr/mathematics/operators.py +239 -0
- tnfr/mathematics/operators.pyi +59 -0
- tnfr/mathematics/operators_factory.py +124 -0
- tnfr/mathematics/operators_factory.pyi +11 -0
- tnfr/mathematics/projection.py +87 -0
- tnfr/mathematics/projection.pyi +33 -0
- tnfr/mathematics/runtime.py +182 -0
- tnfr/mathematics/runtime.pyi +64 -0
- tnfr/mathematics/spaces.py +256 -0
- tnfr/mathematics/spaces.pyi +83 -0
- tnfr/mathematics/transforms.py +305 -0
- tnfr/mathematics/transforms.pyi +62 -0
- tnfr/metrics/__init__.py +47 -9
- tnfr/metrics/__init__.pyi +20 -0
- tnfr/metrics/buffer_cache.py +163 -0
- tnfr/metrics/buffer_cache.pyi +24 -0
- tnfr/metrics/cache_utils.py +214 -0
- tnfr/metrics/coherence.py +1510 -330
- tnfr/metrics/coherence.pyi +129 -0
- tnfr/metrics/common.py +23 -16
- tnfr/metrics/common.pyi +35 -0
- tnfr/metrics/core.py +251 -36
- tnfr/metrics/core.pyi +13 -0
- tnfr/metrics/diagnosis.py +709 -110
- tnfr/metrics/diagnosis.pyi +86 -0
- tnfr/metrics/emergence.py +245 -0
- tnfr/metrics/export.py +60 -18
- tnfr/metrics/export.pyi +7 -0
- tnfr/metrics/glyph_timing.py +233 -43
- tnfr/metrics/glyph_timing.pyi +81 -0
- tnfr/metrics/learning_metrics.py +280 -0
- tnfr/metrics/learning_metrics.pyi +21 -0
- tnfr/metrics/phase_coherence.py +351 -0
- tnfr/metrics/phase_compatibility.py +349 -0
- tnfr/metrics/reporting.py +63 -28
- tnfr/metrics/reporting.pyi +25 -0
- tnfr/metrics/sense_index.py +1126 -43
- tnfr/metrics/sense_index.pyi +9 -0
- tnfr/metrics/trig.py +215 -23
- tnfr/metrics/trig.pyi +13 -0
- tnfr/metrics/trig_cache.py +148 -24
- tnfr/metrics/trig_cache.pyi +10 -0
- tnfr/multiscale/__init__.py +32 -0
- tnfr/multiscale/hierarchical.py +517 -0
- tnfr/node.py +646 -140
- tnfr/node.pyi +139 -0
- tnfr/observers.py +160 -45
- tnfr/observers.pyi +31 -0
- tnfr/ontosim.py +23 -19
- tnfr/ontosim.pyi +28 -0
- tnfr/operators/__init__.py +1358 -106
- tnfr/operators/__init__.pyi +31 -0
- tnfr/operators/algebra.py +277 -0
- tnfr/operators/canonical_patterns.py +420 -0
- tnfr/operators/cascade.py +267 -0
- tnfr/operators/cycle_detection.py +358 -0
- tnfr/operators/definitions.py +4108 -0
- tnfr/operators/definitions.pyi +78 -0
- tnfr/operators/grammar.py +1164 -0
- tnfr/operators/grammar.pyi +140 -0
- tnfr/operators/hamiltonian.py +710 -0
- tnfr/operators/health_analyzer.py +809 -0
- tnfr/operators/jitter.py +107 -38
- tnfr/operators/jitter.pyi +11 -0
- tnfr/operators/lifecycle.py +314 -0
- tnfr/operators/metabolism.py +618 -0
- tnfr/operators/metrics.py +2138 -0
- tnfr/operators/network_analysis/__init__.py +27 -0
- tnfr/operators/network_analysis/source_detection.py +186 -0
- tnfr/operators/nodal_equation.py +395 -0
- tnfr/operators/pattern_detection.py +660 -0
- tnfr/operators/patterns.py +669 -0
- tnfr/operators/postconditions/__init__.py +38 -0
- tnfr/operators/postconditions/mutation.py +236 -0
- tnfr/operators/preconditions/__init__.py +1226 -0
- tnfr/operators/preconditions/coherence.py +305 -0
- tnfr/operators/preconditions/dissonance.py +236 -0
- tnfr/operators/preconditions/emission.py +128 -0
- tnfr/operators/preconditions/mutation.py +580 -0
- tnfr/operators/preconditions/reception.py +125 -0
- tnfr/operators/preconditions/resonance.py +364 -0
- tnfr/operators/registry.py +74 -0
- tnfr/operators/registry.pyi +9 -0
- tnfr/operators/remesh.py +1415 -91
- tnfr/operators/remesh.pyi +26 -0
- tnfr/operators/structural_units.py +268 -0
- tnfr/operators/unified_grammar.py +105 -0
- tnfr/parallel/__init__.py +54 -0
- tnfr/parallel/auto_scaler.py +234 -0
- tnfr/parallel/distributed.py +384 -0
- tnfr/parallel/engine.py +238 -0
- tnfr/parallel/gpu_engine.py +420 -0
- tnfr/parallel/monitoring.py +248 -0
- tnfr/parallel/partitioner.py +459 -0
- tnfr/py.typed +0 -0
- tnfr/recipes/__init__.py +22 -0
- tnfr/recipes/cookbook.py +743 -0
- tnfr/rng.py +75 -151
- tnfr/rng.pyi +26 -0
- tnfr/schemas/__init__.py +8 -0
- tnfr/schemas/grammar.json +94 -0
- tnfr/sdk/__init__.py +107 -0
- tnfr/sdk/__init__.pyi +19 -0
- tnfr/sdk/adaptive_system.py +173 -0
- tnfr/sdk/adaptive_system.pyi +21 -0
- tnfr/sdk/builders.py +370 -0
- tnfr/sdk/builders.pyi +51 -0
- tnfr/sdk/fluent.py +1121 -0
- tnfr/sdk/fluent.pyi +74 -0
- tnfr/sdk/templates.py +342 -0
- tnfr/sdk/templates.pyi +41 -0
- tnfr/sdk/utils.py +341 -0
- tnfr/secure_config.py +46 -0
- tnfr/security/__init__.py +70 -0
- tnfr/security/database.py +514 -0
- tnfr/security/subprocess.py +503 -0
- tnfr/security/validation.py +290 -0
- tnfr/selector.py +59 -22
- tnfr/selector.pyi +19 -0
- tnfr/sense.py +92 -67
- tnfr/sense.pyi +23 -0
- tnfr/services/__init__.py +17 -0
- tnfr/services/orchestrator.py +325 -0
- tnfr/sparse/__init__.py +39 -0
- tnfr/sparse/representations.py +492 -0
- tnfr/structural.py +639 -263
- tnfr/structural.pyi +83 -0
- tnfr/telemetry/__init__.py +35 -0
- tnfr/telemetry/cache_metrics.py +226 -0
- tnfr/telemetry/cache_metrics.pyi +64 -0
- tnfr/telemetry/nu_f.py +422 -0
- tnfr/telemetry/nu_f.pyi +108 -0
- tnfr/telemetry/verbosity.py +36 -0
- tnfr/telemetry/verbosity.pyi +15 -0
- tnfr/tokens.py +2 -4
- tnfr/tokens.pyi +36 -0
- tnfr/tools/__init__.py +20 -0
- tnfr/tools/domain_templates.py +478 -0
- tnfr/tools/sequence_generator.py +846 -0
- tnfr/topology/__init__.py +13 -0
- tnfr/topology/asymmetry.py +151 -0
- tnfr/trace.py +300 -126
- tnfr/trace.pyi +42 -0
- tnfr/tutorials/__init__.py +38 -0
- tnfr/tutorials/autonomous_evolution.py +285 -0
- tnfr/tutorials/interactive.py +1576 -0
- tnfr/tutorials/structural_metabolism.py +238 -0
- tnfr/types.py +743 -12
- tnfr/types.pyi +357 -0
- tnfr/units.py +68 -0
- tnfr/units.pyi +13 -0
- tnfr/utils/__init__.py +282 -0
- tnfr/utils/__init__.pyi +215 -0
- tnfr/utils/cache.py +4223 -0
- tnfr/utils/cache.pyi +470 -0
- tnfr/{callback_utils.py → utils/callbacks.py} +26 -39
- tnfr/utils/callbacks.pyi +49 -0
- tnfr/utils/chunks.py +108 -0
- tnfr/utils/chunks.pyi +22 -0
- tnfr/utils/data.py +428 -0
- tnfr/utils/data.pyi +74 -0
- tnfr/utils/graph.py +85 -0
- tnfr/utils/graph.pyi +10 -0
- tnfr/utils/init.py +821 -0
- tnfr/utils/init.pyi +80 -0
- tnfr/utils/io.py +559 -0
- tnfr/utils/io.pyi +66 -0
- tnfr/{helpers → utils}/numeric.py +51 -24
- tnfr/utils/numeric.pyi +21 -0
- tnfr/validation/__init__.py +257 -0
- tnfr/validation/__init__.pyi +85 -0
- tnfr/validation/compatibility.py +460 -0
- tnfr/validation/compatibility.pyi +6 -0
- tnfr/validation/config.py +73 -0
- tnfr/validation/graph.py +139 -0
- tnfr/validation/graph.pyi +18 -0
- tnfr/validation/input_validation.py +755 -0
- tnfr/validation/invariants.py +712 -0
- tnfr/validation/rules.py +253 -0
- tnfr/validation/rules.pyi +44 -0
- tnfr/validation/runtime.py +279 -0
- tnfr/validation/runtime.pyi +28 -0
- tnfr/validation/sequence_validator.py +162 -0
- tnfr/validation/soft_filters.py +170 -0
- tnfr/validation/soft_filters.pyi +32 -0
- tnfr/validation/spectral.py +164 -0
- tnfr/validation/spectral.pyi +42 -0
- tnfr/validation/validator.py +1266 -0
- tnfr/validation/window.py +39 -0
- tnfr/validation/window.pyi +1 -0
- tnfr/visualization/__init__.py +98 -0
- tnfr/visualization/cascade_viz.py +256 -0
- tnfr/visualization/hierarchy.py +284 -0
- tnfr/visualization/sequence_plotter.py +784 -0
- tnfr/viz/__init__.py +60 -0
- tnfr/viz/matplotlib.py +278 -0
- tnfr/viz/matplotlib.pyi +35 -0
- tnfr-8.5.0.dist-info/METADATA +573 -0
- tnfr-8.5.0.dist-info/RECORD +353 -0
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/entry_points.txt +1 -0
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/licenses/LICENSE.md +1 -1
- tnfr/collections_utils.py +0 -300
- tnfr/config.py +0 -32
- tnfr/grammar.py +0 -344
- tnfr/graph_utils.py +0 -84
- tnfr/helpers/__init__.py +0 -71
- tnfr/import_utils.py +0 -228
- tnfr/json_utils.py +0 -162
- tnfr/logging_utils.py +0 -116
- tnfr/presets.py +0 -60
- tnfr/validators.py +0 -84
- tnfr/value_utils.py +0 -59
- tnfr-4.5.2.dist-info/METADATA +0 -379
- tnfr-4.5.2.dist-info/RECORD +0 -67
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/WHEEL +0 -0
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
"""Vibrational metabolism functions for THOL (Self-organization) operator.
|
|
2
|
+
|
|
3
|
+
Implements canonical pattern digestion: capturing external network signals
|
|
4
|
+
and transforming them into internal structural reorganization (ΔNFR and sub-EPIs).
|
|
5
|
+
|
|
6
|
+
TNFR Canonical Principle
|
|
7
|
+
-------------------------
|
|
8
|
+
From "El pulso que nos atraviesa" (TNFR Manual, §2.2.10):
|
|
9
|
+
|
|
10
|
+
"THOL es el glifo de la autoorganización activa. No necesita intervención
|
|
11
|
+
externa, ni programación, ni control — su función es reorganizar la forma
|
|
12
|
+
desde dentro, en respuesta a la coherencia vibracional del campo."
|
|
13
|
+
|
|
14
|
+
"THOL no es una propiedad, es una dinámica. No es un atributo de lo vivo,
|
|
15
|
+
es lo que hace que algo esté vivo. La autoorganización no es espontaneidad
|
|
16
|
+
aleatoria, es resonancia estructurada desde el interior del nodo."
|
|
17
|
+
|
|
18
|
+
This module operationalizes vibrational metabolism:
|
|
19
|
+
1. **Capture**: Sample network environment (EPI gradient, phase variance, coupling)
|
|
20
|
+
2. **Metabolize**: Transform external patterns into internal structure (sub-EPIs)
|
|
21
|
+
3. **Integrate**: Sub-EPIs reflect both internal acceleration AND network context
|
|
22
|
+
|
|
23
|
+
Metabolic Formula
|
|
24
|
+
-----------------
|
|
25
|
+
sub-EPI = base_internal + network_contribution + complexity_bonus
|
|
26
|
+
|
|
27
|
+
Where:
|
|
28
|
+
- base_internal: parent_epi * scaling_factor (internal bifurcation)
|
|
29
|
+
- network_contribution: epi_gradient * weight (external pressure)
|
|
30
|
+
- complexity_bonus: phase_variance * weight (field complexity)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
import math
|
|
36
|
+
from typing import TYPE_CHECKING, Any
|
|
37
|
+
|
|
38
|
+
if TYPE_CHECKING:
|
|
39
|
+
from ..types import NodeId, TNFRGraph
|
|
40
|
+
|
|
41
|
+
from ..alias import get_attr
|
|
42
|
+
from ..constants.aliases import ALIAS_EPI, ALIAS_THETA
|
|
43
|
+
from ..utils import get_numpy
|
|
44
|
+
from ..utils.numeric import angle_diff
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
"capture_network_signals",
|
|
48
|
+
"metabolize_signals_into_subepi",
|
|
49
|
+
"propagate_subepi_to_network",
|
|
50
|
+
"compute_cascade_depth",
|
|
51
|
+
"compute_hierarchical_depth",
|
|
52
|
+
"compute_propagation_radius",
|
|
53
|
+
"compute_subepi_collective_coherence",
|
|
54
|
+
"compute_metabolic_activity_index",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def capture_network_signals(G: TNFRGraph, node: NodeId) -> dict[str, Any] | None:
|
|
59
|
+
"""Capture external vibrational patterns from coupled neighbors.
|
|
60
|
+
|
|
61
|
+
This function implements the "perception" phase of THOL's vibrational metabolism.
|
|
62
|
+
It samples the network environment around the target node, computing structural
|
|
63
|
+
gradients, phase variance, and coupling strength.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
G : TNFRGraph
|
|
68
|
+
Graph containing the node and its network context
|
|
69
|
+
node : NodeId
|
|
70
|
+
Node performing metabolic capture
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
dict | None
|
|
75
|
+
Network signal structure containing:
|
|
76
|
+
- epi_gradient: Difference between mean neighbor EPI and node EPI
|
|
77
|
+
- phase_variance: Variance of neighbor phases (instability indicator)
|
|
78
|
+
- neighbor_count: Number of coupled neighbors
|
|
79
|
+
- coupling_strength_mean: Average phase alignment with neighbors
|
|
80
|
+
- mean_neighbor_epi: Mean EPI value of neighbors
|
|
81
|
+
Returns None if node has no neighbors (isolated metabolism).
|
|
82
|
+
|
|
83
|
+
Notes
|
|
84
|
+
-----
|
|
85
|
+
TNFR Principle: THOL doesn't operate in vacuum—it metabolizes the network's
|
|
86
|
+
vibrational field. EPI gradient represents "structural pressure" from environment.
|
|
87
|
+
Phase variance indicates "complexity" of external patterns to digest.
|
|
88
|
+
|
|
89
|
+
Examples
|
|
90
|
+
--------
|
|
91
|
+
>>> # Node with coherent neighbors (low variance)
|
|
92
|
+
>>> signals = capture_network_signals(G, node)
|
|
93
|
+
>>> signals["phase_variance"] # Low = stable field
|
|
94
|
+
0.02
|
|
95
|
+
|
|
96
|
+
>>> # Node in dissonant field (high variance)
|
|
97
|
+
>>> signals = capture_network_signals(G_dissonant, node)
|
|
98
|
+
>>> signals["phase_variance"] # High = complex field
|
|
99
|
+
0.45
|
|
100
|
+
"""
|
|
101
|
+
np = get_numpy()
|
|
102
|
+
from ..metrics.phase_compatibility import compute_phase_coupling_strength
|
|
103
|
+
|
|
104
|
+
neighbors = list(G.neighbors(node))
|
|
105
|
+
if not neighbors:
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
node_epi = float(get_attr(G.nodes[node], ALIAS_EPI, 0.0))
|
|
109
|
+
node_theta = float(get_attr(G.nodes[node], ALIAS_THETA, 0.0))
|
|
110
|
+
|
|
111
|
+
# Aggregate neighbor states
|
|
112
|
+
neighbor_epis = []
|
|
113
|
+
neighbor_thetas = []
|
|
114
|
+
coupling_strengths = []
|
|
115
|
+
|
|
116
|
+
for n in neighbors:
|
|
117
|
+
n_epi = float(get_attr(G.nodes[n], ALIAS_EPI, 0.0))
|
|
118
|
+
n_theta = float(get_attr(G.nodes[n], ALIAS_THETA, 0.0))
|
|
119
|
+
|
|
120
|
+
neighbor_epis.append(n_epi)
|
|
121
|
+
neighbor_thetas.append(n_theta)
|
|
122
|
+
|
|
123
|
+
# Coupling strength using canonical phase compatibility formula
|
|
124
|
+
# (unified across UM, RA, THOL operators - see phase_compatibility module)
|
|
125
|
+
coupling_strength = compute_phase_coupling_strength(node_theta, n_theta)
|
|
126
|
+
coupling_strengths.append(coupling_strength)
|
|
127
|
+
|
|
128
|
+
# Compute structural gradients
|
|
129
|
+
mean_neighbor_epi = float(np.mean(neighbor_epis))
|
|
130
|
+
epi_gradient = mean_neighbor_epi - node_epi
|
|
131
|
+
|
|
132
|
+
# Phase variance (complexity/dissonance indicator)
|
|
133
|
+
phase_variance = float(np.var(neighbor_thetas))
|
|
134
|
+
|
|
135
|
+
# Mean coupling strength
|
|
136
|
+
coupling_strength_mean = float(np.mean(coupling_strengths))
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
"epi_gradient": epi_gradient,
|
|
140
|
+
"phase_variance": phase_variance,
|
|
141
|
+
"neighbor_count": len(neighbors),
|
|
142
|
+
"coupling_strength_mean": coupling_strength_mean,
|
|
143
|
+
"mean_neighbor_epi": mean_neighbor_epi,
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def metabolize_signals_into_subepi(
|
|
148
|
+
parent_epi: float,
|
|
149
|
+
signals: dict[str, Any] | None,
|
|
150
|
+
d2_epi: float,
|
|
151
|
+
scaling_factor: float = 0.25,
|
|
152
|
+
gradient_weight: float = 0.15,
|
|
153
|
+
complexity_weight: float = 0.10,
|
|
154
|
+
) -> float:
|
|
155
|
+
"""Transform external signals into sub-EPI structure through metabolism.
|
|
156
|
+
|
|
157
|
+
This function implements the "digestion" phase of THOL's vibrational metabolism.
|
|
158
|
+
It combines internal acceleration (d²EPI/dt²) with external network pressure
|
|
159
|
+
to compute the magnitude of emergent sub-EPI.
|
|
160
|
+
|
|
161
|
+
Parameters
|
|
162
|
+
----------
|
|
163
|
+
parent_epi : float
|
|
164
|
+
Current EPI magnitude of parent node
|
|
165
|
+
signals : dict | None
|
|
166
|
+
Network signals captured from environment (from capture_network_signals).
|
|
167
|
+
If None, falls back to internal bifurcation only.
|
|
168
|
+
d2_epi : float
|
|
169
|
+
Internal structural acceleration (∂²EPI/∂t²)
|
|
170
|
+
scaling_factor : float, default 0.25
|
|
171
|
+
Canonical THOL sub-EPI scaling (0.25 = 25% of parent)
|
|
172
|
+
gradient_weight : float, default 0.15
|
|
173
|
+
Weight for external EPI gradient contribution
|
|
174
|
+
complexity_weight : float, default 0.10
|
|
175
|
+
Weight for phase variance complexity bonus
|
|
176
|
+
|
|
177
|
+
Returns
|
|
178
|
+
-------
|
|
179
|
+
float
|
|
180
|
+
Metabolized sub-EPI magnitude, bounded to [0, 1.0]
|
|
181
|
+
|
|
182
|
+
Notes
|
|
183
|
+
-----
|
|
184
|
+
TNFR Metabolic Formula:
|
|
185
|
+
|
|
186
|
+
sub-EPI = base_internal + network_contribution + complexity_bonus
|
|
187
|
+
|
|
188
|
+
Where:
|
|
189
|
+
- base_internal: parent_epi * scaling_factor (internal bifurcation)
|
|
190
|
+
- network_contribution: epi_gradient * weight (external pressure)
|
|
191
|
+
- complexity_bonus: phase_variance * weight (field complexity)
|
|
192
|
+
|
|
193
|
+
This reflects canonical principle: "THOL reorganizes external experience
|
|
194
|
+
into internal structure without external instruction" (Manual TNFR, p. 112).
|
|
195
|
+
|
|
196
|
+
Examples
|
|
197
|
+
--------
|
|
198
|
+
>>> # Internal bifurcation only (isolated node)
|
|
199
|
+
>>> metabolize_signals_into_subepi(0.60, None, d2_epi=0.15)
|
|
200
|
+
0.15
|
|
201
|
+
|
|
202
|
+
>>> # Metabolizing network pressure
|
|
203
|
+
>>> signals = {"epi_gradient": 0.20, "phase_variance": 0.10, ...}
|
|
204
|
+
>>> metabolize_signals_into_subepi(0.60, signals, d2_epi=0.15)
|
|
205
|
+
0.21 # Enhanced by network context
|
|
206
|
+
"""
|
|
207
|
+
np = get_numpy()
|
|
208
|
+
|
|
209
|
+
# Base: Internal bifurcation (existing behavior)
|
|
210
|
+
base_sub_epi = parent_epi * scaling_factor
|
|
211
|
+
|
|
212
|
+
# If isolated, return internal bifurcation only
|
|
213
|
+
if signals is None:
|
|
214
|
+
return float(np.clip(base_sub_epi, 0.0, 1.0))
|
|
215
|
+
|
|
216
|
+
# Network contribution: EPI gradient pressure
|
|
217
|
+
network_contribution = signals["epi_gradient"] * gradient_weight
|
|
218
|
+
|
|
219
|
+
# Complexity bonus: Phase variance indicates rich field to metabolize
|
|
220
|
+
complexity_bonus = signals["phase_variance"] * complexity_weight
|
|
221
|
+
|
|
222
|
+
# Combine internal + external
|
|
223
|
+
metabolized_epi = base_sub_epi + network_contribution + complexity_bonus
|
|
224
|
+
|
|
225
|
+
# Structural bounds [0, 1]
|
|
226
|
+
return float(np.clip(metabolized_epi, 0.0, 1.0))
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def propagate_subepi_to_network(
|
|
230
|
+
G: TNFRGraph,
|
|
231
|
+
parent_node: NodeId,
|
|
232
|
+
sub_epi_record: dict[str, Any],
|
|
233
|
+
) -> list[tuple[NodeId, float]]:
|
|
234
|
+
"""Propagate emergent sub-EPI to coupled neighbors through resonance.
|
|
235
|
+
|
|
236
|
+
Implements canonical THOL network dynamics: bifurcation creates structures
|
|
237
|
+
that propagate through coupled nodes, triggering potential cascades.
|
|
238
|
+
|
|
239
|
+
Parameters
|
|
240
|
+
----------
|
|
241
|
+
G : TNFRGraph
|
|
242
|
+
Graph containing the network
|
|
243
|
+
parent_node : NodeId
|
|
244
|
+
Node where sub-EPI originated (bifurcation source)
|
|
245
|
+
sub_epi_record : dict
|
|
246
|
+
Sub-EPI record from bifurcation, containing:
|
|
247
|
+
- "epi": sub-EPI magnitude
|
|
248
|
+
- "vf": inherited structural frequency
|
|
249
|
+
- "timestamp": creation time
|
|
250
|
+
|
|
251
|
+
Returns
|
|
252
|
+
-------
|
|
253
|
+
list of (NodeId, float)
|
|
254
|
+
List of (neighbor_id, injected_epi) tuples showing propagation results.
|
|
255
|
+
Empty list if no propagation occurred.
|
|
256
|
+
|
|
257
|
+
Notes
|
|
258
|
+
-----
|
|
259
|
+
TNFR Principle: "Sub-EPIs propagate to coupled neighbors, triggering their
|
|
260
|
+
own bifurcations when ∂²EPI/∂t² > τ" (canonical THOL dynamics).
|
|
261
|
+
|
|
262
|
+
**AGENTS.md Invariant #5**: No coupling is valid without explicit phase
|
|
263
|
+
verification. This function enforces phase compatibility before propagation:
|
|
264
|
+
- Computes coupling_strength = 1.0 - (|Δθ| / π) using angle_diff()
|
|
265
|
+
- Rejects neighbors with coupling_strength < threshold (antiphase blocked)
|
|
266
|
+
- Ensures resonance physics: only phase-aligned nodes receive sub-EPIs
|
|
267
|
+
|
|
268
|
+
Propagation mechanism:
|
|
269
|
+
1. Select neighbors with sufficient coupling (phase alignment)
|
|
270
|
+
2. Compute attenuation based on coupling strength
|
|
271
|
+
3. Inject attenuated sub-EPI influence into neighbor's EPI
|
|
272
|
+
4. Record propagation in graph telemetry
|
|
273
|
+
|
|
274
|
+
Attenuation prevents unbounded growth while enabling cascades.
|
|
275
|
+
|
|
276
|
+
Examples
|
|
277
|
+
--------
|
|
278
|
+
>>> # Create coupled network
|
|
279
|
+
>>> G = nx.Graph()
|
|
280
|
+
>>> G.add_node(0, epi=0.50, vf=1.0, theta=0.1)
|
|
281
|
+
>>> G.add_node(1, epi=0.40, vf=1.0, theta=0.12) # Phase-aligned
|
|
282
|
+
>>> G.add_edge(0, 1)
|
|
283
|
+
>>> sub_epi = {"epi": 0.15, "vf": 1.1, "timestamp": 10}
|
|
284
|
+
>>> propagations = propagate_subepi_to_network(G, node=0, sub_epi_record=sub_epi)
|
|
285
|
+
>>> len(propagations) # Number of neighbors reached
|
|
286
|
+
1
|
|
287
|
+
>>> propagations[0] # (neighbor_id, injected_epi)
|
|
288
|
+
(1, 0.105) # 70% attenuation
|
|
289
|
+
"""
|
|
290
|
+
from ..alias import set_attr
|
|
291
|
+
from ..metrics.phase_compatibility import compute_phase_coupling_strength
|
|
292
|
+
|
|
293
|
+
neighbors = list(G.neighbors(parent_node))
|
|
294
|
+
if not neighbors:
|
|
295
|
+
return []
|
|
296
|
+
|
|
297
|
+
# Configuration
|
|
298
|
+
min_coupling_strength = float(G.graph.get("THOL_MIN_COUPLING_FOR_PROPAGATION", 0.5))
|
|
299
|
+
attenuation_factor = float(G.graph.get("THOL_PROPAGATION_ATTENUATION", 0.7))
|
|
300
|
+
|
|
301
|
+
parent_theta = float(get_attr(G.nodes[parent_node], ALIAS_THETA, 0.0))
|
|
302
|
+
sub_epi_magnitude = sub_epi_record["epi"]
|
|
303
|
+
|
|
304
|
+
propagations = []
|
|
305
|
+
|
|
306
|
+
for neighbor in neighbors:
|
|
307
|
+
neighbor_theta = float(get_attr(G.nodes[neighbor], ALIAS_THETA, 0.0))
|
|
308
|
+
|
|
309
|
+
# INVARIANT #5: Phase verification before coupling
|
|
310
|
+
# Compute coupling strength based on phase alignment
|
|
311
|
+
# coupling_strength ∈ [0, 1]: 1 = in-phase, 0 = antiphase
|
|
312
|
+
phase_diff = abs(angle_diff(neighbor_theta, parent_theta))
|
|
313
|
+
coupling_strength = 1.0 - (phase_diff / math.pi)
|
|
314
|
+
|
|
315
|
+
# Propagate only if sufficiently coupled (phase-aligned)
|
|
316
|
+
# Antiphase neighbors (Δθ ≈ π) have coupling_strength ≈ 0, blocked by threshold
|
|
317
|
+
if coupling_strength >= min_coupling_strength:
|
|
318
|
+
# Attenuate sub-EPI based on distance and coupling
|
|
319
|
+
attenuated_epi = sub_epi_magnitude * attenuation_factor * coupling_strength
|
|
320
|
+
|
|
321
|
+
# Inject into neighbor's EPI
|
|
322
|
+
neighbor_epi = float(get_attr(G.nodes[neighbor], ALIAS_EPI, 0.0))
|
|
323
|
+
new_neighbor_epi = neighbor_epi + attenuated_epi
|
|
324
|
+
|
|
325
|
+
# Boundary check
|
|
326
|
+
from ..dynamics.structural_clip import structural_clip
|
|
327
|
+
|
|
328
|
+
epi_max = float(G.graph.get("EPI_MAX", 1.0))
|
|
329
|
+
new_neighbor_epi = structural_clip(new_neighbor_epi, lo=0.0, hi=epi_max)
|
|
330
|
+
|
|
331
|
+
set_attr(G.nodes[neighbor], ALIAS_EPI, new_neighbor_epi)
|
|
332
|
+
|
|
333
|
+
propagations.append((neighbor, attenuated_epi))
|
|
334
|
+
|
|
335
|
+
# Update neighbor's EPI history for potential subsequent bifurcation
|
|
336
|
+
history = G.nodes[neighbor].get("epi_history", [])
|
|
337
|
+
history.append(new_neighbor_epi)
|
|
338
|
+
G.nodes[neighbor]["epi_history"] = history[-10:] # Keep last 10
|
|
339
|
+
|
|
340
|
+
return propagations
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def compute_cascade_depth(G: TNFRGraph, node: NodeId) -> int:
|
|
344
|
+
"""Compute maximum hierarchical depth of bifurcation cascade.
|
|
345
|
+
|
|
346
|
+
Recursively measures how many levels of nested sub-EPIs exist,
|
|
347
|
+
where each sub-EPI can itself bifurcate into deeper levels.
|
|
348
|
+
|
|
349
|
+
With architectural refactor: sub-EPIs are now independent NFR nodes,
|
|
350
|
+
enabling true recursive depth computation.
|
|
351
|
+
|
|
352
|
+
Parameters
|
|
353
|
+
----------
|
|
354
|
+
G : TNFRGraph
|
|
355
|
+
Graph containing bifurcation history
|
|
356
|
+
node : NodeId
|
|
357
|
+
Root node of cascade analysis
|
|
358
|
+
|
|
359
|
+
Returns
|
|
360
|
+
-------
|
|
361
|
+
int
|
|
362
|
+
Maximum cascade depth (0 if no bifurcation occurred)
|
|
363
|
+
|
|
364
|
+
Examples
|
|
365
|
+
--------
|
|
366
|
+
>>> # Single-level bifurcation
|
|
367
|
+
>>> compute_cascade_depth(G, node)
|
|
368
|
+
1
|
|
369
|
+
|
|
370
|
+
>>> # Multi-level cascade (sub-EPIs bifurcated further)
|
|
371
|
+
>>> compute_cascade_depth(G_complex, node)
|
|
372
|
+
3
|
|
373
|
+
|
|
374
|
+
Notes
|
|
375
|
+
-----
|
|
376
|
+
TNFR Principle: Cascade depth measures the hierarchical complexity
|
|
377
|
+
of emergent self-organization. Depth = 1 indicates direct bifurcation;
|
|
378
|
+
depth > 1 indicates recursive, multi-scale emergence.
|
|
379
|
+
|
|
380
|
+
ARCHITECTURAL: Now supports true recursive bifurcation with independent
|
|
381
|
+
sub-nodes. If a node has no independent sub-nodes, falls back to
|
|
382
|
+
metadata-based depth for backward compatibility.
|
|
383
|
+
"""
|
|
384
|
+
# Primary path: Check for independent sub-nodes (new architecture)
|
|
385
|
+
sub_nodes = G.nodes[node].get("sub_nodes", [])
|
|
386
|
+
if sub_nodes:
|
|
387
|
+
# Recursive computation with actual nodes
|
|
388
|
+
max_depth = 0
|
|
389
|
+
for sub_node_id in sub_nodes:
|
|
390
|
+
if sub_node_id in G.nodes:
|
|
391
|
+
# Recurse into child's depth
|
|
392
|
+
child_depth = compute_cascade_depth(G, sub_node_id)
|
|
393
|
+
max_depth = max(max_depth, 1 + child_depth)
|
|
394
|
+
else:
|
|
395
|
+
# Child node exists in list but not in graph (shouldn't happen)
|
|
396
|
+
max_depth = max(max_depth, 1)
|
|
397
|
+
return max_depth
|
|
398
|
+
|
|
399
|
+
# Fallback path: Legacy metadata-based depth
|
|
400
|
+
sub_epis = G.nodes[node].get("sub_epis", [])
|
|
401
|
+
if not sub_epis:
|
|
402
|
+
return 0
|
|
403
|
+
|
|
404
|
+
max_depth = 1
|
|
405
|
+
for sub in sub_epis:
|
|
406
|
+
# Check if sub-EPI has node_id (new architecture with metadata)
|
|
407
|
+
if "node_id" in sub and sub["node_id"] in G.nodes:
|
|
408
|
+
# Recurse into independent node
|
|
409
|
+
child_depth = compute_cascade_depth(G, sub["node_id"])
|
|
410
|
+
max_depth = max(max_depth, 1 + child_depth)
|
|
411
|
+
else:
|
|
412
|
+
# Legacy metadata-only mode
|
|
413
|
+
nested_depth = sub.get("cascade_depth", 0)
|
|
414
|
+
max_depth = max(max_depth, 1 + nested_depth)
|
|
415
|
+
|
|
416
|
+
return max_depth
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def compute_hierarchical_depth(G: TNFRGraph, node: NodeId) -> int:
|
|
420
|
+
"""Compute maximum bifurcation depth from node using recursive traversal.
|
|
421
|
+
|
|
422
|
+
Traverses sub-EPI hierarchy recursively to find the maximum bifurcation_level
|
|
423
|
+
across all nested branches. This provides accurate hierarchical telemetry for
|
|
424
|
+
nested THOL bifurcations, supporting operational fractality analysis.
|
|
425
|
+
|
|
426
|
+
Parameters
|
|
427
|
+
----------
|
|
428
|
+
G : TNFRGraph
|
|
429
|
+
Network graph
|
|
430
|
+
node : NodeId
|
|
431
|
+
Root node to measure depth from
|
|
432
|
+
|
|
433
|
+
Returns
|
|
434
|
+
-------
|
|
435
|
+
int
|
|
436
|
+
Maximum bifurcation depth (0 = no bifurcations, 1 = single-level, etc.)
|
|
437
|
+
|
|
438
|
+
Notes
|
|
439
|
+
-----
|
|
440
|
+
TNFR Principle: Hierarchical depth reflects operational fractality
|
|
441
|
+
(Invariant #7) - the ability of sub-EPIs to bifurcate recursively,
|
|
442
|
+
creating multi-scale emergent structures.
|
|
443
|
+
|
|
444
|
+
This function recursively traverses all branches to find the deepest
|
|
445
|
+
bifurcation_level, providing precise depth tracking for:
|
|
446
|
+
- Debugging complex nested structures
|
|
447
|
+
- Validating depth limits
|
|
448
|
+
- Analyzing bifurcation patterns
|
|
449
|
+
- Performance monitoring
|
|
450
|
+
|
|
451
|
+
Examples
|
|
452
|
+
--------
|
|
453
|
+
>>> # Node with no bifurcations
|
|
454
|
+
>>> compute_hierarchical_depth(G, node)
|
|
455
|
+
0
|
|
456
|
+
|
|
457
|
+
>>> # Node with single-level bifurcation
|
|
458
|
+
>>> compute_hierarchical_depth(G, node_with_subs)
|
|
459
|
+
1
|
|
460
|
+
|
|
461
|
+
>>> # Node with 2-level nested bifurcation
|
|
462
|
+
>>> compute_hierarchical_depth(G, node_nested)
|
|
463
|
+
2
|
|
464
|
+
"""
|
|
465
|
+
sub_epis = G.nodes[node].get("sub_epis", [])
|
|
466
|
+
|
|
467
|
+
if not sub_epis:
|
|
468
|
+
return 0
|
|
469
|
+
|
|
470
|
+
# Recursively find the maximum bifurcation_level across all branches
|
|
471
|
+
max_level = 0
|
|
472
|
+
for sub_epi in sub_epis:
|
|
473
|
+
# Get this sub-EPI's bifurcation level
|
|
474
|
+
level = sub_epi.get("bifurcation_level", 1)
|
|
475
|
+
max_level = max(max_level, level)
|
|
476
|
+
|
|
477
|
+
# Recurse into sub-node if it exists to find deeper levels
|
|
478
|
+
sub_node_id = sub_epi.get("node_id")
|
|
479
|
+
if sub_node_id and sub_node_id in G.nodes:
|
|
480
|
+
# Recursively check this sub-node's depth
|
|
481
|
+
sub_depth = compute_hierarchical_depth(G, sub_node_id)
|
|
482
|
+
# If sub-node has bifurcations, its depth represents deeper levels
|
|
483
|
+
if sub_depth > 0:
|
|
484
|
+
max_level = max(max_level, sub_depth)
|
|
485
|
+
|
|
486
|
+
return max_level
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def compute_propagation_radius(G: TNFRGraph) -> int:
|
|
490
|
+
"""Count total unique nodes affected by THOL cascades.
|
|
491
|
+
|
|
492
|
+
Parameters
|
|
493
|
+
----------
|
|
494
|
+
G : TNFRGraph
|
|
495
|
+
Graph with THOL propagation history
|
|
496
|
+
|
|
497
|
+
Returns
|
|
498
|
+
-------
|
|
499
|
+
int
|
|
500
|
+
Number of nodes reached by at least one propagation event
|
|
501
|
+
|
|
502
|
+
Notes
|
|
503
|
+
-----
|
|
504
|
+
TNFR Principle: Propagation radius measures the spatial extent
|
|
505
|
+
of cascade effects across the network. High radius indicates
|
|
506
|
+
network-wide self-organization.
|
|
507
|
+
|
|
508
|
+
Examples
|
|
509
|
+
--------
|
|
510
|
+
>>> # Local cascade (few nodes)
|
|
511
|
+
>>> compute_propagation_radius(G_local)
|
|
512
|
+
3
|
|
513
|
+
|
|
514
|
+
>>> # Network-wide cascade
|
|
515
|
+
>>> compute_propagation_radius(G_wide)
|
|
516
|
+
15
|
|
517
|
+
"""
|
|
518
|
+
propagations = G.graph.get("thol_propagations", [])
|
|
519
|
+
affected_nodes = set()
|
|
520
|
+
|
|
521
|
+
for prop in propagations:
|
|
522
|
+
affected_nodes.add(prop["source_node"])
|
|
523
|
+
for target, _ in prop["propagations"]:
|
|
524
|
+
affected_nodes.add(target)
|
|
525
|
+
|
|
526
|
+
return len(affected_nodes)
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def compute_subepi_collective_coherence(G: TNFRGraph, node: NodeId) -> float:
|
|
530
|
+
"""Calculate coherence of sub-EPI ensemble.
|
|
531
|
+
|
|
532
|
+
Measures how structurally aligned the emergent sub-EPIs are.
|
|
533
|
+
Low variance = high coherence = stable emergence.
|
|
534
|
+
|
|
535
|
+
Parameters
|
|
536
|
+
----------
|
|
537
|
+
G : TNFRGraph
|
|
538
|
+
Graph containing the node
|
|
539
|
+
node : NodeId
|
|
540
|
+
Node with sub-EPIs to analyze
|
|
541
|
+
|
|
542
|
+
Returns
|
|
543
|
+
-------
|
|
544
|
+
float
|
|
545
|
+
Coherence metric [0, 1] where 1 = perfect alignment
|
|
546
|
+
|
|
547
|
+
Notes
|
|
548
|
+
-----
|
|
549
|
+
Uses variance-based coherence:
|
|
550
|
+
C_sub = 1 / (1 + var(sub_epi_magnitudes))
|
|
551
|
+
|
|
552
|
+
TNFR Principle: Coherent bifurcation produces sub-EPIs with similar
|
|
553
|
+
structural magnitudes, indicating controlled emergence vs chaotic
|
|
554
|
+
fragmentation.
|
|
555
|
+
|
|
556
|
+
Examples
|
|
557
|
+
--------
|
|
558
|
+
>>> # Coherent bifurcation (similar sub-EPIs)
|
|
559
|
+
>>> compute_subepi_collective_coherence(G, node)
|
|
560
|
+
0.85
|
|
561
|
+
|
|
562
|
+
>>> # Chaotic fragmentation (varied sub-EPIs)
|
|
563
|
+
>>> compute_subepi_collective_coherence(G_chaotic, node)
|
|
564
|
+
0.23
|
|
565
|
+
"""
|
|
566
|
+
np = get_numpy()
|
|
567
|
+
|
|
568
|
+
sub_epis = G.nodes[node].get("sub_epis", [])
|
|
569
|
+
if len(sub_epis) < 2:
|
|
570
|
+
return 0.0 # Need ≥2 sub-EPIs to measure coherence
|
|
571
|
+
|
|
572
|
+
epi_values = [sub["epi"] for sub in sub_epis]
|
|
573
|
+
variance = float(np.var(epi_values))
|
|
574
|
+
|
|
575
|
+
# Coherence: inverse relationship with variance
|
|
576
|
+
coherence = 1.0 / (1.0 + variance)
|
|
577
|
+
return coherence
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
def compute_metabolic_activity_index(G: TNFRGraph, node: NodeId) -> float:
|
|
581
|
+
"""Measure proportion of sub-EPIs generated through network metabolism.
|
|
582
|
+
|
|
583
|
+
Parameters
|
|
584
|
+
----------
|
|
585
|
+
G : TNFRGraph
|
|
586
|
+
Graph containing the node
|
|
587
|
+
node : NodeId
|
|
588
|
+
Node to analyze
|
|
589
|
+
|
|
590
|
+
Returns
|
|
591
|
+
-------
|
|
592
|
+
float
|
|
593
|
+
Ratio [0, 1] of metabolized sub-EPIs to total sub-EPIs
|
|
594
|
+
1.0 = all sub-EPIs included network context
|
|
595
|
+
0.0 = all sub-EPIs were purely internal bifurcations
|
|
596
|
+
|
|
597
|
+
Notes
|
|
598
|
+
-----
|
|
599
|
+
TNFR Principle: Metabolic activity measures how much network context
|
|
600
|
+
influenced bifurcation. High index indicates external pressure drove
|
|
601
|
+
emergence; low index indicates internal acceleration dominated.
|
|
602
|
+
|
|
603
|
+
Examples
|
|
604
|
+
--------
|
|
605
|
+
>>> # Network-driven bifurcation
|
|
606
|
+
>>> compute_metabolic_activity_index(G_coupled, node)
|
|
607
|
+
0.90
|
|
608
|
+
|
|
609
|
+
>>> # Internal-only bifurcation
|
|
610
|
+
>>> compute_metabolic_activity_index(G_isolated, node)
|
|
611
|
+
0.0
|
|
612
|
+
"""
|
|
613
|
+
sub_epis = G.nodes[node].get("sub_epis", [])
|
|
614
|
+
if not sub_epis:
|
|
615
|
+
return 0.0
|
|
616
|
+
|
|
617
|
+
metabolized_count = sum(1 for sub in sub_epis if sub.get("metabolized", False))
|
|
618
|
+
return metabolized_count / len(sub_epis)
|