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
tnfr/alias.py
CHANGED
|
@@ -4,39 +4,113 @@
|
|
|
4
4
|
alias-based attribute access. Legacy wrappers ``alias_get`` and
|
|
5
5
|
``alias_set`` have been removed; use :func:`get_attr` and
|
|
6
6
|
:func:`set_attr` instead.
|
|
7
|
+
|
|
8
|
+
CRITICAL: Canonical Attribute Access
|
|
9
|
+
=====================================
|
|
10
|
+
|
|
11
|
+
**ALWAYS use the alias system for reading/writing TNFR attributes.**
|
|
12
|
+
|
|
13
|
+
The TNFR canonical attribute keys use Unicode symbols (e.g., 'νf' for structural
|
|
14
|
+
frequency), but NetworkX and Python code often use ASCII equivalents (e.g., 'vf').
|
|
15
|
+
This creates a critical inconsistency:
|
|
16
|
+
|
|
17
|
+
**WRONG (breaks canonicity)**:
|
|
18
|
+
>>> G.add_node(0, vf=1.0) # Uses ASCII 'vf' key
|
|
19
|
+
>>> value = G.nodes[0]['vf'] # Reads ASCII 'vf' - may not exist!
|
|
20
|
+
>>> G.nodes[0]['vf'] = 2.0 # Writes ASCII 'vf' - wrong key!
|
|
21
|
+
|
|
22
|
+
**CORRECT (maintains canonicity)**:
|
|
23
|
+
>>> from tnfr.alias import set_vf, get_attr
|
|
24
|
+
>>> from tnfr.constants.aliases import ALIAS_VF
|
|
25
|
+
>>> from tnfr.constants import VF_PRIMARY
|
|
26
|
+
>>>
|
|
27
|
+
>>> # For initialization, use canonical setters:
|
|
28
|
+
>>> set_vf(G, 0, 1.0) # Writes to 'νf' (Greek nu)
|
|
29
|
+
>>>
|
|
30
|
+
>>> # For reading, use canonical getters:
|
|
31
|
+
>>> value = get_attr(G.nodes[0], ALIAS_VF, 0.0) # Reads from 'νf'
|
|
32
|
+
>>>
|
|
33
|
+
>>> # Or use PRIMARY constants in add_node:
|
|
34
|
+
>>> G.add_node(1, **{VF_PRIMARY: 1.0}) # Writes to 'νf' directly
|
|
35
|
+
|
|
36
|
+
**Why This Matters**:
|
|
37
|
+
- The alias system tries ALL aliases in order: ('νf', 'nu_f', 'nu-f', 'nu', 'freq', 'frequency')
|
|
38
|
+
- If you write to 'vf', the data is stored under a key NOT in the alias list
|
|
39
|
+
- Reading via get_attr() will return the default (0.0) instead of your value
|
|
40
|
+
- This breaks the nodal equation: ∂EPI/∂t = νf · ΔNFR(t)
|
|
41
|
+
|
|
42
|
+
**For Tests**:
|
|
43
|
+
>>> from tnfr.structural import create_nfr
|
|
44
|
+
>>> # PREFERRED: Use create_nfr which handles canonicity
|
|
45
|
+
>>> G, node = create_nfr("test", vf=1.0, epi=0.5, theta=0.0)
|
|
46
|
+
>>>
|
|
47
|
+
>>> # ALTERNATIVE: Manual initialization with canonical setters
|
|
48
|
+
>>> from tnfr.alias import set_vf, get_attr
|
|
49
|
+
>>> from tnfr.constants.aliases import ALIAS_VF
|
|
50
|
+
>>> G = nx.Graph()
|
|
51
|
+
>>> G.add_node(0, theta=0.0, EPI=1.0, Si=0.5) # Other attrs OK
|
|
52
|
+
>>> set_vf(G, 0, 1.0) # Use canonical setter for vf
|
|
53
|
+
>>> value = get_attr(G.nodes[0], ALIAS_VF, 0.0) # Use canonical getter
|
|
54
|
+
|
|
55
|
+
**Applies to**: νf (vf), θ (theta), ΔNFR (dnfr), and other aliased attributes.
|
|
56
|
+
See ALIAS_VF, ALIAS_THETA, ALIAS_DNFR in tnfr.constants.aliases for full lists.
|
|
7
57
|
"""
|
|
8
58
|
|
|
9
59
|
from __future__ import annotations
|
|
60
|
+
|
|
10
61
|
from collections import defaultdict
|
|
11
|
-
from collections.abc import Iterable, Sized
|
|
12
|
-
from
|
|
62
|
+
from collections.abc import Iterable, Mapping, MutableMapping, Sized
|
|
63
|
+
from functools import lru_cache, partial
|
|
64
|
+
from threading import Lock
|
|
65
|
+
from types import ModuleType
|
|
13
66
|
from typing import (
|
|
67
|
+
TYPE_CHECKING,
|
|
14
68
|
Any,
|
|
15
69
|
Callable,
|
|
16
|
-
TypeVar,
|
|
17
|
-
Optional,
|
|
18
70
|
Generic,
|
|
19
71
|
Hashable,
|
|
20
|
-
|
|
72
|
+
Optional,
|
|
73
|
+
TypeVar,
|
|
21
74
|
cast,
|
|
22
75
|
)
|
|
23
76
|
|
|
24
|
-
from
|
|
25
|
-
from
|
|
26
|
-
|
|
27
|
-
from .
|
|
28
|
-
from .value_utils import convert_value
|
|
29
|
-
|
|
30
|
-
ALIAS_VF = get_aliases("VF")
|
|
31
|
-
ALIAS_DNFR = get_aliases("DNFR")
|
|
32
|
-
ALIAS_THETA = get_aliases("THETA")
|
|
77
|
+
from .compat.dataclass import dataclass
|
|
78
|
+
from .constants.aliases import ALIAS_DNFR, ALIAS_THETA, ALIAS_VF
|
|
79
|
+
from .types import FloatArray, NodeId
|
|
80
|
+
from .utils import convert_value
|
|
33
81
|
|
|
34
82
|
if TYPE_CHECKING: # pragma: no cover
|
|
35
|
-
import networkx
|
|
83
|
+
import networkx
|
|
36
84
|
|
|
37
85
|
T = TypeVar("T")
|
|
38
86
|
|
|
39
87
|
|
|
88
|
+
def _bepi_to_float(value: Any) -> float:
|
|
89
|
+
"""Extract scalar from BEPIElement dict or convert value to float.
|
|
90
|
+
|
|
91
|
+
When operators transform EPI from float to BEPIElement dict, this helper
|
|
92
|
+
extracts the maximum magnitude from the 'continuous' component. This
|
|
93
|
+
preserves ΔNFR semantics (§3.3) and structural metrics accuracy (§3.9).
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
value : Any
|
|
98
|
+
Value to convert. If it's a dict with a 'continuous' key, extracts
|
|
99
|
+
the maximum magnitude. Otherwise converts directly to float.
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
float
|
|
104
|
+
Scalar representation of the value.
|
|
105
|
+
"""
|
|
106
|
+
if isinstance(value, dict) and "continuous" in value:
|
|
107
|
+
cont = value["continuous"]
|
|
108
|
+
if isinstance(cont, tuple):
|
|
109
|
+
return float(max(abs(c) for c in cont)) if cont else 0.0
|
|
110
|
+
return float(abs(cont))
|
|
111
|
+
return float(value)
|
|
112
|
+
|
|
113
|
+
|
|
40
114
|
@lru_cache(maxsize=128)
|
|
41
115
|
def _alias_cache(alias_tuple: tuple[str, ...]) -> tuple[str, ...]:
|
|
42
116
|
"""Validate and cache alias tuples.
|
|
@@ -132,6 +206,8 @@ class AliasAccessor(Generic[T]):
|
|
|
132
206
|
log_level: int | None = None,
|
|
133
207
|
conv: Callable[[Any], T] | None = None,
|
|
134
208
|
) -> Optional[T]:
|
|
209
|
+
"""Return ``value`` for the first alias present in ``d``."""
|
|
210
|
+
|
|
135
211
|
aliases, conv, default = self._prepare(aliases, conv, default)
|
|
136
212
|
cache_key, key = self._resolve_cache_key(d, aliases)
|
|
137
213
|
if key is not None:
|
|
@@ -168,6 +244,8 @@ class AliasAccessor(Generic[T]):
|
|
|
168
244
|
value: Any,
|
|
169
245
|
conv: Callable[[Any], T] | None = None,
|
|
170
246
|
) -> T:
|
|
247
|
+
"""Write ``value`` under the first matching alias and cache the choice."""
|
|
248
|
+
|
|
171
249
|
aliases, conv, _ = self._prepare(aliases, conv)
|
|
172
250
|
cache_key, key = self._resolve_cache_key(d, aliases)
|
|
173
251
|
if key is not None:
|
|
@@ -184,6 +262,25 @@ class AliasAccessor(Generic[T]):
|
|
|
184
262
|
_generic_accessor: AliasAccessor[Any] = AliasAccessor()
|
|
185
263
|
|
|
186
264
|
|
|
265
|
+
def get_theta_attr(
|
|
266
|
+
d: Mapping[str, Any],
|
|
267
|
+
default: T | None = None,
|
|
268
|
+
*,
|
|
269
|
+
strict: bool = False,
|
|
270
|
+
log_level: int | None = None,
|
|
271
|
+
conv: Callable[[Any], T] = float,
|
|
272
|
+
) -> T | None:
|
|
273
|
+
"""Return ``theta``/``phase`` using the English alias set."""
|
|
274
|
+
return _generic_accessor.get(
|
|
275
|
+
cast(dict[str, Any], d),
|
|
276
|
+
ALIAS_THETA,
|
|
277
|
+
default,
|
|
278
|
+
strict=strict,
|
|
279
|
+
log_level=log_level,
|
|
280
|
+
conv=conv,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
|
|
187
284
|
def get_attr(
|
|
188
285
|
d: dict[str, Any],
|
|
189
286
|
aliases: Iterable[str],
|
|
@@ -191,9 +288,17 @@ def get_attr(
|
|
|
191
288
|
*,
|
|
192
289
|
strict: bool = False,
|
|
193
290
|
log_level: int | None = None,
|
|
194
|
-
conv: Callable[[Any], T] =
|
|
291
|
+
conv: Callable[[Any], T] = _bepi_to_float,
|
|
195
292
|
) -> T | None:
|
|
196
|
-
"""Return the value for the first key in ``aliases`` found in ``d``.
|
|
293
|
+
"""Return the value for the first key in ``aliases`` found in ``d``.
|
|
294
|
+
|
|
295
|
+
WARNING: This function searches for keys in alias order. If you manually
|
|
296
|
+
wrote to a non-canonical key (e.g., 'vf' instead of 'νf'), this function
|
|
297
|
+
will NOT find it and will return the default value instead.
|
|
298
|
+
|
|
299
|
+
For structural frequency: ALWAYS use set_vf() to write, not d['vf'] = value.
|
|
300
|
+
See module docstring for detailed guidance on canonical attribute access.
|
|
301
|
+
"""
|
|
197
302
|
|
|
198
303
|
return _generic_accessor.get(
|
|
199
304
|
d,
|
|
@@ -207,12 +312,12 @@ def get_attr(
|
|
|
207
312
|
|
|
208
313
|
def collect_attr(
|
|
209
314
|
G: "networkx.Graph",
|
|
210
|
-
nodes: Iterable[
|
|
315
|
+
nodes: Iterable[NodeId],
|
|
211
316
|
aliases: Iterable[str],
|
|
212
317
|
default: float = 0.0,
|
|
213
318
|
*,
|
|
214
|
-
np=None,
|
|
215
|
-
):
|
|
319
|
+
np: ModuleType | None = None,
|
|
320
|
+
) -> FloatArray | list[float]:
|
|
216
321
|
"""Collect attribute values for ``nodes`` from ``G`` using ``aliases``.
|
|
217
322
|
|
|
218
323
|
Parameters
|
|
@@ -235,7 +340,7 @@ def collect_attr(
|
|
|
235
340
|
Collected attribute values in the same order as ``nodes``.
|
|
236
341
|
"""
|
|
237
342
|
|
|
238
|
-
def _nodes_iter_and_size(nodes: Iterable[
|
|
343
|
+
def _nodes_iter_and_size(nodes: Iterable[NodeId]) -> tuple[Iterable[NodeId], int]:
|
|
239
344
|
if nodes is G.nodes:
|
|
240
345
|
return G.nodes, G.number_of_nodes()
|
|
241
346
|
if isinstance(nodes, Sized):
|
|
@@ -245,13 +350,46 @@ def collect_attr(
|
|
|
245
350
|
|
|
246
351
|
nodes_iter, size = _nodes_iter_and_size(nodes)
|
|
247
352
|
|
|
353
|
+
def _value(node: NodeId) -> float:
|
|
354
|
+
return float(get_attr(G.nodes[node], aliases, default))
|
|
355
|
+
|
|
248
356
|
if np is not None:
|
|
249
|
-
|
|
250
|
-
(
|
|
251
|
-
float,
|
|
252
|
-
count=size,
|
|
357
|
+
values: FloatArray = np.fromiter(
|
|
358
|
+
(_value(n) for n in nodes_iter), float, count=size
|
|
253
359
|
)
|
|
254
|
-
|
|
360
|
+
return values
|
|
361
|
+
return [_value(n) for n in nodes_iter]
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def collect_theta_attr(
|
|
365
|
+
G: "networkx.Graph",
|
|
366
|
+
nodes: Iterable[NodeId],
|
|
367
|
+
default: float = 0.0,
|
|
368
|
+
*,
|
|
369
|
+
np: ModuleType | None = None,
|
|
370
|
+
) -> FloatArray | list[float]:
|
|
371
|
+
"""Collect ``theta`` values honouring the English-only attribute contract."""
|
|
372
|
+
|
|
373
|
+
def _nodes_iter_and_size(nodes: Iterable[NodeId]) -> tuple[Iterable[NodeId], int]:
|
|
374
|
+
if nodes is G.nodes:
|
|
375
|
+
return G.nodes, G.number_of_nodes()
|
|
376
|
+
if isinstance(nodes, Sized):
|
|
377
|
+
return nodes, len(nodes) # type: ignore[arg-type]
|
|
378
|
+
nodes_list = list(nodes)
|
|
379
|
+
return nodes_list, len(nodes_list)
|
|
380
|
+
|
|
381
|
+
nodes_iter, size = _nodes_iter_and_size(nodes)
|
|
382
|
+
|
|
383
|
+
def _value(node: NodeId) -> float:
|
|
384
|
+
return float(get_theta_attr(G.nodes[node], default))
|
|
385
|
+
|
|
386
|
+
if np is not None:
|
|
387
|
+
values: FloatArray = np.fromiter(
|
|
388
|
+
(_value(n) for n in nodes_iter), float, count=size
|
|
389
|
+
)
|
|
390
|
+
return values
|
|
391
|
+
|
|
392
|
+
return [_value(n) for n in nodes_iter]
|
|
255
393
|
|
|
256
394
|
|
|
257
395
|
def set_attr_generic(
|
|
@@ -261,20 +399,37 @@ def set_attr_generic(
|
|
|
261
399
|
*,
|
|
262
400
|
conv: Callable[[Any], T],
|
|
263
401
|
) -> T:
|
|
264
|
-
"""Assign ``value`` to the
|
|
402
|
+
"""Assign ``value`` to the FIRST (canonical) alias key in ``aliases``.
|
|
403
|
+
|
|
404
|
+
CRITICAL: This function writes to the FIRST key in the alias tuple.
|
|
405
|
+
For ALIAS_VF = ('νf', 'nu_f', ...), this writes to 'νf' (Greek nu), NOT 'vf'.
|
|
406
|
+
|
|
407
|
+
If you later try to read with G.nodes[n]['vf'], you will NOT find the value.
|
|
408
|
+
ALWAYS use get_attr() to read what set_attr() wrote.
|
|
409
|
+
|
|
410
|
+
For high-level usage, prefer set_vf(), set_theta(), etc. which handle this correctly.
|
|
411
|
+
See module docstring for detailed guidance on canonical attribute access.
|
|
412
|
+
"""
|
|
265
413
|
|
|
266
414
|
return _generic_accessor.set(d, aliases, value, conv=conv)
|
|
267
415
|
|
|
268
416
|
|
|
269
417
|
set_attr = partial(set_attr_generic, conv=float)
|
|
270
418
|
|
|
271
|
-
|
|
272
419
|
get_attr_str = partial(get_attr, conv=str)
|
|
273
420
|
set_attr_str = partial(set_attr_generic, conv=str)
|
|
274
421
|
|
|
275
422
|
|
|
423
|
+
def set_theta_attr(d: MutableMapping[str, Any], value: Any) -> float:
|
|
424
|
+
"""Assign ``theta``/``phase`` using the English attribute names."""
|
|
425
|
+
result = float(value)
|
|
426
|
+
d["theta"] = result
|
|
427
|
+
d["phase"] = result
|
|
428
|
+
return result
|
|
429
|
+
|
|
430
|
+
|
|
276
431
|
# -------------------------
|
|
277
|
-
#
|
|
432
|
+
# Cached global maxima
|
|
278
433
|
# -------------------------
|
|
279
434
|
|
|
280
435
|
|
|
@@ -292,7 +447,7 @@ def _coerce_abs_value(value: Any) -> float:
|
|
|
292
447
|
if value is None:
|
|
293
448
|
return 0.0
|
|
294
449
|
try:
|
|
295
|
-
return
|
|
450
|
+
return _bepi_to_float(value)
|
|
296
451
|
except (TypeError, ValueError):
|
|
297
452
|
return 0.0
|
|
298
453
|
|
|
@@ -388,9 +543,7 @@ def _update_cached_abs_max(
|
|
|
388
543
|
cur_node = cast(Hashable | None, G.graph.get(node_key))
|
|
389
544
|
|
|
390
545
|
if val >= cur:
|
|
391
|
-
return _compute_abs_max_result(
|
|
392
|
-
G, aliases, key=key, candidate=(n, val)
|
|
393
|
-
)
|
|
546
|
+
return _compute_abs_max_result(G, aliases, key=key, candidate=(n, val))
|
|
394
547
|
if cur_node == n:
|
|
395
548
|
return _compute_abs_max_result(G, aliases, key=key)
|
|
396
549
|
return AbsMaxResult(max_value=cur, node=cur_node)
|
|
@@ -461,9 +614,7 @@ def set_scalar(
|
|
|
461
614
|
return set_attr_and_cache(G, n, alias, value, cache=cache, extra=extra)
|
|
462
615
|
|
|
463
616
|
|
|
464
|
-
def _increment_trig_version(
|
|
465
|
-
G: "networkx.Graph", _: Hashable, __: float
|
|
466
|
-
) -> None:
|
|
617
|
+
def _increment_trig_version(G: "networkx.Graph", _: Hashable, __: float) -> None:
|
|
467
618
|
"""Increment cached trig version to invalidate trig caches."""
|
|
468
619
|
g = G.graph
|
|
469
620
|
g["_trig_version"] = int(g.get("_trig_version", 0)) + 1
|
|
@@ -484,7 +635,7 @@ SCALAR_SETTERS: dict[str, dict[str, Any]] = {
|
|
|
484
635
|
"theta": {
|
|
485
636
|
"alias": ALIAS_THETA,
|
|
486
637
|
"extra": _increment_trig_version,
|
|
487
|
-
"doc": "Set
|
|
638
|
+
"doc": "Set ``theta`` for node ``n`` and invalidate trig caches.",
|
|
488
639
|
},
|
|
489
640
|
}
|
|
490
641
|
|
|
@@ -528,15 +679,41 @@ for _name, _spec in SCALAR_SETTERS.items():
|
|
|
528
679
|
|
|
529
680
|
del _name, _spec, _make_scalar_setter
|
|
530
681
|
|
|
682
|
+
_set_theta_impl = cast(
|
|
683
|
+
Callable[["networkx.Graph", Hashable, float], AbsMaxResult | None],
|
|
684
|
+
globals()["set_theta"],
|
|
685
|
+
)
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
def _set_theta_with_compat(
|
|
689
|
+
G: "networkx.Graph", n: Hashable, value: float
|
|
690
|
+
) -> AbsMaxResult | None:
|
|
691
|
+
nd = cast(MutableMapping[str, Any], G.nodes[n])
|
|
692
|
+
result = _set_theta_impl(G, n, value)
|
|
693
|
+
theta_val = get_theta_attr(nd, value)
|
|
694
|
+
if theta_val is not None:
|
|
695
|
+
float_theta = float(theta_val)
|
|
696
|
+
nd["theta"] = float_theta
|
|
697
|
+
nd["phase"] = float_theta
|
|
698
|
+
return result
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
_set_theta_with_compat.__name__ = "set_theta"
|
|
702
|
+
_set_theta_with_compat.__qualname__ = "set_theta"
|
|
703
|
+
_set_theta_with_compat.__doc__ = _set_theta_impl.__doc__
|
|
704
|
+
globals()["set_theta"] = _set_theta_with_compat
|
|
531
705
|
|
|
532
706
|
__all__ = [
|
|
533
707
|
"AbsMaxResult",
|
|
534
708
|
"set_attr_generic",
|
|
535
709
|
"get_attr",
|
|
710
|
+
"get_theta_attr",
|
|
536
711
|
"collect_attr",
|
|
712
|
+
"collect_theta_attr",
|
|
537
713
|
"set_attr",
|
|
538
714
|
"get_attr_str",
|
|
539
715
|
"set_attr_str",
|
|
716
|
+
"set_theta_attr",
|
|
540
717
|
"set_attr_and_cache",
|
|
541
718
|
"set_attr_with_max",
|
|
542
719
|
"set_scalar",
|
tnfr/alias.pyi
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Iterable, Mapping, MutableMapping
|
|
4
|
+
from types import ModuleType
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Hashable, TypeVar
|
|
6
|
+
|
|
7
|
+
from .types import FloatArray, NodeId
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
import networkx as nx
|
|
11
|
+
|
|
12
|
+
T = TypeVar("T")
|
|
13
|
+
|
|
14
|
+
__all__: list[str]
|
|
15
|
+
|
|
16
|
+
def __getattr__(name: str) -> Any: ...
|
|
17
|
+
|
|
18
|
+
class AbsMaxResult:
|
|
19
|
+
max_value: float
|
|
20
|
+
node: Hashable | None
|
|
21
|
+
|
|
22
|
+
SCALAR_SETTERS: dict[str, dict[str, Any]]
|
|
23
|
+
|
|
24
|
+
def get_attr(
|
|
25
|
+
d: dict[str, Any],
|
|
26
|
+
aliases: Iterable[str],
|
|
27
|
+
default: T | None = ...,
|
|
28
|
+
*,
|
|
29
|
+
strict: bool = ...,
|
|
30
|
+
log_level: int | None = ...,
|
|
31
|
+
conv: Callable[[Any], T] = ...,
|
|
32
|
+
) -> T | None: ...
|
|
33
|
+
def get_theta_attr(
|
|
34
|
+
d: Mapping[str, Any],
|
|
35
|
+
default: T | None = ...,
|
|
36
|
+
*,
|
|
37
|
+
strict: bool = ...,
|
|
38
|
+
log_level: int | None = ...,
|
|
39
|
+
conv: Callable[[Any], T] = ...,
|
|
40
|
+
) -> T | None: ...
|
|
41
|
+
def collect_attr(
|
|
42
|
+
G: "nx.Graph",
|
|
43
|
+
nodes: Iterable[NodeId],
|
|
44
|
+
aliases: Iterable[str],
|
|
45
|
+
default: float = ...,
|
|
46
|
+
*,
|
|
47
|
+
np: ModuleType | None = ...,
|
|
48
|
+
) -> FloatArray | list[float]: ...
|
|
49
|
+
def collect_theta_attr(
|
|
50
|
+
G: "nx.Graph",
|
|
51
|
+
nodes: Iterable[NodeId],
|
|
52
|
+
default: float = ...,
|
|
53
|
+
*,
|
|
54
|
+
np: ModuleType | None = ...,
|
|
55
|
+
) -> FloatArray | list[float]: ...
|
|
56
|
+
def set_attr_generic(
|
|
57
|
+
d: dict[str, Any],
|
|
58
|
+
aliases: Iterable[str],
|
|
59
|
+
value: Any,
|
|
60
|
+
*,
|
|
61
|
+
conv: Callable[[Any], T],
|
|
62
|
+
) -> T: ...
|
|
63
|
+
def set_attr(
|
|
64
|
+
d: dict[str, Any],
|
|
65
|
+
aliases: Iterable[str],
|
|
66
|
+
value: Any,
|
|
67
|
+
conv: Callable[[Any], T] = ...,
|
|
68
|
+
) -> T: ...
|
|
69
|
+
def get_attr_str(
|
|
70
|
+
d: dict[str, Any],
|
|
71
|
+
aliases: Iterable[str],
|
|
72
|
+
default: str | None = ...,
|
|
73
|
+
*,
|
|
74
|
+
strict: bool = ...,
|
|
75
|
+
log_level: int | None = ...,
|
|
76
|
+
conv: Callable[[Any], str] = ...,
|
|
77
|
+
) -> str | None: ...
|
|
78
|
+
def set_attr_str(d: dict[str, Any], aliases: Iterable[str], value: Any) -> str: ...
|
|
79
|
+
def set_theta_attr(d: MutableMapping[str, Any], value: Any) -> float: ...
|
|
80
|
+
def multi_recompute_abs_max(
|
|
81
|
+
G: "nx.Graph", alias_map: Mapping[str, tuple[str, ...]]
|
|
82
|
+
) -> dict[str, float]: ...
|
|
83
|
+
def set_attr_and_cache(
|
|
84
|
+
G: "nx.Graph",
|
|
85
|
+
n: Hashable,
|
|
86
|
+
aliases: tuple[str, ...],
|
|
87
|
+
value: float,
|
|
88
|
+
*,
|
|
89
|
+
cache: str | None = ...,
|
|
90
|
+
extra: Callable[["nx.Graph", Hashable, float], None] | None = ...,
|
|
91
|
+
) -> AbsMaxResult | None: ...
|
|
92
|
+
def set_attr_with_max(
|
|
93
|
+
G: "nx.Graph", n: Hashable, aliases: tuple[str, ...], value: float, *, cache: str
|
|
94
|
+
) -> AbsMaxResult: ...
|
|
95
|
+
def set_scalar(
|
|
96
|
+
G: "nx.Graph",
|
|
97
|
+
n: Hashable,
|
|
98
|
+
alias: tuple[str, ...],
|
|
99
|
+
value: float,
|
|
100
|
+
*,
|
|
101
|
+
cache: str | None = ...,
|
|
102
|
+
extra: Callable[["nx.Graph", Hashable, float], None] | None = ...,
|
|
103
|
+
) -> AbsMaxResult | None: ...
|
|
104
|
+
def set_vf(
|
|
105
|
+
G: "nx.Graph", n: Hashable, value: float, *, update_max: bool = ...
|
|
106
|
+
) -> AbsMaxResult | None: ...
|
|
107
|
+
def set_dnfr(G: "nx.Graph", n: Hashable, value: float) -> AbsMaxResult | None: ...
|
|
108
|
+
def set_theta(G: "nx.Graph", n: Hashable, value: float) -> AbsMaxResult | None: ...
|