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,349 @@
|
|
|
1
|
+
"""Unified phase compatibility calculations for TNFR operators.
|
|
2
|
+
|
|
3
|
+
This module provides canonical implementations of phase-based coupling strength
|
|
4
|
+
calculations used by multiple TNFR operators (UM, RA, THOL). All operators that
|
|
5
|
+
perform phase-based coupling or propagation MUST use these functions to ensure
|
|
6
|
+
consistency with TNFR physics and Invariant #5.
|
|
7
|
+
|
|
8
|
+
Physical Foundation
|
|
9
|
+
-------------------
|
|
10
|
+
|
|
11
|
+
**Phase Compatibility in TNFR:**
|
|
12
|
+
|
|
13
|
+
Coupling between nodes requires phase synchronization. Destructive interference
|
|
14
|
+
occurs when phases are misaligned (antiphase), while constructive interference
|
|
15
|
+
occurs when phases align. The coupling strength formula reflects this physics:
|
|
16
|
+
|
|
17
|
+
.. math::
|
|
18
|
+
\\text{coupling_strength} = 1.0 - \\frac{|\\Delta\\phi|}{\\pi}
|
|
19
|
+
|
|
20
|
+
where Δφ is the phase difference in radians.
|
|
21
|
+
|
|
22
|
+
**Physical Interpretation:**
|
|
23
|
+
|
|
24
|
+
- Δφ = 0 (perfect alignment) → coupling = 1.0 (maximum constructive interference)
|
|
25
|
+
- Δφ = π/2 (orthogonal) → coupling = 0.5 (partial coupling)
|
|
26
|
+
- Δφ = π (antiphase) → coupling = 0.0 (destructive interference)
|
|
27
|
+
|
|
28
|
+
**TNFR Invariant #5:** "No coupling without explicit phase verification"
|
|
29
|
+
(see AGENTS.md). All coupling operations must verify phase compatibility
|
|
30
|
+
before propagating structural information.
|
|
31
|
+
|
|
32
|
+
Canonical Usage
|
|
33
|
+
---------------
|
|
34
|
+
|
|
35
|
+
**Operators Using This Module:**
|
|
36
|
+
|
|
37
|
+
1. **UM (Coupling)**: Phase synchronization and network formation
|
|
38
|
+
2. **RA (Resonance)**: Coherence propagation through phase-aligned paths
|
|
39
|
+
3. **THOL (Self-organization)**: Sub-EPI propagation to coupled neighbors
|
|
40
|
+
|
|
41
|
+
**Before Refactoring:**
|
|
42
|
+
|
|
43
|
+
Each operator implemented its own phase compatibility calculation, leading
|
|
44
|
+
to potential inconsistencies and maintenance burden.
|
|
45
|
+
|
|
46
|
+
**After Refactoring:**
|
|
47
|
+
|
|
48
|
+
All operators use the canonical functions defined here, ensuring theoretical
|
|
49
|
+
consistency and simplifying validation against TNFR physics.
|
|
50
|
+
|
|
51
|
+
Examples
|
|
52
|
+
--------
|
|
53
|
+
|
|
54
|
+
**Basic coupling strength calculation:**
|
|
55
|
+
|
|
56
|
+
>>> import math
|
|
57
|
+
>>> # Perfect alignment
|
|
58
|
+
>>> compute_phase_coupling_strength(0.0, 0.0)
|
|
59
|
+
1.0
|
|
60
|
+
>>> # Orthogonal phases
|
|
61
|
+
>>> compute_phase_coupling_strength(0.0, math.pi/2)
|
|
62
|
+
0.5
|
|
63
|
+
>>> # Antiphase (destructive)
|
|
64
|
+
>>> round(compute_phase_coupling_strength(0.0, math.pi), 10)
|
|
65
|
+
0.0
|
|
66
|
+
|
|
67
|
+
**Phase compatibility check:**
|
|
68
|
+
|
|
69
|
+
>>> # Check if phases are compatible for coupling
|
|
70
|
+
>>> is_phase_compatible(0.0, 0.1, threshold=0.5)
|
|
71
|
+
True
|
|
72
|
+
>>> is_phase_compatible(0.0, math.pi, threshold=0.5)
|
|
73
|
+
False
|
|
74
|
+
|
|
75
|
+
**Network phase alignment:**
|
|
76
|
+
|
|
77
|
+
>>> import networkx as nx
|
|
78
|
+
>>> from tnfr.constants.aliases import ALIAS_THETA
|
|
79
|
+
>>> G = nx.Graph()
|
|
80
|
+
>>> G.add_edges_from([(0, 1), (1, 2)])
|
|
81
|
+
>>> for i, theta in enumerate([0.0, 0.1, 0.2]):
|
|
82
|
+
... G.nodes[i][ALIAS_THETA] = theta
|
|
83
|
+
>>> alignment = compute_network_phase_alignment(G, node=1, radius=1)
|
|
84
|
+
>>> 0.0 <= alignment <= 1.0
|
|
85
|
+
True
|
|
86
|
+
|
|
87
|
+
See Also
|
|
88
|
+
--------
|
|
89
|
+
|
|
90
|
+
operators.definitions : Operator implementations (UM, RA, THOL)
|
|
91
|
+
metrics.phase_coherence : Kuramoto order parameter and phase metrics
|
|
92
|
+
AGENTS.md : Invariant #5 - Phase Verification requirement
|
|
93
|
+
UNIFIED_GRAMMAR_RULES.md : U3 - RESONANT COUPLING grammar rule
|
|
94
|
+
|
|
95
|
+
References
|
|
96
|
+
----------
|
|
97
|
+
|
|
98
|
+
.. [1] TNFR.pdf § 2.3: Phase synchronization and coupling
|
|
99
|
+
.. [2] AGENTS.md: Invariant #5 - No coupling without phase verification
|
|
100
|
+
.. [3] UNIFIED_GRAMMAR_RULES.md: U3 - Resonant Coupling requires |φᵢ - φⱼ| ≤ Δφ_max
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
from __future__ import annotations
|
|
104
|
+
|
|
105
|
+
import math
|
|
106
|
+
from typing import TYPE_CHECKING, Any
|
|
107
|
+
|
|
108
|
+
if TYPE_CHECKING:
|
|
109
|
+
from ..types import TNFRGraph, NodeId
|
|
110
|
+
|
|
111
|
+
from ..utils.numeric import angle_diff
|
|
112
|
+
|
|
113
|
+
__all__ = [
|
|
114
|
+
"compute_phase_coupling_strength",
|
|
115
|
+
"is_phase_compatible",
|
|
116
|
+
"compute_network_phase_alignment",
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def compute_phase_coupling_strength(
|
|
121
|
+
theta_a: float,
|
|
122
|
+
theta_b: float,
|
|
123
|
+
) -> float:
|
|
124
|
+
"""Compute canonical coupling strength from phase difference.
|
|
125
|
+
|
|
126
|
+
This is the canonical TNFR formula for phase-based coupling strength,
|
|
127
|
+
representing the degree of constructive vs. destructive interference
|
|
128
|
+
between two oscillating nodes.
|
|
129
|
+
|
|
130
|
+
Parameters
|
|
131
|
+
----------
|
|
132
|
+
theta_a : float
|
|
133
|
+
Phase of first node in radians [0, 2π)
|
|
134
|
+
theta_b : float
|
|
135
|
+
Phase of second node in radians [0, 2π)
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
float
|
|
140
|
+
Coupling strength in [0, 1]:
|
|
141
|
+
- 1.0: Perfect phase alignment (Δφ = 0)
|
|
142
|
+
- 0.5: Orthogonal phases (Δφ = π/2)
|
|
143
|
+
- 0.0: Antiphase (Δφ = π, destructive interference)
|
|
144
|
+
|
|
145
|
+
Notes
|
|
146
|
+
-----
|
|
147
|
+
**Formula:**
|
|
148
|
+
|
|
149
|
+
.. math::
|
|
150
|
+
\\text{coupling_strength} = 1.0 - \\frac{|\\text{angle_diff}(\\theta_b, \\theta_a)|}{\\pi}
|
|
151
|
+
|
|
152
|
+
The formula uses :func:`~tnfr.utils.numeric.angle_diff` to compute the
|
|
153
|
+
shortest angular distance between phases, properly handling wrap-around
|
|
154
|
+
at 2π boundaries.
|
|
155
|
+
|
|
156
|
+
**Physics:**
|
|
157
|
+
|
|
158
|
+
- Based on wave interference physics: aligned phases → constructive interference
|
|
159
|
+
- Antiphase (Δφ = π) → destructive interference → zero coupling
|
|
160
|
+
- Linear interpolation between extremes reflects gradual transition
|
|
161
|
+
|
|
162
|
+
**Used By:**
|
|
163
|
+
|
|
164
|
+
- UM (Coupling): For determining link formation and synchronization strength
|
|
165
|
+
- RA (Resonance): For gating coherence propagation to neighbors
|
|
166
|
+
- THOL (Self-organization): For sub-EPI propagation through coupled nodes
|
|
167
|
+
|
|
168
|
+
**Invariant #5:** This function implements the explicit phase verification
|
|
169
|
+
required by TNFR Invariant #5 (AGENTS.md). All coupling operations must
|
|
170
|
+
verify phase compatibility before propagating structural information.
|
|
171
|
+
|
|
172
|
+
Examples
|
|
173
|
+
--------
|
|
174
|
+
>>> import math
|
|
175
|
+
>>> # Perfect alignment
|
|
176
|
+
>>> compute_phase_coupling_strength(0.0, 0.0)
|
|
177
|
+
1.0
|
|
178
|
+
>>> # Small misalignment
|
|
179
|
+
>>> compute_phase_coupling_strength(0.0, 0.1) # doctest: +ELLIPSIS
|
|
180
|
+
0.96...
|
|
181
|
+
>>> # Orthogonal phases
|
|
182
|
+
>>> compute_phase_coupling_strength(0.0, math.pi/2)
|
|
183
|
+
0.5
|
|
184
|
+
>>> # Antiphase (destructive)
|
|
185
|
+
>>> round(compute_phase_coupling_strength(0.0, math.pi), 10)
|
|
186
|
+
0.0
|
|
187
|
+
>>> # Wrap-around handling
|
|
188
|
+
>>> compute_phase_coupling_strength(0.1, 2*math.pi - 0.1) # doctest: +ELLIPSIS
|
|
189
|
+
0.93...
|
|
190
|
+
|
|
191
|
+
See Also
|
|
192
|
+
--------
|
|
193
|
+
is_phase_compatible : Boolean compatibility check with threshold
|
|
194
|
+
angle_diff : Shortest angular distance between phases
|
|
195
|
+
"""
|
|
196
|
+
phase_diff = abs(angle_diff(theta_b, theta_a))
|
|
197
|
+
return 1.0 - (phase_diff / math.pi)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def is_phase_compatible(
|
|
201
|
+
theta_a: float,
|
|
202
|
+
theta_b: float,
|
|
203
|
+
threshold: float = 0.5,
|
|
204
|
+
) -> bool:
|
|
205
|
+
"""Check if two phases are compatible for coupling/propagation.
|
|
206
|
+
|
|
207
|
+
Determines whether two nodes are sufficiently phase-aligned to support
|
|
208
|
+
resonant coupling, based on a configurable coupling strength threshold.
|
|
209
|
+
|
|
210
|
+
Parameters
|
|
211
|
+
----------
|
|
212
|
+
theta_a : float
|
|
213
|
+
Phase of first node in radians [0, 2π)
|
|
214
|
+
theta_b : float
|
|
215
|
+
Phase of second node in radians [0, 2π)
|
|
216
|
+
threshold : float, default=0.5
|
|
217
|
+
Minimum coupling strength required for compatibility [0, 1].
|
|
218
|
+
Default 0.5 corresponds to maximum phase difference of π/2 (orthogonal).
|
|
219
|
+
|
|
220
|
+
Returns
|
|
221
|
+
-------
|
|
222
|
+
bool
|
|
223
|
+
True if coupling_strength >= threshold (nodes are compatible)
|
|
224
|
+
False if coupling_strength < threshold (nodes are incompatible)
|
|
225
|
+
|
|
226
|
+
Notes
|
|
227
|
+
-----
|
|
228
|
+
**Common Thresholds:**
|
|
229
|
+
|
|
230
|
+
- 0.5 (default): Allows coupling up to π/2 phase difference
|
|
231
|
+
- 0.7: More restrictive, requires Δφ < π/2.1 (~95°)
|
|
232
|
+
- 0.9: Very restrictive, requires Δφ < π/10 (~18°)
|
|
233
|
+
|
|
234
|
+
**Usage:**
|
|
235
|
+
|
|
236
|
+
- **UM (Coupling)**: Gate link formation based on phase compatibility
|
|
237
|
+
- **RA (Resonance)**: Filter neighbors for coherence propagation
|
|
238
|
+
- **THOL propagation**: Minimum coupling for sub-EPI propagation
|
|
239
|
+
|
|
240
|
+
**Invariant #5:** This function provides a boolean interface to the
|
|
241
|
+
phase verification requirement (AGENTS.md Invariant #5).
|
|
242
|
+
|
|
243
|
+
Examples
|
|
244
|
+
--------
|
|
245
|
+
>>> import math
|
|
246
|
+
>>> # In-phase: compatible
|
|
247
|
+
>>> is_phase_compatible(0.0, 0.1, threshold=0.5)
|
|
248
|
+
True
|
|
249
|
+
>>> # Orthogonal: at threshold boundary
|
|
250
|
+
>>> is_phase_compatible(0.0, math.pi/2, threshold=0.5)
|
|
251
|
+
True
|
|
252
|
+
>>> # Slightly beyond orthogonal: incompatible
|
|
253
|
+
>>> is_phase_compatible(0.0, math.pi/2 + 0.1, threshold=0.5)
|
|
254
|
+
False
|
|
255
|
+
>>> # Antiphase: incompatible
|
|
256
|
+
>>> is_phase_compatible(0.0, math.pi, threshold=0.5)
|
|
257
|
+
False
|
|
258
|
+
>>> # Higher threshold: more restrictive
|
|
259
|
+
>>> is_phase_compatible(0.0, math.pi/4, threshold=0.9)
|
|
260
|
+
False
|
|
261
|
+
>>> is_phase_compatible(0.0, 0.1, threshold=0.9)
|
|
262
|
+
True
|
|
263
|
+
|
|
264
|
+
See Also
|
|
265
|
+
--------
|
|
266
|
+
compute_phase_coupling_strength : Continuous coupling strength [0, 1]
|
|
267
|
+
"""
|
|
268
|
+
coupling = compute_phase_coupling_strength(theta_a, theta_b)
|
|
269
|
+
return coupling >= threshold
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def compute_network_phase_alignment(
|
|
273
|
+
G: TNFRGraph,
|
|
274
|
+
node: NodeId,
|
|
275
|
+
radius: int = 1,
|
|
276
|
+
) -> float:
|
|
277
|
+
"""Compute phase alignment in local neighborhood using Kuramoto order parameter.
|
|
278
|
+
|
|
279
|
+
This is a convenience wrapper around the existing
|
|
280
|
+
:func:`~tnfr.metrics.phase_coherence.compute_phase_alignment` function,
|
|
281
|
+
provided for API consistency within this module.
|
|
282
|
+
|
|
283
|
+
Parameters
|
|
284
|
+
----------
|
|
285
|
+
G : TNFRGraph
|
|
286
|
+
TNFR network graph containing nodes with phase (theta) attributes
|
|
287
|
+
node : NodeId
|
|
288
|
+
Central node for neighborhood analysis
|
|
289
|
+
radius : int, default=1
|
|
290
|
+
Neighborhood radius in hops from central node
|
|
291
|
+
|
|
292
|
+
Returns
|
|
293
|
+
-------
|
|
294
|
+
float
|
|
295
|
+
Phase alignment quality in [0, 1]:
|
|
296
|
+
- 1.0: Perfect phase synchronization (all nodes aligned)
|
|
297
|
+
- 0.0: Complete phase disorder (random phases)
|
|
298
|
+
|
|
299
|
+
Notes
|
|
300
|
+
-----
|
|
301
|
+
**Kuramoto Order Parameter:**
|
|
302
|
+
|
|
303
|
+
Measures collective phase synchrony using:
|
|
304
|
+
|
|
305
|
+
.. math::
|
|
306
|
+
r = |\\frac{1}{N} \\sum_{j=1}^{N} e^{i\\theta_j}|
|
|
307
|
+
|
|
308
|
+
**Used By:**
|
|
309
|
+
|
|
310
|
+
- **RA (Resonance)**: Assess network coherence for propagation gating
|
|
311
|
+
- **IL (Coherence)**: Validate phase locking effectiveness
|
|
312
|
+
|
|
313
|
+
**Implementation:**
|
|
314
|
+
|
|
315
|
+
This function delegates to the existing implementation in
|
|
316
|
+
:mod:`tnfr.metrics.phase_coherence` to avoid code duplication
|
|
317
|
+
while providing a unified API for phase compatibility calculations.
|
|
318
|
+
|
|
319
|
+
Examples
|
|
320
|
+
--------
|
|
321
|
+
>>> import networkx as nx
|
|
322
|
+
>>> from tnfr.constants.aliases import ALIAS_THETA
|
|
323
|
+
>>> G = nx.Graph()
|
|
324
|
+
>>> G.add_edges_from([(0, 1), (1, 2), (2, 3)])
|
|
325
|
+
>>> # Highly aligned phases
|
|
326
|
+
>>> for i in range(4):
|
|
327
|
+
... G.nodes[i][ALIAS_THETA] = i * 0.1
|
|
328
|
+
>>> alignment = compute_network_phase_alignment(G, node=1, radius=1)
|
|
329
|
+
>>> alignment > 0.9 # High alignment
|
|
330
|
+
True
|
|
331
|
+
>>> # Random phases
|
|
332
|
+
>>> import math
|
|
333
|
+
>>> G.nodes[0][ALIAS_THETA] = 0.0
|
|
334
|
+
>>> G.nodes[1][ALIAS_THETA] = math.pi/3
|
|
335
|
+
>>> G.nodes[2][ALIAS_THETA] = 2*math.pi/3
|
|
336
|
+
>>> G.nodes[3][ALIAS_THETA] = math.pi
|
|
337
|
+
>>> alignment = compute_network_phase_alignment(G, node=1, radius=1)
|
|
338
|
+
>>> 0.0 <= alignment <= 1.0
|
|
339
|
+
True
|
|
340
|
+
|
|
341
|
+
See Also
|
|
342
|
+
--------
|
|
343
|
+
metrics.phase_coherence.compute_phase_alignment : Underlying implementation
|
|
344
|
+
metrics.phase_coherence.compute_global_phase_coherence : Global network metric
|
|
345
|
+
"""
|
|
346
|
+
# Import existing function to avoid duplication
|
|
347
|
+
from .phase_coherence import compute_phase_alignment
|
|
348
|
+
|
|
349
|
+
return compute_phase_alignment(G, node, radius=radius)
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Reporting helpers for collected metrics."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
from heapq import nlargest
|
|
7
|
+
from statistics import StatisticsError, fmean, mean
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from ..glyph_history import ensure_history
|
|
11
|
+
from ..sense import sigma_rose
|
|
12
|
+
from ..types import NodeId, TNFRGraph
|
|
13
|
+
from .glyph_timing import for_each_glyph
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"Tg_global",
|
|
17
|
+
"Tg_by_node",
|
|
18
|
+
"latency_series",
|
|
19
|
+
"glyphogram_series",
|
|
20
|
+
"glyph_top",
|
|
21
|
+
"build_metrics_summary",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
# Reporting functions
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def Tg_global(G: TNFRGraph, normalize: bool = True) -> dict[str, float]:
|
|
30
|
+
"""Total glyph dwell time per class."""
|
|
31
|
+
|
|
32
|
+
hist = ensure_history(G)
|
|
33
|
+
tg_total: dict[str, float] = hist.get("Tg_total", {})
|
|
34
|
+
total = sum(tg_total.values()) or 1.0
|
|
35
|
+
out: dict[str, float] = {}
|
|
36
|
+
|
|
37
|
+
def add(g: str) -> None:
|
|
38
|
+
val = float(tg_total.get(g, 0.0))
|
|
39
|
+
out[g] = val / total if normalize else val
|
|
40
|
+
|
|
41
|
+
for_each_glyph(add)
|
|
42
|
+
return out
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def Tg_by_node(
|
|
46
|
+
G: TNFRGraph, n: NodeId, normalize: bool = False
|
|
47
|
+
) -> dict[str, float] | dict[str, list[float]]:
|
|
48
|
+
"""Per-node glyph dwell summary."""
|
|
49
|
+
|
|
50
|
+
hist = ensure_history(G)
|
|
51
|
+
rec = hist.get("Tg_by_node", {}).get(n, {})
|
|
52
|
+
if not normalize:
|
|
53
|
+
runs_out: dict[str, list[float]] = {}
|
|
54
|
+
|
|
55
|
+
def copy_runs(g: str) -> None:
|
|
56
|
+
runs_out[g] = list(rec.get(g, []))
|
|
57
|
+
|
|
58
|
+
for_each_glyph(copy_runs)
|
|
59
|
+
return runs_out
|
|
60
|
+
mean_out: dict[str, float] = {}
|
|
61
|
+
|
|
62
|
+
def add(g: str) -> None:
|
|
63
|
+
runs = rec.get(g, [])
|
|
64
|
+
mean_out[g] = float(mean(runs)) if runs else 0.0
|
|
65
|
+
|
|
66
|
+
for_each_glyph(add)
|
|
67
|
+
return mean_out
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def latency_series(G: TNFRGraph) -> dict[str, list[float]]:
|
|
71
|
+
"""Return latency samples as ``{"t": [...], "value": [...]}``."""
|
|
72
|
+
|
|
73
|
+
hist = ensure_history(G)
|
|
74
|
+
xs = hist.get("latency_index", [])
|
|
75
|
+
return {
|
|
76
|
+
"t": [float(x.get("t", i)) for i, x in enumerate(xs)],
|
|
77
|
+
"value": [float(x.get("value", 0.0)) for x in xs],
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def glyphogram_series(G: TNFRGraph) -> dict[str, list[float]]:
|
|
82
|
+
"""Return glyphogram time series keyed by glyph label."""
|
|
83
|
+
|
|
84
|
+
hist = ensure_history(G)
|
|
85
|
+
xs = hist.get("glyphogram", [])
|
|
86
|
+
if not xs:
|
|
87
|
+
return {"t": []}
|
|
88
|
+
out: dict[str, list[float]] = {
|
|
89
|
+
"t": [float(x.get("t", i)) for i, x in enumerate(xs)]
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
def add(g: str) -> None:
|
|
93
|
+
out[g] = [float(x.get(g, 0.0)) for x in xs]
|
|
94
|
+
|
|
95
|
+
for_each_glyph(add)
|
|
96
|
+
return out
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def glyph_top(G: TNFRGraph, k: int = 3) -> list[tuple[str, float]]:
|
|
100
|
+
"""Top-k structural operators by ``Tg_global`` fraction."""
|
|
101
|
+
|
|
102
|
+
k = int(k)
|
|
103
|
+
if k <= 0:
|
|
104
|
+
raise ValueError("k must be a positive integer")
|
|
105
|
+
tg = Tg_global(G, normalize=True)
|
|
106
|
+
return nlargest(k, tg.items(), key=lambda kv: kv[1])
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def build_metrics_summary(
|
|
110
|
+
G: TNFRGraph, *, series_limit: int | None = None
|
|
111
|
+
) -> tuple[
|
|
112
|
+
dict[str, float | dict[str, float] | dict[str, list[float]] | dict[str, int]], bool
|
|
113
|
+
]:
|
|
114
|
+
"""Collect a compact metrics summary for CLI reporting.
|
|
115
|
+
|
|
116
|
+
This factory aggregates various TNFR metrics into a unified summary
|
|
117
|
+
structure suitable for command-line display and analysis. It combines
|
|
118
|
+
glyph timing statistics, latency measurements, and coherence indicators.
|
|
119
|
+
|
|
120
|
+
Parameters
|
|
121
|
+
----------
|
|
122
|
+
G : TNFRGraph
|
|
123
|
+
Graph containing the recorded metrics history.
|
|
124
|
+
series_limit : int | None, optional
|
|
125
|
+
Maximum number of samples to keep for each glyphogram series.
|
|
126
|
+
When ``None`` or non-positive, returns the full history without
|
|
127
|
+
trimming. Default is None.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
tuple[dict, bool]
|
|
132
|
+
A two-element tuple containing:
|
|
133
|
+
|
|
134
|
+
- **summary** (dict): Metrics dictionary with the following keys:
|
|
135
|
+
|
|
136
|
+
- ``Tg_global``: Normalized glyph dwell time per class
|
|
137
|
+
- ``latency_mean``: Mean latency across all samples
|
|
138
|
+
- ``rose``: Sigma rose coherence indicator
|
|
139
|
+
- ``glyphogram``: Time series of glyph activity (trimmed if limit set)
|
|
140
|
+
|
|
141
|
+
- **has_data** (bool): True if latency data is available, False otherwise
|
|
142
|
+
|
|
143
|
+
Notes
|
|
144
|
+
-----
|
|
145
|
+
The series trimming feature is useful for limiting memory usage when
|
|
146
|
+
tracking long-running simulations. Trimming only affects the glyphogram
|
|
147
|
+
time series; aggregate statistics remain computed from the full history.
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
tg = Tg_global(G, normalize=True)
|
|
151
|
+
latency = latency_series(G)
|
|
152
|
+
glyph = glyphogram_series(G)
|
|
153
|
+
rose = sigma_rose(G)
|
|
154
|
+
|
|
155
|
+
latency_values = latency.get("value", [])
|
|
156
|
+
try:
|
|
157
|
+
latency_mean = fmean(latency_values)
|
|
158
|
+
except StatisticsError:
|
|
159
|
+
latency_mean = 0.0
|
|
160
|
+
|
|
161
|
+
limit: int | None
|
|
162
|
+
if series_limit is None:
|
|
163
|
+
limit = None
|
|
164
|
+
else:
|
|
165
|
+
limit = int(series_limit)
|
|
166
|
+
if limit <= 0:
|
|
167
|
+
limit = None
|
|
168
|
+
|
|
169
|
+
def _trim(values: Sequence[Any]) -> list[Any]:
|
|
170
|
+
seq = list(values)
|
|
171
|
+
if limit is None:
|
|
172
|
+
return seq
|
|
173
|
+
return seq[:limit]
|
|
174
|
+
|
|
175
|
+
glyph_summary = {k: _trim(v) for k, v in glyph.items()}
|
|
176
|
+
|
|
177
|
+
summary = {
|
|
178
|
+
"Tg_global": tg,
|
|
179
|
+
"latency_mean": latency_mean,
|
|
180
|
+
"rose": rose,
|
|
181
|
+
"glyphogram": glyph_summary,
|
|
182
|
+
}
|
|
183
|
+
return summary, bool(latency_values)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ..types import NodeId, TNFRGraph
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"Tg_global",
|
|
7
|
+
"Tg_by_node",
|
|
8
|
+
"latency_series",
|
|
9
|
+
"glyphogram_series",
|
|
10
|
+
"glyph_top",
|
|
11
|
+
"build_metrics_summary",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
def Tg_global(G: TNFRGraph, normalize: bool = True) -> dict[str, float]: ...
|
|
15
|
+
def Tg_by_node(
|
|
16
|
+
G: TNFRGraph, n: NodeId, normalize: bool = False
|
|
17
|
+
) -> dict[str, float] | dict[str, list[float]]: ...
|
|
18
|
+
def latency_series(G: TNFRGraph) -> dict[str, list[float]]: ...
|
|
19
|
+
def glyphogram_series(G: TNFRGraph) -> dict[str, list[float]]: ...
|
|
20
|
+
def glyph_top(G: TNFRGraph, k: int = 3) -> list[tuple[str, float]]: ...
|
|
21
|
+
def build_metrics_summary(
|
|
22
|
+
G: TNFRGraph, *, series_limit: int | None = None
|
|
23
|
+
) -> tuple[
|
|
24
|
+
dict[str, float | dict[str, float] | dict[str, list[float]] | dict[str, int]], bool
|
|
25
|
+
]: ...
|