tnfr 4.5.2__py3-none-any.whl → 7.0.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 (195) hide show
  1. tnfr/__init__.py +275 -51
  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 +117 -31
  8. tnfr/alias.pyi +108 -0
  9. tnfr/cache.py +6 -572
  10. tnfr/cache.pyi +16 -0
  11. tnfr/callback_utils.py +16 -38
  12. tnfr/callback_utils.pyi +79 -0
  13. tnfr/cli/__init__.py +34 -14
  14. tnfr/cli/__init__.pyi +26 -0
  15. tnfr/cli/arguments.py +211 -28
  16. tnfr/cli/arguments.pyi +27 -0
  17. tnfr/cli/execution.py +470 -50
  18. tnfr/cli/execution.pyi +70 -0
  19. tnfr/cli/utils.py +18 -3
  20. tnfr/cli/utils.pyi +8 -0
  21. tnfr/config/__init__.py +13 -0
  22. tnfr/config/__init__.pyi +10 -0
  23. tnfr/{constants_glyphs.py → config/constants.py} +26 -20
  24. tnfr/config/constants.pyi +12 -0
  25. tnfr/config/feature_flags.py +83 -0
  26. tnfr/{config.py → config/init.py} +11 -7
  27. tnfr/config/init.pyi +8 -0
  28. tnfr/config/operator_names.py +93 -0
  29. tnfr/config/operator_names.pyi +28 -0
  30. tnfr/config/presets.py +84 -0
  31. tnfr/config/presets.pyi +7 -0
  32. tnfr/constants/__init__.py +80 -29
  33. tnfr/constants/__init__.pyi +92 -0
  34. tnfr/constants/aliases.py +31 -0
  35. tnfr/constants/core.py +4 -4
  36. tnfr/constants/core.pyi +17 -0
  37. tnfr/constants/init.py +1 -1
  38. tnfr/constants/init.pyi +12 -0
  39. tnfr/constants/metric.py +7 -15
  40. tnfr/constants/metric.pyi +19 -0
  41. tnfr/dynamics/__init__.py +165 -633
  42. tnfr/dynamics/__init__.pyi +82 -0
  43. tnfr/dynamics/adaptation.py +267 -0
  44. tnfr/dynamics/aliases.py +23 -0
  45. tnfr/dynamics/coordination.py +385 -0
  46. tnfr/dynamics/dnfr.py +2283 -400
  47. tnfr/dynamics/dnfr.pyi +24 -0
  48. tnfr/dynamics/integrators.py +406 -98
  49. tnfr/dynamics/integrators.pyi +34 -0
  50. tnfr/dynamics/runtime.py +881 -0
  51. tnfr/dynamics/sampling.py +10 -5
  52. tnfr/dynamics/sampling.pyi +7 -0
  53. tnfr/dynamics/selectors.py +719 -0
  54. tnfr/execution.py +70 -48
  55. tnfr/execution.pyi +45 -0
  56. tnfr/flatten.py +13 -9
  57. tnfr/flatten.pyi +21 -0
  58. tnfr/gamma.py +66 -53
  59. tnfr/gamma.pyi +34 -0
  60. tnfr/glyph_history.py +110 -52
  61. tnfr/glyph_history.pyi +35 -0
  62. tnfr/glyph_runtime.py +16 -0
  63. tnfr/glyph_runtime.pyi +9 -0
  64. tnfr/immutable.py +69 -28
  65. tnfr/immutable.pyi +34 -0
  66. tnfr/initialization.py +16 -16
  67. tnfr/initialization.pyi +65 -0
  68. tnfr/io.py +6 -240
  69. tnfr/io.pyi +16 -0
  70. tnfr/locking.pyi +7 -0
  71. tnfr/mathematics/__init__.py +81 -0
  72. tnfr/mathematics/backend.py +426 -0
  73. tnfr/mathematics/dynamics.py +398 -0
  74. tnfr/mathematics/epi.py +254 -0
  75. tnfr/mathematics/generators.py +222 -0
  76. tnfr/mathematics/metrics.py +119 -0
  77. tnfr/mathematics/operators.py +233 -0
  78. tnfr/mathematics/operators_factory.py +71 -0
  79. tnfr/mathematics/projection.py +78 -0
  80. tnfr/mathematics/runtime.py +173 -0
  81. tnfr/mathematics/spaces.py +247 -0
  82. tnfr/mathematics/transforms.py +292 -0
  83. tnfr/metrics/__init__.py +10 -10
  84. tnfr/metrics/__init__.pyi +20 -0
  85. tnfr/metrics/coherence.py +993 -324
  86. tnfr/metrics/common.py +23 -16
  87. tnfr/metrics/common.pyi +46 -0
  88. tnfr/metrics/core.py +251 -35
  89. tnfr/metrics/core.pyi +13 -0
  90. tnfr/metrics/diagnosis.py +708 -111
  91. tnfr/metrics/diagnosis.pyi +85 -0
  92. tnfr/metrics/export.py +27 -15
  93. tnfr/metrics/glyph_timing.py +232 -42
  94. tnfr/metrics/reporting.py +33 -22
  95. tnfr/metrics/reporting.pyi +12 -0
  96. tnfr/metrics/sense_index.py +987 -43
  97. tnfr/metrics/sense_index.pyi +9 -0
  98. tnfr/metrics/trig.py +214 -23
  99. tnfr/metrics/trig.pyi +13 -0
  100. tnfr/metrics/trig_cache.py +115 -22
  101. tnfr/metrics/trig_cache.pyi +10 -0
  102. tnfr/node.py +542 -136
  103. tnfr/node.pyi +178 -0
  104. tnfr/observers.py +152 -35
  105. tnfr/observers.pyi +31 -0
  106. tnfr/ontosim.py +23 -19
  107. tnfr/ontosim.pyi +28 -0
  108. tnfr/operators/__init__.py +601 -82
  109. tnfr/operators/__init__.pyi +45 -0
  110. tnfr/operators/definitions.py +513 -0
  111. tnfr/operators/definitions.pyi +78 -0
  112. tnfr/operators/grammar.py +760 -0
  113. tnfr/operators/jitter.py +107 -38
  114. tnfr/operators/jitter.pyi +11 -0
  115. tnfr/operators/registry.py +75 -0
  116. tnfr/operators/registry.pyi +13 -0
  117. tnfr/operators/remesh.py +149 -88
  118. tnfr/py.typed +0 -0
  119. tnfr/rng.py +46 -143
  120. tnfr/rng.pyi +14 -0
  121. tnfr/schemas/__init__.py +8 -0
  122. tnfr/schemas/grammar.json +94 -0
  123. tnfr/selector.py +25 -19
  124. tnfr/selector.pyi +19 -0
  125. tnfr/sense.py +72 -62
  126. tnfr/sense.pyi +23 -0
  127. tnfr/structural.py +522 -262
  128. tnfr/structural.pyi +69 -0
  129. tnfr/telemetry/__init__.py +35 -0
  130. tnfr/telemetry/cache_metrics.py +226 -0
  131. tnfr/telemetry/nu_f.py +423 -0
  132. tnfr/telemetry/nu_f.pyi +123 -0
  133. tnfr/telemetry/verbosity.py +37 -0
  134. tnfr/tokens.py +1 -3
  135. tnfr/tokens.pyi +36 -0
  136. tnfr/trace.py +270 -113
  137. tnfr/trace.pyi +40 -0
  138. tnfr/types.py +574 -6
  139. tnfr/types.pyi +331 -0
  140. tnfr/units.py +69 -0
  141. tnfr/units.pyi +16 -0
  142. tnfr/utils/__init__.py +217 -0
  143. tnfr/utils/__init__.pyi +202 -0
  144. tnfr/utils/cache.py +2395 -0
  145. tnfr/utils/cache.pyi +468 -0
  146. tnfr/utils/chunks.py +104 -0
  147. tnfr/utils/chunks.pyi +21 -0
  148. tnfr/{collections_utils.py → utils/data.py} +147 -90
  149. tnfr/utils/data.pyi +64 -0
  150. tnfr/utils/graph.py +85 -0
  151. tnfr/utils/graph.pyi +10 -0
  152. tnfr/utils/init.py +770 -0
  153. tnfr/utils/init.pyi +78 -0
  154. tnfr/utils/io.py +456 -0
  155. tnfr/{helpers → utils}/numeric.py +51 -24
  156. tnfr/utils/numeric.pyi +21 -0
  157. tnfr/validation/__init__.py +113 -0
  158. tnfr/validation/__init__.pyi +77 -0
  159. tnfr/validation/compatibility.py +95 -0
  160. tnfr/validation/compatibility.pyi +6 -0
  161. tnfr/validation/grammar.py +71 -0
  162. tnfr/validation/grammar.pyi +40 -0
  163. tnfr/validation/graph.py +138 -0
  164. tnfr/validation/graph.pyi +17 -0
  165. tnfr/validation/rules.py +281 -0
  166. tnfr/validation/rules.pyi +55 -0
  167. tnfr/validation/runtime.py +263 -0
  168. tnfr/validation/runtime.pyi +31 -0
  169. tnfr/validation/soft_filters.py +170 -0
  170. tnfr/validation/soft_filters.pyi +37 -0
  171. tnfr/validation/spectral.py +159 -0
  172. tnfr/validation/spectral.pyi +46 -0
  173. tnfr/validation/syntax.py +40 -0
  174. tnfr/validation/syntax.pyi +10 -0
  175. tnfr/validation/window.py +39 -0
  176. tnfr/validation/window.pyi +1 -0
  177. tnfr/viz/__init__.py +9 -0
  178. tnfr/viz/matplotlib.py +246 -0
  179. tnfr-7.0.0.dist-info/METADATA +179 -0
  180. tnfr-7.0.0.dist-info/RECORD +185 -0
  181. {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/licenses/LICENSE.md +1 -1
  182. tnfr/grammar.py +0 -344
  183. tnfr/graph_utils.py +0 -84
  184. tnfr/helpers/__init__.py +0 -71
  185. tnfr/import_utils.py +0 -228
  186. tnfr/json_utils.py +0 -162
  187. tnfr/logging_utils.py +0 -116
  188. tnfr/presets.py +0 -60
  189. tnfr/validators.py +0 -84
  190. tnfr/value_utils.py +0 -59
  191. tnfr-4.5.2.dist-info/METADATA +0 -379
  192. tnfr-4.5.2.dist-info/RECORD +0 -67
  193. {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/WHEEL +0 -0
  194. {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/entry_points.txt +0 -0
  195. {tnfr-4.5.2.dist-info → tnfr-7.0.0.dist-info}/top_level.txt +0 -0
tnfr/cli/execution.pyi ADDED
@@ -0,0 +1,70 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+ from typing import Any, Optional
6
+
7
+ import networkx as nx
8
+
9
+ from ..config import apply_config
10
+ from ..config.presets import get_preset
11
+ from ..constants import METRIC_DEFAULTS
12
+ from ..dynamics import (
13
+ default_glyph_selector,
14
+ parametric_glyph_selector,
15
+ run,
16
+ validate_canon,
17
+ )
18
+ from ..execution import CANONICAL_PRESET_NAME, play, seq
19
+ from ..flatten import parse_program_tokens
20
+ from ..glyph_history import ensure_history
21
+ from ..metrics import (
22
+ build_metrics_summary,
23
+ export_metrics,
24
+ glyph_top,
25
+ register_metrics_callbacks,
26
+ )
27
+ from ..metrics.core import _metrics_step
28
+ from ..ontosim import prepare_network
29
+ from ..sense import register_sigma_callback
30
+ from ..trace import register_trace
31
+ from ..types import Glyph, ProgramTokens
32
+ from ..utils import (
33
+ StructuredFileError,
34
+ get_logger,
35
+ json_dumps,
36
+ read_structured_file,
37
+ safe_write,
38
+ )
39
+ from .arguments import _args_to_dict
40
+
41
+ DEFAULT_SUMMARY_SERIES_LIMIT: int
42
+ logger: Any
43
+
44
+ def _save_json(path: str, data: Any) -> None: ...
45
+ def _attach_callbacks(G: nx.Graph) -> None: ...
46
+ def _persist_history(G: nx.Graph, args: argparse.Namespace) -> None: ...
47
+ def build_basic_graph(args: argparse.Namespace) -> nx.Graph: ...
48
+ def apply_cli_config(G: nx.Graph, args: argparse.Namespace) -> None: ...
49
+ def register_callbacks_and_observer(G: nx.Graph) -> None: ...
50
+ def _build_graph_from_args(args: argparse.Namespace) -> nx.Graph: ...
51
+ def _load_sequence(path: Path) -> ProgramTokens: ...
52
+ def resolve_program(
53
+ args: argparse.Namespace, default: Optional[ProgramTokens] = ...
54
+ ) -> Optional[ProgramTokens]: ...
55
+ def run_program(
56
+ G: Optional[nx.Graph],
57
+ program: Optional[ProgramTokens],
58
+ args: argparse.Namespace,
59
+ ) -> nx.Graph: ...
60
+ def _run_cli_program(
61
+ args: argparse.Namespace,
62
+ *,
63
+ default_program: Optional[ProgramTokens] = ...,
64
+ graph: Optional[nx.Graph] = ...,
65
+ ) -> tuple[int, Optional[nx.Graph]]: ...
66
+ def _log_run_summaries(G: nx.Graph, args: argparse.Namespace) -> None: ...
67
+ def cmd_run(args: argparse.Namespace) -> int: ...
68
+ def cmd_sequence(args: argparse.Namespace) -> int: ...
69
+ def cmd_metrics(args: argparse.Namespace) -> int: ...
70
+ def cmd_profile_si(args: argparse.Namespace) -> int: ...
tnfr/cli/utils.py CHANGED
@@ -2,8 +2,11 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from collections.abc import Iterable
5
6
  from typing import Any
6
7
 
8
+ from ..utils import normalize_optional_int
9
+
7
10
 
8
11
  def spec(opt: str, /, **kwargs: Any) -> tuple[str, dict[str, Any]]:
9
12
  """Create an argument specification pair.
@@ -27,10 +30,22 @@ def spec(opt: str, /, **kwargs: Any) -> tuple[str, dict[str, Any]]:
27
30
  """
28
31
 
29
32
  kwargs = dict(kwargs)
30
- kwargs.setdefault(
31
- "dest", opt.lstrip("-").replace("-", "_").replace(".", "_")
32
- )
33
+ kwargs.setdefault("dest", opt.lstrip("-").replace("-", "_").replace(".", "_"))
33
34
  kwargs.setdefault("default", None)
34
35
  return opt, kwargs
35
36
 
36
37
 
38
+ def _parse_cli_variants(values: Iterable[Any] | None) -> list[int | None]:
39
+ """Return a stable list of integer/``None`` variants for the CLI options."""
40
+
41
+ if values is None:
42
+ return [None]
43
+ parsed: list[int | None] = []
44
+ seen: set[int | None] = set()
45
+ for raw in values:
46
+ coerced = normalize_optional_int(raw, strict=True)
47
+ if coerced in seen:
48
+ continue
49
+ seen.add(coerced)
50
+ parsed.append(coerced)
51
+ return parsed or [None]
tnfr/cli/utils.pyi ADDED
@@ -0,0 +1,8 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterable
4
+ from typing import Any
5
+
6
+ def spec(opt: str, /, **kwargs: Any) -> tuple[str, dict[str, Any]]: ...
7
+
8
+ def _parse_cli_variants(values: Iterable[Any] | None) -> list[int | None]: ...
@@ -0,0 +1,13 @@
1
+ """Configuration package for TNFR.
2
+
3
+ This package groups helpers and canonical defaults that orchestrate how
4
+ configuration payloads interact with the engine. The public API mirrors the
5
+ previous module level functions so downstream importers remain stable.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from .feature_flags import context_flags, get_flags
11
+ from .init import apply_config, load_config
12
+
13
+ __all__ = ("load_config", "apply_config", "get_flags", "context_flags")
@@ -0,0 +1,10 @@
1
+ from typing import Any
2
+
3
+ __all__: Any
4
+
5
+ def __getattr__(name: str) -> Any: ...
6
+
7
+ apply_config: Any
8
+ load_config: Any
9
+ get_flags: Any
10
+ context_flags: Any
@@ -1,4 +1,4 @@
1
- """Default glyphs."""
1
+ """Canonical glyph constants tied to configuration presets."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -6,10 +6,10 @@ import math
6
6
  from types import MappingProxyType
7
7
  from typing import Mapping
8
8
 
9
- from .types import Glyph
9
+ from ..types import Glyph
10
10
 
11
11
  # -------------------------
12
- # Orden canónico y clasificaciones funcionales
12
+ # Canonical order and functional classifications
13
13
  # -------------------------
14
14
 
15
15
  GLYPHS_CANONICAL: tuple[str, ...] = (
@@ -30,26 +30,31 @@ GLYPHS_CANONICAL: tuple[str, ...] = (
30
30
 
31
31
  GLYPHS_CANONICAL_SET: frozenset[str] = frozenset(GLYPHS_CANONICAL)
32
32
 
33
- ESTABILIZADORES = (
33
+ STABILIZERS: tuple[str, ...] = (
34
34
  Glyph.IL.value,
35
35
  Glyph.RA.value,
36
36
  Glyph.UM.value,
37
37
  Glyph.SHA.value,
38
38
  )
39
39
 
40
- DISRUPTIVOS = (
40
+ DISRUPTORS: tuple[str, ...] = (
41
41
  Glyph.OZ.value,
42
42
  Glyph.ZHIR.value,
43
43
  Glyph.NAV.value,
44
44
  Glyph.THOL.value,
45
45
  )
46
46
 
47
- # Mapa general de agrupaciones glíficas para referencia cruzada.
47
+ # General map of glyph groupings for cross-reference.
48
+ #
49
+ # Spanish keys (``estabilizadores`` / ``disruptivos``) were removed in TNFR 7.0
50
+ # to keep the public surface English-only. Code that still referenced those
51
+ # identifiers must switch to the canonical ``stabilizers`` / ``disruptors``
52
+ # entries or maintain a private compatibility layer.
48
53
  GLYPH_GROUPS: Mapping[str, tuple[str, ...]] = MappingProxyType(
49
54
  {
50
- "estabilizadores": ESTABILIZADORES,
51
- "disruptivos": DISRUPTIVOS,
52
- # Grupos auxiliares para métricas morfosintácticas
55
+ "stabilizers": STABILIZERS,
56
+ "disruptors": DISRUPTORS,
57
+ # Auxiliary groups for morphosyntactic metrics
53
58
  "ID": (Glyph.OZ.value,),
54
59
  "CM": (Glyph.ZHIR.value, Glyph.NAV.value),
55
60
  "NE": (Glyph.IL.value, Glyph.THOL.value),
@@ -59,27 +64,28 @@ GLYPH_GROUPS: Mapping[str, tuple[str, ...]] = MappingProxyType(
59
64
  )
60
65
 
61
66
  # -------------------------
62
- # Mapa de ángulos glíficos
67
+ # Glyph angle map
63
68
  # -------------------------
64
69
 
65
- # Ángulos canónicos para todos los glyphs reconocidos. Se calculan a partir
66
- # del orden canónico y reglas de orientación para las categorías
67
- # "estabilizadores" y "disruptivos".
70
+ # Canonical angles for all recognised glyphs. They are computed from the
71
+ # canonical order and orientation rules for the "stabilizers" and
72
+ # "disruptors" categories.
68
73
 
69
74
 
70
75
  def _build_angle_map() -> dict[str, float]:
71
- """Construir el mapa de ángulos en el plano σ."""
76
+ """Build the angle map in the σ-plane."""
77
+
72
78
  step = 2 * math.pi / len(GLYPHS_CANONICAL)
73
79
  canonical = {g: i * step for i, g in enumerate(GLYPHS_CANONICAL)}
74
80
  angles = dict(canonical)
75
81
 
76
- # Reglas específicas de orientación
77
- for idx, g in enumerate(ESTABILIZADORES):
82
+ # Orientation rules
83
+ for idx, g in enumerate(STABILIZERS):
78
84
  angles[g] = idx * math.pi / 4
79
- for idx, g in enumerate(DISRUPTIVOS):
85
+ for idx, g in enumerate(DISRUPTORS):
80
86
  angles[g] = math.pi + idx * math.pi / 4
81
87
 
82
- # Excepciones manuales
88
+ # Manual exceptions
83
89
  angles[Glyph.VAL.value] = canonical[Glyph.RA.value]
84
90
  angles[Glyph.NUL.value] = canonical[Glyph.ZHIR.value]
85
91
  angles[Glyph.AL.value] = 0.0
@@ -91,8 +97,8 @@ ANGLE_MAP: Mapping[str, float] = MappingProxyType(_build_angle_map())
91
97
  __all__ = (
92
98
  "GLYPHS_CANONICAL",
93
99
  "GLYPHS_CANONICAL_SET",
94
- "ESTABILIZADORES",
95
- "DISRUPTIVOS",
100
+ "STABILIZERS",
101
+ "DISRUPTORS",
96
102
  "GLYPH_GROUPS",
97
103
  "ANGLE_MAP",
98
104
  )
@@ -0,0 +1,12 @@
1
+ from typing import Any
2
+
3
+ __all__: Any
4
+
5
+ def __getattr__(name: str) -> Any: ...
6
+
7
+ ANGLE_MAP: Any
8
+ DISRUPTORS: Any
9
+ STABILIZERS: Any
10
+ GLYPHS_CANONICAL: Any
11
+ GLYPHS_CANONICAL_SET: Any
12
+ GLYPH_GROUPS: Any
@@ -0,0 +1,83 @@
1
+ """Math feature flag configuration helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from contextlib import contextmanager
7
+ from dataclasses import dataclass, replace
8
+ from typing import Iterator
9
+
10
+ __all__ = ("MathFeatureFlags", "get_flags", "context_flags")
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class MathFeatureFlags:
15
+ """Toggle optional mathematical behaviours in the engine."""
16
+
17
+ enable_math_validation: bool = False
18
+ enable_math_dynamics: bool = False
19
+ log_performance: bool = False
20
+ math_backend: str = "numpy"
21
+
22
+
23
+ _TRUE_VALUES = {"1", "true", "on", "yes", "y", "t"}
24
+ _FALSE_VALUES = {"0", "false", "off", "no", "n", "f"}
25
+
26
+ _BASE_FLAGS: MathFeatureFlags | None = None
27
+ _FLAGS_STACK: list[MathFeatureFlags] = []
28
+
29
+
30
+ def _parse_env_flag(name: str, default: bool) -> bool:
31
+ value = os.getenv(name)
32
+ if value is None:
33
+ return default
34
+ lowered = value.strip().lower()
35
+ if lowered in _TRUE_VALUES:
36
+ return True
37
+ if lowered in _FALSE_VALUES:
38
+ return False
39
+ return default
40
+
41
+
42
+ def _load_base_flags() -> MathFeatureFlags:
43
+ global _BASE_FLAGS
44
+ if _BASE_FLAGS is None:
45
+ backend = os.getenv("TNFR_MATH_BACKEND")
46
+ backend_choice = backend.strip() if backend else "numpy"
47
+ _BASE_FLAGS = MathFeatureFlags(
48
+ enable_math_validation=_parse_env_flag(
49
+ "TNFR_ENABLE_MATH_VALIDATION", False
50
+ ),
51
+ enable_math_dynamics=_parse_env_flag(
52
+ "TNFR_ENABLE_MATH_DYNAMICS", False
53
+ ),
54
+ log_performance=_parse_env_flag("TNFR_LOG_PERF", False),
55
+ math_backend=backend_choice or "numpy",
56
+ )
57
+ return _BASE_FLAGS
58
+
59
+
60
+ def get_flags() -> MathFeatureFlags:
61
+ """Return the currently active feature flags."""
62
+
63
+ if _FLAGS_STACK:
64
+ return _FLAGS_STACK[-1]
65
+ return _load_base_flags()
66
+
67
+
68
+ @contextmanager
69
+ def context_flags(**overrides: bool) -> Iterator[MathFeatureFlags]:
70
+ """Temporarily override math feature flags."""
71
+
72
+ invalid = set(overrides) - set(MathFeatureFlags.__annotations__)
73
+ if invalid:
74
+ invalid_names = ", ".join(sorted(invalid))
75
+ raise TypeError(f"Unknown flag overrides: {invalid_names}")
76
+
77
+ previous = get_flags()
78
+ next_flags = replace(previous, **overrides)
79
+ _FLAGS_STACK.append(next_flags)
80
+ try:
81
+ yield next_flags
82
+ finally:
83
+ _FLAGS_STACK.pop()
@@ -1,21 +1,23 @@
1
- """Configuration utilities."""
1
+ """Core configuration helpers."""
2
2
 
3
3
  from __future__ import annotations
4
- from typing import Any, TYPE_CHECKING
4
+
5
5
  from collections.abc import Mapping
6
6
  from pathlib import Path
7
- from .io import read_structured_file
7
+ from typing import TYPE_CHECKING, Any
8
8
 
9
- from .constants import inject_defaults
9
+ from ..constants import inject_defaults
10
+ from ..utils import read_structured_file
10
11
 
11
12
  if TYPE_CHECKING: # pragma: no cover - only for type checkers
12
- import networkx as nx # type: ignore[import-untyped]
13
+ import networkx as nx
13
14
 
14
15
  __all__ = ("load_config", "apply_config")
15
16
 
16
17
 
17
18
  def load_config(path: str | Path) -> Mapping[str, Any]:
18
19
  """Read a JSON/YAML file and return a mapping with parameters."""
20
+
19
21
  path_obj = path if isinstance(path, Path) else Path(path)
20
22
  data = read_structured_file(path_obj)
21
23
  if not isinstance(data, Mapping):
@@ -23,10 +25,12 @@ def load_config(path: str | Path) -> Mapping[str, Any]:
23
25
  return data
24
26
 
25
27
 
26
- def apply_config(G: nx.Graph, path: str | Path) -> None:
28
+ def apply_config(G: "nx.Graph", path: str | Path) -> None:
27
29
  """Inject parameters from ``path`` into ``G.graph``.
28
30
 
29
- Reuses :func:`inject_defaults` to keep canonical default semantics.
31
+ Reuses :func:`tnfr.constants.inject_defaults` to keep canonical default
32
+ semantics.
30
33
  """
34
+
31
35
  cfg = load_config(path)
32
36
  inject_defaults(G, cfg, override=True)
tnfr/config/init.pyi ADDED
@@ -0,0 +1,8 @@
1
+ from typing import Any
2
+
3
+ __all__: Any
4
+
5
+ def __getattr__(name: str) -> Any: ...
6
+
7
+ apply_config: Any
8
+ load_config: Any
@@ -0,0 +1,93 @@
1
+ """Canonical operator name constants and reusable sets."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ # Canonical operator identifiers (English tokens)
8
+ EMISSION = "emission"
9
+ RECEPTION = "reception"
10
+ COHERENCE = "coherence"
11
+ DISSONANCE = "dissonance"
12
+ COUPLING = "coupling"
13
+ RESONANCE = "resonance"
14
+ SILENCE = "silence"
15
+ EXPANSION = "expansion"
16
+ CONTRACTION = "contraction"
17
+ SELF_ORGANIZATION = "self_organization"
18
+ MUTATION = "mutation"
19
+ TRANSITION = "transition"
20
+ RECURSIVITY = "recursivity"
21
+
22
+
23
+ # Canonical collections -------------------------------------------------------
24
+
25
+ CANONICAL_OPERATOR_NAMES = frozenset(
26
+ {
27
+ EMISSION,
28
+ RECEPTION,
29
+ COHERENCE,
30
+ DISSONANCE,
31
+ COUPLING,
32
+ RESONANCE,
33
+ SILENCE,
34
+ EXPANSION,
35
+ CONTRACTION,
36
+ SELF_ORGANIZATION,
37
+ MUTATION,
38
+ TRANSITION,
39
+ RECURSIVITY,
40
+ }
41
+ )
42
+
43
+ ALL_OPERATOR_NAMES = CANONICAL_OPERATOR_NAMES
44
+ ENGLISH_OPERATOR_NAMES = CANONICAL_OPERATOR_NAMES
45
+
46
+ VALID_START_OPERATORS = frozenset({EMISSION, RECURSIVITY})
47
+ INTERMEDIATE_OPERATORS = frozenset({DISSONANCE, COUPLING, RESONANCE})
48
+ VALID_END_OPERATORS = frozenset({SILENCE, TRANSITION, RECURSIVITY})
49
+ SELF_ORGANIZATION_CLOSURES = frozenset({SILENCE, CONTRACTION})
50
+
51
+
52
+ def canonical_operator_name(name: str) -> str:
53
+ """Return the canonical operator token for ``name``."""
54
+
55
+ return name
56
+
57
+
58
+ def operator_display_name(name: str) -> str:
59
+ """Return the display label for ``name`` (currently the canonical token)."""
60
+
61
+ return canonical_operator_name(name)
62
+
63
+
64
+ __all__ = [
65
+ "EMISSION",
66
+ "RECEPTION",
67
+ "COHERENCE",
68
+ "DISSONANCE",
69
+ "COUPLING",
70
+ "RESONANCE",
71
+ "SILENCE",
72
+ "EXPANSION",
73
+ "CONTRACTION",
74
+ "SELF_ORGANIZATION",
75
+ "MUTATION",
76
+ "TRANSITION",
77
+ "RECURSIVITY",
78
+ "CANONICAL_OPERATOR_NAMES",
79
+ "ENGLISH_OPERATOR_NAMES",
80
+ "ALL_OPERATOR_NAMES",
81
+ "VALID_START_OPERATORS",
82
+ "INTERMEDIATE_OPERATORS",
83
+ "VALID_END_OPERATORS",
84
+ "SELF_ORGANIZATION_CLOSURES",
85
+ "canonical_operator_name",
86
+ "operator_display_name",
87
+ ]
88
+
89
+
90
+ def __getattr__(name: str) -> Any:
91
+ """Provide a consistent ``AttributeError`` when names are missing."""
92
+
93
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
@@ -0,0 +1,28 @@
1
+ from typing import Any
2
+
3
+ __all__: Any
4
+
5
+ def __getattr__(name: str) -> Any: ...
6
+
7
+ ALL_OPERATOR_NAMES: Any
8
+ CANONICAL_OPERATOR_NAMES: Any
9
+ COHERENCE: Any
10
+ CONTRACTION: Any
11
+ COUPLING: Any
12
+ DISSONANCE: Any
13
+ EMISSION: Any
14
+ ENGLISH_OPERATOR_NAMES: Any
15
+ EXPANSION: Any
16
+ INTERMEDIATE_OPERATORS: Any
17
+ MUTATION: Any
18
+ RECEPTION: Any
19
+ RECURSIVITY: Any
20
+ RESONANCE: Any
21
+ SELF_ORGANIZATION: Any
22
+ SELF_ORGANIZATION_CLOSURES: Any
23
+ SILENCE: Any
24
+ TRANSITION: Any
25
+ VALID_END_OPERATORS: Any
26
+ VALID_START_OPERATORS: Any
27
+ canonical_operator_name: Any
28
+ operator_display_name: Any
tnfr/config/presets.py ADDED
@@ -0,0 +1,84 @@
1
+ """Predefined TNFR configuration sequences.
2
+
3
+ Only the canonical English preset identifiers are recognised.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from ..execution import (
9
+ CANONICAL_PRESET_NAME,
10
+ CANONICAL_PROGRAM_TOKENS,
11
+ block,
12
+ seq,
13
+ wait,
14
+ )
15
+ from ..types import Glyph, PresetTokens
16
+
17
+ __all__ = (
18
+ "get_preset",
19
+ "PREFERRED_PRESET_NAMES",
20
+ "legacy_preset_guidance",
21
+ )
22
+
23
+
24
+ _PRIMARY_PRESETS: dict[str, PresetTokens] = {
25
+ "resonant_bootstrap": seq(
26
+ Glyph.AL,
27
+ Glyph.EN,
28
+ Glyph.IL,
29
+ Glyph.RA,
30
+ Glyph.VAL,
31
+ Glyph.UM,
32
+ wait(3),
33
+ Glyph.SHA,
34
+ ),
35
+ "contained_mutation": seq(
36
+ Glyph.AL,
37
+ Glyph.EN,
38
+ block(Glyph.OZ, Glyph.ZHIR, Glyph.IL, repeat=2),
39
+ Glyph.RA,
40
+ Glyph.SHA,
41
+ ),
42
+ "coupling_exploration": seq(
43
+ Glyph.AL,
44
+ Glyph.EN,
45
+ Glyph.IL,
46
+ Glyph.VAL,
47
+ Glyph.UM,
48
+ block(Glyph.OZ, Glyph.NAV, Glyph.IL, repeat=1),
49
+ Glyph.RA,
50
+ Glyph.SHA,
51
+ ),
52
+ "fractal_expand": seq(
53
+ block(Glyph.THOL, Glyph.VAL, Glyph.UM, repeat=2, close=Glyph.NUL),
54
+ Glyph.RA,
55
+ ),
56
+ "fractal_contract": seq(
57
+ block(Glyph.THOL, Glyph.NUL, Glyph.UM, repeat=2, close=Glyph.SHA),
58
+ Glyph.RA,
59
+ ),
60
+ CANONICAL_PRESET_NAME: list(CANONICAL_PROGRAM_TOKENS),
61
+ }
62
+
63
+ PREFERRED_PRESET_NAMES: tuple[str, ...] = tuple(_PRIMARY_PRESETS.keys())
64
+
65
+ _PRESETS: dict[str, PresetTokens] = {**_PRIMARY_PRESETS}
66
+
67
+
68
+ def legacy_preset_guidance(name: str) -> str | None:
69
+ """Return CLI guidance for preset lookups.
70
+
71
+ Legacy aliases were removed; the function now always returns ``None``.
72
+ ``name`` is accepted to preserve the public helper signature.
73
+ """
74
+
75
+ return None
76
+
77
+
78
+ def get_preset(name: str) -> PresetTokens:
79
+ """Return the preset token sequence identified by ``name``."""
80
+
81
+ try:
82
+ return _PRESETS[name]
83
+ except KeyError:
84
+ raise KeyError(f"Preset not found: {name}") from None
@@ -0,0 +1,7 @@
1
+ from typing import Any
2
+
3
+ __all__: Any
4
+
5
+ def __getattr__(name: str) -> Any: ...
6
+
7
+ get_preset: Any