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,305 @@
|
|
|
1
|
+
"""Strict precondition validation for IL (Coherence) operator.
|
|
2
|
+
|
|
3
|
+
This module implements canonical precondition validation for the Coherence (IL)
|
|
4
|
+
structural operator according to TNFR.pdf §2.2.1. IL requires specific structural
|
|
5
|
+
conditions to maintain TNFR operational fidelity:
|
|
6
|
+
|
|
7
|
+
1. **Active EPI**: Node must have non-zero structural form (EPI > 0)
|
|
8
|
+
2. **Non-saturated EPI**: EPI must be below maximum (leave room for stabilization increment)
|
|
9
|
+
3. **Active νf**: Structural frequency must exceed minimum threshold
|
|
10
|
+
4. **ΔNFR presence**: While IL reduces ΔNFR, some reorganization pressure should exist
|
|
11
|
+
5. **ΔNFR not critical**: Excessive ΔNFR may require OZ (Dissonance) first
|
|
12
|
+
6. **Network coupling**: Connections enable phase locking
|
|
13
|
+
|
|
14
|
+
These validations protect structural integrity by ensuring IL is only applied to
|
|
15
|
+
nodes in the appropriate state for coherence stabilization.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import TYPE_CHECKING, Any
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from ...types import TNFRGraph
|
|
24
|
+
|
|
25
|
+
__all__ = ["validate_coherence_strict", "diagnose_coherence_readiness"]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def validate_coherence_strict(G: TNFRGraph, node: Any) -> None:
|
|
29
|
+
"""Validate strict canonical preconditions for IL (Coherence) operator.
|
|
30
|
+
|
|
31
|
+
According to TNFR.pdf §2.2.1, Coherence (IL - Coherencia estructural) requires:
|
|
32
|
+
|
|
33
|
+
1. **Active EPI**: EPI > 0 (node must have active structural form)
|
|
34
|
+
2. **Non-saturated EPI**: EPI < maximum (leave room for stabilization)
|
|
35
|
+
3. **Active νf**: νf > threshold (sufficient structural frequency)
|
|
36
|
+
4. **ΔNFR presence**: ΔNFR > 0 (reorganization pressure to stabilize)
|
|
37
|
+
5. **ΔNFR not critical**: ΔNFR < critical threshold (manageable instability)
|
|
38
|
+
6. **Network coupling**: degree > 0 (connections for phase locking)
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
G : TNFRGraph
|
|
43
|
+
Graph containing the node to validate
|
|
44
|
+
node : Any
|
|
45
|
+
Node identifier for validation
|
|
46
|
+
|
|
47
|
+
Raises
|
|
48
|
+
------
|
|
49
|
+
ValueError
|
|
50
|
+
If EPI <= 0 (no structural form to stabilize)
|
|
51
|
+
If EPI >= maximum (node saturated - consider NUL/Contraction)
|
|
52
|
+
If νf <= 0 (no structural frequency - consider AL/Emission or NAV/Transition)
|
|
53
|
+
|
|
54
|
+
Warnings
|
|
55
|
+
--------
|
|
56
|
+
UserWarning
|
|
57
|
+
If ΔNFR == 0 (no reorganization pressure - IL may be redundant)
|
|
58
|
+
If ΔNFR > critical threshold (high instability - consider OZ/Dissonance first)
|
|
59
|
+
If node is isolated (no connections - phase locking will have no effect)
|
|
60
|
+
|
|
61
|
+
Notes
|
|
62
|
+
-----
|
|
63
|
+
Thresholds are configurable via:
|
|
64
|
+
- Graph metadata: ``G.graph["IL_PRECONDITIONS"]``
|
|
65
|
+
- Module defaults: :data:`tnfr.config.thresholds.EPI_IL_MAX`, etc.
|
|
66
|
+
|
|
67
|
+
Examples
|
|
68
|
+
--------
|
|
69
|
+
>>> from tnfr.structural import create_nfr
|
|
70
|
+
>>> from tnfr.operators.preconditions.coherence import validate_coherence_strict
|
|
71
|
+
>>> G, node = create_nfr("test", epi=0.5, vf=0.9)
|
|
72
|
+
>>> G.nodes[node]["dnfr"] = 0.1
|
|
73
|
+
>>> validate_coherence_strict(G, node) # OK - active state with reorganization pressure
|
|
74
|
+
|
|
75
|
+
>>> G2, node2 = create_nfr("inactive", epi=0.0, vf=0.9)
|
|
76
|
+
>>> validate_coherence_strict(G2, node2) # doctest: +SKIP
|
|
77
|
+
Traceback (most recent call last):
|
|
78
|
+
...
|
|
79
|
+
ValueError: IL precondition failed: EPI=0.000 <= 0.0. IL requires active structural form.
|
|
80
|
+
|
|
81
|
+
See Also
|
|
82
|
+
--------
|
|
83
|
+
tnfr.config.thresholds : Configurable threshold constants
|
|
84
|
+
tnfr.operators.preconditions : Base precondition validators
|
|
85
|
+
tnfr.operators.definitions.Coherence : Coherence operator implementation
|
|
86
|
+
diagnose_coherence_readiness : Diagnostic function for IL readiness
|
|
87
|
+
"""
|
|
88
|
+
import warnings
|
|
89
|
+
|
|
90
|
+
from ...alias import get_attr
|
|
91
|
+
from ...constants.aliases import ALIAS_DNFR, ALIAS_EPI, ALIAS_VF
|
|
92
|
+
from ...config.thresholds import (
|
|
93
|
+
DNFR_IL_CRITICAL,
|
|
94
|
+
EPI_IL_MAX,
|
|
95
|
+
EPI_IL_MIN,
|
|
96
|
+
VF_IL_MIN,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Get current node state
|
|
100
|
+
epi = float(get_attr(G.nodes[node], ALIAS_EPI, 0.0))
|
|
101
|
+
vf = float(get_attr(G.nodes[node], ALIAS_VF, 0.0))
|
|
102
|
+
dnfr = float(get_attr(G.nodes[node], ALIAS_DNFR, 0.0))
|
|
103
|
+
|
|
104
|
+
# Get configurable thresholds (allow override via graph metadata)
|
|
105
|
+
config = G.graph.get("IL_PRECONDITIONS", {})
|
|
106
|
+
min_epi = float(config.get("min_epi", EPI_IL_MIN))
|
|
107
|
+
max_epi = float(config.get("max_epi", EPI_IL_MAX))
|
|
108
|
+
min_vf = float(config.get("min_vf", VF_IL_MIN))
|
|
109
|
+
dnfr_critical = float(config.get("dnfr_critical_threshold", DNFR_IL_CRITICAL))
|
|
110
|
+
warn_isolated = bool(config.get("warn_isolated", True))
|
|
111
|
+
warn_zero_dnfr = bool(config.get("warn_zero_dnfr", True))
|
|
112
|
+
|
|
113
|
+
# Precondition 1: EPI must be active (non-zero structural form)
|
|
114
|
+
# IL stabilizes existing structure - requires structure to exist
|
|
115
|
+
if epi <= min_epi:
|
|
116
|
+
raise ValueError(
|
|
117
|
+
f"IL precondition failed: EPI={epi:.3f} <= {min_epi:.3f}. "
|
|
118
|
+
f"IL requires active structural form (non-zero EPI). "
|
|
119
|
+
f"Suggestion: Apply AL (Emission) first to activate node."
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Precondition 2: EPI must not be saturated (leave room for stabilization)
|
|
123
|
+
# IL may increment EPI slightly during stabilization
|
|
124
|
+
if epi >= max_epi:
|
|
125
|
+
raise ValueError(
|
|
126
|
+
f"IL precondition failed: EPI={epi:.3f} >= {max_epi:.3f}. "
|
|
127
|
+
f"Node saturated, cannot stabilize further. "
|
|
128
|
+
f"Suggestion: Consider NUL (Contraction) to consolidate structure."
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Precondition 3: νf must be active (sufficient structural frequency)
|
|
132
|
+
# IL requires active reorganization capacity to effect stabilization
|
|
133
|
+
if vf <= min_vf:
|
|
134
|
+
raise ValueError(
|
|
135
|
+
f"IL precondition failed: νf={vf:.3f} <= {min_vf:.3f}. "
|
|
136
|
+
f"Structural frequency too low for coherence stabilization. "
|
|
137
|
+
f"Suggestion: Apply AL (Emission) or NAV (Transition) to activate νf first."
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Precondition 4: Check for ΔNFR presence (warning only - not hard failure)
|
|
141
|
+
# IL reduces ΔNFR, but if ΔNFR is already zero, IL is redundant
|
|
142
|
+
if warn_zero_dnfr and dnfr == 0.0:
|
|
143
|
+
warnings.warn(
|
|
144
|
+
f"IL warning: Node {node!r} has ΔNFR=0. "
|
|
145
|
+
f"No reorganization pressure to stabilize. "
|
|
146
|
+
f"IL application may be redundant in this state.",
|
|
147
|
+
UserWarning,
|
|
148
|
+
stacklevel=3,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Precondition 5: Check for critically high ΔNFR (warning only)
|
|
152
|
+
# Excessive instability may require controlled dissonance (OZ) before stabilization
|
|
153
|
+
if dnfr > dnfr_critical:
|
|
154
|
+
warnings.warn(
|
|
155
|
+
f"IL warning: Node {node!r} has ΔNFR={dnfr:.3f} > {dnfr_critical:.3f}. "
|
|
156
|
+
f"High reorganization pressure - stabilization may be difficult. "
|
|
157
|
+
f"Consider applying OZ (Dissonance) → IL sequence for better control.",
|
|
158
|
+
UserWarning,
|
|
159
|
+
stacklevel=3,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# Precondition 6: Check for network connections (warning only)
|
|
163
|
+
# Isolated nodes can stabilize but phase locking will have no effect
|
|
164
|
+
degree = G.degree(node)
|
|
165
|
+
network_size = len(G)
|
|
166
|
+
if warn_isolated and degree == 0 and network_size > 1:
|
|
167
|
+
warnings.warn(
|
|
168
|
+
f"IL warning: Node {node!r} isolated (degree=0). "
|
|
169
|
+
f"Phase locking will have no effect. "
|
|
170
|
+
f"Consider applying UM (Coupling) first to connect node to network.",
|
|
171
|
+
UserWarning,
|
|
172
|
+
stacklevel=3,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def diagnose_coherence_readiness(G: TNFRGraph, node: Any) -> dict:
|
|
177
|
+
"""Diagnose node readiness for IL (Coherence) operator.
|
|
178
|
+
|
|
179
|
+
Performs all canonical precondition checks and returns a diagnostic report
|
|
180
|
+
with readiness status and actionable recommendations.
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
G : TNFRGraph
|
|
185
|
+
Graph containing the node
|
|
186
|
+
node : Any
|
|
187
|
+
Node identifier for diagnosis
|
|
188
|
+
|
|
189
|
+
Returns
|
|
190
|
+
-------
|
|
191
|
+
dict
|
|
192
|
+
Diagnostic report with the following structure:
|
|
193
|
+
|
|
194
|
+
- ``node``: Node identifier
|
|
195
|
+
- ``ready``: bool - Overall readiness (all critical checks passed)
|
|
196
|
+
- ``checks``: dict - Individual check results
|
|
197
|
+
|
|
198
|
+
- ``epi_active``: bool - EPI > 0
|
|
199
|
+
- ``epi_not_saturated``: bool - EPI < maximum
|
|
200
|
+
- ``vf_active``: bool - νf > 0
|
|
201
|
+
- ``dnfr_present``: bool - ΔNFR > 0 (warning only)
|
|
202
|
+
- ``dnfr_not_critical``: bool - ΔNFR < critical (warning only)
|
|
203
|
+
- ``has_connections``: bool - degree > 0 (warning only)
|
|
204
|
+
|
|
205
|
+
- ``values``: dict - Current node attribute values
|
|
206
|
+
|
|
207
|
+
- ``epi``: Current EPI value
|
|
208
|
+
- ``vf``: Current νf value
|
|
209
|
+
- ``dnfr``: Current ΔNFR value
|
|
210
|
+
- ``degree``: Node degree
|
|
211
|
+
|
|
212
|
+
- ``recommendations``: list[str] - Actionable suggestions
|
|
213
|
+
|
|
214
|
+
Examples
|
|
215
|
+
--------
|
|
216
|
+
>>> from tnfr.structural import create_nfr
|
|
217
|
+
>>> from tnfr.operators.preconditions.coherence import diagnose_coherence_readiness
|
|
218
|
+
>>> G, node = create_nfr("test", epi=0.5, vf=0.9)
|
|
219
|
+
>>> G.nodes[node]["dnfr"] = 0.1
|
|
220
|
+
>>> report = diagnose_coherence_readiness(G, node)
|
|
221
|
+
>>> report["ready"]
|
|
222
|
+
True
|
|
223
|
+
>>> "✓ Node ready" in report["recommendations"][0]
|
|
224
|
+
True
|
|
225
|
+
|
|
226
|
+
See Also
|
|
227
|
+
--------
|
|
228
|
+
validate_coherence_strict : Strict precondition validator
|
|
229
|
+
"""
|
|
230
|
+
from ...alias import get_attr
|
|
231
|
+
from ...constants.aliases import ALIAS_DNFR, ALIAS_EPI, ALIAS_VF
|
|
232
|
+
from ...config.thresholds import (
|
|
233
|
+
DNFR_IL_CRITICAL,
|
|
234
|
+
EPI_IL_MAX,
|
|
235
|
+
EPI_IL_MIN,
|
|
236
|
+
VF_IL_MIN,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
# Get current node state
|
|
240
|
+
epi = float(get_attr(G.nodes[node], ALIAS_EPI, 0.0))
|
|
241
|
+
vf = float(get_attr(G.nodes[node], ALIAS_VF, 0.0))
|
|
242
|
+
dnfr = float(get_attr(G.nodes[node], ALIAS_DNFR, 0.0))
|
|
243
|
+
degree = G.degree(node)
|
|
244
|
+
|
|
245
|
+
# Get configurable thresholds
|
|
246
|
+
config = G.graph.get("IL_PRECONDITIONS", {})
|
|
247
|
+
min_epi = float(config.get("min_epi", EPI_IL_MIN))
|
|
248
|
+
max_epi = float(config.get("max_epi", EPI_IL_MAX))
|
|
249
|
+
min_vf = float(config.get("min_vf", VF_IL_MIN))
|
|
250
|
+
dnfr_critical = float(config.get("dnfr_critical_threshold", DNFR_IL_CRITICAL))
|
|
251
|
+
|
|
252
|
+
# Perform checks
|
|
253
|
+
checks = {
|
|
254
|
+
"epi_active": epi > min_epi,
|
|
255
|
+
"epi_not_saturated": epi < max_epi,
|
|
256
|
+
"vf_active": vf > min_vf,
|
|
257
|
+
"dnfr_present": dnfr > 0.0,
|
|
258
|
+
"dnfr_not_critical": dnfr < dnfr_critical,
|
|
259
|
+
"has_connections": degree > 0,
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
# Critical checks (hard failures)
|
|
263
|
+
critical_checks = ["epi_active", "epi_not_saturated", "vf_active"]
|
|
264
|
+
all_critical_passed = all(checks[key] for key in critical_checks)
|
|
265
|
+
|
|
266
|
+
# Generate recommendations
|
|
267
|
+
recommendations = []
|
|
268
|
+
|
|
269
|
+
if not checks["epi_active"]:
|
|
270
|
+
recommendations.append("Apply AL (Emission) to activate node")
|
|
271
|
+
|
|
272
|
+
if checks["epi_active"] and not checks["epi_not_saturated"]:
|
|
273
|
+
recommendations.append(
|
|
274
|
+
"Apply NUL (Contraction) to consolidate saturated structure"
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
if not checks["vf_active"]:
|
|
278
|
+
recommendations.append("Apply AL (Emission) or NAV (Transition) to activate νf")
|
|
279
|
+
|
|
280
|
+
if checks["epi_active"] and not checks["dnfr_present"]:
|
|
281
|
+
recommendations.append("⚠ ΔNFR=0 - IL may be redundant")
|
|
282
|
+
|
|
283
|
+
if checks["dnfr_present"] and not checks["dnfr_not_critical"]:
|
|
284
|
+
recommendations.append("⚠ High ΔNFR - consider OZ (Dissonance) → IL sequence")
|
|
285
|
+
|
|
286
|
+
if not checks["has_connections"]:
|
|
287
|
+
recommendations.append(
|
|
288
|
+
"⚠ Isolated node - consider UM (Coupling) to enable phase locking"
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
if all_critical_passed:
|
|
292
|
+
recommendations.insert(0, "✓ Node ready for IL (Coherence)")
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
"node": node,
|
|
296
|
+
"ready": all_critical_passed,
|
|
297
|
+
"checks": checks,
|
|
298
|
+
"values": {
|
|
299
|
+
"epi": epi,
|
|
300
|
+
"vf": vf,
|
|
301
|
+
"dnfr": dnfr,
|
|
302
|
+
"degree": degree,
|
|
303
|
+
},
|
|
304
|
+
"recommendations": recommendations,
|
|
305
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"""Strict precondition validation for OZ (Dissonance) operator.
|
|
2
|
+
|
|
3
|
+
This module implements canonical precondition validation for the Dissonance (OZ)
|
|
4
|
+
structural operator according to TNFR canonical theory. OZ requires specific
|
|
5
|
+
structural conditions to enable productive dissonance without premature collapse:
|
|
6
|
+
|
|
7
|
+
1. **Minimum coherence base (EPI)**: Node must have sufficient structural form to
|
|
8
|
+
withstand disruption (EPI >= threshold)
|
|
9
|
+
2. **ΔNFR not critically high**: Avoid sobrecarga (overload) when ΔNFR already extreme
|
|
10
|
+
3. **Sufficient νf**: Structural frequency must support reorganization response
|
|
11
|
+
4. **No overload pattern**: Detect sobrecarga disonante (multiple OZ without resolution)
|
|
12
|
+
5. **Network connectivity**: Warn if isolated (bifurcation requires alternative paths)
|
|
13
|
+
|
|
14
|
+
These validations implement the canonical warning from TNFR.pdf:
|
|
15
|
+
> "OZ debe ir precedido por estabilización adecuada (IL). Genera nodos frágiles o
|
|
16
|
+
> fallidos si se aplica sobre estructuras sin coherencia interna."
|
|
17
|
+
|
|
18
|
+
References
|
|
19
|
+
----------
|
|
20
|
+
- TNFR.pdf §2.3.6: Catálogo de errores arquetípicos (Sobrecarga disonante)
|
|
21
|
+
- TNFR.pdf §2.3.3: Reglas sintácticas R4 (Bifurcación)
|
|
22
|
+
- Tabla de validación estructural: Condiciones de activación de OZ
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from typing import TYPE_CHECKING, Any
|
|
28
|
+
|
|
29
|
+
if TYPE_CHECKING:
|
|
30
|
+
from ...types import TNFRGraph
|
|
31
|
+
|
|
32
|
+
__all__ = ["validate_dissonance_strict"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def validate_dissonance_strict(G: TNFRGraph, node: Any) -> None:
|
|
36
|
+
"""Validate strict canonical preconditions for OZ (Dissonance) operator.
|
|
37
|
+
|
|
38
|
+
According to TNFR canonical theory, Dissonance (OZ - Disonancia) requires:
|
|
39
|
+
|
|
40
|
+
1. **Coherence base**: EPI >= threshold (sufficient structure to withstand disruption)
|
|
41
|
+
2. **ΔNFR safety**: |ΔNFR| < critical (avoid overload/collapse)
|
|
42
|
+
3. **Active νf**: νf >= threshold (capacity to respond to dissonance)
|
|
43
|
+
4. **No overload**: < 2 consecutive OZ without resolution (IL/THOL/NUL)
|
|
44
|
+
5. **Network connectivity**: degree >= 1 (warning only - enables bifurcation paths)
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
G : TNFRGraph
|
|
49
|
+
Graph containing the node to validate
|
|
50
|
+
node : Any
|
|
51
|
+
Node identifier for validation
|
|
52
|
+
|
|
53
|
+
Raises
|
|
54
|
+
------
|
|
55
|
+
ValueError
|
|
56
|
+
If EPI < minimum (insufficient coherence base - apply IL first)
|
|
57
|
+
If |ΔNFR| > maximum (reorganization pressure critical - apply IL first)
|
|
58
|
+
If νf < minimum (cannot respond to dissonance)
|
|
59
|
+
If overload detected (>= 2 OZ without resolver operators)
|
|
60
|
+
|
|
61
|
+
Warnings
|
|
62
|
+
--------
|
|
63
|
+
UserWarning
|
|
64
|
+
If node has low connectivity (degree < 1) - bifurcation paths limited
|
|
65
|
+
|
|
66
|
+
Notes
|
|
67
|
+
-----
|
|
68
|
+
Thresholds are configurable via graph metadata:
|
|
69
|
+
- ``G.graph["OZ_MIN_EPI"]``: Minimum EPI (default 0.2)
|
|
70
|
+
- ``G.graph["OZ_MAX_DNFR"]``: Maximum |ΔNFR| (default 0.8)
|
|
71
|
+
- ``G.graph["OZ_MIN_VF"]``: Minimum νf (default 0.1)
|
|
72
|
+
- ``G.graph["OZ_MIN_DEGREE"]``: Minimum degree for warning (default 1)
|
|
73
|
+
|
|
74
|
+
**Resolver operators** that integrate dissonance (reset overload counter):
|
|
75
|
+
- IL (Coherence): Stabilizes structure
|
|
76
|
+
- THOL (Self-organization): Creates sub-EPIs
|
|
77
|
+
- NUL (Contraction): Simplifies structure
|
|
78
|
+
|
|
79
|
+
Examples
|
|
80
|
+
--------
|
|
81
|
+
>>> from tnfr.structural import create_nfr
|
|
82
|
+
>>> from tnfr.operators.preconditions.dissonance import validate_dissonance_strict
|
|
83
|
+
>>> G, node = create_nfr("test", epi=0.5, vf=1.0)
|
|
84
|
+
>>> G.nodes[node]["dnfr"] = 0.3
|
|
85
|
+
>>> validate_dissonance_strict(G, node) # OK - sufficient coherence base
|
|
86
|
+
|
|
87
|
+
>>> G2, node2 = create_nfr("weak", epi=0.05, vf=1.0)
|
|
88
|
+
>>> validate_dissonance_strict(G2, node2) # doctest: +SKIP
|
|
89
|
+
Traceback (most recent call last):
|
|
90
|
+
...
|
|
91
|
+
ValueError: OZ precondition failed: EPI=0.050 < 0.2. Insufficient coherence base.
|
|
92
|
+
|
|
93
|
+
See Also
|
|
94
|
+
--------
|
|
95
|
+
tnfr.operators.preconditions : Base precondition validators
|
|
96
|
+
tnfr.operators.definitions.Dissonance : Dissonance operator implementation
|
|
97
|
+
"""
|
|
98
|
+
import warnings
|
|
99
|
+
|
|
100
|
+
from ...alias import get_attr
|
|
101
|
+
from ...constants.aliases import ALIAS_DNFR, ALIAS_EPI, ALIAS_VF
|
|
102
|
+
|
|
103
|
+
# Get current node state
|
|
104
|
+
epi = float(get_attr(G.nodes[node], ALIAS_EPI, 0.0))
|
|
105
|
+
vf = float(get_attr(G.nodes[node], ALIAS_VF, 0.0))
|
|
106
|
+
dnfr = float(get_attr(G.nodes[node], ALIAS_DNFR, 0.0))
|
|
107
|
+
degree = G.degree(node)
|
|
108
|
+
|
|
109
|
+
# Get configurable thresholds
|
|
110
|
+
min_epi = float(G.graph.get("OZ_MIN_EPI", 0.2))
|
|
111
|
+
max_dnfr = float(G.graph.get("OZ_MAX_DNFR", 0.8))
|
|
112
|
+
min_vf = float(G.graph.get("OZ_MIN_VF", 0.1))
|
|
113
|
+
min_degree = int(G.graph.get("OZ_MIN_DEGREE", 1))
|
|
114
|
+
|
|
115
|
+
# Precondition 1: Minimum coherence base (EPI)
|
|
116
|
+
# OZ requires existing structure to perturb - without it, OZ causes collapse
|
|
117
|
+
if epi < min_epi:
|
|
118
|
+
raise ValueError(
|
|
119
|
+
f"OZ precondition failed: EPI={epi:.3f} < {min_epi:.3f}. "
|
|
120
|
+
f"Insufficient coherence base to withstand dissonance. "
|
|
121
|
+
f"Suggestion: Apply IL (Coherence) first to stabilize node before introducing dissonance."
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Precondition 2: ΔNFR not critically high
|
|
125
|
+
# Applying OZ when ΔNFR already extreme creates sobrecarga (overload) → collapse
|
|
126
|
+
if abs(dnfr) > max_dnfr:
|
|
127
|
+
raise ValueError(
|
|
128
|
+
f"OZ precondition failed: |ΔNFR|={abs(dnfr):.3f} > {max_dnfr:.3f}. "
|
|
129
|
+
f"Reorganization pressure already critical - applying OZ risks collapse. "
|
|
130
|
+
f"Suggestion: Apply IL (Coherence) first to reduce ΔNFR before introducing more dissonance."
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Precondition 3: Sufficient νf for reorganization response
|
|
134
|
+
# OZ triggers reorganization - node needs capacity (νf) to respond
|
|
135
|
+
if vf < min_vf:
|
|
136
|
+
raise ValueError(
|
|
137
|
+
f"OZ precondition failed: νf={vf:.3f} < {min_vf:.3f}. "
|
|
138
|
+
f"Structural frequency too low - node lacks capacity to respond to dissonance. "
|
|
139
|
+
f"Suggestion: Increase νf before applying OZ."
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Precondition 4: Detect OZ overload (sobrecarga disonante)
|
|
143
|
+
# Multiple OZ without resolution = entropic loop (violates R5)
|
|
144
|
+
_validate_oz_no_overload(G, node)
|
|
145
|
+
|
|
146
|
+
# Precondition 5: Network connectivity (warning only - not blocking)
|
|
147
|
+
# Isolated nodes can experience dissonance but bifurcation paths are limited
|
|
148
|
+
if degree < min_degree:
|
|
149
|
+
warnings.warn(
|
|
150
|
+
f"OZ warning: Node {node!r} has low connectivity (degree={degree} < {min_degree}). "
|
|
151
|
+
f"OZ-induced bifurcation may have limited structural paths. "
|
|
152
|
+
f"Consider applying UM (Coupling) first to increase network coupling.",
|
|
153
|
+
UserWarning,
|
|
154
|
+
stacklevel=3,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# Store validation context for telemetry
|
|
158
|
+
G.nodes[node]["_oz_precondition_context"] = {
|
|
159
|
+
"epi": epi,
|
|
160
|
+
"dnfr": dnfr,
|
|
161
|
+
"vf": vf,
|
|
162
|
+
"degree": degree,
|
|
163
|
+
"validation_passed": True,
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _validate_oz_no_overload(G: TNFRGraph, node: Any) -> None:
|
|
168
|
+
"""Detect and prevent dissonance overload (sobrecarga disonante).
|
|
169
|
+
|
|
170
|
+
Sobrecarga occurs when multiple OZ operators are applied in succession
|
|
171
|
+
without intervening resolution operators (IL, THOL, NUL). This creates
|
|
172
|
+
entropic loops that violate TNFR structural coherence requirements.
|
|
173
|
+
|
|
174
|
+
Parameters
|
|
175
|
+
----------
|
|
176
|
+
G : TNFRGraph
|
|
177
|
+
Graph containing the node
|
|
178
|
+
node : Any
|
|
179
|
+
Node identifier to check for overload
|
|
180
|
+
|
|
181
|
+
Raises
|
|
182
|
+
------
|
|
183
|
+
ValueError
|
|
184
|
+
If >= 1 OZ application detected in recent history without resolver
|
|
185
|
+
(since we're about to apply another OZ, that would make it >= 2)
|
|
186
|
+
|
|
187
|
+
Notes
|
|
188
|
+
-----
|
|
189
|
+
**Resolver operators** that integrate dissonance:
|
|
190
|
+
- coherence (IL): Stabilizes structure, reduces ΔNFR
|
|
191
|
+
- self_organization (THOL): Creates sub-EPIs via bifurcation
|
|
192
|
+
- contraction (NUL): Simplifies structure
|
|
193
|
+
|
|
194
|
+
This check examines the last 5 operators in glyph_history to detect
|
|
195
|
+
overload patterns. Since validation is called BEFORE the operator is
|
|
196
|
+
applied, if we find >= 1 OZ in history without a resolver, applying
|
|
197
|
+
another OZ would create overload.
|
|
198
|
+
|
|
199
|
+
References
|
|
200
|
+
----------
|
|
201
|
+
TNFR.pdf §2.3.6 - Sobrecarga disonante: "acumulación excesiva de OZ sin
|
|
202
|
+
paso a mutación"
|
|
203
|
+
"""
|
|
204
|
+
from ...operators.grammar import glyph_function_name
|
|
205
|
+
|
|
206
|
+
# Get glyph history from node
|
|
207
|
+
history = G.nodes[node].get("glyph_history", [])
|
|
208
|
+
if not history:
|
|
209
|
+
# No history - first operator application, cannot be overload
|
|
210
|
+
return
|
|
211
|
+
|
|
212
|
+
# Convert deque to list and examine recent history (last 5 operations)
|
|
213
|
+
history_list = list(history)
|
|
214
|
+
recent_history = history_list[-5:] if len(history_list) >= 5 else history_list
|
|
215
|
+
|
|
216
|
+
# Count OZ applications in recent history
|
|
217
|
+
oz_count = sum(
|
|
218
|
+
1 for glyph in recent_history if glyph_function_name(glyph) == "dissonance"
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# If >= 1 OZ in history, check for resolver operators
|
|
222
|
+
# (we're about to apply another OZ, so that would make >= 2 total)
|
|
223
|
+
if oz_count >= 1:
|
|
224
|
+
# Resolver operators that integrate dissonance
|
|
225
|
+
resolvers = {"coherence", "self_organization", "contraction"}
|
|
226
|
+
recent_names = [glyph_function_name(g) for g in recent_history]
|
|
227
|
+
has_resolver = any(name in resolvers for name in recent_names)
|
|
228
|
+
|
|
229
|
+
if not has_resolver:
|
|
230
|
+
raise ValueError(
|
|
231
|
+
f"OZ precondition failed: Sobrecarga disonante detected. "
|
|
232
|
+
f"Found {oz_count} OZ in recent history without resolution. "
|
|
233
|
+
f"Applying another OZ without resolving previous dissonance risks collapse. "
|
|
234
|
+
f"Suggestion: Apply IL (Coherence), THOL (Self-organization), or NUL (Contraction) "
|
|
235
|
+
f"to integrate dissonance before introducing more."
|
|
236
|
+
)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Strict precondition validation for AL (Emission) operator.
|
|
2
|
+
|
|
3
|
+
This module implements canonical precondition validation for the Emission (AL)
|
|
4
|
+
structural operator according to TNFR.pdf §2.2.1. AL requires specific structural
|
|
5
|
+
conditions to maintain TNFR operational fidelity:
|
|
6
|
+
|
|
7
|
+
1. **Latent state**: EPI must be below activation threshold (node not already active)
|
|
8
|
+
2. **Basal frequency**: νf must exceed minimum threshold (sufficient reorganization capacity)
|
|
9
|
+
3. **Coupling availability**: Network connectivity for phase alignment (warning for isolated nodes)
|
|
10
|
+
|
|
11
|
+
These validations protect structural integrity by ensuring AL is only applied to
|
|
12
|
+
nodes in the appropriate state for foundational emission.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import TYPE_CHECKING, Any
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from ...types import TNFRGraph
|
|
21
|
+
|
|
22
|
+
__all__ = ["validate_emission_strict"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def validate_emission_strict(G: TNFRGraph, node: Any) -> None:
|
|
26
|
+
"""Validate strict canonical preconditions for AL (Emission) operator.
|
|
27
|
+
|
|
28
|
+
According to TNFR.pdf §2.2.1, Emission (AL - Emisión fundacional) requires:
|
|
29
|
+
|
|
30
|
+
1. **Latent state**: EPI < threshold (node must be in latent or low-activation state)
|
|
31
|
+
2. **Basal frequency**: νf > threshold (sufficient structural frequency for activation)
|
|
32
|
+
3. **Coupling availability**: Network connectivity (warning if isolated)
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
G : TNFRGraph
|
|
37
|
+
Graph containing the node to validate
|
|
38
|
+
node : Any
|
|
39
|
+
Node identifier for validation
|
|
40
|
+
|
|
41
|
+
Raises
|
|
42
|
+
------
|
|
43
|
+
ValueError
|
|
44
|
+
If EPI >= latent threshold (node already active - consider IL/Coherence instead)
|
|
45
|
+
If νf < basal threshold (frequency too low - consider NAV/Transition first)
|
|
46
|
+
|
|
47
|
+
Warnings
|
|
48
|
+
--------
|
|
49
|
+
UserWarning
|
|
50
|
+
If node is isolated in a multi-node network (limited coupling - consider UM/Coupling first)
|
|
51
|
+
|
|
52
|
+
Notes
|
|
53
|
+
-----
|
|
54
|
+
Thresholds are configurable via:
|
|
55
|
+
- Graph metadata: ``G.graph["EPI_LATENT_MAX"]``, ``G.graph["VF_BASAL_THRESHOLD"]``
|
|
56
|
+
- Module defaults: :data:`tnfr.config.thresholds.EPI_LATENT_MAX`, etc.
|
|
57
|
+
|
|
58
|
+
Examples
|
|
59
|
+
--------
|
|
60
|
+
>>> from tnfr.structural import create_nfr
|
|
61
|
+
>>> from tnfr.operators.preconditions.emission import validate_emission_strict
|
|
62
|
+
>>> G, node = create_nfr("test", epi=0.25, vf=0.95)
|
|
63
|
+
>>> validate_emission_strict(G, node) # OK - latent state with sufficient frequency
|
|
64
|
+
|
|
65
|
+
>>> G2, node2 = create_nfr("active", epi=0.85, vf=1.0)
|
|
66
|
+
>>> validate_emission_strict(G2, node2) # doctest: +SKIP
|
|
67
|
+
Traceback (most recent call last):
|
|
68
|
+
...
|
|
69
|
+
ValueError: AL precondition failed: EPI=0.850 >= 0.8. AL requires latent state. Consider IL (Coherence) instead.
|
|
70
|
+
|
|
71
|
+
See Also
|
|
72
|
+
--------
|
|
73
|
+
tnfr.config.thresholds : Configurable threshold constants
|
|
74
|
+
tnfr.operators.preconditions : Base precondition validators
|
|
75
|
+
tnfr.operators.definitions.Emission : Emission operator implementation
|
|
76
|
+
"""
|
|
77
|
+
import warnings
|
|
78
|
+
|
|
79
|
+
from ...alias import get_attr
|
|
80
|
+
from ...constants.aliases import ALIAS_EPI, ALIAS_VF
|
|
81
|
+
from ...config.thresholds import (
|
|
82
|
+
EPI_LATENT_MAX,
|
|
83
|
+
MIN_NETWORK_DEGREE_COUPLING,
|
|
84
|
+
VF_BASAL_THRESHOLD,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Get current node state
|
|
88
|
+
epi = float(get_attr(G.nodes[node], ALIAS_EPI, 0.0))
|
|
89
|
+
vf = float(get_attr(G.nodes[node], ALIAS_VF, 0.0))
|
|
90
|
+
|
|
91
|
+
# Get configurable thresholds (allow override via graph metadata)
|
|
92
|
+
epi_threshold = float(G.graph.get("EPI_LATENT_MAX", EPI_LATENT_MAX))
|
|
93
|
+
vf_threshold = float(G.graph.get("VF_BASAL_THRESHOLD", VF_BASAL_THRESHOLD))
|
|
94
|
+
min_degree = int(
|
|
95
|
+
G.graph.get("MIN_NETWORK_DEGREE_COUPLING", MIN_NETWORK_DEGREE_COUPLING)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Precondition 1: EPI must be below latent threshold (node in latent state)
|
|
99
|
+
# Emission is for activating nascent/latent structures, not boosting active ones
|
|
100
|
+
if epi >= epi_threshold:
|
|
101
|
+
raise ValueError(
|
|
102
|
+
f"AL precondition failed: EPI={epi:.3f} >= {epi_threshold:.3f}. "
|
|
103
|
+
f"AL requires latent state (node not already highly active). "
|
|
104
|
+
f"Consider IL (Coherence) to stabilize active nodes instead."
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Precondition 2: νf must exceed basal threshold (sufficient frequency for emission)
|
|
108
|
+
# Below basal frequency, node lacks capacity to sustain structural activation
|
|
109
|
+
if vf < vf_threshold:
|
|
110
|
+
raise ValueError(
|
|
111
|
+
f"AL precondition failed: νf={vf:.3f} < {vf_threshold:.3f}. "
|
|
112
|
+
f"Structural frequency too low for emission. "
|
|
113
|
+
f"Consider NAV (Transition) to increase frequency first."
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Precondition 3: Network connectivity (warning only - not a hard failure)
|
|
117
|
+
# Isolated nodes can still emit, but phase coupling will be limited
|
|
118
|
+
node_degree = G.degree(node)
|
|
119
|
+
network_size = len(G)
|
|
120
|
+
|
|
121
|
+
if node_degree < min_degree and network_size > 1:
|
|
122
|
+
warnings.warn(
|
|
123
|
+
f"AL warning: Node {node!r} has degree {node_degree} < {min_degree}. "
|
|
124
|
+
f"Emission possible but phase coupling limited (isolated node). "
|
|
125
|
+
f"Consider UM (Coupling) to establish network connections first.",
|
|
126
|
+
UserWarning,
|
|
127
|
+
stacklevel=3,
|
|
128
|
+
)
|