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/rng.py CHANGED
@@ -2,17 +2,22 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import random
6
5
  import hashlib
6
+ import random
7
7
  import struct
8
- from collections.abc import Iterator, MutableMapping
9
- from typing import Any, Generic, Hashable, TypeVar
8
+ from typing import Any, cast
10
9
 
10
+ from cachetools import cached # type: ignore[import-untyped]
11
11
 
12
- from cachetools import LRUCache, cached
13
12
  from .constants import DEFAULTS, get_param
14
- from .graph_utils import get_graph
15
13
  from .locking import get_lock
14
+ from .types import GraphLike, TNFRGraph
15
+ from .utils import (
16
+ ScopedCounterCache,
17
+ _SeedHashCache,
18
+ build_cache_manager,
19
+ get_graph,
20
+ )
16
21
 
17
22
  MASK64 = 0xFFFFFFFFFFFFFFFF
18
23
 
@@ -21,147 +26,41 @@ _DEFAULT_CACHE_MAXSIZE = int(DEFAULTS.get("JITTER_CACHE_SIZE", 128))
21
26
  _CACHE_MAXSIZE = _DEFAULT_CACHE_MAXSIZE
22
27
  _CACHE_LOCKED = False
23
28
 
24
- K = TypeVar("K", bound=Hashable)
25
-
26
-
27
- class _SeedHashCache(MutableMapping[tuple[int, int], int]):
28
- """Mutable mapping proxy exposing a configurable LRU cache."""
29
-
30
- def __init__(self, maxsize: int) -> None:
31
- self._maxsize = 0
32
- self._cache: LRUCache[tuple[int, int], int] | None = None
33
- self.configure(maxsize)
34
-
35
- def configure(self, maxsize: int) -> None:
36
- """Configure internal cache size, clearing previous entries."""
37
-
38
- self._maxsize = int(maxsize)
39
- if self._maxsize <= 0:
40
- self._cache = None
41
- else:
42
- self._cache = LRUCache(maxsize=self._maxsize)
43
-
44
- def __getitem__(self, key: tuple[int, int]) -> int:
45
- if self._cache is None:
46
- raise KeyError(key)
47
- return self._cache[key]
48
-
49
- def __setitem__(self, key: tuple[int, int], value: int) -> None:
50
- if self._cache is not None:
51
- self._cache[key] = value
52
-
53
- def __delitem__(self, key: tuple[int, int]) -> None:
54
- if self._cache is None:
55
- raise KeyError(key)
56
- del self._cache[key]
57
-
58
- def __iter__(self) -> Iterator[tuple[int, int]]:
59
- if self._cache is None:
60
- return iter(())
61
- return iter(self._cache)
62
-
63
- def __len__(self) -> int:
64
- if self._cache is None:
65
- return 0
66
- return len(self._cache)
67
-
68
- def clear(self) -> None: # type: ignore[override]
69
- if self._cache is not None:
70
- self._cache.clear()
71
-
72
- @property
73
- def maxsize(self) -> int:
74
- return self._maxsize
75
-
76
- @property
77
- def enabled(self) -> bool:
78
- return self._cache is not None
79
-
80
- @property
81
- def data(self) -> LRUCache[tuple[int, int], int] | None:
82
- """Expose the underlying cache for diagnostics/tests."""
83
-
84
- return self._cache
85
-
86
-
87
- class ScopedCounterCache(Generic[K]):
88
- """Thread-safe LRU cache storing monotonic counters by ``key``."""
89
-
90
- def __init__(self, name: str, max_entries: int) -> None:
91
- if max_entries < 0:
92
- raise ValueError("max_entries must be non-negative")
93
- self._lock = get_lock(name)
94
- self._max_entries = int(max_entries)
95
- self._cache: LRUCache[K, int] = LRUCache(maxsize=self._max_entries)
96
-
97
- @property
98
- def lock(self):
99
- """Return the lock guarding access to the underlying cache."""
100
-
101
- return self._lock
102
-
103
- @property
104
- def max_entries(self) -> int:
105
- """Return the configured maximum number of cached entries."""
106
-
107
- return self._max_entries
108
-
109
- @property
110
- def cache(self) -> LRUCache[K, int]:
111
- """Expose the underlying ``LRUCache`` for inspection."""
29
+ _RNG_CACHE_MANAGER = build_cache_manager(default_capacity=_DEFAULT_CACHE_MAXSIZE)
112
30
 
113
- return self._cache
114
-
115
- def configure(
116
- self, *, force: bool = False, max_entries: int | None = None
117
- ) -> None:
118
- """Resize or reset the cache keeping previous settings."""
119
-
120
- size = self._max_entries if max_entries is None else int(max_entries)
121
- if size < 0:
122
- raise ValueError("max_entries must be non-negative")
123
- with self._lock:
124
- if size != self._max_entries:
125
- self._max_entries = size
126
- force = True
127
- if force:
128
- self._cache = LRUCache(maxsize=self._max_entries)
129
-
130
- def clear(self) -> None:
131
- """Clear stored counters preserving ``max_entries``."""
132
-
133
- self.configure(force=True)
134
-
135
- def bump(self, key: K) -> int:
136
- """Return current counter for ``key`` and increment it atomically."""
31
+ _seed_hash_cache = _SeedHashCache(
32
+ manager=_RNG_CACHE_MANAGER,
33
+ default_maxsize=_DEFAULT_CACHE_MAXSIZE,
34
+ )
137
35
 
138
- with self._lock:
139
- value = int(self._cache.get(key, 0))
140
- self._cache[key] = value + 1
141
- return value
142
36
 
143
- def __len__(self) -> int:
144
- return len(self._cache)
37
+ def _compute_seed_hash(seed_int: int, key_int: int) -> int:
38
+ seed_bytes = struct.pack(
39
+ ">QQ",
40
+ seed_int & MASK64,
41
+ key_int & MASK64,
42
+ )
43
+ return int.from_bytes(hashlib.blake2b(seed_bytes, digest_size=8).digest(), "big")
145
44
 
146
45
 
147
- _seed_hash_cache = _SeedHashCache(_CACHE_MAXSIZE)
46
+ @cached(cache=_seed_hash_cache, lock=_RNG_LOCK)
47
+ def _cached_seed_hash(seed_int: int, key_int: int) -> int:
48
+ return _compute_seed_hash(seed_int, key_int)
148
49
 
149
50
 
150
- @cached(cache=_seed_hash_cache, lock=_RNG_LOCK)
151
51
  def seed_hash(seed_int: int, key_int: int) -> int:
152
52
  """Return a 64-bit hash derived from ``seed_int`` and ``key_int``."""
153
53
 
154
- seed_bytes = struct.pack(
155
- ">QQ",
156
- seed_int & MASK64,
157
- key_int & MASK64,
158
- )
159
- return int.from_bytes(
160
- hashlib.blake2b(seed_bytes, digest_size=8).digest(), "big"
161
- )
54
+ if _CACHE_MAXSIZE <= 0 or not _seed_hash_cache.enabled:
55
+ return _compute_seed_hash(seed_int, key_int)
56
+ return _cached_seed_hash(seed_int, key_int)
162
57
 
163
58
 
164
- def _sync_cache_size(G: Any | None) -> None:
59
+ seed_hash.cache_clear = cast(Any, _cached_seed_hash).cache_clear # type: ignore[attr-defined]
60
+ seed_hash.cache = _seed_hash_cache # type: ignore[attr-defined]
61
+
62
+
63
+ def _sync_cache_size(G: TNFRGraph | GraphLike | None) -> None:
165
64
  """Synchronise cache size with ``G`` when needed."""
166
65
 
167
66
  global _CACHE_MAXSIZE
@@ -169,16 +68,41 @@ def _sync_cache_size(G: Any | None) -> None:
169
68
  return
170
69
  size = get_cache_maxsize(G)
171
70
  with _RNG_LOCK:
172
- if size != _CACHE_MAXSIZE:
71
+ if size != _seed_hash_cache.maxsize:
173
72
  _seed_hash_cache.configure(size)
174
- _CACHE_MAXSIZE = size
175
-
176
-
177
- def make_rng(seed: int, key: int, G: Any | None = None) -> random.Random:
178
- """Return a ``random.Random`` for ``seed`` and ``key``.
179
-
180
- When ``G`` is provided, ``JITTER_CACHE_SIZE`` is read from ``G`` and the
181
- internal cache size is updated accordingly.
73
+ _CACHE_MAXSIZE = _seed_hash_cache.maxsize
74
+
75
+
76
+ def make_rng(
77
+ seed: int, key: int, G: TNFRGraph | GraphLike | None = None
78
+ ) -> random.Random:
79
+ """Create a reproducible RNG instance from seed and key.
80
+
81
+ This factory constructs a deterministic :class:`random.Random` generator
82
+ by hashing the seed and key together. The hash result is cached for
83
+ performance when the same (seed, key) pair is requested repeatedly.
84
+
85
+ Parameters
86
+ ----------
87
+ seed : int
88
+ Base random seed for the generator. Must be an integer.
89
+ key : int
90
+ Key used to derive a unique hash with the seed. Multiple keys
91
+ allow independent RNG streams from the same base seed.
92
+ G : TNFRGraph | GraphLike | None, optional
93
+ Graph containing JITTER_CACHE_SIZE parameter. When provided, the
94
+ internal cache size is synchronized with the graph configuration.
95
+
96
+ Returns
97
+ -------
98
+ random.Random
99
+ Deterministic random number generator seeded with hash(seed, key).
100
+
101
+ Notes
102
+ -----
103
+ The same (seed, key) pair always produces the same generator state,
104
+ ensuring reproducibility across TNFR simulations. Cache synchronization
105
+ with ``G`` allows adaptive caching based on simulation requirements.
182
106
  """
183
107
  _sync_cache_size(G)
184
108
  seed_int = int(seed)
@@ -188,17 +112,17 @@ def make_rng(seed: int, key: int, G: Any | None = None) -> random.Random:
188
112
 
189
113
  def clear_rng_cache() -> None:
190
114
  """Clear cached seed hashes."""
191
- if _CACHE_MAXSIZE <= 0 or not _seed_hash_cache.enabled:
115
+ if _seed_hash_cache.maxsize <= 0 or not _seed_hash_cache.enabled:
192
116
  return
193
- seed_hash.cache_clear()
117
+ seed_hash.cache_clear() # type: ignore[attr-defined]
194
118
 
195
119
 
196
- def get_cache_maxsize(G: Any) -> int:
120
+ def get_cache_maxsize(G: TNFRGraph | GraphLike) -> int:
197
121
  """Return RNG cache maximum size for ``G``."""
198
122
  return int(get_param(G, "JITTER_CACHE_SIZE"))
199
123
 
200
124
 
201
- def cache_enabled(G: Any | None = None) -> bool:
125
+ def cache_enabled(G: TNFRGraph | GraphLike | None = None) -> bool:
202
126
  """Return ``True`` if RNG caching is enabled.
203
127
 
204
128
  When ``G`` is provided, the cache size is synchronised with
@@ -207,12 +131,12 @@ def cache_enabled(G: Any | None = None) -> bool:
207
131
  # Only synchronise the cache size with ``G`` when caching is enabled. This
208
132
  # preserves explicit calls to :func:`set_cache_maxsize(0)` which are used in
209
133
  # tests to temporarily disable caching regardless of graph defaults.
210
- if _CACHE_MAXSIZE > 0:
134
+ if _seed_hash_cache.maxsize > 0:
211
135
  _sync_cache_size(G)
212
- return _CACHE_MAXSIZE > 0
136
+ return _seed_hash_cache.maxsize > 0
213
137
 
214
138
 
215
- def base_seed(G: Any) -> int:
139
+ def base_seed(G: TNFRGraph | GraphLike) -> int:
216
140
  """Return base RNG seed stored in ``G.graph``."""
217
141
  graph = get_graph(G)
218
142
  return int(graph.get("RANDOM_SEED", 0))
@@ -238,7 +162,7 @@ def set_cache_maxsize(size: int) -> None:
238
162
  raise ValueError("size must be non-negative")
239
163
  with _RNG_LOCK:
240
164
  _seed_hash_cache.configure(new_size)
241
- _CACHE_MAXSIZE = new_size
165
+ _CACHE_MAXSIZE = _seed_hash_cache.maxsize
242
166
  _CACHE_LOCKED = new_size != _DEFAULT_CACHE_MAXSIZE
243
167
 
244
168
 
tnfr/rng.pyi ADDED
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ import random
4
+ from .types import GraphLike, TNFRGraph
5
+ from .utils import ScopedCounterCache as ScopedCounterCache
6
+
7
+ __all__ = [
8
+ "seed_hash",
9
+ "make_rng",
10
+ "get_cache_maxsize",
11
+ "set_cache_maxsize",
12
+ "base_seed",
13
+ "cache_enabled",
14
+ "clear_rng_cache",
15
+ "ScopedCounterCache",
16
+ ]
17
+
18
+ def seed_hash(seed_int: int, key_int: int) -> int: ...
19
+ def make_rng(
20
+ seed: int, key: int, G: TNFRGraph | GraphLike | None = None
21
+ ) -> random.Random: ...
22
+ def clear_rng_cache() -> None: ...
23
+ def get_cache_maxsize(G: TNFRGraph | GraphLike) -> int: ...
24
+ def cache_enabled(G: TNFRGraph | GraphLike | None = None) -> bool: ...
25
+ def base_seed(G: TNFRGraph | GraphLike) -> int: ...
26
+ def set_cache_maxsize(size: int) -> None: ...
@@ -0,0 +1,8 @@
1
+ """JSON schema resources bundled with the TNFR engine."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __all__ = ["package"]
6
+
7
+ # Namespace packages need at least one attribute for static analysers.
8
+ package = __name__
@@ -0,0 +1,94 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://tnfr.io/schemas/grammar.json",
4
+ "title": "TNFR Grammar Configuration",
5
+ "type": "object",
6
+ "definitions": {
7
+ "glyphCode": {
8
+ "description": "Canonical glyph identifier in uppercase notation.",
9
+ "type": "string",
10
+ "pattern": "^[A-Z][A-Z_]*$"
11
+ },
12
+ "probability": {
13
+ "description": "Threshold constrained to the [0, 1] interval.",
14
+ "type": "number",
15
+ "minimum": 0.0,
16
+ "maximum": 1.0
17
+ },
18
+ "cfg_soft": {
19
+ "type": "object",
20
+ "description": "Soft grammar preferences applied before canonical automaton rules.",
21
+ "properties": {
22
+ "window": {
23
+ "description": "History window inspected to avoid short-term glyph repetitions.",
24
+ "type": "integer",
25
+ "minimum": 0
26
+ },
27
+ "avoid_repeats": {
28
+ "description": "Glyph codes that should be substituted when repeated inside the window.",
29
+ "type": "array",
30
+ "items": { "$ref": "#/definitions/glyphCode" },
31
+ "uniqueItems": true
32
+ },
33
+ "fallbacks": {
34
+ "description": "Mapping of glyph codes to their explicit substitution when repetition is detected.",
35
+ "type": "object",
36
+ "additionalProperties": { "$ref": "#/definitions/glyphCode" }
37
+ },
38
+ "force_dnfr": {
39
+ "description": "Minimum |ΔNFR| normalised score that bypasses soft filtering.",
40
+ "$ref": "#/definitions/probability"
41
+ },
42
+ "force_accel": {
43
+ "description": "Minimum acceleration normalised score that bypasses soft filtering.",
44
+ "$ref": "#/definitions/probability"
45
+ }
46
+ },
47
+ "additionalProperties": true
48
+ },
49
+ "cfg_canon": {
50
+ "type": "object",
51
+ "description": "Canonical grammar thresholds enforced by the automaton.",
52
+ "properties": {
53
+ "enabled": {
54
+ "description": "Toggle canonical grammar enforcement during metric runs.",
55
+ "type": "boolean"
56
+ },
57
+ "zhir_requires_oz_window": {
58
+ "description": "Window requiring a DISSONANCE glyph before a MUTATION.",
59
+ "type": "integer",
60
+ "minimum": 0
61
+ },
62
+ "zhir_dnfr_min": {
63
+ "description": "Minimum normalised |ΔNFR| required to allow MUTATION without recent DISSONANCE.",
64
+ "type": "number",
65
+ "minimum": 0.0
66
+ },
67
+ "thol_min_len": {
68
+ "description": "Minimum number of THOL glyphs before canonical closure is allowed.",
69
+ "type": "integer",
70
+ "minimum": 0
71
+ },
72
+ "thol_max_len": {
73
+ "description": "Maximum number of THOL glyphs tolerated before forcing closure.",
74
+ "type": "integer",
75
+ "minimum": 0
76
+ },
77
+ "thol_close_dnfr": {
78
+ "description": "Upper bound on normalised |ΔNFR| that triggers THOL closure.",
79
+ "$ref": "#/definitions/probability"
80
+ },
81
+ "si_high": {
82
+ "description": "Sense index threshold: Si at or above this resolves THOL closures with silence; lower Si forces contraction.",
83
+ "$ref": "#/definitions/probability"
84
+ }
85
+ },
86
+ "additionalProperties": true
87
+ }
88
+ },
89
+ "properties": {
90
+ "cfg_soft": { "$ref": "#/definitions/cfg_soft" },
91
+ "cfg_canon": { "$ref": "#/definitions/cfg_canon" }
92
+ },
93
+ "additionalProperties": false
94
+ }
tnfr/sdk/__init__.py ADDED
@@ -0,0 +1,107 @@
1
+ """Simplified SDK for non-expert TNFR users.
2
+
3
+ This module provides a high-level, user-friendly API for creating and
4
+ simulating TNFR networks without requiring deep knowledge of the underlying
5
+ theory. The SDK maintains full theoretical fidelity while hiding complexity
6
+ through fluent interfaces, pre-configured templates, and domain-specific
7
+ patterns.
8
+
9
+ Public API
10
+ ----------
11
+ TNFRNetwork
12
+ Fluent API for creating and evolving TNFR networks with method chaining.
13
+ TNFRTemplates
14
+ Pre-configured templates for common domain-specific use cases.
15
+ TNFRExperimentBuilder
16
+ Builder pattern for standard TNFR experiment workflows.
17
+ NetworkResults
18
+ Structured results container for TNFR metrics and graph state.
19
+ NetworkConfig
20
+ Configuration dataclass for network settings.
21
+
22
+ Utilities
23
+ ---------
24
+ compare_networks
25
+ Compare metrics across multiple networks.
26
+ compute_network_statistics
27
+ Compute extended statistics for a network.
28
+ export_to_json
29
+ Export network data to JSON file.
30
+ import_from_json
31
+ Import network data from JSON file.
32
+ format_comparison_table
33
+ Format network comparison as readable table.
34
+ suggest_sequence_for_goal
35
+ Suggest operator sequence for a specific goal.
36
+ """
37
+
38
+ from __future__ import annotations
39
+
40
+ __all__ = [
41
+ "TNFRNetwork",
42
+ "NetworkConfig",
43
+ "NetworkResults",
44
+ "TNFRTemplates",
45
+ "TNFRExperimentBuilder",
46
+ "TNFRAdaptiveSystem",
47
+ # Utilities
48
+ "compare_networks",
49
+ "compute_network_statistics",
50
+ "export_to_json",
51
+ "import_from_json",
52
+ "format_comparison_table",
53
+ "suggest_sequence_for_goal",
54
+ ]
55
+
56
+
57
+ # Lazy imports to avoid circular dependencies and optional dependency issues
58
+ def __getattr__(name: str):
59
+ """Lazy load SDK components."""
60
+ if name == "TNFRNetwork" or name == "NetworkConfig" or name == "NetworkResults":
61
+ from .fluent import TNFRNetwork, NetworkConfig, NetworkResults
62
+
63
+ if name == "TNFRNetwork":
64
+ return TNFRNetwork
65
+ elif name == "NetworkConfig":
66
+ return NetworkConfig
67
+ else:
68
+ return NetworkResults
69
+ elif name == "TNFRTemplates":
70
+ from .templates import TNFRTemplates
71
+
72
+ return TNFRTemplates
73
+ elif name == "TNFRExperimentBuilder":
74
+ from .builders import TNFRExperimentBuilder
75
+
76
+ return TNFRExperimentBuilder
77
+ elif name == "TNFRAdaptiveSystem":
78
+ from .adaptive_system import TNFRAdaptiveSystem
79
+
80
+ return TNFRAdaptiveSystem
81
+ elif name in [
82
+ "compare_networks",
83
+ "compute_network_statistics",
84
+ "export_to_json",
85
+ "import_from_json",
86
+ "format_comparison_table",
87
+ "suggest_sequence_for_goal",
88
+ ]:
89
+ from .utils import (
90
+ compare_networks,
91
+ compute_network_statistics,
92
+ export_to_json,
93
+ import_from_json,
94
+ format_comparison_table,
95
+ suggest_sequence_for_goal,
96
+ )
97
+
98
+ mapping = {
99
+ "compare_networks": compare_networks,
100
+ "compute_network_statistics": compute_network_statistics,
101
+ "export_to_json": export_to_json,
102
+ "import_from_json": import_from_json,
103
+ "format_comparison_table": format_comparison_table,
104
+ "suggest_sequence_for_goal": suggest_sequence_for_goal,
105
+ }
106
+ return mapping[name]
107
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
tnfr/sdk/__init__.pyi ADDED
@@ -0,0 +1,19 @@
1
+ """Type stubs for tnfr.sdk module."""
2
+
3
+ from typing import Any
4
+
5
+ __all__: tuple[str, ...]
6
+
7
+ TNFRNetwork: Any
8
+ NetworkConfig: Any
9
+ NetworkResults: Any
10
+ TNFRTemplates: Any
11
+ TNFRExperimentBuilder: Any
12
+ TNFRAdaptiveSystem: Any
13
+
14
+ compare_networks: Any
15
+ compute_network_statistics: Any
16
+ export_to_json: Any
17
+ import_from_json: Any
18
+ format_comparison_table: Any
19
+ suggest_sequence_for_goal: Any