tnfr 4.5.2__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 +334 -50
- 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 +214 -37
- 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 +149 -556
- tnfr/cache.pyi +13 -0
- tnfr/cli/__init__.py +51 -16
- tnfr/cli/__init__.pyi +26 -0
- tnfr/cli/arguments.py +344 -32
- tnfr/cli/arguments.pyi +29 -0
- tnfr/cli/execution.py +676 -50
- tnfr/cli/execution.pyi +70 -0
- tnfr/cli/interactive_validator.py +614 -0
- tnfr/cli/utils.py +18 -3
- 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/{constants_glyphs.py → config/constants.py} +26 -20
- tnfr/config/constants.pyi +12 -0
- tnfr/config/defaults.py +54 -0
- tnfr/{constants/core.py → config/defaults_core.py} +59 -6
- 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 +51 -133
- tnfr/constants/__init__.pyi +92 -0
- tnfr/constants/aliases.py +33 -0
- tnfr/constants/aliases.pyi +27 -0
- tnfr/constants/init.py +3 -1
- tnfr/constants/init.pyi +12 -0
- tnfr/constants/metric.py +9 -15
- 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 +213 -633
- 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 +2699 -398
- 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 +496 -102
- 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 +10 -5
- 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 +77 -55
- 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 +29 -50
- tnfr/flatten.pyi +21 -0
- tnfr/gamma.py +66 -53
- tnfr/gamma.pyi +36 -0
- tnfr/glyph_history.py +144 -57
- tnfr/glyph_history.pyi +35 -0
- tnfr/glyph_runtime.py +19 -0
- tnfr/glyph_runtime.pyi +8 -0
- tnfr/immutable.py +70 -30
- tnfr/immutable.pyi +36 -0
- tnfr/initialization.py +22 -16
- tnfr/initialization.pyi +65 -0
- tnfr/io.py +5 -241
- tnfr/io.pyi +13 -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 +47 -9
- 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 +1510 -330
- tnfr/metrics/coherence.pyi +129 -0
- tnfr/metrics/common.py +23 -16
- tnfr/metrics/common.pyi +35 -0
- tnfr/metrics/core.py +251 -36
- tnfr/metrics/core.pyi +13 -0
- tnfr/metrics/diagnosis.py +709 -110
- tnfr/metrics/diagnosis.pyi +86 -0
- tnfr/metrics/emergence.py +245 -0
- tnfr/metrics/export.py +60 -18
- tnfr/metrics/export.pyi +7 -0
- tnfr/metrics/glyph_timing.py +233 -43
- 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 +63 -28
- tnfr/metrics/reporting.pyi +25 -0
- tnfr/metrics/sense_index.py +1126 -43
- tnfr/metrics/sense_index.pyi +9 -0
- tnfr/metrics/trig.py +215 -23
- tnfr/metrics/trig.pyi +13 -0
- tnfr/metrics/trig_cache.py +148 -24
- tnfr/metrics/trig_cache.pyi +10 -0
- tnfr/multiscale/__init__.py +32 -0
- tnfr/multiscale/hierarchical.py +517 -0
- tnfr/node.py +646 -140
- tnfr/node.pyi +139 -0
- tnfr/observers.py +160 -45
- tnfr/observers.pyi +31 -0
- tnfr/ontosim.py +23 -19
- tnfr/ontosim.pyi +28 -0
- tnfr/operators/__init__.py +1358 -106
- 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 +107 -38
- 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 +1415 -91
- 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 +75 -151
- 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 +59 -22
- tnfr/selector.pyi +19 -0
- tnfr/sense.py +92 -67
- 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 +639 -263
- 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 +2 -4
- 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 +300 -126
- 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 +743 -12
- 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/{callback_utils.py → utils/callbacks.py} +26 -39
- 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/{helpers → utils}/numeric.py +51 -24
- 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-4.5.2.dist-info → tnfr-8.5.0.dist-info}/entry_points.txt +1 -0
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/licenses/LICENSE.md +1 -1
- tnfr/collections_utils.py +0 -300
- tnfr/config.py +0 -32
- tnfr/grammar.py +0 -344
- tnfr/graph_utils.py +0 -84
- tnfr/helpers/__init__.py +0 -71
- tnfr/import_utils.py +0 -228
- tnfr/json_utils.py +0 -162
- tnfr/logging_utils.py +0 -116
- tnfr/presets.py +0 -60
- tnfr/validators.py +0 -84
- tnfr/value_utils.py +0 -59
- tnfr-4.5.2.dist-info/METADATA +0 -379
- tnfr-4.5.2.dist-info/RECORD +0 -67
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/WHEEL +0 -0
- {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Literal, Sequence
|
|
4
|
+
|
|
5
|
+
from tnfr.types import GlyphCode, TNFRGraph
|
|
6
|
+
|
|
7
|
+
__all__: tuple[str, ...]
|
|
8
|
+
|
|
9
|
+
dnfr: Any
|
|
10
|
+
integrators: Any
|
|
11
|
+
metabolism: Any
|
|
12
|
+
|
|
13
|
+
ALIAS_D2EPI: Sequence[str]
|
|
14
|
+
ALIAS_DNFR: Sequence[str]
|
|
15
|
+
ALIAS_DSI: Sequence[str]
|
|
16
|
+
ALIAS_EPI: Sequence[str]
|
|
17
|
+
ALIAS_SI: Sequence[str]
|
|
18
|
+
ALIAS_VF: Sequence[str]
|
|
19
|
+
|
|
20
|
+
AbstractSelector: Any
|
|
21
|
+
DefaultGlyphSelector: Any
|
|
22
|
+
ParametricGlyphSelector: Any
|
|
23
|
+
StructuralFeedbackLoop: Any
|
|
24
|
+
AdaptiveSequenceSelector: Any
|
|
25
|
+
StructuralHomeostasis: Any
|
|
26
|
+
AdaptiveLearningSystem: Any
|
|
27
|
+
_SelectorPreselection: Any
|
|
28
|
+
_apply_glyphs: Any
|
|
29
|
+
_apply_selector: Any
|
|
30
|
+
_choose_glyph: Any
|
|
31
|
+
_configure_selector_weights: Any
|
|
32
|
+
ProcessPoolExecutor: Any
|
|
33
|
+
_maybe_remesh: Any
|
|
34
|
+
_normalize_job_overrides: Any
|
|
35
|
+
_prepare_dnfr: Any
|
|
36
|
+
_prepare_dnfr_data: Any
|
|
37
|
+
_prepare_selector_preselection: Any
|
|
38
|
+
_resolve_jobs_override: Any
|
|
39
|
+
_resolve_preselected_glyph: Any
|
|
40
|
+
_run_after_callbacks: Any
|
|
41
|
+
_run_before_callbacks: Any
|
|
42
|
+
_run_validators: Any
|
|
43
|
+
_selector_parallel_jobs: Any
|
|
44
|
+
_update_epi_hist: Any
|
|
45
|
+
_update_node_sample: Any
|
|
46
|
+
_update_nodes: Any
|
|
47
|
+
_compute_dnfr: Any
|
|
48
|
+
_compute_neighbor_means: Any
|
|
49
|
+
_init_dnfr_cache: Any
|
|
50
|
+
_refresh_dnfr_vectors: Any
|
|
51
|
+
adapt_vf_by_coherence: Any
|
|
52
|
+
coordinate_global_local_phase: Any
|
|
53
|
+
default_compute_delta_nfr: Any
|
|
54
|
+
default_glyph_selector: Any
|
|
55
|
+
dnfr_epi_vf_mixed: Any
|
|
56
|
+
dnfr_laplacian: Any
|
|
57
|
+
dnfr_phase_only: Any
|
|
58
|
+
get_numpy: Any
|
|
59
|
+
apply_glyph: Any
|
|
60
|
+
parametric_glyph_selector: Any
|
|
61
|
+
|
|
62
|
+
AbstractIntegrator: Any
|
|
63
|
+
DefaultIntegrator: Any
|
|
64
|
+
|
|
65
|
+
def prepare_integration_params(
|
|
66
|
+
G: TNFRGraph,
|
|
67
|
+
dt: float | None = ...,
|
|
68
|
+
t: float | None = ...,
|
|
69
|
+
method: Literal["euler", "rk4"] | None = ...,
|
|
70
|
+
) -> tuple[float, int, float, Literal["euler", "rk4"]]: ...
|
|
71
|
+
|
|
72
|
+
run: Any
|
|
73
|
+
set_delta_nfr_hook: Any
|
|
74
|
+
step: Any
|
|
75
|
+
|
|
76
|
+
def update_epi_via_nodal_equation(
|
|
77
|
+
G: TNFRGraph,
|
|
78
|
+
*,
|
|
79
|
+
dt: float | None = ...,
|
|
80
|
+
t: float | None = ...,
|
|
81
|
+
method: Literal["euler", "rk4"] | None = ...,
|
|
82
|
+
n_jobs: int | None = ...,
|
|
83
|
+
) -> None: ...
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"""νf adaptation routines for TNFR dynamics."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from concurrent.futures import ProcessPoolExecutor
|
|
7
|
+
from typing import Any, cast
|
|
8
|
+
|
|
9
|
+
from ..alias import collect_attr, set_vf
|
|
10
|
+
from ..constants import get_graph_param
|
|
11
|
+
from ..utils import clamp, resolve_chunk_size
|
|
12
|
+
from ..metrics.common import ensure_neighbors_map
|
|
13
|
+
from ..types import CoherenceMetric, DeltaNFR, TNFRGraph
|
|
14
|
+
from ..utils import get_numpy
|
|
15
|
+
from .aliases import ALIAS_DNFR, ALIAS_SI, ALIAS_VF
|
|
16
|
+
|
|
17
|
+
__all__ = ("adapt_vf_by_coherence",)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _vf_adapt_chunk(
|
|
21
|
+
args: tuple[list[tuple[Any, int, tuple[int, ...]]], tuple[float, ...], float],
|
|
22
|
+
) -> list[tuple[Any, float]]:
|
|
23
|
+
"""Return proposed νf updates for ``chunk`` of stable nodes."""
|
|
24
|
+
|
|
25
|
+
chunk, vf_values, mu = args
|
|
26
|
+
updates: list[tuple[Any, float]] = []
|
|
27
|
+
for node, idx, neighbor_idx in chunk:
|
|
28
|
+
vf = vf_values[idx]
|
|
29
|
+
if neighbor_idx:
|
|
30
|
+
mean = math.fsum(vf_values[j] for j in neighbor_idx) / len(neighbor_idx)
|
|
31
|
+
else:
|
|
32
|
+
mean = vf
|
|
33
|
+
updates.append((node, vf + mu * (mean - vf)))
|
|
34
|
+
return updates
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def adapt_vf_by_coherence(G: TNFRGraph, n_jobs: int | None = None) -> None:
|
|
38
|
+
"""Synchronise νf to the neighbour mean once ΔNFR and Si stay coherent.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
G : TNFRGraph
|
|
43
|
+
Graph that stores the TNFR nodes and configuration required for
|
|
44
|
+
adaptation. The routine reads ``VF_ADAPT_TAU`` (τ) to decide how many
|
|
45
|
+
consecutive stable steps a node must accumulate in ``stable_count``
|
|
46
|
+
before updating. The adaptation weight ``VF_ADAPT_MU`` (μ) controls how
|
|
47
|
+
quickly νf moves toward the neighbour mean. Stability is detected when
|
|
48
|
+
the absolute ΔNFR stays below ``EPS_DNFR_STABLE`` and the sense index Si
|
|
49
|
+
exceeds the selector threshold ``SELECTOR_THRESHOLDS['si_hi']`` (falling
|
|
50
|
+
back to ``GLYPH_THRESHOLDS['hi']``). Only nodes that satisfy both
|
|
51
|
+
thresholds for τ successive evaluations are eligible for μ-weighted
|
|
52
|
+
averaging.
|
|
53
|
+
n_jobs : int or None, optional
|
|
54
|
+
Number of worker processes used for eligible nodes. ``None`` (the
|
|
55
|
+
default) keeps the adaptation serial, ``1`` disables parallelism, and
|
|
56
|
+
any value greater than one dispatches chunks of nodes to a
|
|
57
|
+
:class:`~concurrent.futures.ProcessPoolExecutor` so large graphs can
|
|
58
|
+
adjust νf without blocking the main dynamic loop.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
None
|
|
63
|
+
The graph is updated in place; no value is returned.
|
|
64
|
+
|
|
65
|
+
Raises
|
|
66
|
+
------
|
|
67
|
+
KeyError
|
|
68
|
+
Raised when ``G.graph`` lacks the canonical adaptation parameters and
|
|
69
|
+
defaults have not been injected.
|
|
70
|
+
|
|
71
|
+
Examples
|
|
72
|
+
--------
|
|
73
|
+
>>> from tnfr.constants import inject_defaults
|
|
74
|
+
>>> from tnfr.dynamics import adapt_vf_by_coherence
|
|
75
|
+
>>> from tnfr.structural import create_nfr
|
|
76
|
+
>>> G, seed = create_nfr("seed", vf=0.2)
|
|
77
|
+
>>> _, anchor = create_nfr("anchor", graph=G, vf=1.0)
|
|
78
|
+
>>> G.add_edge(seed, anchor)
|
|
79
|
+
>>> inject_defaults(G)
|
|
80
|
+
>>> G.graph["VF_ADAPT_TAU"] = 2 # τ: consecutive stable steps
|
|
81
|
+
>>> G.graph["VF_ADAPT_MU"] = 0.5 # μ: neighbour coupling strength
|
|
82
|
+
>>> G.graph["SELECTOR_THRESHOLDS"] = {"si_hi": 0.8}
|
|
83
|
+
>>> for node in G.nodes:
|
|
84
|
+
... G.nodes[node]["Si"] = 0.9 # above ΔSi threshold
|
|
85
|
+
... G.nodes[node]["ΔNFR"] = 0.0 # within |ΔNFR| ≤ eps guard
|
|
86
|
+
... G.nodes[node]["stable_count"] = 1
|
|
87
|
+
>>> adapt_vf_by_coherence(G)
|
|
88
|
+
>>> round(G.nodes[seed]["νf"], 2), round(G.nodes[anchor]["νf"], 2)
|
|
89
|
+
(0.6, 0.6)
|
|
90
|
+
>>> G.nodes[seed]["stable_count"], G.nodes[anchor]["stable_count"] >= 2
|
|
91
|
+
(2, True)
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
required_keys = ("VF_ADAPT_TAU", "VF_ADAPT_MU")
|
|
95
|
+
missing_keys = [key for key in required_keys if key not in G.graph]
|
|
96
|
+
if missing_keys:
|
|
97
|
+
missing_list = ", ".join(sorted(missing_keys))
|
|
98
|
+
raise KeyError(
|
|
99
|
+
"adapt_vf_by_coherence requires graph parameters "
|
|
100
|
+
f"{missing_list}; call tnfr.constants.inject_defaults(G) "
|
|
101
|
+
"before adaptation."
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
tau = get_graph_param(G, "VF_ADAPT_TAU", int)
|
|
105
|
+
mu = float(get_graph_param(G, "VF_ADAPT_MU"))
|
|
106
|
+
eps_dnfr = cast(DeltaNFR, get_graph_param(G, "EPS_DNFR_STABLE"))
|
|
107
|
+
thr_sel = get_graph_param(G, "SELECTOR_THRESHOLDS", dict)
|
|
108
|
+
thr_def = get_graph_param(G, "GLYPH_THRESHOLDS", dict)
|
|
109
|
+
si_hi = cast(
|
|
110
|
+
CoherenceMetric,
|
|
111
|
+
float(thr_sel.get("si_hi", thr_def.get("hi", 0.66))),
|
|
112
|
+
)
|
|
113
|
+
vf_min = float(get_graph_param(G, "VF_MIN"))
|
|
114
|
+
vf_max = float(get_graph_param(G, "VF_MAX"))
|
|
115
|
+
|
|
116
|
+
nodes = list(G.nodes)
|
|
117
|
+
if not nodes:
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
neighbors_map = ensure_neighbors_map(G)
|
|
121
|
+
node_count = len(nodes)
|
|
122
|
+
node_index = {node: idx for idx, node in enumerate(nodes)}
|
|
123
|
+
|
|
124
|
+
jobs: int | None
|
|
125
|
+
if n_jobs is None:
|
|
126
|
+
jobs = None
|
|
127
|
+
else:
|
|
128
|
+
try:
|
|
129
|
+
jobs = int(n_jobs)
|
|
130
|
+
except (TypeError, ValueError):
|
|
131
|
+
jobs = None
|
|
132
|
+
else:
|
|
133
|
+
if jobs <= 1:
|
|
134
|
+
jobs = None
|
|
135
|
+
|
|
136
|
+
np_mod = get_numpy()
|
|
137
|
+
use_np = np_mod is not None
|
|
138
|
+
|
|
139
|
+
si_values = collect_attr(G, nodes, ALIAS_SI, 0.0, np=np_mod if use_np else None)
|
|
140
|
+
dnfr_values = collect_attr(G, nodes, ALIAS_DNFR, 0.0, np=np_mod if use_np else None)
|
|
141
|
+
vf_values = collect_attr(G, nodes, ALIAS_VF, 0.0, np=np_mod if use_np else None)
|
|
142
|
+
|
|
143
|
+
if use_np:
|
|
144
|
+
np = np_mod # type: ignore[assignment]
|
|
145
|
+
assert np is not None
|
|
146
|
+
si_arr = si_values.astype(float, copy=False)
|
|
147
|
+
dnfr_arr = np.abs(dnfr_values.astype(float, copy=False))
|
|
148
|
+
vf_arr = vf_values.astype(float, copy=False)
|
|
149
|
+
|
|
150
|
+
prev_counts = np.fromiter(
|
|
151
|
+
(int(G.nodes[node].get("stable_count", 0)) for node in nodes),
|
|
152
|
+
dtype=int,
|
|
153
|
+
count=node_count,
|
|
154
|
+
)
|
|
155
|
+
stable_mask = (si_arr >= si_hi) & (dnfr_arr <= eps_dnfr)
|
|
156
|
+
new_counts = np.where(stable_mask, prev_counts + 1, 0)
|
|
157
|
+
|
|
158
|
+
for node, count in zip(nodes, new_counts.tolist()):
|
|
159
|
+
G.nodes[node]["stable_count"] = int(count)
|
|
160
|
+
|
|
161
|
+
eligible_mask = new_counts >= tau
|
|
162
|
+
if not bool(eligible_mask.any()):
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
max_degree = 0
|
|
166
|
+
if node_count:
|
|
167
|
+
degree_counts = np.fromiter(
|
|
168
|
+
(len(neighbors_map.get(node, ())) for node in nodes),
|
|
169
|
+
dtype=int,
|
|
170
|
+
count=node_count,
|
|
171
|
+
)
|
|
172
|
+
if degree_counts.size:
|
|
173
|
+
max_degree = int(degree_counts.max())
|
|
174
|
+
|
|
175
|
+
if max_degree > 0:
|
|
176
|
+
neighbor_indices = np.zeros((node_count, max_degree), dtype=int)
|
|
177
|
+
mask = np.zeros((node_count, max_degree), dtype=bool)
|
|
178
|
+
for idx, node in enumerate(nodes):
|
|
179
|
+
neigh = neighbors_map.get(node, ())
|
|
180
|
+
if not neigh:
|
|
181
|
+
continue
|
|
182
|
+
idxs = [node_index[nbr] for nbr in neigh if nbr in node_index]
|
|
183
|
+
if not idxs:
|
|
184
|
+
continue
|
|
185
|
+
length = len(idxs)
|
|
186
|
+
neighbor_indices[idx, :length] = idxs
|
|
187
|
+
mask[idx, :length] = True
|
|
188
|
+
neighbor_values = vf_arr[neighbor_indices]
|
|
189
|
+
sums = (neighbor_values * mask).sum(axis=1)
|
|
190
|
+
counts = mask.sum(axis=1)
|
|
191
|
+
neighbor_means = np.where(counts > 0, sums / counts, vf_arr)
|
|
192
|
+
else:
|
|
193
|
+
neighbor_means = vf_arr
|
|
194
|
+
|
|
195
|
+
vf_updates = vf_arr + mu * (neighbor_means - vf_arr)
|
|
196
|
+
for idx in np.nonzero(eligible_mask)[0]:
|
|
197
|
+
node = nodes[int(idx)]
|
|
198
|
+
vf_new = clamp(float(vf_updates[int(idx)]), vf_min, vf_max)
|
|
199
|
+
set_vf(G, node, vf_new)
|
|
200
|
+
return
|
|
201
|
+
|
|
202
|
+
si_list = [float(val) for val in si_values]
|
|
203
|
+
dnfr_list = [abs(float(val)) for val in dnfr_values]
|
|
204
|
+
vf_list = [float(val) for val in vf_values]
|
|
205
|
+
|
|
206
|
+
prev_counts = [int(G.nodes[node].get("stable_count", 0)) for node in nodes]
|
|
207
|
+
stable_flags = [
|
|
208
|
+
si >= si_hi and dnfr <= eps_dnfr for si, dnfr in zip(si_list, dnfr_list)
|
|
209
|
+
]
|
|
210
|
+
new_counts = [
|
|
211
|
+
prev + 1 if flag else 0 for prev, flag in zip(prev_counts, stable_flags)
|
|
212
|
+
]
|
|
213
|
+
|
|
214
|
+
for node, count in zip(nodes, new_counts):
|
|
215
|
+
G.nodes[node]["stable_count"] = int(count)
|
|
216
|
+
|
|
217
|
+
eligible_nodes = [node for node, count in zip(nodes, new_counts) if count >= tau]
|
|
218
|
+
if not eligible_nodes:
|
|
219
|
+
return
|
|
220
|
+
|
|
221
|
+
if jobs is None:
|
|
222
|
+
for node in eligible_nodes:
|
|
223
|
+
idx = node_index[node]
|
|
224
|
+
neigh_indices = [
|
|
225
|
+
node_index[nbr]
|
|
226
|
+
for nbr in neighbors_map.get(node, ())
|
|
227
|
+
if nbr in node_index
|
|
228
|
+
]
|
|
229
|
+
if neigh_indices:
|
|
230
|
+
total = math.fsum(vf_list[i] for i in neigh_indices)
|
|
231
|
+
mean = total / len(neigh_indices)
|
|
232
|
+
else:
|
|
233
|
+
mean = vf_list[idx]
|
|
234
|
+
vf_new = vf_list[idx] + mu * (mean - vf_list[idx])
|
|
235
|
+
set_vf(G, node, clamp(float(vf_new), vf_min, vf_max))
|
|
236
|
+
return
|
|
237
|
+
|
|
238
|
+
work_items: list[tuple[Any, int, tuple[int, ...]]] = []
|
|
239
|
+
for node in eligible_nodes:
|
|
240
|
+
idx = node_index[node]
|
|
241
|
+
neigh_indices = tuple(
|
|
242
|
+
node_index[nbr] for nbr in neighbors_map.get(node, ()) if nbr in node_index
|
|
243
|
+
)
|
|
244
|
+
work_items.append((node, idx, neigh_indices))
|
|
245
|
+
|
|
246
|
+
approx_chunk = math.ceil(len(work_items) / jobs) if jobs else None
|
|
247
|
+
chunk_size = resolve_chunk_size(
|
|
248
|
+
approx_chunk,
|
|
249
|
+
len(work_items),
|
|
250
|
+
minimum=1,
|
|
251
|
+
)
|
|
252
|
+
chunks = [
|
|
253
|
+
work_items[i : i + chunk_size] for i in range(0, len(work_items), chunk_size)
|
|
254
|
+
]
|
|
255
|
+
vf_tuple = tuple(vf_list)
|
|
256
|
+
updates: dict[Any, float] = {}
|
|
257
|
+
with ProcessPoolExecutor(max_workers=jobs) as executor:
|
|
258
|
+
args = ((chunk, vf_tuple, mu) for chunk in chunks)
|
|
259
|
+
for chunk_updates in executor.map(_vf_adapt_chunk, args):
|
|
260
|
+
for node, value in chunk_updates:
|
|
261
|
+
updates[node] = float(value)
|
|
262
|
+
|
|
263
|
+
for node in eligible_nodes:
|
|
264
|
+
vf_new = updates.get(node)
|
|
265
|
+
if vf_new is None:
|
|
266
|
+
continue
|
|
267
|
+
set_vf(G, node, clamp(float(vf_new), vf_min, vf_max))
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""Adaptive sequence selection for TNFR operator trajectories.
|
|
2
|
+
|
|
3
|
+
This module implements learning-based selection of operator sequences.
|
|
4
|
+
Rather than executing fixed sequences, the system learns which sequences
|
|
5
|
+
work best for given contexts and adapts its selection over time.
|
|
6
|
+
|
|
7
|
+
The approach combines predefined canonical sequences with epsilon-greedy
|
|
8
|
+
exploration to balance exploitation (use known good sequences) with
|
|
9
|
+
exploration (try new patterns).
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import random
|
|
15
|
+
from typing import TYPE_CHECKING, Any, Dict, List
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from ..types import TNFRGraph, NodeId
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
import numpy as np
|
|
22
|
+
except ImportError:
|
|
23
|
+
np = None # type: ignore[assignment]
|
|
24
|
+
|
|
25
|
+
from ..config.operator_names import (
|
|
26
|
+
COHERENCE,
|
|
27
|
+
DISSONANCE,
|
|
28
|
+
EMISSION,
|
|
29
|
+
MUTATION,
|
|
30
|
+
RECEPTION,
|
|
31
|
+
RECURSIVITY,
|
|
32
|
+
RESONANCE,
|
|
33
|
+
SELF_ORGANIZATION,
|
|
34
|
+
SILENCE,
|
|
35
|
+
TRANSITION,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
__all__ = ["AdaptiveSequenceSelector"]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class AdaptiveSequenceSelector:
|
|
42
|
+
"""Learns and selects optimal operator sequences based on context.
|
|
43
|
+
|
|
44
|
+
This class maintains a pool of canonical operator sequences and tracks
|
|
45
|
+
their performance over time. It uses epsilon-greedy selection to balance
|
|
46
|
+
exploitation of known-good sequences with exploration of alternatives.
|
|
47
|
+
|
|
48
|
+
**Selection Strategy:**
|
|
49
|
+
|
|
50
|
+
- **Exploitation (80%)**: Choose sequence with best historical performance
|
|
51
|
+
- **Exploration (20%)**: Random selection to discover new patterns
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
graph : TNFRGraph
|
|
56
|
+
Graph containing the node
|
|
57
|
+
node : NodeId
|
|
58
|
+
Identifier of the node
|
|
59
|
+
|
|
60
|
+
Attributes
|
|
61
|
+
----------
|
|
62
|
+
G : TNFRGraph
|
|
63
|
+
Graph reference
|
|
64
|
+
node : NodeId
|
|
65
|
+
Node identifier
|
|
66
|
+
sequences : dict[str, list[str]]
|
|
67
|
+
Pool of canonical operator sequences
|
|
68
|
+
performance : dict[str, list[float]]
|
|
69
|
+
Historical performance for each sequence
|
|
70
|
+
|
|
71
|
+
Examples
|
|
72
|
+
--------
|
|
73
|
+
>>> from tnfr.structural import create_nfr
|
|
74
|
+
>>> from tnfr.dynamics.adaptive_sequences import AdaptiveSequenceSelector
|
|
75
|
+
>>> G, node = create_nfr("test_node")
|
|
76
|
+
>>> selector = AdaptiveSequenceSelector(G, node)
|
|
77
|
+
>>> context = {"goal": "stability", "urgency": 0.5}
|
|
78
|
+
>>> sequence = selector.select_sequence(context)
|
|
79
|
+
>>> selector.record_performance("basic_activation", 0.85)
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
def __init__(self, graph: TNFRGraph, node: NodeId) -> None:
|
|
83
|
+
self.G = graph
|
|
84
|
+
self.node = node
|
|
85
|
+
|
|
86
|
+
# Canonical operator sequences
|
|
87
|
+
# Note: Sequences are designed to comply with TNFR grammar rules
|
|
88
|
+
self.sequences: Dict[str, List[str]] = {
|
|
89
|
+
"basic_activation": [EMISSION, COHERENCE],
|
|
90
|
+
"deep_learning": [EMISSION, RECEPTION, COHERENCE],
|
|
91
|
+
"exploration": [EMISSION, DISSONANCE, COHERENCE],
|
|
92
|
+
"consolidation": [COHERENCE, SILENCE, RECURSIVITY],
|
|
93
|
+
"mutation": [COHERENCE, MUTATION, TRANSITION, COHERENCE],
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# Performance history: sequence_name -> [coherence_gains]
|
|
97
|
+
self.performance: Dict[str, List[float]] = {
|
|
98
|
+
k: [] for k in self.sequences.keys()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
def select_sequence(self, context: Dict[str, Any]) -> List[str]:
|
|
102
|
+
"""Select optimal sequence based on context and historical performance.
|
|
103
|
+
|
|
104
|
+
Uses goal-based filtering and epsilon-greedy selection:
|
|
105
|
+
|
|
106
|
+
1. Filter sequences appropriate for goal
|
|
107
|
+
2. With probability 0.8: select best-performing sequence
|
|
108
|
+
3. With probability 0.2: select random sequence (exploration)
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
context : dict
|
|
113
|
+
Context with keys:
|
|
114
|
+
|
|
115
|
+
- **goal** (str): "stability", "growth", or "adaptation"
|
|
116
|
+
- **urgency** (float): Urgency level (0-1), currently unused
|
|
117
|
+
|
|
118
|
+
Returns
|
|
119
|
+
-------
|
|
120
|
+
list[str]
|
|
121
|
+
Sequence of operator names to execute
|
|
122
|
+
|
|
123
|
+
Notes
|
|
124
|
+
-----
|
|
125
|
+
Goal-to-sequence mapping follows TNFR principles:
|
|
126
|
+
|
|
127
|
+
- **stability**: Sequences emphasizing IL (Coherence) and SHA (Silence)
|
|
128
|
+
- **growth**: Sequences with AL (Emission) and THOL (Self-organization)
|
|
129
|
+
- **adaptation**: Sequences with ZHIR (Mutation) and learning cycles
|
|
130
|
+
"""
|
|
131
|
+
goal = context.get("goal", "stability")
|
|
132
|
+
|
|
133
|
+
# Map goals to appropriate sequence candidates
|
|
134
|
+
if goal == "stability":
|
|
135
|
+
candidates = ["basic_activation", "consolidation"]
|
|
136
|
+
elif goal == "growth":
|
|
137
|
+
candidates = ["deep_learning", "exploration"]
|
|
138
|
+
elif goal == "adaptation":
|
|
139
|
+
candidates = ["mutation", "deep_learning"]
|
|
140
|
+
else:
|
|
141
|
+
candidates = list(self.sequences.keys())
|
|
142
|
+
|
|
143
|
+
# Epsilon-greedy selection (20% exploration, 80% exploitation)
|
|
144
|
+
epsilon = 0.2
|
|
145
|
+
|
|
146
|
+
if np is not None:
|
|
147
|
+
random_val = np.random.random()
|
|
148
|
+
else:
|
|
149
|
+
random_val = random.random()
|
|
150
|
+
|
|
151
|
+
if random_val < epsilon:
|
|
152
|
+
# Exploration: random selection
|
|
153
|
+
if np is not None:
|
|
154
|
+
selected = str(np.random.choice(candidates))
|
|
155
|
+
else:
|
|
156
|
+
selected = random.choice(candidates)
|
|
157
|
+
else:
|
|
158
|
+
# Exploitation: select best-performing sequence
|
|
159
|
+
avg_perf = {
|
|
160
|
+
k: (
|
|
161
|
+
sum(self.performance[k]) / len(self.performance[k])
|
|
162
|
+
if self.performance[k]
|
|
163
|
+
else 0.0
|
|
164
|
+
)
|
|
165
|
+
for k in candidates
|
|
166
|
+
}
|
|
167
|
+
selected = max(avg_perf, key=avg_perf.get) # type: ignore[arg-type]
|
|
168
|
+
|
|
169
|
+
return self.sequences[selected]
|
|
170
|
+
|
|
171
|
+
def record_performance(self, sequence_name: str, coherence_gain: float) -> None:
|
|
172
|
+
"""Record performance metric for a sequence to enable learning.
|
|
173
|
+
|
|
174
|
+
Parameters
|
|
175
|
+
----------
|
|
176
|
+
sequence_name : str
|
|
177
|
+
Name of the sequence that was executed
|
|
178
|
+
coherence_gain : float
|
|
179
|
+
Achieved coherence improvement or other performance metric
|
|
180
|
+
|
|
181
|
+
Notes
|
|
182
|
+
-----
|
|
183
|
+
Maintains a sliding window of the last 20 executions to adapt to
|
|
184
|
+
changing dynamics. Older performance data is discarded.
|
|
185
|
+
"""
|
|
186
|
+
if sequence_name in self.performance:
|
|
187
|
+
self.performance[sequence_name].append(float(coherence_gain))
|
|
188
|
+
# Keep only last 20 executions (sliding window)
|
|
189
|
+
self.performance[sequence_name] = self.performance[sequence_name][-20:]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Type stubs for tnfr.dynamics.adaptive_sequences module."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List
|
|
4
|
+
from ..types import TNFRGraph, NodeId
|
|
5
|
+
|
|
6
|
+
class AdaptiveSequenceSelector:
|
|
7
|
+
G: TNFRGraph
|
|
8
|
+
node: NodeId
|
|
9
|
+
sequences: Dict[str, List[str]]
|
|
10
|
+
performance: Dict[str, List[float]]
|
|
11
|
+
|
|
12
|
+
def __init__(self, graph: TNFRGraph, node: NodeId) -> None: ...
|
|
13
|
+
def select_sequence(self, context: Dict[str, Any]) -> List[str]: ...
|
|
14
|
+
def record_performance(self, sequence_name: str, coherence_gain: float) -> None: ...
|
tnfr/dynamics/aliases.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Shared alias tokens used across TNFR dynamics submodules."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..constants.aliases import (
|
|
6
|
+
ALIAS_D2EPI,
|
|
7
|
+
ALIAS_DNFR,
|
|
8
|
+
ALIAS_DSI,
|
|
9
|
+
ALIAS_EPI,
|
|
10
|
+
ALIAS_SI,
|
|
11
|
+
ALIAS_THETA,
|
|
12
|
+
ALIAS_VF,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = (
|
|
16
|
+
"ALIAS_VF",
|
|
17
|
+
"ALIAS_DNFR",
|
|
18
|
+
"ALIAS_EPI",
|
|
19
|
+
"ALIAS_SI",
|
|
20
|
+
"ALIAS_THETA",
|
|
21
|
+
"ALIAS_D2EPI",
|
|
22
|
+
"ALIAS_DSI",
|
|
23
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from ..constants.aliases import (
|
|
2
|
+
ALIAS_D2EPI as ALIAS_D2EPI,
|
|
3
|
+
ALIAS_DNFR as ALIAS_DNFR,
|
|
4
|
+
ALIAS_DSI as ALIAS_DSI,
|
|
5
|
+
ALIAS_EPI as ALIAS_EPI,
|
|
6
|
+
ALIAS_SI as ALIAS_SI,
|
|
7
|
+
ALIAS_THETA as ALIAS_THETA,
|
|
8
|
+
ALIAS_VF as ALIAS_VF,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"ALIAS_VF",
|
|
13
|
+
"ALIAS_DNFR",
|
|
14
|
+
"ALIAS_EPI",
|
|
15
|
+
"ALIAS_SI",
|
|
16
|
+
"ALIAS_THETA",
|
|
17
|
+
"ALIAS_D2EPI",
|
|
18
|
+
"ALIAS_DSI",
|
|
19
|
+
]
|