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,492 @@
1
+ """Contextual error handling for TNFR operations.
2
+
3
+ This module provides enhanced error messages that guide users to solutions
4
+ while maintaining TNFR theoretical compliance. All errors include:
5
+
6
+ 1. Clear explanation of the violation
7
+ 2. Actionable suggestions for resolution
8
+ 3. Links to relevant documentation
9
+ 4. Context about the structural operation that failed
10
+
11
+ Canonical Invariants Preserved
12
+ ------------------------------
13
+ These errors enforce TNFR invariants from AGENTS.md:
14
+ - Operator closure and sequence validity
15
+ - Phase synchrony requirements for coupling
16
+ - Frequency (νf) bounds in Hz_str units
17
+ - ΔNFR semantic correctness
18
+ - EPI coherence preservation
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from difflib import get_close_matches
24
+ from typing import Optional, List, Dict, Any
25
+
26
+ __all__ = [
27
+ "TNFRUserError",
28
+ "OperatorSequenceError",
29
+ "NetworkConfigError",
30
+ "PhaseError",
31
+ "CoherenceError",
32
+ "FrequencyError",
33
+ ]
34
+
35
+
36
+ class TNFRUserError(Exception):
37
+ """Base class for user-facing TNFR errors with helpful context.
38
+
39
+ All TNFR errors inherit from this class and provide:
40
+ - Human-readable error messages
41
+ - Actionable suggestions
42
+ - Documentation links
43
+ - Structural context
44
+
45
+ Parameters
46
+ ----------
47
+ message : str
48
+ Primary error message describing what went wrong.
49
+ suggestion : str, optional
50
+ Specific suggestion for how to fix the issue.
51
+ docs_url : str, optional
52
+ URL to relevant documentation section.
53
+ context : dict, optional
54
+ Additional context about the failed operation (node IDs, values, etc).
55
+
56
+ Examples
57
+ --------
58
+ >>> raise TNFRUserError(
59
+ ... "Invalid structural frequency",
60
+ ... suggestion="νf must be positive in Hz_str units",
61
+ ... docs_url="https://tnfr.readthedocs.io/api/core.html#frequency"
62
+ ... )
63
+ """
64
+
65
+ def __init__(
66
+ self,
67
+ message: str,
68
+ suggestion: Optional[str] = None,
69
+ docs_url: Optional[str] = None,
70
+ context: Optional[Dict[str, Any]] = None,
71
+ ):
72
+ self.message = message
73
+ self.suggestion = suggestion
74
+ self.docs_url = docs_url
75
+ self.context = context or {}
76
+
77
+ # Build comprehensive error message
78
+ full_message = f"\n{'='*70}\n"
79
+ full_message += f"TNFR Error: {message}\n"
80
+ full_message += f"{'='*70}\n"
81
+
82
+ if suggestion:
83
+ full_message += f"\n💡 Suggestion: {suggestion}\n"
84
+
85
+ if context:
86
+ full_message += f"\n📊 Context:\n"
87
+ for key, value in context.items():
88
+ full_message += f" • {key}: {value}\n"
89
+
90
+ if docs_url:
91
+ full_message += f"\n📚 Documentation: {docs_url}\n"
92
+
93
+ full_message += f"{'='*70}\n"
94
+
95
+ super().__init__(full_message)
96
+
97
+
98
+ class OperatorSequenceError(TNFRUserError):
99
+ """Error raised when operator sequence violates TNFR grammar.
100
+
101
+ TNFR operators must be applied in valid sequences that respect
102
+ structural coherence. This error provides:
103
+ - The invalid sequence attempted
104
+ - Which operator violated the grammar
105
+ - Valid next operators
106
+ - Fuzzy matching for typos
107
+
108
+ Enforces Invariant #4: Operator closure from AGENTS.md
109
+
110
+ Parameters
111
+ ----------
112
+ invalid_operator : str
113
+ The operator that violated the grammar.
114
+ sequence_so_far : list of str
115
+ Operators successfully applied before the error.
116
+ valid_next : list of str, optional
117
+ Valid operators that can follow the current sequence.
118
+
119
+ Examples
120
+ --------
121
+ >>> raise OperatorSequenceError(
122
+ ... "emision",
123
+ ... ["reception", "coherence"],
124
+ ... ["emission", "recursivity"]
125
+ ... )
126
+ """
127
+
128
+ # Valid TNFR operators (13 canonical operators)
129
+ VALID_OPERATORS = {
130
+ "emission",
131
+ "reception",
132
+ "coherence",
133
+ "dissonance",
134
+ "coupling",
135
+ "resonance",
136
+ "silence",
137
+ "expansion",
138
+ "contraction",
139
+ "self_organization",
140
+ "mutation",
141
+ "transition",
142
+ "recursivity",
143
+ }
144
+
145
+ # Operator aliases for user convenience
146
+ OPERATOR_ALIASES = {
147
+ "emit": "emission",
148
+ "receive": "reception",
149
+ "cohere": "coherence",
150
+ "couple": "coupling",
151
+ "resonate": "resonance",
152
+ "silent": "silence",
153
+ "expand": "expansion",
154
+ "contract": "contraction",
155
+ "self_organize": "self_organization",
156
+ "mutate": "mutation",
157
+ "recurse": "recursivity",
158
+ }
159
+
160
+ def __init__(
161
+ self,
162
+ invalid_operator: str,
163
+ sequence_so_far: Optional[List[str]] = None,
164
+ valid_next: Optional[List[str]] = None,
165
+ ):
166
+ sequence_so_far = sequence_so_far or []
167
+
168
+ # Try fuzzy matching for typos
169
+ all_valid = list(self.VALID_OPERATORS) + list(self.OPERATOR_ALIASES.keys())
170
+ matches = get_close_matches(invalid_operator, all_valid, n=3, cutoff=0.6)
171
+
172
+ suggestion_parts = []
173
+ if matches:
174
+ suggestion_parts.append(f"Did you mean one of: {', '.join(matches)}?")
175
+
176
+ if valid_next:
177
+ suggestion_parts.append(f"Valid next operators: {', '.join(valid_next)}")
178
+ else:
179
+ suggestion_parts.append(
180
+ f"Use one of the 13 canonical operators: "
181
+ f"{', '.join(sorted(self.VALID_OPERATORS))}"
182
+ )
183
+
184
+ suggestion = " ".join(suggestion_parts) if suggestion_parts else None
185
+
186
+ context = {
187
+ "invalid_operator": invalid_operator,
188
+ "sequence_so_far": (
189
+ " → ".join(sequence_so_far) if sequence_so_far else "empty"
190
+ ),
191
+ "operator_count": len(sequence_so_far),
192
+ }
193
+
194
+ super().__init__(
195
+ message=f"Invalid operator sequence: '{invalid_operator}' cannot be applied",
196
+ suggestion=suggestion,
197
+ docs_url="https://github.com/fermga/Teoria-de-la-naturaleza-fractal-resonante-TNFR-/blob/main/docs/source/api/operators.md",
198
+ context=context,
199
+ )
200
+
201
+
202
+ class NetworkConfigError(TNFRUserError):
203
+ """Error raised when network configuration violates TNFR constraints.
204
+
205
+ This error validates configuration parameters and provides valid ranges
206
+ with physical/structural meaning.
207
+
208
+ Enforces multiple invariants:
209
+ - Invariant #2: Structural units (νf in Hz_str)
210
+ - Invariant #5: Phase check requirements
211
+ - Invariant #6: Node birth/collapse conditions
212
+
213
+ Parameters
214
+ ----------
215
+ parameter : str
216
+ The configuration parameter that is invalid.
217
+ value : any
218
+ The invalid value provided.
219
+ valid_range : tuple, optional
220
+ Valid range for the parameter (min, max).
221
+ reason : str, optional
222
+ Structural reason for the constraint.
223
+
224
+ Examples
225
+ --------
226
+ >>> raise NetworkConfigError(
227
+ ... "vf",
228
+ ... -0.5,
229
+ ... (0.01, 100.0),
230
+ ... "Structural frequency must be positive (Hz_str units)"
231
+ ... )
232
+ """
233
+
234
+ # Valid parameter ranges with structural meaning
235
+ PARAMETER_CONSTRAINTS = {
236
+ "vf": {
237
+ "range": (0.01, 100.0),
238
+ "unit": "Hz_str",
239
+ "description": "Structural frequency (reorganization rate)",
240
+ },
241
+ "phase": {
242
+ "range": (0.0, 2 * 3.14159),
243
+ "unit": "radians",
244
+ "description": "Phase angle for network synchrony",
245
+ },
246
+ "coherence": {
247
+ "range": (0.0, 1.0),
248
+ "unit": "dimensionless",
249
+ "description": "Structural stability measure C(t)",
250
+ },
251
+ "delta_nfr": {
252
+ "range": (-10.0, 10.0),
253
+ "unit": "dimensionless",
254
+ "description": "Internal reorganization gradient ΔNFR",
255
+ },
256
+ "epi": {
257
+ "range": (0.0, 1.0),
258
+ "unit": "dimensionless",
259
+ "description": "Primary Information Structure magnitude",
260
+ },
261
+ "edge_probability": {
262
+ "range": (0.0, 1.0),
263
+ "unit": "probability",
264
+ "description": "Network edge connection probability",
265
+ },
266
+ "num_nodes": {
267
+ "range": (1, 100000),
268
+ "unit": "count",
269
+ "description": "Number of nodes in network",
270
+ },
271
+ }
272
+
273
+ def __init__(
274
+ self,
275
+ parameter: str,
276
+ value: Any,
277
+ valid_range: Optional[tuple] = None,
278
+ reason: Optional[str] = None,
279
+ ):
280
+ # Get constraint info if available
281
+ constraint_info = self.PARAMETER_CONSTRAINTS.get(parameter)
282
+
283
+ if constraint_info and not valid_range:
284
+ valid_range = constraint_info["range"]
285
+ reason = reason or constraint_info["description"]
286
+
287
+ suggestion_parts = []
288
+ if valid_range:
289
+ min_val, max_val = valid_range
290
+ suggestion_parts.append(
291
+ f"'{parameter}' must be in range [{min_val}, {max_val}]"
292
+ )
293
+
294
+ if constraint_info:
295
+ suggestion_parts.append(f"Unit: {constraint_info['unit']}")
296
+
297
+ if reason:
298
+ suggestion_parts.append(f"Structural meaning: {reason}")
299
+
300
+ context = {
301
+ "parameter": parameter,
302
+ "provided_value": value,
303
+ "valid_range": (
304
+ f"[{valid_range[0]}, {valid_range[1]}]" if valid_range else "see docs"
305
+ ),
306
+ }
307
+
308
+ super().__init__(
309
+ message=f"Invalid network configuration for '{parameter}'",
310
+ suggestion=" | ".join(suggestion_parts) if suggestion_parts else None,
311
+ docs_url="https://github.com/fermga/Teoria-de-la-naturaleza-fractal-resonante-TNFR-/blob/main/docs/source/api/overview.md",
312
+ context=context,
313
+ )
314
+
315
+
316
+ class PhaseError(TNFRUserError):
317
+ """Error raised when phase synchrony is violated.
318
+
319
+ TNFR requires explicit phase checking before coupling operations.
320
+ This error indicates phase incompatibility between nodes.
321
+
322
+ Enforces Invariant #5: Phase check from AGENTS.md
323
+
324
+ Parameters
325
+ ----------
326
+ node1 : str
327
+ First node ID.
328
+ node2 : str
329
+ Second node ID.
330
+ phase1 : float
331
+ Phase of first node (radians).
332
+ phase2 : float
333
+ Phase of second node (radians).
334
+ threshold : float
335
+ Phase difference threshold for coupling.
336
+
337
+ Examples
338
+ --------
339
+ >>> raise PhaseError("n1", "n2", 0.5, 2.8, 0.5)
340
+ """
341
+
342
+ def __init__(
343
+ self,
344
+ node1: str,
345
+ node2: str,
346
+ phase1: float,
347
+ phase2: float,
348
+ threshold: float = 0.5,
349
+ ):
350
+ phase_diff = abs(phase1 - phase2)
351
+
352
+ suggestion = (
353
+ f"Nodes cannot couple: phase difference ({phase_diff:.3f} rad) "
354
+ f"exceeds threshold ({threshold:.3f} rad). "
355
+ f"Apply phase synchronization or adjust threshold."
356
+ )
357
+
358
+ context = {
359
+ "node1": node1,
360
+ "node2": node2,
361
+ "phase1": f"{phase1:.3f} rad",
362
+ "phase2": f"{phase2:.3f} rad",
363
+ "phase_difference": f"{phase_diff:.3f} rad",
364
+ "threshold": f"{threshold:.3f} rad",
365
+ }
366
+
367
+ super().__init__(
368
+ message=f"Phase synchrony violation between nodes '{node1}' and '{node2}'",
369
+ suggestion=suggestion,
370
+ docs_url="https://github.com/fermga/Teoria-de-la-naturaleza-fractal-resonante-TNFR-/blob/main/GLOSSARY.md#phase",
371
+ context=context,
372
+ )
373
+
374
+
375
+ class CoherenceError(TNFRUserError):
376
+ """Error raised when coherence operations violate monotonicity.
377
+
378
+ Coherence operator must not decrease C(t) except in controlled
379
+ dissonance tests. This error indicates unexpected coherence loss.
380
+
381
+ Enforces Invariant #1: EPI coherent form from AGENTS.md
382
+
383
+ Parameters
384
+ ----------
385
+ operation : str
386
+ The operation that caused coherence decrease.
387
+ before : float
388
+ Coherence C(t) before operation.
389
+ after : float
390
+ Coherence C(t) after operation.
391
+ node_id : str, optional
392
+ Node ID if the error is node-specific.
393
+
394
+ Examples
395
+ --------
396
+ >>> raise CoherenceError("coherence", 0.85, 0.42)
397
+ """
398
+
399
+ def __init__(
400
+ self,
401
+ operation: str,
402
+ before: float,
403
+ after: float,
404
+ node_id: Optional[str] = None,
405
+ ):
406
+ decrease = before - after
407
+ percent_loss = (decrease / before * 100) if before > 0 else 0
408
+
409
+ suggestion = (
410
+ f"Coherence decreased by {decrease:.3f} ({percent_loss:.1f}%). "
411
+ f"This violates the coherence monotonicity invariant. "
412
+ f"Check if this is a controlled dissonance test or if "
413
+ f"there's an unexpected structural instability."
414
+ )
415
+
416
+ context = {
417
+ "operation": operation,
418
+ "coherence_before": f"{before:.3f}",
419
+ "coherence_after": f"{after:.3f}",
420
+ "decrease": f"{decrease:.3f}",
421
+ "percent_loss": f"{percent_loss:.1f}%",
422
+ }
423
+
424
+ if node_id:
425
+ context["node_id"] = node_id
426
+
427
+ super().__init__(
428
+ message=f"Unexpected coherence decrease during '{operation}'",
429
+ suggestion=suggestion,
430
+ docs_url="https://github.com/fermga/Teoria-de-la-naturaleza-fractal-resonante-TNFR-/blob/main/AGENTS.md#canonical-invariants",
431
+ context=context,
432
+ )
433
+
434
+
435
+ class FrequencyError(TNFRUserError):
436
+ """Error raised when structural frequency νf is invalid.
437
+
438
+ Structural frequency must be positive and expressed in Hz_str
439
+ (structural hertz) units. This error indicates frequency violations.
440
+
441
+ Enforces Invariant #2: Structural units from AGENTS.md
442
+
443
+ Parameters
444
+ ----------
445
+ node_id : str
446
+ Node ID with invalid frequency.
447
+ vf : float
448
+ The invalid frequency value.
449
+ operation : str, optional
450
+ Operation that triggered the check.
451
+
452
+ Examples
453
+ --------
454
+ >>> raise FrequencyError("n1", -0.5, "emission")
455
+ """
456
+
457
+ def __init__(
458
+ self,
459
+ node_id: str,
460
+ vf: float,
461
+ operation: Optional[str] = None,
462
+ ):
463
+ if vf <= 0:
464
+ suggestion = (
465
+ f"Structural frequency νf must be positive (Hz_str units). "
466
+ f"Set νf > 0 for node '{node_id}'. "
467
+ f"Typical range: 0.1 to 10.0 Hz_str."
468
+ )
469
+ elif vf > 100:
470
+ suggestion = (
471
+ f"Structural frequency νf = {vf:.3f} Hz_str is very high. "
472
+ f"Typical range: 0.1 to 10.0 Hz_str. "
473
+ f"Verify this is intentional."
474
+ )
475
+ else:
476
+ suggestion = f"Verify structural frequency for node '{node_id}'."
477
+
478
+ context = {
479
+ "node_id": node_id,
480
+ "vf": f"{vf:.3f} Hz_str",
481
+ "valid_range": "[0.01, 100.0] Hz_str",
482
+ }
483
+
484
+ if operation:
485
+ context["operation"] = operation
486
+
487
+ super().__init__(
488
+ message=f"Invalid structural frequency for node '{node_id}'",
489
+ suggestion=suggestion,
490
+ docs_url="https://github.com/fermga/Teoria-de-la-naturaleza-fractal-resonante-TNFR-/blob/main/GLOSSARY.md#structural-frequency",
491
+ context=context,
492
+ )
tnfr/execution.py ADDED
@@ -0,0 +1,223 @@
1
+ """Execution helpers for canonical TNFR programs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections import deque
6
+ from collections.abc import Callable, Iterable, Sequence
7
+ from typing import Any, Optional, cast
8
+
9
+ from ._compat import TypeAlias
10
+ from .constants import get_param
11
+ from .dynamics import step
12
+ from .flatten import _flatten
13
+ from .glyph_history import ensure_history
14
+ from .tokens import TARGET, THOL, WAIT, OpTag, Token
15
+ from .types import Glyph, NodeId, TNFRGraph
16
+ from .utils import MAX_MATERIALIZE_DEFAULT, ensure_collection, is_non_string_sequence
17
+ from .validation import apply_glyph_with_grammar
18
+
19
+ AdvanceFn = Callable[[TNFRGraph], None]
20
+ TraceEntry = dict[str, Any]
21
+ ProgramTrace: TypeAlias = deque[TraceEntry]
22
+ HandlerFn = Callable[
23
+ [TNFRGraph, Any, Optional[Sequence[NodeId]], ProgramTrace, AdvanceFn],
24
+ Optional[Sequence[NodeId]],
25
+ ]
26
+
27
+ __all__ = [
28
+ "AdvanceFn",
29
+ "CANONICAL_PRESET_NAME",
30
+ "CANONICAL_PROGRAM_TOKENS",
31
+ "HANDLERS",
32
+ "_apply_glyph_to_targets",
33
+ "_record_trace",
34
+ "compile_sequence",
35
+ "basic_canonical_example",
36
+ "block",
37
+ "play",
38
+ "seq",
39
+ "target",
40
+ "wait",
41
+ ]
42
+
43
+ CANONICAL_PRESET_NAME = "canonical_example"
44
+ CANONICAL_PROGRAM_TOKENS: tuple[Token, ...] = (
45
+ Glyph.SHA, # silence - initial stabilization
46
+ Glyph.AL, # emission - initiate pattern
47
+ Glyph.RA, # reception - capture information
48
+ Glyph.OZ, # dissonance - required before mutation (grammar rule)
49
+ Glyph.ZHIR, # mutation - phase change
50
+ Glyph.NUL, # contraction - compress structure
51
+ Glyph.THOL, # self_organization - recursive reorganization
52
+ )
53
+
54
+
55
+ def _window(G: TNFRGraph) -> int:
56
+ return int(get_param(G, "GLYPH_HYSTERESIS_WINDOW"))
57
+
58
+
59
+ def _apply_glyph_to_targets(
60
+ G: TNFRGraph, g: Glyph | str, nodes: Optional[Iterable[NodeId]] = None
61
+ ) -> None:
62
+ """Apply ``g`` to ``nodes`` (or all nodes) respecting the grammar."""
63
+
64
+ nodes_iter = G.nodes() if nodes is None else nodes
65
+ w = _window(G)
66
+ apply_glyph_with_grammar(G, nodes_iter, g, w)
67
+
68
+
69
+ def _advance(G: TNFRGraph, step_fn: AdvanceFn) -> None:
70
+ step_fn(G)
71
+
72
+
73
+ def _record_trace(trace: ProgramTrace, G: TNFRGraph, op: OpTag, **data: Any) -> None:
74
+ """Append an operation snapshot to ``trace`` using graph time metadata."""
75
+
76
+ trace.append({"t": float(G.graph.get("_t", 0.0)), "op": op.name, **data})
77
+
78
+
79
+ def _advance_and_record(
80
+ G: TNFRGraph,
81
+ trace: ProgramTrace,
82
+ label: OpTag,
83
+ step_fn: AdvanceFn,
84
+ *,
85
+ times: int = 1,
86
+ **data: Any,
87
+ ) -> None:
88
+ for _ in range(times):
89
+ _advance(G, step_fn)
90
+ _record_trace(trace, G, label, **data)
91
+
92
+
93
+ def _handle_target(
94
+ G: TNFRGraph,
95
+ payload: TARGET,
96
+ _curr_target: Optional[Sequence[NodeId]],
97
+ trace: ProgramTrace,
98
+ _step_fn: AdvanceFn,
99
+ ) -> Sequence[NodeId]:
100
+ """Handle a ``TARGET`` token and return the active node set."""
101
+
102
+ nodes_src = G.nodes() if payload.nodes is None else payload.nodes
103
+ nodes = ensure_collection(nodes_src, max_materialize=None)
104
+ if is_non_string_sequence(nodes):
105
+ curr_target = cast(Sequence[NodeId], nodes)
106
+ else:
107
+ curr_target = tuple(nodes)
108
+ _record_trace(trace, G, OpTag.TARGET, n=len(curr_target))
109
+ return curr_target
110
+
111
+
112
+ def _handle_wait(
113
+ G: TNFRGraph,
114
+ steps: int,
115
+ curr_target: Optional[Sequence[NodeId]],
116
+ trace: ProgramTrace,
117
+ step_fn: AdvanceFn,
118
+ ) -> Optional[Sequence[NodeId]]:
119
+ _advance_and_record(G, trace, OpTag.WAIT, step_fn, times=steps, k=steps)
120
+ return curr_target
121
+
122
+
123
+ def _handle_glyph(
124
+ G: TNFRGraph,
125
+ g: Glyph | str,
126
+ curr_target: Optional[Sequence[NodeId]],
127
+ trace: ProgramTrace,
128
+ step_fn: AdvanceFn,
129
+ label: OpTag = OpTag.GLYPH,
130
+ ) -> Optional[Sequence[NodeId]]:
131
+ _apply_glyph_to_targets(G, g, curr_target)
132
+ _advance_and_record(G, trace, label, step_fn, g=g)
133
+ return curr_target
134
+
135
+
136
+ def _handle_thol(
137
+ G: TNFRGraph,
138
+ g: Glyph | str | None,
139
+ curr_target: Optional[Sequence[NodeId]],
140
+ trace: ProgramTrace,
141
+ step_fn: AdvanceFn,
142
+ ) -> Optional[Sequence[NodeId]]:
143
+ return _handle_glyph(
144
+ G, g or Glyph.THOL.value, curr_target, trace, step_fn, label=OpTag.THOL
145
+ )
146
+
147
+
148
+ HANDLERS: dict[OpTag, HandlerFn] = {
149
+ OpTag.TARGET: _handle_target,
150
+ OpTag.WAIT: _handle_wait,
151
+ OpTag.GLYPH: _handle_glyph,
152
+ OpTag.THOL: _handle_thol,
153
+ }
154
+
155
+
156
+ def play(
157
+ G: TNFRGraph, sequence: Sequence[Token], step_fn: Optional[AdvanceFn] = None
158
+ ) -> None:
159
+ """Execute a canonical sequence on graph ``G``."""
160
+
161
+ step_fn = step_fn or step
162
+
163
+ curr_target: Optional[Sequence[NodeId]] = None
164
+
165
+ history = ensure_history(G)
166
+ maxlen = int(get_param(G, "PROGRAM_TRACE_MAXLEN"))
167
+ trace_obj = history.get("program_trace")
168
+ trace: ProgramTrace
169
+ if not isinstance(trace_obj, deque) or trace_obj.maxlen != maxlen:
170
+ trace = cast(ProgramTrace, deque(trace_obj or [], maxlen=maxlen))
171
+ history["program_trace"] = trace
172
+ else:
173
+ trace = cast(ProgramTrace, trace_obj)
174
+
175
+ for op, payload in _flatten(sequence):
176
+ handler: HandlerFn | None = HANDLERS.get(op)
177
+ if handler is None:
178
+ raise ValueError(f"Unknown operation: {op}")
179
+ curr_target = handler(G, payload, curr_target, trace, step_fn)
180
+
181
+
182
+ def compile_sequence(
183
+ sequence: Iterable[Token] | Sequence[Token] | Any,
184
+ *,
185
+ max_materialize: int | None = MAX_MATERIALIZE_DEFAULT,
186
+ ) -> list[tuple[OpTag, Any]]:
187
+ """Return the operations executed by :func:`play` for ``sequence``."""
188
+
189
+ return _flatten(sequence, max_materialize=max_materialize)
190
+
191
+
192
+ def seq(*tokens: Token) -> list[Token]:
193
+ """Return a mutable list of ``tokens`` for explicit sequence editing."""
194
+
195
+ return list(tokens)
196
+
197
+
198
+ def block(*tokens: Token, repeat: int = 1, close: Optional[Glyph] = None) -> THOL:
199
+ """Build a THOL block with optional repetition and forced closure."""
200
+
201
+ return THOL(body=list(tokens), repeat=repeat, force_close=close)
202
+
203
+
204
+ def target(nodes: Optional[Iterable[NodeId]] = None) -> TARGET:
205
+ """Return a TARGET token selecting ``nodes`` (defaults to all nodes)."""
206
+
207
+ return TARGET(nodes=nodes)
208
+
209
+
210
+ def wait(steps: int = 1) -> WAIT:
211
+ """Return a WAIT token forcing ``steps`` structural updates before resuming."""
212
+
213
+ return WAIT(steps=max(1, int(steps)))
214
+
215
+
216
+ def basic_canonical_example() -> list[Token]:
217
+ """Return the canonical preset sequence.
218
+
219
+ Returns a copy of the canonical preset tokens to keep CLI defaults aligned
220
+ with :func:`tnfr.config.presets.get_preset`.
221
+ """
222
+
223
+ return list(CANONICAL_PROGRAM_TOKENS)