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.

Files changed (360) hide show
  1. tnfr/__init__.py +375 -56
  2. tnfr/__init__.pyi +33 -0
  3. tnfr/_compat.py +10 -0
  4. tnfr/_generated_version.py +34 -0
  5. tnfr/_version.py +49 -0
  6. tnfr/_version.pyi +7 -0
  7. tnfr/alias.py +723 -0
  8. tnfr/alias.pyi +108 -0
  9. tnfr/backends/__init__.py +354 -0
  10. tnfr/backends/jax_backend.py +173 -0
  11. tnfr/backends/numpy_backend.py +238 -0
  12. tnfr/backends/optimized_numpy.py +420 -0
  13. tnfr/backends/torch_backend.py +408 -0
  14. tnfr/cache.py +171 -0
  15. tnfr/cache.pyi +13 -0
  16. tnfr/cli/__init__.py +110 -0
  17. tnfr/cli/__init__.pyi +26 -0
  18. tnfr/cli/arguments.py +489 -0
  19. tnfr/cli/arguments.pyi +29 -0
  20. tnfr/cli/execution.py +914 -0
  21. tnfr/cli/execution.pyi +70 -0
  22. tnfr/cli/interactive_validator.py +614 -0
  23. tnfr/cli/utils.py +51 -0
  24. tnfr/cli/utils.pyi +7 -0
  25. tnfr/cli/validate.py +236 -0
  26. tnfr/compat/__init__.py +85 -0
  27. tnfr/compat/dataclass.py +136 -0
  28. tnfr/compat/jsonschema_stub.py +61 -0
  29. tnfr/compat/matplotlib_stub.py +73 -0
  30. tnfr/compat/numpy_stub.py +155 -0
  31. tnfr/config/__init__.py +224 -0
  32. tnfr/config/__init__.pyi +10 -0
  33. tnfr/config/constants.py +104 -0
  34. tnfr/config/constants.pyi +12 -0
  35. tnfr/config/defaults.py +54 -0
  36. tnfr/config/defaults_core.py +212 -0
  37. tnfr/config/defaults_init.py +33 -0
  38. tnfr/config/defaults_metric.py +104 -0
  39. tnfr/config/feature_flags.py +81 -0
  40. tnfr/config/feature_flags.pyi +16 -0
  41. tnfr/config/glyph_constants.py +31 -0
  42. tnfr/config/init.py +77 -0
  43. tnfr/config/init.pyi +8 -0
  44. tnfr/config/operator_names.py +254 -0
  45. tnfr/config/operator_names.pyi +36 -0
  46. tnfr/config/physics_derivation.py +354 -0
  47. tnfr/config/presets.py +83 -0
  48. tnfr/config/presets.pyi +7 -0
  49. tnfr/config/security.py +927 -0
  50. tnfr/config/thresholds.py +114 -0
  51. tnfr/config/tnfr_config.py +498 -0
  52. tnfr/constants/__init__.py +92 -0
  53. tnfr/constants/__init__.pyi +92 -0
  54. tnfr/constants/aliases.py +33 -0
  55. tnfr/constants/aliases.pyi +27 -0
  56. tnfr/constants/init.py +33 -0
  57. tnfr/constants/init.pyi +12 -0
  58. tnfr/constants/metric.py +104 -0
  59. tnfr/constants/metric.pyi +19 -0
  60. tnfr/core/__init__.py +33 -0
  61. tnfr/core/container.py +226 -0
  62. tnfr/core/default_implementations.py +329 -0
  63. tnfr/core/interfaces.py +279 -0
  64. tnfr/dynamics/__init__.py +238 -0
  65. tnfr/dynamics/__init__.pyi +83 -0
  66. tnfr/dynamics/adaptation.py +267 -0
  67. tnfr/dynamics/adaptation.pyi +7 -0
  68. tnfr/dynamics/adaptive_sequences.py +189 -0
  69. tnfr/dynamics/adaptive_sequences.pyi +14 -0
  70. tnfr/dynamics/aliases.py +23 -0
  71. tnfr/dynamics/aliases.pyi +19 -0
  72. tnfr/dynamics/bifurcation.py +232 -0
  73. tnfr/dynamics/canonical.py +229 -0
  74. tnfr/dynamics/canonical.pyi +48 -0
  75. tnfr/dynamics/coordination.py +385 -0
  76. tnfr/dynamics/coordination.pyi +25 -0
  77. tnfr/dynamics/dnfr.py +3034 -0
  78. tnfr/dynamics/dnfr.pyi +26 -0
  79. tnfr/dynamics/dynamic_limits.py +225 -0
  80. tnfr/dynamics/feedback.py +252 -0
  81. tnfr/dynamics/feedback.pyi +24 -0
  82. tnfr/dynamics/fused_dnfr.py +454 -0
  83. tnfr/dynamics/homeostasis.py +157 -0
  84. tnfr/dynamics/homeostasis.pyi +14 -0
  85. tnfr/dynamics/integrators.py +661 -0
  86. tnfr/dynamics/integrators.pyi +36 -0
  87. tnfr/dynamics/learning.py +310 -0
  88. tnfr/dynamics/learning.pyi +33 -0
  89. tnfr/dynamics/metabolism.py +254 -0
  90. tnfr/dynamics/nbody.py +796 -0
  91. tnfr/dynamics/nbody_tnfr.py +783 -0
  92. tnfr/dynamics/propagation.py +326 -0
  93. tnfr/dynamics/runtime.py +908 -0
  94. tnfr/dynamics/runtime.pyi +77 -0
  95. tnfr/dynamics/sampling.py +36 -0
  96. tnfr/dynamics/sampling.pyi +7 -0
  97. tnfr/dynamics/selectors.py +711 -0
  98. tnfr/dynamics/selectors.pyi +85 -0
  99. tnfr/dynamics/structural_clip.py +207 -0
  100. tnfr/errors/__init__.py +37 -0
  101. tnfr/errors/contextual.py +492 -0
  102. tnfr/execution.py +223 -0
  103. tnfr/execution.pyi +45 -0
  104. tnfr/extensions/__init__.py +205 -0
  105. tnfr/extensions/__init__.pyi +18 -0
  106. tnfr/extensions/base.py +173 -0
  107. tnfr/extensions/base.pyi +35 -0
  108. tnfr/extensions/business/__init__.py +71 -0
  109. tnfr/extensions/business/__init__.pyi +11 -0
  110. tnfr/extensions/business/cookbook.py +88 -0
  111. tnfr/extensions/business/cookbook.pyi +8 -0
  112. tnfr/extensions/business/health_analyzers.py +202 -0
  113. tnfr/extensions/business/health_analyzers.pyi +9 -0
  114. tnfr/extensions/business/patterns.py +183 -0
  115. tnfr/extensions/business/patterns.pyi +8 -0
  116. tnfr/extensions/medical/__init__.py +73 -0
  117. tnfr/extensions/medical/__init__.pyi +11 -0
  118. tnfr/extensions/medical/cookbook.py +88 -0
  119. tnfr/extensions/medical/cookbook.pyi +8 -0
  120. tnfr/extensions/medical/health_analyzers.py +181 -0
  121. tnfr/extensions/medical/health_analyzers.pyi +9 -0
  122. tnfr/extensions/medical/patterns.py +163 -0
  123. tnfr/extensions/medical/patterns.pyi +8 -0
  124. tnfr/flatten.py +262 -0
  125. tnfr/flatten.pyi +21 -0
  126. tnfr/gamma.py +354 -0
  127. tnfr/gamma.pyi +36 -0
  128. tnfr/glyph_history.py +377 -0
  129. tnfr/glyph_history.pyi +35 -0
  130. tnfr/glyph_runtime.py +19 -0
  131. tnfr/glyph_runtime.pyi +8 -0
  132. tnfr/immutable.py +218 -0
  133. tnfr/immutable.pyi +36 -0
  134. tnfr/initialization.py +203 -0
  135. tnfr/initialization.pyi +65 -0
  136. tnfr/io.py +10 -0
  137. tnfr/io.pyi +13 -0
  138. tnfr/locking.py +37 -0
  139. tnfr/locking.pyi +7 -0
  140. tnfr/mathematics/__init__.py +79 -0
  141. tnfr/mathematics/backend.py +453 -0
  142. tnfr/mathematics/backend.pyi +99 -0
  143. tnfr/mathematics/dynamics.py +408 -0
  144. tnfr/mathematics/dynamics.pyi +90 -0
  145. tnfr/mathematics/epi.py +391 -0
  146. tnfr/mathematics/epi.pyi +65 -0
  147. tnfr/mathematics/generators.py +242 -0
  148. tnfr/mathematics/generators.pyi +29 -0
  149. tnfr/mathematics/metrics.py +119 -0
  150. tnfr/mathematics/metrics.pyi +16 -0
  151. tnfr/mathematics/operators.py +239 -0
  152. tnfr/mathematics/operators.pyi +59 -0
  153. tnfr/mathematics/operators_factory.py +124 -0
  154. tnfr/mathematics/operators_factory.pyi +11 -0
  155. tnfr/mathematics/projection.py +87 -0
  156. tnfr/mathematics/projection.pyi +33 -0
  157. tnfr/mathematics/runtime.py +182 -0
  158. tnfr/mathematics/runtime.pyi +64 -0
  159. tnfr/mathematics/spaces.py +256 -0
  160. tnfr/mathematics/spaces.pyi +83 -0
  161. tnfr/mathematics/transforms.py +305 -0
  162. tnfr/mathematics/transforms.pyi +62 -0
  163. tnfr/metrics/__init__.py +79 -0
  164. tnfr/metrics/__init__.pyi +20 -0
  165. tnfr/metrics/buffer_cache.py +163 -0
  166. tnfr/metrics/buffer_cache.pyi +24 -0
  167. tnfr/metrics/cache_utils.py +214 -0
  168. tnfr/metrics/coherence.py +2009 -0
  169. tnfr/metrics/coherence.pyi +129 -0
  170. tnfr/metrics/common.py +158 -0
  171. tnfr/metrics/common.pyi +35 -0
  172. tnfr/metrics/core.py +316 -0
  173. tnfr/metrics/core.pyi +13 -0
  174. tnfr/metrics/diagnosis.py +833 -0
  175. tnfr/metrics/diagnosis.pyi +86 -0
  176. tnfr/metrics/emergence.py +245 -0
  177. tnfr/metrics/export.py +179 -0
  178. tnfr/metrics/export.pyi +7 -0
  179. tnfr/metrics/glyph_timing.py +379 -0
  180. tnfr/metrics/glyph_timing.pyi +81 -0
  181. tnfr/metrics/learning_metrics.py +280 -0
  182. tnfr/metrics/learning_metrics.pyi +21 -0
  183. tnfr/metrics/phase_coherence.py +351 -0
  184. tnfr/metrics/phase_compatibility.py +349 -0
  185. tnfr/metrics/reporting.py +183 -0
  186. tnfr/metrics/reporting.pyi +25 -0
  187. tnfr/metrics/sense_index.py +1203 -0
  188. tnfr/metrics/sense_index.pyi +9 -0
  189. tnfr/metrics/trig.py +373 -0
  190. tnfr/metrics/trig.pyi +13 -0
  191. tnfr/metrics/trig_cache.py +233 -0
  192. tnfr/metrics/trig_cache.pyi +10 -0
  193. tnfr/multiscale/__init__.py +32 -0
  194. tnfr/multiscale/hierarchical.py +517 -0
  195. tnfr/node.py +763 -0
  196. tnfr/node.pyi +139 -0
  197. tnfr/observers.py +255 -130
  198. tnfr/observers.pyi +31 -0
  199. tnfr/ontosim.py +144 -137
  200. tnfr/ontosim.pyi +28 -0
  201. tnfr/operators/__init__.py +1672 -0
  202. tnfr/operators/__init__.pyi +31 -0
  203. tnfr/operators/algebra.py +277 -0
  204. tnfr/operators/canonical_patterns.py +420 -0
  205. tnfr/operators/cascade.py +267 -0
  206. tnfr/operators/cycle_detection.py +358 -0
  207. tnfr/operators/definitions.py +4108 -0
  208. tnfr/operators/definitions.pyi +78 -0
  209. tnfr/operators/grammar.py +1164 -0
  210. tnfr/operators/grammar.pyi +140 -0
  211. tnfr/operators/hamiltonian.py +710 -0
  212. tnfr/operators/health_analyzer.py +809 -0
  213. tnfr/operators/jitter.py +272 -0
  214. tnfr/operators/jitter.pyi +11 -0
  215. tnfr/operators/lifecycle.py +314 -0
  216. tnfr/operators/metabolism.py +618 -0
  217. tnfr/operators/metrics.py +2138 -0
  218. tnfr/operators/network_analysis/__init__.py +27 -0
  219. tnfr/operators/network_analysis/source_detection.py +186 -0
  220. tnfr/operators/nodal_equation.py +395 -0
  221. tnfr/operators/pattern_detection.py +660 -0
  222. tnfr/operators/patterns.py +669 -0
  223. tnfr/operators/postconditions/__init__.py +38 -0
  224. tnfr/operators/postconditions/mutation.py +236 -0
  225. tnfr/operators/preconditions/__init__.py +1226 -0
  226. tnfr/operators/preconditions/coherence.py +305 -0
  227. tnfr/operators/preconditions/dissonance.py +236 -0
  228. tnfr/operators/preconditions/emission.py +128 -0
  229. tnfr/operators/preconditions/mutation.py +580 -0
  230. tnfr/operators/preconditions/reception.py +125 -0
  231. tnfr/operators/preconditions/resonance.py +364 -0
  232. tnfr/operators/registry.py +74 -0
  233. tnfr/operators/registry.pyi +9 -0
  234. tnfr/operators/remesh.py +1809 -0
  235. tnfr/operators/remesh.pyi +26 -0
  236. tnfr/operators/structural_units.py +268 -0
  237. tnfr/operators/unified_grammar.py +105 -0
  238. tnfr/parallel/__init__.py +54 -0
  239. tnfr/parallel/auto_scaler.py +234 -0
  240. tnfr/parallel/distributed.py +384 -0
  241. tnfr/parallel/engine.py +238 -0
  242. tnfr/parallel/gpu_engine.py +420 -0
  243. tnfr/parallel/monitoring.py +248 -0
  244. tnfr/parallel/partitioner.py +459 -0
  245. tnfr/py.typed +0 -0
  246. tnfr/recipes/__init__.py +22 -0
  247. tnfr/recipes/cookbook.py +743 -0
  248. tnfr/rng.py +178 -0
  249. tnfr/rng.pyi +26 -0
  250. tnfr/schemas/__init__.py +8 -0
  251. tnfr/schemas/grammar.json +94 -0
  252. tnfr/sdk/__init__.py +107 -0
  253. tnfr/sdk/__init__.pyi +19 -0
  254. tnfr/sdk/adaptive_system.py +173 -0
  255. tnfr/sdk/adaptive_system.pyi +21 -0
  256. tnfr/sdk/builders.py +370 -0
  257. tnfr/sdk/builders.pyi +51 -0
  258. tnfr/sdk/fluent.py +1121 -0
  259. tnfr/sdk/fluent.pyi +74 -0
  260. tnfr/sdk/templates.py +342 -0
  261. tnfr/sdk/templates.pyi +41 -0
  262. tnfr/sdk/utils.py +341 -0
  263. tnfr/secure_config.py +46 -0
  264. tnfr/security/__init__.py +70 -0
  265. tnfr/security/database.py +514 -0
  266. tnfr/security/subprocess.py +503 -0
  267. tnfr/security/validation.py +290 -0
  268. tnfr/selector.py +247 -0
  269. tnfr/selector.pyi +19 -0
  270. tnfr/sense.py +378 -0
  271. tnfr/sense.pyi +23 -0
  272. tnfr/services/__init__.py +17 -0
  273. tnfr/services/orchestrator.py +325 -0
  274. tnfr/sparse/__init__.py +39 -0
  275. tnfr/sparse/representations.py +492 -0
  276. tnfr/structural.py +705 -0
  277. tnfr/structural.pyi +83 -0
  278. tnfr/telemetry/__init__.py +35 -0
  279. tnfr/telemetry/cache_metrics.py +226 -0
  280. tnfr/telemetry/cache_metrics.pyi +64 -0
  281. tnfr/telemetry/nu_f.py +422 -0
  282. tnfr/telemetry/nu_f.pyi +108 -0
  283. tnfr/telemetry/verbosity.py +36 -0
  284. tnfr/telemetry/verbosity.pyi +15 -0
  285. tnfr/tokens.py +58 -0
  286. tnfr/tokens.pyi +36 -0
  287. tnfr/tools/__init__.py +20 -0
  288. tnfr/tools/domain_templates.py +478 -0
  289. tnfr/tools/sequence_generator.py +846 -0
  290. tnfr/topology/__init__.py +13 -0
  291. tnfr/topology/asymmetry.py +151 -0
  292. tnfr/trace.py +543 -0
  293. tnfr/trace.pyi +42 -0
  294. tnfr/tutorials/__init__.py +38 -0
  295. tnfr/tutorials/autonomous_evolution.py +285 -0
  296. tnfr/tutorials/interactive.py +1576 -0
  297. tnfr/tutorials/structural_metabolism.py +238 -0
  298. tnfr/types.py +775 -0
  299. tnfr/types.pyi +357 -0
  300. tnfr/units.py +68 -0
  301. tnfr/units.pyi +13 -0
  302. tnfr/utils/__init__.py +282 -0
  303. tnfr/utils/__init__.pyi +215 -0
  304. tnfr/utils/cache.py +4223 -0
  305. tnfr/utils/cache.pyi +470 -0
  306. tnfr/utils/callbacks.py +375 -0
  307. tnfr/utils/callbacks.pyi +49 -0
  308. tnfr/utils/chunks.py +108 -0
  309. tnfr/utils/chunks.pyi +22 -0
  310. tnfr/utils/data.py +428 -0
  311. tnfr/utils/data.pyi +74 -0
  312. tnfr/utils/graph.py +85 -0
  313. tnfr/utils/graph.pyi +10 -0
  314. tnfr/utils/init.py +821 -0
  315. tnfr/utils/init.pyi +80 -0
  316. tnfr/utils/io.py +559 -0
  317. tnfr/utils/io.pyi +66 -0
  318. tnfr/utils/numeric.py +114 -0
  319. tnfr/utils/numeric.pyi +21 -0
  320. tnfr/validation/__init__.py +257 -0
  321. tnfr/validation/__init__.pyi +85 -0
  322. tnfr/validation/compatibility.py +460 -0
  323. tnfr/validation/compatibility.pyi +6 -0
  324. tnfr/validation/config.py +73 -0
  325. tnfr/validation/graph.py +139 -0
  326. tnfr/validation/graph.pyi +18 -0
  327. tnfr/validation/input_validation.py +755 -0
  328. tnfr/validation/invariants.py +712 -0
  329. tnfr/validation/rules.py +253 -0
  330. tnfr/validation/rules.pyi +44 -0
  331. tnfr/validation/runtime.py +279 -0
  332. tnfr/validation/runtime.pyi +28 -0
  333. tnfr/validation/sequence_validator.py +162 -0
  334. tnfr/validation/soft_filters.py +170 -0
  335. tnfr/validation/soft_filters.pyi +32 -0
  336. tnfr/validation/spectral.py +164 -0
  337. tnfr/validation/spectral.pyi +42 -0
  338. tnfr/validation/validator.py +1266 -0
  339. tnfr/validation/window.py +39 -0
  340. tnfr/validation/window.pyi +1 -0
  341. tnfr/visualization/__init__.py +98 -0
  342. tnfr/visualization/cascade_viz.py +256 -0
  343. tnfr/visualization/hierarchy.py +284 -0
  344. tnfr/visualization/sequence_plotter.py +784 -0
  345. tnfr/viz/__init__.py +60 -0
  346. tnfr/viz/matplotlib.py +278 -0
  347. tnfr/viz/matplotlib.pyi +35 -0
  348. tnfr-8.5.0.dist-info/METADATA +573 -0
  349. tnfr-8.5.0.dist-info/RECORD +353 -0
  350. tnfr-8.5.0.dist-info/entry_points.txt +3 -0
  351. tnfr-3.0.3.dist-info/licenses/LICENSE.txt → tnfr-8.5.0.dist-info/licenses/LICENSE.md +1 -1
  352. tnfr/constants.py +0 -183
  353. tnfr/dynamics.py +0 -543
  354. tnfr/helpers.py +0 -198
  355. tnfr/main.py +0 -37
  356. tnfr/operators.py +0 -296
  357. tnfr-3.0.3.dist-info/METADATA +0 -35
  358. tnfr-3.0.3.dist-info/RECORD +0 -13
  359. {tnfr-3.0.3.dist-info → tnfr-8.5.0.dist-info}/WHEEL +0 -0
  360. {tnfr-3.0.3.dist-info → tnfr-8.5.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ import numpy as np
4
+ from dataclasses import dataclass
5
+ from typing import Protocol
6
+ import numpy.typing as npt
7
+
8
+ __all__ = ["StateProjector", "BasicStateProjector"]
9
+
10
+ ComplexVector = npt.NDArray[np.complexfloating[np.float64, np.float64]]
11
+
12
+ class StateProjector(Protocol):
13
+ def __call__(
14
+ self,
15
+ epi: float,
16
+ nu_f: float,
17
+ theta: float,
18
+ dim: int,
19
+ rng: np.random.Generator | None = None,
20
+ ) -> ComplexVector: ...
21
+
22
+ @dataclass
23
+ class BasicStateProjector:
24
+ dtype: np.dtype[np.complexfloating[np.float64, np.float64]] = ...
25
+ atol: float = ...
26
+ def __call__(
27
+ self,
28
+ epi: float,
29
+ nu_f: float,
30
+ theta: float,
31
+ dim: int,
32
+ rng: np.random.Generator | None = None,
33
+ ) -> ComplexVector: ...
@@ -0,0 +1,182 @@
1
+ """Runtime helpers capturing TNFR spectral performance metrics."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Sequence
6
+
7
+ import numpy as np
8
+
9
+ from ..config import get_flags
10
+ from ..utils import get_logger
11
+ from .backend import ensure_array, ensure_numpy, get_backend
12
+ from .operators import CoherenceOperator, FrequencyOperator
13
+ from .spaces import HilbertSpace
14
+
15
+ __all__ = [
16
+ "normalized",
17
+ "coherence",
18
+ "frequency_positive",
19
+ "stable_unitary",
20
+ "coherence_expectation",
21
+ "frequency_expectation",
22
+ ]
23
+
24
+ LOGGER = get_logger(__name__)
25
+
26
+
27
+ def _as_vector(
28
+ state: Sequence[complex] | np.ndarray,
29
+ *,
30
+ dimension: int,
31
+ backend=None,
32
+ ) -> Any:
33
+ resolved_backend = backend or get_backend()
34
+ vector = ensure_array(state, dtype=np.complex128, backend=resolved_backend)
35
+ if (
36
+ getattr(vector, "ndim", len(getattr(vector, "shape", ()))) != 1
37
+ or vector.shape[0] != dimension
38
+ ):
39
+ raise ValueError(
40
+ "State vector dimension mismatch: "
41
+ f"expected ({dimension},), received {vector.shape!r}."
42
+ )
43
+ return vector
44
+
45
+
46
+ def _resolve_operator_backend(operator: CoherenceOperator) -> tuple[Any, Any]:
47
+ backend = getattr(operator, "backend", None) or get_backend()
48
+ matrix_backend = getattr(operator, "_matrix_backend", None)
49
+ if matrix_backend is None:
50
+ matrix_backend = ensure_array(
51
+ operator.matrix, dtype=np.complex128, backend=backend
52
+ )
53
+ return backend, matrix_backend
54
+
55
+
56
+ def _maybe_log(metric: str, payload: dict[str, object]) -> None:
57
+ if not get_flags().log_performance:
58
+ return
59
+ LOGGER.debug("%s: %s", metric, payload)
60
+
61
+
62
+ def normalized(
63
+ state: Sequence[complex] | np.ndarray,
64
+ hilbert_space: HilbertSpace,
65
+ *,
66
+ atol: float = 1e-9,
67
+ label: str = "state",
68
+ ) -> tuple[bool, float]:
69
+ """Return normalization status and norm for ``state``."""
70
+
71
+ backend = get_backend()
72
+ vector = _as_vector(state, dimension=hilbert_space.dimension, backend=backend)
73
+ norm_backend = backend.norm(vector)
74
+ norm = float(np.asarray(ensure_numpy(norm_backend, backend=backend)))
75
+ passed = bool(np.isclose(norm, 1.0, atol=atol))
76
+ _maybe_log("normalized", {"label": label, "norm": norm, "passed": passed})
77
+ return passed, float(norm)
78
+
79
+
80
+ def coherence_expectation(
81
+ state: Sequence[complex] | np.ndarray,
82
+ operator: CoherenceOperator,
83
+ *,
84
+ normalise: bool = True,
85
+ atol: float = 1e-9,
86
+ ) -> float:
87
+ """Return the coherence expectation value for ``state``."""
88
+
89
+ return float(operator.expectation(state, normalise=normalise, atol=atol))
90
+
91
+
92
+ def coherence(
93
+ state: Sequence[complex] | np.ndarray,
94
+ operator: CoherenceOperator,
95
+ threshold: float,
96
+ *,
97
+ normalise: bool = True,
98
+ atol: float = 1e-9,
99
+ label: str = "state",
100
+ ) -> tuple[bool, float]:
101
+ """Evaluate coherence expectation against ``threshold``."""
102
+
103
+ value = coherence_expectation(state, operator, normalise=normalise, atol=atol)
104
+ passed = bool(value + atol >= threshold)
105
+ _maybe_log(
106
+ "coherence",
107
+ {"label": label, "value": value, "threshold": threshold, "passed": passed},
108
+ )
109
+ return passed, value
110
+
111
+
112
+ def frequency_expectation(
113
+ state: Sequence[complex] | np.ndarray,
114
+ operator: FrequencyOperator,
115
+ *,
116
+ normalise: bool = True,
117
+ atol: float = 1e-9,
118
+ ) -> float:
119
+ """Return the structural frequency projection for ``state``."""
120
+
121
+ return float(operator.project_frequency(state, normalise=normalise, atol=atol))
122
+
123
+
124
+ def frequency_positive(
125
+ state: Sequence[complex] | np.ndarray,
126
+ operator: FrequencyOperator,
127
+ *,
128
+ normalise: bool = True,
129
+ enforce: bool = True,
130
+ atol: float = 1e-9,
131
+ label: str = "state",
132
+ ) -> dict[str, float | bool]:
133
+ """Return summary ensuring structural frequency remains non-negative."""
134
+
135
+ spectrum = operator.spectrum()
136
+ spectrum_psd = bool(operator.is_positive_semidefinite(atol=atol))
137
+ value = frequency_expectation(state, operator, normalise=normalise, atol=atol)
138
+ projection_ok = bool(value + atol >= 0.0)
139
+ passed = bool(spectrum_psd and (projection_ok or not enforce))
140
+ summary = {
141
+ "passed": passed,
142
+ "value": value,
143
+ "enforce": enforce,
144
+ "spectrum_psd": spectrum_psd,
145
+ "spectrum_min": float(np.min(spectrum)) if spectrum.size else float("inf"),
146
+ "projection_passed": projection_ok,
147
+ }
148
+ _maybe_log("frequency_positive", {"label": label, **summary})
149
+ return summary
150
+
151
+
152
+ def stable_unitary(
153
+ state: Sequence[complex] | np.ndarray,
154
+ operator: CoherenceOperator,
155
+ hilbert_space: HilbertSpace,
156
+ *,
157
+ normalise: bool = True,
158
+ atol: float = 1e-9,
159
+ label: str = "state",
160
+ ) -> tuple[bool, float]:
161
+ """Return whether a one-step unitary preserves the Hilbert norm."""
162
+
163
+ backend, matrix_backend = _resolve_operator_backend(operator)
164
+ vector = _as_vector(state, dimension=hilbert_space.dimension, backend=backend)
165
+ if normalise:
166
+ norm_backend = backend.norm(vector)
167
+ norm = float(np.asarray(ensure_numpy(norm_backend, backend=backend)))
168
+ if np.isclose(norm, 0.0, atol=atol):
169
+ raise ValueError("Cannot normalise a null state vector.")
170
+ vector = vector / norm
171
+ generator = -1j * matrix_backend
172
+ unitary = backend.matrix_exp(generator)
173
+ evolved_backend = backend.matmul(unitary, vector[..., None]).reshape(
174
+ (hilbert_space.dimension,)
175
+ )
176
+ evolved = np.asarray(ensure_numpy(evolved_backend, backend=backend))
177
+ norm_after = hilbert_space.norm(evolved)
178
+ passed = bool(np.isclose(norm_after, 1.0, atol=atol))
179
+ _maybe_log(
180
+ "stable_unitary", {"label": label, "norm_after": norm_after, "passed": passed}
181
+ )
182
+ return passed, float(norm_after)
@@ -0,0 +1,64 @@
1
+ from __future__ import annotations
2
+
3
+ import numpy as np
4
+ from .operators import CoherenceOperator, FrequencyOperator
5
+ from .spaces import HilbertSpace
6
+ from typing import Sequence
7
+
8
+ __all__ = [
9
+ "normalized",
10
+ "coherence",
11
+ "frequency_positive",
12
+ "stable_unitary",
13
+ "coherence_expectation",
14
+ "frequency_expectation",
15
+ ]
16
+
17
+ def normalized(
18
+ state: Sequence[complex] | np.ndarray,
19
+ hilbert_space: HilbertSpace,
20
+ *,
21
+ atol: float = 1e-09,
22
+ label: str = "state",
23
+ ) -> tuple[bool, float]: ...
24
+ def coherence_expectation(
25
+ state: Sequence[complex] | np.ndarray,
26
+ operator: CoherenceOperator,
27
+ *,
28
+ normalise: bool = True,
29
+ atol: float = 1e-09,
30
+ ) -> float: ...
31
+ def coherence(
32
+ state: Sequence[complex] | np.ndarray,
33
+ operator: CoherenceOperator,
34
+ threshold: float,
35
+ *,
36
+ normalise: bool = True,
37
+ atol: float = 1e-09,
38
+ label: str = "state",
39
+ ) -> tuple[bool, float]: ...
40
+ def frequency_expectation(
41
+ state: Sequence[complex] | np.ndarray,
42
+ operator: FrequencyOperator,
43
+ *,
44
+ normalise: bool = True,
45
+ atol: float = 1e-09,
46
+ ) -> float: ...
47
+ def frequency_positive(
48
+ state: Sequence[complex] | np.ndarray,
49
+ operator: FrequencyOperator,
50
+ *,
51
+ normalise: bool = True,
52
+ enforce: bool = True,
53
+ atol: float = 1e-09,
54
+ label: str = "state",
55
+ ) -> dict[str, float | bool]: ...
56
+ def stable_unitary(
57
+ state: Sequence[complex] | np.ndarray,
58
+ operator: CoherenceOperator,
59
+ hilbert_space: HilbertSpace,
60
+ *,
61
+ normalise: bool = True,
62
+ atol: float = 1e-09,
63
+ label: str = "state",
64
+ ) -> tuple[bool, float]: ...
@@ -0,0 +1,256 @@
1
+ """Mathematical spaces supporting the TNFR canonical paradigm."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Callable, Sequence
7
+
8
+ import numpy as np
9
+
10
+ from .epi import BEPIElement, _EPIValidators
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class HilbertSpace:
15
+ r"""Finite section of :math:`\ell^2(\mathbb{N}) \otimes L^2(\mathbb{R})`.
16
+
17
+ The space models the discrete spectral component of the TNFR paradigm. The
18
+ canonical orthonormal basis corresponds to the standard coordinate vectors
19
+ and the inner product is sesquilinear, implemented through
20
+ :func:`numpy.vdot`. Projection returns expansion coefficients for any
21
+ supplied orthonormal basis.
22
+ """
23
+
24
+ dimension: int
25
+ dtype: np.dtype = np.complex128
26
+
27
+ def __post_init__(self) -> None:
28
+ if self.dimension <= 0:
29
+ raise ValueError("Hilbert spaces require a positive dimension.")
30
+
31
+ @property
32
+ def basis(self) -> np.ndarray:
33
+ """Return the canonical orthonormal basis as identity vectors."""
34
+
35
+ return np.eye(self.dimension, dtype=self.dtype)
36
+
37
+ def _as_vector(self, value: Sequence[complex] | np.ndarray) -> np.ndarray:
38
+ vector = np.asarray(value, dtype=self.dtype)
39
+ if vector.shape != (self.dimension,):
40
+ raise ValueError(
41
+ f"Vector must have shape ({self.dimension},), got {vector.shape!r}."
42
+ )
43
+ return vector
44
+
45
+ def inner_product(
46
+ self,
47
+ vector_a: Sequence[complex] | np.ndarray,
48
+ vector_b: Sequence[complex] | np.ndarray,
49
+ ) -> complex:
50
+ """Compute the sesquilinear inner product ``⟨a, b⟩``."""
51
+
52
+ vec_a = self._as_vector(vector_a)
53
+ vec_b = self._as_vector(vector_b)
54
+ return np.vdot(vec_a, vec_b)
55
+
56
+ def norm(self, vector: Sequence[complex] | np.ndarray) -> float:
57
+ """Return the Hilbert norm induced by the inner product."""
58
+
59
+ value = self.inner_product(vector, vector)
60
+ magnitude = max(value.real, 0.0)
61
+ return float(np.sqrt(magnitude))
62
+
63
+ def is_normalized(
64
+ self, vector: Sequence[complex] | np.ndarray, *, atol: float = 1e-9
65
+ ) -> bool:
66
+ """Check whether a vector has unit norm within a tolerance."""
67
+
68
+ return np.isclose(self.norm(vector), 1.0, atol=atol)
69
+
70
+ def _validate_basis(
71
+ self, basis: Sequence[Sequence[complex] | np.ndarray]
72
+ ) -> np.ndarray:
73
+ basis_list = list(basis)
74
+ if len(basis_list) == 0:
75
+ raise ValueError("An orthonormal basis must contain at least one vector.")
76
+
77
+ basis_vectors = [self._as_vector(vector) for vector in basis_list]
78
+ matrix = np.vstack(basis_vectors)
79
+ gram = matrix @ matrix.conj().T
80
+ identity = np.eye(matrix.shape[0], dtype=self.dtype)
81
+ if not np.allclose(gram, identity, atol=1e-10):
82
+ raise ValueError("Provided basis is not orthonormal within tolerance.")
83
+ return matrix
84
+
85
+ def project(
86
+ self,
87
+ vector: Sequence[complex] | np.ndarray,
88
+ basis: Sequence[Sequence[complex] | np.ndarray] | None = None,
89
+ ) -> np.ndarray:
90
+ """Return coefficients ``⟨b_k|ψ⟩`` for the chosen orthonormal basis."""
91
+
92
+ vec = self._as_vector(vector)
93
+ if basis is None:
94
+ return vec.astype(self.dtype, copy=True)
95
+
96
+ basis_matrix = self._validate_basis(basis)
97
+ coefficients = basis_matrix.conj() @ vec
98
+ return coefficients.astype(self.dtype, copy=False)
99
+
100
+
101
+ class BanachSpaceEPI(_EPIValidators):
102
+ r"""Banach space for :math:`C^0([0, 1],\mathbb{C}) \oplus \ell^2(\mathbb{N})`.
103
+
104
+ Elements are represented by a pair ``(f, a)`` where ``f`` samples the
105
+ continuous field over a uniform grid ``x_grid`` and ``a`` is the discrete
106
+ spectral tail. The coherence norm combines the supremum of ``f``, the
107
+ :math:`\ell^2` norm of ``a`` and a derivative-based functional capturing
108
+ the local stability of ``f``.
109
+ """
110
+
111
+ def element(
112
+ self,
113
+ f_continuous: Sequence[complex] | np.ndarray,
114
+ a_discrete: Sequence[complex] | np.ndarray,
115
+ *,
116
+ x_grid: Sequence[float] | np.ndarray,
117
+ ) -> BEPIElement:
118
+ """Create a :class:`~tnfr.mathematics.epi.BEPIElement` with validated data."""
119
+
120
+ self.validate_domain(f_continuous, a_discrete, x_grid)
121
+ return BEPIElement(f_continuous, a_discrete, x_grid)
122
+
123
+ def zero_element(
124
+ self,
125
+ *,
126
+ continuous_size: int,
127
+ discrete_size: int,
128
+ x_grid: Sequence[float] | np.ndarray | None = None,
129
+ ) -> BEPIElement:
130
+ """Return the neutral element for the direct sum."""
131
+
132
+ if continuous_size < 2:
133
+ raise ValueError("continuous_size must be at least two samples.")
134
+ grid = (
135
+ np.asarray(x_grid, dtype=float)
136
+ if x_grid is not None
137
+ else np.linspace(0.0, 1.0, continuous_size, dtype=float)
138
+ )
139
+ zeros_f = np.zeros(continuous_size, dtype=np.complex128)
140
+ zeros_a = np.zeros(discrete_size, dtype=np.complex128)
141
+ return self.element(zeros_f, zeros_a, x_grid=grid)
142
+
143
+ def canonical_basis(
144
+ self,
145
+ *,
146
+ continuous_size: int,
147
+ discrete_size: int,
148
+ continuous_index: int = 0,
149
+ discrete_index: int = 0,
150
+ x_grid: Sequence[float] | np.ndarray | None = None,
151
+ ) -> BEPIElement:
152
+ """Generate a canonical basis element for the Banach space."""
153
+
154
+ if continuous_size < 2:
155
+ raise ValueError("continuous_size must be at least two samples.")
156
+ if not (0 <= continuous_index < continuous_size):
157
+ raise ValueError("continuous_index out of range.")
158
+ if not (0 <= discrete_index < discrete_size):
159
+ raise ValueError("discrete_index out of range.")
160
+
161
+ grid = (
162
+ np.asarray(x_grid, dtype=float)
163
+ if x_grid is not None
164
+ else np.linspace(0.0, 1.0, continuous_size, dtype=float)
165
+ )
166
+
167
+ f_vector = np.zeros(continuous_size, dtype=np.complex128)
168
+ a_vector = np.zeros(discrete_size, dtype=np.complex128)
169
+ f_vector[continuous_index] = 1.0 + 0.0j
170
+ a_vector[discrete_index] = 1.0 + 0.0j
171
+ return self.element(f_vector, a_vector, x_grid=grid)
172
+
173
+ def direct_sum(self, left: BEPIElement, right: BEPIElement) -> BEPIElement:
174
+ """Delegate direct sums to the underlying EPI element."""
175
+
176
+ return left.direct_sum(right)
177
+
178
+ def adjoint(self, element: BEPIElement) -> BEPIElement:
179
+ """Return the adjoint element of the supplied operand."""
180
+
181
+ return element.adjoint()
182
+
183
+ def compose(
184
+ self,
185
+ element: BEPIElement,
186
+ transform: Callable[[np.ndarray], np.ndarray],
187
+ *,
188
+ spectral_transform: Callable[[np.ndarray], np.ndarray] | None = None,
189
+ ) -> BEPIElement:
190
+ """Compose an element with the provided transforms."""
191
+
192
+ return element.compose(transform, spectral_transform=spectral_transform)
193
+
194
+ def tensor_with_hilbert(
195
+ self,
196
+ element: BEPIElement,
197
+ hilbert_space: HilbertSpace,
198
+ vector: Sequence[complex] | np.ndarray | None = None,
199
+ ) -> np.ndarray:
200
+ """Compute the tensor product against a :class:`HilbertSpace` vector."""
201
+
202
+ raw_vector = hilbert_space.basis[0] if vector is None else vector
203
+ hilbert_vector = hilbert_space._as_vector(
204
+ raw_vector
205
+ ) # pylint: disable=protected-access
206
+ return element.tensor(hilbert_vector)
207
+
208
+ def compute_coherence_functional(
209
+ self,
210
+ f_continuous: Sequence[complex] | np.ndarray,
211
+ x_grid: Sequence[float] | np.ndarray,
212
+ ) -> float:
213
+ r"""Approximate :math:`\int |f'|^2 dx / (1 + \int |f|^2 dx)`."""
214
+
215
+ f_array, _, grid = self.validate_domain(
216
+ f_continuous, np.array([0.0], dtype=np.complex128), x_grid
217
+ )
218
+ if grid is None:
219
+ raise ValueError("x_grid must be provided for coherence evaluations.")
220
+
221
+ derivative = np.gradient(
222
+ f_array,
223
+ grid,
224
+ edge_order=2 if f_array.size > 2 else 1,
225
+ )
226
+ numerator = np.trapz(np.abs(derivative) ** 2, grid)
227
+ denominator = 1.0 + np.trapz(np.abs(f_array) ** 2, grid)
228
+ if denominator <= 0:
229
+ raise ValueError("Denominator of coherence functional must be positive.")
230
+ return float(np.real_if_close(numerator / denominator))
231
+
232
+ def coherence_norm(
233
+ self,
234
+ f_continuous: Sequence[complex] | np.ndarray,
235
+ a_discrete: Sequence[complex] | np.ndarray,
236
+ *,
237
+ x_grid: Sequence[float] | np.ndarray,
238
+ alpha: float = 1.0,
239
+ beta: float = 1.0,
240
+ gamma: float = 1.0,
241
+ ) -> float:
242
+ """Return ``α‖f‖_∞ + β‖a‖_2 + γ CF(f)`` for positive weights."""
243
+
244
+ if alpha <= 0 or beta <= 0 or gamma <= 0:
245
+ raise ValueError("alpha, beta and gamma must be strictly positive.")
246
+
247
+ f_array, a_array, grid = self.validate_domain(f_continuous, a_discrete, x_grid)
248
+ if grid is None:
249
+ raise ValueError("x_grid must be supplied when evaluating the norm.")
250
+
251
+ sup_norm = float(np.max(np.abs(f_array))) if f_array.size else 0.0
252
+ l2_norm = float(np.linalg.norm(a_array))
253
+ coherence_functional = self.compute_coherence_functional(f_array, grid)
254
+
255
+ value = alpha * sup_norm + beta * l2_norm + gamma * coherence_functional
256
+ return float(np.real_if_close(value))
@@ -0,0 +1,83 @@
1
+ from __future__ import annotations
2
+
3
+ import numpy as np
4
+ from .epi import BEPIElement as BEPIElement, _EPIValidators
5
+ from dataclasses import dataclass
6
+ from typing import Callable, Sequence
7
+
8
+ @dataclass(frozen=True)
9
+ class HilbertSpace:
10
+ dimension: int
11
+ dtype: np.dtype = ...
12
+ def __post_init__(self) -> None: ...
13
+ @property
14
+ def basis(self) -> np.ndarray: ...
15
+ def inner_product(
16
+ self,
17
+ vector_a: Sequence[complex] | np.ndarray,
18
+ vector_b: Sequence[complex] | np.ndarray,
19
+ ) -> complex: ...
20
+ def norm(self, vector: Sequence[complex] | np.ndarray) -> float: ...
21
+ def is_normalized(
22
+ self, vector: Sequence[complex] | np.ndarray, *, atol: float = 1e-09
23
+ ) -> bool: ...
24
+ def project(
25
+ self,
26
+ vector: Sequence[complex] | np.ndarray,
27
+ basis: Sequence[Sequence[complex] | np.ndarray] | None = None,
28
+ ) -> np.ndarray: ...
29
+
30
+ class BanachSpaceEPI(_EPIValidators):
31
+ def element(
32
+ self,
33
+ f_continuous: Sequence[complex] | np.ndarray,
34
+ a_discrete: Sequence[complex] | np.ndarray,
35
+ *,
36
+ x_grid: Sequence[float] | np.ndarray,
37
+ ) -> BEPIElement: ...
38
+ def zero_element(
39
+ self,
40
+ *,
41
+ continuous_size: int,
42
+ discrete_size: int,
43
+ x_grid: Sequence[float] | np.ndarray | None = None,
44
+ ) -> BEPIElement: ...
45
+ def canonical_basis(
46
+ self,
47
+ *,
48
+ continuous_size: int,
49
+ discrete_size: int,
50
+ continuous_index: int = 0,
51
+ discrete_index: int = 0,
52
+ x_grid: Sequence[float] | np.ndarray | None = None,
53
+ ) -> BEPIElement: ...
54
+ def direct_sum(self, left: BEPIElement, right: BEPIElement) -> BEPIElement: ...
55
+ def adjoint(self, element: BEPIElement) -> BEPIElement: ...
56
+ def compose(
57
+ self,
58
+ element: BEPIElement,
59
+ transform: Callable[[np.ndarray], np.ndarray],
60
+ *,
61
+ spectral_transform: Callable[[np.ndarray], np.ndarray] | None = None,
62
+ ) -> BEPIElement: ...
63
+ def tensor_with_hilbert(
64
+ self,
65
+ element: BEPIElement,
66
+ hilbert_space: HilbertSpace,
67
+ vector: Sequence[complex] | np.ndarray | None = None,
68
+ ) -> np.ndarray: ...
69
+ def compute_coherence_functional(
70
+ self,
71
+ f_continuous: Sequence[complex] | np.ndarray,
72
+ x_grid: Sequence[float] | np.ndarray,
73
+ ) -> float: ...
74
+ def coherence_norm(
75
+ self,
76
+ f_continuous: Sequence[complex] | np.ndarray,
77
+ a_discrete: Sequence[complex] | np.ndarray,
78
+ *,
79
+ x_grid: Sequence[float] | np.ndarray,
80
+ alpha: float = 1.0,
81
+ beta: float = 1.0,
82
+ gamma: float = 1.0,
83
+ ) -> float: ...