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,710 @@
|
|
|
1
|
+
r"""Internal Hamiltonian operator construction for TNFR.
|
|
2
|
+
|
|
3
|
+
This module implements the explicit construction of the internal Hamiltonian:
|
|
4
|
+
|
|
5
|
+
.. math::
|
|
6
|
+
\hat{H}_{int} = \hat{H}_{coh} + \hat{H}_{freq} + \hat{H}_{coupling}
|
|
7
|
+
|
|
8
|
+
Mathematical Foundation
|
|
9
|
+
-----------------------
|
|
10
|
+
|
|
11
|
+
The internal Hamiltonian :math:`\hat{H}_{int}` governs the structural evolution
|
|
12
|
+
of resonant fractal nodes through the canonical nodal equation:
|
|
13
|
+
|
|
14
|
+
.. math::
|
|
15
|
+
\frac{\partial \text{EPI}}{\partial t} = \nu_f \cdot \Delta\text{NFR}(t)
|
|
16
|
+
|
|
17
|
+
where the reorganization operator :math:`\Delta\text{NFR}` is defined as:
|
|
18
|
+
|
|
19
|
+
.. math::
|
|
20
|
+
\Delta\text{NFR} = \frac{d}{dt} + \frac{i[\hat{H}_{int}, \cdot]}{\hbar_{str}}
|
|
21
|
+
|
|
22
|
+
**Components**:
|
|
23
|
+
|
|
24
|
+
1. **Coherence Potential** :math:`\hat{H}_{coh}`:
|
|
25
|
+
Potential energy from structural alignment between nodes.
|
|
26
|
+
|
|
27
|
+
.. math::
|
|
28
|
+
\hat{H}_{coh} = -C_0 \sum_{ij} w_{ij} |i\rangle\langle j|
|
|
29
|
+
|
|
30
|
+
where :math:`w_{ij}` is the coherence weight from similarity metrics.
|
|
31
|
+
|
|
32
|
+
2. **Frequency Operator** :math:`\hat{H}_{freq}`:
|
|
33
|
+
Diagonal operator encoding each node's structural frequency.
|
|
34
|
+
|
|
35
|
+
.. math::
|
|
36
|
+
\hat{H}_{freq} = \sum_i \nu_{f,i} |i\rangle\langle i|
|
|
37
|
+
|
|
38
|
+
3. **Coupling Hamiltonian** :math:`\hat{H}_{coupling}`:
|
|
39
|
+
Network topology-induced interactions.
|
|
40
|
+
|
|
41
|
+
.. math::
|
|
42
|
+
\hat{H}_{coupling} = J_0 \sum_{(i,j) \in E} (|i\rangle\langle j| + |j\rangle\langle i|)
|
|
43
|
+
|
|
44
|
+
Theoretical References
|
|
45
|
+
----------------------
|
|
46
|
+
|
|
47
|
+
See:
|
|
48
|
+
- Mathematical formalization: ``Formalizacion-Matematica-TNFR-Unificada.pdf``, §2.4
|
|
49
|
+
- ΔNFR development: ``Desarrollo-Exhaustivo_-Formalizacion-Matematica-Ri-3.pdf``
|
|
50
|
+
- Quantum time evolution: Sakurai, "Modern Quantum Mechanics", Chapter 2
|
|
51
|
+
|
|
52
|
+
Examples
|
|
53
|
+
--------
|
|
54
|
+
|
|
55
|
+
**Basic Hamiltonian construction**:
|
|
56
|
+
|
|
57
|
+
>>> import networkx as nx
|
|
58
|
+
>>> from tnfr.operators.hamiltonian import InternalHamiltonian
|
|
59
|
+
>>> G = nx.Graph()
|
|
60
|
+
>>> G.add_edges_from([(0, 1), (1, 2), (2, 0)])
|
|
61
|
+
>>> for i, node in enumerate(G.nodes):
|
|
62
|
+
... G.nodes[node].update({
|
|
63
|
+
... 'nu_f': 0.5 + 0.1 * i,
|
|
64
|
+
... 'phase': 0.0,
|
|
65
|
+
... 'epi': 1.0,
|
|
66
|
+
... 'si': 0.7
|
|
67
|
+
... })
|
|
68
|
+
>>> ham = InternalHamiltonian(G)
|
|
69
|
+
>>> print("Total Hamiltonian shape:", ham.H_int.shape)
|
|
70
|
+
Total Hamiltonian shape: (3, 3)
|
|
71
|
+
|
|
72
|
+
**Time evolution**:
|
|
73
|
+
|
|
74
|
+
>>> U_t = ham.time_evolution_operator(t=1.0)
|
|
75
|
+
>>> import numpy as np
|
|
76
|
+
>>> is_unitary = np.allclose(U_t @ U_t.conj().T, np.eye(3))
|
|
77
|
+
>>> print("Evolution operator is unitary:", is_unitary)
|
|
78
|
+
Evolution operator is unitary: True
|
|
79
|
+
|
|
80
|
+
**Energy spectrum**:
|
|
81
|
+
|
|
82
|
+
>>> eigenvalues, eigenvectors = ham.get_spectrum()
|
|
83
|
+
>>> print("Ground state energy:", eigenvalues[0])
|
|
84
|
+
Ground state energy: ...
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
from __future__ import annotations
|
|
88
|
+
|
|
89
|
+
from typing import TYPE_CHECKING, Any, Tuple
|
|
90
|
+
|
|
91
|
+
from ..alias import get_attr
|
|
92
|
+
from ..constants.aliases import ALIAS_VF
|
|
93
|
+
from ..utils.cache import cached_node_list, CacheManager, _graph_cache_manager
|
|
94
|
+
|
|
95
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
96
|
+
import numpy as np
|
|
97
|
+
from ..types import TNFRGraph, FloatMatrix
|
|
98
|
+
|
|
99
|
+
__all__ = (
|
|
100
|
+
"InternalHamiltonian",
|
|
101
|
+
"build_H_coherence",
|
|
102
|
+
"build_H_frequency",
|
|
103
|
+
"build_H_coupling",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class InternalHamiltonian:
|
|
108
|
+
"""Constructs and manipulates the internal Hamiltonian H_int.
|
|
109
|
+
|
|
110
|
+
Mathematical Definition
|
|
111
|
+
-----------------------
|
|
112
|
+
|
|
113
|
+
.. math::
|
|
114
|
+
\hat{H}_{int} = \hat{H}_{coh} + \hat{H}_{freq} + \hat{H}_{coupling}
|
|
115
|
+
|
|
116
|
+
where each component is an N×N Hermitian matrix (N = number of nodes).
|
|
117
|
+
|
|
118
|
+
Attributes
|
|
119
|
+
----------
|
|
120
|
+
G : TNFRGraph
|
|
121
|
+
Network graph with structural attributes
|
|
122
|
+
H_coh : ndarray, shape (N, N)
|
|
123
|
+
Coherence potential matrix
|
|
124
|
+
H_freq : ndarray, shape (N, N)
|
|
125
|
+
Frequency operator matrix (diagonal)
|
|
126
|
+
H_coupling : ndarray, shape (N, N)
|
|
127
|
+
Coupling matrix from network topology
|
|
128
|
+
H_int : ndarray, shape (N, N)
|
|
129
|
+
Total internal Hamiltonian
|
|
130
|
+
hbar_str : float
|
|
131
|
+
Structural Planck constant (ℏ_str)
|
|
132
|
+
nodes : list
|
|
133
|
+
Ordered list of node identifiers
|
|
134
|
+
N : int
|
|
135
|
+
Number of nodes in the network
|
|
136
|
+
|
|
137
|
+
Notes
|
|
138
|
+
-----
|
|
139
|
+
|
|
140
|
+
This implementation leverages existing cache infrastructure:
|
|
141
|
+
|
|
142
|
+
- Uses ``cached_node_list()`` for consistent node ordering
|
|
143
|
+
- Reuses ``coherence_matrix()`` computation for H_coh
|
|
144
|
+
- Integrates with ``CacheManager`` for performance optimization
|
|
145
|
+
|
|
146
|
+
All matrix components are verified to be Hermitian (self-adjoint),
|
|
147
|
+
ensuring real eigenvalues and unitary time evolution.
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
def __init__(
|
|
151
|
+
self,
|
|
152
|
+
G: TNFRGraph,
|
|
153
|
+
hbar_str: float = 1.0,
|
|
154
|
+
cache_manager: CacheManager | None = None,
|
|
155
|
+
):
|
|
156
|
+
"""Initialize Hamiltonian from graph structure.
|
|
157
|
+
|
|
158
|
+
Parameters
|
|
159
|
+
----------
|
|
160
|
+
G : TNFRGraph
|
|
161
|
+
Graph with nodes containing 'nu_f', 'phase', 'epi', 'si' attributes
|
|
162
|
+
hbar_str : float, default=1.0
|
|
163
|
+
Structural Planck constant (ℏ_str). This sets the scale for
|
|
164
|
+
structural reorganization rates. Default value of 1.0 gives natural
|
|
165
|
+
units where the Hamiltonian directly represents structural energy scales.
|
|
166
|
+
cache_manager : CacheManager, optional
|
|
167
|
+
Cache manager for performance optimization. If None, uses the
|
|
168
|
+
graph's internal cache manager.
|
|
169
|
+
|
|
170
|
+
Raises
|
|
171
|
+
------
|
|
172
|
+
ValueError
|
|
173
|
+
If any Hamiltonian component fails Hermiticity check
|
|
174
|
+
ImportError
|
|
175
|
+
If NumPy is not available
|
|
176
|
+
"""
|
|
177
|
+
# Import NumPy (required for matrix operations)
|
|
178
|
+
try:
|
|
179
|
+
import numpy as np
|
|
180
|
+
|
|
181
|
+
self._np = np
|
|
182
|
+
except ImportError as exc:
|
|
183
|
+
raise ImportError(
|
|
184
|
+
"NumPy is required for Hamiltonian construction. "
|
|
185
|
+
"Install with: pip install numpy"
|
|
186
|
+
) from exc
|
|
187
|
+
|
|
188
|
+
self.G = G
|
|
189
|
+
self.hbar_str = float(hbar_str)
|
|
190
|
+
|
|
191
|
+
# Use unified cache infrastructure
|
|
192
|
+
if cache_manager is None:
|
|
193
|
+
cache_manager = _graph_cache_manager(G.graph)
|
|
194
|
+
self._cache_manager = cache_manager
|
|
195
|
+
|
|
196
|
+
# Get consistent node ordering using cached utility
|
|
197
|
+
self.nodes = cached_node_list(G)
|
|
198
|
+
self.N = len(self.nodes)
|
|
199
|
+
|
|
200
|
+
# Build Hamiltonian components
|
|
201
|
+
self.H_coh = self._build_H_coherence()
|
|
202
|
+
self.H_freq = self._build_H_frequency()
|
|
203
|
+
self.H_coupling = self._build_H_coupling()
|
|
204
|
+
|
|
205
|
+
# Combine into total Hamiltonian
|
|
206
|
+
self.H_int = self.H_coh + self.H_freq + self.H_coupling
|
|
207
|
+
|
|
208
|
+
# Verify Hermiticity (critical for physical validity)
|
|
209
|
+
self._verify_hermitian()
|
|
210
|
+
|
|
211
|
+
def _build_H_coherence(self) -> FloatMatrix:
|
|
212
|
+
"""Construct coherence potential H_coh from coherence matrix.
|
|
213
|
+
|
|
214
|
+
Theory
|
|
215
|
+
------
|
|
216
|
+
|
|
217
|
+
.. math::
|
|
218
|
+
\hat{H}_{coh} = -C_0 \sum_{ij} w_{ij} |i\rangle\langle j|
|
|
219
|
+
|
|
220
|
+
where :math:`w_{ij}` is the coherence weight computed from structural
|
|
221
|
+
similarity (phase, EPI, νf, Si). The negative sign ensures coherent
|
|
222
|
+
states have lower energy (potential well).
|
|
223
|
+
|
|
224
|
+
Returns
|
|
225
|
+
-------
|
|
226
|
+
H_coh : ndarray, shape (N, N)
|
|
227
|
+
Coherence potential matrix (Hermitian)
|
|
228
|
+
|
|
229
|
+
Notes
|
|
230
|
+
-----
|
|
231
|
+
|
|
232
|
+
Reuses ``coherence_matrix()`` function to avoid code duplication and
|
|
233
|
+
ensure consistency with existing coherence computations.
|
|
234
|
+
"""
|
|
235
|
+
np = self._np
|
|
236
|
+
|
|
237
|
+
# Handle empty graph case
|
|
238
|
+
if self.N == 0:
|
|
239
|
+
return np.zeros((0, 0), dtype=complex)
|
|
240
|
+
|
|
241
|
+
# Import here to avoid circular dependency
|
|
242
|
+
from ..metrics.coherence import coherence_matrix
|
|
243
|
+
|
|
244
|
+
# Reuse existing coherence_matrix computation
|
|
245
|
+
nodes, W = coherence_matrix(self.G)
|
|
246
|
+
|
|
247
|
+
# Convert to dense NumPy array
|
|
248
|
+
if isinstance(W, list):
|
|
249
|
+
# Empty list case
|
|
250
|
+
if len(W) == 0:
|
|
251
|
+
W_matrix = np.zeros((self.N, self.N), dtype=complex)
|
|
252
|
+
# Check if sparse format (list of tuples) or dense (list of lists)
|
|
253
|
+
elif isinstance(W[0], (list, tuple)) and len(W[0]) == 3:
|
|
254
|
+
# Sparse format: [(i, j, w), ...]
|
|
255
|
+
W_matrix = np.zeros((self.N, self.N), dtype=complex)
|
|
256
|
+
for i, j, w in W:
|
|
257
|
+
W_matrix[i, j] = w
|
|
258
|
+
else:
|
|
259
|
+
# Dense format: [[...], [...], ...]
|
|
260
|
+
W_matrix = np.array(W, dtype=complex)
|
|
261
|
+
else:
|
|
262
|
+
W_matrix = np.asarray(W, dtype=complex)
|
|
263
|
+
|
|
264
|
+
# Reshape if necessary (handle 1D case)
|
|
265
|
+
if W_matrix.ndim == 1:
|
|
266
|
+
if len(W_matrix) == 0:
|
|
267
|
+
W_matrix = np.zeros((self.N, self.N), dtype=complex)
|
|
268
|
+
elif len(W_matrix) == self.N * self.N:
|
|
269
|
+
W_matrix = W_matrix.reshape((self.N, self.N))
|
|
270
|
+
else:
|
|
271
|
+
raise ValueError(
|
|
272
|
+
f"Cannot reshape coherence vector of length {len(W_matrix)} "
|
|
273
|
+
f"into ({self.N}, {self.N}) matrix"
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
# Ensure correct shape
|
|
277
|
+
if W_matrix.shape != (self.N, self.N):
|
|
278
|
+
raise ValueError(
|
|
279
|
+
f"Coherence matrix shape {W_matrix.shape} does not match "
|
|
280
|
+
f"node count ({self.N}, {self.N})"
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# Scale by coherence strength (negative for potential well)
|
|
284
|
+
C_0 = self.G.graph.get("H_COH_STRENGTH", -1.0)
|
|
285
|
+
H_coh = C_0 * W_matrix
|
|
286
|
+
|
|
287
|
+
return H_coh
|
|
288
|
+
|
|
289
|
+
def _build_H_frequency(self) -> FloatMatrix:
|
|
290
|
+
"""Construct frequency operator H_freq (diagonal).
|
|
291
|
+
|
|
292
|
+
Theory
|
|
293
|
+
------
|
|
294
|
+
|
|
295
|
+
.. math::
|
|
296
|
+
\hat{H}_{freq} = \sum_i \nu_{f,i} |i\rangle\langle i|
|
|
297
|
+
|
|
298
|
+
Each node's structural frequency :math:`\nu_{f,i}` becomes its diagonal
|
|
299
|
+
energy. Nodes with higher νf have higher "kinetic" reorganization energy.
|
|
300
|
+
|
|
301
|
+
Returns
|
|
302
|
+
-------
|
|
303
|
+
H_freq : ndarray, shape (N, N)
|
|
304
|
+
Diagonal frequency operator (Hermitian)
|
|
305
|
+
|
|
306
|
+
Notes
|
|
307
|
+
-----
|
|
308
|
+
|
|
309
|
+
Uses ``get_attr()`` with ``ALIAS_VF`` to support attribute aliasing
|
|
310
|
+
and maintain consistency with the rest of the codebase.
|
|
311
|
+
"""
|
|
312
|
+
np = self._np
|
|
313
|
+
|
|
314
|
+
frequencies = np.zeros(self.N, dtype=float)
|
|
315
|
+
|
|
316
|
+
for i, node in enumerate(self.nodes):
|
|
317
|
+
# Use unified attribute access with aliasing support
|
|
318
|
+
nu_f = get_attr(self.G.nodes[node], ALIAS_VF, 0.0)
|
|
319
|
+
frequencies[i] = float(nu_f)
|
|
320
|
+
|
|
321
|
+
# Create diagonal matrix (automatically Hermitian)
|
|
322
|
+
H_freq = np.diag(frequencies).astype(complex)
|
|
323
|
+
|
|
324
|
+
return H_freq
|
|
325
|
+
|
|
326
|
+
def _build_H_coupling(self) -> FloatMatrix:
|
|
327
|
+
"""Construct coupling Hamiltonian from network topology.
|
|
328
|
+
|
|
329
|
+
Theory
|
|
330
|
+
------
|
|
331
|
+
|
|
332
|
+
.. math::
|
|
333
|
+
\hat{H}_{coupling} = J_0 \sum_{(i,j) \in E} (|i\rangle\langle j| + |j\rangle\langle i|)
|
|
334
|
+
|
|
335
|
+
where E is the edge set and :math:`J_0` is coupling strength.
|
|
336
|
+
The sum is symmetric (Hermitian) for undirected graphs.
|
|
337
|
+
|
|
338
|
+
Returns
|
|
339
|
+
-------
|
|
340
|
+
H_coupling : ndarray, shape (N, N)
|
|
341
|
+
Coupling matrix (Hermitian for undirected graphs)
|
|
342
|
+
|
|
343
|
+
Notes
|
|
344
|
+
-----
|
|
345
|
+
|
|
346
|
+
For directed graphs, the matrix may not be Hermitian unless the graph
|
|
347
|
+
is explicitly symmetrized.
|
|
348
|
+
"""
|
|
349
|
+
np = self._np
|
|
350
|
+
|
|
351
|
+
H_coupling = np.zeros((self.N, self.N), dtype=complex)
|
|
352
|
+
|
|
353
|
+
# Build node index mapping (use consistent ordering)
|
|
354
|
+
node_to_idx = {node: i for i, node in enumerate(self.nodes)}
|
|
355
|
+
|
|
356
|
+
# Get coupling strength from graph configuration
|
|
357
|
+
J_0 = self.G.graph.get("H_COUPLING_STRENGTH", 0.1)
|
|
358
|
+
|
|
359
|
+
# Populate coupling matrix from edges
|
|
360
|
+
for u, v in self.G.edges():
|
|
361
|
+
i = node_to_idx[u]
|
|
362
|
+
j = node_to_idx[v]
|
|
363
|
+
|
|
364
|
+
# Symmetric coupling (ensures Hermiticity)
|
|
365
|
+
H_coupling[i, j] = J_0
|
|
366
|
+
H_coupling[j, i] = J_0
|
|
367
|
+
|
|
368
|
+
return H_coupling
|
|
369
|
+
|
|
370
|
+
def _verify_hermitian(self, tolerance: float = 1e-10) -> None:
|
|
371
|
+
"""Verify that all Hamiltonian components are Hermitian.
|
|
372
|
+
|
|
373
|
+
Parameters
|
|
374
|
+
----------
|
|
375
|
+
tolerance : float, default=1e-10
|
|
376
|
+
Maximum allowed deviation from Hermiticity
|
|
377
|
+
|
|
378
|
+
Raises
|
|
379
|
+
------
|
|
380
|
+
ValueError
|
|
381
|
+
If any component fails Hermiticity check with detailed diagnostics
|
|
382
|
+
|
|
383
|
+
Notes
|
|
384
|
+
-----
|
|
385
|
+
|
|
386
|
+
A matrix H is Hermitian if :math:`H = H^\dagger`, where :math:`\dagger`
|
|
387
|
+
denotes conjugate transpose. This ensures:
|
|
388
|
+
|
|
389
|
+
1. Real eigenvalues (energy spectrum)
|
|
390
|
+
2. Unitary time evolution
|
|
391
|
+
3. Probability conservation
|
|
392
|
+
"""
|
|
393
|
+
np = self._np
|
|
394
|
+
|
|
395
|
+
# Handle empty graph case
|
|
396
|
+
if self.N == 0:
|
|
397
|
+
return
|
|
398
|
+
|
|
399
|
+
components = [
|
|
400
|
+
("H_coh", self.H_coh),
|
|
401
|
+
("H_freq", self.H_freq),
|
|
402
|
+
("H_coupling", self.H_coupling),
|
|
403
|
+
("H_int", self.H_int),
|
|
404
|
+
]
|
|
405
|
+
|
|
406
|
+
for name, H in components:
|
|
407
|
+
# Check Hermiticity: H = H†
|
|
408
|
+
H_dagger = H.conj().T
|
|
409
|
+
deviation = np.max(np.abs(H - H_dagger))
|
|
410
|
+
|
|
411
|
+
if deviation > tolerance:
|
|
412
|
+
raise ValueError(
|
|
413
|
+
f"{name} is not Hermitian: max deviation = {deviation:.2e} "
|
|
414
|
+
f"(tolerance = {tolerance:.2e})"
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
def compute_delta_nfr_operator(self) -> FloatMatrix:
|
|
418
|
+
"""Compute ΔNFR operator from Hamiltonian commutator.
|
|
419
|
+
|
|
420
|
+
Theory
|
|
421
|
+
------
|
|
422
|
+
|
|
423
|
+
.. math::
|
|
424
|
+
\Delta\text{NFR} = \frac{i[\hat{H}_{int}, \cdot]}{\hbar_{str}}
|
|
425
|
+
|
|
426
|
+
For a state :math:`|\psi\rangle`:
|
|
427
|
+
|
|
428
|
+
.. math::
|
|
429
|
+
\Delta\text{NFR}|\psi\rangle = \frac{i}{\hbar_{str}}(\hat{H}_{int}|\psi\rangle - |\psi\rangle\hat{H}_{int})
|
|
430
|
+
|
|
431
|
+
Returns
|
|
432
|
+
-------
|
|
433
|
+
Delta_NFR_matrix : ndarray, shape (N, N)
|
|
434
|
+
ΔNFR operator in matrix form (anti-Hermitian)
|
|
435
|
+
|
|
436
|
+
Notes
|
|
437
|
+
-----
|
|
438
|
+
|
|
439
|
+
The ΔNFR operator is anti-Hermitian: :math:`\Delta\text{NFR}^\dagger = -\Delta\text{NFR}`,
|
|
440
|
+
which ensures imaginary eigenvalues and corresponds to generator of
|
|
441
|
+
time evolution.
|
|
442
|
+
"""
|
|
443
|
+
# ΔNFR = (i/ℏ_str) * H_int (for operators acting on states)
|
|
444
|
+
return (1j / self.hbar_str) * self.H_int
|
|
445
|
+
|
|
446
|
+
def time_evolution_operator(self, t: float) -> FloatMatrix:
|
|
447
|
+
r"""Compute time evolution operator U(t) = exp(-i H_int t / ℏ_str).
|
|
448
|
+
|
|
449
|
+
Parameters
|
|
450
|
+
----------
|
|
451
|
+
t : float
|
|
452
|
+
Evolution time in structural time units
|
|
453
|
+
|
|
454
|
+
Returns
|
|
455
|
+
-------
|
|
456
|
+
U_t : ndarray, shape (N, N)
|
|
457
|
+
Unitary time evolution operator
|
|
458
|
+
|
|
459
|
+
Raises
|
|
460
|
+
------
|
|
461
|
+
ValueError
|
|
462
|
+
If the computed operator is not unitary (indicates numerical issues)
|
|
463
|
+
ImportError
|
|
464
|
+
If scipy is not installed
|
|
465
|
+
|
|
466
|
+
Notes
|
|
467
|
+
-----
|
|
468
|
+
|
|
469
|
+
The time evolution operator propagates states forward in time:
|
|
470
|
+
|
|
471
|
+
.. math::
|
|
472
|
+
|\psi(t)\rangle = U(t)|\psi(0)\rangle
|
|
473
|
+
|
|
474
|
+
Unitarity :math:`U^\dagger U = I` ensures probability conservation.
|
|
475
|
+
"""
|
|
476
|
+
try:
|
|
477
|
+
from scipy.linalg import expm
|
|
478
|
+
except ImportError as exc:
|
|
479
|
+
raise ImportError(
|
|
480
|
+
"scipy is required for time evolution computation. "
|
|
481
|
+
"Install with: pip install scipy"
|
|
482
|
+
) from exc
|
|
483
|
+
|
|
484
|
+
np = self._np
|
|
485
|
+
|
|
486
|
+
# Compute matrix exponential
|
|
487
|
+
exponent = -1j * self.H_int * t / self.hbar_str
|
|
488
|
+
U_t = expm(exponent)
|
|
489
|
+
|
|
490
|
+
# Verify unitarity: U†U = I
|
|
491
|
+
U_dag_U = U_t.conj().T @ U_t
|
|
492
|
+
identity = np.eye(self.N)
|
|
493
|
+
|
|
494
|
+
if not np.allclose(U_dag_U, identity):
|
|
495
|
+
max_error = np.max(np.abs(U_dag_U - identity))
|
|
496
|
+
raise ValueError(
|
|
497
|
+
f"Evolution operator is not unitary: max error = {max_error:.2e}. "
|
|
498
|
+
"This indicates numerical instability, possibly due to "
|
|
499
|
+
"ill-conditioned Hamiltonian or inappropriate time step."
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
return U_t
|
|
503
|
+
|
|
504
|
+
def get_spectrum(self) -> Tuple[Any, Any]:
|
|
505
|
+
"""Compute eigenvalues and eigenvectors of H_int.
|
|
506
|
+
|
|
507
|
+
Returns
|
|
508
|
+
-------
|
|
509
|
+
eigenvalues : ndarray, shape (N,)
|
|
510
|
+
Energy eigenvalues (sorted in ascending order)
|
|
511
|
+
eigenvectors : ndarray, shape (N, N)
|
|
512
|
+
Eigenvector matrix (columns are eigenstates)
|
|
513
|
+
|
|
514
|
+
Notes
|
|
515
|
+
-----
|
|
516
|
+
|
|
517
|
+
The eigenvalue equation:
|
|
518
|
+
|
|
519
|
+
.. math::
|
|
520
|
+
\hat{H}_{int}|\phi_n\rangle = E_n|\phi_n\rangle
|
|
521
|
+
|
|
522
|
+
gives the stationary states :math:`|\phi_n\rangle` with energies :math:`E_n`.
|
|
523
|
+
These are the maximally stable coherent configurations.
|
|
524
|
+
"""
|
|
525
|
+
np = self._np
|
|
526
|
+
|
|
527
|
+
# Use eigh for Hermitian matrices (more efficient and numerically stable)
|
|
528
|
+
eigenvalues, eigenvectors = np.linalg.eigh(self.H_int)
|
|
529
|
+
|
|
530
|
+
return eigenvalues, eigenvectors
|
|
531
|
+
|
|
532
|
+
def compute_node_delta_nfr(self, node: Any) -> float:
|
|
533
|
+
"""Compute ΔNFR for a single node using Hamiltonian commutator.
|
|
534
|
+
|
|
535
|
+
Parameters
|
|
536
|
+
----------
|
|
537
|
+
node : NodeId
|
|
538
|
+
Node identifier
|
|
539
|
+
|
|
540
|
+
Returns
|
|
541
|
+
-------
|
|
542
|
+
delta_nfr : float
|
|
543
|
+
ΔNFR value for the specified node
|
|
544
|
+
|
|
545
|
+
Theory
|
|
546
|
+
------
|
|
547
|
+
|
|
548
|
+
For node n, the ΔNFR is computed as:
|
|
549
|
+
|
|
550
|
+
.. math::
|
|
551
|
+
\Delta\text{NFR}_n = \frac{i}{\hbar_{str}} \langle n | [\hat{H}_{int}, \rho_n] | n \rangle
|
|
552
|
+
|
|
553
|
+
where :math:`\rho_n = |n\rangle\langle n|` is the density matrix for a
|
|
554
|
+
pure state localized on node n.
|
|
555
|
+
|
|
556
|
+
Notes
|
|
557
|
+
-----
|
|
558
|
+
|
|
559
|
+
The commutator result is anti-Hermitian, so its diagonal elements are
|
|
560
|
+
purely imaginary in theory. We extract the real part to obtain the ΔNFR
|
|
561
|
+
observable value. In practice, numerical precision may introduce small
|
|
562
|
+
real components that represent the actual structural reorganization rate.
|
|
563
|
+
"""
|
|
564
|
+
np = self._np
|
|
565
|
+
|
|
566
|
+
# Get node index
|
|
567
|
+
try:
|
|
568
|
+
node_idx = self.nodes.index(node)
|
|
569
|
+
except ValueError:
|
|
570
|
+
raise ValueError(f"Node {node} not found in Hamiltonian")
|
|
571
|
+
|
|
572
|
+
# Node density matrix (pure state |n⟩⟨n|)
|
|
573
|
+
rho_n = np.zeros((self.N, self.N), dtype=complex)
|
|
574
|
+
rho_n[node_idx, node_idx] = 1.0
|
|
575
|
+
|
|
576
|
+
# Commutator: [H_int, ρ_n] = H_int ρ_n - ρ_n H_int
|
|
577
|
+
commutator = self.H_int @ rho_n - rho_n @ self.H_int
|
|
578
|
+
|
|
579
|
+
# ΔNFR operator
|
|
580
|
+
delta_nfr_matrix = (1j / self.hbar_str) * commutator
|
|
581
|
+
|
|
582
|
+
# Extract diagonal element for node n
|
|
583
|
+
# Note: Take real part to obtain observable. Diagonal elements of the
|
|
584
|
+
# anti-Hermitian commutator are purely imaginary theoretically; any
|
|
585
|
+
# nonzero real part comes from numerical precision or represents the
|
|
586
|
+
# actual structural reorganization rate.
|
|
587
|
+
delta_nfr = float(delta_nfr_matrix[node_idx, node_idx].real)
|
|
588
|
+
|
|
589
|
+
return delta_nfr
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
# Standalone builder functions for modular usage
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
def build_H_coherence(
|
|
596
|
+
G: TNFRGraph,
|
|
597
|
+
nodes: list | None = None,
|
|
598
|
+
C_0: float = -1.0,
|
|
599
|
+
) -> FloatMatrix:
|
|
600
|
+
"""Construct coherence potential matrix from graph.
|
|
601
|
+
|
|
602
|
+
Parameters
|
|
603
|
+
----------
|
|
604
|
+
G : TNFRGraph
|
|
605
|
+
Graph with structural attributes
|
|
606
|
+
nodes : list, optional
|
|
607
|
+
Ordered list of nodes. If None, uses cached_node_list(G)
|
|
608
|
+
C_0 : float, default=-1.0
|
|
609
|
+
Coherence potential strength (negative for attractive potential)
|
|
610
|
+
|
|
611
|
+
Returns
|
|
612
|
+
-------
|
|
613
|
+
H_coh : ndarray, shape (N, N)
|
|
614
|
+
Coherence potential matrix
|
|
615
|
+
"""
|
|
616
|
+
import numpy as np
|
|
617
|
+
|
|
618
|
+
# Import here to avoid circular dependency
|
|
619
|
+
from ..metrics.coherence import coherence_matrix
|
|
620
|
+
|
|
621
|
+
if nodes is None:
|
|
622
|
+
nodes = cached_node_list(G)
|
|
623
|
+
|
|
624
|
+
N = len(nodes)
|
|
625
|
+
_, W = coherence_matrix(G)
|
|
626
|
+
|
|
627
|
+
# Convert to NumPy array
|
|
628
|
+
if isinstance(W, list):
|
|
629
|
+
if W and isinstance(W[0], (list, tuple)) and len(W[0]) == 3:
|
|
630
|
+
W_matrix = np.zeros((N, N), dtype=complex)
|
|
631
|
+
for i, j, w in W:
|
|
632
|
+
W_matrix[i, j] = w
|
|
633
|
+
else:
|
|
634
|
+
W_matrix = np.array(W, dtype=complex)
|
|
635
|
+
else:
|
|
636
|
+
W_matrix = np.asarray(W, dtype=complex)
|
|
637
|
+
|
|
638
|
+
return C_0 * W_matrix
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
def build_H_frequency(
|
|
642
|
+
G: TNFRGraph,
|
|
643
|
+
nodes: list | None = None,
|
|
644
|
+
) -> FloatMatrix:
|
|
645
|
+
"""Construct diagonal frequency operator from graph.
|
|
646
|
+
|
|
647
|
+
Parameters
|
|
648
|
+
----------
|
|
649
|
+
G : TNFRGraph
|
|
650
|
+
Graph with 'nu_f' attributes
|
|
651
|
+
nodes : list, optional
|
|
652
|
+
Ordered list of nodes. If None, uses cached_node_list(G)
|
|
653
|
+
|
|
654
|
+
Returns
|
|
655
|
+
-------
|
|
656
|
+
H_freq : ndarray, shape (N, N)
|
|
657
|
+
Diagonal frequency operator
|
|
658
|
+
"""
|
|
659
|
+
import numpy as np
|
|
660
|
+
|
|
661
|
+
if nodes is None:
|
|
662
|
+
nodes = cached_node_list(G)
|
|
663
|
+
|
|
664
|
+
N = len(nodes)
|
|
665
|
+
frequencies = np.zeros(N, dtype=float)
|
|
666
|
+
|
|
667
|
+
for i, node in enumerate(nodes):
|
|
668
|
+
nu_f = get_attr(G.nodes[node], ALIAS_VF, 0.0)
|
|
669
|
+
frequencies[i] = float(nu_f)
|
|
670
|
+
|
|
671
|
+
return np.diag(frequencies).astype(complex)
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
def build_H_coupling(
|
|
675
|
+
G: TNFRGraph,
|
|
676
|
+
nodes: list | None = None,
|
|
677
|
+
J_0: float = 0.1,
|
|
678
|
+
) -> FloatMatrix:
|
|
679
|
+
"""Construct coupling matrix from graph topology.
|
|
680
|
+
|
|
681
|
+
Parameters
|
|
682
|
+
----------
|
|
683
|
+
G : TNFRGraph
|
|
684
|
+
Graph with edge structure
|
|
685
|
+
nodes : list, optional
|
|
686
|
+
Ordered list of nodes. If None, uses cached_node_list(G)
|
|
687
|
+
J_0 : float, default=0.1
|
|
688
|
+
Coupling strength
|
|
689
|
+
|
|
690
|
+
Returns
|
|
691
|
+
-------
|
|
692
|
+
H_coupling : ndarray, shape (N, N)
|
|
693
|
+
Coupling matrix (symmetric for undirected graphs)
|
|
694
|
+
"""
|
|
695
|
+
import numpy as np
|
|
696
|
+
|
|
697
|
+
if nodes is None:
|
|
698
|
+
nodes = cached_node_list(G)
|
|
699
|
+
|
|
700
|
+
N = len(nodes)
|
|
701
|
+
H_coupling = np.zeros((N, N), dtype=complex)
|
|
702
|
+
node_to_idx = {node: i for i, node in enumerate(nodes)}
|
|
703
|
+
|
|
704
|
+
for u, v in G.edges():
|
|
705
|
+
i = node_to_idx[u]
|
|
706
|
+
j = node_to_idx[v]
|
|
707
|
+
H_coupling[i, j] = J_0
|
|
708
|
+
H_coupling[j, i] = J_0
|
|
709
|
+
|
|
710
|
+
return H_coupling
|