tnfr 4.5.2__py3-none-any.whl → 8.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tnfr might be problematic. Click here for more details.
- tnfr/__init__.py +334 -50
- tnfr/__init__.pyi +33 -0
- tnfr/_compat.py +10 -0
- tnfr/_generated_version.py +34 -0
- tnfr/_version.py +49 -0
- tnfr/_version.pyi +7 -0
- tnfr/alias.py +214 -37
- tnfr/alias.pyi +108 -0
- tnfr/backends/__init__.py +354 -0
- tnfr/backends/jax_backend.py +173 -0
- tnfr/backends/numpy_backend.py +238 -0
- tnfr/backends/optimized_numpy.py +420 -0
- tnfr/backends/torch_backend.py +408 -0
- tnfr/cache.py +149 -556
- tnfr/cache.pyi +13 -0
- tnfr/cli/__init__.py +51 -16
- tnfr/cli/__init__.pyi +26 -0
- tnfr/cli/arguments.py +344 -32
- tnfr/cli/arguments.pyi +29 -0
- tnfr/cli/execution.py +676 -50
- tnfr/cli/execution.pyi +70 -0
- tnfr/cli/interactive_validator.py +614 -0
- tnfr/cli/utils.py +18 -3
- tnfr/cli/utils.pyi +7 -0
- tnfr/cli/validate.py +236 -0
- tnfr/compat/__init__.py +85 -0
- tnfr/compat/dataclass.py +136 -0
- tnfr/compat/jsonschema_stub.py +61 -0
- tnfr/compat/matplotlib_stub.py +73 -0
- tnfr/compat/numpy_stub.py +155 -0
- tnfr/config/__init__.py +224 -0
- tnfr/config/__init__.pyi +10 -0
- tnfr/{constants_glyphs.py → config/constants.py} +26 -20
- tnfr/config/constants.pyi +12 -0
- tnfr/config/defaults.py +54 -0
- tnfr/{constants/core.py → config/defaults_core.py} +59 -6
- tnfr/config/defaults_init.py +33 -0
- tnfr/config/defaults_metric.py +104 -0
- tnfr/config/feature_flags.py +81 -0
- tnfr/config/feature_flags.pyi +16 -0
- tnfr/config/glyph_constants.py +31 -0
- tnfr/config/init.py +77 -0
- tnfr/config/init.pyi +8 -0
- tnfr/config/operator_names.py +254 -0
- tnfr/config/operator_names.pyi +36 -0
- tnfr/config/physics_derivation.py +354 -0
- tnfr/config/presets.py +83 -0
- tnfr/config/presets.pyi +7 -0
- tnfr/config/security.py +927 -0
- tnfr/config/thresholds.py +114 -0
- tnfr/config/tnfr_config.py +498 -0
- tnfr/constants/__init__.py +51 -133
- tnfr/constants/__init__.pyi +92 -0
- tnfr/constants/aliases.py +33 -0
- tnfr/constants/aliases.pyi +27 -0
- tnfr/constants/init.py +3 -1
- tnfr/constants/init.pyi +12 -0
- tnfr/constants/metric.py +9 -15
- tnfr/constants/metric.pyi +19 -0
- tnfr/core/__init__.py +33 -0
- tnfr/core/container.py +226 -0
- tnfr/core/default_implementations.py +329 -0
- tnfr/core/interfaces.py +279 -0
- tnfr/dynamics/__init__.py +213 -633
- tnfr/dynamics/__init__.pyi +83 -0
- tnfr/dynamics/adaptation.py +267 -0
- tnfr/dynamics/adaptation.pyi +7 -0
- tnfr/dynamics/adaptive_sequences.py +189 -0
- tnfr/dynamics/adaptive_sequences.pyi +14 -0
- tnfr/dynamics/aliases.py +23 -0
- tnfr/dynamics/aliases.pyi +19 -0
- tnfr/dynamics/bifurcation.py +232 -0
- tnfr/dynamics/canonical.py +229 -0
- tnfr/dynamics/canonical.pyi +48 -0
- tnfr/dynamics/coordination.py +385 -0
- tnfr/dynamics/coordination.pyi +25 -0
- tnfr/dynamics/dnfr.py +2699 -398
- tnfr/dynamics/dnfr.pyi +26 -0
- tnfr/dynamics/dynamic_limits.py +225 -0
- tnfr/dynamics/feedback.py +252 -0
- tnfr/dynamics/feedback.pyi +24 -0
- tnfr/dynamics/fused_dnfr.py +454 -0
- tnfr/dynamics/homeostasis.py +157 -0
- tnfr/dynamics/homeostasis.pyi +14 -0
- tnfr/dynamics/integrators.py +496 -102
- tnfr/dynamics/integrators.pyi +36 -0
- tnfr/dynamics/learning.py +310 -0
- tnfr/dynamics/learning.pyi +33 -0
- tnfr/dynamics/metabolism.py +254 -0
- tnfr/dynamics/nbody.py +796 -0
- tnfr/dynamics/nbody_tnfr.py +783 -0
- tnfr/dynamics/propagation.py +326 -0
- tnfr/dynamics/runtime.py +908 -0
- tnfr/dynamics/runtime.pyi +77 -0
- tnfr/dynamics/sampling.py +10 -5
- tnfr/dynamics/sampling.pyi +7 -0
- tnfr/dynamics/selectors.py +711 -0
- tnfr/dynamics/selectors.pyi +85 -0
- tnfr/dynamics/structural_clip.py +207 -0
- tnfr/errors/__init__.py +37 -0
- tnfr/errors/contextual.py +492 -0
- tnfr/execution.py +77 -55
- tnfr/execution.pyi +45 -0
- tnfr/extensions/__init__.py +205 -0
- tnfr/extensions/__init__.pyi +18 -0
- tnfr/extensions/base.py +173 -0
- tnfr/extensions/base.pyi +35 -0
- tnfr/extensions/business/__init__.py +71 -0
- tnfr/extensions/business/__init__.pyi +11 -0
- tnfr/extensions/business/cookbook.py +88 -0
- tnfr/extensions/business/cookbook.pyi +8 -0
- tnfr/extensions/business/health_analyzers.py +202 -0
- tnfr/extensions/business/health_analyzers.pyi +9 -0
- tnfr/extensions/business/patterns.py +183 -0
- tnfr/extensions/business/patterns.pyi +8 -0
- tnfr/extensions/medical/__init__.py +73 -0
- tnfr/extensions/medical/__init__.pyi +11 -0
- tnfr/extensions/medical/cookbook.py +88 -0
- tnfr/extensions/medical/cookbook.pyi +8 -0
- tnfr/extensions/medical/health_analyzers.py +181 -0
- tnfr/extensions/medical/health_analyzers.pyi +9 -0
- tnfr/extensions/medical/patterns.py +163 -0
- tnfr/extensions/medical/patterns.pyi +8 -0
- tnfr/flatten.py +29 -50
- tnfr/flatten.pyi +21 -0
- tnfr/gamma.py +66 -53
- tnfr/gamma.pyi +36 -0
- tnfr/glyph_history.py +144 -57
- tnfr/glyph_history.pyi +35 -0
- tnfr/glyph_runtime.py +19 -0
- tnfr/glyph_runtime.pyi +8 -0
- tnfr/immutable.py +70 -30
- tnfr/immutable.pyi +36 -0
- tnfr/initialization.py +22 -16
- tnfr/initialization.pyi +65 -0
- tnfr/io.py +5 -241
- tnfr/io.pyi +13 -0
- tnfr/locking.pyi +7 -0
- tnfr/mathematics/__init__.py +79 -0
- tnfr/mathematics/backend.py +453 -0
- tnfr/mathematics/backend.pyi +99 -0
- tnfr/mathematics/dynamics.py +408 -0
- tnfr/mathematics/dynamics.pyi +90 -0
- tnfr/mathematics/epi.py +391 -0
- tnfr/mathematics/epi.pyi +65 -0
- tnfr/mathematics/generators.py +242 -0
- tnfr/mathematics/generators.pyi +29 -0
- tnfr/mathematics/metrics.py +119 -0
- tnfr/mathematics/metrics.pyi +16 -0
- tnfr/mathematics/operators.py +239 -0
- tnfr/mathematics/operators.pyi +59 -0
- tnfr/mathematics/operators_factory.py +124 -0
- tnfr/mathematics/operators_factory.pyi +11 -0
- tnfr/mathematics/projection.py +87 -0
- tnfr/mathematics/projection.pyi +33 -0
- tnfr/mathematics/runtime.py +182 -0
- tnfr/mathematics/runtime.pyi +64 -0
- tnfr/mathematics/spaces.py +256 -0
- tnfr/mathematics/spaces.pyi +83 -0
- tnfr/mathematics/transforms.py +305 -0
- tnfr/mathematics/transforms.pyi +62 -0
- tnfr/metrics/__init__.py +47 -9
- tnfr/metrics/__init__.pyi +20 -0
- tnfr/metrics/buffer_cache.py +163 -0
- tnfr/metrics/buffer_cache.pyi +24 -0
- tnfr/metrics/cache_utils.py +214 -0
- tnfr/metrics/coherence.py +1510 -330
- tnfr/metrics/coherence.pyi +129 -0
- tnfr/metrics/common.py +23 -16
- tnfr/metrics/common.pyi +35 -0
- tnfr/metrics/core.py +251 -36
- tnfr/metrics/core.pyi +13 -0
- tnfr/metrics/diagnosis.py +709 -110
- tnfr/metrics/diagnosis.pyi +86 -0
- tnfr/metrics/emergence.py +245 -0
- tnfr/metrics/export.py +60 -18
- tnfr/metrics/export.pyi +7 -0
- tnfr/metrics/glyph_timing.py +233 -43
- tnfr/metrics/glyph_timing.pyi +81 -0
- tnfr/metrics/learning_metrics.py +280 -0
- tnfr/metrics/learning_metrics.pyi +21 -0
- tnfr/metrics/phase_coherence.py +351 -0
- tnfr/metrics/phase_compatibility.py +349 -0
- tnfr/metrics/reporting.py +63 -28
- tnfr/metrics/reporting.pyi +25 -0
- tnfr/metrics/sense_index.py +1126 -43
- tnfr/metrics/sense_index.pyi +9 -0
- tnfr/metrics/trig.py +215 -23
- tnfr/metrics/trig.pyi +13 -0
- tnfr/metrics/trig_cache.py +148 -24
- tnfr/metrics/trig_cache.pyi +10 -0
- tnfr/multiscale/__init__.py +32 -0
- tnfr/multiscale/hierarchical.py +517 -0
- tnfr/node.py +646 -140
- tnfr/node.pyi +139 -0
- tnfr/observers.py +160 -45
- tnfr/observers.pyi +31 -0
- tnfr/ontosim.py +23 -19
- tnfr/ontosim.pyi +28 -0
- tnfr/operators/__init__.py +1358 -106
- tnfr/operators/__init__.pyi +31 -0
- tnfr/operators/algebra.py +277 -0
- tnfr/operators/canonical_patterns.py +420 -0
- tnfr/operators/cascade.py +267 -0
- tnfr/operators/cycle_detection.py +358 -0
- tnfr/operators/definitions.py +4108 -0
- tnfr/operators/definitions.pyi +78 -0
- tnfr/operators/grammar.py +1164 -0
- tnfr/operators/grammar.pyi +140 -0
- tnfr/operators/hamiltonian.py +710 -0
- tnfr/operators/health_analyzer.py +809 -0
- tnfr/operators/jitter.py +107 -38
- tnfr/operators/jitter.pyi +11 -0
- tnfr/operators/lifecycle.py +314 -0
- tnfr/operators/metabolism.py +618 -0
- tnfr/operators/metrics.py +2138 -0
- tnfr/operators/network_analysis/__init__.py +27 -0
- tnfr/operators/network_analysis/source_detection.py +186 -0
- tnfr/operators/nodal_equation.py +395 -0
- tnfr/operators/pattern_detection.py +660 -0
- tnfr/operators/patterns.py +669 -0
- tnfr/operators/postconditions/__init__.py +38 -0
- tnfr/operators/postconditions/mutation.py +236 -0
- tnfr/operators/preconditions/__init__.py +1226 -0
- tnfr/operators/preconditions/coherence.py +305 -0
- tnfr/operators/preconditions/dissonance.py +236 -0
- tnfr/operators/preconditions/emission.py +128 -0
- tnfr/operators/preconditions/mutation.py +580 -0
- tnfr/operators/preconditions/reception.py +125 -0
- tnfr/operators/preconditions/resonance.py +364 -0
- tnfr/operators/registry.py +74 -0
- tnfr/operators/registry.pyi +9 -0
- tnfr/operators/remesh.py +1415 -91
- tnfr/operators/remesh.pyi +26 -0
- tnfr/operators/structural_units.py +268 -0
- tnfr/operators/unified_grammar.py +105 -0
- tnfr/parallel/__init__.py +54 -0
- tnfr/parallel/auto_scaler.py +234 -0
- tnfr/parallel/distributed.py +384 -0
- tnfr/parallel/engine.py +238 -0
- tnfr/parallel/gpu_engine.py +420 -0
- tnfr/parallel/monitoring.py +248 -0
- tnfr/parallel/partitioner.py +459 -0
- tnfr/py.typed +0 -0
- tnfr/recipes/__init__.py +22 -0
- tnfr/recipes/cookbook.py +743 -0
- tnfr/rng.py +75 -151
- tnfr/rng.pyi +26 -0
- tnfr/schemas/__init__.py +8 -0
- tnfr/schemas/grammar.json +94 -0
- tnfr/sdk/__init__.py +107 -0
- tnfr/sdk/__init__.pyi +19 -0
- tnfr/sdk/adaptive_system.py +173 -0
- tnfr/sdk/adaptive_system.pyi +21 -0
- tnfr/sdk/builders.py +370 -0
- tnfr/sdk/builders.pyi +51 -0
- tnfr/sdk/fluent.py +1121 -0
- tnfr/sdk/fluent.pyi +74 -0
- tnfr/sdk/templates.py +342 -0
- tnfr/sdk/templates.pyi +41 -0
- tnfr/sdk/utils.py +341 -0
- tnfr/secure_config.py +46 -0
- tnfr/security/__init__.py +70 -0
- tnfr/security/database.py +514 -0
- tnfr/security/subprocess.py +503 -0
- tnfr/security/validation.py +290 -0
- tnfr/selector.py +59 -22
- tnfr/selector.pyi +19 -0
- tnfr/sense.py +92 -67
- tnfr/sense.pyi +23 -0
- tnfr/services/__init__.py +17 -0
- tnfr/services/orchestrator.py +325 -0
- tnfr/sparse/__init__.py +39 -0
- tnfr/sparse/representations.py +492 -0
- tnfr/structural.py +639 -263
- tnfr/structural.pyi +83 -0
- tnfr/telemetry/__init__.py +35 -0
- tnfr/telemetry/cache_metrics.py +226 -0
- tnfr/telemetry/cache_metrics.pyi +64 -0
- tnfr/telemetry/nu_f.py +422 -0
- tnfr/telemetry/nu_f.pyi +108 -0
- tnfr/telemetry/verbosity.py +36 -0
- tnfr/telemetry/verbosity.pyi +15 -0
- tnfr/tokens.py +2 -4
- tnfr/tokens.pyi +36 -0
- tnfr/tools/__init__.py +20 -0
- tnfr/tools/domain_templates.py +478 -0
- tnfr/tools/sequence_generator.py +846 -0
- tnfr/topology/__init__.py +13 -0
- tnfr/topology/asymmetry.py +151 -0
- tnfr/trace.py +300 -126
- tnfr/trace.pyi +42 -0
- tnfr/tutorials/__init__.py +38 -0
- tnfr/tutorials/autonomous_evolution.py +285 -0
- tnfr/tutorials/interactive.py +1576 -0
- tnfr/tutorials/structural_metabolism.py +238 -0
- tnfr/types.py +743 -12
- tnfr/types.pyi +357 -0
- tnfr/units.py +68 -0
- tnfr/units.pyi +13 -0
- tnfr/utils/__init__.py +282 -0
- tnfr/utils/__init__.pyi +215 -0
- tnfr/utils/cache.py +4223 -0
- tnfr/utils/cache.pyi +470 -0
- tnfr/{callback_utils.py → utils/callbacks.py} +26 -39
- tnfr/utils/callbacks.pyi +49 -0
- tnfr/utils/chunks.py +108 -0
- tnfr/utils/chunks.pyi +22 -0
- tnfr/utils/data.py +428 -0
- tnfr/utils/data.pyi +74 -0
- tnfr/utils/graph.py +85 -0
- tnfr/utils/graph.pyi +10 -0
- tnfr/utils/init.py +821 -0
- tnfr/utils/init.pyi +80 -0
- tnfr/utils/io.py +559 -0
- tnfr/utils/io.pyi +66 -0
- tnfr/{helpers → utils}/numeric.py +51 -24
- tnfr/utils/numeric.pyi +21 -0
- tnfr/validation/__init__.py +257 -0
- tnfr/validation/__init__.pyi +85 -0
- tnfr/validation/compatibility.py +460 -0
- tnfr/validation/compatibility.pyi +6 -0
- tnfr/validation/config.py +73 -0
- tnfr/validation/graph.py +139 -0
- tnfr/validation/graph.pyi +18 -0
- tnfr/validation/input_validation.py +755 -0
- tnfr/validation/invariants.py +712 -0
- tnfr/validation/rules.py +253 -0
- tnfr/validation/rules.pyi +44 -0
- tnfr/validation/runtime.py +279 -0
- tnfr/validation/runtime.pyi +28 -0
- tnfr/validation/sequence_validator.py +162 -0
- tnfr/validation/soft_filters.py +170 -0
- tnfr/validation/soft_filters.pyi +32 -0
- tnfr/validation/spectral.py +164 -0
- tnfr/validation/spectral.pyi +42 -0
- tnfr/validation/validator.py +1266 -0
- tnfr/validation/window.py +39 -0
- tnfr/validation/window.pyi +1 -0
- tnfr/visualization/__init__.py +98 -0
- tnfr/visualization/cascade_viz.py +256 -0
- tnfr/visualization/hierarchy.py +284 -0
- tnfr/visualization/sequence_plotter.py +784 -0
- tnfr/viz/__init__.py +60 -0
- tnfr/viz/matplotlib.py +278 -0
- tnfr/viz/matplotlib.pyi +35 -0
- tnfr-8.5.0.dist-info/METADATA +573 -0
- tnfr-8.5.0.dist-info/RECORD +353 -0
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/entry_points.txt +1 -0
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/licenses/LICENSE.md +1 -1
- tnfr/collections_utils.py +0 -300
- tnfr/config.py +0 -32
- tnfr/grammar.py +0 -344
- tnfr/graph_utils.py +0 -84
- tnfr/helpers/__init__.py +0 -71
- tnfr/import_utils.py +0 -228
- tnfr/json_utils.py +0 -162
- tnfr/logging_utils.py +0 -116
- tnfr/presets.py +0 -60
- 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-8.5.0.dist-info}/WHEEL +0 -0
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/top_level.txt +0 -0
tnfr/trace.py
CHANGED
|
@@ -3,62 +3,139 @@
|
|
|
3
3
|
Field helpers avoid unnecessary copying by reusing dictionaries stored on
|
|
4
4
|
the graph whenever possible. Callers are expected to treat returned
|
|
5
5
|
structures as immutable snapshots.
|
|
6
|
+
|
|
7
|
+
Immutability Guarantees
|
|
8
|
+
-----------------------
|
|
9
|
+
Trace field producers return mappings wrapped in ``MappingProxyType`` to
|
|
10
|
+
prevent accidental mutation. These proxies enforce immutability while avoiding
|
|
11
|
+
unnecessary data copying. Consumers that need to modify trace data should
|
|
12
|
+
create mutable copies using ``dict(proxy)`` or merge patterns like
|
|
13
|
+
``{**proxy1, **proxy2, "new_key": value}``.
|
|
14
|
+
|
|
15
|
+
Example safe mutation patterns::
|
|
16
|
+
|
|
17
|
+
# Get immutable trace data
|
|
18
|
+
result = gamma_field(G)
|
|
19
|
+
gamma_proxy = result["gamma"]
|
|
20
|
+
|
|
21
|
+
# Cannot mutate directly (TypeError will be raised)
|
|
22
|
+
# gamma_proxy["new_key"] = value # ❌ Error!
|
|
23
|
+
|
|
24
|
+
# Safe pattern: create mutable copy
|
|
25
|
+
mutable = dict(gamma_proxy)
|
|
26
|
+
mutable["new_key"] = value # ✓ OK
|
|
27
|
+
|
|
28
|
+
# Safe pattern: merge with new data
|
|
29
|
+
combined = {**gamma_proxy, "new_key": value} # ✓ OK
|
|
6
30
|
"""
|
|
7
31
|
|
|
8
32
|
from __future__ import annotations
|
|
9
33
|
|
|
10
|
-
|
|
11
|
-
from typing import Any, Callable, Optional, Protocol, NamedTuple, TypedDict, cast
|
|
34
|
+
import warnings
|
|
12
35
|
from collections.abc import Iterable, Mapping
|
|
36
|
+
from types import MappingProxyType
|
|
37
|
+
from typing import Any, NamedTuple, Protocol, cast
|
|
13
38
|
|
|
14
39
|
from .constants import TRACE
|
|
15
|
-
from .glyph_history import
|
|
16
|
-
from .
|
|
17
|
-
from .
|
|
18
|
-
|
|
40
|
+
from .glyph_history import append_metric, count_glyphs, ensure_history
|
|
41
|
+
from .metrics.sense_index import _normalise_si_sensitivity_mapping
|
|
42
|
+
from .telemetry.verbosity import (
|
|
43
|
+
TELEMETRY_VERBOSITY_DEFAULT,
|
|
44
|
+
TelemetryVerbosity,
|
|
45
|
+
)
|
|
46
|
+
from .types import (
|
|
47
|
+
SigmaVector,
|
|
48
|
+
TNFRGraph,
|
|
49
|
+
TraceCallback,
|
|
50
|
+
TraceFieldFn,
|
|
51
|
+
TraceFieldMap,
|
|
52
|
+
TraceFieldRegistry,
|
|
53
|
+
TraceMetadata,
|
|
54
|
+
TraceSnapshot,
|
|
55
|
+
)
|
|
56
|
+
from .utils import cached_import, get_graph_mapping, is_non_string_sequence
|
|
57
|
+
from .utils.callbacks import CallbackSpec
|
|
19
58
|
|
|
20
59
|
|
|
21
60
|
class _KuramotoFn(Protocol):
|
|
22
|
-
def __call__(self, G:
|
|
61
|
+
def __call__(self, G: TNFRGraph) -> tuple[float, float]: ...
|
|
23
62
|
|
|
24
63
|
|
|
25
64
|
class _SigmaVectorFn(Protocol):
|
|
26
|
-
def __call__(
|
|
27
|
-
|
|
28
|
-
|
|
65
|
+
def __call__(self, G: TNFRGraph, weight_mode: str | None = None) -> SigmaVector: ...
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class TraceFieldSpec(NamedTuple):
|
|
69
|
+
"""Declarative specification for a trace field producer."""
|
|
29
70
|
|
|
71
|
+
name: str
|
|
72
|
+
phase: str
|
|
73
|
+
producer: TraceFieldFn
|
|
74
|
+
tiers: tuple[TelemetryVerbosity, ...]
|
|
30
75
|
|
|
31
|
-
class CallbackSpec(NamedTuple):
|
|
32
|
-
"""Specification for a registered callback."""
|
|
33
76
|
|
|
34
|
-
|
|
35
|
-
|
|
77
|
+
TRACE_VERBOSITY_DEFAULT = TELEMETRY_VERBOSITY_DEFAULT
|
|
78
|
+
TRACE_VERBOSITY_PRESETS: dict[str, tuple[str, ...]] = {}
|
|
79
|
+
_TRACE_CAPTURE_ALIASES: Mapping[str, str] = MappingProxyType(
|
|
80
|
+
{
|
|
81
|
+
"glyphs": "glyph_counts",
|
|
82
|
+
}
|
|
83
|
+
)
|
|
36
84
|
|
|
37
85
|
|
|
38
|
-
|
|
39
|
-
"""
|
|
86
|
+
def _canonical_capture_name(name: str) -> str:
|
|
87
|
+
"""Return the canonical capture field name for ``name``."""
|
|
40
88
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
si_weights: Mapping[str, Any]
|
|
46
|
-
si_sensitivity: Mapping[str, Any]
|
|
47
|
-
callbacks: Mapping[str, list[str] | None]
|
|
48
|
-
thol_open_nodes: int
|
|
49
|
-
kuramoto: Mapping[str, float]
|
|
50
|
-
sigma: Mapping[str, float]
|
|
51
|
-
glyphs: Mapping[str, int]
|
|
89
|
+
stripped = name.strip()
|
|
90
|
+
alias = _TRACE_CAPTURE_ALIASES.get(stripped)
|
|
91
|
+
if alias is not None:
|
|
92
|
+
return alias
|
|
52
93
|
|
|
94
|
+
lowered = stripped.lower()
|
|
95
|
+
alias = _TRACE_CAPTURE_ALIASES.get(lowered)
|
|
96
|
+
if alias is not None:
|
|
97
|
+
return alias
|
|
53
98
|
|
|
54
|
-
|
|
55
|
-
"""Trace snapshot stored in the history."""
|
|
99
|
+
return stripped
|
|
56
100
|
|
|
57
|
-
t: float
|
|
58
|
-
phase: str
|
|
59
101
|
|
|
102
|
+
def _normalise_capture_spec(raw: Any) -> set[str]:
|
|
103
|
+
"""Coerce custom capture payloads to a ``set`` of field names."""
|
|
60
104
|
|
|
61
|
-
|
|
105
|
+
if raw is None:
|
|
106
|
+
return set()
|
|
107
|
+
if isinstance(raw, Mapping):
|
|
108
|
+
return {_canonical_capture_name(str(name)) for name in raw.keys()}
|
|
109
|
+
if isinstance(raw, str):
|
|
110
|
+
return {_canonical_capture_name(raw)}
|
|
111
|
+
if isinstance(raw, Iterable):
|
|
112
|
+
return {_canonical_capture_name(str(name)) for name in raw}
|
|
113
|
+
return {_canonical_capture_name(str(raw))}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _resolve_trace_capture(cfg: Mapping[str, Any]) -> set[str]:
|
|
117
|
+
"""Return the capture set declared by ``cfg`` respecting verbosity."""
|
|
118
|
+
|
|
119
|
+
if "capture" in cfg:
|
|
120
|
+
return _normalise_capture_spec(cfg.get("capture"))
|
|
121
|
+
|
|
122
|
+
raw_verbosity = cfg.get("verbosity", TRACE_VERBOSITY_DEFAULT)
|
|
123
|
+
verbosity = str(raw_verbosity).lower()
|
|
124
|
+
fields = TRACE_VERBOSITY_PRESETS.get(verbosity)
|
|
125
|
+
if fields is None:
|
|
126
|
+
warnings.warn(
|
|
127
|
+
(
|
|
128
|
+
"Unknown TRACE verbosity %r; falling back to %s"
|
|
129
|
+
% (raw_verbosity, TRACE_VERBOSITY_DEFAULT)
|
|
130
|
+
),
|
|
131
|
+
UserWarning,
|
|
132
|
+
stacklevel=3,
|
|
133
|
+
)
|
|
134
|
+
fields = TRACE_VERBOSITY_PRESETS[TRACE_VERBOSITY_DEFAULT]
|
|
135
|
+
return set(fields)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _kuramoto_fallback(G: TNFRGraph) -> tuple[float, float]:
|
|
62
139
|
return 0.0, 0.0
|
|
63
140
|
|
|
64
141
|
|
|
@@ -68,9 +145,7 @@ kuramoto_R_psi: _KuramotoFn = cast(
|
|
|
68
145
|
)
|
|
69
146
|
|
|
70
147
|
|
|
71
|
-
def _sigma_fallback(
|
|
72
|
-
G: Any, _weight_mode: str | None = None
|
|
73
|
-
) -> dict[str, float]:
|
|
148
|
+
def _sigma_fallback(G: TNFRGraph, _weight_mode: str | None = None) -> SigmaVector:
|
|
74
149
|
"""Return a null sigma vector regardless of ``_weight_mode``."""
|
|
75
150
|
|
|
76
151
|
return {"x": 0.0, "y": 0.0, "mag": 0.0, "angle": 0.0, "n": 0}
|
|
@@ -79,6 +154,7 @@ def _sigma_fallback(
|
|
|
79
154
|
# Public exports for this module
|
|
80
155
|
__all__ = (
|
|
81
156
|
"CallbackSpec",
|
|
157
|
+
"TraceFieldSpec",
|
|
82
158
|
"TraceMetadata",
|
|
83
159
|
"TraceSnapshot",
|
|
84
160
|
"register_trace",
|
|
@@ -94,24 +170,28 @@ __all__ = (
|
|
|
94
170
|
|
|
95
171
|
|
|
96
172
|
def _trace_setup(
|
|
97
|
-
G,
|
|
173
|
+
G: TNFRGraph,
|
|
98
174
|
) -> tuple[
|
|
99
|
-
|
|
175
|
+
Mapping[str, Any] | None,
|
|
176
|
+
set[str],
|
|
177
|
+
dict[str, Any] | None,
|
|
178
|
+
str | None,
|
|
100
179
|
]:
|
|
101
|
-
"""
|
|
180
|
+
"""Prepare common configuration for trace snapshots.
|
|
102
181
|
|
|
103
182
|
Returns the active configuration, capture set, history and key under
|
|
104
183
|
which metadata will be stored. If tracing is disabled returns
|
|
105
184
|
``(None, set(), None, None)``.
|
|
106
185
|
"""
|
|
107
186
|
|
|
108
|
-
|
|
187
|
+
cfg_raw = G.graph.get("TRACE", TRACE)
|
|
188
|
+
cfg = cfg_raw if isinstance(cfg_raw, Mapping) else TRACE
|
|
109
189
|
if not cfg.get("enabled", True):
|
|
110
190
|
return None, set(), None, None
|
|
111
191
|
|
|
112
|
-
capture
|
|
192
|
+
capture = _resolve_trace_capture(cfg)
|
|
113
193
|
hist = ensure_history(G)
|
|
114
|
-
key = cfg.get("history_key", "trace_meta")
|
|
194
|
+
key = cast(str | None, cfg.get("history_key", "trace_meta"))
|
|
115
195
|
return cfg, capture, hist, key
|
|
116
196
|
|
|
117
197
|
|
|
@@ -122,21 +202,22 @@ def _callback_names(
|
|
|
122
202
|
if isinstance(callbacks, Mapping):
|
|
123
203
|
callbacks = callbacks.values()
|
|
124
204
|
return [
|
|
125
|
-
cb.name
|
|
126
|
-
if cb.name is not None
|
|
127
|
-
else str(getattr(cb.func, "__name__", "fn"))
|
|
205
|
+
cb.name if cb.name is not None else str(getattr(cb.func, "__name__", "fn"))
|
|
128
206
|
for cb in callbacks
|
|
129
207
|
]
|
|
130
208
|
|
|
131
209
|
|
|
132
|
-
|
|
133
|
-
|
|
210
|
+
EMPTY_MAPPING: Mapping[str, Any] = MappingProxyType({})
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def mapping_field(G: TNFRGraph, graph_key: str, out_key: str) -> TraceMetadata:
|
|
214
|
+
"""Copy mappings from ``G.graph`` into trace output."""
|
|
134
215
|
mapping = get_graph_mapping(
|
|
135
|
-
G, graph_key, f"G.graph[{graph_key!r}]
|
|
216
|
+
G, graph_key, f"G.graph[{graph_key!r}] is not a mapping; ignoring"
|
|
136
217
|
)
|
|
137
218
|
if mapping is None:
|
|
138
219
|
return {}
|
|
139
|
-
return
|
|
220
|
+
return {out_key: mapping}
|
|
140
221
|
|
|
141
222
|
|
|
142
223
|
# -------------------------
|
|
@@ -145,10 +226,8 @@ def mapping_field(G: Any, graph_key: str, out_key: str) -> TraceMetadata:
|
|
|
145
226
|
|
|
146
227
|
|
|
147
228
|
def _new_trace_meta(
|
|
148
|
-
G, phase: str
|
|
149
|
-
) ->
|
|
150
|
-
tuple[TraceSnapshot, set[str], Optional[dict[str, Any]], Optional[str]]
|
|
151
|
-
]:
|
|
229
|
+
G: TNFRGraph, phase: str
|
|
230
|
+
) -> tuple[TraceSnapshot, set[str], dict[str, Any] | None, str | None] | None:
|
|
152
231
|
"""Initialise trace metadata for a ``phase``.
|
|
153
232
|
|
|
154
233
|
Wraps :func:`_trace_setup` and creates the base structure with timestamp
|
|
@@ -168,9 +247,7 @@ def _new_trace_meta(
|
|
|
168
247
|
# -------------------------
|
|
169
248
|
|
|
170
249
|
|
|
171
|
-
def _trace_capture(
|
|
172
|
-
G, phase: str, fields: Mapping[str, Callable[[Any], TraceMetadata]]
|
|
173
|
-
) -> None:
|
|
250
|
+
def _trace_capture(G: TNFRGraph, phase: str, fields: TraceFieldMap) -> None:
|
|
174
251
|
"""Capture ``fields`` for ``phase`` and store the snapshot.
|
|
175
252
|
|
|
176
253
|
A :class:`TraceSnapshot` is appended to the configured history when
|
|
@@ -187,7 +264,7 @@ def _trace_capture(
|
|
|
187
264
|
return
|
|
188
265
|
for name, getter in fields.items():
|
|
189
266
|
if name in capture:
|
|
190
|
-
meta.update(
|
|
267
|
+
meta.update(getter(G))
|
|
191
268
|
if hist is None or key is None:
|
|
192
269
|
return
|
|
193
270
|
append_metric(hist, key, meta)
|
|
@@ -197,55 +274,70 @@ def _trace_capture(
|
|
|
197
274
|
# Registry
|
|
198
275
|
# -------------------------
|
|
199
276
|
|
|
200
|
-
|
|
201
|
-
TRACE_FIELDS: dict[str, dict[str, Callable[[Any], TraceMetadata]]] = {}
|
|
277
|
+
TRACE_FIELDS: TraceFieldRegistry = {}
|
|
202
278
|
|
|
203
279
|
|
|
204
|
-
def register_trace_field(
|
|
205
|
-
phase: str, name: str, func: Callable[[Any], TraceMetadata]
|
|
206
|
-
) -> None:
|
|
280
|
+
def register_trace_field(phase: str, name: str, func: TraceFieldFn) -> None:
|
|
207
281
|
"""Register ``func`` to populate trace field ``name`` during ``phase``."""
|
|
208
282
|
|
|
209
283
|
TRACE_FIELDS.setdefault(phase, {})[name] = func
|
|
210
284
|
|
|
211
285
|
|
|
212
|
-
gamma_field
|
|
286
|
+
def gamma_field(G: TNFRGraph) -> TraceMetadata:
|
|
287
|
+
"""Expose γ-field metadata stored under ``G.graph['GAMMA']``."""
|
|
213
288
|
|
|
289
|
+
return mapping_field(G, "GAMMA", "gamma")
|
|
214
290
|
|
|
215
|
-
grammar_field = partial(mapping_field, graph_key="GRAMMAR_CANON", out_key="grammar")
|
|
216
291
|
|
|
292
|
+
def grammar_field(G: TNFRGraph) -> TraceMetadata:
|
|
293
|
+
"""Expose canonical grammar metadata for trace emission."""
|
|
217
294
|
|
|
218
|
-
|
|
219
|
-
mapping_field, graph_key="DNFR_WEIGHTS", out_key="dnfr_weights"
|
|
220
|
-
)
|
|
295
|
+
return mapping_field(G, "GRAMMAR_CANON", "grammar")
|
|
221
296
|
|
|
222
297
|
|
|
223
|
-
def
|
|
298
|
+
def dnfr_weights_field(G: TNFRGraph) -> TraceMetadata:
|
|
299
|
+
return mapping_field(G, "DNFR_WEIGHTS", "dnfr_weights")
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def selector_field(G: TNFRGraph) -> TraceMetadata:
|
|
224
303
|
sel = G.graph.get("glyph_selector")
|
|
225
|
-
|
|
304
|
+
selector_name = getattr(sel, "__name__", str(sel)) if sel else None
|
|
305
|
+
return {"selector": selector_name}
|
|
226
306
|
|
|
227
307
|
|
|
228
|
-
_si_weights_field
|
|
308
|
+
def _si_weights_field(G: TNFRGraph) -> TraceMetadata:
|
|
309
|
+
weights = mapping_field(G, "_Si_weights", "si_weights")
|
|
310
|
+
if weights:
|
|
311
|
+
return weights
|
|
312
|
+
return {"si_weights": EMPTY_MAPPING}
|
|
229
313
|
|
|
230
314
|
|
|
231
|
-
_si_sensitivity_field
|
|
232
|
-
|
|
233
|
-
|
|
315
|
+
def _si_sensitivity_field(G: TNFRGraph) -> TraceMetadata:
|
|
316
|
+
mapping = get_graph_mapping(
|
|
317
|
+
G,
|
|
318
|
+
"_Si_sensitivity",
|
|
319
|
+
"G.graph['_Si_sensitivity'] is not a mapping; ignoring",
|
|
320
|
+
)
|
|
321
|
+
if mapping is None:
|
|
322
|
+
return {"si_sensitivity": EMPTY_MAPPING}
|
|
234
323
|
|
|
324
|
+
normalised = _normalise_si_sensitivity_mapping(mapping, warn=True)
|
|
235
325
|
|
|
236
|
-
|
|
326
|
+
if normalised != mapping:
|
|
327
|
+
G.graph["_Si_sensitivity"] = normalised
|
|
328
|
+
|
|
329
|
+
return {"si_sensitivity": MappingProxyType(normalised)}
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def si_weights_field(G: TNFRGraph) -> TraceMetadata:
|
|
237
333
|
"""Return sense-plane weights and sensitivity."""
|
|
238
334
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
**(_si_weights_field(G) or {"si_weights": {}}),
|
|
243
|
-
**(_si_sensitivity_field(G) or {"si_sensitivity": {}}),
|
|
244
|
-
},
|
|
245
|
-
)
|
|
335
|
+
weights = _si_weights_field(G)
|
|
336
|
+
sensitivity = _si_sensitivity_field(G)
|
|
337
|
+
return {**weights, **sensitivity}
|
|
246
338
|
|
|
247
339
|
|
|
248
|
-
def callbacks_field(G:
|
|
340
|
+
def callbacks_field(G: TNFRGraph) -> TraceMetadata:
|
|
249
341
|
cb = G.graph.get("callbacks")
|
|
250
342
|
if not isinstance(cb, Mapping):
|
|
251
343
|
return {}
|
|
@@ -255,24 +347,24 @@ def callbacks_field(G: Any) -> TraceMetadata:
|
|
|
255
347
|
out[phase] = _callback_names(cb_map)
|
|
256
348
|
else:
|
|
257
349
|
out[phase] = None
|
|
258
|
-
return
|
|
350
|
+
return {"callbacks": out}
|
|
259
351
|
|
|
260
352
|
|
|
261
|
-
def thol_state_field(G:
|
|
353
|
+
def thol_state_field(G: TNFRGraph) -> TraceMetadata:
|
|
262
354
|
th_open = 0
|
|
263
355
|
for _, nd in G.nodes(data=True):
|
|
264
356
|
st = nd.get("_GRAM", {})
|
|
265
357
|
if st.get("thol_open", False):
|
|
266
358
|
th_open += 1
|
|
267
|
-
return
|
|
359
|
+
return {"thol_open_nodes": th_open}
|
|
268
360
|
|
|
269
361
|
|
|
270
|
-
def kuramoto_field(G:
|
|
362
|
+
def kuramoto_field(G: TNFRGraph) -> TraceMetadata:
|
|
271
363
|
R, psi = kuramoto_R_psi(G)
|
|
272
|
-
return
|
|
364
|
+
return {"kuramoto": {"R": float(R), "psi": float(psi)}}
|
|
273
365
|
|
|
274
366
|
|
|
275
|
-
def sigma_field(G:
|
|
367
|
+
def sigma_field(G: TNFRGraph) -> TraceMetadata:
|
|
276
368
|
sigma_vector_from_graph: _SigmaVectorFn = cast(
|
|
277
369
|
_SigmaVectorFn,
|
|
278
370
|
cached_import(
|
|
@@ -282,52 +374,134 @@ def sigma_field(G: Any) -> TraceMetadata:
|
|
|
282
374
|
),
|
|
283
375
|
)
|
|
284
376
|
sv = sigma_vector_from_graph(G)
|
|
285
|
-
return
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
"
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
``count_glyphs`` already produces a fresh mapping so no additional copy
|
|
302
|
-
is taken. Treat the returned mapping as read-only.
|
|
377
|
+
return {
|
|
378
|
+
"sigma": {
|
|
379
|
+
"x": float(sv.get("x", 0.0)),
|
|
380
|
+
"y": float(sv.get("y", 0.0)),
|
|
381
|
+
"mag": float(sv.get("mag", 0.0)),
|
|
382
|
+
"angle": float(sv.get("angle", 0.0)),
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def glyph_counts_field(G: TNFRGraph) -> TraceMetadata:
|
|
388
|
+
"""Return structural operator application count snapshot.
|
|
389
|
+
|
|
390
|
+
Provides a snapshot of which structural operator symbols (glyphs) have been
|
|
391
|
+
applied in the current step. ``count_glyphs`` already produces a fresh
|
|
392
|
+
mapping so no additional copy is taken. Treat the returned mapping as read-only.
|
|
303
393
|
"""
|
|
304
394
|
|
|
305
395
|
cnt = count_glyphs(G, window=1)
|
|
306
|
-
return
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
396
|
+
return {"glyphs": cnt}
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
TRACE_FIELD_SPECS: tuple[TraceFieldSpec, ...] = (
|
|
400
|
+
TraceFieldSpec(
|
|
401
|
+
name="gamma",
|
|
402
|
+
phase="before",
|
|
403
|
+
producer=gamma_field,
|
|
404
|
+
tiers=(
|
|
405
|
+
TelemetryVerbosity.BASIC,
|
|
406
|
+
TelemetryVerbosity.DETAILED,
|
|
407
|
+
TelemetryVerbosity.DEBUG,
|
|
408
|
+
),
|
|
409
|
+
),
|
|
410
|
+
TraceFieldSpec(
|
|
411
|
+
name="grammar",
|
|
412
|
+
phase="before",
|
|
413
|
+
producer=grammar_field,
|
|
414
|
+
tiers=(
|
|
415
|
+
TelemetryVerbosity.BASIC,
|
|
416
|
+
TelemetryVerbosity.DETAILED,
|
|
417
|
+
TelemetryVerbosity.DEBUG,
|
|
418
|
+
),
|
|
419
|
+
),
|
|
420
|
+
TraceFieldSpec(
|
|
421
|
+
name="selector",
|
|
422
|
+
phase="before",
|
|
423
|
+
producer=selector_field,
|
|
424
|
+
tiers=(
|
|
425
|
+
TelemetryVerbosity.BASIC,
|
|
426
|
+
TelemetryVerbosity.DETAILED,
|
|
427
|
+
TelemetryVerbosity.DEBUG,
|
|
428
|
+
),
|
|
429
|
+
),
|
|
430
|
+
TraceFieldSpec(
|
|
431
|
+
name="dnfr_weights",
|
|
432
|
+
phase="before",
|
|
433
|
+
producer=dnfr_weights_field,
|
|
434
|
+
tiers=(
|
|
435
|
+
TelemetryVerbosity.BASIC,
|
|
436
|
+
TelemetryVerbosity.DETAILED,
|
|
437
|
+
TelemetryVerbosity.DEBUG,
|
|
438
|
+
),
|
|
439
|
+
),
|
|
440
|
+
TraceFieldSpec(
|
|
441
|
+
name="si_weights",
|
|
442
|
+
phase="before",
|
|
443
|
+
producer=si_weights_field,
|
|
444
|
+
tiers=(
|
|
445
|
+
TelemetryVerbosity.BASIC,
|
|
446
|
+
TelemetryVerbosity.DETAILED,
|
|
447
|
+
TelemetryVerbosity.DEBUG,
|
|
448
|
+
),
|
|
449
|
+
),
|
|
450
|
+
TraceFieldSpec(
|
|
451
|
+
name="callbacks",
|
|
452
|
+
phase="before",
|
|
453
|
+
producer=callbacks_field,
|
|
454
|
+
tiers=(
|
|
455
|
+
TelemetryVerbosity.BASIC,
|
|
456
|
+
TelemetryVerbosity.DETAILED,
|
|
457
|
+
TelemetryVerbosity.DEBUG,
|
|
458
|
+
),
|
|
459
|
+
),
|
|
460
|
+
TraceFieldSpec(
|
|
461
|
+
name="thol_open_nodes",
|
|
462
|
+
phase="before",
|
|
463
|
+
producer=thol_state_field,
|
|
464
|
+
tiers=(
|
|
465
|
+
TelemetryVerbosity.BASIC,
|
|
466
|
+
TelemetryVerbosity.DETAILED,
|
|
467
|
+
TelemetryVerbosity.DEBUG,
|
|
468
|
+
),
|
|
469
|
+
),
|
|
470
|
+
TraceFieldSpec(
|
|
471
|
+
name="kuramoto",
|
|
472
|
+
phase="after",
|
|
473
|
+
producer=kuramoto_field,
|
|
474
|
+
tiers=(TelemetryVerbosity.DETAILED, TelemetryVerbosity.DEBUG),
|
|
475
|
+
),
|
|
476
|
+
TraceFieldSpec(
|
|
477
|
+
name="sigma",
|
|
478
|
+
phase="after",
|
|
479
|
+
producer=sigma_field,
|
|
480
|
+
tiers=(TelemetryVerbosity.DETAILED, TelemetryVerbosity.DEBUG),
|
|
481
|
+
),
|
|
482
|
+
TraceFieldSpec(
|
|
483
|
+
name="glyph_counts",
|
|
484
|
+
phase="after",
|
|
485
|
+
producer=glyph_counts_field,
|
|
486
|
+
tiers=(TelemetryVerbosity.DEBUG,),
|
|
487
|
+
),
|
|
488
|
+
)
|
|
317
489
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
490
|
+
TRACE_VERBOSITY_PRESETS = {
|
|
491
|
+
level.value: tuple(spec.name for spec in TRACE_FIELD_SPECS if level in spec.tiers)
|
|
492
|
+
for level in TelemetryVerbosity
|
|
493
|
+
}
|
|
321
494
|
|
|
495
|
+
for spec in TRACE_FIELD_SPECS:
|
|
496
|
+
register_trace_field(spec.phase, spec.name, spec.producer)
|
|
322
497
|
|
|
323
498
|
# -------------------------
|
|
324
499
|
# API
|
|
325
500
|
# -------------------------
|
|
326
501
|
|
|
327
502
|
|
|
328
|
-
def register_trace(G) -> None:
|
|
329
|
-
"""Enable before/after-step snapshots and dump operational metadata
|
|
330
|
-
to history.
|
|
503
|
+
def register_trace(G: TNFRGraph) -> None:
|
|
504
|
+
"""Enable before/after-step snapshots and dump operational metadata to history.
|
|
331
505
|
|
|
332
506
|
Trace snapshots are stored as :class:`TraceSnapshot` entries in
|
|
333
507
|
``G.graph['history'][TRACE.history_key]`` with:
|
|
@@ -349,16 +523,16 @@ def register_trace(G) -> None:
|
|
|
349
523
|
if G.graph.get("_trace_registered"):
|
|
350
524
|
return
|
|
351
525
|
|
|
352
|
-
from .
|
|
526
|
+
from .utils import callback_manager
|
|
353
527
|
|
|
354
528
|
for phase in TRACE_FIELDS.keys():
|
|
355
529
|
event = f"{phase}_step"
|
|
356
530
|
|
|
357
|
-
def _make_cb(ph):
|
|
358
|
-
def _cb(
|
|
531
|
+
def _make_cb(ph: str) -> TraceCallback:
|
|
532
|
+
def _cb(graph: TNFRGraph, ctx: dict[str, Any]) -> None:
|
|
359
533
|
del ctx
|
|
360
534
|
|
|
361
|
-
_trace_capture(
|
|
535
|
+
_trace_capture(graph, ph, TRACE_FIELDS.get(ph, {}))
|
|
362
536
|
|
|
363
537
|
return _cb
|
|
364
538
|
|
tnfr/trace.pyi
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterable, Mapping
|
|
4
|
+
from typing import Any, Callable, NamedTuple
|
|
5
|
+
|
|
6
|
+
from .types import (
|
|
7
|
+
TNFRGraph,
|
|
8
|
+
TraceFieldFn,
|
|
9
|
+
TraceFieldMap,
|
|
10
|
+
TraceFieldRegistry,
|
|
11
|
+
TraceMetadata,
|
|
12
|
+
TraceSnapshot,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__: tuple[str, ...]
|
|
16
|
+
|
|
17
|
+
def __getattr__(name: str) -> Any: ...
|
|
18
|
+
|
|
19
|
+
class CallbackSpec(NamedTuple):
|
|
20
|
+
name: str | None
|
|
21
|
+
func: Callable[..., Any]
|
|
22
|
+
|
|
23
|
+
kuramoto_R_psi: Callable[[TNFRGraph], tuple[float, float]]
|
|
24
|
+
TRACE_FIELDS: TraceFieldRegistry
|
|
25
|
+
|
|
26
|
+
def _callback_names(
|
|
27
|
+
callbacks: Mapping[str, CallbackSpec] | Iterable[CallbackSpec],
|
|
28
|
+
) -> list[str]: ...
|
|
29
|
+
def mapping_field(G: TNFRGraph, graph_key: str, out_key: str) -> TraceMetadata: ...
|
|
30
|
+
def _trace_capture(G: TNFRGraph, phase: str, fields: TraceFieldMap) -> None: ...
|
|
31
|
+
def register_trace_field(phase: str, name: str, func: TraceFieldFn) -> None: ...
|
|
32
|
+
def gamma_field(G: TNFRGraph) -> TraceMetadata: ...
|
|
33
|
+
def grammar_field(G: TNFRGraph) -> TraceMetadata: ...
|
|
34
|
+
def dnfr_weights_field(G: TNFRGraph) -> TraceMetadata: ...
|
|
35
|
+
def selector_field(G: TNFRGraph) -> TraceMetadata: ...
|
|
36
|
+
def si_weights_field(G: TNFRGraph) -> TraceMetadata: ...
|
|
37
|
+
def callbacks_field(G: TNFRGraph) -> TraceMetadata: ...
|
|
38
|
+
def thol_state_field(G: TNFRGraph) -> TraceMetadata: ...
|
|
39
|
+
def kuramoto_field(G: TNFRGraph) -> TraceMetadata: ...
|
|
40
|
+
def sigma_field(G: TNFRGraph) -> TraceMetadata: ...
|
|
41
|
+
def glyph_counts_field(G: TNFRGraph) -> TraceMetadata: ...
|
|
42
|
+
def register_trace(G: TNFRGraph) -> None: ...
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Interactive tutorials for learning TNFR step-by-step.
|
|
2
|
+
|
|
3
|
+
This module provides guided, hands-on tutorials that introduce TNFR
|
|
4
|
+
concepts progressively. Each tutorial:
|
|
5
|
+
|
|
6
|
+
1. Explains TNFR concepts in plain language
|
|
7
|
+
2. Shows working code examples
|
|
8
|
+
3. Displays real-time results with interpretation
|
|
9
|
+
4. Builds from simple to advanced concepts
|
|
10
|
+
5. Maintains full TNFR theoretical fidelity
|
|
11
|
+
|
|
12
|
+
All tutorials respect TNFR canonical invariants and can be run
|
|
13
|
+
independently or as a learning sequence.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"hello_tnfr",
|
|
20
|
+
"biological_example",
|
|
21
|
+
"social_network_example",
|
|
22
|
+
"technology_example",
|
|
23
|
+
"team_communication_example",
|
|
24
|
+
"adaptive_ai_example",
|
|
25
|
+
"oz_dissonance_tutorial",
|
|
26
|
+
"run_all_tutorials",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
from .interactive import (
|
|
30
|
+
hello_tnfr,
|
|
31
|
+
biological_example,
|
|
32
|
+
social_network_example,
|
|
33
|
+
technology_example,
|
|
34
|
+
team_communication_example,
|
|
35
|
+
adaptive_ai_example,
|
|
36
|
+
oz_dissonance_tutorial,
|
|
37
|
+
run_all_tutorials,
|
|
38
|
+
)
|