tnfr 3.0.3__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 +375 -56
- 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 +723 -0
- 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 +171 -0
- tnfr/cache.pyi +13 -0
- tnfr/cli/__init__.py +110 -0
- tnfr/cli/__init__.pyi +26 -0
- tnfr/cli/arguments.py +489 -0
- tnfr/cli/arguments.pyi +29 -0
- tnfr/cli/execution.py +914 -0
- tnfr/cli/execution.pyi +70 -0
- tnfr/cli/interactive_validator.py +614 -0
- tnfr/cli/utils.py +51 -0
- 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/config/constants.py +104 -0
- tnfr/config/constants.pyi +12 -0
- tnfr/config/defaults.py +54 -0
- tnfr/config/defaults_core.py +212 -0
- 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 +92 -0
- tnfr/constants/__init__.pyi +92 -0
- tnfr/constants/aliases.py +33 -0
- tnfr/constants/aliases.pyi +27 -0
- tnfr/constants/init.py +33 -0
- tnfr/constants/init.pyi +12 -0
- tnfr/constants/metric.py +104 -0
- 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 +238 -0
- 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 +3034 -0
- 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 +661 -0
- 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 +36 -0
- 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 +223 -0
- 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 +262 -0
- tnfr/flatten.pyi +21 -0
- tnfr/gamma.py +354 -0
- tnfr/gamma.pyi +36 -0
- tnfr/glyph_history.py +377 -0
- tnfr/glyph_history.pyi +35 -0
- tnfr/glyph_runtime.py +19 -0
- tnfr/glyph_runtime.pyi +8 -0
- tnfr/immutable.py +218 -0
- tnfr/immutable.pyi +36 -0
- tnfr/initialization.py +203 -0
- tnfr/initialization.pyi +65 -0
- tnfr/io.py +10 -0
- tnfr/io.pyi +13 -0
- tnfr/locking.py +37 -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 +79 -0
- 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 +2009 -0
- tnfr/metrics/coherence.pyi +129 -0
- tnfr/metrics/common.py +158 -0
- tnfr/metrics/common.pyi +35 -0
- tnfr/metrics/core.py +316 -0
- tnfr/metrics/core.pyi +13 -0
- tnfr/metrics/diagnosis.py +833 -0
- tnfr/metrics/diagnosis.pyi +86 -0
- tnfr/metrics/emergence.py +245 -0
- tnfr/metrics/export.py +179 -0
- tnfr/metrics/export.pyi +7 -0
- tnfr/metrics/glyph_timing.py +379 -0
- 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 +183 -0
- tnfr/metrics/reporting.pyi +25 -0
- tnfr/metrics/sense_index.py +1203 -0
- tnfr/metrics/sense_index.pyi +9 -0
- tnfr/metrics/trig.py +373 -0
- tnfr/metrics/trig.pyi +13 -0
- tnfr/metrics/trig_cache.py +233 -0
- tnfr/metrics/trig_cache.pyi +10 -0
- tnfr/multiscale/__init__.py +32 -0
- tnfr/multiscale/hierarchical.py +517 -0
- tnfr/node.py +763 -0
- tnfr/node.pyi +139 -0
- tnfr/observers.py +255 -130
- tnfr/observers.pyi +31 -0
- tnfr/ontosim.py +144 -137
- tnfr/ontosim.pyi +28 -0
- tnfr/operators/__init__.py +1672 -0
- 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 +272 -0
- 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 +1809 -0
- 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 +178 -0
- 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 +247 -0
- tnfr/selector.pyi +19 -0
- tnfr/sense.py +378 -0
- 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 +705 -0
- 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 +58 -0
- 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 +543 -0
- 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 +775 -0
- 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/utils/callbacks.py +375 -0
- 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/utils/numeric.py +114 -0
- 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-8.5.0.dist-info/entry_points.txt +3 -0
- tnfr-3.0.3.dist-info/licenses/LICENSE.txt → tnfr-8.5.0.dist-info/licenses/LICENSE.md +1 -1
- tnfr/constants.py +0 -183
- tnfr/dynamics.py +0 -543
- tnfr/helpers.py +0 -198
- tnfr/main.py +0 -37
- tnfr/operators.py +0 -296
- tnfr-3.0.3.dist-info/METADATA +0 -35
- tnfr-3.0.3.dist-info/RECORD +0 -13
- {tnfr-3.0.3.dist-info → tnfr-8.5.0.dist-info}/WHEEL +0 -0
- {tnfr-3.0.3.dist-info → tnfr-8.5.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Mapping, Sequence
|
|
4
|
+
|
|
5
|
+
__all__: Any
|
|
6
|
+
|
|
7
|
+
def __getattr__(name: str) -> Any: ...
|
|
8
|
+
|
|
9
|
+
ALIAS_DNFR: Any
|
|
10
|
+
ALIAS_EPI: Any
|
|
11
|
+
ALIAS_SI: Any
|
|
12
|
+
ALIAS_VF: Any
|
|
13
|
+
CallbackEvent: Any
|
|
14
|
+
CoherenceMatrixPayload: Any
|
|
15
|
+
Iterable: Any
|
|
16
|
+
ProcessPoolExecutor: Any
|
|
17
|
+
StatisticsError: Any
|
|
18
|
+
TNFRGraph: Any
|
|
19
|
+
TRANSITION: Any
|
|
20
|
+
VF_KEY: Any
|
|
21
|
+
append_metric: Any
|
|
22
|
+
callback_manager: Any
|
|
23
|
+
clamp01: Any
|
|
24
|
+
coherence_matrix: Any
|
|
25
|
+
compute_dnfr_accel_max: Any
|
|
26
|
+
compute_theta_trig: Any
|
|
27
|
+
dissonance_events: Any
|
|
28
|
+
ensure_history: Any
|
|
29
|
+
fmean: Any
|
|
30
|
+
ge: Any
|
|
31
|
+
get_aliases: Any
|
|
32
|
+
get_attr: Any
|
|
33
|
+
get_numpy: Any
|
|
34
|
+
get_param: Any
|
|
35
|
+
get_trig_cache: Any
|
|
36
|
+
le: Any
|
|
37
|
+
local_phase_sync: Any
|
|
38
|
+
math: Any
|
|
39
|
+
min_max_range: Any
|
|
40
|
+
normalize_dnfr: Any
|
|
41
|
+
partial: Any
|
|
42
|
+
register_diagnosis_callbacks: Any
|
|
43
|
+
similarity_abs: Any
|
|
44
|
+
|
|
45
|
+
class RLocalWorkerArgs:
|
|
46
|
+
chunk: Sequence[Any]
|
|
47
|
+
coherence_nodes: Sequence[Any]
|
|
48
|
+
weight_matrix: Any
|
|
49
|
+
weight_index: Mapping[Any, int]
|
|
50
|
+
neighbors_map: Mapping[Any, tuple[Any, ...]]
|
|
51
|
+
cos_map: Mapping[Any, float]
|
|
52
|
+
sin_map: Mapping[Any, float]
|
|
53
|
+
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
chunk: Sequence[Any],
|
|
57
|
+
coherence_nodes: Sequence[Any],
|
|
58
|
+
weight_matrix: Any,
|
|
59
|
+
weight_index: Mapping[Any, int],
|
|
60
|
+
neighbors_map: Mapping[Any, tuple[Any, ...]],
|
|
61
|
+
cos_map: Mapping[Any, float],
|
|
62
|
+
sin_map: Mapping[Any, float],
|
|
63
|
+
) -> None: ...
|
|
64
|
+
|
|
65
|
+
class NeighborMeanWorkerArgs:
|
|
66
|
+
chunk: Sequence[Any]
|
|
67
|
+
neighbors_map: Mapping[Any, tuple[Any, ...]]
|
|
68
|
+
epi_map: Mapping[Any, float]
|
|
69
|
+
|
|
70
|
+
def __init__(
|
|
71
|
+
self,
|
|
72
|
+
chunk: Sequence[Any],
|
|
73
|
+
neighbors_map: Mapping[Any, tuple[Any, ...]],
|
|
74
|
+
epi_map: Mapping[Any, float],
|
|
75
|
+
) -> None: ...
|
|
76
|
+
|
|
77
|
+
def _rlocal_worker(args: RLocalWorkerArgs) -> list[float]: ...
|
|
78
|
+
def _neighbor_mean_worker(args: NeighborMeanWorkerArgs) -> list[float | None]: ...
|
|
79
|
+
def _state_from_thresholds(
|
|
80
|
+
Rloc: float, dnfr_n: float, cfg: Mapping[str, Any]
|
|
81
|
+
) -> str: ...
|
|
82
|
+
def _recommendation(state: str, cfg: Mapping[str, Any]) -> list[Any]: ...
|
|
83
|
+
def _get_last_weights(
|
|
84
|
+
G: TNFRGraph,
|
|
85
|
+
hist: Mapping[str, Sequence[CoherenceMatrixPayload | None]],
|
|
86
|
+
) -> tuple[CoherenceMatrixPayload | None, CoherenceMatrixPayload | None]: ...
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"""Emergence metrics for T'HOL structural metabolism.
|
|
2
|
+
|
|
3
|
+
Provides quantitative measures of complexity emergence, bifurcation dynamics,
|
|
4
|
+
and metabolic efficiency in self-organizing systems.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from ..types import NodeId, TNFRGraph
|
|
13
|
+
|
|
14
|
+
from ..alias import get_attr
|
|
15
|
+
from ..constants.aliases import ALIAS_EPI
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"compute_structural_complexity",
|
|
19
|
+
"compute_bifurcation_rate",
|
|
20
|
+
"compute_metabolic_efficiency",
|
|
21
|
+
"compute_emergence_index",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
# Emergence index calculation constant
|
|
25
|
+
_EMERGENCE_INDEX_EPSILON = 1e-6 # Small value to avoid zero in geometric mean
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def compute_structural_complexity(G: TNFRGraph, node: NodeId) -> int:
|
|
29
|
+
"""Measure structural complexity by counting nested sub-EPIs.
|
|
30
|
+
|
|
31
|
+
Structural complexity reflects the number of bifurcations that have
|
|
32
|
+
occurred, indicating the degree of self-organized internal structure.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
G : TNFRGraph
|
|
37
|
+
Graph containing the node
|
|
38
|
+
node : NodeId
|
|
39
|
+
Node identifier
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
int
|
|
44
|
+
Number of sub-EPIs generated through T'HOL bifurcations
|
|
45
|
+
|
|
46
|
+
Notes
|
|
47
|
+
-----
|
|
48
|
+
Higher complexity indicates more sophisticated internal organization
|
|
49
|
+
but may also indicate higher maintenance costs (higher νf required).
|
|
50
|
+
|
|
51
|
+
Examples
|
|
52
|
+
--------
|
|
53
|
+
>>> from tnfr.structural import create_nfr
|
|
54
|
+
>>> from tnfr.operators.definitions import SelfOrganization
|
|
55
|
+
>>> from tnfr.metrics.emergence import compute_structural_complexity
|
|
56
|
+
>>> G, node = create_nfr("system", epi=0.5, vf=1.0)
|
|
57
|
+
>>> # Initialize history for bifurcation
|
|
58
|
+
>>> G.nodes[node]["epi_history"] = [0.3, 0.4, 0.6] # Accelerating
|
|
59
|
+
>>> SelfOrganization()(G, node, tau=0.05) # Low threshold
|
|
60
|
+
>>> complexity = compute_structural_complexity(G, node)
|
|
61
|
+
>>> complexity # doctest: +SKIP
|
|
62
|
+
1
|
|
63
|
+
"""
|
|
64
|
+
sub_epis = G.nodes[node].get("sub_epis", [])
|
|
65
|
+
return len(sub_epis)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def compute_bifurcation_rate(G: TNFRGraph, node: NodeId, window: int = 10) -> float:
|
|
69
|
+
"""Calculate frequency of bifurcations in recent history.
|
|
70
|
+
|
|
71
|
+
Bifurcation rate indicates how actively the node is generating new
|
|
72
|
+
structural complexity through T'HOL operations.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
G : TNFRGraph
|
|
77
|
+
Graph containing the node
|
|
78
|
+
node : NodeId
|
|
79
|
+
Node identifier
|
|
80
|
+
window : int
|
|
81
|
+
Time window for rate calculation (in operator steps, default 10)
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
-------
|
|
85
|
+
float
|
|
86
|
+
Bifurcations per step in the window (0.0 to 1.0 typical)
|
|
87
|
+
|
|
88
|
+
Notes
|
|
89
|
+
-----
|
|
90
|
+
High bifurcation rate (> 0.5) may indicate:
|
|
91
|
+
- Active adaptation to changing environment
|
|
92
|
+
- High structural instability
|
|
93
|
+
- Rich exploratory dynamics
|
|
94
|
+
|
|
95
|
+
Low rate (< 0.1) may indicate:
|
|
96
|
+
- Stable structural regime
|
|
97
|
+
- Low adaptive pressure
|
|
98
|
+
- Insufficient ΔNFR for bifurcation
|
|
99
|
+
|
|
100
|
+
Examples
|
|
101
|
+
--------
|
|
102
|
+
>>> from tnfr.structural import create_nfr
|
|
103
|
+
>>> from tnfr.metrics.emergence import compute_bifurcation_rate
|
|
104
|
+
>>> G, node = create_nfr("evolving", epi=0.6, vf=1.0)
|
|
105
|
+
>>> # Simulate several bifurcations
|
|
106
|
+
>>> G.nodes[node]["sub_epis"] = [
|
|
107
|
+
... {"timestamp": 5}, {"timestamp": 8}, {"timestamp": 12}
|
|
108
|
+
... ]
|
|
109
|
+
>>> rate = compute_bifurcation_rate(G, node, window=10)
|
|
110
|
+
>>> rate # 2 bifurcations in last 10 steps
|
|
111
|
+
0.2
|
|
112
|
+
"""
|
|
113
|
+
sub_epis = G.nodes[node].get("sub_epis", [])
|
|
114
|
+
if not sub_epis:
|
|
115
|
+
return 0.0
|
|
116
|
+
|
|
117
|
+
# Get current timestamp from glyph history
|
|
118
|
+
current_time = len(G.nodes[node].get("glyph_history", []))
|
|
119
|
+
|
|
120
|
+
# Count bifurcations in window
|
|
121
|
+
recent_bifurcations = [
|
|
122
|
+
s for s in sub_epis if s.get("timestamp", 0) >= (current_time - window)
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
return len(recent_bifurcations) / float(window)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def compute_metabolic_efficiency(G: TNFRGraph, node: NodeId) -> float:
|
|
129
|
+
"""Calculate EPI gain per T'HOL application (metabolic efficiency).
|
|
130
|
+
|
|
131
|
+
Metabolic efficiency measures how effectively T'HOL converts
|
|
132
|
+
reorganization events into stable structural complexity (EPI growth).
|
|
133
|
+
|
|
134
|
+
Parameters
|
|
135
|
+
----------
|
|
136
|
+
G : TNFRGraph
|
|
137
|
+
Graph containing the node
|
|
138
|
+
node : NodeId
|
|
139
|
+
Node identifier
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
float
|
|
144
|
+
Average EPI increase per T'HOL application
|
|
145
|
+
Returns 0.0 if no T'HOL applications recorded
|
|
146
|
+
|
|
147
|
+
Notes
|
|
148
|
+
-----
|
|
149
|
+
High efficiency (> 0.1) indicates:
|
|
150
|
+
- Effective self-organization
|
|
151
|
+
- Strong coherence maintenance
|
|
152
|
+
- Productive metabolic cycles
|
|
153
|
+
|
|
154
|
+
Low efficiency (< 0.01) indicates:
|
|
155
|
+
- Ineffective reorganization
|
|
156
|
+
- High structural friction
|
|
157
|
+
- Possible need for different operator sequences
|
|
158
|
+
|
|
159
|
+
Examples
|
|
160
|
+
--------
|
|
161
|
+
>>> from tnfr.structural import create_nfr
|
|
162
|
+
>>> from tnfr.metrics.emergence import compute_metabolic_efficiency
|
|
163
|
+
>>> G, node = create_nfr("productive", epi=0.5, vf=1.0)
|
|
164
|
+
>>> # Record initial EPI
|
|
165
|
+
>>> G.nodes[node]["epi_initial"] = 0.3
|
|
166
|
+
>>> # Simulate T'HOL applications
|
|
167
|
+
>>> G.nodes[node]["glyph_history"] = ["THOL", "THOL", "IL"]
|
|
168
|
+
>>> # Current EPI increased to 0.5
|
|
169
|
+
>>> efficiency = compute_metabolic_efficiency(G, node)
|
|
170
|
+
>>> efficiency # (0.5 - 0.3) / 2 = 0.1
|
|
171
|
+
0.1
|
|
172
|
+
"""
|
|
173
|
+
from ..types import Glyph
|
|
174
|
+
|
|
175
|
+
# Count T'HOL applications
|
|
176
|
+
glyph_history = G.nodes[node].get("glyph_history", [])
|
|
177
|
+
thol_count = sum(1 for g in glyph_history if g == "THOL" or g == Glyph.THOL.value)
|
|
178
|
+
|
|
179
|
+
if thol_count == 0:
|
|
180
|
+
return 0.0
|
|
181
|
+
|
|
182
|
+
# Calculate EPI delta
|
|
183
|
+
current_epi = float(get_attr(G.nodes[node], ALIAS_EPI, 0.0))
|
|
184
|
+
initial_epi = float(G.nodes[node].get("epi_initial", current_epi))
|
|
185
|
+
|
|
186
|
+
epi_gain = current_epi - initial_epi
|
|
187
|
+
|
|
188
|
+
return epi_gain / float(thol_count)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def compute_emergence_index(G: TNFRGraph, node: NodeId) -> float:
|
|
192
|
+
"""Composite metric combining complexity, rate, and efficiency.
|
|
193
|
+
|
|
194
|
+
Emergence index provides a holistic measure of T'HOL metabolic health,
|
|
195
|
+
combining structural complexity, bifurcation dynamics, and efficiency.
|
|
196
|
+
|
|
197
|
+
Parameters
|
|
198
|
+
----------
|
|
199
|
+
G : TNFRGraph
|
|
200
|
+
Graph containing the node
|
|
201
|
+
node : NodeId
|
|
202
|
+
Node identifier
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
float
|
|
207
|
+
Emergence index (0.0 to ~1.0 typical, higher indicates more emergent)
|
|
208
|
+
Computed as: sqrt(complexity * rate * efficiency)
|
|
209
|
+
|
|
210
|
+
Notes
|
|
211
|
+
-----
|
|
212
|
+
This index balances three factors:
|
|
213
|
+
- Complexity: how much structure has emerged
|
|
214
|
+
- Rate: how actively new structure forms
|
|
215
|
+
- Efficiency: how productive each reorganization is
|
|
216
|
+
|
|
217
|
+
High index (> 0.5) indicates healthy emergent dynamics.
|
|
218
|
+
Low index (< 0.1) suggests reorganization is stalled or inefficient.
|
|
219
|
+
|
|
220
|
+
Examples
|
|
221
|
+
--------
|
|
222
|
+
>>> from tnfr.structural import create_nfr
|
|
223
|
+
>>> from tnfr.metrics.emergence import compute_emergence_index
|
|
224
|
+
>>> G, node = create_nfr("emergent", epi=0.7, vf=1.0)
|
|
225
|
+
>>> # Setup for high emergence
|
|
226
|
+
>>> G.nodes[node]["epi_initial"] = 0.3
|
|
227
|
+
>>> G.nodes[node]["glyph_history"] = ["THOL", "THOL", "IL"]
|
|
228
|
+
>>> G.nodes[node]["sub_epis"] = [{"timestamp": 1}, {"timestamp": 2}]
|
|
229
|
+
>>> index = compute_emergence_index(G, node)
|
|
230
|
+
>>> index # doctest: +SKIP
|
|
231
|
+
0.63...
|
|
232
|
+
"""
|
|
233
|
+
complexity = float(compute_structural_complexity(G, node))
|
|
234
|
+
rate = compute_bifurcation_rate(G, node)
|
|
235
|
+
efficiency = compute_metabolic_efficiency(G, node)
|
|
236
|
+
|
|
237
|
+
# Geometric mean to avoid dominance by any single factor
|
|
238
|
+
# Add epsilon to avoid zero multiplication when no bifurcations occurred
|
|
239
|
+
index = (
|
|
240
|
+
(complexity + _EMERGENCE_INDEX_EPSILON)
|
|
241
|
+
* (rate + _EMERGENCE_INDEX_EPSILON)
|
|
242
|
+
* (efficiency + _EMERGENCE_INDEX_EPSILON)
|
|
243
|
+
) ** (1.0 / 3.0)
|
|
244
|
+
|
|
245
|
+
return index
|
tnfr/metrics/export.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Metrics export."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import csv
|
|
6
|
+
import math
|
|
7
|
+
from collections.abc import Iterable, Iterator, Sequence
|
|
8
|
+
from itertools import tee, zip_longest
|
|
9
|
+
from typing import Mapping, TextIO
|
|
10
|
+
|
|
11
|
+
from ..config.constants import GLYPHS_CANONICAL
|
|
12
|
+
from ..glyph_history import ensure_history
|
|
13
|
+
from ..utils import json_dumps, safe_write
|
|
14
|
+
from ..types import Graph, SigmaTrace
|
|
15
|
+
from .core import glyphogram_series
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _write_csv(
|
|
19
|
+
path: str,
|
|
20
|
+
headers: Sequence[str],
|
|
21
|
+
rows: Iterable[Sequence[object]],
|
|
22
|
+
*,
|
|
23
|
+
output_dir: str | None = None,
|
|
24
|
+
) -> None:
|
|
25
|
+
def _write(f: TextIO) -> None:
|
|
26
|
+
writer = csv.writer(f)
|
|
27
|
+
writer.writerow(headers)
|
|
28
|
+
for row in rows:
|
|
29
|
+
writer.writerow(row)
|
|
30
|
+
|
|
31
|
+
safe_write(path, _write, newline="", base_dir=output_dir)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _iter_glif_rows(
|
|
35
|
+
glyph: Mapping[str, Sequence[float]],
|
|
36
|
+
) -> Iterator[list[float]]:
|
|
37
|
+
ts = glyph.get("t", [])
|
|
38
|
+
# Precompute columns for each glyph to avoid repeated lookups.
|
|
39
|
+
# ``default_col`` is shared by reference for missing glyphs to prevent
|
|
40
|
+
# unnecessary list allocations.
|
|
41
|
+
default_col = [0] * len(ts)
|
|
42
|
+
cols = [glyph.get(g, default_col) for g in GLYPHS_CANONICAL]
|
|
43
|
+
for i, t in enumerate(ts):
|
|
44
|
+
yield [t] + [col[i] for col in cols]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def export_metrics(
|
|
48
|
+
G: Graph,
|
|
49
|
+
base_path: str,
|
|
50
|
+
fmt: str = "csv",
|
|
51
|
+
*,
|
|
52
|
+
output_dir: str | None = None,
|
|
53
|
+
) -> None:
|
|
54
|
+
"""Dump glyphogram and σ(t) trace to compact CSV or JSON files.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
G : Graph
|
|
59
|
+
The TNFR graph containing metrics to export.
|
|
60
|
+
base_path : str
|
|
61
|
+
Base filename for exported files (without extension).
|
|
62
|
+
fmt : str, default='csv'
|
|
63
|
+
Export format: 'csv' or 'json'.
|
|
64
|
+
output_dir : str | None, optional
|
|
65
|
+
Output directory to restrict exports. If provided, all exports
|
|
66
|
+
must stay within this directory (prevents path traversal).
|
|
67
|
+
|
|
68
|
+
Raises
|
|
69
|
+
------
|
|
70
|
+
ValueError
|
|
71
|
+
If the path is invalid or format is unsupported.
|
|
72
|
+
PathTraversalError
|
|
73
|
+
If path traversal is detected when output_dir is provided.
|
|
74
|
+
"""
|
|
75
|
+
from pathlib import Path
|
|
76
|
+
|
|
77
|
+
hist = ensure_history(G)
|
|
78
|
+
glyph = glyphogram_series(G)
|
|
79
|
+
sigma_x = hist.get("sense_sigma_x", [])
|
|
80
|
+
sigma_y = hist.get("sense_sigma_y", [])
|
|
81
|
+
sigma_mag = hist.get("sense_sigma_mag", [])
|
|
82
|
+
sigma_angle = hist.get("sense_sigma_angle", [])
|
|
83
|
+
t_series = hist.get("sense_sigma_t", []) or glyph.get("t", [])
|
|
84
|
+
rows_raw = zip_longest(
|
|
85
|
+
t_series, sigma_x, sigma_y, sigma_mag, sigma_angle, fillvalue=None
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def _clean(value: float | None) -> float:
|
|
89
|
+
"""Return ``0`` for ``None`` or ``NaN`` values."""
|
|
90
|
+
if value is None or (isinstance(value, float) and math.isnan(value)):
|
|
91
|
+
return 0
|
|
92
|
+
return value
|
|
93
|
+
|
|
94
|
+
def _gen_rows() -> Iterator[tuple[float, float, float, float, float]]:
|
|
95
|
+
for i, (t, x, y, m, a) in enumerate(rows_raw):
|
|
96
|
+
yield (
|
|
97
|
+
i if t is None else t,
|
|
98
|
+
_clean(x),
|
|
99
|
+
_clean(y),
|
|
100
|
+
_clean(m),
|
|
101
|
+
_clean(a),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
rows_csv, rows_sigma = tee(_gen_rows())
|
|
105
|
+
|
|
106
|
+
sigma: SigmaTrace = {
|
|
107
|
+
"t": [],
|
|
108
|
+
"sigma_x": [],
|
|
109
|
+
"sigma_y": [],
|
|
110
|
+
"mag": [],
|
|
111
|
+
"angle": [],
|
|
112
|
+
}
|
|
113
|
+
for t, x, y, m, a in rows_sigma:
|
|
114
|
+
sigma["t"].append(t)
|
|
115
|
+
sigma["sigma_x"].append(x)
|
|
116
|
+
sigma["sigma_y"].append(y)
|
|
117
|
+
sigma["mag"].append(m)
|
|
118
|
+
sigma["angle"].append(a)
|
|
119
|
+
morph: Sequence[Mapping[str, float]] = hist.get("morph", [])
|
|
120
|
+
epi_supp: Sequence[Mapping[str, float]] = hist.get("EPI_support", [])
|
|
121
|
+
fmt = fmt.lower()
|
|
122
|
+
if fmt not in {"csv", "json"}:
|
|
123
|
+
raise ValueError(f"Unsupported export format: {fmt}")
|
|
124
|
+
if fmt == "csv":
|
|
125
|
+
specs: list[tuple[str, Sequence[str], Iterable[Sequence[object]]]] = [
|
|
126
|
+
(
|
|
127
|
+
"_glyphogram.csv",
|
|
128
|
+
["t", *GLYPHS_CANONICAL],
|
|
129
|
+
_iter_glif_rows(glyph),
|
|
130
|
+
),
|
|
131
|
+
(
|
|
132
|
+
"_sigma.csv",
|
|
133
|
+
["t", "x", "y", "mag", "angle"],
|
|
134
|
+
([t, x, y, m, a] for t, x, y, m, a in rows_csv),
|
|
135
|
+
),
|
|
136
|
+
]
|
|
137
|
+
if morph:
|
|
138
|
+
specs.append(
|
|
139
|
+
(
|
|
140
|
+
"_morph.csv",
|
|
141
|
+
["t", "ID", "CM", "NE", "PP"],
|
|
142
|
+
(
|
|
143
|
+
[
|
|
144
|
+
row.get("t"),
|
|
145
|
+
row.get("ID"),
|
|
146
|
+
row.get("CM"),
|
|
147
|
+
row.get("NE"),
|
|
148
|
+
row.get("PP"),
|
|
149
|
+
]
|
|
150
|
+
for row in morph
|
|
151
|
+
),
|
|
152
|
+
)
|
|
153
|
+
)
|
|
154
|
+
if epi_supp:
|
|
155
|
+
specs.append(
|
|
156
|
+
(
|
|
157
|
+
"_epi_support.csv",
|
|
158
|
+
["t", "size", "epi_norm"],
|
|
159
|
+
(
|
|
160
|
+
[row.get("t"), row.get("size"), row.get("epi_norm")]
|
|
161
|
+
for row in epi_supp
|
|
162
|
+
),
|
|
163
|
+
)
|
|
164
|
+
)
|
|
165
|
+
for suffix, headers, rows in specs:
|
|
166
|
+
_write_csv(base_path + suffix, headers, rows, output_dir=output_dir)
|
|
167
|
+
else:
|
|
168
|
+
data = {
|
|
169
|
+
"glyphogram": glyph,
|
|
170
|
+
"sigma": sigma,
|
|
171
|
+
"morph": morph,
|
|
172
|
+
"epi_support": epi_supp,
|
|
173
|
+
}
|
|
174
|
+
json_path = base_path + ".json"
|
|
175
|
+
|
|
176
|
+
def _write_json(f: TextIO) -> None:
|
|
177
|
+
f.write(json_dumps(data))
|
|
178
|
+
|
|
179
|
+
safe_write(json_path, _write_json, base_dir=output_dir)
|
tnfr/metrics/export.pyi
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from ..config.constants import GLYPHS_CANONICAL as GLYPHS_CANONICAL
|
|
2
|
+
from ..glyph_history import ensure_history as ensure_history
|
|
3
|
+
from ..types import Graph as Graph, SigmaTrace as SigmaTrace
|
|
4
|
+
from ..utils import json_dumps as json_dumps, safe_write as safe_write
|
|
5
|
+
from .core import glyphogram_series as glyphogram_series
|
|
6
|
+
|
|
7
|
+
def export_metrics(G: Graph, base_path: str, fmt: str = "csv") -> None: ...
|