tnfr 4.5.2__py3-none-any.whl → 6.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.
- tnfr/__init__.py +228 -49
- tnfr/__init__.pyi +40 -0
- tnfr/_compat.py +11 -0
- tnfr/_version.py +7 -0
- tnfr/_version.pyi +7 -0
- tnfr/alias.py +106 -21
- tnfr/alias.pyi +140 -0
- tnfr/cache.py +666 -512
- tnfr/cache.pyi +232 -0
- tnfr/callback_utils.py +2 -9
- tnfr/callback_utils.pyi +105 -0
- tnfr/cli/__init__.py +21 -7
- tnfr/cli/__init__.pyi +47 -0
- tnfr/cli/arguments.py +42 -20
- tnfr/cli/arguments.pyi +33 -0
- tnfr/cli/execution.py +54 -20
- tnfr/cli/execution.pyi +80 -0
- tnfr/cli/utils.py +0 -2
- tnfr/cli/utils.pyi +8 -0
- tnfr/config/__init__.py +12 -0
- tnfr/config/__init__.pyi +8 -0
- tnfr/config/constants.py +104 -0
- tnfr/config/constants.pyi +12 -0
- tnfr/{config.py → config/init.py} +11 -7
- tnfr/config/init.pyi +8 -0
- tnfr/config/operator_names.py +106 -0
- tnfr/config/operator_names.pyi +28 -0
- tnfr/config/presets.py +104 -0
- tnfr/config/presets.pyi +7 -0
- tnfr/constants/__init__.py +78 -24
- tnfr/constants/__init__.pyi +104 -0
- tnfr/constants/core.py +1 -2
- tnfr/constants/core.pyi +17 -0
- tnfr/constants/init.pyi +12 -0
- tnfr/constants/metric.py +4 -12
- tnfr/constants/metric.pyi +19 -0
- tnfr/constants_glyphs.py +9 -91
- tnfr/constants_glyphs.pyi +12 -0
- tnfr/dynamics/__init__.py +112 -634
- tnfr/dynamics/__init__.pyi +83 -0
- tnfr/dynamics/adaptation.py +201 -0
- tnfr/dynamics/aliases.py +22 -0
- tnfr/dynamics/coordination.py +343 -0
- tnfr/dynamics/dnfr.py +1936 -354
- tnfr/dynamics/dnfr.pyi +33 -0
- tnfr/dynamics/integrators.py +369 -75
- tnfr/dynamics/integrators.pyi +35 -0
- tnfr/dynamics/runtime.py +521 -0
- tnfr/dynamics/sampling.py +8 -5
- tnfr/dynamics/sampling.pyi +7 -0
- tnfr/dynamics/selectors.py +680 -0
- tnfr/execution.py +56 -41
- tnfr/execution.pyi +65 -0
- tnfr/flatten.py +7 -7
- tnfr/flatten.pyi +28 -0
- tnfr/gamma.py +54 -37
- tnfr/gamma.pyi +40 -0
- tnfr/glyph_history.py +85 -38
- tnfr/glyph_history.pyi +53 -0
- tnfr/grammar.py +19 -338
- tnfr/grammar.pyi +13 -0
- tnfr/helpers/__init__.py +110 -30
- tnfr/helpers/__init__.pyi +66 -0
- tnfr/helpers/numeric.py +1 -0
- tnfr/helpers/numeric.pyi +12 -0
- tnfr/immutable.py +55 -19
- tnfr/immutable.pyi +37 -0
- tnfr/initialization.py +12 -10
- tnfr/initialization.pyi +73 -0
- tnfr/io.py +99 -34
- tnfr/io.pyi +11 -0
- tnfr/locking.pyi +7 -0
- tnfr/metrics/__init__.pyi +20 -0
- tnfr/metrics/coherence.py +934 -294
- tnfr/metrics/common.py +1 -3
- tnfr/metrics/common.pyi +15 -0
- tnfr/metrics/core.py +192 -34
- tnfr/metrics/core.pyi +13 -0
- tnfr/metrics/diagnosis.py +707 -101
- tnfr/metrics/diagnosis.pyi +89 -0
- tnfr/metrics/export.py +27 -13
- tnfr/metrics/glyph_timing.py +218 -38
- tnfr/metrics/reporting.py +22 -18
- tnfr/metrics/reporting.pyi +12 -0
- tnfr/metrics/sense_index.py +199 -25
- tnfr/metrics/sense_index.pyi +9 -0
- tnfr/metrics/trig.py +53 -18
- tnfr/metrics/trig.pyi +12 -0
- tnfr/metrics/trig_cache.py +3 -7
- tnfr/metrics/trig_cache.pyi +10 -0
- tnfr/node.py +148 -125
- tnfr/node.pyi +161 -0
- tnfr/observers.py +44 -30
- tnfr/observers.pyi +46 -0
- tnfr/ontosim.py +14 -13
- tnfr/ontosim.pyi +33 -0
- tnfr/operators/__init__.py +84 -52
- tnfr/operators/__init__.pyi +31 -0
- tnfr/operators/definitions.py +181 -0
- tnfr/operators/definitions.pyi +92 -0
- tnfr/operators/jitter.py +86 -23
- tnfr/operators/jitter.pyi +11 -0
- tnfr/operators/registry.py +80 -0
- tnfr/operators/registry.pyi +15 -0
- tnfr/operators/remesh.py +141 -57
- tnfr/presets.py +9 -54
- tnfr/presets.pyi +7 -0
- tnfr/py.typed +0 -0
- tnfr/rng.py +259 -73
- tnfr/rng.pyi +14 -0
- tnfr/selector.py +24 -17
- tnfr/selector.pyi +19 -0
- tnfr/sense.py +55 -43
- tnfr/sense.pyi +30 -0
- tnfr/structural.py +44 -267
- tnfr/structural.pyi +46 -0
- tnfr/telemetry/__init__.py +13 -0
- tnfr/telemetry/verbosity.py +37 -0
- tnfr/tokens.py +3 -2
- tnfr/tokens.pyi +41 -0
- tnfr/trace.py +272 -82
- tnfr/trace.pyi +68 -0
- tnfr/types.py +345 -6
- tnfr/types.pyi +145 -0
- tnfr/utils/__init__.py +158 -0
- tnfr/utils/__init__.pyi +133 -0
- tnfr/utils/cache.py +755 -0
- tnfr/utils/cache.pyi +156 -0
- tnfr/{collections_utils.py → utils/data.py} +57 -90
- tnfr/utils/data.pyi +73 -0
- tnfr/utils/graph.py +87 -0
- tnfr/utils/graph.pyi +10 -0
- tnfr/utils/init.py +746 -0
- tnfr/utils/init.pyi +85 -0
- tnfr/{json_utils.py → utils/io.py} +13 -18
- tnfr/utils/io.pyi +10 -0
- tnfr/utils/validators.py +130 -0
- tnfr/utils/validators.pyi +19 -0
- tnfr/validation/__init__.py +25 -0
- tnfr/validation/__init__.pyi +17 -0
- tnfr/validation/compatibility.py +59 -0
- tnfr/validation/compatibility.pyi +8 -0
- tnfr/validation/grammar.py +149 -0
- tnfr/validation/grammar.pyi +11 -0
- tnfr/validation/rules.py +194 -0
- tnfr/validation/rules.pyi +18 -0
- tnfr/validation/syntax.py +151 -0
- tnfr/validation/syntax.pyi +7 -0
- tnfr-6.0.0.dist-info/METADATA +135 -0
- tnfr-6.0.0.dist-info/RECORD +157 -0
- tnfr/graph_utils.py +0 -84
- tnfr/import_utils.py +0 -228
- tnfr/logging_utils.py +0 -116
- tnfr/validators.py +0 -84
- tnfr/value_utils.py +0 -59
- tnfr-4.5.2.dist-info/METADATA +0 -379
- tnfr-4.5.2.dist-info/RECORD +0 -67
- {tnfr-4.5.2.dist-info → tnfr-6.0.0.dist-info}/WHEEL +0 -0
- {tnfr-4.5.2.dist-info → tnfr-6.0.0.dist-info}/entry_points.txt +0 -0
- {tnfr-4.5.2.dist-info → tnfr-6.0.0.dist-info}/licenses/LICENSE.md +0 -0
- {tnfr-4.5.2.dist-info → tnfr-6.0.0.dist-info}/top_level.txt +0 -0
tnfr/structural.pyi
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Callable, Hashable, Iterable
|
|
2
|
+
|
|
3
|
+
from .operators.definitions import (
|
|
4
|
+
Operator,
|
|
5
|
+
Emission,
|
|
6
|
+
Reception,
|
|
7
|
+
Coherence,
|
|
8
|
+
Dissonance,
|
|
9
|
+
Coupling,
|
|
10
|
+
Resonance,
|
|
11
|
+
Silence,
|
|
12
|
+
Expansion,
|
|
13
|
+
Contraction,
|
|
14
|
+
SelfOrganization,
|
|
15
|
+
Mutation,
|
|
16
|
+
Transition,
|
|
17
|
+
Recursivity,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
import networkx as nx
|
|
22
|
+
|
|
23
|
+
__all__: tuple[str, ...]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def __getattr__(name: str) -> Any: ...
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def create_nfr(
|
|
30
|
+
name: str,
|
|
31
|
+
*,
|
|
32
|
+
epi: float = ...,
|
|
33
|
+
vf: float = ...,
|
|
34
|
+
theta: float = ...,
|
|
35
|
+
graph: "nx.Graph" | None = ...,
|
|
36
|
+
dnfr_hook: Callable[..., None] = ...,
|
|
37
|
+
) -> tuple["nx.Graph", str]: ...
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
OPERATORS: dict[str, Operator]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def validate_sequence(names: Iterable[str]) -> tuple[bool, str]: ...
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def run_sequence(G: "nx.Graph", node: Hashable, ops: Iterable[Operator]) -> None: ...
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Telemetry helpers for shared observability settings."""
|
|
2
|
+
|
|
3
|
+
from .verbosity import (
|
|
4
|
+
TelemetryVerbosity,
|
|
5
|
+
TELEMETRY_VERBOSITY_DEFAULT,
|
|
6
|
+
TELEMETRY_VERBOSITY_LEVELS,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"TelemetryVerbosity",
|
|
11
|
+
"TELEMETRY_VERBOSITY_DEFAULT",
|
|
12
|
+
"TELEMETRY_VERBOSITY_LEVELS",
|
|
13
|
+
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Canonical telemetry verbosity presets for TNFR structures.
|
|
2
|
+
|
|
3
|
+
Each level expresses how much structural context is exported in traces and
|
|
4
|
+
metrics:
|
|
5
|
+
|
|
6
|
+
* ``basic`` preserves lightweight coherence checks for quick health probes.
|
|
7
|
+
* ``detailed`` adds phase alignment and coupling diagnostics to map resonance.
|
|
8
|
+
* ``debug`` captures the full glyph narrative for deep structural forensics.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from enum import Enum
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TelemetryVerbosity(str, Enum):
|
|
17
|
+
"""Enumerated verbosity tiers shared by trace and metrics pipelines."""
|
|
18
|
+
|
|
19
|
+
BASIC = "basic"
|
|
20
|
+
DETAILED = "detailed"
|
|
21
|
+
DEBUG = "debug"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
TELEMETRY_VERBOSITY_LEVELS: tuple[str, ...] = tuple(
|
|
25
|
+
level.value for level in TelemetryVerbosity
|
|
26
|
+
)
|
|
27
|
+
"""Ordered tuple of canonical telemetry verbosity identifiers."""
|
|
28
|
+
|
|
29
|
+
TELEMETRY_VERBOSITY_DEFAULT: str = TelemetryVerbosity.DEBUG.value
|
|
30
|
+
"""Default telemetry verbosity preserving complete structural capture."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"TelemetryVerbosity",
|
|
35
|
+
"TELEMETRY_VERBOSITY_LEVELS",
|
|
36
|
+
"TELEMETRY_VERBOSITY_DEFAULT",
|
|
37
|
+
]
|
tnfr/tokens.py
CHANGED
|
@@ -6,9 +6,10 @@ from dataclasses import dataclass
|
|
|
6
6
|
from enum import Enum, auto
|
|
7
7
|
from typing import Any, Iterable, Optional, Sequence, Union
|
|
8
8
|
|
|
9
|
-
from .types import Glyph
|
|
9
|
+
from .types import Glyph, NodeId
|
|
10
10
|
|
|
11
|
-
Node =
|
|
11
|
+
Node = NodeId
|
|
12
|
+
#: Alias maintained for backwards compatibility with historical token helpers.
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
@dataclass(slots=True)
|
tnfr/tokens.pyi
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Iterable, Optional, Sequence
|
|
6
|
+
|
|
7
|
+
from .types import Glyph, NodeId
|
|
8
|
+
from ._compat import TypeAlias
|
|
9
|
+
|
|
10
|
+
__all__: tuple[str, ...]
|
|
11
|
+
|
|
12
|
+
Node: TypeAlias = NodeId
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(slots=True)
|
|
16
|
+
class WAIT:
|
|
17
|
+
steps: int = 1
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(slots=True)
|
|
21
|
+
class TARGET:
|
|
22
|
+
nodes: Optional[Iterable[Node]] = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(slots=True)
|
|
26
|
+
class THOL:
|
|
27
|
+
body: Sequence["Token"]
|
|
28
|
+
repeat: int = 1
|
|
29
|
+
force_close: Optional[Glyph] = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
Token: TypeAlias = Glyph | WAIT | TARGET | THOL | str
|
|
33
|
+
|
|
34
|
+
THOL_SENTINEL: object
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class OpTag(Enum):
|
|
38
|
+
TARGET = ...
|
|
39
|
+
WAIT = ...
|
|
40
|
+
GLYPH = ...
|
|
41
|
+
THOL = ...
|
tnfr/trace.py
CHANGED
|
@@ -7,25 +7,40 @@ structures as immutable snapshots.
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
from typing import Any, Callable, Protocol, NamedTuple, TypedDict, cast
|
|
12
13
|
from collections.abc import Iterable, Mapping
|
|
14
|
+
from types import MappingProxyType
|
|
13
15
|
|
|
14
16
|
from .constants import TRACE
|
|
15
17
|
from .glyph_history import ensure_history, count_glyphs, append_metric
|
|
16
|
-
from .
|
|
17
|
-
from .
|
|
18
|
-
from .
|
|
18
|
+
from .utils import cached_import, get_graph_mapping, is_non_string_sequence
|
|
19
|
+
from .metrics.sense_index import _normalise_si_sensitivity_mapping
|
|
20
|
+
from .telemetry.verbosity import (
|
|
21
|
+
TelemetryVerbosity,
|
|
22
|
+
TELEMETRY_VERBOSITY_DEFAULT,
|
|
23
|
+
)
|
|
24
|
+
from .types import (
|
|
25
|
+
SigmaVector,
|
|
26
|
+
TNFRGraph,
|
|
27
|
+
TraceCallback,
|
|
28
|
+
TraceFieldFn,
|
|
29
|
+
TraceFieldMap,
|
|
30
|
+
TraceFieldRegistry,
|
|
31
|
+
)
|
|
19
32
|
|
|
20
33
|
|
|
21
34
|
class _KuramotoFn(Protocol):
|
|
22
|
-
def __call__(self, G:
|
|
35
|
+
def __call__(self, G: TNFRGraph) -> tuple[float, float]:
|
|
36
|
+
...
|
|
23
37
|
|
|
24
38
|
|
|
25
39
|
class _SigmaVectorFn(Protocol):
|
|
26
40
|
def __call__(
|
|
27
|
-
self, G:
|
|
28
|
-
) ->
|
|
41
|
+
self, G: TNFRGraph, weight_mode: str | None = None
|
|
42
|
+
) -> SigmaVector:
|
|
43
|
+
...
|
|
29
44
|
|
|
30
45
|
|
|
31
46
|
class CallbackSpec(NamedTuple):
|
|
@@ -58,7 +73,77 @@ class TraceSnapshot(TraceMetadata, total=False):
|
|
|
58
73
|
phase: str
|
|
59
74
|
|
|
60
75
|
|
|
61
|
-
|
|
76
|
+
class TraceFieldSpec(NamedTuple):
|
|
77
|
+
"""Declarative specification for a trace field producer."""
|
|
78
|
+
|
|
79
|
+
name: str
|
|
80
|
+
phase: str
|
|
81
|
+
producer: TraceFieldFn
|
|
82
|
+
tiers: tuple[TelemetryVerbosity, ...]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
TRACE_VERBOSITY_DEFAULT = TELEMETRY_VERBOSITY_DEFAULT
|
|
86
|
+
TRACE_VERBOSITY_PRESETS: dict[str, tuple[str, ...]] = {}
|
|
87
|
+
_TRACE_CAPTURE_ALIASES: Mapping[str, str] = MappingProxyType(
|
|
88
|
+
{
|
|
89
|
+
"glyphs": "glyph_counts",
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _canonical_capture_name(name: str) -> str:
|
|
95
|
+
"""Return the canonical capture field name for ``name``."""
|
|
96
|
+
|
|
97
|
+
stripped = name.strip()
|
|
98
|
+
alias = _TRACE_CAPTURE_ALIASES.get(stripped)
|
|
99
|
+
if alias is not None:
|
|
100
|
+
return alias
|
|
101
|
+
|
|
102
|
+
lowered = stripped.lower()
|
|
103
|
+
alias = _TRACE_CAPTURE_ALIASES.get(lowered)
|
|
104
|
+
if alias is not None:
|
|
105
|
+
return alias
|
|
106
|
+
|
|
107
|
+
return stripped
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _normalise_capture_spec(raw: Any) -> set[str]:
|
|
111
|
+
"""Coerce custom capture payloads to a ``set`` of field names."""
|
|
112
|
+
|
|
113
|
+
if raw is None:
|
|
114
|
+
return set()
|
|
115
|
+
if isinstance(raw, Mapping):
|
|
116
|
+
return {_canonical_capture_name(str(name)) for name in raw.keys()}
|
|
117
|
+
if isinstance(raw, str):
|
|
118
|
+
return {_canonical_capture_name(raw)}
|
|
119
|
+
if isinstance(raw, Iterable):
|
|
120
|
+
return {_canonical_capture_name(str(name)) for name in raw}
|
|
121
|
+
return {_canonical_capture_name(str(raw))}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _resolve_trace_capture(cfg: Mapping[str, Any]) -> set[str]:
|
|
125
|
+
"""Return the capture set declared by ``cfg`` respecting verbosity."""
|
|
126
|
+
|
|
127
|
+
if "capture" in cfg:
|
|
128
|
+
return _normalise_capture_spec(cfg.get("capture"))
|
|
129
|
+
|
|
130
|
+
raw_verbosity = cfg.get("verbosity", TRACE_VERBOSITY_DEFAULT)
|
|
131
|
+
verbosity = str(raw_verbosity).lower()
|
|
132
|
+
fields = TRACE_VERBOSITY_PRESETS.get(verbosity)
|
|
133
|
+
if fields is None:
|
|
134
|
+
warnings.warn(
|
|
135
|
+
(
|
|
136
|
+
"Unknown TRACE verbosity %r; falling back to %s"
|
|
137
|
+
% (raw_verbosity, TRACE_VERBOSITY_DEFAULT)
|
|
138
|
+
),
|
|
139
|
+
UserWarning,
|
|
140
|
+
stacklevel=3,
|
|
141
|
+
)
|
|
142
|
+
fields = TRACE_VERBOSITY_PRESETS[TRACE_VERBOSITY_DEFAULT]
|
|
143
|
+
return set(fields)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _kuramoto_fallback(G: TNFRGraph) -> tuple[float, float]:
|
|
62
147
|
return 0.0, 0.0
|
|
63
148
|
|
|
64
149
|
|
|
@@ -69,8 +154,8 @@ kuramoto_R_psi: _KuramotoFn = cast(
|
|
|
69
154
|
|
|
70
155
|
|
|
71
156
|
def _sigma_fallback(
|
|
72
|
-
G:
|
|
73
|
-
) ->
|
|
157
|
+
G: TNFRGraph, _weight_mode: str | None = None
|
|
158
|
+
) -> SigmaVector:
|
|
74
159
|
"""Return a null sigma vector regardless of ``_weight_mode``."""
|
|
75
160
|
|
|
76
161
|
return {"x": 0.0, "y": 0.0, "mag": 0.0, "angle": 0.0, "n": 0}
|
|
@@ -79,6 +164,7 @@ def _sigma_fallback(
|
|
|
79
164
|
# Public exports for this module
|
|
80
165
|
__all__ = (
|
|
81
166
|
"CallbackSpec",
|
|
167
|
+
"TraceFieldSpec",
|
|
82
168
|
"TraceMetadata",
|
|
83
169
|
"TraceSnapshot",
|
|
84
170
|
"register_trace",
|
|
@@ -94,9 +180,12 @@ __all__ = (
|
|
|
94
180
|
|
|
95
181
|
|
|
96
182
|
def _trace_setup(
|
|
97
|
-
G,
|
|
183
|
+
G: TNFRGraph,
|
|
98
184
|
) -> tuple[
|
|
99
|
-
|
|
185
|
+
Mapping[str, Any] | None,
|
|
186
|
+
set[str],
|
|
187
|
+
dict[str, Any] | None,
|
|
188
|
+
str | None,
|
|
100
189
|
]:
|
|
101
190
|
"""Common configuration for trace snapshots.
|
|
102
191
|
|
|
@@ -105,13 +194,14 @@ def _trace_setup(
|
|
|
105
194
|
``(None, set(), None, None)``.
|
|
106
195
|
"""
|
|
107
196
|
|
|
108
|
-
|
|
197
|
+
cfg_raw = G.graph.get("TRACE", TRACE)
|
|
198
|
+
cfg = cfg_raw if isinstance(cfg_raw, Mapping) else TRACE
|
|
109
199
|
if not cfg.get("enabled", True):
|
|
110
200
|
return None, set(), None, None
|
|
111
201
|
|
|
112
|
-
capture
|
|
202
|
+
capture = _resolve_trace_capture(cfg)
|
|
113
203
|
hist = ensure_history(G)
|
|
114
|
-
key = cfg.get("history_key", "trace_meta")
|
|
204
|
+
key = cast(str | None, cfg.get("history_key", "trace_meta"))
|
|
115
205
|
return cfg, capture, hist, key
|
|
116
206
|
|
|
117
207
|
|
|
@@ -129,14 +219,17 @@ def _callback_names(
|
|
|
129
219
|
]
|
|
130
220
|
|
|
131
221
|
|
|
132
|
-
|
|
222
|
+
EMPTY_MAPPING: Mapping[str, Any] = MappingProxyType({})
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def mapping_field(G: TNFRGraph, graph_key: str, out_key: str) -> TraceMetadata:
|
|
133
226
|
"""Helper to copy mappings from ``G.graph`` into trace output."""
|
|
134
227
|
mapping = get_graph_mapping(
|
|
135
|
-
G, graph_key, f"G.graph[{graph_key!r}]
|
|
228
|
+
G, graph_key, f"G.graph[{graph_key!r}] is not a mapping; ignoring"
|
|
136
229
|
)
|
|
137
230
|
if mapping is None:
|
|
138
231
|
return {}
|
|
139
|
-
return
|
|
232
|
+
return {out_key: mapping}
|
|
140
233
|
|
|
141
234
|
|
|
142
235
|
# -------------------------
|
|
@@ -145,10 +238,8 @@ def mapping_field(G: Any, graph_key: str, out_key: str) -> TraceMetadata:
|
|
|
145
238
|
|
|
146
239
|
|
|
147
240
|
def _new_trace_meta(
|
|
148
|
-
G, phase: str
|
|
149
|
-
) ->
|
|
150
|
-
tuple[TraceSnapshot, set[str], Optional[dict[str, Any]], Optional[str]]
|
|
151
|
-
]:
|
|
241
|
+
G: TNFRGraph, phase: str
|
|
242
|
+
) -> tuple[TraceSnapshot, set[str], dict[str, Any] | None, str | None] | None:
|
|
152
243
|
"""Initialise trace metadata for a ``phase``.
|
|
153
244
|
|
|
154
245
|
Wraps :func:`_trace_setup` and creates the base structure with timestamp
|
|
@@ -169,7 +260,7 @@ def _new_trace_meta(
|
|
|
169
260
|
|
|
170
261
|
|
|
171
262
|
def _trace_capture(
|
|
172
|
-
G, phase: str, fields:
|
|
263
|
+
G: TNFRGraph, phase: str, fields: TraceFieldMap
|
|
173
264
|
) -> None:
|
|
174
265
|
"""Capture ``fields`` for ``phase`` and store the snapshot.
|
|
175
266
|
|
|
@@ -187,7 +278,7 @@ def _trace_capture(
|
|
|
187
278
|
return
|
|
188
279
|
for name, getter in fields.items():
|
|
189
280
|
if name in capture:
|
|
190
|
-
meta.update(
|
|
281
|
+
meta.update(getter(G))
|
|
191
282
|
if hist is None or key is None:
|
|
192
283
|
return
|
|
193
284
|
append_metric(hist, key, meta)
|
|
@@ -198,54 +289,68 @@ def _trace_capture(
|
|
|
198
289
|
# -------------------------
|
|
199
290
|
|
|
200
291
|
|
|
201
|
-
TRACE_FIELDS:
|
|
292
|
+
TRACE_FIELDS: TraceFieldRegistry = {}
|
|
202
293
|
|
|
203
294
|
|
|
204
295
|
def register_trace_field(
|
|
205
|
-
phase: str, name: str, func:
|
|
296
|
+
phase: str, name: str, func: TraceFieldFn
|
|
206
297
|
) -> None:
|
|
207
298
|
"""Register ``func`` to populate trace field ``name`` during ``phase``."""
|
|
208
299
|
|
|
209
300
|
TRACE_FIELDS.setdefault(phase, {})[name] = func
|
|
210
301
|
|
|
211
302
|
|
|
212
|
-
gamma_field
|
|
303
|
+
def gamma_field(G: TNFRGraph) -> TraceMetadata:
|
|
304
|
+
return mapping_field(G, "GAMMA", "gamma")
|
|
213
305
|
|
|
214
306
|
|
|
215
|
-
grammar_field
|
|
307
|
+
def grammar_field(G: TNFRGraph) -> TraceMetadata:
|
|
308
|
+
return mapping_field(G, "GRAMMAR_CANON", "grammar")
|
|
216
309
|
|
|
217
310
|
|
|
218
|
-
dnfr_weights_field
|
|
219
|
-
mapping_field,
|
|
220
|
-
)
|
|
311
|
+
def dnfr_weights_field(G: TNFRGraph) -> TraceMetadata:
|
|
312
|
+
return mapping_field(G, "DNFR_WEIGHTS", "dnfr_weights")
|
|
221
313
|
|
|
222
314
|
|
|
223
|
-
def selector_field(G:
|
|
315
|
+
def selector_field(G: TNFRGraph) -> TraceMetadata:
|
|
224
316
|
sel = G.graph.get("glyph_selector")
|
|
225
|
-
|
|
317
|
+
selector_name = getattr(sel, "__name__", str(sel)) if sel else None
|
|
318
|
+
return {"selector": selector_name}
|
|
226
319
|
|
|
227
320
|
|
|
228
|
-
_si_weights_field
|
|
321
|
+
def _si_weights_field(G: TNFRGraph) -> TraceMetadata:
|
|
322
|
+
weights = mapping_field(G, "_Si_weights", "si_weights")
|
|
323
|
+
if weights:
|
|
324
|
+
return weights
|
|
325
|
+
return {"si_weights": EMPTY_MAPPING}
|
|
229
326
|
|
|
230
327
|
|
|
231
|
-
_si_sensitivity_field
|
|
232
|
-
|
|
233
|
-
|
|
328
|
+
def _si_sensitivity_field(G: TNFRGraph) -> TraceMetadata:
|
|
329
|
+
mapping = get_graph_mapping(
|
|
330
|
+
G,
|
|
331
|
+
"_Si_sensitivity",
|
|
332
|
+
"G.graph['_Si_sensitivity'] is not a mapping; ignoring",
|
|
333
|
+
)
|
|
334
|
+
if mapping is None:
|
|
335
|
+
return {"si_sensitivity": EMPTY_MAPPING}
|
|
336
|
+
|
|
337
|
+
normalised = _normalise_si_sensitivity_mapping(mapping, warn=True)
|
|
234
338
|
|
|
339
|
+
if normalised != mapping:
|
|
340
|
+
G.graph["_Si_sensitivity"] = normalised
|
|
235
341
|
|
|
236
|
-
|
|
342
|
+
return {"si_sensitivity": MappingProxyType(normalised)}
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def si_weights_field(G: TNFRGraph) -> TraceMetadata:
|
|
237
346
|
"""Return sense-plane weights and sensitivity."""
|
|
238
347
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
**(_si_weights_field(G) or {"si_weights": {}}),
|
|
243
|
-
**(_si_sensitivity_field(G) or {"si_sensitivity": {}}),
|
|
244
|
-
},
|
|
245
|
-
)
|
|
348
|
+
weights = _si_weights_field(G)
|
|
349
|
+
sensitivity = _si_sensitivity_field(G)
|
|
350
|
+
return {**weights, **sensitivity}
|
|
246
351
|
|
|
247
352
|
|
|
248
|
-
def callbacks_field(G:
|
|
353
|
+
def callbacks_field(G: TNFRGraph) -> TraceMetadata:
|
|
249
354
|
cb = G.graph.get("callbacks")
|
|
250
355
|
if not isinstance(cb, Mapping):
|
|
251
356
|
return {}
|
|
@@ -255,24 +360,24 @@ def callbacks_field(G: Any) -> TraceMetadata:
|
|
|
255
360
|
out[phase] = _callback_names(cb_map)
|
|
256
361
|
else:
|
|
257
362
|
out[phase] = None
|
|
258
|
-
return
|
|
363
|
+
return {"callbacks": out}
|
|
259
364
|
|
|
260
365
|
|
|
261
|
-
def thol_state_field(G:
|
|
366
|
+
def thol_state_field(G: TNFRGraph) -> TraceMetadata:
|
|
262
367
|
th_open = 0
|
|
263
368
|
for _, nd in G.nodes(data=True):
|
|
264
369
|
st = nd.get("_GRAM", {})
|
|
265
370
|
if st.get("thol_open", False):
|
|
266
371
|
th_open += 1
|
|
267
|
-
return
|
|
372
|
+
return {"thol_open_nodes": th_open}
|
|
268
373
|
|
|
269
374
|
|
|
270
|
-
def kuramoto_field(G:
|
|
375
|
+
def kuramoto_field(G: TNFRGraph) -> TraceMetadata:
|
|
271
376
|
R, psi = kuramoto_R_psi(G)
|
|
272
|
-
return
|
|
377
|
+
return {"kuramoto": {"R": float(R), "psi": float(psi)}}
|
|
273
378
|
|
|
274
379
|
|
|
275
|
-
def sigma_field(G:
|
|
380
|
+
def sigma_field(G: TNFRGraph) -> TraceMetadata:
|
|
276
381
|
sigma_vector_from_graph: _SigmaVectorFn = cast(
|
|
277
382
|
_SigmaVectorFn,
|
|
278
383
|
cached_import(
|
|
@@ -282,20 +387,17 @@ def sigma_field(G: Any) -> TraceMetadata:
|
|
|
282
387
|
),
|
|
283
388
|
)
|
|
284
389
|
sv = sigma_vector_from_graph(G)
|
|
285
|
-
return
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
"
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
}
|
|
294
|
-
},
|
|
295
|
-
)
|
|
390
|
+
return {
|
|
391
|
+
"sigma": {
|
|
392
|
+
"x": float(sv.get("x", 0.0)),
|
|
393
|
+
"y": float(sv.get("y", 0.0)),
|
|
394
|
+
"mag": float(sv.get("mag", 0.0)),
|
|
395
|
+
"angle": float(sv.get("angle", 0.0)),
|
|
396
|
+
}
|
|
397
|
+
}
|
|
296
398
|
|
|
297
399
|
|
|
298
|
-
def glyph_counts_field(G:
|
|
400
|
+
def glyph_counts_field(G: TNFRGraph) -> TraceMetadata:
|
|
299
401
|
"""Return glyph count snapshot.
|
|
300
402
|
|
|
301
403
|
``count_glyphs`` already produces a fresh mapping so no additional copy
|
|
@@ -303,21 +405,109 @@ def glyph_counts_field(G: Any) -> TraceMetadata:
|
|
|
303
405
|
"""
|
|
304
406
|
|
|
305
407
|
cnt = count_glyphs(G, window=1)
|
|
306
|
-
return
|
|
307
|
-
|
|
408
|
+
return {"glyphs": cnt}
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
TRACE_FIELD_SPECS: tuple[TraceFieldSpec, ...] = (
|
|
412
|
+
TraceFieldSpec(
|
|
413
|
+
name="gamma",
|
|
414
|
+
phase="before",
|
|
415
|
+
producer=gamma_field,
|
|
416
|
+
tiers=(
|
|
417
|
+
TelemetryVerbosity.BASIC,
|
|
418
|
+
TelemetryVerbosity.DETAILED,
|
|
419
|
+
TelemetryVerbosity.DEBUG,
|
|
420
|
+
),
|
|
421
|
+
),
|
|
422
|
+
TraceFieldSpec(
|
|
423
|
+
name="grammar",
|
|
424
|
+
phase="before",
|
|
425
|
+
producer=grammar_field,
|
|
426
|
+
tiers=(
|
|
427
|
+
TelemetryVerbosity.BASIC,
|
|
428
|
+
TelemetryVerbosity.DETAILED,
|
|
429
|
+
TelemetryVerbosity.DEBUG,
|
|
430
|
+
),
|
|
431
|
+
),
|
|
432
|
+
TraceFieldSpec(
|
|
433
|
+
name="selector",
|
|
434
|
+
phase="before",
|
|
435
|
+
producer=selector_field,
|
|
436
|
+
tiers=(
|
|
437
|
+
TelemetryVerbosity.BASIC,
|
|
438
|
+
TelemetryVerbosity.DETAILED,
|
|
439
|
+
TelemetryVerbosity.DEBUG,
|
|
440
|
+
),
|
|
441
|
+
),
|
|
442
|
+
TraceFieldSpec(
|
|
443
|
+
name="dnfr_weights",
|
|
444
|
+
phase="before",
|
|
445
|
+
producer=dnfr_weights_field,
|
|
446
|
+
tiers=(
|
|
447
|
+
TelemetryVerbosity.BASIC,
|
|
448
|
+
TelemetryVerbosity.DETAILED,
|
|
449
|
+
TelemetryVerbosity.DEBUG,
|
|
450
|
+
),
|
|
451
|
+
),
|
|
452
|
+
TraceFieldSpec(
|
|
453
|
+
name="si_weights",
|
|
454
|
+
phase="before",
|
|
455
|
+
producer=si_weights_field,
|
|
456
|
+
tiers=(
|
|
457
|
+
TelemetryVerbosity.BASIC,
|
|
458
|
+
TelemetryVerbosity.DETAILED,
|
|
459
|
+
TelemetryVerbosity.DEBUG,
|
|
460
|
+
),
|
|
461
|
+
),
|
|
462
|
+
TraceFieldSpec(
|
|
463
|
+
name="callbacks",
|
|
464
|
+
phase="before",
|
|
465
|
+
producer=callbacks_field,
|
|
466
|
+
tiers=(
|
|
467
|
+
TelemetryVerbosity.BASIC,
|
|
468
|
+
TelemetryVerbosity.DETAILED,
|
|
469
|
+
TelemetryVerbosity.DEBUG,
|
|
470
|
+
),
|
|
471
|
+
),
|
|
472
|
+
TraceFieldSpec(
|
|
473
|
+
name="thol_open_nodes",
|
|
474
|
+
phase="before",
|
|
475
|
+
producer=thol_state_field,
|
|
476
|
+
tiers=(
|
|
477
|
+
TelemetryVerbosity.BASIC,
|
|
478
|
+
TelemetryVerbosity.DETAILED,
|
|
479
|
+
TelemetryVerbosity.DEBUG,
|
|
480
|
+
),
|
|
481
|
+
),
|
|
482
|
+
TraceFieldSpec(
|
|
483
|
+
name="kuramoto",
|
|
484
|
+
phase="after",
|
|
485
|
+
producer=kuramoto_field,
|
|
486
|
+
tiers=(TelemetryVerbosity.DETAILED, TelemetryVerbosity.DEBUG),
|
|
487
|
+
),
|
|
488
|
+
TraceFieldSpec(
|
|
489
|
+
name="sigma",
|
|
490
|
+
phase="after",
|
|
491
|
+
producer=sigma_field,
|
|
492
|
+
tiers=(TelemetryVerbosity.DETAILED, TelemetryVerbosity.DEBUG),
|
|
493
|
+
),
|
|
494
|
+
TraceFieldSpec(
|
|
495
|
+
name="glyph_counts",
|
|
496
|
+
phase="after",
|
|
497
|
+
producer=glyph_counts_field,
|
|
498
|
+
tiers=(TelemetryVerbosity.DEBUG,),
|
|
499
|
+
),
|
|
500
|
+
)
|
|
308
501
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
register_trace_field("before", "callbacks", callbacks_field)
|
|
316
|
-
register_trace_field("before", "thol_open_nodes", thol_state_field)
|
|
502
|
+
TRACE_VERBOSITY_PRESETS = {
|
|
503
|
+
level.value: tuple(
|
|
504
|
+
spec.name for spec in TRACE_FIELD_SPECS if level in spec.tiers
|
|
505
|
+
)
|
|
506
|
+
for level in TelemetryVerbosity
|
|
507
|
+
}
|
|
317
508
|
|
|
318
|
-
|
|
319
|
-
register_trace_field(
|
|
320
|
-
register_trace_field("after", "glyph_counts", glyph_counts_field)
|
|
509
|
+
for spec in TRACE_FIELD_SPECS:
|
|
510
|
+
register_trace_field(spec.phase, spec.name, spec.producer)
|
|
321
511
|
|
|
322
512
|
|
|
323
513
|
# -------------------------
|
|
@@ -325,7 +515,7 @@ register_trace_field("after", "glyph_counts", glyph_counts_field)
|
|
|
325
515
|
# -------------------------
|
|
326
516
|
|
|
327
517
|
|
|
328
|
-
def register_trace(G) -> None:
|
|
518
|
+
def register_trace(G: TNFRGraph) -> None:
|
|
329
519
|
"""Enable before/after-step snapshots and dump operational metadata
|
|
330
520
|
to history.
|
|
331
521
|
|
|
@@ -354,11 +544,11 @@ def register_trace(G) -> None:
|
|
|
354
544
|
for phase in TRACE_FIELDS.keys():
|
|
355
545
|
event = f"{phase}_step"
|
|
356
546
|
|
|
357
|
-
def _make_cb(ph):
|
|
358
|
-
def _cb(
|
|
547
|
+
def _make_cb(ph: str) -> TraceCallback:
|
|
548
|
+
def _cb(graph: TNFRGraph, ctx: dict[str, Any]) -> None:
|
|
359
549
|
del ctx
|
|
360
550
|
|
|
361
|
-
_trace_capture(
|
|
551
|
+
_trace_capture(graph, ph, TRACE_FIELDS.get(ph, {}))
|
|
362
552
|
|
|
363
553
|
return _cb
|
|
364
554
|
|