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,85 @@
1
+ from __future__ import annotations
2
+
3
+ import abc
4
+ from ..selector import _selector_parallel_jobs as _selector_parallel_jobs
5
+ from ..types import (
6
+ GlyphCode as GlyphCode,
7
+ GlyphSelector,
8
+ HistoryState,
9
+ NodeId,
10
+ TNFRGraph,
11
+ )
12
+ from _typeshed import Incomplete
13
+ from abc import ABC, abstractmethod
14
+ from collections.abc import Mapping, MutableMapping, Sequence
15
+ from dataclasses import dataclass
16
+ from typing import Any
17
+
18
+ __all__ = [
19
+ "GlyphCode",
20
+ "AbstractSelector",
21
+ "DefaultGlyphSelector",
22
+ "ParametricGlyphSelector",
23
+ "default_glyph_selector",
24
+ "parametric_glyph_selector",
25
+ "_SelectorPreselection",
26
+ "_configure_selector_weights",
27
+ "_apply_selector",
28
+ "_apply_glyphs",
29
+ "_selector_parallel_jobs",
30
+ "_prepare_selector_preselection",
31
+ "_resolve_preselected_glyph",
32
+ "_choose_glyph",
33
+ ]
34
+
35
+ class AbstractSelector(ABC, metaclass=abc.ABCMeta):
36
+ def prepare(self, graph: TNFRGraph, nodes: Sequence[NodeId]) -> None: ...
37
+ @abstractmethod
38
+ def select(self, graph: TNFRGraph, node: NodeId) -> GlyphCode: ...
39
+ def __call__(self, graph: TNFRGraph, node: NodeId) -> GlyphCode: ...
40
+
41
+ def _configure_selector_weights(G: TNFRGraph) -> Mapping[str, float]: ...
42
+ @dataclass
43
+ class _SelectorPreselection:
44
+ kind: str
45
+ metrics: Mapping[Any, tuple[float, float, float]]
46
+ base_choices: Mapping[Any, GlyphCode]
47
+ thresholds: Mapping[str, float] | None = ...
48
+ margin: float | None = ...
49
+
50
+ class DefaultGlyphSelector(AbstractSelector):
51
+ def __init__(self) -> None: ...
52
+ def prepare(self, graph: TNFRGraph, nodes: Sequence[NodeId]) -> None: ...
53
+ def select(self, graph: TNFRGraph, node: NodeId) -> GlyphCode: ...
54
+
55
+ class ParametricGlyphSelector(AbstractSelector):
56
+ def __init__(self) -> None: ...
57
+ def prepare(self, graph: TNFRGraph, nodes: Sequence[NodeId]) -> None: ...
58
+ def select(self, graph: TNFRGraph, node: NodeId) -> GlyphCode: ...
59
+
60
+ default_glyph_selector: Incomplete
61
+ parametric_glyph_selector: Incomplete
62
+
63
+ def _choose_glyph(
64
+ G: TNFRGraph,
65
+ n: NodeId,
66
+ selector: GlyphSelector,
67
+ use_canon: bool,
68
+ h_al: MutableMapping[Any, int],
69
+ h_en: MutableMapping[Any, int],
70
+ al_max: int,
71
+ en_max: int,
72
+ ) -> GlyphCode: ...
73
+ def _prepare_selector_preselection(
74
+ G: TNFRGraph, selector: GlyphSelector, nodes: Sequence[NodeId]
75
+ ) -> _SelectorPreselection | None: ...
76
+ def _resolve_preselected_glyph(
77
+ G: TNFRGraph,
78
+ n: NodeId,
79
+ selector: GlyphSelector,
80
+ preselection: _SelectorPreselection | None,
81
+ ) -> GlyphCode: ...
82
+ def _apply_glyphs(
83
+ G: TNFRGraph, selector: GlyphSelector, hist: HistoryState
84
+ ) -> None: ...
85
+ def _apply_selector(G: TNFRGraph) -> GlyphSelector: ...
@@ -0,0 +1,207 @@
1
+ """Structural boundary preservation for EPI values.
2
+
3
+ This module implements canonical TNFR structural clipping that preserves
4
+ coherence by constraining EPI values to valid structural boundaries while
5
+ maintaining smooth operator behavior.
6
+
7
+ The structural_clip function ensures that EPI remains within [-1.0, 1.0]
8
+ (or configurable bounds) after operator application and integration steps,
9
+ preventing numerical precision issues from violating structural invariants.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import math
15
+ from typing import Literal
16
+
17
+ __all__ = [
18
+ "structural_clip",
19
+ "StructuralClipStats",
20
+ ]
21
+
22
+
23
+ class StructuralClipStats:
24
+ """Telemetry for structural boundary interventions.
25
+
26
+ Tracks how often and by how much the structural_clip function
27
+ adjusts EPI values to preserve structural boundaries.
28
+ """
29
+
30
+ def __init__(self) -> None:
31
+ """Initialize empty statistics."""
32
+ self.hard_clips: int = 0
33
+ self.soft_clips: int = 0
34
+ self.total_adjustments: int = 0
35
+ self.max_delta_hard: float = 0.0
36
+ self.max_delta_soft: float = 0.0
37
+ self.sum_delta_hard: float = 0.0
38
+ self.sum_delta_soft: float = 0.0
39
+
40
+ def record_hard_clip(self, delta: float) -> None:
41
+ """Record a hard clip intervention."""
42
+ self.hard_clips += 1
43
+ self.total_adjustments += 1
44
+ abs_delta = abs(delta)
45
+ self.max_delta_hard = max(self.max_delta_hard, abs_delta)
46
+ self.sum_delta_hard += abs_delta
47
+
48
+ def record_soft_clip(self, delta: float) -> None:
49
+ """Record a soft clip intervention."""
50
+ self.soft_clips += 1
51
+ self.total_adjustments += 1
52
+ abs_delta = abs(delta)
53
+ self.max_delta_soft = max(self.max_delta_soft, abs_delta)
54
+ self.sum_delta_soft += abs_delta
55
+
56
+ def reset(self) -> None:
57
+ """Reset all statistics to zero."""
58
+ self.hard_clips = 0
59
+ self.soft_clips = 0
60
+ self.total_adjustments = 0
61
+ self.max_delta_hard = 0.0
62
+ self.max_delta_soft = 0.0
63
+ self.sum_delta_hard = 0.0
64
+ self.sum_delta_soft = 0.0
65
+
66
+ def summary(self) -> dict[str, float | int]:
67
+ """Return summary statistics as dictionary."""
68
+ return {
69
+ "hard_clips": self.hard_clips,
70
+ "soft_clips": self.soft_clips,
71
+ "total_adjustments": self.total_adjustments,
72
+ "max_delta_hard": self.max_delta_hard,
73
+ "max_delta_soft": self.max_delta_soft,
74
+ "avg_delta_hard": (
75
+ self.sum_delta_hard / self.hard_clips if self.hard_clips > 0 else 0.0
76
+ ),
77
+ "avg_delta_soft": (
78
+ self.sum_delta_soft / self.soft_clips if self.soft_clips > 0 else 0.0
79
+ ),
80
+ }
81
+
82
+
83
+ # Global statistics instance (optional telemetry)
84
+ _global_stats = StructuralClipStats()
85
+
86
+
87
+ def get_clip_stats() -> StructuralClipStats:
88
+ """Return the global clip statistics instance."""
89
+ return _global_stats
90
+
91
+
92
+ def reset_clip_stats() -> None:
93
+ """Reset global clip statistics."""
94
+ _global_stats.reset()
95
+
96
+
97
+ def structural_clip(
98
+ value: float,
99
+ lo: float = -1.0,
100
+ hi: float = 1.0,
101
+ mode: Literal["hard", "soft"] = "hard",
102
+ k: float = 3.0,
103
+ *,
104
+ record_stats: bool = False,
105
+ ) -> float:
106
+ """Apply structural boundary preservation to EPI value.
107
+
108
+ Ensures that values remain within structural boundaries while preserving
109
+ coherence. Two modes are available:
110
+
111
+ - **hard**: Classic clamping for immediate stability (discontinuous derivative)
112
+ - **soft**: Smooth hyperbolic tangent mapping (continuous derivative)
113
+
114
+ Parameters
115
+ ----------
116
+ value : float
117
+ The EPI value to clip
118
+ lo : float, default -1.0
119
+ Lower structural boundary (EPI_MIN)
120
+ hi : float, default 1.0
121
+ Upper structural boundary (EPI_MAX)
122
+ mode : {'hard', 'soft'}, default 'hard'
123
+ Clipping mode:
124
+ - 'hard': Clamp to [lo, hi] (fast, discontinuous)
125
+ - 'soft': Smooth tanh-based remapping (slower, smooth)
126
+ k : float, default 3.0
127
+ Steepness parameter for soft mode (higher = sharper transition)
128
+ record_stats : bool, default False
129
+ If True, record intervention statistics in global telemetry
130
+
131
+ Returns
132
+ -------
133
+ float
134
+ Value constrained to [lo, hi] with specified mode
135
+
136
+ Notes
137
+ -----
138
+ The soft mode uses a scaled hyperbolic tangent:
139
+
140
+ y = tanh(k · x) / tanh(k)
141
+
142
+ which maps the input smoothly to [-1, 1], then rescales to [lo, hi].
143
+ This preserves derivative continuity but is computationally more expensive.
144
+
145
+ The hard mode is preferred for most use cases as it directly enforces
146
+ boundaries with minimal overhead.
147
+
148
+ Examples
149
+ --------
150
+ >>> structural_clip(1.1, -1.0, 1.0, mode="hard")
151
+ 1.0
152
+ >>> structural_clip(-1.2, -1.0, 1.0, mode="hard")
153
+ -1.0
154
+ >>> abs(structural_clip(0.95, -1.0, 1.0, mode="soft") - 0.95) < 0.01
155
+ True
156
+ """
157
+ if lo > hi:
158
+ raise ValueError(f"Lower bound {lo} must be <= upper bound {hi}")
159
+
160
+ if mode == "hard":
161
+ # Classic clamping - fast and simple
162
+ clipped = max(lo, min(hi, value))
163
+ if record_stats and clipped != value:
164
+ _global_stats.record_hard_clip(clipped - value)
165
+ return clipped
166
+
167
+ elif mode == "soft":
168
+ # Smooth sigmoid-based mapping that guarantees bounds
169
+ # Uses scaled tanh to create smooth transitions near boundaries
170
+ if lo == hi:
171
+ return lo
172
+
173
+ # First, clamp to slightly extended range to handle the mapping
174
+ # Map [lo, hi] to working range
175
+ margin = (hi - lo) * 0.1 # 10% margin for smooth transition
176
+ working_lo = lo - margin
177
+ working_hi = hi + margin
178
+
179
+ # Normalize to [-1, 1] for tanh
180
+ # Check for zero-width range after extension (shouldn't happen with lo != hi)
181
+ range_width = working_hi - working_lo
182
+ if abs(range_width) < 1e-10:
183
+ # Degenerate case: return midpoint
184
+ return (lo + hi) / 2.0
185
+
186
+ normalized = 2.0 * (value - (working_lo + working_hi) / 2.0) / range_width
187
+
188
+ # Apply tanh with steepness k for smooth S-curve
189
+ # tanh maps R → (-1, 1), scaled by k to control steepness
190
+ smooth_normalized = math.tanh(k * normalized)
191
+
192
+ # Map back from (-1, 1) to [lo, hi]
193
+ # This ensures output is always within [lo, hi]
194
+ mid = (lo + hi) / 2.0
195
+ half_range = (hi - lo) / 2.0
196
+ clipped = mid + smooth_normalized * half_range
197
+
198
+ # Final safety clamp for numerical precision
199
+ clipped = max(lo, min(hi, clipped))
200
+
201
+ if record_stats and abs(clipped - value) > 1e-10:
202
+ _global_stats.record_soft_clip(clipped - value)
203
+
204
+ return clipped
205
+
206
+ else:
207
+ raise ValueError(f"mode must be 'hard' or 'soft', got {mode!r}")
@@ -0,0 +1,37 @@
1
+ """Contextual error messages for TNFR operations.
2
+
3
+ This module provides user-friendly error messages with:
4
+ - Clear explanations of what went wrong
5
+ - Suggestions for how to fix the issue
6
+ - Links to relevant documentation
7
+ - Fuzzy matching for common typos
8
+
9
+ Examples
10
+ --------
11
+ >>> from tnfr.errors import OperatorSequenceError
12
+ >>> raise OperatorSequenceError(
13
+ ... "Invalid operator 'emision'",
14
+ ... suggestion="Did you mean 'emission'?",
15
+ ... docs_url="https://tnfr.readthedocs.io/operators.html"
16
+ ... )
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ __all__ = [
22
+ "TNFRUserError",
23
+ "OperatorSequenceError",
24
+ "NetworkConfigError",
25
+ "PhaseError",
26
+ "CoherenceError",
27
+ "FrequencyError",
28
+ ]
29
+
30
+ from .contextual import (
31
+ TNFRUserError,
32
+ OperatorSequenceError,
33
+ NetworkConfigError,
34
+ PhaseError,
35
+ CoherenceError,
36
+ FrequencyError,
37
+ )