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,86 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Mapping, Sequence
4
+
5
+ __all__: Any
6
+
7
+ def __getattr__(name: str) -> Any: ...
8
+
9
+ ALIAS_DNFR: Any
10
+ ALIAS_EPI: Any
11
+ ALIAS_SI: Any
12
+ ALIAS_VF: Any
13
+ CallbackEvent: Any
14
+ CoherenceMatrixPayload: Any
15
+ Iterable: Any
16
+ ProcessPoolExecutor: Any
17
+ StatisticsError: Any
18
+ TNFRGraph: Any
19
+ TRANSITION: Any
20
+ VF_KEY: Any
21
+ append_metric: Any
22
+ callback_manager: Any
23
+ clamp01: Any
24
+ coherence_matrix: Any
25
+ compute_dnfr_accel_max: Any
26
+ compute_theta_trig: Any
27
+ dissonance_events: Any
28
+ ensure_history: Any
29
+ fmean: Any
30
+ ge: Any
31
+ get_aliases: Any
32
+ get_attr: Any
33
+ get_numpy: Any
34
+ get_param: Any
35
+ get_trig_cache: Any
36
+ le: Any
37
+ local_phase_sync: Any
38
+ math: Any
39
+ min_max_range: Any
40
+ normalize_dnfr: Any
41
+ partial: Any
42
+ register_diagnosis_callbacks: Any
43
+ similarity_abs: Any
44
+
45
+ class RLocalWorkerArgs:
46
+ chunk: Sequence[Any]
47
+ coherence_nodes: Sequence[Any]
48
+ weight_matrix: Any
49
+ weight_index: Mapping[Any, int]
50
+ neighbors_map: Mapping[Any, tuple[Any, ...]]
51
+ cos_map: Mapping[Any, float]
52
+ sin_map: Mapping[Any, float]
53
+
54
+ def __init__(
55
+ self,
56
+ chunk: Sequence[Any],
57
+ coherence_nodes: Sequence[Any],
58
+ weight_matrix: Any,
59
+ weight_index: Mapping[Any, int],
60
+ neighbors_map: Mapping[Any, tuple[Any, ...]],
61
+ cos_map: Mapping[Any, float],
62
+ sin_map: Mapping[Any, float],
63
+ ) -> None: ...
64
+
65
+ class NeighborMeanWorkerArgs:
66
+ chunk: Sequence[Any]
67
+ neighbors_map: Mapping[Any, tuple[Any, ...]]
68
+ epi_map: Mapping[Any, float]
69
+
70
+ def __init__(
71
+ self,
72
+ chunk: Sequence[Any],
73
+ neighbors_map: Mapping[Any, tuple[Any, ...]],
74
+ epi_map: Mapping[Any, float],
75
+ ) -> None: ...
76
+
77
+ def _rlocal_worker(args: RLocalWorkerArgs) -> list[float]: ...
78
+ def _neighbor_mean_worker(args: NeighborMeanWorkerArgs) -> list[float | None]: ...
79
+ def _state_from_thresholds(
80
+ Rloc: float, dnfr_n: float, cfg: Mapping[str, Any]
81
+ ) -> str: ...
82
+ def _recommendation(state: str, cfg: Mapping[str, Any]) -> list[Any]: ...
83
+ def _get_last_weights(
84
+ G: TNFRGraph,
85
+ hist: Mapping[str, Sequence[CoherenceMatrixPayload | None]],
86
+ ) -> tuple[CoherenceMatrixPayload | None, CoherenceMatrixPayload | None]: ...
@@ -0,0 +1,245 @@
1
+ """Emergence metrics for T'HOL structural metabolism.
2
+
3
+ Provides quantitative measures of complexity emergence, bifurcation dynamics,
4
+ and metabolic efficiency in self-organizing systems.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from ..types import NodeId, TNFRGraph
13
+
14
+ from ..alias import get_attr
15
+ from ..constants.aliases import ALIAS_EPI
16
+
17
+ __all__ = [
18
+ "compute_structural_complexity",
19
+ "compute_bifurcation_rate",
20
+ "compute_metabolic_efficiency",
21
+ "compute_emergence_index",
22
+ ]
23
+
24
+ # Emergence index calculation constant
25
+ _EMERGENCE_INDEX_EPSILON = 1e-6 # Small value to avoid zero in geometric mean
26
+
27
+
28
+ def compute_structural_complexity(G: TNFRGraph, node: NodeId) -> int:
29
+ """Measure structural complexity by counting nested sub-EPIs.
30
+
31
+ Structural complexity reflects the number of bifurcations that have
32
+ occurred, indicating the degree of self-organized internal structure.
33
+
34
+ Parameters
35
+ ----------
36
+ G : TNFRGraph
37
+ Graph containing the node
38
+ node : NodeId
39
+ Node identifier
40
+
41
+ Returns
42
+ -------
43
+ int
44
+ Number of sub-EPIs generated through T'HOL bifurcations
45
+
46
+ Notes
47
+ -----
48
+ Higher complexity indicates more sophisticated internal organization
49
+ but may also indicate higher maintenance costs (higher νf required).
50
+
51
+ Examples
52
+ --------
53
+ >>> from tnfr.structural import create_nfr
54
+ >>> from tnfr.operators.definitions import SelfOrganization
55
+ >>> from tnfr.metrics.emergence import compute_structural_complexity
56
+ >>> G, node = create_nfr("system", epi=0.5, vf=1.0)
57
+ >>> # Initialize history for bifurcation
58
+ >>> G.nodes[node]["epi_history"] = [0.3, 0.4, 0.6] # Accelerating
59
+ >>> SelfOrganization()(G, node, tau=0.05) # Low threshold
60
+ >>> complexity = compute_structural_complexity(G, node)
61
+ >>> complexity # doctest: +SKIP
62
+ 1
63
+ """
64
+ sub_epis = G.nodes[node].get("sub_epis", [])
65
+ return len(sub_epis)
66
+
67
+
68
+ def compute_bifurcation_rate(G: TNFRGraph, node: NodeId, window: int = 10) -> float:
69
+ """Calculate frequency of bifurcations in recent history.
70
+
71
+ Bifurcation rate indicates how actively the node is generating new
72
+ structural complexity through T'HOL operations.
73
+
74
+ Parameters
75
+ ----------
76
+ G : TNFRGraph
77
+ Graph containing the node
78
+ node : NodeId
79
+ Node identifier
80
+ window : int
81
+ Time window for rate calculation (in operator steps, default 10)
82
+
83
+ Returns
84
+ -------
85
+ float
86
+ Bifurcations per step in the window (0.0 to 1.0 typical)
87
+
88
+ Notes
89
+ -----
90
+ High bifurcation rate (> 0.5) may indicate:
91
+ - Active adaptation to changing environment
92
+ - High structural instability
93
+ - Rich exploratory dynamics
94
+
95
+ Low rate (< 0.1) may indicate:
96
+ - Stable structural regime
97
+ - Low adaptive pressure
98
+ - Insufficient ΔNFR for bifurcation
99
+
100
+ Examples
101
+ --------
102
+ >>> from tnfr.structural import create_nfr
103
+ >>> from tnfr.metrics.emergence import compute_bifurcation_rate
104
+ >>> G, node = create_nfr("evolving", epi=0.6, vf=1.0)
105
+ >>> # Simulate several bifurcations
106
+ >>> G.nodes[node]["sub_epis"] = [
107
+ ... {"timestamp": 5}, {"timestamp": 8}, {"timestamp": 12}
108
+ ... ]
109
+ >>> rate = compute_bifurcation_rate(G, node, window=10)
110
+ >>> rate # 2 bifurcations in last 10 steps
111
+ 0.2
112
+ """
113
+ sub_epis = G.nodes[node].get("sub_epis", [])
114
+ if not sub_epis:
115
+ return 0.0
116
+
117
+ # Get current timestamp from glyph history
118
+ current_time = len(G.nodes[node].get("glyph_history", []))
119
+
120
+ # Count bifurcations in window
121
+ recent_bifurcations = [
122
+ s for s in sub_epis if s.get("timestamp", 0) >= (current_time - window)
123
+ ]
124
+
125
+ return len(recent_bifurcations) / float(window)
126
+
127
+
128
+ def compute_metabolic_efficiency(G: TNFRGraph, node: NodeId) -> float:
129
+ """Calculate EPI gain per T'HOL application (metabolic efficiency).
130
+
131
+ Metabolic efficiency measures how effectively T'HOL converts
132
+ reorganization events into stable structural complexity (EPI growth).
133
+
134
+ Parameters
135
+ ----------
136
+ G : TNFRGraph
137
+ Graph containing the node
138
+ node : NodeId
139
+ Node identifier
140
+
141
+ Returns
142
+ -------
143
+ float
144
+ Average EPI increase per T'HOL application
145
+ Returns 0.0 if no T'HOL applications recorded
146
+
147
+ Notes
148
+ -----
149
+ High efficiency (> 0.1) indicates:
150
+ - Effective self-organization
151
+ - Strong coherence maintenance
152
+ - Productive metabolic cycles
153
+
154
+ Low efficiency (< 0.01) indicates:
155
+ - Ineffective reorganization
156
+ - High structural friction
157
+ - Possible need for different operator sequences
158
+
159
+ Examples
160
+ --------
161
+ >>> from tnfr.structural import create_nfr
162
+ >>> from tnfr.metrics.emergence import compute_metabolic_efficiency
163
+ >>> G, node = create_nfr("productive", epi=0.5, vf=1.0)
164
+ >>> # Record initial EPI
165
+ >>> G.nodes[node]["epi_initial"] = 0.3
166
+ >>> # Simulate T'HOL applications
167
+ >>> G.nodes[node]["glyph_history"] = ["THOL", "THOL", "IL"]
168
+ >>> # Current EPI increased to 0.5
169
+ >>> efficiency = compute_metabolic_efficiency(G, node)
170
+ >>> efficiency # (0.5 - 0.3) / 2 = 0.1
171
+ 0.1
172
+ """
173
+ from ..types import Glyph
174
+
175
+ # Count T'HOL applications
176
+ glyph_history = G.nodes[node].get("glyph_history", [])
177
+ thol_count = sum(1 for g in glyph_history if g == "THOL" or g == Glyph.THOL.value)
178
+
179
+ if thol_count == 0:
180
+ return 0.0
181
+
182
+ # Calculate EPI delta
183
+ current_epi = float(get_attr(G.nodes[node], ALIAS_EPI, 0.0))
184
+ initial_epi = float(G.nodes[node].get("epi_initial", current_epi))
185
+
186
+ epi_gain = current_epi - initial_epi
187
+
188
+ return epi_gain / float(thol_count)
189
+
190
+
191
+ def compute_emergence_index(G: TNFRGraph, node: NodeId) -> float:
192
+ """Composite metric combining complexity, rate, and efficiency.
193
+
194
+ Emergence index provides a holistic measure of T'HOL metabolic health,
195
+ combining structural complexity, bifurcation dynamics, and efficiency.
196
+
197
+ Parameters
198
+ ----------
199
+ G : TNFRGraph
200
+ Graph containing the node
201
+ node : NodeId
202
+ Node identifier
203
+
204
+ Returns
205
+ -------
206
+ float
207
+ Emergence index (0.0 to ~1.0 typical, higher indicates more emergent)
208
+ Computed as: sqrt(complexity * rate * efficiency)
209
+
210
+ Notes
211
+ -----
212
+ This index balances three factors:
213
+ - Complexity: how much structure has emerged
214
+ - Rate: how actively new structure forms
215
+ - Efficiency: how productive each reorganization is
216
+
217
+ High index (> 0.5) indicates healthy emergent dynamics.
218
+ Low index (< 0.1) suggests reorganization is stalled or inefficient.
219
+
220
+ Examples
221
+ --------
222
+ >>> from tnfr.structural import create_nfr
223
+ >>> from tnfr.metrics.emergence import compute_emergence_index
224
+ >>> G, node = create_nfr("emergent", epi=0.7, vf=1.0)
225
+ >>> # Setup for high emergence
226
+ >>> G.nodes[node]["epi_initial"] = 0.3
227
+ >>> G.nodes[node]["glyph_history"] = ["THOL", "THOL", "IL"]
228
+ >>> G.nodes[node]["sub_epis"] = [{"timestamp": 1}, {"timestamp": 2}]
229
+ >>> index = compute_emergence_index(G, node)
230
+ >>> index # doctest: +SKIP
231
+ 0.63...
232
+ """
233
+ complexity = float(compute_structural_complexity(G, node))
234
+ rate = compute_bifurcation_rate(G, node)
235
+ efficiency = compute_metabolic_efficiency(G, node)
236
+
237
+ # Geometric mean to avoid dominance by any single factor
238
+ # Add epsilon to avoid zero multiplication when no bifurcations occurred
239
+ index = (
240
+ (complexity + _EMERGENCE_INDEX_EPSILON)
241
+ * (rate + _EMERGENCE_INDEX_EPSILON)
242
+ * (efficiency + _EMERGENCE_INDEX_EPSILON)
243
+ ) ** (1.0 / 3.0)
244
+
245
+ return index
tnfr/metrics/export.py ADDED
@@ -0,0 +1,179 @@
1
+ """Metrics export."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import csv
6
+ import math
7
+ from collections.abc import Iterable, Iterator, Sequence
8
+ from itertools import tee, zip_longest
9
+ from typing import Mapping, TextIO
10
+
11
+ from ..config.constants import GLYPHS_CANONICAL
12
+ from ..glyph_history import ensure_history
13
+ from ..utils import json_dumps, safe_write
14
+ from ..types import Graph, SigmaTrace
15
+ from .core import glyphogram_series
16
+
17
+
18
+ def _write_csv(
19
+ path: str,
20
+ headers: Sequence[str],
21
+ rows: Iterable[Sequence[object]],
22
+ *,
23
+ output_dir: str | None = None,
24
+ ) -> None:
25
+ def _write(f: TextIO) -> None:
26
+ writer = csv.writer(f)
27
+ writer.writerow(headers)
28
+ for row in rows:
29
+ writer.writerow(row)
30
+
31
+ safe_write(path, _write, newline="", base_dir=output_dir)
32
+
33
+
34
+ def _iter_glif_rows(
35
+ glyph: Mapping[str, Sequence[float]],
36
+ ) -> Iterator[list[float]]:
37
+ ts = glyph.get("t", [])
38
+ # Precompute columns for each glyph to avoid repeated lookups.
39
+ # ``default_col`` is shared by reference for missing glyphs to prevent
40
+ # unnecessary list allocations.
41
+ default_col = [0] * len(ts)
42
+ cols = [glyph.get(g, default_col) for g in GLYPHS_CANONICAL]
43
+ for i, t in enumerate(ts):
44
+ yield [t] + [col[i] for col in cols]
45
+
46
+
47
+ def export_metrics(
48
+ G: Graph,
49
+ base_path: str,
50
+ fmt: str = "csv",
51
+ *,
52
+ output_dir: str | None = None,
53
+ ) -> None:
54
+ """Dump glyphogram and σ(t) trace to compact CSV or JSON files.
55
+
56
+ Parameters
57
+ ----------
58
+ G : Graph
59
+ The TNFR graph containing metrics to export.
60
+ base_path : str
61
+ Base filename for exported files (without extension).
62
+ fmt : str, default='csv'
63
+ Export format: 'csv' or 'json'.
64
+ output_dir : str | None, optional
65
+ Output directory to restrict exports. If provided, all exports
66
+ must stay within this directory (prevents path traversal).
67
+
68
+ Raises
69
+ ------
70
+ ValueError
71
+ If the path is invalid or format is unsupported.
72
+ PathTraversalError
73
+ If path traversal is detected when output_dir is provided.
74
+ """
75
+ from pathlib import Path
76
+
77
+ hist = ensure_history(G)
78
+ glyph = glyphogram_series(G)
79
+ sigma_x = hist.get("sense_sigma_x", [])
80
+ sigma_y = hist.get("sense_sigma_y", [])
81
+ sigma_mag = hist.get("sense_sigma_mag", [])
82
+ sigma_angle = hist.get("sense_sigma_angle", [])
83
+ t_series = hist.get("sense_sigma_t", []) or glyph.get("t", [])
84
+ rows_raw = zip_longest(
85
+ t_series, sigma_x, sigma_y, sigma_mag, sigma_angle, fillvalue=None
86
+ )
87
+
88
+ def _clean(value: float | None) -> float:
89
+ """Return ``0`` for ``None`` or ``NaN`` values."""
90
+ if value is None or (isinstance(value, float) and math.isnan(value)):
91
+ return 0
92
+ return value
93
+
94
+ def _gen_rows() -> Iterator[tuple[float, float, float, float, float]]:
95
+ for i, (t, x, y, m, a) in enumerate(rows_raw):
96
+ yield (
97
+ i if t is None else t,
98
+ _clean(x),
99
+ _clean(y),
100
+ _clean(m),
101
+ _clean(a),
102
+ )
103
+
104
+ rows_csv, rows_sigma = tee(_gen_rows())
105
+
106
+ sigma: SigmaTrace = {
107
+ "t": [],
108
+ "sigma_x": [],
109
+ "sigma_y": [],
110
+ "mag": [],
111
+ "angle": [],
112
+ }
113
+ for t, x, y, m, a in rows_sigma:
114
+ sigma["t"].append(t)
115
+ sigma["sigma_x"].append(x)
116
+ sigma["sigma_y"].append(y)
117
+ sigma["mag"].append(m)
118
+ sigma["angle"].append(a)
119
+ morph: Sequence[Mapping[str, float]] = hist.get("morph", [])
120
+ epi_supp: Sequence[Mapping[str, float]] = hist.get("EPI_support", [])
121
+ fmt = fmt.lower()
122
+ if fmt not in {"csv", "json"}:
123
+ raise ValueError(f"Unsupported export format: {fmt}")
124
+ if fmt == "csv":
125
+ specs: list[tuple[str, Sequence[str], Iterable[Sequence[object]]]] = [
126
+ (
127
+ "_glyphogram.csv",
128
+ ["t", *GLYPHS_CANONICAL],
129
+ _iter_glif_rows(glyph),
130
+ ),
131
+ (
132
+ "_sigma.csv",
133
+ ["t", "x", "y", "mag", "angle"],
134
+ ([t, x, y, m, a] for t, x, y, m, a in rows_csv),
135
+ ),
136
+ ]
137
+ if morph:
138
+ specs.append(
139
+ (
140
+ "_morph.csv",
141
+ ["t", "ID", "CM", "NE", "PP"],
142
+ (
143
+ [
144
+ row.get("t"),
145
+ row.get("ID"),
146
+ row.get("CM"),
147
+ row.get("NE"),
148
+ row.get("PP"),
149
+ ]
150
+ for row in morph
151
+ ),
152
+ )
153
+ )
154
+ if epi_supp:
155
+ specs.append(
156
+ (
157
+ "_epi_support.csv",
158
+ ["t", "size", "epi_norm"],
159
+ (
160
+ [row.get("t"), row.get("size"), row.get("epi_norm")]
161
+ for row in epi_supp
162
+ ),
163
+ )
164
+ )
165
+ for suffix, headers, rows in specs:
166
+ _write_csv(base_path + suffix, headers, rows, output_dir=output_dir)
167
+ else:
168
+ data = {
169
+ "glyphogram": glyph,
170
+ "sigma": sigma,
171
+ "morph": morph,
172
+ "epi_support": epi_supp,
173
+ }
174
+ json_path = base_path + ".json"
175
+
176
+ def _write_json(f: TextIO) -> None:
177
+ f.write(json_dumps(data))
178
+
179
+ safe_write(json_path, _write_json, base_dir=output_dir)
@@ -0,0 +1,7 @@
1
+ from ..config.constants import GLYPHS_CANONICAL as GLYPHS_CANONICAL
2
+ from ..glyph_history import ensure_history as ensure_history
3
+ from ..types import Graph as Graph, SigmaTrace as SigmaTrace
4
+ from ..utils import json_dumps as json_dumps, safe_write as safe_write
5
+ from .core import glyphogram_series as glyphogram_series
6
+
7
+ def export_metrics(G: Graph, base_path: str, fmt: str = "csv") -> None: ...