tnfr 6.0.0__py3-none-any.whl → 7.0.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 +50 -5
- tnfr/__init__.pyi +0 -7
- tnfr/_compat.py +0 -1
- tnfr/_generated_version.py +34 -0
- tnfr/_version.py +44 -2
- tnfr/alias.py +14 -13
- tnfr/alias.pyi +5 -37
- tnfr/cache.py +9 -729
- tnfr/cache.pyi +8 -224
- tnfr/callback_utils.py +16 -31
- tnfr/callback_utils.pyi +3 -29
- tnfr/cli/__init__.py +17 -11
- tnfr/cli/__init__.pyi +0 -21
- tnfr/cli/arguments.py +175 -14
- tnfr/cli/arguments.pyi +5 -11
- tnfr/cli/execution.py +434 -48
- tnfr/cli/execution.pyi +14 -24
- tnfr/cli/utils.py +20 -3
- tnfr/cli/utils.pyi +5 -5
- tnfr/config/__init__.py +2 -1
- tnfr/config/__init__.pyi +2 -0
- tnfr/config/feature_flags.py +83 -0
- tnfr/config/init.py +1 -1
- tnfr/config/operator_names.py +1 -14
- tnfr/config/presets.py +6 -26
- tnfr/constants/__init__.py +10 -13
- tnfr/constants/__init__.pyi +10 -22
- tnfr/constants/aliases.py +31 -0
- tnfr/constants/core.py +4 -3
- tnfr/constants/init.py +1 -1
- tnfr/constants/metric.py +3 -3
- tnfr/dynamics/__init__.py +64 -10
- tnfr/dynamics/__init__.pyi +3 -4
- tnfr/dynamics/adaptation.py +79 -13
- tnfr/dynamics/aliases.py +10 -9
- tnfr/dynamics/coordination.py +77 -35
- tnfr/dynamics/dnfr.py +575 -274
- tnfr/dynamics/dnfr.pyi +1 -10
- tnfr/dynamics/integrators.py +47 -33
- tnfr/dynamics/integrators.pyi +0 -1
- tnfr/dynamics/runtime.py +489 -129
- tnfr/dynamics/sampling.py +2 -0
- tnfr/dynamics/selectors.py +101 -62
- tnfr/execution.py +15 -8
- tnfr/execution.pyi +5 -25
- tnfr/flatten.py +7 -3
- tnfr/flatten.pyi +1 -8
- tnfr/gamma.py +22 -26
- tnfr/gamma.pyi +0 -6
- tnfr/glyph_history.py +37 -26
- tnfr/glyph_history.pyi +1 -19
- tnfr/glyph_runtime.py +16 -0
- tnfr/glyph_runtime.pyi +9 -0
- tnfr/immutable.py +20 -15
- tnfr/immutable.pyi +4 -7
- tnfr/initialization.py +5 -7
- tnfr/initialization.pyi +1 -9
- tnfr/io.py +6 -305
- tnfr/io.pyi +13 -8
- tnfr/mathematics/__init__.py +81 -0
- tnfr/mathematics/backend.py +426 -0
- tnfr/mathematics/dynamics.py +398 -0
- tnfr/mathematics/epi.py +254 -0
- tnfr/mathematics/generators.py +222 -0
- tnfr/mathematics/metrics.py +119 -0
- tnfr/mathematics/operators.py +233 -0
- tnfr/mathematics/operators_factory.py +71 -0
- tnfr/mathematics/projection.py +78 -0
- tnfr/mathematics/runtime.py +173 -0
- tnfr/mathematics/spaces.py +247 -0
- tnfr/mathematics/transforms.py +292 -0
- tnfr/metrics/__init__.py +10 -10
- tnfr/metrics/coherence.py +123 -94
- tnfr/metrics/common.py +22 -13
- tnfr/metrics/common.pyi +42 -11
- tnfr/metrics/core.py +72 -14
- tnfr/metrics/diagnosis.py +48 -57
- tnfr/metrics/diagnosis.pyi +3 -7
- tnfr/metrics/export.py +3 -5
- tnfr/metrics/glyph_timing.py +41 -31
- tnfr/metrics/reporting.py +13 -6
- tnfr/metrics/sense_index.py +884 -114
- tnfr/metrics/trig.py +167 -11
- tnfr/metrics/trig.pyi +1 -0
- tnfr/metrics/trig_cache.py +112 -15
- tnfr/node.py +400 -17
- tnfr/node.pyi +55 -38
- tnfr/observers.py +111 -8
- tnfr/observers.pyi +0 -15
- tnfr/ontosim.py +9 -6
- tnfr/ontosim.pyi +0 -5
- tnfr/operators/__init__.py +529 -42
- tnfr/operators/__init__.pyi +14 -0
- tnfr/operators/definitions.py +350 -18
- tnfr/operators/definitions.pyi +0 -14
- tnfr/operators/grammar.py +760 -0
- tnfr/operators/jitter.py +28 -22
- tnfr/operators/registry.py +7 -12
- tnfr/operators/registry.pyi +0 -2
- tnfr/operators/remesh.py +38 -61
- tnfr/rng.py +17 -300
- tnfr/schemas/__init__.py +8 -0
- tnfr/schemas/grammar.json +94 -0
- tnfr/selector.py +3 -4
- tnfr/selector.pyi +1 -1
- tnfr/sense.py +22 -24
- tnfr/sense.pyi +0 -7
- tnfr/structural.py +504 -21
- tnfr/structural.pyi +41 -18
- tnfr/telemetry/__init__.py +23 -1
- tnfr/telemetry/cache_metrics.py +226 -0
- tnfr/telemetry/nu_f.py +423 -0
- tnfr/telemetry/nu_f.pyi +123 -0
- tnfr/tokens.py +1 -4
- tnfr/tokens.pyi +1 -6
- tnfr/trace.py +20 -53
- tnfr/trace.pyi +9 -37
- tnfr/types.py +244 -15
- tnfr/types.pyi +200 -14
- tnfr/units.py +69 -0
- tnfr/units.pyi +16 -0
- tnfr/utils/__init__.py +107 -48
- tnfr/utils/__init__.pyi +80 -11
- tnfr/utils/cache.py +1705 -65
- tnfr/utils/cache.pyi +370 -58
- tnfr/utils/chunks.py +104 -0
- tnfr/utils/chunks.pyi +21 -0
- tnfr/utils/data.py +95 -5
- tnfr/utils/data.pyi +8 -17
- tnfr/utils/graph.py +2 -4
- tnfr/utils/init.py +31 -7
- tnfr/utils/init.pyi +4 -11
- tnfr/utils/io.py +313 -14
- tnfr/{helpers → utils}/numeric.py +50 -24
- tnfr/utils/numeric.pyi +21 -0
- tnfr/validation/__init__.py +92 -4
- tnfr/validation/__init__.pyi +77 -17
- tnfr/validation/compatibility.py +79 -43
- tnfr/validation/compatibility.pyi +4 -6
- tnfr/validation/grammar.py +55 -133
- tnfr/validation/grammar.pyi +37 -8
- tnfr/validation/graph.py +138 -0
- tnfr/validation/graph.pyi +17 -0
- tnfr/validation/rules.py +161 -74
- tnfr/validation/rules.pyi +55 -18
- tnfr/validation/runtime.py +263 -0
- tnfr/validation/runtime.pyi +31 -0
- tnfr/validation/soft_filters.py +170 -0
- tnfr/validation/soft_filters.pyi +37 -0
- tnfr/validation/spectral.py +159 -0
- tnfr/validation/spectral.pyi +46 -0
- tnfr/validation/syntax.py +28 -139
- tnfr/validation/syntax.pyi +7 -4
- tnfr/validation/window.py +39 -0
- tnfr/validation/window.pyi +1 -0
- tnfr/viz/__init__.py +9 -0
- tnfr/viz/matplotlib.py +246 -0
- {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/METADATA +63 -19
- tnfr-7.0.0.dist-info/RECORD +185 -0
- {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/licenses/LICENSE.md +1 -1
- tnfr/constants_glyphs.py +0 -16
- tnfr/constants_glyphs.pyi +0 -12
- tnfr/grammar.py +0 -25
- tnfr/grammar.pyi +0 -13
- tnfr/helpers/__init__.py +0 -151
- tnfr/helpers/__init__.pyi +0 -66
- tnfr/helpers/numeric.pyi +0 -12
- tnfr/presets.py +0 -15
- tnfr/presets.pyi +0 -7
- tnfr/utils/io.pyi +0 -10
- tnfr/utils/validators.py +0 -130
- tnfr/utils/validators.pyi +0 -19
- tnfr-6.0.0.dist-info/RECORD +0 -157
- {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/WHEEL +0 -0
- {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/entry_points.txt +0 -0
- {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/top_level.txt +0 -0
tnfr/utils/cache.pyi
CHANGED
|
@@ -1,25 +1,234 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import logging
|
|
3
4
|
import threading
|
|
4
|
-
from collections
|
|
5
|
-
from
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
from collections.abc import (
|
|
7
|
+
Callable,
|
|
8
|
+
Hashable,
|
|
9
|
+
Iterable,
|
|
10
|
+
Iterator,
|
|
11
|
+
Mapping,
|
|
12
|
+
MutableMapping,
|
|
13
|
+
)
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from typing import Any, ClassVar, ContextManager, Generic, TypeVar
|
|
6
16
|
|
|
7
17
|
import networkx as nx
|
|
18
|
+
from cachetools import LRUCache
|
|
19
|
+
|
|
20
|
+
from ..types import GraphLike, NodeId, TimingContext, TNFRGraph
|
|
8
21
|
|
|
9
|
-
from ..cache import CacheCapacityConfig, CacheManager
|
|
10
|
-
from ..types import GraphLike, NodeId, TNFRGraph, TimingContext
|
|
11
22
|
|
|
12
23
|
K = TypeVar("K", bound=Hashable)
|
|
13
24
|
V = TypeVar("V")
|
|
14
25
|
T = TypeVar("T")
|
|
15
26
|
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class CacheCapacityConfig:
|
|
29
|
+
default_capacity: int | None
|
|
30
|
+
overrides: dict[str, int | None]
|
|
31
|
+
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
class CacheStatistics:
|
|
34
|
+
hits: int = ...
|
|
35
|
+
misses: int = ...
|
|
36
|
+
evictions: int = ...
|
|
37
|
+
total_time: float = ...
|
|
38
|
+
timings: int = ...
|
|
39
|
+
|
|
40
|
+
def merge(self, other: CacheStatistics) -> CacheStatistics: ...
|
|
41
|
+
|
|
42
|
+
class CacheLayer:
|
|
43
|
+
def load(self, name: str) -> Any: ...
|
|
44
|
+
def store(self, name: str, value: Any) -> None: ...
|
|
45
|
+
def delete(self, name: str) -> None: ...
|
|
46
|
+
def clear(self) -> None: ...
|
|
47
|
+
def close(self) -> None: ...
|
|
48
|
+
|
|
49
|
+
class MappingCacheLayer(CacheLayer):
|
|
50
|
+
def __init__(self, storage: MutableMapping[str, Any] | None = ...) -> None: ...
|
|
51
|
+
|
|
52
|
+
class ShelveCacheLayer(CacheLayer):
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
path: str,
|
|
56
|
+
*,
|
|
57
|
+
flag: str = ...,
|
|
58
|
+
protocol: int | None = ...,
|
|
59
|
+
writeback: bool = ...,
|
|
60
|
+
) -> None: ...
|
|
61
|
+
|
|
62
|
+
class RedisCacheLayer(CacheLayer):
|
|
63
|
+
def __init__(self, client: Any | None = ..., *, namespace: str = ...) -> None: ...
|
|
64
|
+
|
|
65
|
+
class CacheManager:
|
|
66
|
+
_MISSING: ClassVar[object]
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
storage: MutableMapping[str, Any] | None = ...,
|
|
71
|
+
*,
|
|
72
|
+
default_capacity: int | None = ...,
|
|
73
|
+
overrides: Mapping[str, int | None] | None = ...,
|
|
74
|
+
layers: Iterable[CacheLayer] | None = ...,
|
|
75
|
+
) -> None: ...
|
|
76
|
+
@staticmethod
|
|
77
|
+
def _normalise_capacity(value: int | None) -> int | None: ...
|
|
78
|
+
def register(
|
|
79
|
+
self,
|
|
80
|
+
name: str,
|
|
81
|
+
factory: Callable[[], Any],
|
|
82
|
+
*,
|
|
83
|
+
lock_factory: Callable[[], threading.Lock | threading.RLock] | None = ...,
|
|
84
|
+
reset: Callable[[Any], Any] | None = ...,
|
|
85
|
+
create: bool = ...,
|
|
86
|
+
encoder: Callable[[Any], Any] | None = ...,
|
|
87
|
+
decoder: Callable[[Any], Any] | None = ...,
|
|
88
|
+
) -> None: ...
|
|
89
|
+
def configure(
|
|
90
|
+
self,
|
|
91
|
+
*,
|
|
92
|
+
default_capacity: int | None | object = ...,
|
|
93
|
+
overrides: Mapping[str, int | None] | None = ...,
|
|
94
|
+
replace_overrides: bool = ...,
|
|
95
|
+
) -> None: ...
|
|
96
|
+
def configure_from_mapping(self, config: Mapping[str, Any]) -> None: ...
|
|
97
|
+
def export_config(self) -> CacheCapacityConfig: ...
|
|
98
|
+
def get_capacity(
|
|
99
|
+
self,
|
|
100
|
+
name: str,
|
|
101
|
+
*,
|
|
102
|
+
requested: int | None = ...,
|
|
103
|
+
fallback: int | None = ...,
|
|
104
|
+
use_default: bool = ...,
|
|
105
|
+
) -> int | None: ...
|
|
106
|
+
def has_override(self, name: str) -> bool: ...
|
|
107
|
+
def get_lock(self, name: str) -> threading.Lock | threading.RLock: ...
|
|
108
|
+
def names(self) -> Iterator[str]: ...
|
|
109
|
+
def get(self, name: str, *, create: bool = ...) -> Any: ...
|
|
110
|
+
def peek(self, name: str) -> Any: ...
|
|
111
|
+
def store(self, name: str, value: Any) -> None: ...
|
|
112
|
+
def update(
|
|
113
|
+
self,
|
|
114
|
+
name: str,
|
|
115
|
+
updater: Callable[[Any], Any],
|
|
116
|
+
*,
|
|
117
|
+
create: bool = ...,
|
|
118
|
+
) -> Any: ...
|
|
119
|
+
def clear(self, name: str | None = ...) -> None: ...
|
|
120
|
+
def increment_hit(
|
|
121
|
+
self,
|
|
122
|
+
name: str,
|
|
123
|
+
*,
|
|
124
|
+
amount: int = ...,
|
|
125
|
+
duration: float | None = ...,
|
|
126
|
+
) -> None: ...
|
|
127
|
+
def increment_miss(
|
|
128
|
+
self,
|
|
129
|
+
name: str,
|
|
130
|
+
*,
|
|
131
|
+
amount: int = ...,
|
|
132
|
+
duration: float | None = ...,
|
|
133
|
+
) -> None: ...
|
|
134
|
+
def increment_eviction(self, name: str, *, amount: int = ...) -> None: ...
|
|
135
|
+
def record_timing(self, name: str, duration: float) -> None: ...
|
|
136
|
+
def timer(self, name: str) -> TimingContext: ...
|
|
137
|
+
def get_metrics(self, name: str) -> CacheStatistics: ...
|
|
138
|
+
def iter_metrics(self) -> Iterator[tuple[str, CacheStatistics]]: ...
|
|
139
|
+
def aggregate_metrics(self) -> CacheStatistics: ...
|
|
140
|
+
def register_metrics_publisher(
|
|
141
|
+
self, publisher: Callable[[str, CacheStatistics], None]
|
|
142
|
+
) -> None: ...
|
|
143
|
+
def publish_metrics(
|
|
144
|
+
self,
|
|
145
|
+
*,
|
|
146
|
+
publisher: Callable[[str, CacheStatistics], None] | None = ...,
|
|
147
|
+
) -> None: ...
|
|
148
|
+
def log_metrics(self, logger: logging.Logger, *, level: int = ...) -> None: ...
|
|
149
|
+
|
|
150
|
+
class InstrumentedLRUCache(MutableMapping[K, V], Generic[K, V]):
|
|
151
|
+
_MISSING: ClassVar[object]
|
|
152
|
+
|
|
153
|
+
def __init__(
|
|
154
|
+
self,
|
|
155
|
+
maxsize: int,
|
|
156
|
+
*,
|
|
157
|
+
manager: CacheManager | None = ...,
|
|
158
|
+
metrics_key: str | None = ...,
|
|
159
|
+
telemetry_callbacks: (
|
|
160
|
+
Iterable[Callable[[K, V], None]] | Callable[[K, V], None] | None
|
|
161
|
+
) = ...,
|
|
162
|
+
eviction_callbacks: (
|
|
163
|
+
Iterable[Callable[[K, V], None]] | Callable[[K, V], None] | None
|
|
164
|
+
) = ...,
|
|
165
|
+
locks: MutableMapping[K, Any] | None = ...,
|
|
166
|
+
getsizeof: Callable[[V], int] | None = ...,
|
|
167
|
+
count_overwrite_hit: bool = ...,
|
|
168
|
+
) -> None: ...
|
|
169
|
+
@property
|
|
170
|
+
def telemetry_callbacks(self) -> tuple[Callable[[K, V], None], ...]: ...
|
|
171
|
+
@property
|
|
172
|
+
def eviction_callbacks(self) -> tuple[Callable[[K, V], None], ...]: ...
|
|
173
|
+
def set_telemetry_callbacks(
|
|
174
|
+
self,
|
|
175
|
+
callbacks: Iterable[Callable[[K, V], None]] | Callable[[K, V], None] | None,
|
|
176
|
+
*,
|
|
177
|
+
append: bool = ...,
|
|
178
|
+
) -> None: ...
|
|
179
|
+
def set_eviction_callbacks(
|
|
180
|
+
self,
|
|
181
|
+
callbacks: Iterable[Callable[[K, V], None]] | Callable[[K, V], None] | None,
|
|
182
|
+
*,
|
|
183
|
+
append: bool = ...,
|
|
184
|
+
) -> None: ...
|
|
185
|
+
def pop(self, key: K, default: Any = ...) -> V: ...
|
|
186
|
+
def popitem(self) -> tuple[K, V]: ...
|
|
187
|
+
def clear(self) -> None: ...
|
|
188
|
+
@property
|
|
189
|
+
def maxsize(self) -> int: ...
|
|
190
|
+
@property
|
|
191
|
+
def currsize(self) -> int: ...
|
|
192
|
+
def get(self, key: K, default: V | None = ...) -> V | None: ...
|
|
193
|
+
|
|
194
|
+
class ManagedLRUCache(LRUCache[K, V], Generic[K, V]):
|
|
195
|
+
def __init__(
|
|
196
|
+
self,
|
|
197
|
+
maxsize: int,
|
|
198
|
+
*,
|
|
199
|
+
manager: CacheManager | None = ...,
|
|
200
|
+
metrics_key: str | None = ...,
|
|
201
|
+
eviction_callbacks: (
|
|
202
|
+
Iterable[Callable[[K, V], None]] | Callable[[K, V], None] | None
|
|
203
|
+
) = ...,
|
|
204
|
+
telemetry_callbacks: (
|
|
205
|
+
Iterable[Callable[[K, V], None]] | Callable[[K, V], None] | None
|
|
206
|
+
) = ...,
|
|
207
|
+
locks: MutableMapping[K, Any] | None = ...,
|
|
208
|
+
) -> None: ...
|
|
209
|
+
def popitem(self) -> tuple[K, V]: ...
|
|
210
|
+
|
|
211
|
+
def prune_lock_mapping(
|
|
212
|
+
cache: Mapping[K, Any] | MutableMapping[K, Any] | None,
|
|
213
|
+
locks: MutableMapping[K, Any] | None,
|
|
214
|
+
) -> None: ...
|
|
215
|
+
|
|
16
216
|
__all__ = (
|
|
217
|
+
"CacheLayer",
|
|
218
|
+
"CacheManager",
|
|
219
|
+
"CacheCapacityConfig",
|
|
220
|
+
"CacheStatistics",
|
|
221
|
+
"InstrumentedLRUCache",
|
|
222
|
+
"ManagedLRUCache",
|
|
223
|
+
"MappingCacheLayer",
|
|
224
|
+
"RedisCacheLayer",
|
|
225
|
+
"ShelveCacheLayer",
|
|
226
|
+
"prune_lock_mapping",
|
|
17
227
|
"EdgeCacheManager",
|
|
18
228
|
"NODE_SET_CHECKSUM_KEY",
|
|
19
229
|
"cached_node_list",
|
|
20
230
|
"cached_nodes_and_A",
|
|
21
231
|
"clear_node_repr_cache",
|
|
22
|
-
"configure_graph_cache_limits",
|
|
23
232
|
"edge_version_cache",
|
|
24
233
|
"edge_version_update",
|
|
25
234
|
"ensure_node_index_map",
|
|
@@ -29,81 +238,131 @@ __all__ = (
|
|
|
29
238
|
"increment_graph_version",
|
|
30
239
|
"node_set_checksum",
|
|
31
240
|
"stable_json",
|
|
241
|
+
"configure_graph_cache_limits",
|
|
242
|
+
"DNFR_PREP_STATE_KEY",
|
|
243
|
+
"DnfrCache",
|
|
244
|
+
"DnfrPrepState",
|
|
245
|
+
"new_dnfr_cache",
|
|
246
|
+
"build_cache_manager",
|
|
247
|
+
"configure_global_cache_layers",
|
|
248
|
+
"reset_global_cache_manager",
|
|
249
|
+
"_GRAPH_CACHE_LAYERS_KEY",
|
|
250
|
+
"_SeedHashCache",
|
|
251
|
+
"ScopedCounterCache",
|
|
32
252
|
)
|
|
33
253
|
|
|
34
|
-
NODE_SET_CHECKSUM_KEY: str
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class LRUCache(MutableMapping[K, V], Generic[K, V]):
|
|
38
|
-
def __init__(self, maxsize: int = ...) -> None: ...
|
|
39
254
|
|
|
40
|
-
|
|
255
|
+
NODE_SET_CHECKSUM_KEY: str
|
|
256
|
+
_GRAPH_CACHE_LAYERS_KEY: str
|
|
257
|
+
DNFR_PREP_STATE_KEY: str
|
|
258
|
+
|
|
259
|
+
class DnfrCache:
|
|
260
|
+
idx: dict[Any, int]
|
|
261
|
+
theta: list[float]
|
|
262
|
+
epi: list[float]
|
|
263
|
+
vf: list[float]
|
|
264
|
+
cos_theta: list[float]
|
|
265
|
+
sin_theta: list[float]
|
|
266
|
+
neighbor_x: list[float]
|
|
267
|
+
neighbor_y: list[float]
|
|
268
|
+
neighbor_epi_sum: list[float]
|
|
269
|
+
neighbor_vf_sum: list[float]
|
|
270
|
+
neighbor_count: list[float]
|
|
271
|
+
neighbor_deg_sum: list[float] | None
|
|
272
|
+
th_bar: list[float] | None
|
|
273
|
+
epi_bar: list[float] | None
|
|
274
|
+
vf_bar: list[float] | None
|
|
275
|
+
deg_bar: list[float] | None
|
|
276
|
+
degs: dict[Any, float] | None
|
|
277
|
+
deg_list: list[float] | None
|
|
278
|
+
theta_np: Any | None
|
|
279
|
+
epi_np: Any | None
|
|
280
|
+
vf_np: Any | None
|
|
281
|
+
cos_theta_np: Any | None
|
|
282
|
+
sin_theta_np: Any | None
|
|
283
|
+
deg_array: Any | None
|
|
284
|
+
edge_src: Any | None
|
|
285
|
+
edge_dst: Any | None
|
|
286
|
+
checksum: Any | None
|
|
287
|
+
neighbor_x_np: Any | None
|
|
288
|
+
neighbor_y_np: Any | None
|
|
289
|
+
neighbor_epi_sum_np: Any | None
|
|
290
|
+
neighbor_vf_sum_np: Any | None
|
|
291
|
+
neighbor_count_np: Any | None
|
|
292
|
+
neighbor_deg_sum_np: Any | None
|
|
293
|
+
th_bar_np: Any | None
|
|
294
|
+
epi_bar_np: Any | None
|
|
295
|
+
vf_bar_np: Any | None
|
|
296
|
+
deg_bar_np: Any | None
|
|
297
|
+
grad_phase_np: Any | None
|
|
298
|
+
grad_epi_np: Any | None
|
|
299
|
+
grad_vf_np: Any | None
|
|
300
|
+
grad_topo_np: Any | None
|
|
301
|
+
grad_total_np: Any | None
|
|
302
|
+
dense_components_np: Any | None
|
|
303
|
+
dense_accum_np: Any | None
|
|
304
|
+
dense_degree_np: Any | None
|
|
305
|
+
neighbor_accum_np: Any | None
|
|
306
|
+
neighbor_inv_count_np: Any | None
|
|
307
|
+
neighbor_cos_avg_np: Any | None
|
|
308
|
+
neighbor_sin_avg_np: Any | None
|
|
309
|
+
neighbor_mean_tmp_np: Any | None
|
|
310
|
+
neighbor_mean_length_np: Any | None
|
|
311
|
+
edge_signature: Any | None
|
|
312
|
+
neighbor_accum_signature: Any | None
|
|
313
|
+
neighbor_edge_values_np: Any | None
|
|
41
314
|
|
|
42
|
-
def __setitem__(self, __key: K, __value: V) -> None: ...
|
|
43
315
|
|
|
44
|
-
|
|
316
|
+
class EdgeCacheState:
|
|
317
|
+
cache: MutableMapping[Hashable, Any]
|
|
318
|
+
locks: defaultdict[Hashable, threading.RLock]
|
|
319
|
+
max_entries: int | None
|
|
320
|
+
dirty: bool
|
|
45
321
|
|
|
46
|
-
def __iter__(self) -> Iterator[K]: ...
|
|
47
322
|
|
|
48
|
-
|
|
323
|
+
def new_dnfr_cache() -> DnfrCache: ...
|
|
49
324
|
|
|
50
325
|
|
|
51
|
-
class
|
|
52
|
-
cache:
|
|
53
|
-
|
|
54
|
-
|
|
326
|
+
class DnfrPrepState:
|
|
327
|
+
cache: DnfrCache
|
|
328
|
+
cache_lock: threading.RLock
|
|
329
|
+
vector_lock: threading.RLock
|
|
55
330
|
|
|
56
331
|
|
|
57
332
|
class EdgeCacheManager:
|
|
58
333
|
_STATE_KEY: str
|
|
59
334
|
|
|
60
335
|
def __init__(self, graph: MutableMapping[str, Any]) -> None: ...
|
|
61
|
-
|
|
62
336
|
def record_hit(self) -> None: ...
|
|
63
|
-
|
|
64
337
|
def record_miss(self, *, track_metrics: bool = ...) -> None: ...
|
|
65
|
-
|
|
66
338
|
def record_eviction(self, *, track_metrics: bool = ...) -> None: ...
|
|
67
|
-
|
|
68
339
|
def timer(self) -> TimingContext: ...
|
|
69
|
-
|
|
70
340
|
def _default_state(self) -> EdgeCacheState: ...
|
|
71
|
-
|
|
72
341
|
def resolve_max_entries(self, max_entries: int | None | object) -> int | None: ...
|
|
73
|
-
|
|
74
342
|
def _build_state(self, max_entries: int | None) -> EdgeCacheState: ...
|
|
75
|
-
|
|
76
343
|
def _ensure_state(
|
|
77
344
|
self, state: EdgeCacheState | None, max_entries: int | None | object
|
|
78
345
|
) -> EdgeCacheState: ...
|
|
79
|
-
|
|
80
346
|
def _reset_state(self, state: EdgeCacheState | None) -> EdgeCacheState: ...
|
|
81
|
-
|
|
82
347
|
def get_cache(
|
|
83
348
|
self,
|
|
84
349
|
max_entries: int | None | object,
|
|
85
350
|
*,
|
|
86
351
|
create: bool = ...,
|
|
87
|
-
) ->
|
|
88
|
-
|
|
89
|
-
MutableMapping[Hashable, threading.RLock] | None,
|
|
90
|
-
]: ...
|
|
91
|
-
|
|
352
|
+
) -> EdgeCacheState | None: ...
|
|
353
|
+
def flush_state(self, state: EdgeCacheState) -> None: ...
|
|
92
354
|
def clear(self) -> None: ...
|
|
93
355
|
|
|
94
|
-
|
|
95
356
|
def get_graph_version(graph: Any, key: str, default: int = ...) -> int: ...
|
|
96
|
-
|
|
97
|
-
|
|
98
357
|
def increment_graph_version(graph: Any, key: str) -> int: ...
|
|
99
|
-
|
|
100
|
-
|
|
101
358
|
def stable_json(obj: Any) -> str: ...
|
|
102
|
-
|
|
103
|
-
|
|
104
359
|
def clear_node_repr_cache() -> None: ...
|
|
105
|
-
|
|
106
|
-
|
|
360
|
+
def configure_global_cache_layers(
|
|
361
|
+
*,
|
|
362
|
+
shelve: Mapping[str, Any] | None = ...,
|
|
363
|
+
redis: Mapping[str, Any] | None = ...,
|
|
364
|
+
replace: bool = ...,
|
|
365
|
+
) -> None: ...
|
|
107
366
|
def node_set_checksum(
|
|
108
367
|
G: nx.Graph,
|
|
109
368
|
nodes: Iterable[Any] | None = ...,
|
|
@@ -111,17 +370,17 @@ def node_set_checksum(
|
|
|
111
370
|
presorted: bool = ...,
|
|
112
371
|
store: bool = ...,
|
|
113
372
|
) -> str: ...
|
|
114
|
-
|
|
115
|
-
|
|
373
|
+
def reset_global_cache_manager() -> None: ...
|
|
374
|
+
def build_cache_manager(
|
|
375
|
+
*,
|
|
376
|
+
graph: MutableMapping[str, Any] | None = ...,
|
|
377
|
+
storage: MutableMapping[str, Any] | None = ...,
|
|
378
|
+
default_capacity: int | None = ...,
|
|
379
|
+
overrides: Mapping[str, int | None] | None = ...,
|
|
380
|
+
) -> CacheManager: ...
|
|
116
381
|
def cached_node_list(G: nx.Graph) -> tuple[Any, ...]: ...
|
|
117
|
-
|
|
118
|
-
|
|
119
382
|
def ensure_node_index_map(G: TNFRGraph) -> dict[NodeId, int]: ...
|
|
120
|
-
|
|
121
|
-
|
|
122
383
|
def ensure_node_offset_map(G: TNFRGraph) -> dict[NodeId, int]: ...
|
|
123
|
-
|
|
124
|
-
|
|
125
384
|
def configure_graph_cache_limits(
|
|
126
385
|
G: GraphLike | TNFRGraph | MutableMapping[str, Any],
|
|
127
386
|
*,
|
|
@@ -129,11 +388,7 @@ def configure_graph_cache_limits(
|
|
|
129
388
|
overrides: Mapping[str, int | None] | None = ...,
|
|
130
389
|
replace_overrides: bool = ...,
|
|
131
390
|
) -> CacheCapacityConfig: ...
|
|
132
|
-
|
|
133
|
-
|
|
134
391
|
def increment_edge_version(G: Any) -> None: ...
|
|
135
|
-
|
|
136
|
-
|
|
137
392
|
def edge_version_cache(
|
|
138
393
|
G: Any,
|
|
139
394
|
key: Hashable,
|
|
@@ -141,8 +396,6 @@ def edge_version_cache(
|
|
|
141
396
|
*,
|
|
142
397
|
max_entries: int | None | object = CacheManager._MISSING,
|
|
143
398
|
) -> T: ...
|
|
144
|
-
|
|
145
|
-
|
|
146
399
|
def cached_nodes_and_A(
|
|
147
400
|
G: nx.Graph,
|
|
148
401
|
*,
|
|
@@ -151,6 +404,65 @@ def cached_nodes_and_A(
|
|
|
151
404
|
prefer_sparse: bool = ...,
|
|
152
405
|
nodes: tuple[Any, ...] | None = ...,
|
|
153
406
|
) -> tuple[tuple[Any, ...], Any]: ...
|
|
407
|
+
def edge_version_update(G: TNFRGraph) -> ContextManager[None]: ...
|
|
154
408
|
|
|
155
409
|
|
|
156
|
-
|
|
410
|
+
class _SeedCacheState:
|
|
411
|
+
cache: InstrumentedLRUCache[tuple[int, int], int] | None
|
|
412
|
+
maxsize: int
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
class _CounterState(Generic[K]):
|
|
416
|
+
cache: InstrumentedLRUCache[K, int]
|
|
417
|
+
locks: dict[K, threading.RLock]
|
|
418
|
+
max_entries: int
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
class _SeedHashCache(MutableMapping[tuple[int, int], int]):
|
|
422
|
+
_state_key: str
|
|
423
|
+
|
|
424
|
+
def __init__(
|
|
425
|
+
self,
|
|
426
|
+
*,
|
|
427
|
+
manager: CacheManager | None = ...,
|
|
428
|
+
state_key: str = ...,
|
|
429
|
+
default_maxsize: int = ...,
|
|
430
|
+
) -> None: ...
|
|
431
|
+
def configure(self, maxsize: int) -> None: ...
|
|
432
|
+
def __getitem__(self, key: tuple[int, int]) -> int: ...
|
|
433
|
+
def __setitem__(self, key: tuple[int, int], value: int) -> None: ...
|
|
434
|
+
def __delitem__(self, key: tuple[int, int]) -> None: ...
|
|
435
|
+
def __iter__(self) -> Iterator[tuple[int, int]]: ...
|
|
436
|
+
def __len__(self) -> int: ...
|
|
437
|
+
def clear(self) -> None: ...
|
|
438
|
+
@property
|
|
439
|
+
def maxsize(self) -> int: ...
|
|
440
|
+
@property
|
|
441
|
+
def enabled(self) -> bool: ...
|
|
442
|
+
@property
|
|
443
|
+
def data(self) -> InstrumentedLRUCache[tuple[int, int], int] | None: ...
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
class ScopedCounterCache(Generic[K]):
|
|
447
|
+
_state_key: str
|
|
448
|
+
|
|
449
|
+
def __init__(
|
|
450
|
+
self,
|
|
451
|
+
name: str,
|
|
452
|
+
max_entries: int | None = ...,
|
|
453
|
+
*,
|
|
454
|
+
manager: CacheManager | None = ...,
|
|
455
|
+
default_max_entries: int = ...,
|
|
456
|
+
) -> None: ...
|
|
457
|
+
def configure(self, *, force: bool = ..., max_entries: int | None = ...) -> None: ...
|
|
458
|
+
def clear(self) -> None: ...
|
|
459
|
+
def bump(self, key: K) -> int: ...
|
|
460
|
+
def __len__(self) -> int: ...
|
|
461
|
+
@property
|
|
462
|
+
def lock(self) -> threading.Lock | threading.RLock: ...
|
|
463
|
+
@property
|
|
464
|
+
def max_entries(self) -> int: ...
|
|
465
|
+
@property
|
|
466
|
+
def cache(self) -> InstrumentedLRUCache[K, int]: ...
|
|
467
|
+
@property
|
|
468
|
+
def locks(self) -> dict[K, threading.RLock]: ...
|
tnfr/utils/chunks.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Chunk sizing heuristics for batching structural computations.
|
|
2
|
+
|
|
3
|
+
The helpers in this module determine how large each processing block should be
|
|
4
|
+
when splitting work across workers or vectorised loops. They take into account
|
|
5
|
+
the number of items involved, approximate memory pressure, and available CPU
|
|
6
|
+
parallelism so the caller can balance throughput with deterministic behaviour.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import math
|
|
12
|
+
import os
|
|
13
|
+
from typing import Final
|
|
14
|
+
|
|
15
|
+
DEFAULT_APPROX_BYTES_PER_ITEM: Final[int] = 64
|
|
16
|
+
DEFAULT_CHUNK_CLAMP: Final[int] | None = 131_072
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _estimate_available_memory() -> int | None:
|
|
20
|
+
"""Best-effort estimation of free memory available to the process."""
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
page_size = os.sysconf("SC_PAGE_SIZE")
|
|
24
|
+
avail_pages = os.sysconf("SC_AVPHYS_PAGES")
|
|
25
|
+
except (AttributeError, ValueError, OSError): # pragma: no cover - platform specific
|
|
26
|
+
return None
|
|
27
|
+
if page_size <= 0 or avail_pages <= 0:
|
|
28
|
+
return None
|
|
29
|
+
return int(page_size) * int(avail_pages)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def auto_chunk_size(
|
|
33
|
+
total_items: int,
|
|
34
|
+
*,
|
|
35
|
+
minimum: int = 1,
|
|
36
|
+
approx_bytes_per_item: int = DEFAULT_APPROX_BYTES_PER_ITEM,
|
|
37
|
+
clamp_to: int | None = DEFAULT_CHUNK_CLAMP,
|
|
38
|
+
) -> int:
|
|
39
|
+
"""Infer a safe chunk length when the caller does not specify one."""
|
|
40
|
+
|
|
41
|
+
if total_items <= 0:
|
|
42
|
+
return 0
|
|
43
|
+
|
|
44
|
+
minimum = max(1, minimum)
|
|
45
|
+
approx_bytes_per_item = max(1, approx_bytes_per_item)
|
|
46
|
+
|
|
47
|
+
available_memory = _estimate_available_memory()
|
|
48
|
+
if available_memory is not None and available_memory > 0:
|
|
49
|
+
safe_bytes = max(approx_bytes_per_item * minimum, available_memory // 8)
|
|
50
|
+
mem_bound = max(minimum, min(total_items, safe_bytes // approx_bytes_per_item))
|
|
51
|
+
else:
|
|
52
|
+
mem_bound = total_items
|
|
53
|
+
|
|
54
|
+
if clamp_to is not None:
|
|
55
|
+
mem_bound = min(mem_bound, clamp_to)
|
|
56
|
+
|
|
57
|
+
cpu_count = os.cpu_count() or 1
|
|
58
|
+
target_chunks = max(1, cpu_count * 4)
|
|
59
|
+
cpu_chunk = max(minimum, math.ceil(total_items / target_chunks))
|
|
60
|
+
baseline = max(minimum, min(total_items, 1024))
|
|
61
|
+
target = max(cpu_chunk, baseline)
|
|
62
|
+
|
|
63
|
+
chunk = min(mem_bound, target)
|
|
64
|
+
chunk = max(minimum, min(total_items, chunk))
|
|
65
|
+
return chunk
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def resolve_chunk_size(
|
|
69
|
+
chunk_size: int | None,
|
|
70
|
+
total_items: int,
|
|
71
|
+
*,
|
|
72
|
+
minimum: int = 1,
|
|
73
|
+
approx_bytes_per_item: int = DEFAULT_APPROX_BYTES_PER_ITEM,
|
|
74
|
+
clamp_to: int | None = DEFAULT_CHUNK_CLAMP,
|
|
75
|
+
) -> int:
|
|
76
|
+
"""Return a sanitised chunk size honouring automatic fallbacks."""
|
|
77
|
+
|
|
78
|
+
if total_items <= 0:
|
|
79
|
+
return 0
|
|
80
|
+
|
|
81
|
+
resolved: int | None
|
|
82
|
+
if chunk_size is None:
|
|
83
|
+
resolved = None
|
|
84
|
+
else:
|
|
85
|
+
try:
|
|
86
|
+
resolved = int(chunk_size)
|
|
87
|
+
except (TypeError, ValueError):
|
|
88
|
+
resolved = None
|
|
89
|
+
else:
|
|
90
|
+
if resolved <= 0:
|
|
91
|
+
resolved = None
|
|
92
|
+
|
|
93
|
+
if resolved is None:
|
|
94
|
+
resolved = auto_chunk_size(
|
|
95
|
+
total_items,
|
|
96
|
+
minimum=minimum,
|
|
97
|
+
approx_bytes_per_item=approx_bytes_per_item,
|
|
98
|
+
clamp_to=clamp_to,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
return max(minimum, min(total_items, resolved))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
__all__ = ["auto_chunk_size", "resolve_chunk_size"]
|
tnfr/utils/chunks.pyi
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Final
|
|
2
|
+
|
|
3
|
+
DEFAULT_APPROX_BYTES_PER_ITEM: Final[int]
|
|
4
|
+
DEFAULT_CHUNK_CLAMP: Final[int | None]
|
|
5
|
+
|
|
6
|
+
def auto_chunk_size(
|
|
7
|
+
total_items: int,
|
|
8
|
+
*,
|
|
9
|
+
minimum: int = ...,
|
|
10
|
+
approx_bytes_per_item: int = ...,
|
|
11
|
+
clamp_to: int | None = ...,
|
|
12
|
+
) -> int: ...
|
|
13
|
+
|
|
14
|
+
def resolve_chunk_size(
|
|
15
|
+
chunk_size: int | None,
|
|
16
|
+
total_items: int,
|
|
17
|
+
*,
|
|
18
|
+
minimum: int = ...,
|
|
19
|
+
approx_bytes_per_item: int = ...,
|
|
20
|
+
clamp_to: int | None = ...,
|
|
21
|
+
) -> int: ...
|