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/cache.py
CHANGED
|
@@ -1,578 +1,171 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Unified cache interface for TNFR.
|
|
2
2
|
|
|
3
|
-
This module
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
scoped graph caches guarded by locks, and version counters that keep edge
|
|
7
|
-
artifacts in sync with ΔNFR driven updates.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from __future__ import annotations
|
|
11
|
-
|
|
12
|
-
import hashlib
|
|
13
|
-
import threading
|
|
14
|
-
from collections import defaultdict
|
|
15
|
-
from collections.abc import Callable, Hashable, Iterable
|
|
16
|
-
from contextlib import contextmanager
|
|
17
|
-
from functools import lru_cache
|
|
18
|
-
from dataclasses import dataclass
|
|
19
|
-
from typing import Any, TypeVar
|
|
20
|
-
|
|
21
|
-
from cachetools import LRUCache
|
|
22
|
-
import networkx as nx # type: ignore[import-untyped]
|
|
23
|
-
|
|
24
|
-
from .graph_utils import get_graph, mark_dnfr_prep_dirty
|
|
25
|
-
from .import_utils import get_numpy
|
|
26
|
-
from .json_utils import json_dumps
|
|
27
|
-
from .logging_utils import get_logger
|
|
28
|
-
|
|
29
|
-
T = TypeVar("T")
|
|
30
|
-
|
|
31
|
-
__all__ = (
|
|
32
|
-
"EdgeCacheManager",
|
|
33
|
-
"LockAwareLRUCache",
|
|
34
|
-
"NODE_SET_CHECKSUM_KEY",
|
|
35
|
-
"cached_node_list",
|
|
36
|
-
"cached_nodes_and_A",
|
|
37
|
-
"clear_node_repr_cache",
|
|
38
|
-
"edge_version_cache",
|
|
39
|
-
"edge_version_update",
|
|
40
|
-
"ensure_node_index_map",
|
|
41
|
-
"ensure_node_offset_map",
|
|
42
|
-
"get_graph_version",
|
|
43
|
-
"increment_edge_version",
|
|
44
|
-
"increment_graph_version",
|
|
45
|
-
"node_set_checksum",
|
|
46
|
-
"stable_json",
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
# Key used to store the node set checksum in a graph's ``graph`` attribute.
|
|
50
|
-
NODE_SET_CHECKSUM_KEY = "_node_set_checksum_cache"
|
|
51
|
-
|
|
52
|
-
logger = get_logger(__name__)
|
|
53
|
-
|
|
54
|
-
# Keys of cache entries dependent on the edge version. Any change to the edge
|
|
55
|
-
# set requires these to be dropped to avoid stale data.
|
|
56
|
-
EDGE_VERSION_CACHE_KEYS = ("_trig_version",)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class LockAwareLRUCache(LRUCache[Hashable, Any]):
|
|
60
|
-
"""``LRUCache`` that drops per-key locks when evicting items."""
|
|
61
|
-
|
|
62
|
-
def __init__(self, maxsize: int, locks: dict[Hashable, threading.RLock]):
|
|
63
|
-
super().__init__(maxsize)
|
|
64
|
-
self._locks: dict[Hashable, threading.RLock] = locks
|
|
65
|
-
|
|
66
|
-
def popitem(self) -> tuple[Hashable, Any]: # type: ignore[override]
|
|
67
|
-
key, value = super().popitem()
|
|
68
|
-
self._locks.pop(key, None)
|
|
69
|
-
return key, value
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def _ensure_graph_entry(
|
|
73
|
-
graph: Any,
|
|
74
|
-
key: str,
|
|
75
|
-
factory: Callable[[], T],
|
|
76
|
-
validator: Callable[[Any], bool],
|
|
77
|
-
) -> T:
|
|
78
|
-
"""Return a validated entry from ``graph`` or create one when missing."""
|
|
79
|
-
|
|
80
|
-
value = graph.get(key)
|
|
81
|
-
if not validator(value):
|
|
82
|
-
value = factory()
|
|
83
|
-
graph[key] = value
|
|
84
|
-
return value
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def _ensure_lock_mapping(
|
|
88
|
-
graph: Any,
|
|
89
|
-
key: str,
|
|
90
|
-
*,
|
|
91
|
-
lock_factory: Callable[[], threading.RLock] = threading.RLock,
|
|
92
|
-
) -> defaultdict[Hashable, threading.RLock]:
|
|
93
|
-
"""Ensure ``graph`` holds a ``defaultdict`` of locks under ``key``."""
|
|
94
|
-
|
|
95
|
-
return _ensure_graph_entry(
|
|
96
|
-
graph,
|
|
97
|
-
key,
|
|
98
|
-
factory=lambda: defaultdict(lock_factory),
|
|
99
|
-
validator=lambda value: isinstance(value, defaultdict)
|
|
100
|
-
and value.default_factory is lock_factory,
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def _prune_locks(
|
|
105
|
-
cache: dict[Hashable, Any] | LRUCache[Hashable, Any] | None,
|
|
106
|
-
locks: dict[Hashable, threading.RLock]
|
|
107
|
-
| defaultdict[Hashable, threading.RLock]
|
|
108
|
-
| None,
|
|
109
|
-
) -> None:
|
|
110
|
-
"""Drop locks with no corresponding cache entry."""
|
|
111
|
-
|
|
112
|
-
if not isinstance(locks, dict):
|
|
113
|
-
return
|
|
114
|
-
cache_keys = cache.keys() if isinstance(cache, dict) else ()
|
|
115
|
-
for key in list(locks.keys()):
|
|
116
|
-
if key not in cache_keys:
|
|
117
|
-
locks.pop(key, None)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def get_graph_version(graph: Any, key: str, default: int = 0) -> int:
|
|
121
|
-
"""Return integer version stored in ``graph`` under ``key``."""
|
|
122
|
-
|
|
123
|
-
return int(graph.get(key, default))
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def increment_graph_version(graph: Any, key: str) -> int:
|
|
127
|
-
"""Increment and store a version counter in ``graph`` under ``key``."""
|
|
128
|
-
|
|
129
|
-
version = get_graph_version(graph, key) + 1
|
|
130
|
-
graph[key] = version
|
|
131
|
-
return version
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def stable_json(obj: Any) -> str:
|
|
135
|
-
"""Return a JSON string with deterministic ordering for ``obj``."""
|
|
136
|
-
|
|
137
|
-
return json_dumps(
|
|
138
|
-
obj,
|
|
139
|
-
sort_keys=True,
|
|
140
|
-
ensure_ascii=False,
|
|
141
|
-
to_bytes=False,
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
@lru_cache(maxsize=1024)
|
|
146
|
-
def _node_repr_digest(obj: Any) -> tuple[str, bytes]:
|
|
147
|
-
"""Return cached stable representation and digest for ``obj``."""
|
|
148
|
-
|
|
149
|
-
try:
|
|
150
|
-
repr_ = stable_json(obj)
|
|
151
|
-
except TypeError:
|
|
152
|
-
repr_ = repr(obj)
|
|
153
|
-
digest = hashlib.blake2b(repr_.encode("utf-8"), digest_size=16).digest()
|
|
154
|
-
return repr_, digest
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def clear_node_repr_cache() -> None:
|
|
158
|
-
"""Clear cached node representations used for checksums."""
|
|
159
|
-
|
|
160
|
-
_node_repr_digest.cache_clear()
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def _node_repr(n: Any) -> str:
|
|
164
|
-
"""Stable representation for node hashing and sorting."""
|
|
165
|
-
|
|
166
|
-
return _node_repr_digest(n)[0]
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def _iter_node_digests(
|
|
170
|
-
nodes: Iterable[Any], *, presorted: bool
|
|
171
|
-
) -> Iterable[bytes]:
|
|
172
|
-
"""Yield node digests in a deterministic order."""
|
|
173
|
-
|
|
174
|
-
if presorted:
|
|
175
|
-
for node in nodes:
|
|
176
|
-
yield _node_repr_digest(node)[1]
|
|
177
|
-
else:
|
|
178
|
-
for _, digest in sorted(
|
|
179
|
-
(_node_repr_digest(n) for n in nodes), key=lambda x: x[0]
|
|
180
|
-
):
|
|
181
|
-
yield digest
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
def _node_set_checksum_no_nodes(
|
|
185
|
-
G: nx.Graph,
|
|
186
|
-
graph: Any,
|
|
187
|
-
*,
|
|
188
|
-
presorted: bool,
|
|
189
|
-
store: bool,
|
|
190
|
-
) -> str:
|
|
191
|
-
"""Checksum helper when no explicit node set is provided."""
|
|
192
|
-
|
|
193
|
-
nodes_view = G.nodes()
|
|
194
|
-
current_nodes = frozenset(nodes_view)
|
|
195
|
-
cached = graph.get(NODE_SET_CHECKSUM_KEY)
|
|
196
|
-
if cached and len(cached) == 3 and cached[2] == current_nodes:
|
|
197
|
-
return cached[1]
|
|
198
|
-
|
|
199
|
-
hasher = hashlib.blake2b(digest_size=16)
|
|
200
|
-
for digest in _iter_node_digests(nodes_view, presorted=presorted):
|
|
201
|
-
hasher.update(digest)
|
|
202
|
-
|
|
203
|
-
checksum = hasher.hexdigest()
|
|
204
|
-
if store:
|
|
205
|
-
token = checksum[:16]
|
|
206
|
-
if cached and cached[0] == token:
|
|
207
|
-
return cached[1]
|
|
208
|
-
graph[NODE_SET_CHECKSUM_KEY] = (token, checksum, current_nodes)
|
|
209
|
-
else:
|
|
210
|
-
graph.pop(NODE_SET_CHECKSUM_KEY, None)
|
|
211
|
-
return checksum
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def node_set_checksum(
|
|
215
|
-
G: nx.Graph,
|
|
216
|
-
nodes: Iterable[Any] | None = None,
|
|
217
|
-
*,
|
|
218
|
-
presorted: bool = False,
|
|
219
|
-
store: bool = True,
|
|
220
|
-
) -> str:
|
|
221
|
-
"""Return a BLAKE2b checksum of ``G``'s node set."""
|
|
222
|
-
|
|
223
|
-
graph = get_graph(G)
|
|
224
|
-
if nodes is None:
|
|
225
|
-
return _node_set_checksum_no_nodes(
|
|
226
|
-
G, graph, presorted=presorted, store=store
|
|
227
|
-
)
|
|
3
|
+
This module provides a consolidated entry point for all TNFR caching needs,
|
|
4
|
+
integrating both the core CacheManager infrastructure and the advanced
|
|
5
|
+
hierarchical cache with dependency tracking.
|
|
228
6
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
7
|
+
Quick Start
|
|
8
|
+
-----------
|
|
9
|
+
For basic caching with metrics and persistence layers::
|
|
232
10
|
|
|
233
|
-
|
|
234
|
-
if store:
|
|
235
|
-
token = checksum[:16]
|
|
236
|
-
cached = graph.get(NODE_SET_CHECKSUM_KEY)
|
|
237
|
-
if cached and cached[0] == token:
|
|
238
|
-
return cached[1]
|
|
239
|
-
graph[NODE_SET_CHECKSUM_KEY] = (token, checksum)
|
|
240
|
-
else:
|
|
241
|
-
graph.pop(NODE_SET_CHECKSUM_KEY, None)
|
|
242
|
-
return checksum
|
|
11
|
+
from tnfr.cache import CacheManager, build_cache_manager
|
|
243
12
|
|
|
13
|
+
# Create a cache manager with default settings
|
|
14
|
+
manager = build_cache_manager()
|
|
244
15
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
"""Container for cached node data."""
|
|
16
|
+
# Register a named cache
|
|
17
|
+
manager.register("my_cache", lambda: {})
|
|
248
18
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
sorted_nodes: tuple[Any, ...] | None = None
|
|
252
|
-
idx: dict[Any, int] | None = None
|
|
253
|
-
offset: dict[Any, int] | None = None
|
|
19
|
+
# Get and use the cache
|
|
20
|
+
cache = manager.get("my_cache")
|
|
254
21
|
|
|
255
|
-
|
|
256
|
-
def n(self) -> int:
|
|
257
|
-
return len(self.nodes)
|
|
22
|
+
For advanced hierarchical caching with dependency tracking::
|
|
258
23
|
|
|
24
|
+
from tnfr.cache import TNFRHierarchicalCache, CacheLevel
|
|
259
25
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
nodes: tuple[Any, ...],
|
|
263
|
-
key: str,
|
|
264
|
-
*,
|
|
265
|
-
checksum: str,
|
|
266
|
-
sorted_nodes: tuple[Any, ...] | None = None,
|
|
267
|
-
) -> None:
|
|
268
|
-
"""Store ``nodes`` and ``checksum`` in ``graph`` under ``key``."""
|
|
26
|
+
# Create hierarchical cache
|
|
27
|
+
cache = TNFRHierarchicalCache(max_memory_mb=256)
|
|
269
28
|
|
|
270
|
-
|
|
271
|
-
|
|
29
|
+
# Store with dependencies
|
|
30
|
+
cache.set(
|
|
31
|
+
"metric_key",
|
|
32
|
+
value=0.95,
|
|
33
|
+
level=CacheLevel.DERIVED_METRICS,
|
|
34
|
+
dependencies={'graph_topology', 'node_properties'}
|
|
272
35
|
)
|
|
273
|
-
graph[f"{key}_checksum"] = checksum
|
|
274
36
|
|
|
37
|
+
# Selective invalidation
|
|
38
|
+
cache.invalidate_by_dependency('graph_topology')
|
|
275
39
|
|
|
276
|
-
|
|
277
|
-
G: nx.Graph,
|
|
278
|
-
graph: Any,
|
|
279
|
-
*,
|
|
280
|
-
sort_nodes: bool,
|
|
281
|
-
current_n: int,
|
|
282
|
-
) -> tuple[Any, ...]:
|
|
283
|
-
"""Refresh the cached node list and return the nodes."""
|
|
284
|
-
|
|
285
|
-
nodes = tuple(G.nodes())
|
|
286
|
-
checksum = node_set_checksum(G, nodes, store=True)
|
|
287
|
-
sorted_nodes = tuple(sorted(nodes, key=_node_repr)) if sort_nodes else None
|
|
288
|
-
_update_node_cache(
|
|
289
|
-
graph,
|
|
290
|
-
nodes,
|
|
291
|
-
"_node_list",
|
|
292
|
-
checksum=checksum,
|
|
293
|
-
sorted_nodes=sorted_nodes,
|
|
294
|
-
)
|
|
295
|
-
graph["_node_list_len"] = current_n
|
|
296
|
-
return nodes
|
|
40
|
+
For graph-specific caching::
|
|
297
41
|
|
|
42
|
+
from tnfr.cache import configure_graph_cache_limits
|
|
43
|
+
import networkx as nx
|
|
298
44
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
*,
|
|
305
|
-
sort_nodes: bool,
|
|
306
|
-
new_checksum: str | None,
|
|
307
|
-
) -> None:
|
|
308
|
-
"""Reuse existing node cache and record its checksum if missing."""
|
|
309
|
-
|
|
310
|
-
checksum = cache.checksum if new_checksum is None else new_checksum
|
|
311
|
-
if sort_nodes and sorted_nodes is None:
|
|
312
|
-
sorted_nodes = tuple(sorted(nodes, key=_node_repr))
|
|
313
|
-
_update_node_cache(
|
|
314
|
-
graph,
|
|
315
|
-
nodes,
|
|
316
|
-
"_node_list",
|
|
317
|
-
checksum=checksum,
|
|
318
|
-
sorted_nodes=sorted_nodes,
|
|
45
|
+
G = nx.Graph()
|
|
46
|
+
configure_graph_cache_limits(
|
|
47
|
+
G,
|
|
48
|
+
default_capacity=256,
|
|
49
|
+
overrides={"dnfr_prep": 512}
|
|
319
50
|
)
|
|
320
51
|
|
|
52
|
+
See Also
|
|
53
|
+
--------
|
|
54
|
+
tnfr.utils.cache : Core cache infrastructure and CacheManager
|
|
55
|
+
tnfr.caching : Advanced hierarchical cache with dependency tracking
|
|
56
|
+
tnfr.metrics.cache_utils : Hot-path cache configuration helpers
|
|
57
|
+
"""
|
|
321
58
|
|
|
322
|
-
|
|
323
|
-
"""Cache and return the tuple of nodes for ``G``."""
|
|
324
|
-
|
|
325
|
-
graph = get_graph(G)
|
|
326
|
-
cache: NodeCache | None = graph.get("_node_list_cache")
|
|
327
|
-
nodes = cache.nodes if cache else None
|
|
328
|
-
sorted_nodes = cache.sorted_nodes if cache else None
|
|
329
|
-
stored_len = graph.get("_node_list_len")
|
|
330
|
-
current_n = G.number_of_nodes()
|
|
331
|
-
dirty = bool(graph.pop("_node_list_dirty", False))
|
|
332
|
-
|
|
333
|
-
invalid = nodes is None or stored_len != current_n or dirty
|
|
334
|
-
new_checksum: str | None = None
|
|
335
|
-
|
|
336
|
-
if not invalid and cache:
|
|
337
|
-
new_checksum = node_set_checksum(G)
|
|
338
|
-
invalid = cache.checksum != new_checksum
|
|
339
|
-
|
|
340
|
-
sort_nodes = bool(graph.get("SORT_NODES", False))
|
|
341
|
-
|
|
342
|
-
if invalid:
|
|
343
|
-
nodes = _refresh_node_list_cache(
|
|
344
|
-
G, graph, sort_nodes=sort_nodes, current_n=current_n
|
|
345
|
-
)
|
|
346
|
-
elif cache and "_node_list_checksum" not in graph:
|
|
347
|
-
_reuse_node_list_cache(
|
|
348
|
-
graph,
|
|
349
|
-
cache,
|
|
350
|
-
nodes,
|
|
351
|
-
sorted_nodes,
|
|
352
|
-
sort_nodes=sort_nodes,
|
|
353
|
-
new_checksum=new_checksum,
|
|
354
|
-
)
|
|
355
|
-
else:
|
|
356
|
-
if sort_nodes and sorted_nodes is None and cache is not None:
|
|
357
|
-
cache.sorted_nodes = tuple(sorted(nodes, key=_node_repr))
|
|
358
|
-
return nodes
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
def cached_node_list(G: nx.Graph) -> tuple[Any, ...]:
|
|
362
|
-
"""Public wrapper returning the cached node tuple for ``G``."""
|
|
363
|
-
|
|
364
|
-
return _cache_node_list(G)
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
def _ensure_node_map(
|
|
368
|
-
G,
|
|
369
|
-
*,
|
|
370
|
-
attrs: tuple[str, ...],
|
|
371
|
-
sort: bool = False,
|
|
372
|
-
) -> dict[Any, int]:
|
|
373
|
-
"""Return cached node-to-index/offset mappings stored on ``NodeCache``."""
|
|
374
|
-
|
|
375
|
-
graph = G.graph
|
|
376
|
-
_cache_node_list(G)
|
|
377
|
-
cache: NodeCache = graph["_node_list_cache"]
|
|
378
|
-
|
|
379
|
-
missing = [attr for attr in attrs if getattr(cache, attr) is None]
|
|
380
|
-
if missing:
|
|
381
|
-
if sort:
|
|
382
|
-
nodes = cache.sorted_nodes
|
|
383
|
-
if nodes is None:
|
|
384
|
-
nodes = cache.sorted_nodes = tuple(
|
|
385
|
-
sorted(cache.nodes, key=_node_repr)
|
|
386
|
-
)
|
|
387
|
-
else:
|
|
388
|
-
nodes = cache.nodes
|
|
389
|
-
mappings: dict[str, dict[Any, int]] = {attr: {} for attr in missing}
|
|
390
|
-
for idx, node in enumerate(nodes):
|
|
391
|
-
for attr in missing:
|
|
392
|
-
mappings[attr][node] = idx
|
|
393
|
-
for attr in missing:
|
|
394
|
-
setattr(cache, attr, mappings[attr])
|
|
395
|
-
return getattr(cache, attrs[0])
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
def ensure_node_index_map(G) -> dict[Any, int]:
|
|
399
|
-
"""Return cached node-to-index mapping for ``G``."""
|
|
400
|
-
|
|
401
|
-
return _ensure_node_map(G, attrs=("idx",), sort=False)
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
def ensure_node_offset_map(G) -> dict[Any, int]:
|
|
405
|
-
"""Return cached node-to-offset mapping for ``G``."""
|
|
406
|
-
|
|
407
|
-
sort = bool(G.graph.get("SORT_NODES", False))
|
|
408
|
-
return _ensure_node_map(G, attrs=("offset",), sort=sort)
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
class EdgeCacheManager:
|
|
412
|
-
"""Coordinate cache storage and per-key locks for edge version caches."""
|
|
413
|
-
|
|
414
|
-
_LOCK = threading.RLock()
|
|
415
|
-
|
|
416
|
-
def __init__(self, graph: Any) -> None:
|
|
417
|
-
self.graph = graph
|
|
418
|
-
self.cache_key = "_edge_version_cache"
|
|
419
|
-
self.locks_key = "_edge_version_cache_locks"
|
|
420
|
-
|
|
421
|
-
def _validator(self, max_entries: int | None) -> Callable[[Any], bool]:
|
|
422
|
-
if max_entries is None:
|
|
423
|
-
return lambda value: value is not None and not isinstance(value, LRUCache)
|
|
424
|
-
return lambda value: isinstance(value, LRUCache) and value.maxsize == max_entries
|
|
425
|
-
|
|
426
|
-
def _factory(
|
|
427
|
-
self,
|
|
428
|
-
max_entries: int | None,
|
|
429
|
-
locks: dict[Hashable, threading.RLock]
|
|
430
|
-
| defaultdict[Hashable, threading.RLock],
|
|
431
|
-
) -> dict[Hashable, Any] | LRUCache[Hashable, Any]:
|
|
432
|
-
if max_entries:
|
|
433
|
-
return LockAwareLRUCache(max_entries, locks) # type: ignore[arg-type]
|
|
434
|
-
return {}
|
|
435
|
-
|
|
436
|
-
def get_cache(
|
|
437
|
-
self,
|
|
438
|
-
max_entries: int | None,
|
|
439
|
-
*,
|
|
440
|
-
create: bool = True,
|
|
441
|
-
) -> tuple[
|
|
442
|
-
dict[Hashable, Any] | LRUCache[Hashable, Any] | None,
|
|
443
|
-
dict[Hashable, threading.RLock]
|
|
444
|
-
| defaultdict[Hashable, threading.RLock]
|
|
445
|
-
| None,
|
|
446
|
-
]:
|
|
447
|
-
"""Return the cache and lock mapping for the manager's graph."""
|
|
448
|
-
|
|
449
|
-
with self._LOCK:
|
|
450
|
-
if not create:
|
|
451
|
-
cache = self.graph.get(self.cache_key)
|
|
452
|
-
locks = self.graph.get(self.locks_key)
|
|
453
|
-
return cache, locks
|
|
454
|
-
|
|
455
|
-
locks = _ensure_lock_mapping(self.graph, self.locks_key)
|
|
456
|
-
cache = _ensure_graph_entry(
|
|
457
|
-
self.graph,
|
|
458
|
-
self.cache_key,
|
|
459
|
-
factory=lambda: self._factory(max_entries, locks),
|
|
460
|
-
validator=self._validator(max_entries),
|
|
461
|
-
)
|
|
462
|
-
if max_entries is None:
|
|
463
|
-
_prune_locks(cache, locks)
|
|
464
|
-
return cache, locks
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
def edge_version_cache(
|
|
468
|
-
G: Any,
|
|
469
|
-
key: Hashable,
|
|
470
|
-
builder: Callable[[], T],
|
|
471
|
-
*,
|
|
472
|
-
max_entries: int | None = 128,
|
|
473
|
-
) -> T:
|
|
474
|
-
"""Return cached ``builder`` output tied to the edge version of ``G``."""
|
|
475
|
-
|
|
476
|
-
if max_entries is not None:
|
|
477
|
-
max_entries = int(max_entries)
|
|
478
|
-
if max_entries < 0:
|
|
479
|
-
raise ValueError("max_entries must be non-negative or None")
|
|
480
|
-
if max_entries is not None and max_entries == 0:
|
|
481
|
-
return builder()
|
|
482
|
-
|
|
483
|
-
graph = get_graph(G)
|
|
484
|
-
manager = graph.get("_edge_cache_manager") # type: ignore[assignment]
|
|
485
|
-
if not isinstance(manager, EdgeCacheManager) or manager.graph is not graph:
|
|
486
|
-
manager = EdgeCacheManager(graph)
|
|
487
|
-
graph["_edge_cache_manager"] = manager
|
|
488
|
-
|
|
489
|
-
cache, locks = manager.get_cache(max_entries)
|
|
490
|
-
edge_version = get_graph_version(graph, "_edge_version")
|
|
491
|
-
lock = locks[key]
|
|
492
|
-
|
|
493
|
-
with lock:
|
|
494
|
-
entry = cache.get(key)
|
|
495
|
-
if entry is not None and entry[0] == edge_version:
|
|
496
|
-
return entry[1]
|
|
497
|
-
|
|
498
|
-
try:
|
|
499
|
-
value = builder()
|
|
500
|
-
except (RuntimeError, ValueError) as exc: # pragma: no cover - logging side effect
|
|
501
|
-
logger.exception("edge_version_cache builder failed for %r: %s", key, exc)
|
|
502
|
-
raise
|
|
503
|
-
else:
|
|
504
|
-
with lock:
|
|
505
|
-
entry = cache.get(key)
|
|
506
|
-
if entry is not None and entry[0] == edge_version:
|
|
507
|
-
return entry[1]
|
|
508
|
-
cache[key] = (edge_version, value)
|
|
509
|
-
return value
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
def cached_nodes_and_A(
|
|
513
|
-
G: nx.Graph, *, cache_size: int | None = 1, require_numpy: bool = False
|
|
514
|
-
) -> tuple[tuple[Any, ...], Any]:
|
|
515
|
-
"""Return cached nodes tuple and adjacency matrix for ``G``."""
|
|
516
|
-
|
|
517
|
-
nodes = cached_node_list(G)
|
|
518
|
-
graph = G.graph
|
|
519
|
-
|
|
520
|
-
checksum = getattr(graph.get("_node_list_cache"), "checksum", None)
|
|
521
|
-
if checksum is None:
|
|
522
|
-
checksum = graph.get("_node_list_checksum")
|
|
523
|
-
if checksum is None:
|
|
524
|
-
node_set_cache = graph.get(NODE_SET_CHECKSUM_KEY)
|
|
525
|
-
if isinstance(node_set_cache, tuple) and len(node_set_cache) >= 2:
|
|
526
|
-
checksum = node_set_cache[1]
|
|
527
|
-
if checksum is None:
|
|
528
|
-
checksum = ""
|
|
529
|
-
|
|
530
|
-
key = f"_dnfr_{len(nodes)}_{checksum}"
|
|
531
|
-
graph["_dnfr_nodes_checksum"] = checksum
|
|
532
|
-
|
|
533
|
-
def builder() -> tuple[tuple[Any, ...], Any]:
|
|
534
|
-
np = get_numpy()
|
|
535
|
-
if np is None:
|
|
536
|
-
return nodes, None
|
|
537
|
-
A = nx.to_numpy_array(G, nodelist=nodes, weight=None, dtype=float)
|
|
538
|
-
return nodes, A
|
|
539
|
-
|
|
540
|
-
nodes, A = edge_version_cache(G, key, builder, max_entries=cache_size)
|
|
541
|
-
|
|
542
|
-
if require_numpy and A is None:
|
|
543
|
-
raise RuntimeError("NumPy is required for adjacency caching")
|
|
544
|
-
|
|
545
|
-
return nodes, A
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
def _reset_edge_caches(graph: Any, G: Any) -> None:
|
|
549
|
-
"""Clear caches affected by edge updates."""
|
|
550
|
-
|
|
551
|
-
cache, locks = EdgeCacheManager(graph).get_cache(None, create=False)
|
|
552
|
-
if isinstance(cache, (dict, LRUCache)):
|
|
553
|
-
cache.clear()
|
|
554
|
-
if isinstance(locks, dict):
|
|
555
|
-
locks.clear()
|
|
556
|
-
mark_dnfr_prep_dirty(G)
|
|
557
|
-
clear_node_repr_cache()
|
|
558
|
-
for key in EDGE_VERSION_CACHE_KEYS:
|
|
559
|
-
graph.pop(key, None)
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
def increment_edge_version(G: Any) -> None:
|
|
563
|
-
"""Increment the edge version counter in ``G.graph``."""
|
|
59
|
+
from __future__ import annotations
|
|
564
60
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
61
|
+
# Core cache infrastructure from tnfr.utils.cache
|
|
62
|
+
from .utils.cache import (
|
|
63
|
+
# Main classes
|
|
64
|
+
CacheManager,
|
|
65
|
+
CacheLayer,
|
|
66
|
+
MappingCacheLayer,
|
|
67
|
+
ShelveCacheLayer,
|
|
68
|
+
RedisCacheLayer,
|
|
69
|
+
InstrumentedLRUCache,
|
|
70
|
+
ManagedLRUCache,
|
|
71
|
+
EdgeCacheManager,
|
|
72
|
+
# Configuration and stats
|
|
73
|
+
CacheCapacityConfig,
|
|
74
|
+
CacheStatistics,
|
|
75
|
+
# Factory functions
|
|
76
|
+
build_cache_manager,
|
|
77
|
+
create_hmac_signer,
|
|
78
|
+
create_hmac_validator,
|
|
79
|
+
create_secure_shelve_layer,
|
|
80
|
+
create_secure_redis_layer,
|
|
81
|
+
# Graph-specific helpers
|
|
82
|
+
configure_graph_cache_limits,
|
|
83
|
+
configure_global_cache_layers,
|
|
84
|
+
reset_global_cache_manager,
|
|
85
|
+
edge_version_cache,
|
|
86
|
+
cached_node_list,
|
|
87
|
+
cached_nodes_and_A,
|
|
88
|
+
increment_edge_version,
|
|
89
|
+
edge_version_update,
|
|
90
|
+
# ΔNFR caching
|
|
91
|
+
DnfrCache,
|
|
92
|
+
DnfrPrepState,
|
|
93
|
+
new_dnfr_cache,
|
|
94
|
+
# Security
|
|
95
|
+
SecurityError,
|
|
96
|
+
SecurityWarning,
|
|
97
|
+
)
|
|
568
98
|
|
|
99
|
+
# Hierarchical cache with dependency tracking (now all in utils.cache)
|
|
100
|
+
from .utils.cache import (
|
|
101
|
+
TNFRHierarchicalCache,
|
|
102
|
+
CacheLevel,
|
|
103
|
+
CacheEntry,
|
|
104
|
+
cache_tnfr_computation,
|
|
105
|
+
invalidate_function_cache,
|
|
106
|
+
get_global_cache,
|
|
107
|
+
set_global_cache,
|
|
108
|
+
reset_global_cache,
|
|
109
|
+
GraphChangeTracker,
|
|
110
|
+
track_node_property_update,
|
|
111
|
+
PersistentTNFRCache,
|
|
112
|
+
)
|
|
569
113
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
114
|
+
# Hot-path cache configuration helpers
|
|
115
|
+
from .metrics.cache_utils import (
|
|
116
|
+
get_cache_config,
|
|
117
|
+
configure_hot_path_caches,
|
|
118
|
+
log_cache_metrics,
|
|
119
|
+
CacheStats,
|
|
120
|
+
)
|
|
573
121
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
122
|
+
__all__ = [
|
|
123
|
+
# Core cache classes
|
|
124
|
+
"CacheManager",
|
|
125
|
+
"CacheLayer",
|
|
126
|
+
"MappingCacheLayer",
|
|
127
|
+
"ShelveCacheLayer",
|
|
128
|
+
"RedisCacheLayer",
|
|
129
|
+
"InstrumentedLRUCache",
|
|
130
|
+
"ManagedLRUCache",
|
|
131
|
+
"EdgeCacheManager",
|
|
132
|
+
# Configuration and stats
|
|
133
|
+
"CacheCapacityConfig",
|
|
134
|
+
"CacheStatistics",
|
|
135
|
+
"CacheStats",
|
|
136
|
+
# Factory functions
|
|
137
|
+
"build_cache_manager",
|
|
138
|
+
"create_hmac_signer",
|
|
139
|
+
"create_hmac_validator",
|
|
140
|
+
"create_secure_shelve_layer",
|
|
141
|
+
"create_secure_redis_layer",
|
|
142
|
+
# Graph-specific helpers
|
|
143
|
+
"configure_graph_cache_limits",
|
|
144
|
+
"configure_global_cache_layers",
|
|
145
|
+
"reset_global_cache_manager",
|
|
146
|
+
"edge_version_cache",
|
|
147
|
+
"cached_node_list",
|
|
148
|
+
"cached_nodes_and_A",
|
|
149
|
+
"increment_edge_version",
|
|
150
|
+
"edge_version_update",
|
|
151
|
+
"get_cache_config",
|
|
152
|
+
"configure_hot_path_caches",
|
|
153
|
+
"log_cache_metrics",
|
|
154
|
+
# ΔNFR caching
|
|
155
|
+
"DnfrCache",
|
|
156
|
+
"DnfrPrepState",
|
|
157
|
+
"new_dnfr_cache",
|
|
158
|
+
# Hierarchical cache
|
|
159
|
+
"TNFRHierarchicalCache",
|
|
160
|
+
"CacheLevel",
|
|
161
|
+
"CacheEntry",
|
|
162
|
+
"cache_tnfr_computation",
|
|
163
|
+
"invalidate_function_cache",
|
|
164
|
+
# Change tracking
|
|
165
|
+
"GraphChangeTracker",
|
|
166
|
+
"track_node_property_update",
|
|
167
|
+
"PersistentTNFRCache",
|
|
168
|
+
# Security
|
|
169
|
+
"SecurityError",
|
|
170
|
+
"SecurityWarning",
|
|
171
|
+
]
|