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,280 @@
1
+ """Learning metrics for adaptive TNFR dynamics.
2
+
3
+ This module provides metrics specific to adaptive learning processes,
4
+ measuring plasticity, consolidation, and learning efficiency using
5
+ existing TNFR infrastructure (glyph history, EPI, νf, ΔNFR).
6
+
7
+ All functions reuse canonical utilities from glyph_history and alias modules.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import Any, Mapping, Sequence
13
+
14
+ from ..alias import get_attr
15
+ from ..constants.aliases import ALIAS_EPI, ALIAS_VF, ALIAS_DNFR
16
+ from ..glyph_history import ensure_history, count_glyphs
17
+ from ..types import TNFRGraph, Glyph
18
+ from ..config.operator_names import (
19
+ COHERENCE,
20
+ DISSONANCE,
21
+ EMISSION,
22
+ MUTATION,
23
+ RECEPTION,
24
+ RECURSIVITY,
25
+ SELF_ORGANIZATION,
26
+ SILENCE,
27
+ )
28
+
29
+ __all__ = [
30
+ "compute_learning_plasticity",
31
+ "compute_consolidation_index",
32
+ "compute_learning_efficiency",
33
+ "glyph_history_to_operator_names",
34
+ ]
35
+
36
+
37
+ def glyph_history_to_operator_names(glyph_history: Sequence[str]) -> list[str]:
38
+ """Convert glyph history to operator names for comparison.
39
+
40
+ This is a lightweight helper that converts glyphs (e.g., 'AL', 'EN') to
41
+ canonical operator names (e.g., 'emission', 'reception') using the
42
+ existing GLYPH_TO_FUNCTION mapping.
43
+
44
+ Parameters
45
+ ----------
46
+ glyph_history : Sequence[str]
47
+ Sequence of glyph codes from node's glyph_history.
48
+
49
+ Returns
50
+ -------
51
+ list[str]
52
+ List of canonical operator names.
53
+
54
+ Notes
55
+ -----
56
+ Reuses existing GLYPH_TO_FUNCTION mapping from grammar module.
57
+ Computational cost is O(n) with n = len(glyph_history), just dict lookups.
58
+
59
+ Examples
60
+ --------
61
+ >>> from tnfr.metrics.learning_metrics import glyph_history_to_operator_names
62
+ >>> glyphs = ['AL', 'EN', 'IL']
63
+ >>> names = glyph_history_to_operator_names(glyphs)
64
+ >>> names
65
+ ['emission', 'reception', 'coherence']
66
+ """
67
+ from ..operators.grammar import GLYPH_TO_FUNCTION
68
+
69
+ result = []
70
+ for glyph_str in glyph_history:
71
+ # Convert string to Glyph enum if needed
72
+ try:
73
+ glyph = Glyph(glyph_str)
74
+ operator_name = GLYPH_TO_FUNCTION.get(glyph, glyph_str.lower())
75
+ result.append(operator_name)
76
+ except (ValueError, KeyError):
77
+ # If glyph is not recognized, keep as-is lowercased
78
+ result.append(glyph_str.lower())
79
+
80
+ return result
81
+
82
+
83
+ def compute_learning_plasticity(
84
+ G: TNFRGraph,
85
+ node: Any,
86
+ window: int = 10,
87
+ ) -> float:
88
+ """Measure capacity for structural reorganization (learning plasticity).
89
+
90
+ High plasticity indicates high capacity for learning and adaptation.
91
+ Plasticity is measured by the frequency of reorganization operators
92
+ (OZ, THOL, ZHIR) in the recent glyph history.
93
+
94
+ Parameters
95
+ ----------
96
+ G : TNFRGraph
97
+ Graph storing TNFR nodes and their structural operator history.
98
+ node : Any
99
+ Node identifier within G.
100
+ window : int, default=10
101
+ Number of recent glyphs to analyze.
102
+
103
+ Returns
104
+ -------
105
+ float
106
+ Plasticity index in range [0.0, 1.0] where higher values indicate
107
+ greater reorganization capacity.
108
+
109
+ Notes
110
+ -----
111
+ Reuses canonical glyph_history functions for tracking operator emissions.
112
+ Plasticity operators: OZ (Dissonance), THOL (Self-organization),
113
+ ZHIR (Mutation) - these represent structural flexibility.
114
+
115
+ Examples
116
+ --------
117
+ >>> from tnfr.structural import create_nfr, run_sequence
118
+ >>> from tnfr.operators.definitions import Dissonance, SelfOrganization
119
+ >>> from tnfr.metrics.learning_metrics import compute_learning_plasticity
120
+ >>> G, node = create_nfr("learner", epi=0.3, vf=1.0)
121
+ >>> # Apply reorganization operators
122
+ >>> run_sequence(G, node, [Dissonance(), SelfOrganization()])
123
+ >>> plasticity = compute_learning_plasticity(G, node, window=10)
124
+ >>> plasticity > 0.0 # Should show some plasticity
125
+ True
126
+ """
127
+ # Get glyph history directly from node
128
+ history = G.nodes[node].get("glyph_history", [])
129
+ if not history:
130
+ return 0.0
131
+
132
+ # Convert deque to list if needed
133
+ if hasattr(history, "__iter__"):
134
+ history = list(history)
135
+ else:
136
+ return 0.0
137
+
138
+ # Limit to window size
139
+ if window > 0 and len(history) > window:
140
+ history = history[-window:]
141
+
142
+ # Convert glyphs to operator names using canonical function
143
+ operator_names = glyph_history_to_operator_names(history)
144
+
145
+ # Count plastic operators: those that enable reorganization
146
+ plastic_ops = {DISSONANCE, SELF_ORGANIZATION, MUTATION}
147
+ plastic_count = sum(1 for op_name in operator_names if op_name in plastic_ops)
148
+
149
+ # Normalize by history length
150
+ return plastic_count / max(len(operator_names), 1)
151
+
152
+
153
+ def compute_consolidation_index(
154
+ G: TNFRGraph,
155
+ node: Any,
156
+ window: int = 10,
157
+ ) -> float:
158
+ """Measure structural stabilization after learning (consolidation).
159
+
160
+ High consolidation indicates that learning has been stabilized and
161
+ integrated. Consolidation is measured by the frequency of stabilization
162
+ operators (IL, SHA) in the recent glyph history.
163
+
164
+ Parameters
165
+ ----------
166
+ G : TNFRGraph
167
+ Graph storing TNFR nodes and their structural operator history.
168
+ node : Any
169
+ Node identifier within G.
170
+ window : int, default=10
171
+ Number of recent glyphs to analyze.
172
+
173
+ Returns
174
+ -------
175
+ float
176
+ Consolidation index in range [0.0, 1.0] where higher values indicate
177
+ greater stabilization of learned patterns.
178
+
179
+ Notes
180
+ -----
181
+ Reuses canonical glyph_history functions for tracking operator emissions.
182
+ Consolidation operators: IL (Coherence), SHA (Silence) - these represent
183
+ structural stabilization.
184
+
185
+ Examples
186
+ --------
187
+ >>> from tnfr.structural import create_nfr, run_sequence
188
+ >>> from tnfr.operators.definitions import Coherence, Silence
189
+ >>> from tnfr.metrics.learning_metrics import compute_consolidation_index
190
+ >>> G, node = create_nfr("learner", epi=0.5, vf=1.0)
191
+ >>> # Apply consolidation operators
192
+ >>> run_sequence(G, node, [Coherence(), Silence()])
193
+ >>> consolidation = compute_consolidation_index(G, node, window=10)
194
+ >>> consolidation > 0.0 # Should show some consolidation
195
+ True
196
+ """
197
+ # Get glyph history directly from node
198
+ history = G.nodes[node].get("glyph_history", [])
199
+ if not history:
200
+ return 0.0
201
+
202
+ # Convert deque to list if needed
203
+ if hasattr(history, "__iter__"):
204
+ history = list(history)
205
+ else:
206
+ return 0.0
207
+
208
+ # Limit to window size
209
+ if window > 0 and len(history) > window:
210
+ history = history[-window:]
211
+
212
+ # Convert glyphs to operator names using canonical function
213
+ operator_names = glyph_history_to_operator_names(history)
214
+
215
+ # Count stable operators: those that consolidate structure
216
+ stable_ops = {COHERENCE, SILENCE, RECURSIVITY}
217
+ stable_count = sum(1 for op_name in operator_names if op_name in stable_ops)
218
+
219
+ # Normalize by history length
220
+ return stable_count / max(len(operator_names), 1)
221
+
222
+
223
+ def compute_learning_efficiency(
224
+ G: TNFRGraph,
225
+ node: Any,
226
+ ) -> float:
227
+ """Measure learning efficiency (EPI change per operator applied).
228
+
229
+ Efficiency represents how much structural change (ΔEPI) occurs per
230
+ operator application, indicating effective learning without excessive
231
+ reorganization.
232
+
233
+ Parameters
234
+ ----------
235
+ G : TNFRGraph
236
+ Graph storing TNFR nodes and their structural state.
237
+ node : Any
238
+ Node identifier within G.
239
+
240
+ Returns
241
+ -------
242
+ float
243
+ Learning efficiency as ΔEPI / number_of_operators. Higher values
244
+ indicate more efficient learning (more change with fewer operations).
245
+
246
+ Notes
247
+ -----
248
+ Reuses canonical alias functions (get_attr) for accessing node attributes.
249
+ Requires node to have 'epi_initial' attribute set at creation time to
250
+ measure total EPI change.
251
+
252
+ Examples
253
+ --------
254
+ >>> from tnfr.structural import create_nfr, run_sequence
255
+ >>> from tnfr.operators.definitions import Emission, Reception
256
+ >>> from tnfr.metrics.learning_metrics import compute_learning_efficiency
257
+ >>> G, node = create_nfr("learner", epi=0.2, vf=1.0)
258
+ >>> G.nodes[node]["epi_initial"] = 0.2 # Track initial state
259
+ >>> # Apply learning operators
260
+ >>> run_sequence(G, node, [Emission(), Reception()])
261
+ >>> efficiency = compute_learning_efficiency(G, node)
262
+ >>> efficiency >= 0.0 # Should be non-negative
263
+ True
264
+ """
265
+ # Get current EPI using canonical get_attr
266
+ epi_current = float(get_attr(G.nodes[node], ALIAS_EPI, 0.0))
267
+
268
+ # Get initial EPI (should be set at node creation)
269
+ epi_initial = G.nodes[node].get("epi_initial", 0.0)
270
+
271
+ # Get number of operators applied from glyph history
272
+ history = G.nodes[node].get("glyph_history", [])
273
+ num_ops = len(history) if history else 0
274
+
275
+ if num_ops == 0:
276
+ return 0.0
277
+
278
+ # Calculate efficiency: total EPI change per operator
279
+ delta_epi = abs(epi_current - epi_initial)
280
+ return delta_epi / num_ops
@@ -0,0 +1,21 @@
1
+ """Type stubs for learning metrics module."""
2
+
3
+ from typing import Any, Sequence
4
+
5
+ from ..types import TNFRGraph
6
+
7
+ def glyph_history_to_operator_names(glyph_history: Sequence[str]) -> list[str]: ...
8
+ def compute_learning_plasticity(
9
+ G: TNFRGraph,
10
+ node: Any,
11
+ window: int = ...,
12
+ ) -> float: ...
13
+ def compute_consolidation_index(
14
+ G: TNFRGraph,
15
+ node: Any,
16
+ window: int = ...,
17
+ ) -> float: ...
18
+ def compute_learning_efficiency(
19
+ G: TNFRGraph,
20
+ node: Any,
21
+ ) -> float: ...
@@ -0,0 +1,351 @@
1
+ """Phase coherence metrics for TNFR networks.
2
+
3
+ This module provides phase alignment and synchronization metrics based on
4
+ circular statistics and the Kuramoto order parameter. These metrics are
5
+ essential for measuring the effectiveness of the IL (Coherence) operator's
6
+ phase locking mechanism.
7
+
8
+ Mathematical Foundation
9
+ -----------------------
10
+
11
+ **Kuramoto Order Parameter:**
12
+
13
+ The phase alignment quality is measured using the Kuramoto order parameter r:
14
+
15
+ .. math::
16
+ r = |\\frac{1}{N} \\sum_{j=1}^{N} e^{i\\theta_j}|
17
+
18
+ where:
19
+ - r ∈ [0, 1]
20
+ - r = 1: Perfect phase synchrony (all nodes aligned)
21
+ - r = 0: Complete phase disorder (uniformly distributed phases)
22
+ - θ_j: Phase of node j in radians
23
+
24
+ **Circular Mean:**
25
+
26
+ The mean phase of a set of angles is computed using the circular mean to
27
+ properly handle phase wrap-around at 2π:
28
+
29
+ .. math::
30
+ \\theta_{mean} = \\text{arg}\\left(\\frac{1}{N} \\sum_{j=1}^{N} e^{i\\theta_j}\\right)
31
+
32
+ This ensures that phases near 0 and 2π are correctly averaged (e.g., 0.1 and
33
+ 6.2 radians average to near 0, not π).
34
+
35
+ TNFR Context
36
+ ------------
37
+
38
+ Phase alignment is a key component of the IL (Coherence) operator:
39
+
40
+ - **IL Phase Locking**: θ_node → θ_node + α * (θ_network - θ_node)
41
+ - **Network Synchrony**: High r indicates effective IL application
42
+ - **Local vs. Global**: Phase alignment can be measured at node or network level
43
+ - **Structural Traceability**: Phase metrics enable telemetry of synchronization
44
+
45
+ Examples
46
+ --------
47
+
48
+ **Compute phase alignment for a node:**
49
+
50
+ >>> import networkx as nx
51
+ >>> from tnfr.metrics.phase_coherence import compute_phase_alignment
52
+ >>> from tnfr.constants import THETA_PRIMARY
53
+ >>> G = nx.Graph()
54
+ >>> G.add_edges_from([(1, 2), (2, 3)])
55
+ >>> G.nodes[1][THETA_PRIMARY] = 0.0
56
+ >>> G.nodes[2][THETA_PRIMARY] = 0.1
57
+ >>> G.nodes[3][THETA_PRIMARY] = 0.2
58
+ >>> alignment = compute_phase_alignment(G, 2, radius=1)
59
+ >>> 0.0 <= alignment <= 1.0
60
+ True
61
+
62
+ **Compute global phase coherence:**
63
+
64
+ >>> from tnfr.metrics.phase_coherence import compute_global_phase_coherence
65
+ >>> coherence = compute_global_phase_coherence(G)
66
+ >>> 0.0 <= coherence <= 1.0
67
+ True
68
+
69
+ See Also
70
+ --------
71
+
72
+ operators.definitions.Coherence : IL operator that applies phase locking
73
+ metrics.coherence.compute_global_coherence : Global structural coherence C(t)
74
+ observers.kuramoto_order : Alternative Kuramoto order parameter implementation
75
+ """
76
+
77
+ from __future__ import annotations
78
+
79
+ import cmath
80
+ from typing import TYPE_CHECKING, Any
81
+
82
+ if TYPE_CHECKING:
83
+ from ..types import TNFRGraph, NodeId
84
+
85
+ from ..alias import get_attr
86
+ from ..constants.aliases import ALIAS_THETA
87
+ from ..utils import get_numpy
88
+
89
+ __all__ = [
90
+ "compute_phase_alignment",
91
+ "compute_global_phase_coherence",
92
+ ]
93
+
94
+
95
+ def compute_phase_alignment(G: TNFRGraph, node: Any, radius: int = 1) -> float:
96
+ """Compute phase alignment quality for node and neighborhood.
97
+
98
+ Uses Kuramoto order parameter r = |⟨e^(iθ)⟩| to measure phase synchrony
99
+ within a node's neighborhood. Higher values indicate better phase alignment,
100
+ which is the goal of IL (Coherence) phase locking.
101
+
102
+ Parameters
103
+ ----------
104
+ G : TNFRGraph
105
+ Network graph with node phase attributes (θ)
106
+ node : Any
107
+ Central node for local phase alignment computation
108
+ radius : int, default=1
109
+ Neighborhood radius:
110
+ - 1 = node + immediate neighbors (default)
111
+ - 2 = node + neighbors + neighbors-of-neighbors
112
+ - etc.
113
+
114
+ Returns
115
+ -------
116
+ float
117
+ Phase alignment in [0, 1] where:
118
+ - 1.0 = Perfect phase synchrony (all phases aligned)
119
+ - 0.0 = Complete phase disorder (uniformly distributed)
120
+
121
+ Notes
122
+ -----
123
+ **Mathematical Foundation:**
124
+
125
+ Kuramoto order parameter for local neighborhood:
126
+
127
+ .. math::
128
+ r = |\\frac{1}{N} \\sum_{j \\in \\mathcal{N}(i)} e^{i\\theta_j}|
129
+
130
+ where 𝒩(i) is the set of neighbors within `radius` of node i (including i).
131
+
132
+ **Use Cases:**
133
+
134
+ - **IL Effectiveness**: Measure phase locking success after IL application
135
+ - **Synchrony Monitoring**: Track local phase coherence over time
136
+ - **Hotspot Detection**: Identify regions with poor phase alignment
137
+ - **Coupling Validation**: Verify phase prerequisites before UM (Coupling)
138
+
139
+ **Special Cases:**
140
+
141
+ - Isolated node (no neighbors): Returns 1.0 (trivially synchronized)
142
+ - Single neighbor: Returns 1.0 (two nodes always "aligned")
143
+ - Empty neighborhood: Returns 1.0 (no disorder by definition)
144
+
145
+ **TNFR Context:**
146
+
147
+ Phase alignment is a precondition for effective coupling (UM operator) and
148
+ resonance (RA operator). The IL operator increases phase alignment through
149
+ its phase locking mechanism: θ_node → θ_node + α * (θ_network - θ_node).
150
+
151
+ See Also
152
+ --------
153
+ compute_global_phase_coherence : Network-wide phase coherence
154
+ operators.definitions.Coherence : IL operator with phase locking
155
+
156
+ Examples
157
+ --------
158
+ >>> import networkx as nx
159
+ >>> from tnfr.metrics.phase_coherence import compute_phase_alignment
160
+ >>> from tnfr.constants import THETA_PRIMARY
161
+ >>> G = nx.Graph()
162
+ >>> G.add_edges_from([(1, 2), (2, 3), (3, 4)])
163
+ >>> # Highly aligned phases
164
+ >>> for n in [1, 2, 3, 4]:
165
+ ... G.nodes[n][THETA_PRIMARY] = 0.1 * n # Small differences
166
+ >>> r = compute_phase_alignment(G, node=2, radius=1)
167
+ >>> r > 0.9 # Should be highly aligned
168
+ True
169
+ >>> # Disordered phases
170
+ >>> import numpy as np
171
+ >>> for n in [1, 2, 3, 4]:
172
+ ... G.nodes[n][THETA_PRIMARY] = np.random.uniform(0, 2*np.pi)
173
+ >>> r = compute_phase_alignment(G, node=2, radius=1)
174
+ >>> 0.0 <= r <= 1.0 # Could be anywhere in range
175
+ True
176
+ """
177
+ import networkx as nx
178
+
179
+ # Get neighborhood
180
+ if radius == 1:
181
+ neighbors = set(G.neighbors(node)) | {node}
182
+ else:
183
+ try:
184
+ neighbors = set(
185
+ nx.single_source_shortest_path_length(G, node, cutoff=radius).keys()
186
+ )
187
+ except (nx.NetworkXError, KeyError):
188
+ # Node not in graph or graph is empty
189
+ neighbors = {node} if node in G.nodes else set()
190
+
191
+ # Collect phases from neighborhood
192
+ phases = []
193
+ for n in neighbors:
194
+ try:
195
+ theta = float(get_attr(G.nodes[n], ALIAS_THETA, 0.0))
196
+ phases.append(theta)
197
+ except (KeyError, ValueError, TypeError):
198
+ # Skip nodes with invalid phase data
199
+ continue
200
+
201
+ # Handle edge cases
202
+ if not phases:
203
+ return 1.0 # Empty neighborhood: trivially synchronized
204
+
205
+ if len(phases) == 1:
206
+ return 1.0 # Single node: perfect synchrony
207
+
208
+ # Compute Kuramoto order parameter using circular statistics
209
+ np = get_numpy()
210
+
211
+ if np is not None:
212
+ # NumPy vectorized computation
213
+ phases_array = np.array(phases)
214
+ complex_phases = np.exp(1j * phases_array)
215
+ mean_complex = np.mean(complex_phases)
216
+ r = np.abs(mean_complex)
217
+ return float(r)
218
+ else:
219
+ # Pure Python fallback
220
+
221
+ # Convert phases to complex exponentials
222
+ complex_phases = [cmath.exp(1j * theta) for theta in phases]
223
+
224
+ # Compute mean complex phasor
225
+ mean_real = sum(z.real for z in complex_phases) / len(complex_phases)
226
+ mean_imag = sum(z.imag for z in complex_phases) / len(complex_phases)
227
+ mean_complex = complex(mean_real, mean_imag)
228
+
229
+ # Kuramoto order parameter is magnitude of mean phasor
230
+ r = abs(mean_complex)
231
+ return float(r)
232
+
233
+
234
+ def compute_global_phase_coherence(G: TNFRGraph) -> float:
235
+ """Compute global phase coherence across entire network.
236
+
237
+ Measures network-wide phase synchronization using the Kuramoto order
238
+ parameter applied to all nodes. This is the global analog of
239
+ compute_phase_alignment and indicates overall phase alignment quality.
240
+
241
+ Parameters
242
+ ----------
243
+ G : TNFRGraph
244
+ Network graph with node phase attributes (θ)
245
+
246
+ Returns
247
+ -------
248
+ float
249
+ Global phase coherence in [0, 1] where:
250
+ - 1.0 = Perfect network-wide phase synchrony
251
+ - 0.0 = Complete phase disorder across network
252
+
253
+ Notes
254
+ -----
255
+ **Mathematical Foundation:**
256
+
257
+ Global Kuramoto order parameter:
258
+
259
+ .. math::
260
+ r_{global} = |\\frac{1}{N} \\sum_{j=1}^{N} e^{i\\theta_j}|
261
+
262
+ where N is the total number of nodes in the network.
263
+
264
+ **Use Cases:**
265
+
266
+ - **IL Effectiveness**: Measure global impact of IL phase locking
267
+ - **Network Health**: Monitor overall synchronization state
268
+ - **Convergence Tracking**: Verify phase alignment over time
269
+ - **Bifurcation Detection**: Low r_global may indicate impending split
270
+
271
+ **Special Cases:**
272
+
273
+ - Empty network: Returns 1.0 (no disorder by definition)
274
+ - Single node: Returns 1.0 (trivially synchronized)
275
+ - All phases = 0: Returns 1.0 (perfect alignment)
276
+
277
+ **TNFR Context:**
278
+
279
+ Global phase coherence is a key metric for network structural health.
280
+ Repeated IL application should increase r_global as nodes synchronize
281
+ their phases. Combined with C(t) (structural coherence), r_global provides
282
+ a complete picture of network stability.
283
+
284
+ See Also
285
+ --------
286
+ compute_phase_alignment : Local phase alignment for node neighborhoods
287
+ metrics.coherence.compute_global_coherence : Global structural coherence C(t)
288
+ observers.kuramoto_order : Alternative Kuramoto implementation
289
+
290
+ Examples
291
+ --------
292
+ >>> import networkx as nx
293
+ >>> from tnfr.metrics.phase_coherence import compute_global_phase_coherence
294
+ >>> from tnfr.constants import THETA_PRIMARY
295
+ >>> G = nx.Graph()
296
+ >>> G.add_nodes_from([1, 2, 3, 4])
297
+ >>> # Aligned network
298
+ >>> for n in [1, 2, 3, 4]:
299
+ ... G.nodes[n][THETA_PRIMARY] = 0.5 # All same phase
300
+ >>> r = compute_global_phase_coherence(G)
301
+ >>> r == 1.0 # Perfect alignment
302
+ True
303
+ >>> # Disordered network
304
+ >>> import numpy as np
305
+ >>> for n in [1, 2, 3, 4]:
306
+ ... G.nodes[n][THETA_PRIMARY] = np.random.uniform(0, 2*np.pi)
307
+ >>> r = compute_global_phase_coherence(G)
308
+ >>> 0.0 <= r <= 1.0
309
+ True
310
+ """
311
+ # Collect all node phases
312
+ phases = []
313
+ for n in G.nodes():
314
+ try:
315
+ theta = float(get_attr(G.nodes[n], ALIAS_THETA, 0.0))
316
+ phases.append(theta)
317
+ except (KeyError, ValueError, TypeError):
318
+ # Skip nodes with invalid phase data
319
+ continue
320
+
321
+ # Handle edge cases
322
+ if not phases:
323
+ return 1.0 # Empty network: trivially synchronized
324
+
325
+ if len(phases) == 1:
326
+ return 1.0 # Single node: perfect synchrony
327
+
328
+ # Compute Kuramoto order parameter using circular statistics
329
+ np = get_numpy()
330
+
331
+ if np is not None:
332
+ # NumPy vectorized computation
333
+ phases_array = np.array(phases)
334
+ complex_phases = np.exp(1j * phases_array)
335
+ mean_complex = np.mean(complex_phases)
336
+ r = np.abs(mean_complex)
337
+ return float(r)
338
+ else:
339
+ # Pure Python fallback
340
+
341
+ # Convert phases to complex exponentials
342
+ complex_phases = [cmath.exp(1j * theta) for theta in phases]
343
+
344
+ # Compute mean complex phasor
345
+ mean_real = sum(z.real for z in complex_phases) / len(complex_phases)
346
+ mean_imag = sum(z.imag for z in complex_phases) / len(complex_phases)
347
+ mean_complex = complex(mean_real, mean_imag)
348
+
349
+ # Kuramoto order parameter is magnitude of mean phasor
350
+ r = abs(mean_complex)
351
+ return float(r)