tnfr 4.5.2__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.

Files changed (195) hide show
  1. tnfr/__init__.py +275 -51
  2. tnfr/__init__.pyi +33 -0
  3. tnfr/_compat.py +10 -0
  4. tnfr/_generated_version.py +34 -0
  5. tnfr/_version.py +49 -0
  6. tnfr/_version.pyi +7 -0
  7. tnfr/alias.py +117 -31
  8. tnfr/alias.pyi +108 -0
  9. tnfr/cache.py +6 -572
  10. tnfr/cache.pyi +16 -0
  11. tnfr/callback_utils.py +16 -38
  12. tnfr/callback_utils.pyi +79 -0
  13. tnfr/cli/__init__.py +34 -14
  14. tnfr/cli/__init__.pyi +26 -0
  15. tnfr/cli/arguments.py +211 -28
  16. tnfr/cli/arguments.pyi +27 -0
  17. tnfr/cli/execution.py +470 -50
  18. tnfr/cli/execution.pyi +70 -0
  19. tnfr/cli/utils.py +18 -3
  20. tnfr/cli/utils.pyi +8 -0
  21. tnfr/config/__init__.py +13 -0
  22. tnfr/config/__init__.pyi +10 -0
  23. tnfr/{constants_glyphs.py → config/constants.py} +26 -20
  24. tnfr/config/constants.pyi +12 -0
  25. tnfr/config/feature_flags.py +83 -0
  26. tnfr/{config.py → config/init.py} +11 -7
  27. tnfr/config/init.pyi +8 -0
  28. tnfr/config/operator_names.py +93 -0
  29. tnfr/config/operator_names.pyi +28 -0
  30. tnfr/config/presets.py +84 -0
  31. tnfr/config/presets.pyi +7 -0
  32. tnfr/constants/__init__.py +80 -29
  33. tnfr/constants/__init__.pyi +92 -0
  34. tnfr/constants/aliases.py +31 -0
  35. tnfr/constants/core.py +4 -4
  36. tnfr/constants/core.pyi +17 -0
  37. tnfr/constants/init.py +1 -1
  38. tnfr/constants/init.pyi +12 -0
  39. tnfr/constants/metric.py +7 -15
  40. tnfr/constants/metric.pyi +19 -0
  41. tnfr/dynamics/__init__.py +165 -633
  42. tnfr/dynamics/__init__.pyi +82 -0
  43. tnfr/dynamics/adaptation.py +267 -0
  44. tnfr/dynamics/aliases.py +23 -0
  45. tnfr/dynamics/coordination.py +385 -0
  46. tnfr/dynamics/dnfr.py +2283 -400
  47. tnfr/dynamics/dnfr.pyi +24 -0
  48. tnfr/dynamics/integrators.py +406 -98
  49. tnfr/dynamics/integrators.pyi +34 -0
  50. tnfr/dynamics/runtime.py +881 -0
  51. tnfr/dynamics/sampling.py +10 -5
  52. tnfr/dynamics/sampling.pyi +7 -0
  53. tnfr/dynamics/selectors.py +719 -0
  54. tnfr/execution.py +70 -48
  55. tnfr/execution.pyi +45 -0
  56. tnfr/flatten.py +13 -9
  57. tnfr/flatten.pyi +21 -0
  58. tnfr/gamma.py +66 -53
  59. tnfr/gamma.pyi +34 -0
  60. tnfr/glyph_history.py +110 -52
  61. tnfr/glyph_history.pyi +35 -0
  62. tnfr/glyph_runtime.py +16 -0
  63. tnfr/glyph_runtime.pyi +9 -0
  64. tnfr/immutable.py +69 -28
  65. tnfr/immutable.pyi +34 -0
  66. tnfr/initialization.py +16 -16
  67. tnfr/initialization.pyi +65 -0
  68. tnfr/io.py +6 -240
  69. tnfr/io.pyi +16 -0
  70. tnfr/locking.pyi +7 -0
  71. tnfr/mathematics/__init__.py +81 -0
  72. tnfr/mathematics/backend.py +426 -0
  73. tnfr/mathematics/dynamics.py +398 -0
  74. tnfr/mathematics/epi.py +254 -0
  75. tnfr/mathematics/generators.py +222 -0
  76. tnfr/mathematics/metrics.py +119 -0
  77. tnfr/mathematics/operators.py +233 -0
  78. tnfr/mathematics/operators_factory.py +71 -0
  79. tnfr/mathematics/projection.py +78 -0
  80. tnfr/mathematics/runtime.py +173 -0
  81. tnfr/mathematics/spaces.py +247 -0
  82. tnfr/mathematics/transforms.py +292 -0
  83. tnfr/metrics/__init__.py +10 -10
  84. tnfr/metrics/__init__.pyi +20 -0
  85. tnfr/metrics/coherence.py +993 -324
  86. tnfr/metrics/common.py +23 -16
  87. tnfr/metrics/common.pyi +46 -0
  88. tnfr/metrics/core.py +251 -35
  89. tnfr/metrics/core.pyi +13 -0
  90. tnfr/metrics/diagnosis.py +708 -111
  91. tnfr/metrics/diagnosis.pyi +85 -0
  92. tnfr/metrics/export.py +27 -15
  93. tnfr/metrics/glyph_timing.py +232 -42
  94. tnfr/metrics/reporting.py +33 -22
  95. tnfr/metrics/reporting.pyi +12 -0
  96. tnfr/metrics/sense_index.py +987 -43
  97. tnfr/metrics/sense_index.pyi +9 -0
  98. tnfr/metrics/trig.py +214 -23
  99. tnfr/metrics/trig.pyi +13 -0
  100. tnfr/metrics/trig_cache.py +115 -22
  101. tnfr/metrics/trig_cache.pyi +10 -0
  102. tnfr/node.py +542 -136
  103. tnfr/node.pyi +178 -0
  104. tnfr/observers.py +152 -35
  105. tnfr/observers.pyi +31 -0
  106. tnfr/ontosim.py +23 -19
  107. tnfr/ontosim.pyi +28 -0
  108. tnfr/operators/__init__.py +601 -82
  109. tnfr/operators/__init__.pyi +45 -0
  110. tnfr/operators/definitions.py +513 -0
  111. tnfr/operators/definitions.pyi +78 -0
  112. tnfr/operators/grammar.py +760 -0
  113. tnfr/operators/jitter.py +107 -38
  114. tnfr/operators/jitter.pyi +11 -0
  115. tnfr/operators/registry.py +75 -0
  116. tnfr/operators/registry.pyi +13 -0
  117. tnfr/operators/remesh.py +149 -88
  118. tnfr/py.typed +0 -0
  119. tnfr/rng.py +46 -143
  120. tnfr/rng.pyi +14 -0
  121. tnfr/schemas/__init__.py +8 -0
  122. tnfr/schemas/grammar.json +94 -0
  123. tnfr/selector.py +25 -19
  124. tnfr/selector.pyi +19 -0
  125. tnfr/sense.py +72 -62
  126. tnfr/sense.pyi +23 -0
  127. tnfr/structural.py +522 -262
  128. tnfr/structural.pyi +69 -0
  129. tnfr/telemetry/__init__.py +35 -0
  130. tnfr/telemetry/cache_metrics.py +226 -0
  131. tnfr/telemetry/nu_f.py +423 -0
  132. tnfr/telemetry/nu_f.pyi +123 -0
  133. tnfr/telemetry/verbosity.py +37 -0
  134. tnfr/tokens.py +1 -3
  135. tnfr/tokens.pyi +36 -0
  136. tnfr/trace.py +270 -113
  137. tnfr/trace.pyi +40 -0
  138. tnfr/types.py +574 -6
  139. tnfr/types.pyi +331 -0
  140. tnfr/units.py +69 -0
  141. tnfr/units.pyi +16 -0
  142. tnfr/utils/__init__.py +217 -0
  143. tnfr/utils/__init__.pyi +202 -0
  144. tnfr/utils/cache.py +2395 -0
  145. tnfr/utils/cache.pyi +468 -0
  146. tnfr/utils/chunks.py +104 -0
  147. tnfr/utils/chunks.pyi +21 -0
  148. tnfr/{collections_utils.py → utils/data.py} +147 -90
  149. tnfr/utils/data.pyi +64 -0
  150. tnfr/utils/graph.py +85 -0
  151. tnfr/utils/graph.pyi +10 -0
  152. tnfr/utils/init.py +770 -0
  153. tnfr/utils/init.pyi +78 -0
  154. tnfr/utils/io.py +456 -0
  155. tnfr/{helpers → utils}/numeric.py +51 -24
  156. tnfr/utils/numeric.pyi +21 -0
  157. tnfr/validation/__init__.py +113 -0
  158. tnfr/validation/__init__.pyi +77 -0
  159. tnfr/validation/compatibility.py +95 -0
  160. tnfr/validation/compatibility.pyi +6 -0
  161. tnfr/validation/grammar.py +71 -0
  162. tnfr/validation/grammar.pyi +40 -0
  163. tnfr/validation/graph.py +138 -0
  164. tnfr/validation/graph.pyi +17 -0
  165. tnfr/validation/rules.py +281 -0
  166. tnfr/validation/rules.pyi +55 -0
  167. tnfr/validation/runtime.py +263 -0
  168. tnfr/validation/runtime.pyi +31 -0
  169. tnfr/validation/soft_filters.py +170 -0
  170. tnfr/validation/soft_filters.pyi +37 -0
  171. tnfr/validation/spectral.py +159 -0
  172. tnfr/validation/spectral.pyi +46 -0
  173. tnfr/validation/syntax.py +40 -0
  174. tnfr/validation/syntax.pyi +10 -0
  175. tnfr/validation/window.py +39 -0
  176. tnfr/validation/window.pyi +1 -0
  177. tnfr/viz/__init__.py +9 -0
  178. tnfr/viz/matplotlib.py +246 -0
  179. tnfr-7.0.0.dist-info/METADATA +179 -0
  180. tnfr-7.0.0.dist-info/RECORD +185 -0
  181. {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/licenses/LICENSE.md +1 -1
  182. tnfr/grammar.py +0 -344
  183. tnfr/graph_utils.py +0 -84
  184. tnfr/helpers/__init__.py +0 -71
  185. tnfr/import_utils.py +0 -228
  186. tnfr/json_utils.py +0 -162
  187. tnfr/logging_utils.py +0 -116
  188. tnfr/presets.py +0 -60
  189. tnfr/validators.py +0 -84
  190. tnfr/value_utils.py +0 -59
  191. tnfr-4.5.2.dist-info/METADATA +0 -379
  192. tnfr-4.5.2.dist-info/RECORD +0 -67
  193. {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/WHEEL +0 -0
  194. {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/entry_points.txt +0 -0
  195. {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/top_level.txt +0 -0
tnfr/types.pyi ADDED
@@ -0,0 +1,331 @@
1
+ from collections.abc import (
2
+ Hashable,
3
+ Mapping,
4
+ MutableMapping,
5
+ MutableSequence,
6
+ Sequence,
7
+ )
8
+ from enum import Enum
9
+ from typing import Any, Callable, ContextManager, Iterable, Protocol, TypedDict, cast
10
+
11
+ from ._compat import TypeAlias
12
+
13
+ try:
14
+ import networkx as nx # type: ignore[import-not-found]
15
+ except Exception:
16
+ class _FallbackGraph: ...
17
+
18
+ class _FallbackNetworkX:
19
+ Graph = _FallbackGraph
20
+
21
+ nx = cast(Any, _FallbackNetworkX())
22
+
23
+ try:
24
+ import numpy as np # type: ignore[import-not-found]
25
+ except Exception:
26
+ class _FallbackNdArray: ...
27
+
28
+ class _FallbackNumpy:
29
+ ndarray = _FallbackNdArray
30
+
31
+ np = cast(Any, _FallbackNumpy())
32
+
33
+ from .glyph_history import HistoryDict as _HistoryDict
34
+ from .tokens import Token
35
+ __all__: tuple[str, ...] = (
36
+ "TNFRGraph",
37
+ "Graph",
38
+ "ValidatorFunc",
39
+ "NodeId",
40
+ "Node",
41
+ "GammaSpec",
42
+ "EPIValue",
43
+ "BEPIProtocol",
44
+ "ensure_bepi",
45
+ "serialize_bepi",
46
+ "ZERO_BEPI_STORAGE",
47
+ "DeltaNFR",
48
+ "SecondDerivativeEPI",
49
+ "Phase",
50
+ "StructuralFrequency",
51
+ "SenseIndex",
52
+ "CouplingWeight",
53
+ "CoherenceMetric",
54
+ "DeltaNFRHook",
55
+ "GraphLike",
56
+ "IntegratorProtocol",
57
+ "Glyph",
58
+ "GlyphCode",
59
+ "GlyphLoadDistribution",
60
+ "GlyphSelector",
61
+ "SelectorPreselectionMetrics",
62
+ "SelectorPreselectionChoices",
63
+ "SelectorPreselectionPayload",
64
+ "SelectorMetrics",
65
+ "SelectorNorms",
66
+ "SelectorThresholds",
67
+ "SelectorWeights",
68
+ "TraceCallback",
69
+ "CallbackError",
70
+ "TraceFieldFn",
71
+ "TraceFieldMap",
72
+ "TraceFieldRegistry",
73
+ "TraceMetadata",
74
+ "TraceSnapshot",
75
+ "HistoryState",
76
+ "DiagnosisNodeData",
77
+ "DiagnosisSharedState",
78
+ "DiagnosisPayload",
79
+ "DiagnosisResult",
80
+ "DiagnosisPayloadChunk",
81
+ "DiagnosisResultList",
82
+ "DnfrCacheVectors",
83
+ "DnfrVectorMap",
84
+ "NeighborStats",
85
+ "TimingContext",
86
+ "PresetTokens",
87
+ "ProgramTokens",
88
+ "ArgSpec",
89
+ "TNFRConfigValue",
90
+ "SigmaVector",
91
+ "SigmaTrace",
92
+ "FloatArray",
93
+ "FloatMatrix",
94
+ "NodeInitAttrMap",
95
+ "NodeAttrMap",
96
+ "GlyphogramRow",
97
+ "GlyphTimingTotals",
98
+ "GlyphTimingByNode",
99
+ "GlyphCounts",
100
+ "GlyphMetricsHistoryValue",
101
+ "GlyphMetricsHistory",
102
+ "MetricsListHistory",
103
+ "ParallelWijPayload",
104
+ "RemeshMeta",
105
+ )
106
+
107
+ def __getattr__(name: str) -> Any: ...
108
+
109
+ TNFRGraph: TypeAlias = nx.Graph
110
+ Graph: TypeAlias = TNFRGraph
111
+ ValidatorFunc: TypeAlias = Callable[[TNFRGraph], None]
112
+ NodeId: TypeAlias = Hashable
113
+ Node: TypeAlias = NodeId
114
+ NodeInitAttrMap: TypeAlias = MutableMapping[str, float]
115
+ NodeAttrMap: TypeAlias = Mapping[str, Any]
116
+ GammaSpec: TypeAlias = Mapping[str, Any]
117
+ class BEPIProtocol(Protocol): ...
118
+
119
+ EPIValue: TypeAlias = BEPIProtocol
120
+ ZERO_BEPI_STORAGE: dict[str, tuple[complex, ...] | tuple[float, ...]]
121
+ def ensure_bepi(value: Any) -> "BEPIElement": ...
122
+ def serialize_bepi(value: Any) -> dict[str, tuple[complex, ...] | tuple[float, ...]]: ...
123
+ DeltaNFR: TypeAlias = float
124
+ SecondDerivativeEPI: TypeAlias = float
125
+ Phase: TypeAlias = float
126
+ StructuralFrequency: TypeAlias = float
127
+ SenseIndex: TypeAlias = float
128
+ CouplingWeight: TypeAlias = float
129
+ CoherenceMetric: TypeAlias = float
130
+ TimingContext: TypeAlias = ContextManager[None]
131
+ PresetTokens: TypeAlias = Sequence[Token]
132
+ ProgramTokens: TypeAlias = Sequence[Token]
133
+ ArgSpec: TypeAlias = tuple[str, Mapping[str, Any]]
134
+
135
+ TNFRConfigScalar: TypeAlias = bool | int | float | str | None
136
+ TNFRConfigSequence: TypeAlias = Sequence[TNFRConfigScalar]
137
+ TNFRConfigValue: TypeAlias = (
138
+ TNFRConfigScalar | TNFRConfigSequence | Mapping[str, "TNFRConfigValue"]
139
+ )
140
+
141
+ class _SigmaVectorRequired(TypedDict):
142
+ x: float
143
+ y: float
144
+ mag: float
145
+ angle: float
146
+ n: int
147
+
148
+
149
+ class _SigmaVectorOptional(TypedDict, total=False):
150
+ glyph: str
151
+ w: float
152
+ t: float
153
+
154
+
155
+ class SigmaVector(_SigmaVectorRequired, _SigmaVectorOptional): ...
156
+
157
+
158
+ class SigmaTrace(TypedDict):
159
+ t: list[float]
160
+ sigma_x: list[float]
161
+ sigma_y: list[float]
162
+ mag: list[float]
163
+ angle: list[float]
164
+
165
+
166
+ FloatArray: TypeAlias = np.ndarray
167
+ FloatMatrix: TypeAlias = np.ndarray
168
+
169
+ class SelectorThresholds(TypedDict):
170
+ si_hi: float
171
+ si_lo: float
172
+ dnfr_hi: float
173
+ dnfr_lo: float
174
+ accel_hi: float
175
+ accel_lo: float
176
+
177
+ class SelectorWeights(TypedDict):
178
+ w_si: float
179
+ w_dnfr: float
180
+ w_accel: float
181
+
182
+ SelectorMetrics: TypeAlias = tuple[float, float, float]
183
+ SelectorNorms: TypeAlias = Mapping[str, float]
184
+
185
+ class _DeltaNFRHookProtocol(Protocol):
186
+ def __call__(self, graph: TNFRGraph, /, *args: Any, **kwargs: Any) -> None: ...
187
+
188
+ DeltaNFRHook: TypeAlias = _DeltaNFRHookProtocol
189
+
190
+ class GraphLike(Protocol):
191
+ graph: dict[str, Any]
192
+
193
+ def nodes(self, data: bool = ...) -> Iterable[Any]: ...
194
+ def number_of_nodes(self) -> int: ...
195
+ def neighbors(self, n: Any) -> Iterable[Any]: ...
196
+ def __iter__(self) -> Iterable[Any]: ...
197
+
198
+ class IntegratorProtocol(Protocol):
199
+ def integrate(
200
+ self,
201
+ graph: TNFRGraph,
202
+ *,
203
+ dt: float | None = ...,
204
+ t: float | None = ...,
205
+ method: str | None = ...,
206
+ n_jobs: int | None = ...,
207
+ ) -> None: ...
208
+
209
+ class Glyph(str, Enum):
210
+ AL = "AL"
211
+ EN = "EN"
212
+ IL = "IL"
213
+ OZ = "OZ"
214
+ UM = "UM"
215
+ RA = "RA"
216
+ SHA = "SHA"
217
+ VAL = "VAL"
218
+ NUL = "NUL"
219
+ THOL = "THOL"
220
+ ZHIR = "ZHIR"
221
+ NAV = "NAV"
222
+ REMESH = "REMESH"
223
+
224
+ GlyphCode: TypeAlias = Glyph | str
225
+ GlyphLoadDistribution: TypeAlias = dict[Glyph | str, float]
226
+
227
+
228
+ class _SelectorLifecycle(Protocol):
229
+ def __call__(self, graph: TNFRGraph, node: NodeId) -> GlyphCode: ...
230
+ def prepare(self, graph: TNFRGraph, nodes: Sequence[NodeId]) -> None: ...
231
+ def select(self, graph: TNFRGraph, node: NodeId) -> GlyphCode: ...
232
+
233
+
234
+ GlyphSelector: TypeAlias = Callable[[TNFRGraph, NodeId], GlyphCode] | _SelectorLifecycle
235
+ SelectorPreselectionMetrics: TypeAlias = Mapping[Any, SelectorMetrics]
236
+ SelectorPreselectionChoices: TypeAlias = Mapping[Any, Glyph | str]
237
+ SelectorPreselectionPayload: TypeAlias = tuple[
238
+ SelectorPreselectionMetrics,
239
+ SelectorPreselectionChoices,
240
+ ]
241
+ TraceFieldFn: TypeAlias = Callable[[TNFRGraph], "TraceMetadata"]
242
+ TraceFieldMap: TypeAlias = Mapping[str, "TraceFieldFn"]
243
+ TraceFieldRegistry: TypeAlias = dict[str, dict[str, "TraceFieldFn"]]
244
+
245
+ class TraceMetadata(TypedDict, total=False):
246
+ gamma: Mapping[str, Any]
247
+ grammar: Mapping[str, Any]
248
+ selector: str | None
249
+ dnfr_weights: Mapping[str, Any]
250
+ si_weights: Mapping[str, Any]
251
+ si_sensitivity: Mapping[str, Any]
252
+ callbacks: Mapping[str, list[str] | None]
253
+ thol_open_nodes: int
254
+ kuramoto: Mapping[str, float]
255
+ sigma: Mapping[str, float]
256
+ glyphs: Mapping[str, int]
257
+
258
+ class TraceSnapshot(TraceMetadata, total=False):
259
+ t: float
260
+ phase: str
261
+ HistoryState: TypeAlias = _HistoryDict | dict[str, Any]
262
+ TraceCallback: TypeAlias = Callable[[TNFRGraph, dict[str, Any]], None]
263
+
264
+
265
+ class CallbackError(TypedDict):
266
+ event: str
267
+ step: int | None
268
+ error: str
269
+ traceback: str
270
+ fn: str
271
+ name: str | None
272
+
273
+
274
+ DiagnosisNodeData: TypeAlias = Mapping[str, Any]
275
+ DiagnosisSharedState: TypeAlias = Mapping[str, Any]
276
+ DiagnosisPayload: TypeAlias = dict[str, Any]
277
+ DiagnosisResult: TypeAlias = tuple[NodeId, DiagnosisPayload]
278
+ DiagnosisPayloadChunk: TypeAlias = list[DiagnosisNodeData]
279
+ DiagnosisResultList: TypeAlias = list[DiagnosisResult]
280
+ DnfrCacheVectors: TypeAlias = tuple[
281
+ np.ndarray | None,
282
+ np.ndarray | None,
283
+ np.ndarray | None,
284
+ np.ndarray | None,
285
+ np.ndarray | None,
286
+ ]
287
+ DnfrVectorMap: TypeAlias = dict[str, np.ndarray | None]
288
+ NeighborStats: TypeAlias = tuple[
289
+ Sequence[float],
290
+ Sequence[float],
291
+ Sequence[float],
292
+ Sequence[float],
293
+ Sequence[float] | None,
294
+ Sequence[float] | None,
295
+ Sequence[float] | None,
296
+ ]
297
+
298
+ GlyphogramRow: TypeAlias = MutableMapping[str, float]
299
+ GlyphTimingTotals: TypeAlias = MutableMapping[str, float]
300
+ GlyphTimingByNode: TypeAlias = MutableMapping[
301
+ Any, MutableMapping[str, MutableSequence[float]]
302
+ ]
303
+ GlyphCounts: TypeAlias = Mapping[str, int]
304
+ GlyphMetricsHistoryValue: TypeAlias = MutableMapping[Any, Any] | MutableSequence[Any]
305
+ GlyphMetricsHistory: TypeAlias = MutableMapping[str, GlyphMetricsHistoryValue]
306
+ MetricsListHistory: TypeAlias = MutableMapping[str, list[Any]]
307
+
308
+ class RemeshMeta(TypedDict, total=False):
309
+ alpha: float
310
+ alpha_source: str
311
+ tau_global: int
312
+ tau_local: int
313
+ step: int | None
314
+ topo_hash: str | None
315
+ epi_mean_before: float
316
+ epi_mean_after: float
317
+ epi_checksum_before: str
318
+ epi_checksum_after: str
319
+ stable_frac_last: float
320
+ phase_sync_last: float
321
+ glyph_disr_last: float
322
+
323
+ class ParallelWijPayload(TypedDict):
324
+ epi_vals: Sequence[float]
325
+ vf_vals: Sequence[float]
326
+ si_vals: Sequence[float]
327
+ cos_vals: Sequence[float]
328
+ sin_vals: Sequence[float]
329
+ weights: tuple[float, float, float, float]
330
+ epi_range: float
331
+ vf_range: float
tnfr/units.py ADDED
@@ -0,0 +1,69 @@
1
+ """Structural unit conversion helpers.
2
+
3
+ The TNFR engine tracks structural dynamics using the ``Hz_str`` unit. A
4
+ single configurable scale factor ``k`` bridges this canonical structural
5
+ frequency with the conventional ``Hz`` base unit. The factor is resolved
6
+ according to the following invariants:
7
+
8
+ * ``k`` is always read from the graph configuration via :func:`get_param` so
9
+ per-graph overrides take precedence over the package defaults.
10
+ * The fallback value comes from :data:`tnfr.constants.DEFAULTS`, ensuring the
11
+ canonical 1 Hz_str↔Hz relationship is preserved when callers do not provide
12
+ explicit overrides.
13
+ * ``k`` must remain strictly positive. Invalid overrides raise
14
+ :class:`ValueError` to prevent incoherent conversions.
15
+
16
+ All helpers defined here operate purely on ``GraphLike`` instances and only
17
+ depend on :mod:`tnfr.constants` for configuration access, keeping the
18
+ conversion logic transparent and side-effect free.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from typing import Final
24
+
25
+ from .constants import get_param
26
+ from .types import GraphLike
27
+
28
+ __all__ = ("get_hz_bridge", "hz_str_to_hz", "hz_to_hz_str")
29
+
30
+ HZ_STR_BRIDGE_KEY: Final[str] = "HZ_STR_BRIDGE"
31
+
32
+
33
+ def _coerce_bridge_factor(raw: object) -> float:
34
+ """Return ``raw`` coerced to a strictly positive floating point factor."""
35
+
36
+ try:
37
+ factor = float(raw)
38
+ except (TypeError, ValueError) as exc: # pragma: no cover - defensive guard
39
+ raise TypeError(
40
+ "HZ_STR_BRIDGE must be a real number convertible to float"
41
+ ) from exc
42
+
43
+ if factor <= 0.0:
44
+ raise ValueError("HZ_STR_BRIDGE must be strictly positive")
45
+
46
+ return factor
47
+
48
+
49
+ def get_hz_bridge(G: GraphLike) -> float:
50
+ """Return the ``Hz_str``→``Hz`` bridge factor for ``G``.
51
+
52
+ The helper always consults ``G.graph`` via :func:`get_param` so per-graph
53
+ overrides remain authoritative.
54
+ """
55
+
56
+ return _coerce_bridge_factor(get_param(G, HZ_STR_BRIDGE_KEY))
57
+
58
+
59
+ def hz_str_to_hz(value: float, G: GraphLike) -> float:
60
+ """Convert ``value`` expressed in ``Hz_str`` into ``Hz`` using ``G``."""
61
+
62
+ return float(value) * get_hz_bridge(G)
63
+
64
+
65
+ def hz_to_hz_str(value: float, G: GraphLike) -> float:
66
+ """Convert ``value`` expressed in ``Hz`` into ``Hz_str`` using ``G``."""
67
+
68
+ return float(value) / get_hz_bridge(G)
69
+
tnfr/units.pyi ADDED
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Final
4
+
5
+ from .types import GraphLike
6
+
7
+ __all__ = ("get_hz_bridge", "hz_str_to_hz", "hz_to_hz_str")
8
+
9
+ HZ_STR_BRIDGE_KEY: Final[str]
10
+
11
+ def get_hz_bridge(G: GraphLike) -> float: ...
12
+
13
+ def hz_str_to_hz(value: float, G: GraphLike) -> float: ...
14
+
15
+ def hz_to_hz_str(value: float, G: GraphLike) -> float: ...
16
+
tnfr/utils/__init__.py ADDED
@@ -0,0 +1,217 @@
1
+ """Shared utility helpers exposed under :mod:`tnfr.utils`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Final
6
+
7
+ from . import init as _init
8
+ from ..locking import get_lock
9
+
10
+ WarnOnce = _init.WarnOnce
11
+ cached_import = _init.cached_import
12
+ warm_cached_import = _init.warm_cached_import
13
+ LazyImportProxy = _init.LazyImportProxy
14
+ get_logger = _init.get_logger
15
+ get_nodenx = _init.get_nodenx
16
+ get_numpy = _init.get_numpy
17
+ prune_failed_imports = _init.prune_failed_imports
18
+ warn_once = _init.warn_once
19
+ _configure_root = _init._configure_root
20
+ _reset_logging_state = _init._reset_logging_state
21
+ _reset_import_state = _init._reset_import_state
22
+ _warn_failure = _init._warn_failure
23
+ _FAILED_IMPORT_LIMIT = _init._FAILED_IMPORT_LIMIT
24
+ _DEFAULT_CACHE_SIZE = _init._DEFAULT_CACHE_SIZE
25
+ EMIT_MAP = _init.EMIT_MAP
26
+
27
+ from .cache import (
28
+ CacheCapacityConfig,
29
+ CacheLayer,
30
+ CacheManager,
31
+ CacheStatistics,
32
+ InstrumentedLRUCache,
33
+ ManagedLRUCache,
34
+ MappingCacheLayer,
35
+ RedisCacheLayer,
36
+ ShelveCacheLayer,
37
+ prune_lock_mapping,
38
+ DNFR_PREP_STATE_KEY,
39
+ DnfrPrepState,
40
+ DnfrCache,
41
+ NODE_SET_CHECKSUM_KEY,
42
+ ScopedCounterCache,
43
+ EdgeCacheManager,
44
+ cached_node_list,
45
+ cached_nodes_and_A,
46
+ clear_node_repr_cache,
47
+ configure_graph_cache_limits,
48
+ configure_global_cache_layers,
49
+ edge_version_cache,
50
+ edge_version_update,
51
+ ensure_node_index_map,
52
+ ensure_node_offset_map,
53
+ new_dnfr_cache,
54
+ _SeedHashCache,
55
+ _GRAPH_CACHE_MANAGER_KEY,
56
+ _graph_cache_manager,
57
+ build_cache_manager,
58
+ get_graph_version,
59
+ increment_edge_version,
60
+ increment_graph_version,
61
+ node_set_checksum,
62
+ reset_global_cache_manager,
63
+ stable_json,
64
+ _GRAPH_CACHE_LAYERS_KEY,
65
+ )
66
+ from .data import (
67
+ MAX_MATERIALIZE_DEFAULT,
68
+ STRING_TYPES,
69
+ convert_value,
70
+ normalize_optional_int,
71
+ ensure_collection,
72
+ flatten_structure,
73
+ is_non_string_sequence,
74
+ mix_groups,
75
+ negative_weights_warn_once,
76
+ normalize_counter,
77
+ normalize_materialize_limit,
78
+ normalize_weights,
79
+ )
80
+ from .chunks import auto_chunk_size, resolve_chunk_size
81
+ from .graph import (
82
+ get_graph,
83
+ get_graph_mapping,
84
+ mark_dnfr_prep_dirty,
85
+ supports_add_edge,
86
+ )
87
+ from .numeric import (
88
+ angle_diff,
89
+ angle_diff_array,
90
+ clamp,
91
+ clamp01,
92
+ kahan_sum_nd,
93
+ similarity_abs,
94
+ within_range,
95
+ )
96
+ from .io import (
97
+ DEFAULT_PARAMS,
98
+ JsonDumpsParams,
99
+ StructuredFileError,
100
+ clear_orjson_param_warnings,
101
+ json_dumps,
102
+ read_structured_file,
103
+ safe_write,
104
+ )
105
+
106
+ __all__ = (
107
+ "IMPORT_LOG",
108
+ "WarnOnce",
109
+ "cached_import",
110
+ "warm_cached_import",
111
+ "LazyImportProxy",
112
+ "get_logger",
113
+ "get_lock",
114
+ "get_nodenx",
115
+ "get_numpy",
116
+ "prune_failed_imports",
117
+ "warn_once",
118
+ "convert_value",
119
+ "normalize_optional_int",
120
+ "normalize_weights",
121
+ "normalize_counter",
122
+ "normalize_materialize_limit",
123
+ "ensure_collection",
124
+ "flatten_structure",
125
+ "is_non_string_sequence",
126
+ "STRING_TYPES",
127
+ "MAX_MATERIALIZE_DEFAULT",
128
+ "negative_weights_warn_once",
129
+ "mix_groups",
130
+ "angle_diff",
131
+ "angle_diff_array",
132
+ "clamp",
133
+ "clamp01",
134
+ "auto_chunk_size",
135
+ "resolve_chunk_size",
136
+ "CacheCapacityConfig",
137
+ "CacheLayer",
138
+ "CacheManager",
139
+ "CacheStatistics",
140
+ "InstrumentedLRUCache",
141
+ "ManagedLRUCache",
142
+ "MappingCacheLayer",
143
+ "RedisCacheLayer",
144
+ "ShelveCacheLayer",
145
+ "prune_lock_mapping",
146
+ "EdgeCacheManager",
147
+ "DNFR_PREP_STATE_KEY",
148
+ "DnfrPrepState",
149
+ "DnfrCache",
150
+ "NODE_SET_CHECKSUM_KEY",
151
+ "ScopedCounterCache",
152
+ "cached_node_list",
153
+ "cached_nodes_and_A",
154
+ "clear_node_repr_cache",
155
+ "edge_version_cache",
156
+ "edge_version_update",
157
+ "configure_global_cache_layers",
158
+ "ensure_node_index_map",
159
+ "ensure_node_offset_map",
160
+ "new_dnfr_cache",
161
+ "get_graph_version",
162
+ "increment_edge_version",
163
+ "increment_graph_version",
164
+ "configure_graph_cache_limits",
165
+ "build_cache_manager",
166
+ "_graph_cache_manager",
167
+ "_GRAPH_CACHE_MANAGER_KEY",
168
+ "node_set_checksum",
169
+ "stable_json",
170
+ "reset_global_cache_manager",
171
+ "_SeedHashCache",
172
+ "_GRAPH_CACHE_LAYERS_KEY",
173
+ "get_graph",
174
+ "get_graph_mapping",
175
+ "mark_dnfr_prep_dirty",
176
+ "supports_add_edge",
177
+ "JsonDumpsParams",
178
+ "DEFAULT_PARAMS",
179
+ "json_dumps",
180
+ "clear_orjson_param_warnings",
181
+ "read_structured_file",
182
+ "safe_write",
183
+ "StructuredFileError",
184
+ "kahan_sum_nd",
185
+ "similarity_abs",
186
+ "within_range",
187
+ "_configure_root",
188
+ "_LOGGING_CONFIGURED",
189
+ "_reset_logging_state",
190
+ "_reset_import_state",
191
+ "_IMPORT_STATE",
192
+ "_warn_failure",
193
+ "_FAILED_IMPORT_LIMIT",
194
+ "_DEFAULT_CACHE_SIZE",
195
+ "EMIT_MAP",
196
+ )
197
+
198
+ #: Mapping of dynamically proxied names to the runtime types they expose.
199
+ #:
200
+ #: ``IMPORT_LOG`` and ``_IMPORT_STATE`` refer to the
201
+ #: :class:`~tnfr.utils.init.ImportRegistry` instance that tracks cached import
202
+ #: metadata, while ``_LOGGING_CONFIGURED`` is the module-level flag guarding the
203
+ #: lazy logging bootstrap performed in :mod:`tnfr.utils.init`.
204
+ _DYNAMIC_EXPORT_TYPES: Final[dict[str, type[object]]] = {
205
+ "IMPORT_LOG": _init.ImportRegistry,
206
+ "_IMPORT_STATE": _init.ImportRegistry,
207
+ "_LOGGING_CONFIGURED": bool,
208
+ }
209
+ _DYNAMIC_EXPORTS: Final[frozenset[str]] = frozenset(_DYNAMIC_EXPORT_TYPES)
210
+ def __getattr__(name: str) -> Any: # pragma: no cover - trivial delegation
211
+ if name in _DYNAMIC_EXPORTS:
212
+ return getattr(_init, name)
213
+ raise AttributeError(name)
214
+
215
+
216
+ def __dir__() -> list[str]: # pragma: no cover - trivial delegation
217
+ return sorted(set(globals()) | set(_DYNAMIC_EXPORTS))