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,460 @@
|
|
|
1
|
+
"""Canonical TNFR compatibility tables expressed via structural operators."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
|
|
7
|
+
from ..config.operator_names import (
|
|
8
|
+
COHERENCE,
|
|
9
|
+
CONTRACTION,
|
|
10
|
+
COUPLING,
|
|
11
|
+
DISSONANCE,
|
|
12
|
+
EMISSION,
|
|
13
|
+
EXPANSION,
|
|
14
|
+
MUTATION,
|
|
15
|
+
RECEPTION,
|
|
16
|
+
RECURSIVITY,
|
|
17
|
+
RESONANCE,
|
|
18
|
+
SELF_ORGANIZATION,
|
|
19
|
+
SILENCE,
|
|
20
|
+
TRANSITION,
|
|
21
|
+
)
|
|
22
|
+
from ..operators import grammar as _grammar
|
|
23
|
+
from ..types import Glyph
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"CANON_COMPAT",
|
|
27
|
+
"CANON_FALLBACK",
|
|
28
|
+
"CompatibilityLevel",
|
|
29
|
+
"GRADUATED_COMPATIBILITY",
|
|
30
|
+
"get_compatibility_level",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class CompatibilityLevel(Enum):
|
|
35
|
+
"""Graduated compatibility levels for structural operator transitions.
|
|
36
|
+
|
|
37
|
+
Reflects the theoretical richness of TNFR by distinguishing between
|
|
38
|
+
optimal, acceptable, contextual, and incompatible transitions.
|
|
39
|
+
|
|
40
|
+
Attributes
|
|
41
|
+
----------
|
|
42
|
+
EXCELLENT : str
|
|
43
|
+
Optimal transition that directly supports structural coherence.
|
|
44
|
+
Example: EMISSION → COHERENCE (initiation → stabilization)
|
|
45
|
+
GOOD : str
|
|
46
|
+
Acceptable transition that maintains structural integrity.
|
|
47
|
+
Example: EMISSION → RESONANCE (initiation → amplification)
|
|
48
|
+
CAUTION : str
|
|
49
|
+
Contextually dependent transition requiring careful validation.
|
|
50
|
+
Example: EMISSION → DISSONANCE (initiation → tension)
|
|
51
|
+
Generates warnings to alert users of potential incoherence.
|
|
52
|
+
AVOID : str
|
|
53
|
+
Incompatible transition that violates structural coherence.
|
|
54
|
+
Example: SILENCE → DISSONANCE (pause → tension is contradictory)
|
|
55
|
+
Raises SequenceSyntaxError when encountered.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
EXCELLENT = "excellent"
|
|
59
|
+
GOOD = "good"
|
|
60
|
+
CAUTION = "caution"
|
|
61
|
+
AVOID = "avoid"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# Graduated compatibility matrix expressing structural operator transition quality
|
|
65
|
+
# Maps each operator to its allowed next operators categorized by compatibility level
|
|
66
|
+
GRADUATED_COMPATIBILITY: dict[str, dict[str, list[str]]] = {
|
|
67
|
+
# EMISSION (AL) - Initiates resonant patterns, seeds coherence outward
|
|
68
|
+
EMISSION: {
|
|
69
|
+
"excellent": [
|
|
70
|
+
COHERENCE,
|
|
71
|
+
TRANSITION,
|
|
72
|
+
RECEPTION,
|
|
73
|
+
], # Initiation → stabilization/handoff/anchoring
|
|
74
|
+
"good": [RESONANCE, EXPANSION, COUPLING], # Amplification, exploration, linking
|
|
75
|
+
"caution": [DISSONANCE], # Direct tension after initiation requires context
|
|
76
|
+
"avoid": [
|
|
77
|
+
SILENCE,
|
|
78
|
+
EMISSION,
|
|
79
|
+
MUTATION,
|
|
80
|
+
CONTRACTION,
|
|
81
|
+
SELF_ORGANIZATION,
|
|
82
|
+
RECURSIVITY,
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
# RECEPTION (EN) - Anchors inbound energy into the EPI
|
|
86
|
+
RECEPTION: {
|
|
87
|
+
"excellent": [
|
|
88
|
+
COHERENCE,
|
|
89
|
+
COUPLING,
|
|
90
|
+
SELF_ORGANIZATION,
|
|
91
|
+
], # Anchoring → stabilization/linking/autonomous cascades
|
|
92
|
+
"good": [RESONANCE], # Amplification after receiving
|
|
93
|
+
"caution": [],
|
|
94
|
+
"avoid": [
|
|
95
|
+
SILENCE,
|
|
96
|
+
EMISSION,
|
|
97
|
+
DISSONANCE,
|
|
98
|
+
EXPANSION,
|
|
99
|
+
CONTRACTION,
|
|
100
|
+
MUTATION,
|
|
101
|
+
TRANSITION,
|
|
102
|
+
RECURSIVITY,
|
|
103
|
+
RECEPTION,
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
# COHERENCE (IL) - Compresses ΔNFR drift to stabilize C(t)
|
|
107
|
+
COHERENCE: {
|
|
108
|
+
"excellent": [
|
|
109
|
+
RESONANCE,
|
|
110
|
+
EXPANSION,
|
|
111
|
+
COUPLING,
|
|
112
|
+
], # Stability → amplification/exploration/linking
|
|
113
|
+
"good": [
|
|
114
|
+
SILENCE,
|
|
115
|
+
TRANSITION,
|
|
116
|
+
CONTRACTION,
|
|
117
|
+
SELF_ORGANIZATION,
|
|
118
|
+
RECURSIVITY,
|
|
119
|
+
], # Valid progressions
|
|
120
|
+
"caution": [
|
|
121
|
+
MUTATION,
|
|
122
|
+
DISSONANCE,
|
|
123
|
+
], # Post-stabilization tension/mutation needs context
|
|
124
|
+
"avoid": [
|
|
125
|
+
EMISSION,
|
|
126
|
+
RECEPTION,
|
|
127
|
+
COHERENCE,
|
|
128
|
+
], # Cannot re-initiate, re-anchor, or re-stabilize
|
|
129
|
+
},
|
|
130
|
+
# DISSONANCE (OZ) - Injects controlled tension for probes
|
|
131
|
+
DISSONANCE: {
|
|
132
|
+
"excellent": [
|
|
133
|
+
MUTATION,
|
|
134
|
+
TRANSITION,
|
|
135
|
+
SELF_ORGANIZATION,
|
|
136
|
+
], # Tension → transformation/handoff/reorganization
|
|
137
|
+
"good": [
|
|
138
|
+
CONTRACTION,
|
|
139
|
+
RESONANCE,
|
|
140
|
+
RECURSIVITY,
|
|
141
|
+
COHERENCE,
|
|
142
|
+
], # Concentration, amplification, fractal echo, stabilization
|
|
143
|
+
"caution": [DISSONANCE], # Repeated dissonance needs careful management
|
|
144
|
+
"avoid": [SILENCE, EMISSION, RECEPTION, COUPLING, EXPANSION],
|
|
145
|
+
},
|
|
146
|
+
# COUPLING (UM) - Synchronizes bidirectional coherence links
|
|
147
|
+
COUPLING: {
|
|
148
|
+
"excellent": [
|
|
149
|
+
RESONANCE,
|
|
150
|
+
COHERENCE,
|
|
151
|
+
EXPANSION,
|
|
152
|
+
], # Linking → amplification/stabilization/exploration
|
|
153
|
+
"good": [TRANSITION, SILENCE], # Handoff or pause after coupling
|
|
154
|
+
"caution": [],
|
|
155
|
+
"avoid": [
|
|
156
|
+
EMISSION,
|
|
157
|
+
RECEPTION,
|
|
158
|
+
DISSONANCE,
|
|
159
|
+
CONTRACTION,
|
|
160
|
+
MUTATION,
|
|
161
|
+
SELF_ORGANIZATION,
|
|
162
|
+
RECURSIVITY,
|
|
163
|
+
COUPLING,
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
# RESONANCE (RA) - Amplifies aligned structural frequency
|
|
167
|
+
RESONANCE: {
|
|
168
|
+
"excellent": [
|
|
169
|
+
COHERENCE,
|
|
170
|
+
EXPANSION,
|
|
171
|
+
COUPLING,
|
|
172
|
+
], # Amplification → stabilization/exploration/linking
|
|
173
|
+
"good": [
|
|
174
|
+
TRANSITION,
|
|
175
|
+
SILENCE,
|
|
176
|
+
EMISSION,
|
|
177
|
+
RECURSIVITY,
|
|
178
|
+
], # Handoff, pause, re-initiation, fractal echo
|
|
179
|
+
"caution": [],
|
|
180
|
+
"avoid": [
|
|
181
|
+
RECEPTION,
|
|
182
|
+
DISSONANCE,
|
|
183
|
+
CONTRACTION,
|
|
184
|
+
MUTATION,
|
|
185
|
+
SELF_ORGANIZATION,
|
|
186
|
+
RESONANCE,
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
# SILENCE (SHA) - Suspends reorganization while preserving form
|
|
190
|
+
SILENCE: {
|
|
191
|
+
"excellent": [
|
|
192
|
+
EMISSION,
|
|
193
|
+
RECEPTION,
|
|
194
|
+
], # Resume from pause → initiation or anchoring
|
|
195
|
+
"good": [],
|
|
196
|
+
"caution": [],
|
|
197
|
+
"avoid": [
|
|
198
|
+
COHERENCE,
|
|
199
|
+
DISSONANCE,
|
|
200
|
+
COUPLING,
|
|
201
|
+
RESONANCE,
|
|
202
|
+
EXPANSION,
|
|
203
|
+
CONTRACTION,
|
|
204
|
+
MUTATION,
|
|
205
|
+
TRANSITION,
|
|
206
|
+
SELF_ORGANIZATION,
|
|
207
|
+
RECURSIVITY,
|
|
208
|
+
SILENCE,
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
# EXPANSION (VAL) - Dilates structure to explore volume
|
|
212
|
+
EXPANSION: {
|
|
213
|
+
"excellent": [
|
|
214
|
+
COUPLING,
|
|
215
|
+
RESONANCE,
|
|
216
|
+
COHERENCE,
|
|
217
|
+
], # Exploration → linking/amplification/stabilization
|
|
218
|
+
"good": [TRANSITION], # Handoff after expansion
|
|
219
|
+
"caution": [],
|
|
220
|
+
"avoid": [
|
|
221
|
+
EMISSION,
|
|
222
|
+
RECEPTION,
|
|
223
|
+
DISSONANCE,
|
|
224
|
+
SILENCE,
|
|
225
|
+
CONTRACTION,
|
|
226
|
+
MUTATION,
|
|
227
|
+
SELF_ORGANIZATION,
|
|
228
|
+
RECURSIVITY,
|
|
229
|
+
EXPANSION,
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
# CONTRACTION (NUL) - Concentrates trajectories into core
|
|
233
|
+
CONTRACTION: {
|
|
234
|
+
"excellent": [
|
|
235
|
+
EMISSION,
|
|
236
|
+
COHERENCE,
|
|
237
|
+
], # Concentration → re-initiation or stabilization
|
|
238
|
+
"good": [],
|
|
239
|
+
"caution": [],
|
|
240
|
+
"avoid": [
|
|
241
|
+
RECEPTION,
|
|
242
|
+
DISSONANCE,
|
|
243
|
+
COUPLING,
|
|
244
|
+
RESONANCE,
|
|
245
|
+
SILENCE,
|
|
246
|
+
EXPANSION,
|
|
247
|
+
MUTATION,
|
|
248
|
+
TRANSITION,
|
|
249
|
+
SELF_ORGANIZATION,
|
|
250
|
+
RECURSIVITY,
|
|
251
|
+
CONTRACTION,
|
|
252
|
+
],
|
|
253
|
+
},
|
|
254
|
+
# SELF_ORGANIZATION (THOL) - Spawns autonomous cascades
|
|
255
|
+
SELF_ORGANIZATION: {
|
|
256
|
+
"excellent": [
|
|
257
|
+
COHERENCE,
|
|
258
|
+
COUPLING,
|
|
259
|
+
RESONANCE,
|
|
260
|
+
], # Autonomous cascades → stabilization/linking/amplification
|
|
261
|
+
"good": [
|
|
262
|
+
DISSONANCE,
|
|
263
|
+
MUTATION,
|
|
264
|
+
TRANSITION,
|
|
265
|
+
SILENCE,
|
|
266
|
+
CONTRACTION,
|
|
267
|
+
EMISSION,
|
|
268
|
+
SELF_ORGANIZATION,
|
|
269
|
+
], # Nested/sequential self-organization
|
|
270
|
+
"caution": [],
|
|
271
|
+
"avoid": [RECEPTION, EXPANSION, RECURSIVITY],
|
|
272
|
+
},
|
|
273
|
+
# MUTATION (ZHIR) - Pivots node across structural thresholds
|
|
274
|
+
MUTATION: {
|
|
275
|
+
"excellent": [
|
|
276
|
+
COHERENCE,
|
|
277
|
+
TRANSITION,
|
|
278
|
+
SILENCE,
|
|
279
|
+
], # Transformation → stabilization/handoff/pause
|
|
280
|
+
"good": [],
|
|
281
|
+
"caution": [],
|
|
282
|
+
"avoid": [
|
|
283
|
+
EMISSION,
|
|
284
|
+
RECEPTION,
|
|
285
|
+
DISSONANCE,
|
|
286
|
+
COUPLING,
|
|
287
|
+
RESONANCE,
|
|
288
|
+
EXPANSION,
|
|
289
|
+
CONTRACTION,
|
|
290
|
+
MUTATION,
|
|
291
|
+
SELF_ORGANIZATION,
|
|
292
|
+
RECURSIVITY,
|
|
293
|
+
],
|
|
294
|
+
},
|
|
295
|
+
# TRANSITION (NAV) - Guides controlled regime hand-offs
|
|
296
|
+
TRANSITION: {
|
|
297
|
+
"excellent": [
|
|
298
|
+
RESONANCE,
|
|
299
|
+
COHERENCE,
|
|
300
|
+
COUPLING,
|
|
301
|
+
], # Handoff → amplification/stabilization/linking
|
|
302
|
+
"good": [
|
|
303
|
+
DISSONANCE,
|
|
304
|
+
MUTATION,
|
|
305
|
+
SILENCE,
|
|
306
|
+
TRANSITION,
|
|
307
|
+
], # Tension, transformation, pause, continued handoff
|
|
308
|
+
"caution": [],
|
|
309
|
+
"avoid": [
|
|
310
|
+
EMISSION,
|
|
311
|
+
RECEPTION,
|
|
312
|
+
EXPANSION,
|
|
313
|
+
CONTRACTION,
|
|
314
|
+
SELF_ORGANIZATION,
|
|
315
|
+
RECURSIVITY,
|
|
316
|
+
],
|
|
317
|
+
},
|
|
318
|
+
# RECURSIVITY (REMESH) - Echoes patterns across nested EPIs
|
|
319
|
+
RECURSIVITY: {
|
|
320
|
+
"excellent": [
|
|
321
|
+
COHERENCE,
|
|
322
|
+
RESONANCE,
|
|
323
|
+
], # Fractal echo → stabilization/amplification
|
|
324
|
+
"good": [
|
|
325
|
+
DISSONANCE,
|
|
326
|
+
RECEPTION,
|
|
327
|
+
COUPLING,
|
|
328
|
+
TRANSITION,
|
|
329
|
+
], # Tension, anchoring, linking, handoff after recursive pattern
|
|
330
|
+
"caution": [],
|
|
331
|
+
"avoid": [
|
|
332
|
+
EMISSION,
|
|
333
|
+
SILENCE,
|
|
334
|
+
EXPANSION,
|
|
335
|
+
CONTRACTION,
|
|
336
|
+
MUTATION,
|
|
337
|
+
SELF_ORGANIZATION,
|
|
338
|
+
RECURSIVITY,
|
|
339
|
+
],
|
|
340
|
+
},
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def get_compatibility_level(prev: str, next_op: str) -> CompatibilityLevel:
|
|
345
|
+
"""Return the compatibility level between two structural operators.
|
|
346
|
+
|
|
347
|
+
Parameters
|
|
348
|
+
----------
|
|
349
|
+
prev : str
|
|
350
|
+
Previous operator in canonical form (e.g., "emission", "coherence").
|
|
351
|
+
next_op : str
|
|
352
|
+
Next operator in canonical form (e.g., "dissonance", "resonance").
|
|
353
|
+
|
|
354
|
+
Returns
|
|
355
|
+
-------
|
|
356
|
+
CompatibilityLevel
|
|
357
|
+
The graduated compatibility level: EXCELLENT, GOOD, CAUTION, or AVOID.
|
|
358
|
+
|
|
359
|
+
Examples
|
|
360
|
+
--------
|
|
361
|
+
>>> get_compatibility_level("emission", "coherence")
|
|
362
|
+
CompatibilityLevel.EXCELLENT
|
|
363
|
+
|
|
364
|
+
>>> get_compatibility_level("emission", "dissonance")
|
|
365
|
+
CompatibilityLevel.CAUTION
|
|
366
|
+
|
|
367
|
+
>>> get_compatibility_level("silence", "dissonance")
|
|
368
|
+
CompatibilityLevel.AVOID
|
|
369
|
+
|
|
370
|
+
Notes
|
|
371
|
+
-----
|
|
372
|
+
This function implements the graduated compatibility matrix following TNFR
|
|
373
|
+
canonical theory. Transitions are categorized as:
|
|
374
|
+
|
|
375
|
+
- EXCELLENT: Optimal structural progression
|
|
376
|
+
- GOOD: Acceptable structural progression
|
|
377
|
+
- CAUTION: Contextually dependent, requires validation
|
|
378
|
+
- AVOID: Incompatible, violates structural coherence
|
|
379
|
+
"""
|
|
380
|
+
if prev not in GRADUATED_COMPATIBILITY:
|
|
381
|
+
# Unknown operator defaults to AVOID
|
|
382
|
+
return CompatibilityLevel.AVOID
|
|
383
|
+
|
|
384
|
+
levels = GRADUATED_COMPATIBILITY[prev]
|
|
385
|
+
|
|
386
|
+
# Check each level in order of preference
|
|
387
|
+
if next_op in levels.get("excellent", []):
|
|
388
|
+
return CompatibilityLevel.EXCELLENT
|
|
389
|
+
elif next_op in levels.get("good", []):
|
|
390
|
+
return CompatibilityLevel.GOOD
|
|
391
|
+
elif next_op in levels.get("caution", []):
|
|
392
|
+
return CompatibilityLevel.CAUTION
|
|
393
|
+
else:
|
|
394
|
+
return CompatibilityLevel.AVOID
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
# Generate backward-compatible binary compatibility table from graduated matrix
|
|
398
|
+
# This combines excellent, good, and caution levels as "allowed" transitions
|
|
399
|
+
def _generate_binary_compat() -> dict[str, set[str]]:
|
|
400
|
+
"""Generate binary compatibility table from graduated matrix.
|
|
401
|
+
|
|
402
|
+
Combines EXCELLENT, GOOD, and CAUTION levels into a single "allowed" set
|
|
403
|
+
for backward compatibility with existing code that expects binary validation.
|
|
404
|
+
"""
|
|
405
|
+
compat: dict[str, set[str]] = {}
|
|
406
|
+
for operator, levels in GRADUATED_COMPATIBILITY.items():
|
|
407
|
+
allowed = set()
|
|
408
|
+
allowed.update(levels.get("excellent", []))
|
|
409
|
+
allowed.update(levels.get("good", []))
|
|
410
|
+
allowed.update(levels.get("caution", []))
|
|
411
|
+
compat[operator] = allowed
|
|
412
|
+
return compat
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
# Canonical compatibilities (allowed next operators) expressed via structural names
|
|
416
|
+
# Derived from GRADUATED_COMPATIBILITY for backward compatibility
|
|
417
|
+
_STRUCTURAL_COMPAT: dict[str, set[str]] = _generate_binary_compat()
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def _name_to_glyph(name: str) -> Glyph:
|
|
421
|
+
glyph = _grammar.function_name_to_glyph(name)
|
|
422
|
+
if glyph is None:
|
|
423
|
+
raise KeyError(f"No glyph mapped to structural operator '{name}'")
|
|
424
|
+
return glyph
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def _translate_structural() -> tuple[dict[Glyph, set[Glyph]], dict[Glyph, Glyph]]:
|
|
428
|
+
compat: dict[Glyph, set[Glyph]] = {}
|
|
429
|
+
for src, targets in _STRUCTURAL_COMPAT.items():
|
|
430
|
+
src_glyph = _name_to_glyph(src)
|
|
431
|
+
compat[src_glyph] = {_name_to_glyph(target) for target in targets}
|
|
432
|
+
fallback: dict[Glyph, Glyph] = {}
|
|
433
|
+
for src, target in _STRUCTURAL_FALLBACK.items():
|
|
434
|
+
fallback[_name_to_glyph(src)] = _name_to_glyph(target)
|
|
435
|
+
return compat, fallback
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
# Canonical fallbacks when a transition is not allowed (structural names)
|
|
439
|
+
_STRUCTURAL_FALLBACK: dict[str, str] = {
|
|
440
|
+
EMISSION: RECEPTION,
|
|
441
|
+
RECEPTION: COHERENCE,
|
|
442
|
+
COHERENCE: RESONANCE,
|
|
443
|
+
TRANSITION: RESONANCE,
|
|
444
|
+
CONTRACTION: EMISSION,
|
|
445
|
+
DISSONANCE: MUTATION,
|
|
446
|
+
RESONANCE: COHERENCE,
|
|
447
|
+
SILENCE: EMISSION,
|
|
448
|
+
SELF_ORGANIZATION: TRANSITION,
|
|
449
|
+
COUPLING: RESONANCE,
|
|
450
|
+
EXPANSION: RESONANCE,
|
|
451
|
+
MUTATION: COHERENCE,
|
|
452
|
+
RECURSIVITY: COHERENCE, # Fractal echo → stabilization
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
CANON_COMPAT, CANON_FALLBACK = _translate_structural()
|
|
456
|
+
|
|
457
|
+
# Re-export structural tables for internal consumers that operate on functional
|
|
458
|
+
# identifiers without exposing them as part of the public API.
|
|
459
|
+
_STRUCTURAL_COMPAT_TABLE = _STRUCTURAL_COMPAT
|
|
460
|
+
_STRUCTURAL_FALLBACK_TABLE = _STRUCTURAL_FALLBACK
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Configuration for TNFR validation system.
|
|
2
|
+
|
|
3
|
+
This module provides configuration options for controlling validation behavior,
|
|
4
|
+
including thresholds, performance settings, and validation levels.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import math
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
|
|
12
|
+
from .invariants import InvariantSeverity
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"ValidationConfig",
|
|
16
|
+
"validation_config",
|
|
17
|
+
"configure_validation",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class ValidationConfig:
|
|
23
|
+
"""TNFR validation system configuration."""
|
|
24
|
+
|
|
25
|
+
# Validation levels
|
|
26
|
+
validate_invariants: bool = True
|
|
27
|
+
validate_each_step: bool = False # Expensive, only for debugging
|
|
28
|
+
min_severity: InvariantSeverity = InvariantSeverity.ERROR
|
|
29
|
+
|
|
30
|
+
# Numerical thresholds (can be overridden from graph.graph config)
|
|
31
|
+
epi_range: tuple[float, float] = (0.0, 1.0)
|
|
32
|
+
vf_range: tuple[float, float] = (0.001, 1000.0) # Hz_str
|
|
33
|
+
phase_coupling_threshold: float = math.pi / 2
|
|
34
|
+
|
|
35
|
+
# Semantic validation
|
|
36
|
+
enable_semantic_validation: bool = True
|
|
37
|
+
allow_semantic_warnings: bool = True
|
|
38
|
+
|
|
39
|
+
# Performance
|
|
40
|
+
cache_validation_results: bool = False # Future optimization
|
|
41
|
+
max_validation_time_ms: float = 1000.0 # Timeout (not implemented yet)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Global configuration
|
|
45
|
+
validation_config = ValidationConfig()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def configure_validation(**kwargs: object) -> None:
|
|
49
|
+
"""Updates global validation configuration.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
**kwargs
|
|
54
|
+
Configuration parameters to update. Valid keys match
|
|
55
|
+
ValidationConfig attributes.
|
|
56
|
+
|
|
57
|
+
Raises
|
|
58
|
+
------
|
|
59
|
+
ValueError
|
|
60
|
+
If an unknown configuration key is provided.
|
|
61
|
+
|
|
62
|
+
Examples
|
|
63
|
+
--------
|
|
64
|
+
>>> from tnfr.validation.config import configure_validation
|
|
65
|
+
>>> configure_validation(validate_each_step=True)
|
|
66
|
+
>>> configure_validation(phase_coupling_threshold=3.14159/3)
|
|
67
|
+
"""
|
|
68
|
+
global validation_config
|
|
69
|
+
for key, value in kwargs.items():
|
|
70
|
+
if hasattr(validation_config, key):
|
|
71
|
+
setattr(validation_config, key, value)
|
|
72
|
+
else:
|
|
73
|
+
raise ValueError(f"Unknown validation config key: {key}")
|
tnfr/validation/graph.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Graph-level validation helpers enforcing TNFR invariants."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from collections.abc import Sequence
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from ..alias import get_attr
|
|
11
|
+
from ..glyph_runtime import last_glyph
|
|
12
|
+
from ..config.constants import GLYPHS_CANONICAL_SET
|
|
13
|
+
from ..constants import get_param
|
|
14
|
+
from ..constants.aliases import ALIAS_EPI, ALIAS_VF
|
|
15
|
+
from ..utils import within_range
|
|
16
|
+
from ..types import (
|
|
17
|
+
EPIValue,
|
|
18
|
+
NodeAttrMap,
|
|
19
|
+
NodeId,
|
|
20
|
+
StructuralFrequency,
|
|
21
|
+
TNFRGraph,
|
|
22
|
+
ValidatorFunc,
|
|
23
|
+
ensure_bepi,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
NodeData = NodeAttrMap
|
|
27
|
+
"""Read-only node attribute mapping used by validators."""
|
|
28
|
+
|
|
29
|
+
AliasSequence = Sequence[str]
|
|
30
|
+
"""Sequence of accepted attribute aliases."""
|
|
31
|
+
|
|
32
|
+
__all__ = ("run_validators", "GRAPH_VALIDATORS")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _materialize_node_mapping(data: NodeData) -> dict[str, object]:
|
|
36
|
+
if isinstance(data, dict):
|
|
37
|
+
return data
|
|
38
|
+
return dict(data)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _require_attr(
|
|
42
|
+
data: NodeData, alias: AliasSequence, node: NodeId, name: str
|
|
43
|
+
) -> float:
|
|
44
|
+
"""Return scalar attribute value or raise if missing."""
|
|
45
|
+
|
|
46
|
+
mapping = _materialize_node_mapping(data)
|
|
47
|
+
val = get_attr(mapping, alias, None)
|
|
48
|
+
if val is None:
|
|
49
|
+
raise ValueError(f"Missing {name} attribute in node {node}")
|
|
50
|
+
return float(val)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _require_epi(data: NodeData, node: NodeId) -> EPIValue:
|
|
54
|
+
"""Return a validated BEPI element stored in ``data``."""
|
|
55
|
+
|
|
56
|
+
mapping = _materialize_node_mapping(data)
|
|
57
|
+
value = get_attr(mapping, ALIAS_EPI, None, conv=lambda obj: obj)
|
|
58
|
+
if value is None:
|
|
59
|
+
raise ValueError(f"Missing EPI attribute in node {node}")
|
|
60
|
+
try:
|
|
61
|
+
return ensure_bepi(value)
|
|
62
|
+
except (TypeError, ValueError) as exc:
|
|
63
|
+
raise ValueError(f"Invalid EPI payload in node {node}: {exc}") from exc
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _validate_sigma(graph: TNFRGraph) -> None:
|
|
67
|
+
from ..sense import sigma_vector_from_graph
|
|
68
|
+
|
|
69
|
+
sv = sigma_vector_from_graph(graph)
|
|
70
|
+
if sv.get("mag", 0.0) > 1.0 + sys.float_info.epsilon:
|
|
71
|
+
raise ValueError("σ norm exceeds 1")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
GRAPH_VALIDATORS: tuple[ValidatorFunc, ...] = (_validate_sigma,)
|
|
75
|
+
"""Ordered collection of graph-level validators."""
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _max_abs(values: np.ndarray) -> float:
|
|
79
|
+
if values.size == 0:
|
|
80
|
+
return 0.0
|
|
81
|
+
return float(np.max(np.abs(values)))
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _check_epi(
|
|
85
|
+
epi: EPIValue,
|
|
86
|
+
epi_min: float,
|
|
87
|
+
epi_max: float,
|
|
88
|
+
node: NodeId,
|
|
89
|
+
) -> None:
|
|
90
|
+
continuous_max = _max_abs(epi.f_continuous)
|
|
91
|
+
discrete_max = _max_abs(epi.a_discrete)
|
|
92
|
+
_check_range(continuous_max, epi_min, epi_max, "EPI continuous", node)
|
|
93
|
+
_check_range(discrete_max, epi_min, epi_max, "EPI discrete", node)
|
|
94
|
+
|
|
95
|
+
spacings = np.diff(epi.x_grid)
|
|
96
|
+
if np.any(spacings <= 0.0):
|
|
97
|
+
raise ValueError(f"EPI grid must be strictly increasing for node {node}")
|
|
98
|
+
if not np.allclose(spacings, spacings[0], rtol=1e-9, atol=1e-12):
|
|
99
|
+
raise ValueError(f"EPI grid must be uniform for node {node}")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _out_of_range_msg(name: str, node: NodeId, val: float) -> str:
|
|
103
|
+
return f"{name} out of range in node {node}: {val}"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _check_range(
|
|
107
|
+
val: float,
|
|
108
|
+
lower: float,
|
|
109
|
+
upper: float,
|
|
110
|
+
name: str,
|
|
111
|
+
node: NodeId,
|
|
112
|
+
tol: float = 1e-9,
|
|
113
|
+
) -> None:
|
|
114
|
+
if not within_range(val, lower, upper, tol):
|
|
115
|
+
raise ValueError(_out_of_range_msg(name, node, val))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _check_glyph(glyph: str | None, node: NodeId) -> None:
|
|
119
|
+
if glyph and glyph not in GLYPHS_CANONICAL_SET:
|
|
120
|
+
raise KeyError(f"Invalid glyph {glyph} in node {node}")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def run_validators(graph: TNFRGraph) -> None:
|
|
124
|
+
"""Run all invariant validators on ``graph`` with a single node pass."""
|
|
125
|
+
|
|
126
|
+
epi_min = float(get_param(graph, "EPI_MIN"))
|
|
127
|
+
epi_max = float(get_param(graph, "EPI_MAX"))
|
|
128
|
+
vf_min = float(get_param(graph, "VF_MIN"))
|
|
129
|
+
vf_max = float(get_param(graph, "VF_MAX"))
|
|
130
|
+
|
|
131
|
+
for node, data in graph.nodes(data=True):
|
|
132
|
+
epi = _require_epi(data, node)
|
|
133
|
+
vf = StructuralFrequency(_require_attr(data, ALIAS_VF, node, "VF"))
|
|
134
|
+
_check_epi(epi, epi_min, epi_max, node)
|
|
135
|
+
_check_range(vf, vf_min, vf_max, "VF", node)
|
|
136
|
+
_check_glyph(last_glyph(data), node)
|
|
137
|
+
|
|
138
|
+
for validator in GRAPH_VALIDATORS:
|
|
139
|
+
validator(graph)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
from typing import Tuple
|
|
3
|
+
|
|
4
|
+
from ..types import (
|
|
5
|
+
EPIValue,
|
|
6
|
+
NodeAttrMap,
|
|
7
|
+
NodeId,
|
|
8
|
+
StructuralFrequency,
|
|
9
|
+
TNFRGraph,
|
|
10
|
+
ValidatorFunc,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
NodeData = NodeAttrMap
|
|
14
|
+
AliasSequence = Sequence[str]
|
|
15
|
+
|
|
16
|
+
GRAPH_VALIDATORS: Tuple[ValidatorFunc, ...]
|
|
17
|
+
|
|
18
|
+
def run_validators(graph: TNFRGraph) -> None: ...
|