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.py CHANGED
@@ -2,10 +2,366 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from collections.abc import (
6
+ Callable,
7
+ Hashable,
8
+ Mapping,
9
+ MutableMapping,
10
+ MutableSequence,
11
+ Sequence,
12
+ )
5
13
  from enum import Enum
6
- from typing import Any, Iterable, Protocol
14
+ from types import SimpleNamespace
15
+ from typing import (
16
+ TYPE_CHECKING,
17
+ Any,
18
+ ContextManager,
19
+ Iterable,
20
+ Protocol,
21
+ TypedDict,
22
+ runtime_checkable,
23
+ )
7
24
 
8
- __all__ = ("GraphLike", "Glyph")
25
+ from numbers import Real
26
+
27
+ from ._compat import TypeAlias
28
+
29
+ try: # pragma: no cover - optional dependency for typing only
30
+ import numpy as np
31
+ except Exception: # pragma: no cover - graceful fallback when NumPy is missing
32
+ np = SimpleNamespace(ndarray=Any, float_=float) # type: ignore[assignment]
33
+
34
+ if TYPE_CHECKING: # pragma: no cover - import-time typing hook
35
+ try:
36
+ import numpy.typing as npt
37
+ except Exception: # pragma: no cover - fallback when NumPy typing is missing
38
+ npt = SimpleNamespace(NDArray=Any) # type: ignore[assignment]
39
+ else: # pragma: no cover - runtime fallback without numpy.typing
40
+ npt = SimpleNamespace(NDArray=Any) # type: ignore[assignment]
41
+
42
+ __all__ = (
43
+ "TNFRGraph",
44
+ "Graph",
45
+ "ValidatorFunc",
46
+ "NodeId",
47
+ "Node",
48
+ "GammaSpec",
49
+ "EPIValue",
50
+ "BEPIProtocol",
51
+ "ensure_bepi",
52
+ "serialize_bepi",
53
+ "ZERO_BEPI_STORAGE",
54
+ "DeltaNFR",
55
+ "SecondDerivativeEPI",
56
+ "Phase",
57
+ "StructuralFrequency",
58
+ "SenseIndex",
59
+ "CouplingWeight",
60
+ "CoherenceMetric",
61
+ "DeltaNFRHook",
62
+ "GraphLike",
63
+ "IntegratorProtocol",
64
+ "Glyph",
65
+ "GlyphCode",
66
+ "GlyphLoadDistribution",
67
+ "GlyphSelector",
68
+ "SelectorPreselectionMetrics",
69
+ "SelectorPreselectionChoices",
70
+ "SelectorPreselectionPayload",
71
+ "SelectorMetrics",
72
+ "SelectorNorms",
73
+ "SelectorThresholds",
74
+ "SelectorWeights",
75
+ "TraceCallback",
76
+ "CallbackError",
77
+ "TraceFieldFn",
78
+ "TraceFieldMap",
79
+ "TraceFieldRegistry",
80
+ "TraceMetadata",
81
+ "TraceSnapshot",
82
+ "RemeshMeta",
83
+ "HistoryState",
84
+ "DiagnosisNodeData",
85
+ "DiagnosisSharedState",
86
+ "DiagnosisPayload",
87
+ "DiagnosisResult",
88
+ "DiagnosisPayloadChunk",
89
+ "DiagnosisResultList",
90
+ "DnfrCacheVectors",
91
+ "DnfrVectorMap",
92
+ "NeighborStats",
93
+ "TimingContext",
94
+ "PresetTokens",
95
+ "ProgramTokens",
96
+ "ArgSpec",
97
+ "TNFRConfigValue",
98
+ "SigmaVector",
99
+ "SigmaTrace",
100
+ "FloatArray",
101
+ "FloatMatrix",
102
+ "NodeInitAttrMap",
103
+ "NodeAttrMap",
104
+ "GlyphogramRow",
105
+ "GlyphTimingTotals",
106
+ "GlyphTimingByNode",
107
+ "GlyphCounts",
108
+ "GlyphMetricsHistoryValue",
109
+ "GlyphMetricsHistory",
110
+ "MetricsListHistory",
111
+ "ParallelWijPayload",
112
+ )
113
+
114
+
115
+ if TYPE_CHECKING: # pragma: no cover - import-time typing hook
116
+ import networkx as nx
117
+
118
+ from .glyph_history import HistoryDict as _HistoryDict
119
+ from .tokens import Token as _Token
120
+ TNFRGraph: TypeAlias = nx.Graph
121
+ else: # pragma: no cover - runtime fallback without networkx
122
+ TNFRGraph: TypeAlias = Any
123
+ _HistoryDict = Any # type: ignore[assignment]
124
+ _Token = Any # type: ignore[assignment]
125
+ #: Graph container storing TNFR nodes, edges and their coherence telemetry.
126
+
127
+ if TYPE_CHECKING:
128
+ FloatArray: TypeAlias = npt.NDArray[np.float_]
129
+ FloatMatrix: TypeAlias = npt.NDArray[np.float_]
130
+ else: # pragma: no cover - runtime fallback without NumPy
131
+ FloatArray: TypeAlias = Any
132
+ FloatMatrix: TypeAlias = Any
133
+
134
+ Graph: TypeAlias = TNFRGraph
135
+ #: Backwards-compatible alias for :data:`TNFRGraph`.
136
+
137
+ ValidatorFunc: TypeAlias = Callable[[TNFRGraph], None]
138
+ """Callable signature enforced by graph validation hooks."""
139
+
140
+ NodeId: TypeAlias = Hashable
141
+ #: Hashable identifier for a coherent TNFR node.
142
+
143
+ Node: TypeAlias = NodeId
144
+ #: Backwards-compatible alias for :data:`NodeId`.
145
+
146
+ NodeInitAttrMap: TypeAlias = MutableMapping[str, float]
147
+ #: Mutable mapping storing scalar node attributes during initialization.
148
+
149
+ NodeAttrMap: TypeAlias = Mapping[str, Any]
150
+ #: Read-only mapping exposing resolved node attributes during execution.
151
+
152
+ GammaSpec: TypeAlias = Mapping[str, Any]
153
+ #: Mapping describing Γ evaluation parameters for a node or graph.
154
+
155
+ @runtime_checkable
156
+ class BEPIProtocol(Protocol):
157
+ """Structural contract describing BEPI-compatible values."""
158
+
159
+ f_continuous: Any
160
+ a_discrete: Any
161
+ x_grid: Any
162
+
163
+ def direct_sum(self, other: Any) -> Any: ...
164
+
165
+ def tensor(self, vector: Sequence[complex] | np.ndarray) -> np.ndarray: ...
166
+
167
+ def adjoint(self) -> Any: ...
168
+
169
+ def compose(
170
+ self,
171
+ transform: Callable[[np.ndarray], np.ndarray],
172
+ *,
173
+ spectral_transform: Callable[[np.ndarray], np.ndarray] | None = None,
174
+ ) -> Any: ...
175
+
176
+
177
+ EPIValue: TypeAlias = BEPIProtocol
178
+ #: BEPI Primary Information Structure carried by a node.
179
+
180
+ ZERO_BEPI_STORAGE: dict[str, tuple[complex, ...] | tuple[float, ...]] = {
181
+ "continuous": (0j, 0j),
182
+ "discrete": (0j, 0j),
183
+ "grid": (0.0, 1.0),
184
+ }
185
+ """Canonical zero element used as fallback when EPI data is missing."""
186
+
187
+
188
+ def _is_scalar(value: Any) -> bool:
189
+ scalar_types: tuple[type[Any], ...]
190
+ np_scalar = getattr(np, "generic", None)
191
+ if np_scalar is None:
192
+ scalar_types = (int, float, complex, Real)
193
+ else:
194
+ scalar_types = (int, float, complex, Real, np_scalar)
195
+ return isinstance(value, scalar_types)
196
+
197
+
198
+ def ensure_bepi(value: Any) -> "BEPIElement":
199
+ """Normalise arbitrary inputs into a :class:`~tnfr.mathematics.BEPIElement`."""
200
+
201
+ from .mathematics import BEPIElement as _BEPIElement
202
+
203
+ if isinstance(value, _BEPIElement):
204
+ return value
205
+ if _is_scalar(value):
206
+ scalar = complex(value)
207
+ return _BEPIElement((scalar, scalar), (scalar, scalar), (0.0, 1.0))
208
+ if isinstance(value, Mapping):
209
+ try:
210
+ continuous = value["continuous"]
211
+ discrete = value["discrete"]
212
+ grid = value["grid"]
213
+ except KeyError as exc: # pragma: no cover - defensive
214
+ missing = exc.args[0]
215
+ raise ValueError(f"Missing '{missing}' key for BEPI serialization.") from exc
216
+ return _BEPIElement(continuous, discrete, grid)
217
+ if isinstance(value, Sequence) and not isinstance(value, (str, bytes, bytearray)):
218
+ if len(value) != 3:
219
+ raise ValueError("Sequential BEPI representations must contain 3 elements.")
220
+ continuous, discrete, grid = value
221
+ return _BEPIElement(continuous, discrete, grid)
222
+ raise TypeError(f"Unsupported BEPI value type: {type(value)!r}")
223
+
224
+
225
+ def serialize_bepi(value: Any) -> dict[str, tuple[complex, ...] | tuple[float, ...]]:
226
+ """Serialise a BEPI element into canonical ``continuous/discrete/grid`` tuples."""
227
+
228
+ element = ensure_bepi(value)
229
+ continuous = tuple(complex(v) for v in element.f_continuous.tolist())
230
+ discrete = tuple(complex(v) for v in element.a_discrete.tolist())
231
+ grid = tuple(float(v) for v in element.x_grid.tolist())
232
+ return {"continuous": continuous, "discrete": discrete, "grid": grid}
233
+
234
+ DeltaNFR: TypeAlias = float
235
+ #: Scalar internal reorganisation driver ΔNFR applied to a node.
236
+
237
+ SecondDerivativeEPI: TypeAlias = float
238
+ #: Second derivative ∂²EPI/∂t² tracking bifurcation pressure.
239
+
240
+ Phase: TypeAlias = float
241
+ #: Phase (φ) describing a node's synchrony relative to its neighbors.
242
+
243
+ StructuralFrequency: TypeAlias = float
244
+ #: Structural frequency νf expressed in Hz_str.
245
+
246
+ SenseIndex: TypeAlias = float
247
+ #: Sense index Si capturing a node's reorganising capacity.
248
+
249
+ CouplingWeight: TypeAlias = float
250
+ #: Weight attached to edges describing coupling coherence strength.
251
+
252
+ CoherenceMetric: TypeAlias = float
253
+ #: Aggregated measure of coherence such as C(t) or Si.
254
+
255
+ TimingContext: TypeAlias = ContextManager[None]
256
+ #: Context manager used to measure execution time for cache operations.
257
+
258
+ ProgramTokens: TypeAlias = Sequence[_Token]
259
+ #: Sequence of execution tokens composing a TNFR program.
260
+
261
+ PresetTokens: TypeAlias = Sequence[_Token]
262
+ #: Sequence of execution tokens composing a preset program.
263
+
264
+ ArgSpec: TypeAlias = tuple[str, Mapping[str, Any]]
265
+ #: CLI argument specification pairing an option flag with keyword arguments.
266
+
267
+
268
+ TNFRConfigScalar: TypeAlias = bool | int | float | str | None
269
+ """Primitive value allowed within TNFR configuration stores."""
270
+
271
+ TNFRConfigSequence: TypeAlias = Sequence[TNFRConfigScalar]
272
+ """Homogeneous sequence of scalar TNFR configuration values."""
273
+
274
+ TNFRConfigValue: TypeAlias = (
275
+ TNFRConfigScalar | TNFRConfigSequence | Mapping[str, "TNFRConfigValue"]
276
+ )
277
+ """Permissible configuration entry for TNFR coherence defaults.
278
+
279
+ The alias captures the recursive structure used by TNFR defaults: scalars
280
+ express structural thresholds, booleans toggle operators, and nested mappings
281
+ or sequences describe coherent parameter bundles such as γ grammars,
282
+ selector advice or trace capture lists.
283
+ """
284
+
285
+
286
+ class _SigmaVectorRequired(TypedDict):
287
+ """Mandatory components for a σ-vector in the sense plane."""
288
+
289
+ x: float
290
+ y: float
291
+ mag: float
292
+ angle: float
293
+ n: int
294
+
295
+
296
+ class _SigmaVectorOptional(TypedDict, total=False):
297
+ """Optional metadata captured when tracking σ-vectors."""
298
+
299
+ glyph: str
300
+ w: float
301
+ t: float
302
+
303
+
304
+ class SigmaVector(_SigmaVectorRequired, _SigmaVectorOptional):
305
+ """Typed dictionary describing σ-vector telemetry."""
306
+
307
+
308
+ class SigmaTrace(TypedDict):
309
+ """Time-aligned σ(t) trace exported alongside glyphograms."""
310
+
311
+ t: list[float]
312
+ sigma_x: list[float]
313
+ sigma_y: list[float]
314
+ mag: list[float]
315
+ angle: list[float]
316
+
317
+
318
+ class SelectorThresholds(TypedDict):
319
+ """Normalised thresholds applied by the glyph selector."""
320
+
321
+ si_hi: float
322
+ si_lo: float
323
+ dnfr_hi: float
324
+ dnfr_lo: float
325
+ accel_hi: float
326
+ accel_lo: float
327
+
328
+
329
+ class SelectorWeights(TypedDict):
330
+ """Normalised weights controlling selector scoring."""
331
+
332
+ w_si: float
333
+ w_dnfr: float
334
+ w_accel: float
335
+
336
+
337
+ SelectorMetrics: TypeAlias = tuple[float, float, float]
338
+ """Tuple grouping normalised Si, |ΔNFR| and acceleration values."""
339
+
340
+ SelectorNorms: TypeAlias = Mapping[str, float]
341
+ """Mapping storing maxima used to normalise selector metrics."""
342
+
343
+
344
+ class _DeltaNFRHookProtocol(Protocol):
345
+ """Callable signature expected for ΔNFR update hooks.
346
+
347
+ Hooks receive the graph instance and may expose optional keyword
348
+ arguments such as ``n_jobs`` or cache controls. Additional positional
349
+ arguments are reserved for future extensions and ignored by the core
350
+ engine, keeping compatibility with user-provided hooks that only need the
351
+ graph reference.
352
+ """
353
+
354
+ def __call__(
355
+ self,
356
+ graph: TNFRGraph,
357
+ /,
358
+ *args: Any,
359
+ **kwargs: Any,
360
+ ) -> None: ...
361
+
362
+
363
+ DeltaNFRHook: TypeAlias = _DeltaNFRHookProtocol
364
+ #: Callable hook invoked to compute ΔNFR for a :data:`TNFRGraph`.
9
365
 
10
366
 
11
367
  class GraphLike(Protocol):
@@ -18,13 +374,43 @@ class GraphLike(Protocol):
18
374
 
19
375
  graph: dict[str, Any]
20
376
 
21
- def nodes(self, data: bool = ...) -> Iterable[Any]: ...
377
+ def nodes(self, data: bool = ...) -> Iterable[Any]:
378
+ """Return an iterable of nodes mirroring NetworkX semantics."""
379
+
380
+ ...
381
+
382
+ def number_of_nodes(self) -> int:
383
+ """Return the total number of coherent nodes in the graph."""
22
384
 
23
- def number_of_nodes(self) -> int: ...
385
+ ...
24
386
 
25
- def neighbors(self, n: Any) -> Iterable[Any]: ...
387
+ def neighbors(self, n: Any) -> Iterable[Any]:
388
+ """Yield adjacent nodes coupled to ``n`` within the structure."""
389
+
390
+ ...
391
+
392
+ def __iter__(self) -> Iterable[Any]:
393
+ """Iterate over nodes to allow direct structural traversals."""
394
+
395
+ ...
396
+
397
+
398
+ class IntegratorProtocol(Protocol):
399
+ """Interface describing configurable nodal equation integrators."""
400
+
401
+ def integrate(
402
+ self,
403
+ graph: TNFRGraph,
404
+ *,
405
+ dt: float | None,
406
+ t: float | None,
407
+ method: str | None,
408
+ n_jobs: int | None,
409
+ ) -> None:
410
+ """Advance the nodal equation for ``graph`` using integrator configuration."""
411
+
412
+ ...
26
413
 
27
- def __iter__(self) -> Iterable[Any]: ...
28
414
 
29
415
  class Glyph(str, Enum):
30
416
  """Canonical TNFR glyphs."""
@@ -42,3 +428,185 @@ class Glyph(str, Enum):
42
428
  ZHIR = "ZHIR"
43
429
  NAV = "NAV"
44
430
  REMESH = "REMESH"
431
+
432
+
433
+ GlyphCode: TypeAlias = Glyph | str
434
+ """Glyph identifier accepted by selector pipelines and grammars."""
435
+
436
+
437
+ GlyphLoadDistribution: TypeAlias = dict[Glyph | str, float]
438
+ #: Normalised glyph load proportions keyed by :class:`Glyph` or aggregate labels.
439
+
440
+
441
+ class _SelectorLifecycle(Protocol):
442
+ """Protocol describing the selector lifecycle supported by the runtime."""
443
+
444
+ def __call__(self, graph: TNFRGraph, node: NodeId) -> GlyphCode: ...
445
+
446
+ def prepare(self, graph: TNFRGraph, nodes: Sequence[NodeId]) -> None: ...
447
+
448
+ def select(self, graph: TNFRGraph, node: NodeId) -> GlyphCode: ...
449
+
450
+
451
+ GlyphSelector: TypeAlias = (
452
+ Callable[[TNFRGraph, NodeId], GlyphCode] | _SelectorLifecycle
453
+ )
454
+ #: Selector callable or object returning the glyph to apply for ``NodeId``.
455
+
456
+ SelectorPreselectionMetrics: TypeAlias = Mapping[Any, SelectorMetrics]
457
+ #: Mapping of nodes to their normalised selector metrics.
458
+
459
+ SelectorPreselectionChoices: TypeAlias = Mapping[Any, Glyph | str]
460
+ #: Mapping of nodes to their preferred glyph choices prior to grammar filters.
461
+
462
+ SelectorPreselectionPayload: TypeAlias = tuple[
463
+ SelectorPreselectionMetrics,
464
+ SelectorPreselectionChoices,
465
+ ]
466
+ #: Tuple grouping selector metrics and base decisions for preselection steps.
467
+
468
+ TraceFieldFn: TypeAlias = Callable[[TNFRGraph], "TraceMetadata"]
469
+ #: Callable producing :class:`tnfr.trace.TraceMetadata` from a :data:`TNFRGraph`.
470
+
471
+ TraceFieldMap: TypeAlias = Mapping[str, "TraceFieldFn"]
472
+ #: Mapping of trace field names to their producers for a given phase.
473
+
474
+ TraceFieldRegistry: TypeAlias = dict[str, dict[str, "TraceFieldFn"]]
475
+ #: Registry grouping trace field producers by capture phase.
476
+
477
+
478
+ class TraceMetadata(TypedDict, total=False):
479
+ """Metadata captured by trace field producers across phases."""
480
+
481
+ gamma: Mapping[str, Any]
482
+ grammar: Mapping[str, Any]
483
+ selector: str | None
484
+ dnfr_weights: Mapping[str, Any]
485
+ si_weights: Mapping[str, Any]
486
+ si_sensitivity: Mapping[str, Any]
487
+ callbacks: Mapping[str, list[str] | None]
488
+ thol_open_nodes: int
489
+ kuramoto: Mapping[str, float]
490
+ sigma: Mapping[str, float]
491
+ glyphs: Mapping[str, int]
492
+
493
+
494
+ class TraceSnapshot(TraceMetadata, total=False):
495
+ """Trace metadata snapshot recorded in TNFR history."""
496
+
497
+ t: float
498
+ phase: str
499
+
500
+
501
+ HistoryState: TypeAlias = _HistoryDict | dict[str, Any]
502
+ #: History container used to accumulate glyph metrics and logs for the graph.
503
+
504
+
505
+ class CallbackError(TypedDict):
506
+ """Metadata captured for a failed callback invocation."""
507
+
508
+ event: str
509
+ step: int | None
510
+ error: str
511
+ traceback: str
512
+ fn: str
513
+ name: str | None
514
+
515
+
516
+ TraceCallback: TypeAlias = Callable[[TNFRGraph, dict[str, Any]], None]
517
+ #: Callback signature used by :func:`tnfr.trace.register_trace`.
518
+
519
+ DiagnosisNodeData: TypeAlias = Mapping[str, Any]
520
+ #: Raw nodal measurement payload used prior to computing diagnostics.
521
+
522
+ DiagnosisSharedState: TypeAlias = Mapping[str, Any]
523
+ #: Shared read-only state propagated to diagnosis workers.
524
+
525
+ DiagnosisPayload: TypeAlias = dict[str, Any]
526
+ #: Structured diagnostics exported for a single node.
527
+
528
+ DiagnosisResult: TypeAlias = tuple[NodeId, DiagnosisPayload]
529
+ #: Node identifier paired with its :data:`DiagnosisPayload`.
530
+
531
+ DiagnosisPayloadChunk: TypeAlias = list[DiagnosisNodeData]
532
+ #: Chunk of nodal payloads processed together by diagnosis workers.
533
+
534
+ DiagnosisResultList: TypeAlias = list[DiagnosisResult]
535
+ #: Collection of diagnosis results matching worker output shape.
536
+
537
+ DnfrCacheVectors: TypeAlias = tuple[
538
+ np.ndarray | None,
539
+ np.ndarray | None,
540
+ np.ndarray | None,
541
+ np.ndarray | None,
542
+ np.ndarray | None,
543
+ ]
544
+ """Tuple grouping cached NumPy vectors for θ, EPI, νf and trigonometric projections."""
545
+
546
+ DnfrVectorMap: TypeAlias = dict[str, np.ndarray | None]
547
+ """Mapping of TNFR state aliases to their NumPy buffers synchronized from lists."""
548
+
549
+ NeighborStats: TypeAlias = tuple[
550
+ Sequence[float],
551
+ Sequence[float],
552
+ Sequence[float],
553
+ Sequence[float],
554
+ Sequence[float] | None,
555
+ Sequence[float] | None,
556
+ Sequence[float] | None,
557
+ ]
558
+ """Bundle of neighbour accumulators for cosine, sine, EPI, νf and topology totals."""
559
+
560
+ GlyphogramRow: TypeAlias = MutableMapping[str, float]
561
+ """Row exported by glyph timing summaries."""
562
+
563
+ GlyphTimingTotals: TypeAlias = MutableMapping[str, float]
564
+ """Aggregate glyph timing totals keyed by glyph code."""
565
+
566
+ GlyphTimingByNode: TypeAlias = MutableMapping[
567
+ Any, MutableMapping[str, MutableSequence[float]]
568
+ ]
569
+ """Glyph timing segments stored per node during audits."""
570
+
571
+ GlyphCounts: TypeAlias = Mapping[str, int]
572
+ """Glyph occurrence counters keyed by glyph code."""
573
+
574
+ GlyphMetricsHistoryValue: TypeAlias = MutableMapping[Any, Any] | MutableSequence[Any]
575
+ """Flexible container used by glyph history accumulators."""
576
+
577
+ GlyphMetricsHistory: TypeAlias = MutableMapping[str, GlyphMetricsHistoryValue]
578
+ """History map storing glyph metrics by identifier."""
579
+
580
+ MetricsListHistory: TypeAlias = MutableMapping[str, list[Any]]
581
+ """Mapping associating glyph metric identifiers with time series."""
582
+
583
+
584
+ class RemeshMeta(TypedDict, total=False):
585
+ """Event metadata persisted after applying REMESH coherence operators."""
586
+
587
+ alpha: float
588
+ alpha_source: str
589
+ tau_global: int
590
+ tau_local: int
591
+ step: int | None
592
+ topo_hash: str | None
593
+ epi_mean_before: float
594
+ epi_mean_after: float
595
+ epi_checksum_before: str
596
+ epi_checksum_after: str
597
+ stable_frac_last: float
598
+ phase_sync_last: float
599
+ glyph_disr_last: float
600
+
601
+
602
+ class ParallelWijPayload(TypedDict):
603
+ """Container for broadcasting Wij coherence components to worker pools."""
604
+
605
+ epi_vals: Sequence[float]
606
+ vf_vals: Sequence[float]
607
+ si_vals: Sequence[float]
608
+ cos_vals: Sequence[float]
609
+ sin_vals: Sequence[float]
610
+ weights: tuple[float, float, float, float]
611
+ epi_range: float
612
+ vf_range: float