tnfr 4.5.2__py3-none-any.whl → 8.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tnfr might be problematic. Click here for more details.

Files changed (365) hide show
  1. tnfr/__init__.py +334 -50
  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 +214 -37
  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 +149 -556
  15. tnfr/cache.pyi +13 -0
  16. tnfr/cli/__init__.py +51 -16
  17. tnfr/cli/__init__.pyi +26 -0
  18. tnfr/cli/arguments.py +344 -32
  19. tnfr/cli/arguments.pyi +29 -0
  20. tnfr/cli/execution.py +676 -50
  21. tnfr/cli/execution.pyi +70 -0
  22. tnfr/cli/interactive_validator.py +614 -0
  23. tnfr/cli/utils.py +18 -3
  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/{constants_glyphs.py → config/constants.py} +26 -20
  34. tnfr/config/constants.pyi +12 -0
  35. tnfr/config/defaults.py +54 -0
  36. tnfr/{constants/core.py → config/defaults_core.py} +59 -6
  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 +51 -133
  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 +3 -1
  57. tnfr/constants/init.pyi +12 -0
  58. tnfr/constants/metric.py +9 -15
  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 +213 -633
  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 +2699 -398
  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 +496 -102
  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 +10 -5
  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 +77 -55
  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 +29 -50
  125. tnfr/flatten.pyi +21 -0
  126. tnfr/gamma.py +66 -53
  127. tnfr/gamma.pyi +36 -0
  128. tnfr/glyph_history.py +144 -57
  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 +70 -30
  133. tnfr/immutable.pyi +36 -0
  134. tnfr/initialization.py +22 -16
  135. tnfr/initialization.pyi +65 -0
  136. tnfr/io.py +5 -241
  137. tnfr/io.pyi +13 -0
  138. tnfr/locking.pyi +7 -0
  139. tnfr/mathematics/__init__.py +79 -0
  140. tnfr/mathematics/backend.py +453 -0
  141. tnfr/mathematics/backend.pyi +99 -0
  142. tnfr/mathematics/dynamics.py +408 -0
  143. tnfr/mathematics/dynamics.pyi +90 -0
  144. tnfr/mathematics/epi.py +391 -0
  145. tnfr/mathematics/epi.pyi +65 -0
  146. tnfr/mathematics/generators.py +242 -0
  147. tnfr/mathematics/generators.pyi +29 -0
  148. tnfr/mathematics/metrics.py +119 -0
  149. tnfr/mathematics/metrics.pyi +16 -0
  150. tnfr/mathematics/operators.py +239 -0
  151. tnfr/mathematics/operators.pyi +59 -0
  152. tnfr/mathematics/operators_factory.py +124 -0
  153. tnfr/mathematics/operators_factory.pyi +11 -0
  154. tnfr/mathematics/projection.py +87 -0
  155. tnfr/mathematics/projection.pyi +33 -0
  156. tnfr/mathematics/runtime.py +182 -0
  157. tnfr/mathematics/runtime.pyi +64 -0
  158. tnfr/mathematics/spaces.py +256 -0
  159. tnfr/mathematics/spaces.pyi +83 -0
  160. tnfr/mathematics/transforms.py +305 -0
  161. tnfr/mathematics/transforms.pyi +62 -0
  162. tnfr/metrics/__init__.py +47 -9
  163. tnfr/metrics/__init__.pyi +20 -0
  164. tnfr/metrics/buffer_cache.py +163 -0
  165. tnfr/metrics/buffer_cache.pyi +24 -0
  166. tnfr/metrics/cache_utils.py +214 -0
  167. tnfr/metrics/coherence.py +1510 -330
  168. tnfr/metrics/coherence.pyi +129 -0
  169. tnfr/metrics/common.py +23 -16
  170. tnfr/metrics/common.pyi +35 -0
  171. tnfr/metrics/core.py +251 -36
  172. tnfr/metrics/core.pyi +13 -0
  173. tnfr/metrics/diagnosis.py +709 -110
  174. tnfr/metrics/diagnosis.pyi +86 -0
  175. tnfr/metrics/emergence.py +245 -0
  176. tnfr/metrics/export.py +60 -18
  177. tnfr/metrics/export.pyi +7 -0
  178. tnfr/metrics/glyph_timing.py +233 -43
  179. tnfr/metrics/glyph_timing.pyi +81 -0
  180. tnfr/metrics/learning_metrics.py +280 -0
  181. tnfr/metrics/learning_metrics.pyi +21 -0
  182. tnfr/metrics/phase_coherence.py +351 -0
  183. tnfr/metrics/phase_compatibility.py +349 -0
  184. tnfr/metrics/reporting.py +63 -28
  185. tnfr/metrics/reporting.pyi +25 -0
  186. tnfr/metrics/sense_index.py +1126 -43
  187. tnfr/metrics/sense_index.pyi +9 -0
  188. tnfr/metrics/trig.py +215 -23
  189. tnfr/metrics/trig.pyi +13 -0
  190. tnfr/metrics/trig_cache.py +148 -24
  191. tnfr/metrics/trig_cache.pyi +10 -0
  192. tnfr/multiscale/__init__.py +32 -0
  193. tnfr/multiscale/hierarchical.py +517 -0
  194. tnfr/node.py +646 -140
  195. tnfr/node.pyi +139 -0
  196. tnfr/observers.py +160 -45
  197. tnfr/observers.pyi +31 -0
  198. tnfr/ontosim.py +23 -19
  199. tnfr/ontosim.pyi +28 -0
  200. tnfr/operators/__init__.py +1358 -106
  201. tnfr/operators/__init__.pyi +31 -0
  202. tnfr/operators/algebra.py +277 -0
  203. tnfr/operators/canonical_patterns.py +420 -0
  204. tnfr/operators/cascade.py +267 -0
  205. tnfr/operators/cycle_detection.py +358 -0
  206. tnfr/operators/definitions.py +4108 -0
  207. tnfr/operators/definitions.pyi +78 -0
  208. tnfr/operators/grammar.py +1164 -0
  209. tnfr/operators/grammar.pyi +140 -0
  210. tnfr/operators/hamiltonian.py +710 -0
  211. tnfr/operators/health_analyzer.py +809 -0
  212. tnfr/operators/jitter.py +107 -38
  213. tnfr/operators/jitter.pyi +11 -0
  214. tnfr/operators/lifecycle.py +314 -0
  215. tnfr/operators/metabolism.py +618 -0
  216. tnfr/operators/metrics.py +2138 -0
  217. tnfr/operators/network_analysis/__init__.py +27 -0
  218. tnfr/operators/network_analysis/source_detection.py +186 -0
  219. tnfr/operators/nodal_equation.py +395 -0
  220. tnfr/operators/pattern_detection.py +660 -0
  221. tnfr/operators/patterns.py +669 -0
  222. tnfr/operators/postconditions/__init__.py +38 -0
  223. tnfr/operators/postconditions/mutation.py +236 -0
  224. tnfr/operators/preconditions/__init__.py +1226 -0
  225. tnfr/operators/preconditions/coherence.py +305 -0
  226. tnfr/operators/preconditions/dissonance.py +236 -0
  227. tnfr/operators/preconditions/emission.py +128 -0
  228. tnfr/operators/preconditions/mutation.py +580 -0
  229. tnfr/operators/preconditions/reception.py +125 -0
  230. tnfr/operators/preconditions/resonance.py +364 -0
  231. tnfr/operators/registry.py +74 -0
  232. tnfr/operators/registry.pyi +9 -0
  233. tnfr/operators/remesh.py +1415 -91
  234. tnfr/operators/remesh.pyi +26 -0
  235. tnfr/operators/structural_units.py +268 -0
  236. tnfr/operators/unified_grammar.py +105 -0
  237. tnfr/parallel/__init__.py +54 -0
  238. tnfr/parallel/auto_scaler.py +234 -0
  239. tnfr/parallel/distributed.py +384 -0
  240. tnfr/parallel/engine.py +238 -0
  241. tnfr/parallel/gpu_engine.py +420 -0
  242. tnfr/parallel/monitoring.py +248 -0
  243. tnfr/parallel/partitioner.py +459 -0
  244. tnfr/py.typed +0 -0
  245. tnfr/recipes/__init__.py +22 -0
  246. tnfr/recipes/cookbook.py +743 -0
  247. tnfr/rng.py +75 -151
  248. tnfr/rng.pyi +26 -0
  249. tnfr/schemas/__init__.py +8 -0
  250. tnfr/schemas/grammar.json +94 -0
  251. tnfr/sdk/__init__.py +107 -0
  252. tnfr/sdk/__init__.pyi +19 -0
  253. tnfr/sdk/adaptive_system.py +173 -0
  254. tnfr/sdk/adaptive_system.pyi +21 -0
  255. tnfr/sdk/builders.py +370 -0
  256. tnfr/sdk/builders.pyi +51 -0
  257. tnfr/sdk/fluent.py +1121 -0
  258. tnfr/sdk/fluent.pyi +74 -0
  259. tnfr/sdk/templates.py +342 -0
  260. tnfr/sdk/templates.pyi +41 -0
  261. tnfr/sdk/utils.py +341 -0
  262. tnfr/secure_config.py +46 -0
  263. tnfr/security/__init__.py +70 -0
  264. tnfr/security/database.py +514 -0
  265. tnfr/security/subprocess.py +503 -0
  266. tnfr/security/validation.py +290 -0
  267. tnfr/selector.py +59 -22
  268. tnfr/selector.pyi +19 -0
  269. tnfr/sense.py +92 -67
  270. tnfr/sense.pyi +23 -0
  271. tnfr/services/__init__.py +17 -0
  272. tnfr/services/orchestrator.py +325 -0
  273. tnfr/sparse/__init__.py +39 -0
  274. tnfr/sparse/representations.py +492 -0
  275. tnfr/structural.py +639 -263
  276. tnfr/structural.pyi +83 -0
  277. tnfr/telemetry/__init__.py +35 -0
  278. tnfr/telemetry/cache_metrics.py +226 -0
  279. tnfr/telemetry/cache_metrics.pyi +64 -0
  280. tnfr/telemetry/nu_f.py +422 -0
  281. tnfr/telemetry/nu_f.pyi +108 -0
  282. tnfr/telemetry/verbosity.py +36 -0
  283. tnfr/telemetry/verbosity.pyi +15 -0
  284. tnfr/tokens.py +2 -4
  285. tnfr/tokens.pyi +36 -0
  286. tnfr/tools/__init__.py +20 -0
  287. tnfr/tools/domain_templates.py +478 -0
  288. tnfr/tools/sequence_generator.py +846 -0
  289. tnfr/topology/__init__.py +13 -0
  290. tnfr/topology/asymmetry.py +151 -0
  291. tnfr/trace.py +300 -126
  292. tnfr/trace.pyi +42 -0
  293. tnfr/tutorials/__init__.py +38 -0
  294. tnfr/tutorials/autonomous_evolution.py +285 -0
  295. tnfr/tutorials/interactive.py +1576 -0
  296. tnfr/tutorials/structural_metabolism.py +238 -0
  297. tnfr/types.py +743 -12
  298. tnfr/types.pyi +357 -0
  299. tnfr/units.py +68 -0
  300. tnfr/units.pyi +13 -0
  301. tnfr/utils/__init__.py +282 -0
  302. tnfr/utils/__init__.pyi +215 -0
  303. tnfr/utils/cache.py +4223 -0
  304. tnfr/utils/cache.pyi +470 -0
  305. tnfr/{callback_utils.py → utils/callbacks.py} +26 -39
  306. tnfr/utils/callbacks.pyi +49 -0
  307. tnfr/utils/chunks.py +108 -0
  308. tnfr/utils/chunks.pyi +22 -0
  309. tnfr/utils/data.py +428 -0
  310. tnfr/utils/data.pyi +74 -0
  311. tnfr/utils/graph.py +85 -0
  312. tnfr/utils/graph.pyi +10 -0
  313. tnfr/utils/init.py +821 -0
  314. tnfr/utils/init.pyi +80 -0
  315. tnfr/utils/io.py +559 -0
  316. tnfr/utils/io.pyi +66 -0
  317. tnfr/{helpers → utils}/numeric.py +51 -24
  318. tnfr/utils/numeric.pyi +21 -0
  319. tnfr/validation/__init__.py +257 -0
  320. tnfr/validation/__init__.pyi +85 -0
  321. tnfr/validation/compatibility.py +460 -0
  322. tnfr/validation/compatibility.pyi +6 -0
  323. tnfr/validation/config.py +73 -0
  324. tnfr/validation/graph.py +139 -0
  325. tnfr/validation/graph.pyi +18 -0
  326. tnfr/validation/input_validation.py +755 -0
  327. tnfr/validation/invariants.py +712 -0
  328. tnfr/validation/rules.py +253 -0
  329. tnfr/validation/rules.pyi +44 -0
  330. tnfr/validation/runtime.py +279 -0
  331. tnfr/validation/runtime.pyi +28 -0
  332. tnfr/validation/sequence_validator.py +162 -0
  333. tnfr/validation/soft_filters.py +170 -0
  334. tnfr/validation/soft_filters.pyi +32 -0
  335. tnfr/validation/spectral.py +164 -0
  336. tnfr/validation/spectral.pyi +42 -0
  337. tnfr/validation/validator.py +1266 -0
  338. tnfr/validation/window.py +39 -0
  339. tnfr/validation/window.pyi +1 -0
  340. tnfr/visualization/__init__.py +98 -0
  341. tnfr/visualization/cascade_viz.py +256 -0
  342. tnfr/visualization/hierarchy.py +284 -0
  343. tnfr/visualization/sequence_plotter.py +784 -0
  344. tnfr/viz/__init__.py +60 -0
  345. tnfr/viz/matplotlib.py +278 -0
  346. tnfr/viz/matplotlib.pyi +35 -0
  347. tnfr-8.5.0.dist-info/METADATA +573 -0
  348. tnfr-8.5.0.dist-info/RECORD +353 -0
  349. {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/entry_points.txt +1 -0
  350. {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/licenses/LICENSE.md +1 -1
  351. tnfr/collections_utils.py +0 -300
  352. tnfr/config.py +0 -32
  353. tnfr/grammar.py +0 -344
  354. tnfr/graph_utils.py +0 -84
  355. tnfr/helpers/__init__.py +0 -71
  356. tnfr/import_utils.py +0 -228
  357. tnfr/json_utils.py +0 -162
  358. tnfr/logging_utils.py +0 -116
  359. tnfr/presets.py +0 -60
  360. tnfr/validators.py +0 -84
  361. tnfr/value_utils.py +0 -59
  362. tnfr-4.5.2.dist-info/METADATA +0 -379
  363. tnfr-4.5.2.dist-info/RECORD +0 -67
  364. {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/WHEEL +0 -0
  365. {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/top_level.txt +0 -0
tnfr/sense.py CHANGED
@@ -1,31 +1,39 @@
1
- """Sense calculations."""
1
+ """Sense calculations and structural operator symbol vector analysis.
2
+
3
+ This module implements the sense index (Si) calculation and related vector
4
+ operations for analyzing the distribution of structural operator applications.
5
+
6
+ The 'glyph rose' visualization represents the distribution of structural operator
7
+ symbols in a circular format, where each glyph corresponds to an angle representing
8
+ the associated structural operator.
9
+ """
2
10
 
3
11
  from __future__ import annotations
4
- from typing import TypeVar
5
- from collections.abc import Iterable, Mapping
12
+
6
13
  import math
7
14
  from collections import Counter
15
+ from collections.abc import Iterable, Iterator, Mapping
8
16
  from itertools import tee
17
+ from typing import Any, Callable, TypeVar
9
18
 
10
- import networkx as nx # type: ignore[import-untyped]
19
+ import networkx as nx
11
20
 
12
- from .constants import get_aliases, get_graph_param
13
21
  from .alias import get_attr
14
- from .helpers.numeric import clamp01, kahan_sum_nd
15
- from .import_utils import get_numpy
16
- from .callback_utils import CallbackEvent, callback_manager
17
- from .glyph_history import (
18
- ensure_history,
19
- last_glyph,
20
- count_glyphs,
21
- append_metric,
22
- )
23
- from .constants_glyphs import (
22
+ from .utils import CallbackEvent, callback_manager
23
+ from .config.constants import (
24
24
  ANGLE_MAP,
25
25
  GLYPHS_CANONICAL,
26
26
  )
27
+ from .constants import get_graph_param
28
+ from .constants.aliases import ALIAS_EPI, ALIAS_SI
29
+ from .glyph_history import append_metric, count_glyphs, ensure_history
30
+ from .glyph_runtime import last_glyph
31
+ from .utils import clamp01, kahan_sum_nd
32
+ from .types import NodeId, SigmaVector, TNFRGraph
33
+ from .utils import get_numpy
34
+
27
35
  # -------------------------
28
- # Canon: orden circular de glyphs y ángulos
36
+ # Canon: circular glyph order and angles
29
37
  # -------------------------
30
38
 
31
39
  GLYPH_UNITS: dict[str, complex] = {
@@ -45,10 +53,9 @@ __all__ = (
45
53
  )
46
54
 
47
55
  # -------------------------
48
- # Utilidades básicas
56
+ # Basic utilities
49
57
  # -------------------------
50
58
 
51
-
52
59
  T = TypeVar("T")
53
60
 
54
61
 
@@ -58,35 +65,42 @@ def _resolve_glyph(g: str, mapping: Mapping[str, T]) -> T:
58
65
  try:
59
66
  return mapping[g]
60
67
  except KeyError as e: # pragma: no cover - small helper
61
- raise KeyError(f"Glyph desconocido: {g}") from e
68
+ raise KeyError(f"Unknown glyph: {g}") from e
62
69
 
63
70
 
64
71
  def glyph_angle(g: str) -> float:
65
- """Return angle for glyph ``g``."""
72
+ """Return the canonical angle for structural operator symbol ``g``.
73
+
74
+ Each structural operator symbol (glyph) is mapped to a specific angle
75
+ in the circular representation used for sense vector calculations.
76
+ """
66
77
 
67
78
  return float(_resolve_glyph(g, ANGLE_MAP))
68
79
 
69
80
 
70
81
  def glyph_unit(g: str) -> complex:
71
- """Return unit vector for glyph ``g``."""
82
+ """Return the unit vector for structural operator symbol ``g``.
72
83
 
73
- return _resolve_glyph(g, GLYPH_UNITS)
84
+ Each structural operator symbol (glyph) corresponds to a unit vector
85
+ in the complex plane, used for aggregating operator applications.
86
+ """
74
87
 
88
+ return _resolve_glyph(g, GLYPH_UNITS)
75
89
 
76
- ALIAS_SI = get_aliases("SI")
77
- ALIAS_EPI = get_aliases("EPI")
78
90
 
79
- MODE_FUNCS = {
91
+ MODE_FUNCS: dict[str, Callable[[Mapping[str, Any]], float]] = {
80
92
  "Si": lambda nd: clamp01(get_attr(nd, ALIAS_SI, 0.5)),
81
93
  "EPI": lambda nd: max(0.0, get_attr(nd, ALIAS_EPI, 0.0)),
82
94
  }
83
95
 
84
96
 
85
- def _weight(nd, mode: str) -> float:
97
+ def _weight(nd: Mapping[str, Any], mode: str) -> float:
86
98
  return MODE_FUNCS.get(mode, lambda _: 1.0)(nd)
87
99
 
88
100
 
89
- def _node_weight(nd, weight_mode: str) -> tuple[str, float, complex] | None:
101
+ def _node_weight(
102
+ nd: Mapping[str, Any], weight_mode: str
103
+ ) -> tuple[str, float, complex] | None:
90
104
  """Return ``(glyph, weight, weighted_unit)`` or ``None`` if no glyph."""
91
105
  g = last_glyph(nd)
92
106
  if not g:
@@ -96,7 +110,7 @@ def _node_weight(nd, weight_mode: str) -> tuple[str, float, complex] | None:
96
110
  return g, w, z
97
111
 
98
112
 
99
- def _sigma_cfg(G):
113
+ def _sigma_cfg(G: TNFRGraph) -> dict[str, Any]:
100
114
  return get_graph_param(G, "SIGMA", dict)
101
115
 
102
116
 
@@ -110,7 +124,7 @@ def _to_complex(val: complex | float | int) -> complex:
110
124
  raise TypeError("values must be an iterable of real or complex numbers")
111
125
 
112
126
 
113
- def _empty_sigma(fallback_angle: float) -> dict[str, float]:
127
+ def _empty_sigma(fallback_angle: float) -> SigmaVector:
114
128
  """Return an empty σ-vector with ``fallback_angle``.
115
129
 
116
130
  Helps centralise the default structure returned when no values are
@@ -127,14 +141,14 @@ def _empty_sigma(fallback_angle: float) -> dict[str, float]:
127
141
 
128
142
 
129
143
  # -------------------------
130
- # σ por nodo y σ global
144
+ # σ per node and global σ
131
145
  # -------------------------
132
146
 
133
147
 
134
148
  def _sigma_from_iterable(
135
149
  values: Iterable[complex | float | int] | complex | float | int,
136
150
  fallback_angle: float = 0.0,
137
- ) -> dict[str, float]:
151
+ ) -> SigmaVector:
138
152
  """Normalise vectors in the σ-plane.
139
153
 
140
154
  ``values`` may contain complex or real numbers; real inputs are promoted to
@@ -142,7 +156,9 @@ def _sigma_from_iterable(
142
156
  number of processed values under the ``"n"`` key.
143
157
  """
144
158
 
145
- if isinstance(values, Iterable) and not isinstance(values, (str, bytes, bytearray, Mapping)):
159
+ if isinstance(values, Iterable) and not isinstance(
160
+ values, (str, bytes, bytearray, Mapping)
161
+ ):
146
162
  iterator = iter(values)
147
163
  else:
148
164
  iterator = iter((values,))
@@ -159,15 +175,15 @@ def _sigma_from_iterable(
159
175
  mag = float(np.hypot(x, y))
160
176
  ang = float(np.arctan2(y, x)) if mag > 0 else float(fallback_angle)
161
177
  return {
162
- "x": x,
163
- "y": y,
164
- "mag": mag,
165
- "angle": ang,
166
- "n": cnt,
178
+ "x": float(x),
179
+ "y": float(y),
180
+ "mag": float(mag),
181
+ "angle": float(ang),
182
+ "n": int(cnt),
167
183
  }
168
184
  cnt = 0
169
185
 
170
- def pair_iter():
186
+ def pair_iter() -> Iterator[tuple[float, float]]:
171
187
  nonlocal cnt
172
188
  for val in iterator:
173
189
  z = _to_complex(val)
@@ -188,24 +204,30 @@ def _sigma_from_iterable(
188
204
  "y": float(y),
189
205
  "mag": float(mag),
190
206
  "angle": float(ang),
191
- "n": cnt,
207
+ "n": int(cnt),
192
208
  }
193
209
 
194
210
 
195
- def _ema_update(
196
- prev: dict[str, float], current: dict[str, float], alpha: float
197
- ) -> dict[str, float]:
211
+ def _ema_update(prev: SigmaVector, current: SigmaVector, alpha: float) -> SigmaVector:
198
212
  """Exponential moving average update for σ vectors."""
199
213
  x = (1 - alpha) * prev["x"] + alpha * current["x"]
200
214
  y = (1 - alpha) * prev["y"] + alpha * current["y"]
201
215
  mag = math.hypot(x, y)
202
216
  ang = math.atan2(y, x)
203
- return {"x": x, "y": y, "mag": mag, "angle": ang, "n": current.get("n", 0)}
217
+ return {
218
+ "x": float(x),
219
+ "y": float(y),
220
+ "mag": float(mag),
221
+ "angle": float(ang),
222
+ "n": int(current["n"]),
223
+ }
204
224
 
205
225
 
206
226
  def _sigma_from_nodes(
207
- nodes: Iterable[dict], weight_mode: str, fallback_angle: float = 0.0
208
- ) -> tuple[dict[str, float], list[tuple[str, float, complex]]]:
227
+ nodes: Iterable[Mapping[str, Any]],
228
+ weight_mode: str,
229
+ fallback_angle: float = 0.0,
230
+ ) -> tuple[SigmaVector, list[tuple[str, float, complex]]]:
209
231
  """Aggregate weighted glyph vectors for ``nodes``.
210
232
 
211
233
  Returns the aggregated σ vector and the list of ``(glyph, weight, vector)``
@@ -218,8 +240,10 @@ def _sigma_from_nodes(
218
240
 
219
241
 
220
242
  def sigma_vector_node(
221
- G, n, weight_mode: str | None = None
222
- ) -> dict[str, float] | None:
243
+ G: TNFRGraph, n: NodeId, weight_mode: str | None = None
244
+ ) -> SigmaVector | None:
245
+ """Return the σ vector for node ``n`` using the configured weighting."""
246
+
223
247
  cfg = _sigma_cfg(G)
224
248
  nd = G.nodes[n]
225
249
  weight_mode = weight_mode or cfg.get("weight", "Si")
@@ -229,11 +253,12 @@ def sigma_vector_node(
229
253
  g, w, _ = nws[0]
230
254
  if sv["mag"] == 0:
231
255
  sv["angle"] = glyph_angle(g)
232
- sv.update({"glyph": g, "w": float(w)})
256
+ sv["glyph"] = g
257
+ sv["w"] = float(w)
233
258
  return sv
234
259
 
235
260
 
236
- def sigma_vector(dist: dict[str, float]) -> dict[str, float]:
261
+ def sigma_vector(dist: Mapping[str, float]) -> SigmaVector:
237
262
  """Compute Σ⃗ from a glyph distribution.
238
263
 
239
264
  ``dist`` may contain raw counts or proportions. All ``(glyph, weight)``
@@ -246,8 +271,8 @@ def sigma_vector(dist: dict[str, float]) -> dict[str, float]:
246
271
 
247
272
 
248
273
  def sigma_vector_from_graph(
249
- G: nx.Graph, weight_mode: str | None = None
250
- ) -> dict[str, float]:
274
+ G: TNFRGraph, weight_mode: str | None = None
275
+ ) -> SigmaVector:
251
276
  """Global vector in the σ sense plane for a graph.
252
277
 
253
278
  Parameters
@@ -264,34 +289,34 @@ def sigma_vector_from_graph(
264
289
  """
265
290
 
266
291
  if not isinstance(G, nx.Graph):
267
- raise TypeError("sigma_vector_from_graph requiere un networkx.Graph")
292
+ raise TypeError("sigma_vector_from_graph requires a networkx.Graph")
268
293
 
269
294
  cfg = _sigma_cfg(G)
270
295
  weight_mode = weight_mode or cfg.get("weight", "Si")
271
- sv, _ = _sigma_from_nodes(
272
- (nd for _, nd in G.nodes(data=True)), weight_mode
273
- )
296
+ sv, _ = _sigma_from_nodes((nd for _, nd in G.nodes(data=True)), weight_mode)
274
297
  return sv
275
298
 
276
299
 
277
300
  # -------------------------
278
- # Historia / series
301
+ # History / series
279
302
  # -------------------------
280
303
 
281
304
 
282
- def push_sigma_snapshot(G, t: float | None = None) -> None:
305
+ def push_sigma_snapshot(G: TNFRGraph, t: float | None = None) -> None:
306
+ """Record a global σ snapshot (and optional per-node traces) for ``G``."""
307
+
283
308
  cfg = _sigma_cfg(G)
284
309
  if not cfg.get("enabled", True):
285
310
  return
286
311
 
287
- # Cache local de la historia para evitar llamadas repetidas
312
+ # Local history cache to avoid repeated lookups
288
313
  hist = ensure_history(G)
289
314
  key = cfg.get("history_key", "sigma_global")
290
315
 
291
316
  weight_mode = cfg.get("weight", "Si")
292
317
  sv = sigma_vector_from_graph(G, weight_mode)
293
318
 
294
- # Suavizado exponencial (EMA) opcional
319
+ # Optional exponential smoothing (EMA)
295
320
  alpha = float(cfg.get("smooth", 0.0))
296
321
  if alpha > 0 and hist.get(key):
297
322
  sv = _ema_update(hist[key][-1], sv, alpha)
@@ -301,11 +326,11 @@ def push_sigma_snapshot(G, t: float | None = None) -> None:
301
326
 
302
327
  append_metric(hist, key, sv)
303
328
 
304
- # Conteo de glyphs por paso (útil para rosa glífica)
329
+ # Glyph count per step (useful for the glyph rose)
305
330
  counts = count_glyphs(G, last_only=True)
306
331
  append_metric(hist, "sigma_counts", {"t": current_t, **counts})
307
332
 
308
- # Trayectoria por nodo (opcional)
333
+ # Optional per-node trajectory
309
334
  if cfg.get("per_node", False):
310
335
  per = hist.setdefault("sigma_per_node", {})
311
336
  for n, nd in G.nodes(data=True):
@@ -317,11 +342,13 @@ def push_sigma_snapshot(G, t: float | None = None) -> None:
317
342
 
318
343
 
319
344
  # -------------------------
320
- # Registro como callback automático (after_step)
345
+ # Register as an automatic callback (after_step)
321
346
  # -------------------------
322
347
 
323
348
 
324
- def register_sigma_callback(G) -> None:
349
+ def register_sigma_callback(G: TNFRGraph) -> None:
350
+ """Attach :func:`push_sigma_snapshot` to the ``AFTER_STEP`` callback bus."""
351
+
325
352
  callback_manager.register_callback(
326
353
  G,
327
354
  event=CallbackEvent.AFTER_STEP.value,
@@ -330,7 +357,7 @@ def register_sigma_callback(G) -> None:
330
357
  )
331
358
 
332
359
 
333
- def sigma_rose(G, steps: int | None = None) -> dict[str, int]:
360
+ def sigma_rose(G: TNFRGraph, steps: int | None = None) -> dict[str, int]:
334
361
  """Histogram of glyphs in the last ``steps`` steps (or all)."""
335
362
  hist = ensure_history(G)
336
363
  counts = hist.get("sigma_counts", [])
@@ -340,9 +367,7 @@ def sigma_rose(G, steps: int | None = None) -> dict[str, int]:
340
367
  steps = int(steps)
341
368
  if steps < 0:
342
369
  raise ValueError("steps must be non-negative")
343
- rows = (
344
- counts if steps >= len(counts) else counts[-steps:]
345
- ) # noqa: E203
370
+ rows = counts if steps >= len(counts) else counts[-steps:] # noqa: E203
346
371
  else:
347
372
  rows = counts
348
373
  counter = Counter()
tnfr/sense.pyi ADDED
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Optional
5
+
6
+ from .types import NodeId, SigmaVector, TNFRGraph
7
+
8
+ __all__: tuple[str, ...]
9
+
10
+ GLYPH_UNITS: dict[str, complex]
11
+
12
+ def glyph_angle(g: str) -> float: ...
13
+ def glyph_unit(g: str) -> complex: ...
14
+ def push_sigma_snapshot(G: TNFRGraph, t: Optional[float] = None) -> None: ...
15
+ def register_sigma_callback(G: TNFRGraph) -> None: ...
16
+ def sigma_rose(G: TNFRGraph, steps: Optional[int] = None) -> dict[str, int]: ...
17
+ def sigma_vector(dist: Mapping[str, float]) -> SigmaVector: ...
18
+ def sigma_vector_from_graph(
19
+ G: TNFRGraph, weight_mode: Optional[str] = None
20
+ ) -> SigmaVector: ...
21
+ def sigma_vector_node(
22
+ G: TNFRGraph, n: NodeId, weight_mode: Optional[str] = None
23
+ ) -> Optional[SigmaVector]: ...
@@ -0,0 +1,17 @@
1
+ """Service layer for TNFR orchestration.
2
+
3
+ This package provides the service layer that coordinates execution of TNFR
4
+ operator sequences while maintaining clean separation of responsibilities
5
+ across validation, execution, dynamics, and telemetry concerns.
6
+
7
+ Public API
8
+ ----------
9
+ TNFROrchestrator
10
+ Main orchestration service coordinating sequence execution.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from .orchestrator import TNFROrchestrator
16
+
17
+ __all__ = ("TNFROrchestrator",)