tnfr 3.0.3__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.

Files changed (360) hide show
  1. tnfr/__init__.py +375 -56
  2. tnfr/__init__.pyi +33 -0
  3. tnfr/_compat.py +10 -0
  4. tnfr/_generated_version.py +34 -0
  5. tnfr/_version.py +49 -0
  6. tnfr/_version.pyi +7 -0
  7. tnfr/alias.py +723 -0
  8. tnfr/alias.pyi +108 -0
  9. tnfr/backends/__init__.py +354 -0
  10. tnfr/backends/jax_backend.py +173 -0
  11. tnfr/backends/numpy_backend.py +238 -0
  12. tnfr/backends/optimized_numpy.py +420 -0
  13. tnfr/backends/torch_backend.py +408 -0
  14. tnfr/cache.py +171 -0
  15. tnfr/cache.pyi +13 -0
  16. tnfr/cli/__init__.py +110 -0
  17. tnfr/cli/__init__.pyi +26 -0
  18. tnfr/cli/arguments.py +489 -0
  19. tnfr/cli/arguments.pyi +29 -0
  20. tnfr/cli/execution.py +914 -0
  21. tnfr/cli/execution.pyi +70 -0
  22. tnfr/cli/interactive_validator.py +614 -0
  23. tnfr/cli/utils.py +51 -0
  24. tnfr/cli/utils.pyi +7 -0
  25. tnfr/cli/validate.py +236 -0
  26. tnfr/compat/__init__.py +85 -0
  27. tnfr/compat/dataclass.py +136 -0
  28. tnfr/compat/jsonschema_stub.py +61 -0
  29. tnfr/compat/matplotlib_stub.py +73 -0
  30. tnfr/compat/numpy_stub.py +155 -0
  31. tnfr/config/__init__.py +224 -0
  32. tnfr/config/__init__.pyi +10 -0
  33. tnfr/config/constants.py +104 -0
  34. tnfr/config/constants.pyi +12 -0
  35. tnfr/config/defaults.py +54 -0
  36. tnfr/config/defaults_core.py +212 -0
  37. tnfr/config/defaults_init.py +33 -0
  38. tnfr/config/defaults_metric.py +104 -0
  39. tnfr/config/feature_flags.py +81 -0
  40. tnfr/config/feature_flags.pyi +16 -0
  41. tnfr/config/glyph_constants.py +31 -0
  42. tnfr/config/init.py +77 -0
  43. tnfr/config/init.pyi +8 -0
  44. tnfr/config/operator_names.py +254 -0
  45. tnfr/config/operator_names.pyi +36 -0
  46. tnfr/config/physics_derivation.py +354 -0
  47. tnfr/config/presets.py +83 -0
  48. tnfr/config/presets.pyi +7 -0
  49. tnfr/config/security.py +927 -0
  50. tnfr/config/thresholds.py +114 -0
  51. tnfr/config/tnfr_config.py +498 -0
  52. tnfr/constants/__init__.py +92 -0
  53. tnfr/constants/__init__.pyi +92 -0
  54. tnfr/constants/aliases.py +33 -0
  55. tnfr/constants/aliases.pyi +27 -0
  56. tnfr/constants/init.py +33 -0
  57. tnfr/constants/init.pyi +12 -0
  58. tnfr/constants/metric.py +104 -0
  59. tnfr/constants/metric.pyi +19 -0
  60. tnfr/core/__init__.py +33 -0
  61. tnfr/core/container.py +226 -0
  62. tnfr/core/default_implementations.py +329 -0
  63. tnfr/core/interfaces.py +279 -0
  64. tnfr/dynamics/__init__.py +238 -0
  65. tnfr/dynamics/__init__.pyi +83 -0
  66. tnfr/dynamics/adaptation.py +267 -0
  67. tnfr/dynamics/adaptation.pyi +7 -0
  68. tnfr/dynamics/adaptive_sequences.py +189 -0
  69. tnfr/dynamics/adaptive_sequences.pyi +14 -0
  70. tnfr/dynamics/aliases.py +23 -0
  71. tnfr/dynamics/aliases.pyi +19 -0
  72. tnfr/dynamics/bifurcation.py +232 -0
  73. tnfr/dynamics/canonical.py +229 -0
  74. tnfr/dynamics/canonical.pyi +48 -0
  75. tnfr/dynamics/coordination.py +385 -0
  76. tnfr/dynamics/coordination.pyi +25 -0
  77. tnfr/dynamics/dnfr.py +3034 -0
  78. tnfr/dynamics/dnfr.pyi +26 -0
  79. tnfr/dynamics/dynamic_limits.py +225 -0
  80. tnfr/dynamics/feedback.py +252 -0
  81. tnfr/dynamics/feedback.pyi +24 -0
  82. tnfr/dynamics/fused_dnfr.py +454 -0
  83. tnfr/dynamics/homeostasis.py +157 -0
  84. tnfr/dynamics/homeostasis.pyi +14 -0
  85. tnfr/dynamics/integrators.py +661 -0
  86. tnfr/dynamics/integrators.pyi +36 -0
  87. tnfr/dynamics/learning.py +310 -0
  88. tnfr/dynamics/learning.pyi +33 -0
  89. tnfr/dynamics/metabolism.py +254 -0
  90. tnfr/dynamics/nbody.py +796 -0
  91. tnfr/dynamics/nbody_tnfr.py +783 -0
  92. tnfr/dynamics/propagation.py +326 -0
  93. tnfr/dynamics/runtime.py +908 -0
  94. tnfr/dynamics/runtime.pyi +77 -0
  95. tnfr/dynamics/sampling.py +36 -0
  96. tnfr/dynamics/sampling.pyi +7 -0
  97. tnfr/dynamics/selectors.py +711 -0
  98. tnfr/dynamics/selectors.pyi +85 -0
  99. tnfr/dynamics/structural_clip.py +207 -0
  100. tnfr/errors/__init__.py +37 -0
  101. tnfr/errors/contextual.py +492 -0
  102. tnfr/execution.py +223 -0
  103. tnfr/execution.pyi +45 -0
  104. tnfr/extensions/__init__.py +205 -0
  105. tnfr/extensions/__init__.pyi +18 -0
  106. tnfr/extensions/base.py +173 -0
  107. tnfr/extensions/base.pyi +35 -0
  108. tnfr/extensions/business/__init__.py +71 -0
  109. tnfr/extensions/business/__init__.pyi +11 -0
  110. tnfr/extensions/business/cookbook.py +88 -0
  111. tnfr/extensions/business/cookbook.pyi +8 -0
  112. tnfr/extensions/business/health_analyzers.py +202 -0
  113. tnfr/extensions/business/health_analyzers.pyi +9 -0
  114. tnfr/extensions/business/patterns.py +183 -0
  115. tnfr/extensions/business/patterns.pyi +8 -0
  116. tnfr/extensions/medical/__init__.py +73 -0
  117. tnfr/extensions/medical/__init__.pyi +11 -0
  118. tnfr/extensions/medical/cookbook.py +88 -0
  119. tnfr/extensions/medical/cookbook.pyi +8 -0
  120. tnfr/extensions/medical/health_analyzers.py +181 -0
  121. tnfr/extensions/medical/health_analyzers.pyi +9 -0
  122. tnfr/extensions/medical/patterns.py +163 -0
  123. tnfr/extensions/medical/patterns.pyi +8 -0
  124. tnfr/flatten.py +262 -0
  125. tnfr/flatten.pyi +21 -0
  126. tnfr/gamma.py +354 -0
  127. tnfr/gamma.pyi +36 -0
  128. tnfr/glyph_history.py +377 -0
  129. tnfr/glyph_history.pyi +35 -0
  130. tnfr/glyph_runtime.py +19 -0
  131. tnfr/glyph_runtime.pyi +8 -0
  132. tnfr/immutable.py +218 -0
  133. tnfr/immutable.pyi +36 -0
  134. tnfr/initialization.py +203 -0
  135. tnfr/initialization.pyi +65 -0
  136. tnfr/io.py +10 -0
  137. tnfr/io.pyi +13 -0
  138. tnfr/locking.py +37 -0
  139. tnfr/locking.pyi +7 -0
  140. tnfr/mathematics/__init__.py +79 -0
  141. tnfr/mathematics/backend.py +453 -0
  142. tnfr/mathematics/backend.pyi +99 -0
  143. tnfr/mathematics/dynamics.py +408 -0
  144. tnfr/mathematics/dynamics.pyi +90 -0
  145. tnfr/mathematics/epi.py +391 -0
  146. tnfr/mathematics/epi.pyi +65 -0
  147. tnfr/mathematics/generators.py +242 -0
  148. tnfr/mathematics/generators.pyi +29 -0
  149. tnfr/mathematics/metrics.py +119 -0
  150. tnfr/mathematics/metrics.pyi +16 -0
  151. tnfr/mathematics/operators.py +239 -0
  152. tnfr/mathematics/operators.pyi +59 -0
  153. tnfr/mathematics/operators_factory.py +124 -0
  154. tnfr/mathematics/operators_factory.pyi +11 -0
  155. tnfr/mathematics/projection.py +87 -0
  156. tnfr/mathematics/projection.pyi +33 -0
  157. tnfr/mathematics/runtime.py +182 -0
  158. tnfr/mathematics/runtime.pyi +64 -0
  159. tnfr/mathematics/spaces.py +256 -0
  160. tnfr/mathematics/spaces.pyi +83 -0
  161. tnfr/mathematics/transforms.py +305 -0
  162. tnfr/mathematics/transforms.pyi +62 -0
  163. tnfr/metrics/__init__.py +79 -0
  164. tnfr/metrics/__init__.pyi +20 -0
  165. tnfr/metrics/buffer_cache.py +163 -0
  166. tnfr/metrics/buffer_cache.pyi +24 -0
  167. tnfr/metrics/cache_utils.py +214 -0
  168. tnfr/metrics/coherence.py +2009 -0
  169. tnfr/metrics/coherence.pyi +129 -0
  170. tnfr/metrics/common.py +158 -0
  171. tnfr/metrics/common.pyi +35 -0
  172. tnfr/metrics/core.py +316 -0
  173. tnfr/metrics/core.pyi +13 -0
  174. tnfr/metrics/diagnosis.py +833 -0
  175. tnfr/metrics/diagnosis.pyi +86 -0
  176. tnfr/metrics/emergence.py +245 -0
  177. tnfr/metrics/export.py +179 -0
  178. tnfr/metrics/export.pyi +7 -0
  179. tnfr/metrics/glyph_timing.py +379 -0
  180. tnfr/metrics/glyph_timing.pyi +81 -0
  181. tnfr/metrics/learning_metrics.py +280 -0
  182. tnfr/metrics/learning_metrics.pyi +21 -0
  183. tnfr/metrics/phase_coherence.py +351 -0
  184. tnfr/metrics/phase_compatibility.py +349 -0
  185. tnfr/metrics/reporting.py +183 -0
  186. tnfr/metrics/reporting.pyi +25 -0
  187. tnfr/metrics/sense_index.py +1203 -0
  188. tnfr/metrics/sense_index.pyi +9 -0
  189. tnfr/metrics/trig.py +373 -0
  190. tnfr/metrics/trig.pyi +13 -0
  191. tnfr/metrics/trig_cache.py +233 -0
  192. tnfr/metrics/trig_cache.pyi +10 -0
  193. tnfr/multiscale/__init__.py +32 -0
  194. tnfr/multiscale/hierarchical.py +517 -0
  195. tnfr/node.py +763 -0
  196. tnfr/node.pyi +139 -0
  197. tnfr/observers.py +255 -130
  198. tnfr/observers.pyi +31 -0
  199. tnfr/ontosim.py +144 -137
  200. tnfr/ontosim.pyi +28 -0
  201. tnfr/operators/__init__.py +1672 -0
  202. tnfr/operators/__init__.pyi +31 -0
  203. tnfr/operators/algebra.py +277 -0
  204. tnfr/operators/canonical_patterns.py +420 -0
  205. tnfr/operators/cascade.py +267 -0
  206. tnfr/operators/cycle_detection.py +358 -0
  207. tnfr/operators/definitions.py +4108 -0
  208. tnfr/operators/definitions.pyi +78 -0
  209. tnfr/operators/grammar.py +1164 -0
  210. tnfr/operators/grammar.pyi +140 -0
  211. tnfr/operators/hamiltonian.py +710 -0
  212. tnfr/operators/health_analyzer.py +809 -0
  213. tnfr/operators/jitter.py +272 -0
  214. tnfr/operators/jitter.pyi +11 -0
  215. tnfr/operators/lifecycle.py +314 -0
  216. tnfr/operators/metabolism.py +618 -0
  217. tnfr/operators/metrics.py +2138 -0
  218. tnfr/operators/network_analysis/__init__.py +27 -0
  219. tnfr/operators/network_analysis/source_detection.py +186 -0
  220. tnfr/operators/nodal_equation.py +395 -0
  221. tnfr/operators/pattern_detection.py +660 -0
  222. tnfr/operators/patterns.py +669 -0
  223. tnfr/operators/postconditions/__init__.py +38 -0
  224. tnfr/operators/postconditions/mutation.py +236 -0
  225. tnfr/operators/preconditions/__init__.py +1226 -0
  226. tnfr/operators/preconditions/coherence.py +305 -0
  227. tnfr/operators/preconditions/dissonance.py +236 -0
  228. tnfr/operators/preconditions/emission.py +128 -0
  229. tnfr/operators/preconditions/mutation.py +580 -0
  230. tnfr/operators/preconditions/reception.py +125 -0
  231. tnfr/operators/preconditions/resonance.py +364 -0
  232. tnfr/operators/registry.py +74 -0
  233. tnfr/operators/registry.pyi +9 -0
  234. tnfr/operators/remesh.py +1809 -0
  235. tnfr/operators/remesh.pyi +26 -0
  236. tnfr/operators/structural_units.py +268 -0
  237. tnfr/operators/unified_grammar.py +105 -0
  238. tnfr/parallel/__init__.py +54 -0
  239. tnfr/parallel/auto_scaler.py +234 -0
  240. tnfr/parallel/distributed.py +384 -0
  241. tnfr/parallel/engine.py +238 -0
  242. tnfr/parallel/gpu_engine.py +420 -0
  243. tnfr/parallel/monitoring.py +248 -0
  244. tnfr/parallel/partitioner.py +459 -0
  245. tnfr/py.typed +0 -0
  246. tnfr/recipes/__init__.py +22 -0
  247. tnfr/recipes/cookbook.py +743 -0
  248. tnfr/rng.py +178 -0
  249. tnfr/rng.pyi +26 -0
  250. tnfr/schemas/__init__.py +8 -0
  251. tnfr/schemas/grammar.json +94 -0
  252. tnfr/sdk/__init__.py +107 -0
  253. tnfr/sdk/__init__.pyi +19 -0
  254. tnfr/sdk/adaptive_system.py +173 -0
  255. tnfr/sdk/adaptive_system.pyi +21 -0
  256. tnfr/sdk/builders.py +370 -0
  257. tnfr/sdk/builders.pyi +51 -0
  258. tnfr/sdk/fluent.py +1121 -0
  259. tnfr/sdk/fluent.pyi +74 -0
  260. tnfr/sdk/templates.py +342 -0
  261. tnfr/sdk/templates.pyi +41 -0
  262. tnfr/sdk/utils.py +341 -0
  263. tnfr/secure_config.py +46 -0
  264. tnfr/security/__init__.py +70 -0
  265. tnfr/security/database.py +514 -0
  266. tnfr/security/subprocess.py +503 -0
  267. tnfr/security/validation.py +290 -0
  268. tnfr/selector.py +247 -0
  269. tnfr/selector.pyi +19 -0
  270. tnfr/sense.py +378 -0
  271. tnfr/sense.pyi +23 -0
  272. tnfr/services/__init__.py +17 -0
  273. tnfr/services/orchestrator.py +325 -0
  274. tnfr/sparse/__init__.py +39 -0
  275. tnfr/sparse/representations.py +492 -0
  276. tnfr/structural.py +705 -0
  277. tnfr/structural.pyi +83 -0
  278. tnfr/telemetry/__init__.py +35 -0
  279. tnfr/telemetry/cache_metrics.py +226 -0
  280. tnfr/telemetry/cache_metrics.pyi +64 -0
  281. tnfr/telemetry/nu_f.py +422 -0
  282. tnfr/telemetry/nu_f.pyi +108 -0
  283. tnfr/telemetry/verbosity.py +36 -0
  284. tnfr/telemetry/verbosity.pyi +15 -0
  285. tnfr/tokens.py +58 -0
  286. tnfr/tokens.pyi +36 -0
  287. tnfr/tools/__init__.py +20 -0
  288. tnfr/tools/domain_templates.py +478 -0
  289. tnfr/tools/sequence_generator.py +846 -0
  290. tnfr/topology/__init__.py +13 -0
  291. tnfr/topology/asymmetry.py +151 -0
  292. tnfr/trace.py +543 -0
  293. tnfr/trace.pyi +42 -0
  294. tnfr/tutorials/__init__.py +38 -0
  295. tnfr/tutorials/autonomous_evolution.py +285 -0
  296. tnfr/tutorials/interactive.py +1576 -0
  297. tnfr/tutorials/structural_metabolism.py +238 -0
  298. tnfr/types.py +775 -0
  299. tnfr/types.pyi +357 -0
  300. tnfr/units.py +68 -0
  301. tnfr/units.pyi +13 -0
  302. tnfr/utils/__init__.py +282 -0
  303. tnfr/utils/__init__.pyi +215 -0
  304. tnfr/utils/cache.py +4223 -0
  305. tnfr/utils/cache.pyi +470 -0
  306. tnfr/utils/callbacks.py +375 -0
  307. tnfr/utils/callbacks.pyi +49 -0
  308. tnfr/utils/chunks.py +108 -0
  309. tnfr/utils/chunks.pyi +22 -0
  310. tnfr/utils/data.py +428 -0
  311. tnfr/utils/data.pyi +74 -0
  312. tnfr/utils/graph.py +85 -0
  313. tnfr/utils/graph.pyi +10 -0
  314. tnfr/utils/init.py +821 -0
  315. tnfr/utils/init.pyi +80 -0
  316. tnfr/utils/io.py +559 -0
  317. tnfr/utils/io.pyi +66 -0
  318. tnfr/utils/numeric.py +114 -0
  319. tnfr/utils/numeric.pyi +21 -0
  320. tnfr/validation/__init__.py +257 -0
  321. tnfr/validation/__init__.pyi +85 -0
  322. tnfr/validation/compatibility.py +460 -0
  323. tnfr/validation/compatibility.pyi +6 -0
  324. tnfr/validation/config.py +73 -0
  325. tnfr/validation/graph.py +139 -0
  326. tnfr/validation/graph.pyi +18 -0
  327. tnfr/validation/input_validation.py +755 -0
  328. tnfr/validation/invariants.py +712 -0
  329. tnfr/validation/rules.py +253 -0
  330. tnfr/validation/rules.pyi +44 -0
  331. tnfr/validation/runtime.py +279 -0
  332. tnfr/validation/runtime.pyi +28 -0
  333. tnfr/validation/sequence_validator.py +162 -0
  334. tnfr/validation/soft_filters.py +170 -0
  335. tnfr/validation/soft_filters.pyi +32 -0
  336. tnfr/validation/spectral.py +164 -0
  337. tnfr/validation/spectral.pyi +42 -0
  338. tnfr/validation/validator.py +1266 -0
  339. tnfr/validation/window.py +39 -0
  340. tnfr/validation/window.pyi +1 -0
  341. tnfr/visualization/__init__.py +98 -0
  342. tnfr/visualization/cascade_viz.py +256 -0
  343. tnfr/visualization/hierarchy.py +284 -0
  344. tnfr/visualization/sequence_plotter.py +784 -0
  345. tnfr/viz/__init__.py +60 -0
  346. tnfr/viz/matplotlib.py +278 -0
  347. tnfr/viz/matplotlib.pyi +35 -0
  348. tnfr-8.5.0.dist-info/METADATA +573 -0
  349. tnfr-8.5.0.dist-info/RECORD +353 -0
  350. tnfr-8.5.0.dist-info/entry_points.txt +3 -0
  351. tnfr-3.0.3.dist-info/licenses/LICENSE.txt → tnfr-8.5.0.dist-info/licenses/LICENSE.md +1 -1
  352. tnfr/constants.py +0 -183
  353. tnfr/dynamics.py +0 -543
  354. tnfr/helpers.py +0 -198
  355. tnfr/main.py +0 -37
  356. tnfr/operators.py +0 -296
  357. tnfr-3.0.3.dist-info/METADATA +0 -35
  358. tnfr-3.0.3.dist-info/RECORD +0 -13
  359. {tnfr-3.0.3.dist-info → tnfr-8.5.0.dist-info}/WHEEL +0 -0
  360. {tnfr-3.0.3.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)