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,809 @@
|
|
|
1
|
+
"""Structural health metrics analyzer for TNFR operator sequences.
|
|
2
|
+
|
|
3
|
+
Provides quantitative assessment of sequence structural quality through
|
|
4
|
+
canonical TNFR metrics: coherence, balance, sustainability, and efficiency.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from functools import lru_cache
|
|
10
|
+
from typing import Any, List, Tuple, TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from ..types import TNFRGraph
|
|
14
|
+
|
|
15
|
+
from ..compat.dataclass import dataclass
|
|
16
|
+
from ..config.operator_names import (
|
|
17
|
+
COHERENCE,
|
|
18
|
+
DISSONANCE,
|
|
19
|
+
RECURSIVITY,
|
|
20
|
+
RESONANCE,
|
|
21
|
+
SELF_ORGANIZATION,
|
|
22
|
+
SILENCE,
|
|
23
|
+
TRANSITION,
|
|
24
|
+
DESTABILIZERS,
|
|
25
|
+
TRANSFORMERS,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"SequenceHealthMetrics",
|
|
30
|
+
"SequenceHealthAnalyzer",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Operator categories for health analysis
|
|
35
|
+
_STABILIZERS = frozenset({COHERENCE, SELF_ORGANIZATION, SILENCE, RESONANCE})
|
|
36
|
+
_REGENERATORS = frozenset({TRANSITION, RECURSIVITY}) # NAV, REMESH
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class SequenceHealthMetrics:
|
|
41
|
+
"""Structural health metrics for a TNFR operator sequence.
|
|
42
|
+
|
|
43
|
+
All metrics range from 0.0 (poor) to 1.0 (excellent), measuring different
|
|
44
|
+
aspects of sequence structural quality according to TNFR principles.
|
|
45
|
+
|
|
46
|
+
Attributes
|
|
47
|
+
----------
|
|
48
|
+
coherence_index : float
|
|
49
|
+
Global sequential flow quality (0.0-1.0). Measures how well operators
|
|
50
|
+
transition and whether the sequence forms a recognizable pattern.
|
|
51
|
+
balance_score : float
|
|
52
|
+
Equilibrium between stabilizers and destabilizers (0.0-1.0). Ideal
|
|
53
|
+
sequences have balanced structural forces.
|
|
54
|
+
sustainability_index : float
|
|
55
|
+
Capacity for long-term maintenance (0.0-1.0). Considers final stabilization,
|
|
56
|
+
resolved dissonance, and regenerative elements.
|
|
57
|
+
complexity_efficiency : float
|
|
58
|
+
Value-to-complexity ratio (0.0-1.0). Penalizes unnecessarily long sequences
|
|
59
|
+
that don't provide proportional structural value.
|
|
60
|
+
frequency_harmony : float
|
|
61
|
+
Structural frequency transition smoothness (0.0-1.0). High when transitions
|
|
62
|
+
respect νf harmonics.
|
|
63
|
+
pattern_completeness : float
|
|
64
|
+
How complete the detected pattern is (0.0-1.0). Full cycles score higher.
|
|
65
|
+
transition_smoothness : float
|
|
66
|
+
Quality of operator transitions (0.0-1.0). Measures valid transitions vs
|
|
67
|
+
total transitions.
|
|
68
|
+
overall_health : float
|
|
69
|
+
Composite health index (0.0-1.0). Weighted average of primary metrics.
|
|
70
|
+
sequence_length : int
|
|
71
|
+
Number of operators in the sequence.
|
|
72
|
+
dominant_pattern : str
|
|
73
|
+
Detected structural pattern type (e.g., "activation", "therapeutic", "unknown").
|
|
74
|
+
recommendations : List[str]
|
|
75
|
+
Specific suggestions for improving sequence health.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
coherence_index: float
|
|
79
|
+
balance_score: float
|
|
80
|
+
sustainability_index: float
|
|
81
|
+
complexity_efficiency: float
|
|
82
|
+
frequency_harmony: float
|
|
83
|
+
pattern_completeness: float
|
|
84
|
+
transition_smoothness: float
|
|
85
|
+
overall_health: float
|
|
86
|
+
sequence_length: int
|
|
87
|
+
dominant_pattern: str
|
|
88
|
+
recommendations: List[str]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class SequenceHealthAnalyzer:
|
|
92
|
+
"""Analyzer for structural health of TNFR operator sequences.
|
|
93
|
+
|
|
94
|
+
Evaluates sequences along multiple dimensions to provide quantitative
|
|
95
|
+
assessment of structural quality, coherence, and sustainability.
|
|
96
|
+
|
|
97
|
+
Uses caching to optimize repeated analysis of identical sequences,
|
|
98
|
+
which is common in pattern exploration and batch validation workflows.
|
|
99
|
+
|
|
100
|
+
Examples
|
|
101
|
+
--------
|
|
102
|
+
>>> from tnfr.operators.health_analyzer import SequenceHealthAnalyzer
|
|
103
|
+
>>> analyzer = SequenceHealthAnalyzer()
|
|
104
|
+
>>> sequence = ["emission", "reception", "coherence", "silence"]
|
|
105
|
+
>>> health = analyzer.analyze_health(sequence)
|
|
106
|
+
>>> health.overall_health
|
|
107
|
+
0.82
|
|
108
|
+
>>> health.recommendations
|
|
109
|
+
[]
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
def __init__(self) -> None:
|
|
113
|
+
"""Initialize the health analyzer with caching support."""
|
|
114
|
+
self._recommendations: List[str] = []
|
|
115
|
+
# Cache for single-pass analysis results keyed by sequence tuple
|
|
116
|
+
# Using maxsize=128 to avoid unbounded growth while caching common sequences
|
|
117
|
+
self._analysis_cache = lru_cache(maxsize=128)(self._compute_single_pass)
|
|
118
|
+
|
|
119
|
+
def _compute_single_pass(
|
|
120
|
+
self, sequence_tuple: Tuple[str, ...]
|
|
121
|
+
) -> Tuple[int, int, int, int, int, List[Tuple[str, str]]]:
|
|
122
|
+
"""Compute sequence statistics in a single pass for efficiency.
|
|
123
|
+
|
|
124
|
+
This method scans the sequence once and extracts all the information
|
|
125
|
+
needed for the various health metrics, avoiding redundant iterations.
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
sequence_tuple : Tuple[str, ...]
|
|
130
|
+
Immutable sequence of operators (tuple for hashability in cache).
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
Tuple containing:
|
|
135
|
+
- stabilizer_count: int
|
|
136
|
+
- destabilizer_count: int
|
|
137
|
+
- transformer_count: int
|
|
138
|
+
- regenerator_count: int
|
|
139
|
+
- unique_ops: int
|
|
140
|
+
- problematic_transitions: List[(op1, op2)] pairs
|
|
141
|
+
|
|
142
|
+
Notes
|
|
143
|
+
-----
|
|
144
|
+
This function is cached using lru_cache to optimize repeated analysis
|
|
145
|
+
of identical sequences, which is common in batch validation and
|
|
146
|
+
pattern exploration workflows.
|
|
147
|
+
"""
|
|
148
|
+
sequence = list(sequence_tuple)
|
|
149
|
+
|
|
150
|
+
# Initialize counters
|
|
151
|
+
stabilizer_count = 0
|
|
152
|
+
destabilizer_count = 0
|
|
153
|
+
transformer_count = 0
|
|
154
|
+
regenerator_count = 0
|
|
155
|
+
unique_ops_set = set()
|
|
156
|
+
problematic_transitions = []
|
|
157
|
+
|
|
158
|
+
# Single pass through sequence
|
|
159
|
+
for i, op in enumerate(sequence):
|
|
160
|
+
unique_ops_set.add(op)
|
|
161
|
+
|
|
162
|
+
# Count operator categories
|
|
163
|
+
if op in _STABILIZERS:
|
|
164
|
+
stabilizer_count += 1
|
|
165
|
+
if op in DESTABILIZERS:
|
|
166
|
+
destabilizer_count += 1
|
|
167
|
+
if op in TRANSFORMERS:
|
|
168
|
+
transformer_count += 1
|
|
169
|
+
if op in _REGENERATORS:
|
|
170
|
+
regenerator_count += 1
|
|
171
|
+
|
|
172
|
+
# Check transitions
|
|
173
|
+
if i < len(sequence) - 1:
|
|
174
|
+
next_op = sequence[i + 1]
|
|
175
|
+
# Destabilizer → destabilizer is problematic
|
|
176
|
+
if op in DESTABILIZERS and next_op in DESTABILIZERS:
|
|
177
|
+
problematic_transitions.append((op, next_op))
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
stabilizer_count,
|
|
181
|
+
destabilizer_count,
|
|
182
|
+
transformer_count,
|
|
183
|
+
regenerator_count,
|
|
184
|
+
len(unique_ops_set),
|
|
185
|
+
problematic_transitions,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
def analyze_health(self, sequence: List[str]) -> SequenceHealthMetrics:
|
|
189
|
+
"""Perform complete structural health analysis of a sequence.
|
|
190
|
+
|
|
191
|
+
Parameters
|
|
192
|
+
----------
|
|
193
|
+
sequence : List[str]
|
|
194
|
+
Operator sequence to analyze (canonical names like "emission", "coherence").
|
|
195
|
+
|
|
196
|
+
Returns
|
|
197
|
+
-------
|
|
198
|
+
SequenceHealthMetrics
|
|
199
|
+
Comprehensive health metrics for the sequence.
|
|
200
|
+
|
|
201
|
+
Examples
|
|
202
|
+
--------
|
|
203
|
+
>>> analyzer = SequenceHealthAnalyzer()
|
|
204
|
+
>>> health = analyzer.analyze_health(["emission", "reception", "coherence", "silence"])
|
|
205
|
+
>>> health.coherence_index > 0.7
|
|
206
|
+
True
|
|
207
|
+
"""
|
|
208
|
+
self._recommendations = []
|
|
209
|
+
|
|
210
|
+
# Use single-pass analysis for efficiency (cached)
|
|
211
|
+
sequence_tuple = tuple(sequence)
|
|
212
|
+
analysis = self._analysis_cache(sequence_tuple)
|
|
213
|
+
|
|
214
|
+
# Extract results from single-pass analysis
|
|
215
|
+
(
|
|
216
|
+
stabilizer_count,
|
|
217
|
+
destabilizer_count,
|
|
218
|
+
transformer_count,
|
|
219
|
+
regenerator_count,
|
|
220
|
+
unique_count,
|
|
221
|
+
problematic_transitions,
|
|
222
|
+
) = analysis
|
|
223
|
+
|
|
224
|
+
coherence = self._calculate_coherence(sequence, problematic_transitions)
|
|
225
|
+
balance = self._calculate_balance(
|
|
226
|
+
sequence, stabilizer_count, destabilizer_count
|
|
227
|
+
)
|
|
228
|
+
sustainability = self._calculate_sustainability(
|
|
229
|
+
sequence, stabilizer_count, destabilizer_count, regenerator_count
|
|
230
|
+
)
|
|
231
|
+
efficiency = self._calculate_efficiency(sequence, unique_count)
|
|
232
|
+
frequency = self._calculate_frequency_harmony(sequence)
|
|
233
|
+
completeness = self._calculate_completeness(
|
|
234
|
+
sequence, stabilizer_count, destabilizer_count, transformer_count
|
|
235
|
+
)
|
|
236
|
+
smoothness = self._calculate_smoothness(sequence, problematic_transitions)
|
|
237
|
+
|
|
238
|
+
# Calculate overall health as weighted average
|
|
239
|
+
# Primary metrics weighted more heavily
|
|
240
|
+
overall = (
|
|
241
|
+
coherence * 0.20
|
|
242
|
+
+ balance * 0.20
|
|
243
|
+
+ sustainability * 0.20
|
|
244
|
+
+ efficiency * 0.15
|
|
245
|
+
+ frequency * 0.10
|
|
246
|
+
+ completeness * 0.10
|
|
247
|
+
+ smoothness * 0.05
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
pattern = self._detect_pattern(sequence)
|
|
251
|
+
|
|
252
|
+
return SequenceHealthMetrics(
|
|
253
|
+
coherence_index=coherence,
|
|
254
|
+
balance_score=balance,
|
|
255
|
+
sustainability_index=sustainability,
|
|
256
|
+
complexity_efficiency=efficiency,
|
|
257
|
+
frequency_harmony=frequency,
|
|
258
|
+
pattern_completeness=completeness,
|
|
259
|
+
transition_smoothness=smoothness,
|
|
260
|
+
overall_health=overall,
|
|
261
|
+
sequence_length=len(sequence),
|
|
262
|
+
dominant_pattern=pattern,
|
|
263
|
+
recommendations=self._recommendations.copy(),
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
def _calculate_coherence(
|
|
267
|
+
self, sequence: List[str], problematic_transitions: List[Tuple[str, str]]
|
|
268
|
+
) -> float:
|
|
269
|
+
"""Calculate coherence index: how well the sequence flows.
|
|
270
|
+
|
|
271
|
+
Factors:
|
|
272
|
+
- Valid transitions between operators
|
|
273
|
+
- Recognizable pattern structure
|
|
274
|
+
- Structural closure (proper ending)
|
|
275
|
+
|
|
276
|
+
Parameters
|
|
277
|
+
----------
|
|
278
|
+
sequence : List[str]
|
|
279
|
+
Operator sequence
|
|
280
|
+
problematic_transitions : List[Tuple[str, str]]
|
|
281
|
+
Pre-computed list of problematic transition pairs
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
float
|
|
286
|
+
Coherence score (0.0-1.0)
|
|
287
|
+
"""
|
|
288
|
+
if not sequence:
|
|
289
|
+
return 0.0
|
|
290
|
+
|
|
291
|
+
# Transition quality: use pre-computed problematic transitions
|
|
292
|
+
if len(sequence) < 2:
|
|
293
|
+
transition_quality = 1.0
|
|
294
|
+
else:
|
|
295
|
+
total_transitions = len(sequence) - 1
|
|
296
|
+
# Each problematic transition gets 0.5 penalty
|
|
297
|
+
penalty = len(problematic_transitions) * 0.5
|
|
298
|
+
transition_quality = max(0.0, 1.0 - (penalty / total_transitions))
|
|
299
|
+
|
|
300
|
+
# Pattern clarity: does it form a recognizable structure?
|
|
301
|
+
pattern_clarity = self._assess_pattern_clarity(sequence)
|
|
302
|
+
|
|
303
|
+
# Structural closure: does it end properly?
|
|
304
|
+
structural_closure = self._assess_closure(sequence)
|
|
305
|
+
|
|
306
|
+
return (transition_quality + pattern_clarity + structural_closure) / 3.0
|
|
307
|
+
|
|
308
|
+
def _calculate_balance(
|
|
309
|
+
self, sequence: List[str], stabilizer_count: int, destabilizer_count: int
|
|
310
|
+
) -> float:
|
|
311
|
+
"""Calculate balance score: equilibrium between stabilizers and destabilizers.
|
|
312
|
+
|
|
313
|
+
Ideal sequences have roughly equal stabilization and transformation forces.
|
|
314
|
+
Severe imbalance reduces structural health.
|
|
315
|
+
|
|
316
|
+
Parameters
|
|
317
|
+
----------
|
|
318
|
+
sequence : List[str]
|
|
319
|
+
Operator sequence
|
|
320
|
+
stabilizer_count : int
|
|
321
|
+
Pre-computed count of stabilizing operators
|
|
322
|
+
destabilizer_count : int
|
|
323
|
+
Pre-computed count of destabilizing operators
|
|
324
|
+
|
|
325
|
+
Returns
|
|
326
|
+
-------
|
|
327
|
+
float
|
|
328
|
+
Balance score (0.0-1.0)
|
|
329
|
+
"""
|
|
330
|
+
if not sequence:
|
|
331
|
+
return 0.5 # Neutral for empty
|
|
332
|
+
|
|
333
|
+
# If neither present, neutral balance
|
|
334
|
+
if stabilizer_count == 0 and destabilizer_count == 0:
|
|
335
|
+
return 0.5
|
|
336
|
+
|
|
337
|
+
# Calculate ratio: closer to 1.0 means better balance
|
|
338
|
+
max_count = max(stabilizer_count, destabilizer_count)
|
|
339
|
+
min_count = min(stabilizer_count, destabilizer_count)
|
|
340
|
+
|
|
341
|
+
if max_count == 0:
|
|
342
|
+
return 0.5
|
|
343
|
+
|
|
344
|
+
ratio = min_count / max_count
|
|
345
|
+
|
|
346
|
+
# Penalize severe imbalance (difference > half the sequence length)
|
|
347
|
+
imbalance = abs(stabilizer_count - destabilizer_count)
|
|
348
|
+
if imbalance > len(sequence) // 2:
|
|
349
|
+
ratio *= 0.7 # Apply penalty
|
|
350
|
+
self._recommendations.append(
|
|
351
|
+
"Severe imbalance detected: add stabilizers or reduce destabilizers"
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
return ratio
|
|
355
|
+
|
|
356
|
+
def _calculate_sustainability(
|
|
357
|
+
self,
|
|
358
|
+
sequence: List[str],
|
|
359
|
+
stabilizer_count: int,
|
|
360
|
+
destabilizer_count: int,
|
|
361
|
+
regenerator_count: int,
|
|
362
|
+
) -> float:
|
|
363
|
+
"""Calculate sustainability index: capacity to maintain without collapse.
|
|
364
|
+
|
|
365
|
+
Factors:
|
|
366
|
+
- Final operator is a stabilizer
|
|
367
|
+
- Dissonance is resolved (not left unbalanced)
|
|
368
|
+
- Contains regenerative elements
|
|
369
|
+
|
|
370
|
+
Parameters
|
|
371
|
+
----------
|
|
372
|
+
sequence : List[str]
|
|
373
|
+
Operator sequence
|
|
374
|
+
stabilizer_count : int
|
|
375
|
+
Pre-computed count of stabilizing operators
|
|
376
|
+
destabilizer_count : int
|
|
377
|
+
Pre-computed count of destabilizing operators
|
|
378
|
+
regenerator_count : int
|
|
379
|
+
Pre-computed count of regenerative operators
|
|
380
|
+
|
|
381
|
+
Returns
|
|
382
|
+
-------
|
|
383
|
+
float
|
|
384
|
+
Sustainability score (0.0-1.0)
|
|
385
|
+
"""
|
|
386
|
+
if not sequence:
|
|
387
|
+
return 0.0
|
|
388
|
+
|
|
389
|
+
sustainability = 0.0
|
|
390
|
+
|
|
391
|
+
# Factor 1: Ends with stabilizer (0.4 points)
|
|
392
|
+
has_final_stabilizer = sequence[-1] in _STABILIZERS
|
|
393
|
+
if has_final_stabilizer:
|
|
394
|
+
sustainability += 0.4
|
|
395
|
+
else:
|
|
396
|
+
sustainability += 0.1 # Some credit for other endings
|
|
397
|
+
self._recommendations.append(
|
|
398
|
+
"Consider ending with a stabilizer (coherence, silence, resonance, or self_organization)"
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
# Factor 2: Resolved dissonance (0.3 points)
|
|
402
|
+
unresolved_dissonance = self._count_unresolved_dissonance(sequence)
|
|
403
|
+
if unresolved_dissonance == 0:
|
|
404
|
+
sustainability += 0.3
|
|
405
|
+
else:
|
|
406
|
+
penalty = min(0.3, unresolved_dissonance * 0.1)
|
|
407
|
+
sustainability += max(0, 0.3 - penalty)
|
|
408
|
+
if unresolved_dissonance > 1:
|
|
409
|
+
self._recommendations.append(
|
|
410
|
+
"Multiple unresolved dissonances detected: add stabilizers after destabilizing operators"
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
# Factor 3: Regenerative elements (0.3 points)
|
|
414
|
+
# Use pre-computed regenerator count
|
|
415
|
+
if regenerator_count > 0:
|
|
416
|
+
sustainability += 0.3
|
|
417
|
+
else:
|
|
418
|
+
sustainability += 0.1 # Some credit even without
|
|
419
|
+
|
|
420
|
+
return min(1.0, sustainability)
|
|
421
|
+
|
|
422
|
+
def _calculate_efficiency(self, sequence: List[str], unique_count: int) -> float:
|
|
423
|
+
"""Calculate complexity efficiency: value achieved relative to length.
|
|
424
|
+
|
|
425
|
+
Penalizes unnecessarily long sequences that don't provide proportional value.
|
|
426
|
+
|
|
427
|
+
Parameters
|
|
428
|
+
----------
|
|
429
|
+
sequence : List[str]
|
|
430
|
+
Operator sequence
|
|
431
|
+
unique_count : int
|
|
432
|
+
Pre-computed count of unique operators in sequence
|
|
433
|
+
|
|
434
|
+
Returns
|
|
435
|
+
-------
|
|
436
|
+
float
|
|
437
|
+
Efficiency score (0.0-1.0)
|
|
438
|
+
"""
|
|
439
|
+
if not sequence:
|
|
440
|
+
return 0.0
|
|
441
|
+
|
|
442
|
+
# Assess structural value using pre-computed unique count
|
|
443
|
+
diversity_score = min(
|
|
444
|
+
1.0, unique_count / 6.0
|
|
445
|
+
) # 6+ operators is excellent diversity
|
|
446
|
+
|
|
447
|
+
# Note: We still need to call _assess_pattern_value for category coverage
|
|
448
|
+
# This is minimal overhead as it's a single pass checking set memberships
|
|
449
|
+
pattern_value = self._assess_pattern_value_optimized(sequence, unique_count)
|
|
450
|
+
|
|
451
|
+
# Length penalty: sequences longer than 10 operators get penalized
|
|
452
|
+
# Optimal range is 3-8 operators
|
|
453
|
+
length = len(sequence)
|
|
454
|
+
if length < 3:
|
|
455
|
+
length_factor = 0.7 # Too short, limited value
|
|
456
|
+
elif length <= 8:
|
|
457
|
+
length_factor = 1.0 # Optimal range
|
|
458
|
+
else:
|
|
459
|
+
# Gradual penalty for length > 8
|
|
460
|
+
excess = length - 8
|
|
461
|
+
length_factor = max(0.5, 1.0 - (excess * 0.05))
|
|
462
|
+
|
|
463
|
+
if length > 12:
|
|
464
|
+
self._recommendations.append(
|
|
465
|
+
f"Sequence is long ({length} operators): consider breaking into sub-sequences"
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
return pattern_value * length_factor
|
|
469
|
+
|
|
470
|
+
def _calculate_frequency_harmony(self, sequence: List[str]) -> float:
|
|
471
|
+
"""Calculate frequency harmony: smoothness of νf transitions.
|
|
472
|
+
|
|
473
|
+
TODO: Full implementation requires integration with STRUCTURAL_FREQUENCIES
|
|
474
|
+
and FREQUENCY_TRANSITIONS from the grammar module. Currently returns
|
|
475
|
+
a conservative estimate based on transition patterns.
|
|
476
|
+
|
|
477
|
+
Parameters
|
|
478
|
+
----------
|
|
479
|
+
sequence : List[str]
|
|
480
|
+
Operator sequence
|
|
481
|
+
|
|
482
|
+
Returns
|
|
483
|
+
-------
|
|
484
|
+
float
|
|
485
|
+
Harmony score (0.0-1.0)
|
|
486
|
+
"""
|
|
487
|
+
# Conservative estimate: assume good harmony unless obvious issues detected
|
|
488
|
+
# Future enhancement: integrate with grammar.STRUCTURAL_FREQUENCIES
|
|
489
|
+
return 0.85
|
|
490
|
+
|
|
491
|
+
def _calculate_completeness(
|
|
492
|
+
self,
|
|
493
|
+
sequence: List[str],
|
|
494
|
+
stabilizer_count: int,
|
|
495
|
+
destabilizer_count: int,
|
|
496
|
+
transformer_count: int,
|
|
497
|
+
) -> float:
|
|
498
|
+
"""Calculate pattern completeness: how complete the pattern is.
|
|
499
|
+
|
|
500
|
+
Complete patterns (with activation, transformation, stabilization) score higher.
|
|
501
|
+
|
|
502
|
+
Parameters
|
|
503
|
+
----------
|
|
504
|
+
sequence : List[str]
|
|
505
|
+
Operator sequence
|
|
506
|
+
stabilizer_count : int
|
|
507
|
+
Pre-computed count of stabilizing operators
|
|
508
|
+
destabilizer_count : int
|
|
509
|
+
Pre-computed count of destabilizing operators
|
|
510
|
+
transformer_count : int
|
|
511
|
+
Pre-computed count of transforming operators
|
|
512
|
+
|
|
513
|
+
Returns
|
|
514
|
+
-------
|
|
515
|
+
float
|
|
516
|
+
Completeness score (0.0-1.0)
|
|
517
|
+
"""
|
|
518
|
+
if not sequence:
|
|
519
|
+
return 0.0
|
|
520
|
+
|
|
521
|
+
# Check for key phases using pre-computed counts and minimal checks
|
|
522
|
+
has_activation = any(op in {"emission", "reception"} for op in sequence)
|
|
523
|
+
has_transformation = destabilizer_count > 0 or transformer_count > 0
|
|
524
|
+
has_stabilization = stabilizer_count > 0
|
|
525
|
+
has_completion = any(op in {"silence", "transition"} for op in sequence)
|
|
526
|
+
|
|
527
|
+
phase_count = sum(
|
|
528
|
+
[has_activation, has_transformation, has_stabilization, has_completion]
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
# All 4 phases = 1.0, 3 phases = 0.75, 2 phases = 0.5, 1 phase = 0.25
|
|
532
|
+
return phase_count / 4.0
|
|
533
|
+
|
|
534
|
+
def _calculate_smoothness(
|
|
535
|
+
self, sequence: List[str], problematic_transitions: List[Tuple[str, str]]
|
|
536
|
+
) -> float:
|
|
537
|
+
"""Calculate transition smoothness: quality of operator transitions.
|
|
538
|
+
|
|
539
|
+
Measures ratio of valid/smooth transitions vs total transitions.
|
|
540
|
+
|
|
541
|
+
Parameters
|
|
542
|
+
----------
|
|
543
|
+
sequence : List[str]
|
|
544
|
+
Operator sequence
|
|
545
|
+
problematic_transitions : List[Tuple[str, str]]
|
|
546
|
+
Pre-computed list of problematic transition pairs
|
|
547
|
+
|
|
548
|
+
Returns
|
|
549
|
+
-------
|
|
550
|
+
float
|
|
551
|
+
Smoothness score (0.0-1.0)
|
|
552
|
+
"""
|
|
553
|
+
if len(sequence) < 2:
|
|
554
|
+
return 1.0 # No transitions to assess
|
|
555
|
+
|
|
556
|
+
total_transitions = len(sequence) - 1
|
|
557
|
+
# Each problematic transition gets 0.5 penalty (same as in _calculate_coherence)
|
|
558
|
+
penalty = len(problematic_transitions) * 0.5
|
|
559
|
+
return max(0.0, 1.0 - (penalty / total_transitions))
|
|
560
|
+
|
|
561
|
+
def _assess_pattern_clarity(self, sequence: List[str]) -> float:
|
|
562
|
+
"""Assess how clearly the sequence forms a recognizable pattern.
|
|
563
|
+
|
|
564
|
+
Parameters
|
|
565
|
+
----------
|
|
566
|
+
sequence : List[str]
|
|
567
|
+
Operator sequence
|
|
568
|
+
|
|
569
|
+
Returns
|
|
570
|
+
-------
|
|
571
|
+
float
|
|
572
|
+
Pattern clarity score (0.0-1.0)
|
|
573
|
+
"""
|
|
574
|
+
if len(sequence) < 3:
|
|
575
|
+
return 0.5 # Too short for clear pattern
|
|
576
|
+
|
|
577
|
+
# Check for canonical patterns
|
|
578
|
+
pattern = self._detect_pattern(sequence)
|
|
579
|
+
|
|
580
|
+
if pattern in {"activation", "therapeutic", "regenerative", "transformative"}:
|
|
581
|
+
return 0.9 # Clear, recognized pattern
|
|
582
|
+
elif pattern in {"stabilization", "exploratory"}:
|
|
583
|
+
return 0.7 # Recognizable but simpler
|
|
584
|
+
else:
|
|
585
|
+
return 0.5 # No clear pattern
|
|
586
|
+
|
|
587
|
+
def _assess_closure(self, sequence: List[str]) -> float:
|
|
588
|
+
"""Assess structural closure quality.
|
|
589
|
+
|
|
590
|
+
Parameters
|
|
591
|
+
----------
|
|
592
|
+
sequence : List[str]
|
|
593
|
+
Operator sequence
|
|
594
|
+
|
|
595
|
+
Returns
|
|
596
|
+
-------
|
|
597
|
+
float
|
|
598
|
+
Closure quality score (0.0-1.0)
|
|
599
|
+
"""
|
|
600
|
+
if not sequence:
|
|
601
|
+
return 0.0
|
|
602
|
+
|
|
603
|
+
# Valid endings per grammar
|
|
604
|
+
valid_endings = {SILENCE, TRANSITION, RECURSIVITY, DISSONANCE}
|
|
605
|
+
|
|
606
|
+
if sequence[-1] in valid_endings:
|
|
607
|
+
# Stabilizer endings are best
|
|
608
|
+
if sequence[-1] in _STABILIZERS:
|
|
609
|
+
return 1.0
|
|
610
|
+
# Other valid endings are good
|
|
611
|
+
return 0.8
|
|
612
|
+
|
|
613
|
+
# Invalid ending
|
|
614
|
+
return 0.3
|
|
615
|
+
|
|
616
|
+
def _count_unresolved_dissonance(self, sequence: List[str]) -> int:
|
|
617
|
+
"""Count destabilizers not followed by stabilizers within reasonable window.
|
|
618
|
+
|
|
619
|
+
Parameters
|
|
620
|
+
----------
|
|
621
|
+
sequence : List[str]
|
|
622
|
+
Operator sequence
|
|
623
|
+
|
|
624
|
+
Returns
|
|
625
|
+
-------
|
|
626
|
+
int
|
|
627
|
+
Count of unresolved dissonant operators
|
|
628
|
+
"""
|
|
629
|
+
unresolved = 0
|
|
630
|
+
window = 3 # Look ahead up to 3 operators
|
|
631
|
+
|
|
632
|
+
for i, op in enumerate(sequence):
|
|
633
|
+
if op in DESTABILIZERS:
|
|
634
|
+
# Check if a stabilizer appears in the next 'window' operators
|
|
635
|
+
lookahead = sequence[i + 1 : i + 1 + window]
|
|
636
|
+
if not any(stabilizer in _STABILIZERS for stabilizer in lookahead):
|
|
637
|
+
unresolved += 1
|
|
638
|
+
|
|
639
|
+
return unresolved
|
|
640
|
+
|
|
641
|
+
def _assess_pattern_value_optimized(
|
|
642
|
+
self, sequence: List[str], unique_count: int
|
|
643
|
+
) -> float:
|
|
644
|
+
"""Assess the structural value of the pattern using pre-computed unique count.
|
|
645
|
+
|
|
646
|
+
Value is higher when:
|
|
647
|
+
- Multiple operator types present (diversity)
|
|
648
|
+
- Key structural phases are included
|
|
649
|
+
- Balance between forces
|
|
650
|
+
|
|
651
|
+
Parameters
|
|
652
|
+
----------
|
|
653
|
+
sequence : List[str]
|
|
654
|
+
Operator sequence
|
|
655
|
+
unique_count : int
|
|
656
|
+
Pre-computed count of unique operators in sequence
|
|
657
|
+
|
|
658
|
+
Returns
|
|
659
|
+
-------
|
|
660
|
+
float
|
|
661
|
+
Pattern value score (0.0-1.0)
|
|
662
|
+
"""
|
|
663
|
+
if not sequence:
|
|
664
|
+
return 0.0
|
|
665
|
+
|
|
666
|
+
# Diversity: use pre-computed unique count
|
|
667
|
+
diversity_score = min(
|
|
668
|
+
1.0, unique_count / 6.0
|
|
669
|
+
) # 6+ operators is excellent diversity
|
|
670
|
+
|
|
671
|
+
# Coverage: how many operator categories are represented
|
|
672
|
+
# This is still a minimal single-pass check
|
|
673
|
+
categories_present = 0
|
|
674
|
+
if any(op in {"emission", "reception"} for op in sequence):
|
|
675
|
+
categories_present += 1 # Activation
|
|
676
|
+
if any(op in _STABILIZERS for op in sequence):
|
|
677
|
+
categories_present += 1 # Stabilization
|
|
678
|
+
if any(op in DESTABILIZERS for op in sequence):
|
|
679
|
+
categories_present += 1 # Destabilization
|
|
680
|
+
if any(op in TRANSFORMERS for op in sequence):
|
|
681
|
+
categories_present += 1 # Transformation
|
|
682
|
+
|
|
683
|
+
coverage_score = categories_present / 4.0
|
|
684
|
+
|
|
685
|
+
# Combine factors
|
|
686
|
+
return (diversity_score * 0.5) + (coverage_score * 0.5)
|
|
687
|
+
|
|
688
|
+
def _detect_pattern(self, sequence: List[str]) -> str:
|
|
689
|
+
"""Detect the dominant structural pattern type.
|
|
690
|
+
|
|
691
|
+
Parameters
|
|
692
|
+
----------
|
|
693
|
+
sequence : List[str]
|
|
694
|
+
Operator sequence
|
|
695
|
+
|
|
696
|
+
Returns
|
|
697
|
+
-------
|
|
698
|
+
str
|
|
699
|
+
Pattern name (e.g., "activation", "therapeutic", "unknown")
|
|
700
|
+
"""
|
|
701
|
+
if not sequence:
|
|
702
|
+
return "empty"
|
|
703
|
+
|
|
704
|
+
# Check for common patterns
|
|
705
|
+
starts_with_emission = sequence[0] == "emission"
|
|
706
|
+
has_reception = "reception" in sequence
|
|
707
|
+
has_coherence = COHERENCE in sequence
|
|
708
|
+
has_dissonance = DISSONANCE in sequence
|
|
709
|
+
has_self_org = SELF_ORGANIZATION in sequence
|
|
710
|
+
has_regenerator = any(op in _REGENERATORS for op in sequence)
|
|
711
|
+
|
|
712
|
+
# Pattern detection logic
|
|
713
|
+
if starts_with_emission and has_reception and has_coherence:
|
|
714
|
+
if has_dissonance and has_self_org:
|
|
715
|
+
return "therapeutic"
|
|
716
|
+
elif has_regenerator:
|
|
717
|
+
return "regenerative"
|
|
718
|
+
else:
|
|
719
|
+
return "activation"
|
|
720
|
+
|
|
721
|
+
if has_dissonance and has_self_org:
|
|
722
|
+
return "transformative"
|
|
723
|
+
|
|
724
|
+
if sum(1 for op in sequence if op in _STABILIZERS) > len(sequence) // 2:
|
|
725
|
+
return "stabilization"
|
|
726
|
+
|
|
727
|
+
if sum(1 for op in sequence if op in DESTABILIZERS) > len(sequence) // 2:
|
|
728
|
+
return "exploratory"
|
|
729
|
+
|
|
730
|
+
return "unknown"
|
|
731
|
+
|
|
732
|
+
def analyze_thol_coherence(self, G: TNFRGraph) -> dict[str, Any] | None:
|
|
733
|
+
"""Analyze collective coherence of THOL bifurcations across the network.
|
|
734
|
+
|
|
735
|
+
Examines all nodes that have undergone THOL bifurcation and provides
|
|
736
|
+
statistics on their collective coherence metrics.
|
|
737
|
+
|
|
738
|
+
Parameters
|
|
739
|
+
----------
|
|
740
|
+
G : TNFRGraph
|
|
741
|
+
Graph containing nodes with potential THOL bifurcations
|
|
742
|
+
|
|
743
|
+
Returns
|
|
744
|
+
-------
|
|
745
|
+
dict or None
|
|
746
|
+
Dictionary containing coherence statistics:
|
|
747
|
+
- mean_coherence: Average coherence across all THOL nodes
|
|
748
|
+
- min_coherence: Lowest coherence value observed
|
|
749
|
+
- max_coherence: Highest coherence value observed
|
|
750
|
+
- nodes_below_threshold: Count of nodes with coherence < 0.3
|
|
751
|
+
- total_thol_nodes: Total nodes with sub-EPIs
|
|
752
|
+
Returns None if no THOL bifurcations exist in the network.
|
|
753
|
+
|
|
754
|
+
Notes
|
|
755
|
+
-----
|
|
756
|
+
TNFR Principle: Collective coherence measures the structural alignment
|
|
757
|
+
of emergent sub-EPIs. Low coherence may indicate chaotic fragmentation
|
|
758
|
+
rather than controlled emergence.
|
|
759
|
+
|
|
760
|
+
This metric is particularly useful for:
|
|
761
|
+
- Detecting pathological bifurcation patterns
|
|
762
|
+
- Monitoring network-wide self-organization quality
|
|
763
|
+
- Identifying nodes requiring stabilization
|
|
764
|
+
|
|
765
|
+
Examples
|
|
766
|
+
--------
|
|
767
|
+
>>> analyzer = SequenceHealthAnalyzer()
|
|
768
|
+
>>> # After running THOL operations on graph G
|
|
769
|
+
>>> coherence_stats = analyzer.analyze_thol_coherence(G)
|
|
770
|
+
>>> if coherence_stats:
|
|
771
|
+
... print(f"Mean coherence: {coherence_stats['mean_coherence']:.3f}")
|
|
772
|
+
... print(f"Nodes below threshold: {coherence_stats['nodes_below_threshold']}")
|
|
773
|
+
"""
|
|
774
|
+
# Find all nodes with sub-EPIs (THOL bifurcation occurred)
|
|
775
|
+
thol_nodes = []
|
|
776
|
+
for node in G.nodes():
|
|
777
|
+
if G.nodes[node].get("sub_epis"):
|
|
778
|
+
thol_nodes.append(node)
|
|
779
|
+
|
|
780
|
+
if not thol_nodes:
|
|
781
|
+
return None
|
|
782
|
+
|
|
783
|
+
# Collect coherence values
|
|
784
|
+
coherences = []
|
|
785
|
+
for node in thol_nodes:
|
|
786
|
+
coh = G.nodes[node].get("_thol_collective_coherence")
|
|
787
|
+
if coh is not None:
|
|
788
|
+
coherences.append(coh)
|
|
789
|
+
|
|
790
|
+
if not coherences:
|
|
791
|
+
return None
|
|
792
|
+
|
|
793
|
+
# Compute statistics
|
|
794
|
+
mean_coherence = sum(coherences) / len(coherences)
|
|
795
|
+
min_coherence = min(coherences)
|
|
796
|
+
max_coherence = max(coherences)
|
|
797
|
+
|
|
798
|
+
# Get threshold from graph config
|
|
799
|
+
threshold = float(G.graph.get("THOL_MIN_COLLECTIVE_COHERENCE", 0.3))
|
|
800
|
+
nodes_below_threshold = sum(1 for c in coherences if c < threshold)
|
|
801
|
+
|
|
802
|
+
return {
|
|
803
|
+
"mean_coherence": mean_coherence,
|
|
804
|
+
"min_coherence": min_coherence,
|
|
805
|
+
"max_coherence": max_coherence,
|
|
806
|
+
"nodes_below_threshold": nodes_below_threshold,
|
|
807
|
+
"total_thol_nodes": len(thol_nodes),
|
|
808
|
+
"threshold": threshold,
|
|
809
|
+
}
|