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.
- tnfr/__init__.py +334 -50
- tnfr/__init__.pyi +33 -0
- tnfr/_compat.py +10 -0
- tnfr/_generated_version.py +34 -0
- tnfr/_version.py +49 -0
- tnfr/_version.pyi +7 -0
- tnfr/alias.py +214 -37
- tnfr/alias.pyi +108 -0
- tnfr/backends/__init__.py +354 -0
- tnfr/backends/jax_backend.py +173 -0
- tnfr/backends/numpy_backend.py +238 -0
- tnfr/backends/optimized_numpy.py +420 -0
- tnfr/backends/torch_backend.py +408 -0
- tnfr/cache.py +149 -556
- tnfr/cache.pyi +13 -0
- tnfr/cli/__init__.py +51 -16
- tnfr/cli/__init__.pyi +26 -0
- tnfr/cli/arguments.py +344 -32
- tnfr/cli/arguments.pyi +29 -0
- tnfr/cli/execution.py +676 -50
- tnfr/cli/execution.pyi +70 -0
- tnfr/cli/interactive_validator.py +614 -0
- tnfr/cli/utils.py +18 -3
- tnfr/cli/utils.pyi +7 -0
- tnfr/cli/validate.py +236 -0
- tnfr/compat/__init__.py +85 -0
- tnfr/compat/dataclass.py +136 -0
- tnfr/compat/jsonschema_stub.py +61 -0
- tnfr/compat/matplotlib_stub.py +73 -0
- tnfr/compat/numpy_stub.py +155 -0
- tnfr/config/__init__.py +224 -0
- tnfr/config/__init__.pyi +10 -0
- tnfr/{constants_glyphs.py → config/constants.py} +26 -20
- tnfr/config/constants.pyi +12 -0
- tnfr/config/defaults.py +54 -0
- tnfr/{constants/core.py → config/defaults_core.py} +59 -6
- tnfr/config/defaults_init.py +33 -0
- tnfr/config/defaults_metric.py +104 -0
- tnfr/config/feature_flags.py +81 -0
- tnfr/config/feature_flags.pyi +16 -0
- tnfr/config/glyph_constants.py +31 -0
- tnfr/config/init.py +77 -0
- tnfr/config/init.pyi +8 -0
- tnfr/config/operator_names.py +254 -0
- tnfr/config/operator_names.pyi +36 -0
- tnfr/config/physics_derivation.py +354 -0
- tnfr/config/presets.py +83 -0
- tnfr/config/presets.pyi +7 -0
- tnfr/config/security.py +927 -0
- tnfr/config/thresholds.py +114 -0
- tnfr/config/tnfr_config.py +498 -0
- tnfr/constants/__init__.py +51 -133
- tnfr/constants/__init__.pyi +92 -0
- tnfr/constants/aliases.py +33 -0
- tnfr/constants/aliases.pyi +27 -0
- tnfr/constants/init.py +3 -1
- tnfr/constants/init.pyi +12 -0
- tnfr/constants/metric.py +9 -15
- tnfr/constants/metric.pyi +19 -0
- tnfr/core/__init__.py +33 -0
- tnfr/core/container.py +226 -0
- tnfr/core/default_implementations.py +329 -0
- tnfr/core/interfaces.py +279 -0
- tnfr/dynamics/__init__.py +213 -633
- tnfr/dynamics/__init__.pyi +83 -0
- tnfr/dynamics/adaptation.py +267 -0
- tnfr/dynamics/adaptation.pyi +7 -0
- tnfr/dynamics/adaptive_sequences.py +189 -0
- tnfr/dynamics/adaptive_sequences.pyi +14 -0
- tnfr/dynamics/aliases.py +23 -0
- tnfr/dynamics/aliases.pyi +19 -0
- tnfr/dynamics/bifurcation.py +232 -0
- tnfr/dynamics/canonical.py +229 -0
- tnfr/dynamics/canonical.pyi +48 -0
- tnfr/dynamics/coordination.py +385 -0
- tnfr/dynamics/coordination.pyi +25 -0
- tnfr/dynamics/dnfr.py +2699 -398
- tnfr/dynamics/dnfr.pyi +26 -0
- tnfr/dynamics/dynamic_limits.py +225 -0
- tnfr/dynamics/feedback.py +252 -0
- tnfr/dynamics/feedback.pyi +24 -0
- tnfr/dynamics/fused_dnfr.py +454 -0
- tnfr/dynamics/homeostasis.py +157 -0
- tnfr/dynamics/homeostasis.pyi +14 -0
- tnfr/dynamics/integrators.py +496 -102
- tnfr/dynamics/integrators.pyi +36 -0
- tnfr/dynamics/learning.py +310 -0
- tnfr/dynamics/learning.pyi +33 -0
- tnfr/dynamics/metabolism.py +254 -0
- tnfr/dynamics/nbody.py +796 -0
- tnfr/dynamics/nbody_tnfr.py +783 -0
- tnfr/dynamics/propagation.py +326 -0
- tnfr/dynamics/runtime.py +908 -0
- tnfr/dynamics/runtime.pyi +77 -0
- tnfr/dynamics/sampling.py +10 -5
- tnfr/dynamics/sampling.pyi +7 -0
- tnfr/dynamics/selectors.py +711 -0
- tnfr/dynamics/selectors.pyi +85 -0
- tnfr/dynamics/structural_clip.py +207 -0
- tnfr/errors/__init__.py +37 -0
- tnfr/errors/contextual.py +492 -0
- tnfr/execution.py +77 -55
- tnfr/execution.pyi +45 -0
- tnfr/extensions/__init__.py +205 -0
- tnfr/extensions/__init__.pyi +18 -0
- tnfr/extensions/base.py +173 -0
- tnfr/extensions/base.pyi +35 -0
- tnfr/extensions/business/__init__.py +71 -0
- tnfr/extensions/business/__init__.pyi +11 -0
- tnfr/extensions/business/cookbook.py +88 -0
- tnfr/extensions/business/cookbook.pyi +8 -0
- tnfr/extensions/business/health_analyzers.py +202 -0
- tnfr/extensions/business/health_analyzers.pyi +9 -0
- tnfr/extensions/business/patterns.py +183 -0
- tnfr/extensions/business/patterns.pyi +8 -0
- tnfr/extensions/medical/__init__.py +73 -0
- tnfr/extensions/medical/__init__.pyi +11 -0
- tnfr/extensions/medical/cookbook.py +88 -0
- tnfr/extensions/medical/cookbook.pyi +8 -0
- tnfr/extensions/medical/health_analyzers.py +181 -0
- tnfr/extensions/medical/health_analyzers.pyi +9 -0
- tnfr/extensions/medical/patterns.py +163 -0
- tnfr/extensions/medical/patterns.pyi +8 -0
- tnfr/flatten.py +29 -50
- tnfr/flatten.pyi +21 -0
- tnfr/gamma.py +66 -53
- tnfr/gamma.pyi +36 -0
- tnfr/glyph_history.py +144 -57
- tnfr/glyph_history.pyi +35 -0
- tnfr/glyph_runtime.py +19 -0
- tnfr/glyph_runtime.pyi +8 -0
- tnfr/immutable.py +70 -30
- tnfr/immutable.pyi +36 -0
- tnfr/initialization.py +22 -16
- tnfr/initialization.pyi +65 -0
- tnfr/io.py +5 -241
- tnfr/io.pyi +13 -0
- tnfr/locking.pyi +7 -0
- tnfr/mathematics/__init__.py +79 -0
- tnfr/mathematics/backend.py +453 -0
- tnfr/mathematics/backend.pyi +99 -0
- tnfr/mathematics/dynamics.py +408 -0
- tnfr/mathematics/dynamics.pyi +90 -0
- tnfr/mathematics/epi.py +391 -0
- tnfr/mathematics/epi.pyi +65 -0
- tnfr/mathematics/generators.py +242 -0
- tnfr/mathematics/generators.pyi +29 -0
- tnfr/mathematics/metrics.py +119 -0
- tnfr/mathematics/metrics.pyi +16 -0
- tnfr/mathematics/operators.py +239 -0
- tnfr/mathematics/operators.pyi +59 -0
- tnfr/mathematics/operators_factory.py +124 -0
- tnfr/mathematics/operators_factory.pyi +11 -0
- tnfr/mathematics/projection.py +87 -0
- tnfr/mathematics/projection.pyi +33 -0
- tnfr/mathematics/runtime.py +182 -0
- tnfr/mathematics/runtime.pyi +64 -0
- tnfr/mathematics/spaces.py +256 -0
- tnfr/mathematics/spaces.pyi +83 -0
- tnfr/mathematics/transforms.py +305 -0
- tnfr/mathematics/transforms.pyi +62 -0
- tnfr/metrics/__init__.py +47 -9
- tnfr/metrics/__init__.pyi +20 -0
- tnfr/metrics/buffer_cache.py +163 -0
- tnfr/metrics/buffer_cache.pyi +24 -0
- tnfr/metrics/cache_utils.py +214 -0
- tnfr/metrics/coherence.py +1510 -330
- tnfr/metrics/coherence.pyi +129 -0
- tnfr/metrics/common.py +23 -16
- tnfr/metrics/common.pyi +35 -0
- tnfr/metrics/core.py +251 -36
- tnfr/metrics/core.pyi +13 -0
- tnfr/metrics/diagnosis.py +709 -110
- tnfr/metrics/diagnosis.pyi +86 -0
- tnfr/metrics/emergence.py +245 -0
- tnfr/metrics/export.py +60 -18
- tnfr/metrics/export.pyi +7 -0
- tnfr/metrics/glyph_timing.py +233 -43
- tnfr/metrics/glyph_timing.pyi +81 -0
- tnfr/metrics/learning_metrics.py +280 -0
- tnfr/metrics/learning_metrics.pyi +21 -0
- tnfr/metrics/phase_coherence.py +351 -0
- tnfr/metrics/phase_compatibility.py +349 -0
- tnfr/metrics/reporting.py +63 -28
- tnfr/metrics/reporting.pyi +25 -0
- tnfr/metrics/sense_index.py +1126 -43
- tnfr/metrics/sense_index.pyi +9 -0
- tnfr/metrics/trig.py +215 -23
- tnfr/metrics/trig.pyi +13 -0
- tnfr/metrics/trig_cache.py +148 -24
- tnfr/metrics/trig_cache.pyi +10 -0
- tnfr/multiscale/__init__.py +32 -0
- tnfr/multiscale/hierarchical.py +517 -0
- tnfr/node.py +646 -140
- tnfr/node.pyi +139 -0
- tnfr/observers.py +160 -45
- tnfr/observers.pyi +31 -0
- tnfr/ontosim.py +23 -19
- tnfr/ontosim.pyi +28 -0
- tnfr/operators/__init__.py +1358 -106
- tnfr/operators/__init__.pyi +31 -0
- tnfr/operators/algebra.py +277 -0
- tnfr/operators/canonical_patterns.py +420 -0
- tnfr/operators/cascade.py +267 -0
- tnfr/operators/cycle_detection.py +358 -0
- tnfr/operators/definitions.py +4108 -0
- tnfr/operators/definitions.pyi +78 -0
- tnfr/operators/grammar.py +1164 -0
- tnfr/operators/grammar.pyi +140 -0
- tnfr/operators/hamiltonian.py +710 -0
- tnfr/operators/health_analyzer.py +809 -0
- tnfr/operators/jitter.py +107 -38
- tnfr/operators/jitter.pyi +11 -0
- tnfr/operators/lifecycle.py +314 -0
- tnfr/operators/metabolism.py +618 -0
- tnfr/operators/metrics.py +2138 -0
- tnfr/operators/network_analysis/__init__.py +27 -0
- tnfr/operators/network_analysis/source_detection.py +186 -0
- tnfr/operators/nodal_equation.py +395 -0
- tnfr/operators/pattern_detection.py +660 -0
- tnfr/operators/patterns.py +669 -0
- tnfr/operators/postconditions/__init__.py +38 -0
- tnfr/operators/postconditions/mutation.py +236 -0
- tnfr/operators/preconditions/__init__.py +1226 -0
- tnfr/operators/preconditions/coherence.py +305 -0
- tnfr/operators/preconditions/dissonance.py +236 -0
- tnfr/operators/preconditions/emission.py +128 -0
- tnfr/operators/preconditions/mutation.py +580 -0
- tnfr/operators/preconditions/reception.py +125 -0
- tnfr/operators/preconditions/resonance.py +364 -0
- tnfr/operators/registry.py +74 -0
- tnfr/operators/registry.pyi +9 -0
- tnfr/operators/remesh.py +1415 -91
- tnfr/operators/remesh.pyi +26 -0
- tnfr/operators/structural_units.py +268 -0
- tnfr/operators/unified_grammar.py +105 -0
- tnfr/parallel/__init__.py +54 -0
- tnfr/parallel/auto_scaler.py +234 -0
- tnfr/parallel/distributed.py +384 -0
- tnfr/parallel/engine.py +238 -0
- tnfr/parallel/gpu_engine.py +420 -0
- tnfr/parallel/monitoring.py +248 -0
- tnfr/parallel/partitioner.py +459 -0
- tnfr/py.typed +0 -0
- tnfr/recipes/__init__.py +22 -0
- tnfr/recipes/cookbook.py +743 -0
- tnfr/rng.py +75 -151
- tnfr/rng.pyi +26 -0
- tnfr/schemas/__init__.py +8 -0
- tnfr/schemas/grammar.json +94 -0
- tnfr/sdk/__init__.py +107 -0
- tnfr/sdk/__init__.pyi +19 -0
- tnfr/sdk/adaptive_system.py +173 -0
- tnfr/sdk/adaptive_system.pyi +21 -0
- tnfr/sdk/builders.py +370 -0
- tnfr/sdk/builders.pyi +51 -0
- tnfr/sdk/fluent.py +1121 -0
- tnfr/sdk/fluent.pyi +74 -0
- tnfr/sdk/templates.py +342 -0
- tnfr/sdk/templates.pyi +41 -0
- tnfr/sdk/utils.py +341 -0
- tnfr/secure_config.py +46 -0
- tnfr/security/__init__.py +70 -0
- tnfr/security/database.py +514 -0
- tnfr/security/subprocess.py +503 -0
- tnfr/security/validation.py +290 -0
- tnfr/selector.py +59 -22
- tnfr/selector.pyi +19 -0
- tnfr/sense.py +92 -67
- tnfr/sense.pyi +23 -0
- tnfr/services/__init__.py +17 -0
- tnfr/services/orchestrator.py +325 -0
- tnfr/sparse/__init__.py +39 -0
- tnfr/sparse/representations.py +492 -0
- tnfr/structural.py +639 -263
- tnfr/structural.pyi +83 -0
- tnfr/telemetry/__init__.py +35 -0
- tnfr/telemetry/cache_metrics.py +226 -0
- tnfr/telemetry/cache_metrics.pyi +64 -0
- tnfr/telemetry/nu_f.py +422 -0
- tnfr/telemetry/nu_f.pyi +108 -0
- tnfr/telemetry/verbosity.py +36 -0
- tnfr/telemetry/verbosity.pyi +15 -0
- tnfr/tokens.py +2 -4
- tnfr/tokens.pyi +36 -0
- tnfr/tools/__init__.py +20 -0
- tnfr/tools/domain_templates.py +478 -0
- tnfr/tools/sequence_generator.py +846 -0
- tnfr/topology/__init__.py +13 -0
- tnfr/topology/asymmetry.py +151 -0
- tnfr/trace.py +300 -126
- tnfr/trace.pyi +42 -0
- tnfr/tutorials/__init__.py +38 -0
- tnfr/tutorials/autonomous_evolution.py +285 -0
- tnfr/tutorials/interactive.py +1576 -0
- tnfr/tutorials/structural_metabolism.py +238 -0
- tnfr/types.py +743 -12
- tnfr/types.pyi +357 -0
- tnfr/units.py +68 -0
- tnfr/units.pyi +13 -0
- tnfr/utils/__init__.py +282 -0
- tnfr/utils/__init__.pyi +215 -0
- tnfr/utils/cache.py +4223 -0
- tnfr/utils/cache.pyi +470 -0
- tnfr/{callback_utils.py → utils/callbacks.py} +26 -39
- tnfr/utils/callbacks.pyi +49 -0
- tnfr/utils/chunks.py +108 -0
- tnfr/utils/chunks.pyi +22 -0
- tnfr/utils/data.py +428 -0
- tnfr/utils/data.pyi +74 -0
- tnfr/utils/graph.py +85 -0
- tnfr/utils/graph.pyi +10 -0
- tnfr/utils/init.py +821 -0
- tnfr/utils/init.pyi +80 -0
- tnfr/utils/io.py +559 -0
- tnfr/utils/io.pyi +66 -0
- tnfr/{helpers → utils}/numeric.py +51 -24
- tnfr/utils/numeric.pyi +21 -0
- tnfr/validation/__init__.py +257 -0
- tnfr/validation/__init__.pyi +85 -0
- tnfr/validation/compatibility.py +460 -0
- tnfr/validation/compatibility.pyi +6 -0
- tnfr/validation/config.py +73 -0
- tnfr/validation/graph.py +139 -0
- tnfr/validation/graph.pyi +18 -0
- tnfr/validation/input_validation.py +755 -0
- tnfr/validation/invariants.py +712 -0
- tnfr/validation/rules.py +253 -0
- tnfr/validation/rules.pyi +44 -0
- tnfr/validation/runtime.py +279 -0
- tnfr/validation/runtime.pyi +28 -0
- tnfr/validation/sequence_validator.py +162 -0
- tnfr/validation/soft_filters.py +170 -0
- tnfr/validation/soft_filters.pyi +32 -0
- tnfr/validation/spectral.py +164 -0
- tnfr/validation/spectral.pyi +42 -0
- tnfr/validation/validator.py +1266 -0
- tnfr/validation/window.py +39 -0
- tnfr/validation/window.pyi +1 -0
- tnfr/visualization/__init__.py +98 -0
- tnfr/visualization/cascade_viz.py +256 -0
- tnfr/visualization/hierarchy.py +284 -0
- tnfr/visualization/sequence_plotter.py +784 -0
- tnfr/viz/__init__.py +60 -0
- tnfr/viz/matplotlib.py +278 -0
- tnfr/viz/matplotlib.pyi +35 -0
- tnfr-8.5.0.dist-info/METADATA +573 -0
- tnfr-8.5.0.dist-info/RECORD +353 -0
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/entry_points.txt +1 -0
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/licenses/LICENSE.md +1 -1
- tnfr/collections_utils.py +0 -300
- tnfr/config.py +0 -32
- tnfr/grammar.py +0 -344
- tnfr/graph_utils.py +0 -84
- tnfr/helpers/__init__.py +0 -71
- tnfr/import_utils.py +0 -228
- tnfr/json_utils.py +0 -162
- tnfr/logging_utils.py +0 -116
- tnfr/presets.py +0 -60
- tnfr/validators.py +0 -84
- tnfr/value_utils.py +0 -59
- tnfr-4.5.2.dist-info/METADATA +0 -379
- tnfr-4.5.2.dist-info/RECORD +0 -67
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/WHEEL +0 -0
- {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
|
|
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
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
144
|
-
|
|
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 =
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
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 !=
|
|
71
|
+
if size != _seed_hash_cache.maxsize:
|
|
173
72
|
_seed_hash_cache.configure(size)
|
|
174
|
-
_CACHE_MAXSIZE =
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def make_rng(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
134
|
+
if _seed_hash_cache.maxsize > 0:
|
|
211
135
|
_sync_cache_size(G)
|
|
212
|
-
return
|
|
136
|
+
return _seed_hash_cache.maxsize > 0
|
|
213
137
|
|
|
214
138
|
|
|
215
|
-
def base_seed(G:
|
|
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 =
|
|
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: ...
|
tnfr/schemas/__init__.py
ADDED
|
@@ -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
|