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/sense.py
CHANGED
|
@@ -1,31 +1,39 @@
|
|
|
1
|
-
"""Sense calculations.
|
|
1
|
+
"""Sense calculations and structural operator symbol vector analysis.
|
|
2
|
+
|
|
3
|
+
This module implements the sense index (Si) calculation and related vector
|
|
4
|
+
operations for analyzing the distribution of structural operator applications.
|
|
5
|
+
|
|
6
|
+
The 'glyph rose' visualization represents the distribution of structural operator
|
|
7
|
+
symbols in a circular format, where each glyph corresponds to an angle representing
|
|
8
|
+
the associated structural operator.
|
|
9
|
+
"""
|
|
2
10
|
|
|
3
11
|
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from collections.abc import Iterable, Mapping
|
|
12
|
+
|
|
6
13
|
import math
|
|
7
14
|
from collections import Counter
|
|
15
|
+
from collections.abc import Iterable, Iterator, Mapping
|
|
8
16
|
from itertools import tee
|
|
17
|
+
from typing import Any, Callable, TypeVar
|
|
9
18
|
|
|
10
|
-
import networkx as nx
|
|
19
|
+
import networkx as nx
|
|
11
20
|
|
|
12
|
-
from .constants import get_aliases, get_graph_param
|
|
13
21
|
from .alias import get_attr
|
|
14
|
-
from .
|
|
15
|
-
from .
|
|
16
|
-
from .callback_utils import CallbackEvent, callback_manager
|
|
17
|
-
from .glyph_history import (
|
|
18
|
-
ensure_history,
|
|
19
|
-
last_glyph,
|
|
20
|
-
count_glyphs,
|
|
21
|
-
append_metric,
|
|
22
|
-
)
|
|
23
|
-
from .constants_glyphs import (
|
|
22
|
+
from .utils import CallbackEvent, callback_manager
|
|
23
|
+
from .config.constants import (
|
|
24
24
|
ANGLE_MAP,
|
|
25
25
|
GLYPHS_CANONICAL,
|
|
26
26
|
)
|
|
27
|
+
from .constants import get_graph_param
|
|
28
|
+
from .constants.aliases import ALIAS_EPI, ALIAS_SI
|
|
29
|
+
from .glyph_history import append_metric, count_glyphs, ensure_history
|
|
30
|
+
from .glyph_runtime import last_glyph
|
|
31
|
+
from .utils import clamp01, kahan_sum_nd
|
|
32
|
+
from .types import NodeId, SigmaVector, TNFRGraph
|
|
33
|
+
from .utils import get_numpy
|
|
34
|
+
|
|
27
35
|
# -------------------------
|
|
28
|
-
# Canon:
|
|
36
|
+
# Canon: circular glyph order and angles
|
|
29
37
|
# -------------------------
|
|
30
38
|
|
|
31
39
|
GLYPH_UNITS: dict[str, complex] = {
|
|
@@ -45,10 +53,9 @@ __all__ = (
|
|
|
45
53
|
)
|
|
46
54
|
|
|
47
55
|
# -------------------------
|
|
48
|
-
#
|
|
56
|
+
# Basic utilities
|
|
49
57
|
# -------------------------
|
|
50
58
|
|
|
51
|
-
|
|
52
59
|
T = TypeVar("T")
|
|
53
60
|
|
|
54
61
|
|
|
@@ -58,35 +65,42 @@ def _resolve_glyph(g: str, mapping: Mapping[str, T]) -> T:
|
|
|
58
65
|
try:
|
|
59
66
|
return mapping[g]
|
|
60
67
|
except KeyError as e: # pragma: no cover - small helper
|
|
61
|
-
raise KeyError(f"
|
|
68
|
+
raise KeyError(f"Unknown glyph: {g}") from e
|
|
62
69
|
|
|
63
70
|
|
|
64
71
|
def glyph_angle(g: str) -> float:
|
|
65
|
-
"""Return angle for
|
|
72
|
+
"""Return the canonical angle for structural operator symbol ``g``.
|
|
73
|
+
|
|
74
|
+
Each structural operator symbol (glyph) is mapped to a specific angle
|
|
75
|
+
in the circular representation used for sense vector calculations.
|
|
76
|
+
"""
|
|
66
77
|
|
|
67
78
|
return float(_resolve_glyph(g, ANGLE_MAP))
|
|
68
79
|
|
|
69
80
|
|
|
70
81
|
def glyph_unit(g: str) -> complex:
|
|
71
|
-
"""Return unit vector for
|
|
82
|
+
"""Return the unit vector for structural operator symbol ``g``.
|
|
72
83
|
|
|
73
|
-
|
|
84
|
+
Each structural operator symbol (glyph) corresponds to a unit vector
|
|
85
|
+
in the complex plane, used for aggregating operator applications.
|
|
86
|
+
"""
|
|
74
87
|
|
|
88
|
+
return _resolve_glyph(g, GLYPH_UNITS)
|
|
75
89
|
|
|
76
|
-
ALIAS_SI = get_aliases("SI")
|
|
77
|
-
ALIAS_EPI = get_aliases("EPI")
|
|
78
90
|
|
|
79
|
-
MODE_FUNCS = {
|
|
91
|
+
MODE_FUNCS: dict[str, Callable[[Mapping[str, Any]], float]] = {
|
|
80
92
|
"Si": lambda nd: clamp01(get_attr(nd, ALIAS_SI, 0.5)),
|
|
81
93
|
"EPI": lambda nd: max(0.0, get_attr(nd, ALIAS_EPI, 0.0)),
|
|
82
94
|
}
|
|
83
95
|
|
|
84
96
|
|
|
85
|
-
def _weight(nd, mode: str) -> float:
|
|
97
|
+
def _weight(nd: Mapping[str, Any], mode: str) -> float:
|
|
86
98
|
return MODE_FUNCS.get(mode, lambda _: 1.0)(nd)
|
|
87
99
|
|
|
88
100
|
|
|
89
|
-
def _node_weight(
|
|
101
|
+
def _node_weight(
|
|
102
|
+
nd: Mapping[str, Any], weight_mode: str
|
|
103
|
+
) -> tuple[str, float, complex] | None:
|
|
90
104
|
"""Return ``(glyph, weight, weighted_unit)`` or ``None`` if no glyph."""
|
|
91
105
|
g = last_glyph(nd)
|
|
92
106
|
if not g:
|
|
@@ -96,7 +110,7 @@ def _node_weight(nd, weight_mode: str) -> tuple[str, float, complex] | None:
|
|
|
96
110
|
return g, w, z
|
|
97
111
|
|
|
98
112
|
|
|
99
|
-
def _sigma_cfg(G):
|
|
113
|
+
def _sigma_cfg(G: TNFRGraph) -> dict[str, Any]:
|
|
100
114
|
return get_graph_param(G, "SIGMA", dict)
|
|
101
115
|
|
|
102
116
|
|
|
@@ -110,7 +124,7 @@ def _to_complex(val: complex | float | int) -> complex:
|
|
|
110
124
|
raise TypeError("values must be an iterable of real or complex numbers")
|
|
111
125
|
|
|
112
126
|
|
|
113
|
-
def _empty_sigma(fallback_angle: float) ->
|
|
127
|
+
def _empty_sigma(fallback_angle: float) -> SigmaVector:
|
|
114
128
|
"""Return an empty σ-vector with ``fallback_angle``.
|
|
115
129
|
|
|
116
130
|
Helps centralise the default structure returned when no values are
|
|
@@ -127,14 +141,14 @@ def _empty_sigma(fallback_angle: float) -> dict[str, float]:
|
|
|
127
141
|
|
|
128
142
|
|
|
129
143
|
# -------------------------
|
|
130
|
-
# σ
|
|
144
|
+
# σ per node and global σ
|
|
131
145
|
# -------------------------
|
|
132
146
|
|
|
133
147
|
|
|
134
148
|
def _sigma_from_iterable(
|
|
135
149
|
values: Iterable[complex | float | int] | complex | float | int,
|
|
136
150
|
fallback_angle: float = 0.0,
|
|
137
|
-
) ->
|
|
151
|
+
) -> SigmaVector:
|
|
138
152
|
"""Normalise vectors in the σ-plane.
|
|
139
153
|
|
|
140
154
|
``values`` may contain complex or real numbers; real inputs are promoted to
|
|
@@ -142,7 +156,9 @@ def _sigma_from_iterable(
|
|
|
142
156
|
number of processed values under the ``"n"`` key.
|
|
143
157
|
"""
|
|
144
158
|
|
|
145
|
-
if isinstance(values, Iterable) and not isinstance(
|
|
159
|
+
if isinstance(values, Iterable) and not isinstance(
|
|
160
|
+
values, (str, bytes, bytearray, Mapping)
|
|
161
|
+
):
|
|
146
162
|
iterator = iter(values)
|
|
147
163
|
else:
|
|
148
164
|
iterator = iter((values,))
|
|
@@ -159,15 +175,15 @@ def _sigma_from_iterable(
|
|
|
159
175
|
mag = float(np.hypot(x, y))
|
|
160
176
|
ang = float(np.arctan2(y, x)) if mag > 0 else float(fallback_angle)
|
|
161
177
|
return {
|
|
162
|
-
"x": x,
|
|
163
|
-
"y": y,
|
|
164
|
-
"mag": mag,
|
|
165
|
-
"angle": ang,
|
|
166
|
-
"n": cnt,
|
|
178
|
+
"x": float(x),
|
|
179
|
+
"y": float(y),
|
|
180
|
+
"mag": float(mag),
|
|
181
|
+
"angle": float(ang),
|
|
182
|
+
"n": int(cnt),
|
|
167
183
|
}
|
|
168
184
|
cnt = 0
|
|
169
185
|
|
|
170
|
-
def pair_iter():
|
|
186
|
+
def pair_iter() -> Iterator[tuple[float, float]]:
|
|
171
187
|
nonlocal cnt
|
|
172
188
|
for val in iterator:
|
|
173
189
|
z = _to_complex(val)
|
|
@@ -188,24 +204,30 @@ def _sigma_from_iterable(
|
|
|
188
204
|
"y": float(y),
|
|
189
205
|
"mag": float(mag),
|
|
190
206
|
"angle": float(ang),
|
|
191
|
-
"n": cnt,
|
|
207
|
+
"n": int(cnt),
|
|
192
208
|
}
|
|
193
209
|
|
|
194
210
|
|
|
195
|
-
def _ema_update(
|
|
196
|
-
prev: dict[str, float], current: dict[str, float], alpha: float
|
|
197
|
-
) -> dict[str, float]:
|
|
211
|
+
def _ema_update(prev: SigmaVector, current: SigmaVector, alpha: float) -> SigmaVector:
|
|
198
212
|
"""Exponential moving average update for σ vectors."""
|
|
199
213
|
x = (1 - alpha) * prev["x"] + alpha * current["x"]
|
|
200
214
|
y = (1 - alpha) * prev["y"] + alpha * current["y"]
|
|
201
215
|
mag = math.hypot(x, y)
|
|
202
216
|
ang = math.atan2(y, x)
|
|
203
|
-
return {
|
|
217
|
+
return {
|
|
218
|
+
"x": float(x),
|
|
219
|
+
"y": float(y),
|
|
220
|
+
"mag": float(mag),
|
|
221
|
+
"angle": float(ang),
|
|
222
|
+
"n": int(current["n"]),
|
|
223
|
+
}
|
|
204
224
|
|
|
205
225
|
|
|
206
226
|
def _sigma_from_nodes(
|
|
207
|
-
nodes: Iterable[
|
|
208
|
-
|
|
227
|
+
nodes: Iterable[Mapping[str, Any]],
|
|
228
|
+
weight_mode: str,
|
|
229
|
+
fallback_angle: float = 0.0,
|
|
230
|
+
) -> tuple[SigmaVector, list[tuple[str, float, complex]]]:
|
|
209
231
|
"""Aggregate weighted glyph vectors for ``nodes``.
|
|
210
232
|
|
|
211
233
|
Returns the aggregated σ vector and the list of ``(glyph, weight, vector)``
|
|
@@ -218,8 +240,10 @@ def _sigma_from_nodes(
|
|
|
218
240
|
|
|
219
241
|
|
|
220
242
|
def sigma_vector_node(
|
|
221
|
-
G, n, weight_mode: str | None = None
|
|
222
|
-
) ->
|
|
243
|
+
G: TNFRGraph, n: NodeId, weight_mode: str | None = None
|
|
244
|
+
) -> SigmaVector | None:
|
|
245
|
+
"""Return the σ vector for node ``n`` using the configured weighting."""
|
|
246
|
+
|
|
223
247
|
cfg = _sigma_cfg(G)
|
|
224
248
|
nd = G.nodes[n]
|
|
225
249
|
weight_mode = weight_mode or cfg.get("weight", "Si")
|
|
@@ -229,11 +253,12 @@ def sigma_vector_node(
|
|
|
229
253
|
g, w, _ = nws[0]
|
|
230
254
|
if sv["mag"] == 0:
|
|
231
255
|
sv["angle"] = glyph_angle(g)
|
|
232
|
-
sv
|
|
256
|
+
sv["glyph"] = g
|
|
257
|
+
sv["w"] = float(w)
|
|
233
258
|
return sv
|
|
234
259
|
|
|
235
260
|
|
|
236
|
-
def sigma_vector(dist:
|
|
261
|
+
def sigma_vector(dist: Mapping[str, float]) -> SigmaVector:
|
|
237
262
|
"""Compute Σ⃗ from a glyph distribution.
|
|
238
263
|
|
|
239
264
|
``dist`` may contain raw counts or proportions. All ``(glyph, weight)``
|
|
@@ -246,8 +271,8 @@ def sigma_vector(dist: dict[str, float]) -> dict[str, float]:
|
|
|
246
271
|
|
|
247
272
|
|
|
248
273
|
def sigma_vector_from_graph(
|
|
249
|
-
G:
|
|
250
|
-
) ->
|
|
274
|
+
G: TNFRGraph, weight_mode: str | None = None
|
|
275
|
+
) -> SigmaVector:
|
|
251
276
|
"""Global vector in the σ sense plane for a graph.
|
|
252
277
|
|
|
253
278
|
Parameters
|
|
@@ -264,34 +289,34 @@ def sigma_vector_from_graph(
|
|
|
264
289
|
"""
|
|
265
290
|
|
|
266
291
|
if not isinstance(G, nx.Graph):
|
|
267
|
-
raise TypeError("sigma_vector_from_graph
|
|
292
|
+
raise TypeError("sigma_vector_from_graph requires a networkx.Graph")
|
|
268
293
|
|
|
269
294
|
cfg = _sigma_cfg(G)
|
|
270
295
|
weight_mode = weight_mode or cfg.get("weight", "Si")
|
|
271
|
-
sv, _ = _sigma_from_nodes(
|
|
272
|
-
(nd for _, nd in G.nodes(data=True)), weight_mode
|
|
273
|
-
)
|
|
296
|
+
sv, _ = _sigma_from_nodes((nd for _, nd in G.nodes(data=True)), weight_mode)
|
|
274
297
|
return sv
|
|
275
298
|
|
|
276
299
|
|
|
277
300
|
# -------------------------
|
|
278
|
-
#
|
|
301
|
+
# History / series
|
|
279
302
|
# -------------------------
|
|
280
303
|
|
|
281
304
|
|
|
282
|
-
def push_sigma_snapshot(G, t: float | None = None) -> None:
|
|
305
|
+
def push_sigma_snapshot(G: TNFRGraph, t: float | None = None) -> None:
|
|
306
|
+
"""Record a global σ snapshot (and optional per-node traces) for ``G``."""
|
|
307
|
+
|
|
283
308
|
cfg = _sigma_cfg(G)
|
|
284
309
|
if not cfg.get("enabled", True):
|
|
285
310
|
return
|
|
286
311
|
|
|
287
|
-
#
|
|
312
|
+
# Local history cache to avoid repeated lookups
|
|
288
313
|
hist = ensure_history(G)
|
|
289
314
|
key = cfg.get("history_key", "sigma_global")
|
|
290
315
|
|
|
291
316
|
weight_mode = cfg.get("weight", "Si")
|
|
292
317
|
sv = sigma_vector_from_graph(G, weight_mode)
|
|
293
318
|
|
|
294
|
-
#
|
|
319
|
+
# Optional exponential smoothing (EMA)
|
|
295
320
|
alpha = float(cfg.get("smooth", 0.0))
|
|
296
321
|
if alpha > 0 and hist.get(key):
|
|
297
322
|
sv = _ema_update(hist[key][-1], sv, alpha)
|
|
@@ -301,11 +326,11 @@ def push_sigma_snapshot(G, t: float | None = None) -> None:
|
|
|
301
326
|
|
|
302
327
|
append_metric(hist, key, sv)
|
|
303
328
|
|
|
304
|
-
#
|
|
329
|
+
# Glyph count per step (useful for the glyph rose)
|
|
305
330
|
counts = count_glyphs(G, last_only=True)
|
|
306
331
|
append_metric(hist, "sigma_counts", {"t": current_t, **counts})
|
|
307
332
|
|
|
308
|
-
#
|
|
333
|
+
# Optional per-node trajectory
|
|
309
334
|
if cfg.get("per_node", False):
|
|
310
335
|
per = hist.setdefault("sigma_per_node", {})
|
|
311
336
|
for n, nd in G.nodes(data=True):
|
|
@@ -317,11 +342,13 @@ def push_sigma_snapshot(G, t: float | None = None) -> None:
|
|
|
317
342
|
|
|
318
343
|
|
|
319
344
|
# -------------------------
|
|
320
|
-
#
|
|
345
|
+
# Register as an automatic callback (after_step)
|
|
321
346
|
# -------------------------
|
|
322
347
|
|
|
323
348
|
|
|
324
|
-
def register_sigma_callback(G) -> None:
|
|
349
|
+
def register_sigma_callback(G: TNFRGraph) -> None:
|
|
350
|
+
"""Attach :func:`push_sigma_snapshot` to the ``AFTER_STEP`` callback bus."""
|
|
351
|
+
|
|
325
352
|
callback_manager.register_callback(
|
|
326
353
|
G,
|
|
327
354
|
event=CallbackEvent.AFTER_STEP.value,
|
|
@@ -330,7 +357,7 @@ def register_sigma_callback(G) -> None:
|
|
|
330
357
|
)
|
|
331
358
|
|
|
332
359
|
|
|
333
|
-
def sigma_rose(G, steps: int | None = None) -> dict[str, int]:
|
|
360
|
+
def sigma_rose(G: TNFRGraph, steps: int | None = None) -> dict[str, int]:
|
|
334
361
|
"""Histogram of glyphs in the last ``steps`` steps (or all)."""
|
|
335
362
|
hist = ensure_history(G)
|
|
336
363
|
counts = hist.get("sigma_counts", [])
|
|
@@ -340,9 +367,7 @@ def sigma_rose(G, steps: int | None = None) -> dict[str, int]:
|
|
|
340
367
|
steps = int(steps)
|
|
341
368
|
if steps < 0:
|
|
342
369
|
raise ValueError("steps must be non-negative")
|
|
343
|
-
rows = (
|
|
344
|
-
counts if steps >= len(counts) else counts[-steps:]
|
|
345
|
-
) # noqa: E203
|
|
370
|
+
rows = counts if steps >= len(counts) else counts[-steps:] # noqa: E203
|
|
346
371
|
else:
|
|
347
372
|
rows = counts
|
|
348
373
|
counter = Counter()
|
tnfr/sense.pyi
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from .types import NodeId, SigmaVector, TNFRGraph
|
|
7
|
+
|
|
8
|
+
__all__: tuple[str, ...]
|
|
9
|
+
|
|
10
|
+
GLYPH_UNITS: dict[str, complex]
|
|
11
|
+
|
|
12
|
+
def glyph_angle(g: str) -> float: ...
|
|
13
|
+
def glyph_unit(g: str) -> complex: ...
|
|
14
|
+
def push_sigma_snapshot(G: TNFRGraph, t: Optional[float] = None) -> None: ...
|
|
15
|
+
def register_sigma_callback(G: TNFRGraph) -> None: ...
|
|
16
|
+
def sigma_rose(G: TNFRGraph, steps: Optional[int] = None) -> dict[str, int]: ...
|
|
17
|
+
def sigma_vector(dist: Mapping[str, float]) -> SigmaVector: ...
|
|
18
|
+
def sigma_vector_from_graph(
|
|
19
|
+
G: TNFRGraph, weight_mode: Optional[str] = None
|
|
20
|
+
) -> SigmaVector: ...
|
|
21
|
+
def sigma_vector_node(
|
|
22
|
+
G: TNFRGraph, n: NodeId, weight_mode: Optional[str] = None
|
|
23
|
+
) -> Optional[SigmaVector]: ...
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Service layer for TNFR orchestration.
|
|
2
|
+
|
|
3
|
+
This package provides the service layer that coordinates execution of TNFR
|
|
4
|
+
operator sequences while maintaining clean separation of responsibilities
|
|
5
|
+
across validation, execution, dynamics, and telemetry concerns.
|
|
6
|
+
|
|
7
|
+
Public API
|
|
8
|
+
----------
|
|
9
|
+
TNFROrchestrator
|
|
10
|
+
Main orchestration service coordinating sequence execution.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from .orchestrator import TNFROrchestrator
|
|
16
|
+
|
|
17
|
+
__all__ = ("TNFROrchestrator",)
|