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,454 @@
1
+ """Fused ΔNFR computation kernels for optimized backend.
2
+
3
+ This module provides optimized implementations of ΔNFR computation that fuse
4
+ multiple operations to reduce memory traffic and improve cache locality.
5
+
6
+ The fused kernels maintain exact TNFR semantics while achieving better
7
+ performance through:
8
+
9
+ 1. Combined gradient computation (phase + EPI + topology in single pass)
10
+ 2. Reduced intermediate array allocations
11
+ 3. Better cache locality through sequential memory access
12
+ 4. Optional Numba JIT compilation for critical loops
13
+
14
+ All implementations preserve TNFR structural invariants:
15
+ - ΔNFR = w_phase·g_phase + w_epi·g_epi + w_vf·g_vf + w_topo·g_topo
16
+ - Isolated nodes receive ΔNFR = 0
17
+ - Deterministic results with fixed topology
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import math
23
+ from typing import Any, Mapping
24
+
25
+ from ..utils import get_numpy, get_logger
26
+
27
+ logger = get_logger(__name__)
28
+
29
+ # Try to import Numba for JIT acceleration
30
+ _NUMBA_AVAILABLE = False
31
+ _numba = None
32
+ try:
33
+ import numba
34
+
35
+ _numba = numba
36
+ _NUMBA_AVAILABLE = True
37
+ logger.debug("Numba JIT available for fused gradient acceleration")
38
+ except ImportError:
39
+ logger.debug("Numba not available, using pure NumPy implementation")
40
+
41
+
42
+ def _compute_fused_gradients_jit_kernel(
43
+ edge_src,
44
+ edge_dst,
45
+ phase,
46
+ epi,
47
+ vf,
48
+ w_phase: float,
49
+ w_epi: float,
50
+ w_vf: float,
51
+ w_topo: float,
52
+ delta_nfr,
53
+ ):
54
+ """Numba JIT kernel for fused gradient computation.
55
+
56
+ This function is designed to be JIT-compiled by Numba for maximum
57
+ performance. It operates directly on arrays with explicit loops.
58
+
59
+ Parameters
60
+ ----------
61
+ edge_src : ndarray
62
+ Source node indices (int)
63
+ edge_dst : ndarray
64
+ Destination node indices (int)
65
+ phase : ndarray
66
+ Phase values (float)
67
+ epi : ndarray
68
+ EPI values (float)
69
+ vf : ndarray
70
+ νf values (float)
71
+ w_phase : float
72
+ Phase gradient weight
73
+ w_epi : float
74
+ EPI gradient weight
75
+ w_vf : float
76
+ νf gradient weight
77
+ w_topo : float
78
+ Topology gradient weight
79
+ delta_nfr : ndarray
80
+ Output array for ΔNFR (modified in-place)
81
+ """
82
+ n_edges = edge_src.shape[0]
83
+
84
+ for i in range(n_edges):
85
+ src = edge_src[i]
86
+ dst = edge_dst[i]
87
+
88
+ # Compute gradients for this edge
89
+ phase_diff = math.sin(phase[dst] - phase[src])
90
+ epi_diff = epi[dst] - epi[src]
91
+ vf_diff = vf[dst] - vf[src]
92
+
93
+ # Fused contribution
94
+ contrib = (
95
+ w_phase * phase_diff + w_epi * epi_diff + w_vf * vf_diff + w_topo * 1.0
96
+ )
97
+
98
+ # Accumulate to destination node
99
+ delta_nfr[dst] += contrib
100
+
101
+
102
+ # Create JIT-compiled version if Numba is available
103
+ if _NUMBA_AVAILABLE:
104
+ try:
105
+ _compute_fused_gradients_jit = _numba.njit(
106
+ _compute_fused_gradients_jit_kernel,
107
+ parallel=False,
108
+ fastmath=True,
109
+ cache=True,
110
+ )
111
+ logger.debug("Numba JIT compilation successful for fused gradients")
112
+ except Exception as e:
113
+ logger.warning(f"Numba JIT compilation failed: {e}")
114
+ _compute_fused_gradients_jit = _compute_fused_gradients_jit_kernel
115
+ else:
116
+ _compute_fused_gradients_jit = _compute_fused_gradients_jit_kernel
117
+
118
+
119
+ def compute_fused_gradients(
120
+ *,
121
+ edge_src: Any,
122
+ edge_dst: Any,
123
+ phase: Any,
124
+ epi: Any,
125
+ vf: Any,
126
+ weights: Mapping[str, float],
127
+ np: Any,
128
+ use_jit: bool = True,
129
+ ) -> Any:
130
+ """Compute all ΔNFR gradients in a fused kernel.
131
+
132
+ This function combines phase, EPI, and νf gradient computations into
133
+ a single pass over the edge list, reducing memory traffic by ~50%
134
+ compared to separate accumulations.
135
+
136
+ When Numba is available and `use_jit=True`, uses JIT-compiled inner
137
+ loop for additional 2-3x speedup on large graphs.
138
+
139
+ Parameters
140
+ ----------
141
+ edge_src : array-like
142
+ Source node indices for each edge (shape: [E])
143
+ edge_dst : array-like
144
+ Destination node indices for each edge (shape: [E])
145
+ phase : array-like
146
+ Phase values for each node (shape: [N])
147
+ epi : array-like
148
+ EPI values for each node (shape: [N])
149
+ vf : array-like
150
+ Structural frequency νf for each node (shape: [N])
151
+ weights : Mapping[str, float]
152
+ ΔNFR component weights (w_phase, w_epi, w_vf, w_topo)
153
+ np : module
154
+ NumPy module
155
+ use_jit : bool, default=True
156
+ Whether to use JIT compilation if available
157
+
158
+ Returns
159
+ -------
160
+ ndarray
161
+ Fused gradient vector (shape: [N])
162
+
163
+ Notes
164
+ -----
165
+ The fused kernel computes:
166
+
167
+ ```
168
+ for each edge (i → j):
169
+ g_phase = sin(phase[j] - phase[i])
170
+ g_epi = epi[j] - epi[i]
171
+ g_vf = vf[j] - vf[i]
172
+
173
+ delta_nfr[dst] += w_phase * g_phase + w_epi * g_epi + w_vf * g_vf + w_topo
174
+ ```
175
+
176
+ Where dst is the destination node index (j) for each edge.
177
+
178
+ By processing all components simultaneously, we:
179
+ - Access edge arrays once instead of 3+ times
180
+ - Reduce cache misses on node attribute arrays
181
+ - Minimize temporary array allocations
182
+ - Enable JIT compilation for 2-3x additional speedup
183
+
184
+ Examples
185
+ --------
186
+ >>> import numpy as np
187
+ >>> edge_src = np.array([0, 0, 1])
188
+ >>> edge_dst = np.array([1, 2, 2])
189
+ >>> phase = np.array([0.0, 0.1, 0.2])
190
+ >>> epi = np.array([0.5, 0.6, 0.7])
191
+ >>> vf = np.array([1.0, 1.0, 1.0])
192
+ >>> weights = {'w_phase': 0.3, 'w_epi': 0.3, 'w_vf': 0.2, 'w_topo': 0.2}
193
+ >>> result = compute_fused_gradients(
194
+ ... edge_src=edge_src, edge_dst=edge_dst,
195
+ ... phase=phase, epi=epi, vf=vf,
196
+ ... weights=weights, np=np
197
+ ... )
198
+ >>> result.shape
199
+ (3,)
200
+ """
201
+ n_nodes = phase.shape[0]
202
+ n_edges = edge_src.shape[0]
203
+
204
+ # Extract weights
205
+ w_phase = float(weights.get("w_phase", 0.0))
206
+ w_epi = float(weights.get("w_epi", 0.0))
207
+ w_vf = float(weights.get("w_vf", 0.0))
208
+ w_topo = float(weights.get("w_topo", 0.0))
209
+
210
+ # Allocate result
211
+ delta_nfr = np.zeros(n_nodes, dtype=float)
212
+
213
+ if n_edges == 0:
214
+ return delta_nfr
215
+
216
+ # Choose implementation based on JIT availability and preference
217
+ if use_jit and _NUMBA_AVAILABLE and n_edges > 100:
218
+ # Use JIT-compiled kernel for large graphs
219
+ _compute_fused_gradients_jit(
220
+ edge_src, edge_dst, phase, epi, vf, w_phase, w_epi, w_vf, w_topo, delta_nfr
221
+ )
222
+ else:
223
+ # Use vectorized NumPy implementation
224
+ # Compute edge contributions (fused)
225
+ phase_src = phase[edge_src]
226
+ phase_dst = phase[edge_dst]
227
+ phase_diff = np.sin(phase_dst - phase_src)
228
+
229
+ epi_src = epi[edge_src]
230
+ epi_dst = epi[edge_dst]
231
+ epi_diff = epi_dst - epi_src
232
+
233
+ vf_src = vf[edge_src]
234
+ vf_dst = vf[edge_dst]
235
+ vf_diff = vf_dst - vf_src
236
+
237
+ # Fused contribution per edge
238
+ edge_contrib = (
239
+ w_phase * phase_diff + w_epi * epi_diff + w_vf * vf_diff + w_topo * 1.0
240
+ )
241
+
242
+ # Accumulate contributions to destination nodes
243
+ np.add.at(delta_nfr, edge_dst, edge_contrib)
244
+
245
+ return delta_nfr
246
+
247
+
248
+ def compute_fused_gradients_symmetric(
249
+ *,
250
+ edge_src: Any,
251
+ edge_dst: Any,
252
+ phase: Any,
253
+ epi: Any,
254
+ vf: Any,
255
+ weights: Mapping[str, float],
256
+ np: Any,
257
+ ) -> Any:
258
+ """Compute ΔNFR gradients using TNFR canonical formula with neighbor means.
259
+
260
+ For undirected graphs, this function implements the canonical TNFR gradient
261
+ computation where each node's gradient is computed from the circular mean
262
+ of its neighbors' phases (divided by π), and arithmetic means for EPI/νf.
263
+
264
+ The canonical TNFR formulas are:
265
+ - Phase gradient: g_phase = sin(θ_node - θ̄_neighbors) / π
266
+ - EPI/νf gradient: g = x̄_neighbors - x_node
267
+ - Topology gradient: g_topo = degree · w_topo
268
+
269
+ This implementation performs the computation in two passes:
270
+ 1. Accumulate neighbor cos/sin sums and value sums for means
271
+ 2. Compute gradients from means for each node
272
+
273
+ Parameters
274
+ ----------
275
+ edge_src : array-like
276
+ Source node indices (shape: [E])
277
+ edge_dst : array-like
278
+ Destination node indices (shape: [E])
279
+ phase : array-like
280
+ Phase values (shape: [N])
281
+ epi : array-like
282
+ EPI values (shape: [N])
283
+ vf : array-like
284
+ νf values (shape: [N])
285
+ weights : Mapping[str, float]
286
+ Component weights (w_phase, w_epi, w_vf, w_topo)
287
+ np : module
288
+ NumPy module
289
+
290
+ Returns
291
+ -------
292
+ ndarray
293
+ ΔNFR gradient vector (shape: [N])
294
+
295
+ Notes
296
+ -----
297
+ The division by π in the phase gradient is part of the canonical TNFR
298
+ formulation and ensures proper scaling of phase-based reorganization.
299
+
300
+ For isolated nodes (no neighbors), all gradients are zero.
301
+
302
+ Examples
303
+ --------
304
+ >>> import numpy as np
305
+ >>> edge_src = np.array([0, 0, 1])
306
+ >>> edge_dst = np.array([1, 2, 2])
307
+ >>> phase = np.array([0.0, 0.1, 0.2])
308
+ >>> epi = np.array([0.5, 0.6, 0.7])
309
+ >>> vf = np.array([1.0, 1.0, 1.0])
310
+ >>> weights = {'w_phase': 0.3, 'w_epi': 0.3, 'w_vf': 0.2, 'w_topo': 0.2}
311
+ >>> result = compute_fused_gradients_symmetric(
312
+ ... edge_src=edge_src, edge_dst=edge_dst,
313
+ ... phase=phase, epi=epi, vf=vf,
314
+ ... weights=weights, np=np
315
+ ... )
316
+ >>> result.shape
317
+ (3,)
318
+ """
319
+ n_nodes = phase.shape[0]
320
+ n_edges = edge_src.shape[0]
321
+
322
+ w_phase = float(weights.get("w_phase", 0.0))
323
+ w_epi = float(weights.get("w_epi", 0.0))
324
+ w_vf = float(weights.get("w_vf", 0.0))
325
+ w_topo = float(weights.get("w_topo", 0.0))
326
+
327
+ delta_nfr = np.zeros(n_nodes, dtype=float)
328
+
329
+ if n_edges == 0:
330
+ return delta_nfr
331
+
332
+ # Pass 1: Accumulate neighbor statistics for computing means
333
+ # For phase: accumulate cos/sin sums for circular mean
334
+ # For EPI/vf: accumulate value sums for arithmetic mean
335
+ neighbor_cos_sum = np.zeros(n_nodes, dtype=float)
336
+ neighbor_sin_sum = np.zeros(n_nodes, dtype=float)
337
+ neighbor_epi_sum = np.zeros(n_nodes, dtype=float)
338
+ neighbor_vf_sum = np.zeros(n_nodes, dtype=float)
339
+ neighbor_count = np.zeros(n_nodes, dtype=float)
340
+
341
+ # For undirected graphs, each edge contributes to both endpoints
342
+ # Extract neighbor values
343
+ phase_src_vals = phase[edge_src]
344
+ phase_dst_vals = phase[edge_dst]
345
+ epi_src_vals = epi[edge_src]
346
+ epi_dst_vals = epi[edge_dst]
347
+ vf_src_vals = vf[edge_src]
348
+ vf_dst_vals = vf[edge_dst]
349
+
350
+ # Accumulate from src to dst (dst's neighbors include src)
351
+ np.add.at(neighbor_cos_sum, edge_dst, np.cos(phase_src_vals))
352
+ np.add.at(neighbor_sin_sum, edge_dst, np.sin(phase_src_vals))
353
+ np.add.at(neighbor_epi_sum, edge_dst, epi_src_vals)
354
+ np.add.at(neighbor_vf_sum, edge_dst, vf_src_vals)
355
+ np.add.at(neighbor_count, edge_dst, 1.0)
356
+
357
+ # Accumulate from dst to src (src's neighbors include dst)
358
+ np.add.at(neighbor_cos_sum, edge_src, np.cos(phase_dst_vals))
359
+ np.add.at(neighbor_sin_sum, edge_src, np.sin(phase_dst_vals))
360
+ np.add.at(neighbor_epi_sum, edge_src, epi_dst_vals)
361
+ np.add.at(neighbor_vf_sum, edge_src, vf_dst_vals)
362
+ np.add.at(neighbor_count, edge_src, 1.0)
363
+
364
+ # Pass 2: Compute gradients from means
365
+ # Avoid division by zero for isolated nodes
366
+ has_neighbors = neighbor_count > 0
367
+
368
+ # Compute circular mean phase for nodes with neighbors
369
+ phase_mean = np.zeros(n_nodes, dtype=float)
370
+ phase_mean[has_neighbors] = np.arctan2(
371
+ neighbor_sin_sum[has_neighbors], neighbor_cos_sum[has_neighbors]
372
+ )
373
+
374
+ # Compute arithmetic means for EPI and νf
375
+ epi_mean = np.zeros(n_nodes, dtype=float)
376
+ vf_mean = np.zeros(n_nodes, dtype=float)
377
+ epi_mean[has_neighbors] = (
378
+ neighbor_epi_sum[has_neighbors] / neighbor_count[has_neighbors]
379
+ )
380
+ vf_mean[has_neighbors] = (
381
+ neighbor_vf_sum[has_neighbors] / neighbor_count[has_neighbors]
382
+ )
383
+
384
+ # Compute gradients using TNFR canonical formula
385
+ # Phase: g_phase = -angle_diff(θ_node, θ_mean) / π
386
+ # angle_diff(a, b) = (a - b + π) % 2π - π (minimal angular difference)
387
+ phase_diff = (phase_mean - phase + np.pi) % (2 * np.pi) - np.pi
388
+ g_phase = phase_diff / np.pi
389
+ g_phase[~has_neighbors] = 0.0 # Isolated nodes have no gradient
390
+
391
+ # EPI/νf: g = mean - node_value
392
+ g_epi = epi_mean - epi
393
+ g_epi[~has_neighbors] = 0.0
394
+
395
+ g_vf = vf_mean - vf
396
+ g_vf[~has_neighbors] = 0.0
397
+
398
+ # Topology: each neighbor contributes w_topo
399
+ g_topo = neighbor_count * w_topo
400
+
401
+ # Combine gradients
402
+ delta_nfr = (
403
+ w_phase * g_phase
404
+ + w_epi * g_epi
405
+ + w_vf * g_vf
406
+ + g_topo # Already scaled by w_topo
407
+ )
408
+
409
+ return delta_nfr
410
+
411
+
412
+ def apply_vf_scaling(
413
+ *,
414
+ delta_nfr: Any,
415
+ vf: Any,
416
+ np: Any,
417
+ ) -> None:
418
+ """Apply structural frequency scaling to ΔNFR in-place.
419
+
420
+ Applies the fundamental TNFR transformation:
421
+ ΔNFR_final = νf · ΔNFR_gradient
422
+
423
+ This completes the nodal equation: ∂EPI/∂t = νf · ΔNFR(t)
424
+
425
+ Parameters
426
+ ----------
427
+ delta_nfr : array-like
428
+ Gradient vector to scale in-place (shape: [N])
429
+ vf : array-like
430
+ Structural frequency for each node (shape: [N])
431
+ np : module
432
+ NumPy module
433
+
434
+ Notes
435
+ -----
436
+ Modified in-place to avoid allocating result array.
437
+
438
+ Examples
439
+ --------
440
+ >>> import numpy as np
441
+ >>> delta_nfr = np.array([1.0, 2.0, 3.0])
442
+ >>> vf = np.array([0.5, 1.0, 1.5])
443
+ >>> apply_vf_scaling(delta_nfr=delta_nfr, vf=vf, np=np)
444
+ >>> delta_nfr
445
+ array([0.5, 2. , 4.5])
446
+ """
447
+ np.multiply(delta_nfr, vf, out=delta_nfr)
448
+
449
+
450
+ __all__ = [
451
+ "compute_fused_gradients",
452
+ "compute_fused_gradients_symmetric",
453
+ "apply_vf_scaling",
454
+ ]
@@ -0,0 +1,157 @@
1
+ """Structural homeostasis for TNFR nodes.
2
+
3
+ This module implements homeostatic regulation that maintains nodal parameters
4
+ within target ranges. When parameters drift outside acceptable bounds, corrective
5
+ operators are automatically applied to restore equilibrium.
6
+
7
+ Homeostasis ensures long-term stability while allowing dynamic adaptation
8
+ within safe operating ranges.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import TYPE_CHECKING
14
+
15
+ if TYPE_CHECKING:
16
+ from ..types import TNFRGraph, NodeId
17
+
18
+ from ..alias import get_attr
19
+ from ..constants.aliases import ALIAS_DNFR, ALIAS_EPI, ALIAS_VF
20
+ from ..operators.registry import get_operator_class
21
+ from ..config.operator_names import (
22
+ COHERENCE,
23
+ CONTRACTION,
24
+ EMISSION,
25
+ EXPANSION,
26
+ RECURSIVITY,
27
+ SILENCE,
28
+ )
29
+
30
+ __all__ = ["StructuralHomeostasis"]
31
+
32
+
33
+ class StructuralHomeostasis:
34
+ """Maintains dynamic equilibrium in nodal parameters.
35
+
36
+ This class monitors EPI, νf, and ΔNFR values and applies corrective operators
37
+ when they drift outside target ranges. The goal is to maintain healthy
38
+ structural dynamics without constraining natural evolution.
39
+
40
+ **Homeostatic Principles:**
41
+
42
+ - **EPI range**: Maintain adequate activation without saturation
43
+ - **νf range**: Keep reorganization rate within functional bounds
44
+ - **ΔNFR range**: Prevent excessive reorganization pressure
45
+
46
+ Parameters
47
+ ----------
48
+ graph : TNFRGraph
49
+ Graph containing the regulated node
50
+ node : NodeId
51
+ Identifier of the node to regulate
52
+ epi_range : tuple[float, float], optional
53
+ Target EPI range (min, max). Default: (0.4, 0.8)
54
+ vf_range : tuple[float, float], optional
55
+ Target νf range (min, max). Default: (0.8, 1.2)
56
+ dnfr_range : tuple[float, float], optional
57
+ Target ΔNFR range (min, max). Default: (0.0, 0.15)
58
+
59
+ Attributes
60
+ ----------
61
+ G : TNFRGraph
62
+ Graph reference
63
+ node : NodeId
64
+ Node identifier
65
+ epi_range : tuple[float, float]
66
+ Target EPI range (min, max)
67
+ vf_range : tuple[float, float]
68
+ Target νf range (min, max)
69
+ dnfr_range : tuple[float, float]
70
+ Target ΔNFR range (min, max)
71
+
72
+ Examples
73
+ --------
74
+ >>> from tnfr.structural import create_nfr
75
+ >>> from tnfr.dynamics.homeostasis import StructuralHomeostasis
76
+ >>> G, node = create_nfr("test_node")
77
+ >>> homeostasis = StructuralHomeostasis(G, node)
78
+ >>> homeostasis.maintain_equilibrium()
79
+
80
+ Notes
81
+ -----
82
+ Corrective operators follow TNFR canonical principles:
83
+
84
+ - **Low EPI**: Apply AL (Emission) to activate
85
+ - **High EPI**: Apply NUL (Contraction) to reduce
86
+ - **Low νf**: Apply VAL (Expansion) to increase frequency
87
+ - **High νf**: Apply SHA (Silence) to slow down
88
+ - **High ΔNFR**: Apply IL (Coherence) to stabilize
89
+ """
90
+
91
+ def __init__(
92
+ self,
93
+ graph: TNFRGraph,
94
+ node: NodeId,
95
+ epi_range: tuple[float, float] = (0.4, 0.8),
96
+ vf_range: tuple[float, float] = (0.8, 1.2),
97
+ dnfr_range: tuple[float, float] = (0.0, 0.15),
98
+ ) -> None:
99
+ self.G = graph
100
+ self.node = node
101
+
102
+ # Target ranges for homeostatic regulation
103
+ self.epi_range = epi_range
104
+ self.vf_range = vf_range
105
+ self.dnfr_range = dnfr_range
106
+
107
+ def maintain_equilibrium(self) -> None:
108
+ """Apply corrective operators if parameters exceed target ranges.
109
+
110
+ Checks each parameter (EPI, νf, ΔNFR) and applies appropriate
111
+ operators when out of bounds. Multiple corrections can occur
112
+ in a single call if multiple parameters are out of range.
113
+
114
+ Notes
115
+ -----
116
+ Corrections are applied sequentially:
117
+
118
+ 1. Check and correct EPI
119
+ 2. Check and correct νf
120
+ 3. Check and correct ΔNFR
121
+
122
+ Each correction is minimal: one operator application per parameter.
123
+ """
124
+ epi = get_attr(self.G.nodes[self.node], ALIAS_EPI, 0.0)
125
+ vf = get_attr(self.G.nodes[self.node], ALIAS_VF, 1.0)
126
+ dnfr = get_attr(self.G.nodes[self.node], ALIAS_DNFR, 0.0)
127
+
128
+ # Correct EPI if out of range
129
+ if epi < self.epi_range[0]:
130
+ # EPI too low → activate with Emission
131
+ operator_class = get_operator_class(EMISSION)
132
+ operator = operator_class()
133
+ operator(self.G, self.node)
134
+ elif epi > self.epi_range[1]:
135
+ # EPI too high → contract with Contraction
136
+ operator_class = get_operator_class(CONTRACTION)
137
+ operator = operator_class()
138
+ operator(self.G, self.node)
139
+
140
+ # Correct νf if out of range
141
+ if vf < self.vf_range[0]:
142
+ # Frequency too low → expand with Expansion
143
+ operator_class = get_operator_class(EXPANSION)
144
+ operator = operator_class()
145
+ operator(self.G, self.node)
146
+ elif vf > self.vf_range[1]:
147
+ # Frequency too high → silence with Silence
148
+ operator_class = get_operator_class(SILENCE)
149
+ operator = operator_class()
150
+ operator(self.G, self.node)
151
+
152
+ # Correct ΔNFR if too high
153
+ if dnfr > self.dnfr_range[1]:
154
+ # ΔNFR too high → stabilize with Coherence
155
+ operator_class = get_operator_class(COHERENCE)
156
+ operator = operator_class()
157
+ operator(self.G, self.node)
@@ -0,0 +1,14 @@
1
+ """Type stubs for tnfr.dynamics.homeostasis module."""
2
+
3
+ from typing import Tuple
4
+ from ..types import TNFRGraph, NodeId
5
+
6
+ class StructuralHomeostasis:
7
+ G: TNFRGraph
8
+ node: NodeId
9
+ epi_range: Tuple[float, float]
10
+ vf_range: Tuple[float, float]
11
+ dnfr_range: Tuple[float, float]
12
+
13
+ def __init__(self, graph: TNFRGraph, node: NodeId) -> None: ...
14
+ def maintain_equilibrium(self) -> None: ...