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,364 @@
|
|
|
1
|
+
"""Strict precondition validation for RA (Resonance) operator.
|
|
2
|
+
|
|
3
|
+
This module implements canonical precondition validation for the Resonance (RA)
|
|
4
|
+
structural operator according to TNFR theory. RA requires specific structural
|
|
5
|
+
conditions to maintain TNFR operational fidelity:
|
|
6
|
+
|
|
7
|
+
1. **Coherent source EPI**: Node must have sufficient structural form for propagation
|
|
8
|
+
2. **Network connectivity**: Edges must exist for resonance to propagate through
|
|
9
|
+
3. **Phase compatibility**: Node must be synchronized with neighbors (coupling)
|
|
10
|
+
4. **Controlled dissonance**: ΔNFR must not be excessive (stable resonance)
|
|
11
|
+
5. **Sufficient νf**: Structural frequency must support propagation dynamics
|
|
12
|
+
|
|
13
|
+
These validations protect structural integrity by ensuring RA is only applied to
|
|
14
|
+
nodes in the appropriate state for coherence propagation through the network.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import warnings
|
|
20
|
+
from typing import TYPE_CHECKING, Any
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from ...types import TNFRGraph
|
|
24
|
+
|
|
25
|
+
__all__ = ["validate_resonance_strict", "diagnose_resonance_readiness"]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def validate_resonance_strict(
|
|
29
|
+
G: TNFRGraph,
|
|
30
|
+
node: Any,
|
|
31
|
+
*,
|
|
32
|
+
min_epi: float | None = None,
|
|
33
|
+
require_coupling: bool = True,
|
|
34
|
+
max_dissonance: float | None = None,
|
|
35
|
+
warn_phase_misalignment: bool = True,
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Validate strict canonical preconditions for RA (Resonance) operator.
|
|
38
|
+
|
|
39
|
+
According to TNFR theory, Resonance (RA - Resonancia) requires:
|
|
40
|
+
|
|
41
|
+
1. **Coherent source**: EPI >= threshold (sufficient structure to propagate)
|
|
42
|
+
2. **Network connectivity**: degree > 0 (edges for propagation)
|
|
43
|
+
3. **Phase compatibility**: alignment with neighbors (synchronization)
|
|
44
|
+
4. **Controlled dissonance**: |ΔNFR| < threshold (stable for resonance)
|
|
45
|
+
5. **Sufficient νf**: νf > threshold (capacity for propagation dynamics)
|
|
46
|
+
|
|
47
|
+
Canonical sequences that satisfy preconditions:
|
|
48
|
+
- **UM → RA**: Coupling establishes connections, then resonance propagates
|
|
49
|
+
- **AL → RA**: Emission activates source, then resonance broadcasts
|
|
50
|
+
- **IL → RA**: Coherence stabilizes, then propagates stable form
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
G : TNFRGraph
|
|
55
|
+
Graph containing the node to validate
|
|
56
|
+
node : Any
|
|
57
|
+
Node identifier for validation
|
|
58
|
+
min_epi : float, optional
|
|
59
|
+
Minimum EPI magnitude for resonance source
|
|
60
|
+
Default: Uses G.graph["RA_MIN_SOURCE_EPI"] or 0.1
|
|
61
|
+
require_coupling : bool, default True
|
|
62
|
+
If True, validates that node has edges (connectivity)
|
|
63
|
+
max_dissonance : float, optional
|
|
64
|
+
Maximum allowed |ΔNFR| for resonance
|
|
65
|
+
Default: Uses G.graph["RA_MAX_DISSONANCE"] or 0.5
|
|
66
|
+
warn_phase_misalignment : bool, default True
|
|
67
|
+
If True, warns when phase difference with neighbors is high
|
|
68
|
+
|
|
69
|
+
Raises
|
|
70
|
+
------
|
|
71
|
+
ValueError
|
|
72
|
+
If EPI < min_epi (insufficient structure to propagate)
|
|
73
|
+
If require_coupling=True and node has no edges
|
|
74
|
+
If |ΔNFR| > max_dissonance (too unstable for resonance)
|
|
75
|
+
If νf < threshold (insufficient structural frequency)
|
|
76
|
+
|
|
77
|
+
Warnings
|
|
78
|
+
--------
|
|
79
|
+
UserWarning
|
|
80
|
+
If phase misalignment with neighbors exceeds threshold (suboptimal resonance)
|
|
81
|
+
If node is isolated but require_coupling=False
|
|
82
|
+
|
|
83
|
+
Notes
|
|
84
|
+
-----
|
|
85
|
+
Thresholds are configurable via graph metadata:
|
|
86
|
+
- ``RA_MIN_SOURCE_EPI``: Minimum EPI for source (default: 0.1)
|
|
87
|
+
- ``RA_MAX_DISSONANCE``: Maximum |ΔNFR| (default: 0.5)
|
|
88
|
+
- ``RA_MAX_PHASE_DIFF``: Maximum phase difference in radians (default: 1.0)
|
|
89
|
+
- ``RA_MIN_VF``: Minimum structural frequency (default: 0.01)
|
|
90
|
+
|
|
91
|
+
Examples
|
|
92
|
+
--------
|
|
93
|
+
>>> from tnfr.structural import create_nfr
|
|
94
|
+
>>> from tnfr.operators.preconditions.resonance import validate_resonance_strict
|
|
95
|
+
>>>
|
|
96
|
+
>>> # Valid node for resonance
|
|
97
|
+
>>> G, node = create_nfr("source", epi=0.8, vf=0.9)
|
|
98
|
+
>>> neighbor = "neighbor"
|
|
99
|
+
>>> G.add_node(neighbor, epi=0.5, vf=0.8, theta=0.1, dnfr=0.05, epi_kind="seed")
|
|
100
|
+
>>> G.add_edge(node, neighbor)
|
|
101
|
+
>>> G.nodes[node]["dnfr"] = 0.1
|
|
102
|
+
>>> validate_resonance_strict(G, node) # OK
|
|
103
|
+
|
|
104
|
+
>>> # Invalid: EPI too low
|
|
105
|
+
>>> G2, node2 = create_nfr("weak_source", epi=0.05, vf=0.9)
|
|
106
|
+
>>> neighbor2 = "neighbor2"
|
|
107
|
+
>>> G2.add_node(neighbor2, epi=0.5, vf=0.8, theta=0.1, dnfr=0.05, epi_kind="seed")
|
|
108
|
+
>>> G2.add_edge(node2, neighbor2)
|
|
109
|
+
>>> validate_resonance_strict(G2, node2) # doctest: +SKIP
|
|
110
|
+
Traceback (most recent call last):
|
|
111
|
+
...
|
|
112
|
+
ValueError: RA requires coherent source with EPI >= 0.1 (current: 0.050). Apply IL or THOL first.
|
|
113
|
+
|
|
114
|
+
>>> # Invalid: No connectivity
|
|
115
|
+
>>> G3, node3 = create_nfr("isolated", epi=0.8, vf=0.9)
|
|
116
|
+
>>> validate_resonance_strict(G3, node3) # doctest: +SKIP
|
|
117
|
+
Traceback (most recent call last):
|
|
118
|
+
...
|
|
119
|
+
ValueError: RA requires network connectivity (node has no edges). Apply UM (Coupling) first.
|
|
120
|
+
|
|
121
|
+
See Also
|
|
122
|
+
--------
|
|
123
|
+
tnfr.operators.definitions.Resonance : Resonance operator implementation
|
|
124
|
+
tnfr.operators.definitions.Coupling : Establishes connectivity for RA
|
|
125
|
+
diagnose_resonance_readiness : Diagnostic function for RA readiness
|
|
126
|
+
"""
|
|
127
|
+
from ...alias import get_attr
|
|
128
|
+
from ...constants.aliases import ALIAS_DNFR, ALIAS_EPI, ALIAS_THETA, ALIAS_VF
|
|
129
|
+
from ...utils.numeric import angle_diff
|
|
130
|
+
|
|
131
|
+
# Get configuration with defensive fallbacks
|
|
132
|
+
if min_epi is None:
|
|
133
|
+
min_epi = float(G.graph.get("RA_MIN_SOURCE_EPI", 0.1))
|
|
134
|
+
if max_dissonance is None:
|
|
135
|
+
max_dissonance = float(G.graph.get("RA_MAX_DISSONANCE", 0.5))
|
|
136
|
+
min_vf = float(G.graph.get("RA_MIN_VF", 0.01))
|
|
137
|
+
max_phase_diff = float(G.graph.get("RA_MAX_PHASE_DIFF", 1.0)) # ~60 degrees
|
|
138
|
+
|
|
139
|
+
# 1. Validate coherent source EPI
|
|
140
|
+
epi = abs(float(get_attr(G.nodes[node], ALIAS_EPI, 0.0)))
|
|
141
|
+
if epi < min_epi:
|
|
142
|
+
raise ValueError(
|
|
143
|
+
f"RA requires coherent source with EPI >= {min_epi:.1f} "
|
|
144
|
+
f"(current: {epi:.3f}). Apply IL or THOL first."
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# 2. Validate network connectivity
|
|
148
|
+
neighbors = list(G.neighbors(node))
|
|
149
|
+
if require_coupling:
|
|
150
|
+
if not neighbors:
|
|
151
|
+
raise ValueError(
|
|
152
|
+
f"RA requires network connectivity (node has no edges). "
|
|
153
|
+
"Apply UM (Coupling) first to establish resonant links."
|
|
154
|
+
)
|
|
155
|
+
elif not neighbors:
|
|
156
|
+
# Node is isolated but require_coupling=False - issue warning
|
|
157
|
+
warnings.warn(
|
|
158
|
+
f"Node {node} is isolated - RA will have no propagation effect. "
|
|
159
|
+
"Consider applying UM (Coupling) first.",
|
|
160
|
+
UserWarning,
|
|
161
|
+
stacklevel=3,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# 3. Validate sufficient structural frequency
|
|
165
|
+
vf = float(get_attr(G.nodes[node], ALIAS_VF, 0.0))
|
|
166
|
+
if vf < min_vf:
|
|
167
|
+
raise ValueError(
|
|
168
|
+
f"RA requires sufficient structural frequency νf >= {min_vf:.2f} "
|
|
169
|
+
f"(current: {vf:.3f}). Apply AL (Emission) or VAL (Expansion) first."
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# 4. Validate controlled dissonance
|
|
173
|
+
dnfr = abs(float(get_attr(G.nodes[node], ALIAS_DNFR, 0.0)))
|
|
174
|
+
if dnfr > max_dissonance:
|
|
175
|
+
raise ValueError(
|
|
176
|
+
f"RA requires controlled dissonance with |ΔNFR| <= {max_dissonance:.1f} "
|
|
177
|
+
f"(current: {dnfr:.3f}). Apply IL (Coherence) first to stabilize."
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# 5. Validate phase compatibility (warning only, neighbors exist)
|
|
181
|
+
if warn_phase_misalignment and neighbors:
|
|
182
|
+
try:
|
|
183
|
+
from ...metrics.trig import neighbor_phase_mean
|
|
184
|
+
|
|
185
|
+
theta_node = float(get_attr(G.nodes[node], ALIAS_THETA, 0.0))
|
|
186
|
+
theta_neighbors = neighbor_phase_mean(G, node)
|
|
187
|
+
phase_diff = abs(angle_diff(theta_neighbors, theta_node))
|
|
188
|
+
|
|
189
|
+
if phase_diff > max_phase_diff:
|
|
190
|
+
warnings.warn(
|
|
191
|
+
f"RA phase misalignment: Δφ = {phase_diff:.2f} > {max_phase_diff:.2f}. "
|
|
192
|
+
"Consider applying UM (Coupling) first for better resonance.",
|
|
193
|
+
UserWarning,
|
|
194
|
+
stacklevel=3,
|
|
195
|
+
)
|
|
196
|
+
except Exception:
|
|
197
|
+
# Phase validation is optional, don't fail if unavailable
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def diagnose_resonance_readiness(G: TNFRGraph, node: Any) -> dict[str, Any]:
|
|
202
|
+
"""Diagnose node readiness for RA (Resonance) operator.
|
|
203
|
+
|
|
204
|
+
Provides comprehensive diagnostic report with readiness status and
|
|
205
|
+
actionable recommendations for RA operator application.
|
|
206
|
+
|
|
207
|
+
Parameters
|
|
208
|
+
----------
|
|
209
|
+
G : TNFRGraph
|
|
210
|
+
Graph containing the node
|
|
211
|
+
node : Any
|
|
212
|
+
Node to diagnose
|
|
213
|
+
|
|
214
|
+
Returns
|
|
215
|
+
-------
|
|
216
|
+
dict
|
|
217
|
+
Diagnostic report with:
|
|
218
|
+
- ``ready``: bool - overall readiness status
|
|
219
|
+
- ``checks``: dict - individual check results (passed/failed/warning)
|
|
220
|
+
- ``values``: dict - current node state values
|
|
221
|
+
- ``recommendations``: list - actionable steps to achieve readiness
|
|
222
|
+
- ``canonical_sequences``: list - suggested operator sequences
|
|
223
|
+
|
|
224
|
+
Examples
|
|
225
|
+
--------
|
|
226
|
+
>>> from tnfr.structural import create_nfr
|
|
227
|
+
>>> from tnfr.operators.preconditions.resonance import diagnose_resonance_readiness
|
|
228
|
+
>>>
|
|
229
|
+
>>> # Diagnose weak source
|
|
230
|
+
>>> G, node = create_nfr("weak", epi=0.05, vf=0.9)
|
|
231
|
+
>>> diag = diagnose_resonance_readiness(G, node)
|
|
232
|
+
>>> diag["ready"]
|
|
233
|
+
False
|
|
234
|
+
>>> "coherent_source" in diag["checks"]
|
|
235
|
+
True
|
|
236
|
+
>>> diag["checks"]["coherent_source"]
|
|
237
|
+
'failed'
|
|
238
|
+
>>> "Apply IL (Coherence) or THOL (Self-organization)" in diag["recommendations"][0]
|
|
239
|
+
True
|
|
240
|
+
|
|
241
|
+
See Also
|
|
242
|
+
--------
|
|
243
|
+
validate_resonance_strict : Strict precondition validator
|
|
244
|
+
"""
|
|
245
|
+
from ...alias import get_attr
|
|
246
|
+
from ...constants.aliases import ALIAS_DNFR, ALIAS_EPI, ALIAS_THETA, ALIAS_VF
|
|
247
|
+
from ...utils.numeric import angle_diff
|
|
248
|
+
|
|
249
|
+
# Get thresholds
|
|
250
|
+
min_epi = float(G.graph.get("RA_MIN_SOURCE_EPI", 0.1))
|
|
251
|
+
max_dissonance = float(G.graph.get("RA_MAX_DISSONANCE", 0.5))
|
|
252
|
+
min_vf = float(G.graph.get("RA_MIN_VF", 0.01))
|
|
253
|
+
max_phase_diff = float(G.graph.get("RA_MAX_PHASE_DIFF", 1.0))
|
|
254
|
+
|
|
255
|
+
# Get current state
|
|
256
|
+
epi = abs(float(get_attr(G.nodes[node], ALIAS_EPI, 0.0)))
|
|
257
|
+
vf = float(get_attr(G.nodes[node], ALIAS_VF, 0.0))
|
|
258
|
+
dnfr = abs(float(get_attr(G.nodes[node], ALIAS_DNFR, 0.0)))
|
|
259
|
+
theta = float(get_attr(G.nodes[node], ALIAS_THETA, 0.0))
|
|
260
|
+
neighbors = list(G.neighbors(node))
|
|
261
|
+
neighbor_count = len(neighbors)
|
|
262
|
+
|
|
263
|
+
# Initialize checks
|
|
264
|
+
checks = {}
|
|
265
|
+
recommendations = []
|
|
266
|
+
|
|
267
|
+
# Check 1: Coherent source
|
|
268
|
+
if epi >= min_epi:
|
|
269
|
+
checks["coherent_source"] = "passed"
|
|
270
|
+
else:
|
|
271
|
+
checks["coherent_source"] = "failed"
|
|
272
|
+
recommendations.append(
|
|
273
|
+
f"Apply IL (Coherence) or THOL (Self-organization) to increase EPI "
|
|
274
|
+
f"from {epi:.3f} to >= {min_epi:.1f}"
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
# Check 2: Network connectivity
|
|
278
|
+
if neighbor_count > 0:
|
|
279
|
+
checks["network_connectivity"] = "passed"
|
|
280
|
+
else:
|
|
281
|
+
checks["network_connectivity"] = "failed"
|
|
282
|
+
recommendations.append(
|
|
283
|
+
"Apply UM (Coupling) to establish network connections before RA"
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
# Check 3: Structural frequency
|
|
287
|
+
if vf >= min_vf:
|
|
288
|
+
checks["structural_frequency"] = "passed"
|
|
289
|
+
else:
|
|
290
|
+
checks["structural_frequency"] = "failed"
|
|
291
|
+
recommendations.append(
|
|
292
|
+
f"Apply AL (Emission) or VAL (Expansion) to increase νf "
|
|
293
|
+
f"from {vf:.3f} to >= {min_vf:.2f}"
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# Check 4: Controlled dissonance
|
|
297
|
+
if dnfr <= max_dissonance:
|
|
298
|
+
checks["controlled_dissonance"] = "passed"
|
|
299
|
+
else:
|
|
300
|
+
checks["controlled_dissonance"] = "failed"
|
|
301
|
+
recommendations.append(
|
|
302
|
+
f"Apply IL (Coherence) to reduce |ΔNFR| from {dnfr:.3f} "
|
|
303
|
+
f"to <= {max_dissonance:.1f}"
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# Check 5: Phase alignment (warning only)
|
|
307
|
+
phase_diff = None
|
|
308
|
+
if neighbor_count > 0:
|
|
309
|
+
try:
|
|
310
|
+
from ...metrics.trig import neighbor_phase_mean
|
|
311
|
+
|
|
312
|
+
theta_neighbors = neighbor_phase_mean(G, node)
|
|
313
|
+
phase_diff = abs(angle_diff(theta_neighbors, theta))
|
|
314
|
+
|
|
315
|
+
if phase_diff <= max_phase_diff:
|
|
316
|
+
checks["phase_alignment"] = "passed"
|
|
317
|
+
else:
|
|
318
|
+
checks["phase_alignment"] = "warning"
|
|
319
|
+
recommendations.append(
|
|
320
|
+
f"Consider applying UM (Coupling) to improve phase alignment "
|
|
321
|
+
f"(current: Δφ = {phase_diff:.2f}, optimal: <= {max_phase_diff:.2f})"
|
|
322
|
+
)
|
|
323
|
+
except Exception:
|
|
324
|
+
checks["phase_alignment"] = "unavailable"
|
|
325
|
+
else:
|
|
326
|
+
checks["phase_alignment"] = "n/a"
|
|
327
|
+
|
|
328
|
+
# Determine overall readiness
|
|
329
|
+
critical_checks = [
|
|
330
|
+
"coherent_source",
|
|
331
|
+
"network_connectivity",
|
|
332
|
+
"structural_frequency",
|
|
333
|
+
"controlled_dissonance",
|
|
334
|
+
]
|
|
335
|
+
ready = all(checks.get(check) == "passed" for check in critical_checks)
|
|
336
|
+
|
|
337
|
+
# Canonical sequences
|
|
338
|
+
canonical_sequences = [
|
|
339
|
+
"UM → RA (Coupling then Resonance)",
|
|
340
|
+
"AL → RA (Emission then Resonance)",
|
|
341
|
+
"IL → RA (Coherence then Resonance)",
|
|
342
|
+
"AL → EN → IL → UM → RA (Full activation sequence)",
|
|
343
|
+
]
|
|
344
|
+
|
|
345
|
+
return {
|
|
346
|
+
"ready": ready,
|
|
347
|
+
"checks": checks,
|
|
348
|
+
"values": {
|
|
349
|
+
"epi": epi,
|
|
350
|
+
"vf": vf,
|
|
351
|
+
"dnfr": dnfr,
|
|
352
|
+
"theta": theta,
|
|
353
|
+
"neighbor_count": neighbor_count,
|
|
354
|
+
"phase_diff": phase_diff,
|
|
355
|
+
},
|
|
356
|
+
"recommendations": recommendations,
|
|
357
|
+
"canonical_sequences": canonical_sequences,
|
|
358
|
+
"thresholds": {
|
|
359
|
+
"min_epi": min_epi,
|
|
360
|
+
"max_dissonance": max_dissonance,
|
|
361
|
+
"min_vf": min_vf,
|
|
362
|
+
"max_phase_diff": max_phase_diff,
|
|
363
|
+
},
|
|
364
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Registry mapping operator names to their classes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib
|
|
6
|
+
import pkgutil
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from ..config.operator_names import canonical_operator_name
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING: # pragma: no cover - type checking only
|
|
12
|
+
from .definitions import Operator
|
|
13
|
+
|
|
14
|
+
OPERATORS: dict[str, type["Operator"]] = {}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def register_operator(cls: type["Operator"]) -> type["Operator"]:
|
|
18
|
+
"""Register ``cls`` under its declared ``name`` in :data:`OPERATORS`."""
|
|
19
|
+
|
|
20
|
+
name = getattr(cls, "name", None)
|
|
21
|
+
if not isinstance(name, str) or not name:
|
|
22
|
+
raise ValueError(
|
|
23
|
+
f"Operator {cls.__name__} must declare a non-empty 'name' attribute"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
existing = OPERATORS.get(name)
|
|
27
|
+
if existing is not None and existing is not cls:
|
|
28
|
+
raise ValueError(f"Operator '{name}' is already registered")
|
|
29
|
+
|
|
30
|
+
OPERATORS[name] = cls
|
|
31
|
+
return cls
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_operator_class(name: str) -> type["Operator"]:
|
|
35
|
+
"""Return the operator class registered for ``name`` or its canonical alias."""
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
return OPERATORS[name]
|
|
39
|
+
except KeyError:
|
|
40
|
+
canonical = canonical_operator_name(name)
|
|
41
|
+
if canonical == name:
|
|
42
|
+
raise
|
|
43
|
+
try:
|
|
44
|
+
return OPERATORS[canonical]
|
|
45
|
+
except KeyError as exc: # pragma: no cover - defensive branch
|
|
46
|
+
raise KeyError(name) from exc
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def discover_operators() -> None:
|
|
50
|
+
"""Import all operator submodules so their decorators run."""
|
|
51
|
+
|
|
52
|
+
package = importlib.import_module("tnfr.operators")
|
|
53
|
+
package_path = getattr(package, "__path__", None)
|
|
54
|
+
if not package_path:
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
if getattr(package, "_operators_discovered", False): # pragma: no cover - cache
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
prefix = f"{package.__name__}."
|
|
61
|
+
for module_info in pkgutil.walk_packages(package_path, prefix):
|
|
62
|
+
if module_info.name == f"{prefix}registry":
|
|
63
|
+
continue
|
|
64
|
+
importlib.import_module(module_info.name)
|
|
65
|
+
|
|
66
|
+
setattr(package, "_operators_discovered", True)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
__all__ = (
|
|
70
|
+
"OPERATORS",
|
|
71
|
+
"register_operator",
|
|
72
|
+
"discover_operators",
|
|
73
|
+
"get_operator_class",
|
|
74
|
+
)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from .definitions import Operator
|
|
2
|
+
|
|
3
|
+
__all__ = ["OPERATORS", "register_operator", "discover_operators", "get_operator_class"]
|
|
4
|
+
|
|
5
|
+
OPERATORS: dict[str, type[Operator]]
|
|
6
|
+
|
|
7
|
+
def register_operator(cls: type[Operator]) -> type[Operator]: ...
|
|
8
|
+
def get_operator_class(name: str) -> type[Operator]: ...
|
|
9
|
+
def discover_operators() -> None: ...
|