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.

Files changed (176) hide show
  1. tnfr/__init__.py +50 -5
  2. tnfr/__init__.pyi +0 -7
  3. tnfr/_compat.py +0 -1
  4. tnfr/_generated_version.py +34 -0
  5. tnfr/_version.py +44 -2
  6. tnfr/alias.py +14 -13
  7. tnfr/alias.pyi +5 -37
  8. tnfr/cache.py +9 -729
  9. tnfr/cache.pyi +8 -224
  10. tnfr/callback_utils.py +16 -31
  11. tnfr/callback_utils.pyi +3 -29
  12. tnfr/cli/__init__.py +17 -11
  13. tnfr/cli/__init__.pyi +0 -21
  14. tnfr/cli/arguments.py +175 -14
  15. tnfr/cli/arguments.pyi +5 -11
  16. tnfr/cli/execution.py +434 -48
  17. tnfr/cli/execution.pyi +14 -24
  18. tnfr/cli/utils.py +20 -3
  19. tnfr/cli/utils.pyi +5 -5
  20. tnfr/config/__init__.py +2 -1
  21. tnfr/config/__init__.pyi +2 -0
  22. tnfr/config/feature_flags.py +83 -0
  23. tnfr/config/init.py +1 -1
  24. tnfr/config/operator_names.py +1 -14
  25. tnfr/config/presets.py +6 -26
  26. tnfr/constants/__init__.py +10 -13
  27. tnfr/constants/__init__.pyi +10 -22
  28. tnfr/constants/aliases.py +31 -0
  29. tnfr/constants/core.py +4 -3
  30. tnfr/constants/init.py +1 -1
  31. tnfr/constants/metric.py +3 -3
  32. tnfr/dynamics/__init__.py +64 -10
  33. tnfr/dynamics/__init__.pyi +3 -4
  34. tnfr/dynamics/adaptation.py +79 -13
  35. tnfr/dynamics/aliases.py +10 -9
  36. tnfr/dynamics/coordination.py +77 -35
  37. tnfr/dynamics/dnfr.py +575 -274
  38. tnfr/dynamics/dnfr.pyi +1 -10
  39. tnfr/dynamics/integrators.py +47 -33
  40. tnfr/dynamics/integrators.pyi +0 -1
  41. tnfr/dynamics/runtime.py +489 -129
  42. tnfr/dynamics/sampling.py +2 -0
  43. tnfr/dynamics/selectors.py +101 -62
  44. tnfr/execution.py +15 -8
  45. tnfr/execution.pyi +5 -25
  46. tnfr/flatten.py +7 -3
  47. tnfr/flatten.pyi +1 -8
  48. tnfr/gamma.py +22 -26
  49. tnfr/gamma.pyi +0 -6
  50. tnfr/glyph_history.py +37 -26
  51. tnfr/glyph_history.pyi +1 -19
  52. tnfr/glyph_runtime.py +16 -0
  53. tnfr/glyph_runtime.pyi +9 -0
  54. tnfr/immutable.py +20 -15
  55. tnfr/immutable.pyi +4 -7
  56. tnfr/initialization.py +5 -7
  57. tnfr/initialization.pyi +1 -9
  58. tnfr/io.py +6 -305
  59. tnfr/io.pyi +13 -8
  60. tnfr/mathematics/__init__.py +81 -0
  61. tnfr/mathematics/backend.py +426 -0
  62. tnfr/mathematics/dynamics.py +398 -0
  63. tnfr/mathematics/epi.py +254 -0
  64. tnfr/mathematics/generators.py +222 -0
  65. tnfr/mathematics/metrics.py +119 -0
  66. tnfr/mathematics/operators.py +233 -0
  67. tnfr/mathematics/operators_factory.py +71 -0
  68. tnfr/mathematics/projection.py +78 -0
  69. tnfr/mathematics/runtime.py +173 -0
  70. tnfr/mathematics/spaces.py +247 -0
  71. tnfr/mathematics/transforms.py +292 -0
  72. tnfr/metrics/__init__.py +10 -10
  73. tnfr/metrics/coherence.py +123 -94
  74. tnfr/metrics/common.py +22 -13
  75. tnfr/metrics/common.pyi +42 -11
  76. tnfr/metrics/core.py +72 -14
  77. tnfr/metrics/diagnosis.py +48 -57
  78. tnfr/metrics/diagnosis.pyi +3 -7
  79. tnfr/metrics/export.py +3 -5
  80. tnfr/metrics/glyph_timing.py +41 -31
  81. tnfr/metrics/reporting.py +13 -6
  82. tnfr/metrics/sense_index.py +884 -114
  83. tnfr/metrics/trig.py +167 -11
  84. tnfr/metrics/trig.pyi +1 -0
  85. tnfr/metrics/trig_cache.py +112 -15
  86. tnfr/node.py +400 -17
  87. tnfr/node.pyi +55 -38
  88. tnfr/observers.py +111 -8
  89. tnfr/observers.pyi +0 -15
  90. tnfr/ontosim.py +9 -6
  91. tnfr/ontosim.pyi +0 -5
  92. tnfr/operators/__init__.py +529 -42
  93. tnfr/operators/__init__.pyi +14 -0
  94. tnfr/operators/definitions.py +350 -18
  95. tnfr/operators/definitions.pyi +0 -14
  96. tnfr/operators/grammar.py +760 -0
  97. tnfr/operators/jitter.py +28 -22
  98. tnfr/operators/registry.py +7 -12
  99. tnfr/operators/registry.pyi +0 -2
  100. tnfr/operators/remesh.py +38 -61
  101. tnfr/rng.py +17 -300
  102. tnfr/schemas/__init__.py +8 -0
  103. tnfr/schemas/grammar.json +94 -0
  104. tnfr/selector.py +3 -4
  105. tnfr/selector.pyi +1 -1
  106. tnfr/sense.py +22 -24
  107. tnfr/sense.pyi +0 -7
  108. tnfr/structural.py +504 -21
  109. tnfr/structural.pyi +41 -18
  110. tnfr/telemetry/__init__.py +23 -1
  111. tnfr/telemetry/cache_metrics.py +226 -0
  112. tnfr/telemetry/nu_f.py +423 -0
  113. tnfr/telemetry/nu_f.pyi +123 -0
  114. tnfr/tokens.py +1 -4
  115. tnfr/tokens.pyi +1 -6
  116. tnfr/trace.py +20 -53
  117. tnfr/trace.pyi +9 -37
  118. tnfr/types.py +244 -15
  119. tnfr/types.pyi +200 -14
  120. tnfr/units.py +69 -0
  121. tnfr/units.pyi +16 -0
  122. tnfr/utils/__init__.py +107 -48
  123. tnfr/utils/__init__.pyi +80 -11
  124. tnfr/utils/cache.py +1705 -65
  125. tnfr/utils/cache.pyi +370 -58
  126. tnfr/utils/chunks.py +104 -0
  127. tnfr/utils/chunks.pyi +21 -0
  128. tnfr/utils/data.py +95 -5
  129. tnfr/utils/data.pyi +8 -17
  130. tnfr/utils/graph.py +2 -4
  131. tnfr/utils/init.py +31 -7
  132. tnfr/utils/init.pyi +4 -11
  133. tnfr/utils/io.py +313 -14
  134. tnfr/{helpers → utils}/numeric.py +50 -24
  135. tnfr/utils/numeric.pyi +21 -0
  136. tnfr/validation/__init__.py +92 -4
  137. tnfr/validation/__init__.pyi +77 -17
  138. tnfr/validation/compatibility.py +79 -43
  139. tnfr/validation/compatibility.pyi +4 -6
  140. tnfr/validation/grammar.py +55 -133
  141. tnfr/validation/grammar.pyi +37 -8
  142. tnfr/validation/graph.py +138 -0
  143. tnfr/validation/graph.pyi +17 -0
  144. tnfr/validation/rules.py +161 -74
  145. tnfr/validation/rules.pyi +55 -18
  146. tnfr/validation/runtime.py +263 -0
  147. tnfr/validation/runtime.pyi +31 -0
  148. tnfr/validation/soft_filters.py +170 -0
  149. tnfr/validation/soft_filters.pyi +37 -0
  150. tnfr/validation/spectral.py +159 -0
  151. tnfr/validation/spectral.pyi +46 -0
  152. tnfr/validation/syntax.py +28 -139
  153. tnfr/validation/syntax.pyi +7 -4
  154. tnfr/validation/window.py +39 -0
  155. tnfr/validation/window.pyi +1 -0
  156. tnfr/viz/__init__.py +9 -0
  157. tnfr/viz/matplotlib.py +246 -0
  158. {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/METADATA +63 -19
  159. tnfr-7.0.0.dist-info/RECORD +185 -0
  160. {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/licenses/LICENSE.md +1 -1
  161. tnfr/constants_glyphs.py +0 -16
  162. tnfr/constants_glyphs.pyi +0 -12
  163. tnfr/grammar.py +0 -25
  164. tnfr/grammar.pyi +0 -13
  165. tnfr/helpers/__init__.py +0 -151
  166. tnfr/helpers/__init__.pyi +0 -66
  167. tnfr/helpers/numeric.pyi +0 -12
  168. tnfr/presets.py +0 -15
  169. tnfr/presets.pyi +0 -7
  170. tnfr/utils/io.pyi +0 -10
  171. tnfr/utils/validators.py +0 -130
  172. tnfr/utils/validators.pyi +0 -19
  173. tnfr-6.0.0.dist-info/RECORD +0 -157
  174. {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/WHEEL +0 -0
  175. {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/entry_points.txt +0 -0
  176. {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/top_level.txt +0 -0
tnfr/types.py CHANGED
@@ -2,10 +2,27 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from collections.abc import Callable, Hashable, Mapping, MutableMapping, Sequence
5
+ from collections.abc import (
6
+ Callable,
7
+ Hashable,
8
+ Mapping,
9
+ MutableMapping,
10
+ MutableSequence,
11
+ Sequence,
12
+ )
6
13
  from enum import Enum
7
- from typing import TYPE_CHECKING, Any, ContextManager, Iterable, Protocol, TypedDict
8
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
+ )
24
+
25
+ from numbers import Real
9
26
 
10
27
  from ._compat import TypeAlias
11
28
 
@@ -25,10 +42,15 @@ else: # pragma: no cover - runtime fallback without numpy.typing
25
42
  __all__ = (
26
43
  "TNFRGraph",
27
44
  "Graph",
45
+ "ValidatorFunc",
28
46
  "NodeId",
29
47
  "Node",
30
48
  "GammaSpec",
31
49
  "EPIValue",
50
+ "BEPIProtocol",
51
+ "ensure_bepi",
52
+ "serialize_bepi",
53
+ "ZERO_BEPI_STORAGE",
32
54
  "DeltaNFR",
33
55
  "SecondDerivativeEPI",
34
56
  "Phase",
@@ -40,6 +62,7 @@ __all__ = (
40
62
  "GraphLike",
41
63
  "IntegratorProtocol",
42
64
  "Glyph",
65
+ "GlyphCode",
43
66
  "GlyphLoadDistribution",
44
67
  "GlyphSelector",
45
68
  "SelectorPreselectionMetrics",
@@ -50,9 +73,13 @@ __all__ = (
50
73
  "SelectorThresholds",
51
74
  "SelectorWeights",
52
75
  "TraceCallback",
76
+ "CallbackError",
53
77
  "TraceFieldFn",
54
78
  "TraceFieldMap",
55
79
  "TraceFieldRegistry",
80
+ "TraceMetadata",
81
+ "TraceSnapshot",
82
+ "RemeshMeta",
56
83
  "HistoryState",
57
84
  "DiagnosisNodeData",
58
85
  "DiagnosisSharedState",
@@ -69,18 +96,27 @@ __all__ = (
69
96
  "ArgSpec",
70
97
  "TNFRConfigValue",
71
98
  "SigmaVector",
99
+ "SigmaTrace",
72
100
  "FloatArray",
73
101
  "FloatMatrix",
74
102
  "NodeInitAttrMap",
103
+ "NodeAttrMap",
104
+ "GlyphogramRow",
105
+ "GlyphTimingTotals",
106
+ "GlyphTimingByNode",
107
+ "GlyphCounts",
108
+ "GlyphMetricsHistoryValue",
109
+ "GlyphMetricsHistory",
110
+ "MetricsListHistory",
111
+ "ParallelWijPayload",
75
112
  )
76
113
 
77
114
 
78
115
  if TYPE_CHECKING: # pragma: no cover - import-time typing hook
79
116
  import networkx as nx
80
- from .trace import TraceMetadata
117
+
81
118
  from .glyph_history import HistoryDict as _HistoryDict
82
119
  from .tokens import Token as _Token
83
-
84
120
  TNFRGraph: TypeAlias = nx.Graph
85
121
  else: # pragma: no cover - runtime fallback without networkx
86
122
  TNFRGraph: TypeAlias = Any
@@ -98,6 +134,9 @@ else: # pragma: no cover - runtime fallback without NumPy
98
134
  Graph: TypeAlias = TNFRGraph
99
135
  #: Backwards-compatible alias for :data:`TNFRGraph`.
100
136
 
137
+ ValidatorFunc: TypeAlias = Callable[[TNFRGraph], None]
138
+ """Callable signature enforced by graph validation hooks."""
139
+
101
140
  NodeId: TypeAlias = Hashable
102
141
  #: Hashable identifier for a coherent TNFR node.
103
142
 
@@ -107,11 +146,90 @@ Node: TypeAlias = NodeId
107
146
  NodeInitAttrMap: TypeAlias = MutableMapping[str, float]
108
147
  #: Mutable mapping storing scalar node attributes during initialization.
109
148
 
149
+ NodeAttrMap: TypeAlias = Mapping[str, Any]
150
+ #: Read-only mapping exposing resolved node attributes during execution.
151
+
110
152
  GammaSpec: TypeAlias = Mapping[str, Any]
111
153
  #: Mapping describing Γ evaluation parameters for a node or graph.
112
154
 
113
- EPIValue: TypeAlias = float
114
- #: Scalar Primary Information Structure value carried by a node.
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}
115
233
 
116
234
  DeltaNFR: TypeAlias = float
117
235
  #: Scalar internal reorganisation driver ΔNFR applied to a node.
@@ -187,6 +305,16 @@ class SigmaVector(_SigmaVectorRequired, _SigmaVectorOptional):
187
305
  """Typed dictionary describing σ-vector telemetry."""
188
306
 
189
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
+
190
318
  class SelectorThresholds(TypedDict):
191
319
  """Normalised thresholds applied by the glyph selector."""
192
320
 
@@ -229,8 +357,7 @@ class _DeltaNFRHookProtocol(Protocol):
229
357
  /,
230
358
  *args: Any,
231
359
  **kwargs: Any,
232
- ) -> None:
233
- ...
360
+ ) -> None: ...
234
361
 
235
362
 
236
363
  DeltaNFRHook: TypeAlias = _DeltaNFRHookProtocol
@@ -248,15 +375,23 @@ class GraphLike(Protocol):
248
375
  graph: dict[str, Any]
249
376
 
250
377
  def nodes(self, data: bool = ...) -> Iterable[Any]:
378
+ """Return an iterable of nodes mirroring NetworkX semantics."""
379
+
251
380
  ...
252
381
 
253
382
  def number_of_nodes(self) -> int:
383
+ """Return the total number of coherent nodes in the graph."""
384
+
254
385
  ...
255
386
 
256
387
  def neighbors(self, n: Any) -> Iterable[Any]:
388
+ """Yield adjacent nodes coupled to ``n`` within the structure."""
389
+
257
390
  ...
258
391
 
259
392
  def __iter__(self) -> Iterable[Any]:
393
+ """Iterate over nodes to allow direct structural traversals."""
394
+
260
395
  ...
261
396
 
262
397
 
@@ -272,6 +407,8 @@ class IntegratorProtocol(Protocol):
272
407
  method: str | None,
273
408
  n_jobs: int | None,
274
409
  ) -> None:
410
+ """Advance the nodal equation for ``graph`` using integrator configuration."""
411
+
275
412
  ...
276
413
 
277
414
 
@@ -293,24 +430,26 @@ class Glyph(str, Enum):
293
430
  REMESH = "REMESH"
294
431
 
295
432
 
433
+ GlyphCode: TypeAlias = Glyph | str
434
+ """Glyph identifier accepted by selector pipelines and grammars."""
435
+
436
+
296
437
  GlyphLoadDistribution: TypeAlias = dict[Glyph | str, float]
297
438
  #: Normalised glyph load proportions keyed by :class:`Glyph` or aggregate labels.
298
439
 
440
+
299
441
  class _SelectorLifecycle(Protocol):
300
442
  """Protocol describing the selector lifecycle supported by the runtime."""
301
443
 
302
- def __call__(self, graph: TNFRGraph, node: NodeId) -> Glyph | str:
303
- ...
444
+ def __call__(self, graph: TNFRGraph, node: NodeId) -> GlyphCode: ...
304
445
 
305
- def prepare(self, graph: TNFRGraph, nodes: Sequence[NodeId]) -> None:
306
- ...
446
+ def prepare(self, graph: TNFRGraph, nodes: Sequence[NodeId]) -> None: ...
307
447
 
308
- def select(self, graph: TNFRGraph, node: NodeId) -> Glyph | str:
309
- ...
448
+ def select(self, graph: TNFRGraph, node: NodeId) -> GlyphCode: ...
310
449
 
311
450
 
312
451
  GlyphSelector: TypeAlias = (
313
- Callable[[TNFRGraph, NodeId], Glyph | str] | _SelectorLifecycle
452
+ Callable[[TNFRGraph, NodeId], GlyphCode] | _SelectorLifecycle
314
453
  )
315
454
  #: Selector callable or object returning the glyph to apply for ``NodeId``.
316
455
 
@@ -335,9 +474,45 @@ TraceFieldMap: TypeAlias = Mapping[str, "TraceFieldFn"]
335
474
  TraceFieldRegistry: TypeAlias = dict[str, dict[str, "TraceFieldFn"]]
336
475
  #: Registry grouping trace field producers by capture phase.
337
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
+
338
501
  HistoryState: TypeAlias = _HistoryDict | dict[str, Any]
339
502
  #: History container used to accumulate glyph metrics and logs for the graph.
340
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
+
341
516
  TraceCallback: TypeAlias = Callable[[TNFRGraph, dict[str, Any]], None]
342
517
  #: Callback signature used by :func:`tnfr.trace.register_trace`.
343
518
 
@@ -381,3 +556,57 @@ NeighborStats: TypeAlias = tuple[
381
556
  Sequence[float] | None,
382
557
  ]
383
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
tnfr/types.pyi CHANGED
@@ -1,7 +1,12 @@
1
- from typing import Any, Callable, ContextManager, Iterable, Protocol, cast
2
- from collections.abc import Hashable, Mapping, Sequence
1
+ from collections.abc import (
2
+ Hashable,
3
+ Mapping,
4
+ MutableMapping,
5
+ MutableSequence,
6
+ Sequence,
7
+ )
3
8
  from enum import Enum
4
- from typing import TypedDict
9
+ from typing import Any, Callable, ContextManager, Iterable, Protocol, TypedDict, cast
5
10
 
6
11
  from ._compat import TypeAlias
7
12
 
@@ -25,20 +30,96 @@ except Exception:
25
30
 
26
31
  np = cast(Any, _FallbackNumpy())
27
32
 
28
- from .tokens import Token
29
- from .trace import TraceMetadata
30
33
  from .glyph_history import HistoryDict as _HistoryDict
31
-
32
- __all__: tuple[str, ...]
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
+ )
33
106
 
34
107
  def __getattr__(name: str) -> Any: ...
35
108
 
36
109
  TNFRGraph: TypeAlias = nx.Graph
37
110
  Graph: TypeAlias = TNFRGraph
111
+ ValidatorFunc: TypeAlias = Callable[[TNFRGraph], None]
38
112
  NodeId: TypeAlias = Hashable
39
113
  Node: TypeAlias = NodeId
114
+ NodeInitAttrMap: TypeAlias = MutableMapping[str, float]
115
+ NodeAttrMap: TypeAlias = Mapping[str, Any]
40
116
  GammaSpec: TypeAlias = Mapping[str, Any]
41
- EPIValue: TypeAlias = float
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, ...]]: ...
42
123
  DeltaNFR: TypeAlias = float
43
124
  SecondDerivativeEPI: TypeAlias = float
44
125
  Phase: TypeAlias = float
@@ -48,8 +129,43 @@ CouplingWeight: TypeAlias = float
48
129
  CoherenceMetric: TypeAlias = float
49
130
  TimingContext: TypeAlias = ContextManager[None]
50
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
51
153
 
52
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
+
53
169
  class SelectorThresholds(TypedDict):
54
170
  si_hi: float
55
171
  si_lo: float
@@ -58,13 +174,11 @@ class SelectorThresholds(TypedDict):
58
174
  accel_hi: float
59
175
  accel_lo: float
60
176
 
61
-
62
177
  class SelectorWeights(TypedDict):
63
178
  w_si: float
64
179
  w_dnfr: float
65
180
  w_accel: float
66
181
 
67
-
68
182
  SelectorMetrics: TypeAlias = tuple[float, float, float]
69
183
  SelectorNorms: TypeAlias = Mapping[str, float]
70
184
 
@@ -107,19 +221,56 @@ class Glyph(str, Enum):
107
221
  NAV = "NAV"
108
222
  REMESH = "REMESH"
109
223
 
224
+ GlyphCode: TypeAlias = Glyph | str
110
225
  GlyphLoadDistribution: TypeAlias = dict[Glyph | str, float]
111
- GlyphSelector: TypeAlias = Callable[[TNFRGraph, NodeId], Glyph | str]
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
112
235
  SelectorPreselectionMetrics: TypeAlias = Mapping[Any, SelectorMetrics]
113
236
  SelectorPreselectionChoices: TypeAlias = Mapping[Any, Glyph | str]
114
237
  SelectorPreselectionPayload: TypeAlias = tuple[
115
238
  SelectorPreselectionMetrics,
116
239
  SelectorPreselectionChoices,
117
240
  ]
118
- TraceFieldFn: TypeAlias = Callable[[TNFRGraph], TraceMetadata]
119
- TraceFieldMap: TypeAlias = Mapping[str, TraceFieldFn]
120
- TraceFieldRegistry: TypeAlias = dict[str, dict[str, TraceFieldFn]]
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
121
261
  HistoryState: TypeAlias = _HistoryDict | dict[str, Any]
122
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
+
123
274
  DiagnosisNodeData: TypeAlias = Mapping[str, Any]
124
275
  DiagnosisSharedState: TypeAlias = Mapping[str, Any]
125
276
  DiagnosisPayload: TypeAlias = dict[str, Any]
@@ -143,3 +294,38 @@ NeighborStats: TypeAlias = tuple[
143
294
  Sequence[float] | None,
144
295
  Sequence[float] | None,
145
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