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/callback_utils.py CHANGED
@@ -9,22 +9,20 @@ modify shared state.
9
9
 
10
10
  from __future__ import annotations
11
11
 
12
-
13
- from typing import Any, TypedDict
14
- from enum import Enum
12
+ import threading
13
+ import traceback
15
14
  from collections import defaultdict, deque
16
- from collections.abc import Callable, Mapping, Iterable
15
+ from collections.abc import Callable, Iterable, Mapping
16
+ from enum import Enum
17
+ from typing import Any
18
+
19
+ import networkx as nx
17
20
 
18
- import traceback
19
- import threading
20
- from .logging_utils import get_logger
21
21
  from .constants import DEFAULTS
22
22
  from .locking import get_lock
23
-
24
23
  from .trace import CallbackSpec
25
- from .collections_utils import is_non_string_sequence
26
-
27
- import networkx as nx # type: ignore[import-untyped]
24
+ from .utils import get_logger, is_non_string_sequence
25
+ from .types import CallbackError
28
26
 
29
27
  __all__ = (
30
28
  "CallbackEvent",
@@ -42,6 +40,7 @@ class CallbackEvent(str, Enum):
42
40
  BEFORE_STEP = "before_step"
43
41
  AFTER_STEP = "after_step"
44
42
  ON_REMESH = "on_remesh"
43
+ CACHE_METRICS = "cache_metrics"
45
44
 
46
45
 
47
46
  class CallbackManager:
@@ -131,9 +130,7 @@ class CallbackManager:
131
130
  cb_name = name or getattr(func, "__name__", None)
132
131
  spec = CallbackSpec(cb_name, func)
133
132
  existing_map = cbs[event]
134
- strict = bool(
135
- G.graph.get("CALLBACKS_STRICT", DEFAULTS["CALLBACKS_STRICT"])
136
- )
133
+ strict = bool(G.graph.get("CALLBACKS_STRICT", DEFAULTS["CALLBACKS_STRICT"]))
137
134
  key = _reconcile_callback(event, existing_map, spec, strict)
138
135
 
139
136
  existing_map[key] = spec
@@ -152,9 +149,7 @@ class CallbackManager:
152
149
  event = _normalize_event(event)
153
150
  with self._lock:
154
151
  cbs = dict(self._ensure_callbacks_nolock(G).get(event, {}))
155
- strict = bool(
156
- G.graph.get("CALLBACKS_STRICT", DEFAULTS["CALLBACKS_STRICT"])
157
- )
152
+ strict = bool(G.graph.get("CALLBACKS_STRICT", DEFAULTS["CALLBACKS_STRICT"]))
158
153
  if ctx is None:
159
154
  ctx = {}
160
155
  for spec in cbs.values():
@@ -185,17 +180,6 @@ Callback = Callable[["nx.Graph", dict[str, Any]], None]
185
180
  CallbackRegistry = dict[str, dict[str, "CallbackSpec"]]
186
181
 
187
182
 
188
- class CallbackError(TypedDict):
189
- """Metadata for a failed callback invocation."""
190
-
191
- event: str
192
- step: int | None
193
- error: str
194
- traceback: str
195
- fn: str
196
- name: str | None
197
-
198
-
199
183
  def _func_id(fn: Callable[..., Any]) -> str:
200
184
  """Return a deterministic identifier for ``fn``.
201
185
 
@@ -211,9 +195,7 @@ def _func_id(fn: Callable[..., Any]) -> str:
211
195
  return f"{module}.{qualname}"
212
196
 
213
197
 
214
- def _validate_registry(
215
- G: "nx.Graph", cbs: Any, dirty: set[str]
216
- ) -> CallbackRegistry:
198
+ def _validate_registry(G: "nx.Graph", cbs: Any, dirty: set[str]) -> CallbackRegistry:
217
199
  """Validate and normalise the callback registry.
218
200
 
219
201
  ``cbs`` is coerced to a ``defaultdict(dict)`` and any events listed in
@@ -246,13 +228,13 @@ def _validate_registry(
246
228
  return cbs
247
229
 
248
230
 
249
-
250
-
251
231
  def _normalize_callbacks(entries: Any) -> dict[str, CallbackSpec]:
252
232
  """Return ``entries`` normalised into a callback mapping."""
253
233
  if isinstance(entries, Mapping):
254
234
  entries_iter = entries.values()
255
- elif isinstance(entries, Iterable) and not isinstance(entries, (str, bytes, bytearray)):
235
+ elif isinstance(entries, Iterable) and not isinstance(
236
+ entries, (str, bytes, bytearray)
237
+ ):
256
238
  entries_iter = entries
257
239
  else:
258
240
  return {}
@@ -328,7 +310,6 @@ def _normalize_callback_entry(entry: Any) -> "CallbackSpec | None":
328
310
  return None
329
311
 
330
312
 
331
-
332
313
  def _reconcile_callback(
333
314
  event: str,
334
315
  existing_map: dict[str, CallbackSpec],
@@ -383,6 +364,3 @@ def _reconcile_callback(
383
364
  # ---------------------------------------------------------------------------
384
365
 
385
366
  callback_manager = CallbackManager()
386
-
387
-
388
-
@@ -0,0 +1,79 @@
1
+ from __future__ import annotations
2
+
3
+ import threading
4
+ import traceback
5
+ from collections import defaultdict, deque
6
+ from collections.abc import Callable, Iterable, Mapping
7
+ from enum import Enum
8
+ from typing import Any
9
+
10
+ import networkx as nx
11
+
12
+ from .constants import DEFAULTS
13
+ from .locking import get_lock
14
+ from .trace import CallbackSpec
15
+ from .types import CallbackError
16
+ from .utils import get_logger, is_non_string_sequence
17
+
18
+ __all__ = (
19
+ "CallbackEvent",
20
+ "CallbackManager",
21
+ "callback_manager",
22
+ "CallbackError",
23
+ )
24
+
25
+ logger: Any
26
+
27
+ class CallbackEvent(str, Enum):
28
+ BEFORE_STEP = "before_step"
29
+ AFTER_STEP = "after_step"
30
+ ON_REMESH = "on_remesh"
31
+ CACHE_METRICS = "cache_metrics"
32
+
33
+ Callback = Callable[[nx.Graph, dict[str, Any]], None]
34
+ CallbackRegistry = dict[str, dict[str, CallbackSpec]]
35
+
36
+ class CallbackManager:
37
+ def __init__(self) -> None: ...
38
+ def get_callback_error_limit(self) -> int: ...
39
+ def set_callback_error_limit(self, limit: int) -> int: ...
40
+ def register_callback(
41
+ self,
42
+ G: nx.Graph,
43
+ event: CallbackEvent | str,
44
+ func: Callback,
45
+ *,
46
+ name: str | None = ...,
47
+ ) -> Callback: ...
48
+ def invoke_callbacks(
49
+ self,
50
+ G: nx.Graph,
51
+ event: CallbackEvent | str,
52
+ ctx: dict[str, Any] | None = ...,
53
+ ) -> None: ...
54
+ def _record_callback_error(
55
+ self,
56
+ G: nx.Graph,
57
+ event: str,
58
+ ctx: dict[str, Any],
59
+ spec: CallbackSpec,
60
+ err: Exception,
61
+ ) -> None: ...
62
+ def _ensure_callbacks_nolock(self, G: nx.Graph) -> CallbackRegistry: ...
63
+ def _ensure_callbacks(self, G: nx.Graph) -> CallbackRegistry: ...
64
+
65
+ callback_manager: CallbackManager
66
+
67
+ def _func_id(fn: Callable[..., Any]) -> str: ...
68
+ def _validate_registry(G: nx.Graph, cbs: Any, dirty: set[str]) -> CallbackRegistry: ...
69
+ def _normalize_callbacks(entries: Any) -> dict[str, CallbackSpec]: ...
70
+ def _normalize_event(event: CallbackEvent | str) -> str: ...
71
+ def _is_known_event(event: str) -> bool: ...
72
+ def _ensure_known_event(event: str) -> None: ...
73
+ def _normalize_callback_entry(entry: Any) -> CallbackSpec | None: ...
74
+ def _reconcile_callback(
75
+ event: str,
76
+ existing_map: dict[str, CallbackSpec],
77
+ spec: CallbackSpec,
78
+ strict: bool,
79
+ ) -> str: ...
tnfr/cli/__init__.py CHANGED
@@ -1,3 +1,5 @@
1
+ """Command-line interface entry points for TNFR."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  import argparse
@@ -5,25 +7,27 @@ import logging
5
7
  import sys
6
8
  from typing import Optional
7
9
 
10
+ from .. import __version__
11
+ from ..utils import _configure_root, get_logger
8
12
  from .arguments import (
13
+ _add_metrics_parser,
14
+ _add_profile_parser,
15
+ _add_profile_pipeline_parser,
16
+ _add_run_parser,
17
+ _add_sequence_parser,
18
+ add_canon_toggle,
9
19
  add_common_args,
10
20
  add_grammar_args,
11
21
  add_grammar_selector_args,
12
22
  add_history_export_args,
13
- add_canon_toggle,
14
- _add_run_parser,
15
- _add_sequence_parser,
16
- _add_metrics_parser,
17
23
  )
18
24
  from .execution import (
19
- build_basic_graph,
20
25
  apply_cli_config,
26
+ build_basic_graph,
21
27
  register_callbacks_and_observer,
22
- run_program,
23
28
  resolve_program,
29
+ run_program,
24
30
  )
25
- from ..logging_utils import get_logger
26
- from .. import __version__
27
31
 
28
32
  logger = get_logger(__name__)
29
33
 
@@ -43,27 +47,43 @@ __all__ = (
43
47
 
44
48
 
45
49
  def main(argv: Optional[list[str]] = None) -> int:
46
- logging.basicConfig(
47
- level=logging.INFO, format="%(message)s", stream=sys.stdout, force=True
48
- )
50
+ """Entry point for the ``tnfr`` CLI returning the exit status."""
51
+
52
+ _configure_root()
53
+
54
+ root = logging.getLogger()
55
+ root.setLevel(logging.INFO)
56
+
57
+ formatter = logging.Formatter("%(message)s")
58
+ for handler in list(root.handlers):
59
+ root.removeHandler(handler)
60
+
61
+ handler = logging.StreamHandler(stream=sys.stdout)
62
+ handler.setLevel(logging.INFO)
63
+ handler.setFormatter(formatter)
64
+ root.addHandler(handler)
49
65
 
50
66
  p = argparse.ArgumentParser(
51
67
  prog="tnfr",
52
68
  formatter_class=argparse.RawDescriptionHelpFormatter,
53
69
  epilog=(
54
- "Ejemplo: tnfr sequence --sequence-file secuencia.json\n"
55
- "secuencia.json:\n"
70
+ "Example: tnfr sequence --sequence-file sequence.json\n"
71
+ "sequence.json:\n"
56
72
  '[\n {"WAIT": 1},\n {"TARGET": "A"}\n]'
57
73
  ),
58
74
  )
59
75
  p.add_argument(
60
- "--version", action="store_true", help="muestra versión y sale"
76
+ "--version",
77
+ action="store_true",
78
+ help=("show the actual version and exit (reads pyproject.toml in development)"),
61
79
  )
62
80
  sub = p.add_subparsers(dest="cmd")
63
81
 
64
82
  _add_run_parser(sub)
65
83
  _add_sequence_parser(sub)
66
84
  _add_metrics_parser(sub)
85
+ _add_profile_parser(sub)
86
+ _add_profile_pipeline_parser(sub)
67
87
 
68
88
  args = p.parse_args(argv)
69
89
  if args.version:
tnfr/cli/__init__.pyi ADDED
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from typing import Optional
5
+
6
+ from ..types import ProgramTokens, TNFRGraph
7
+
8
+ __all__: tuple[str, ...]
9
+
10
+ def main(argv: Optional[list[str]] = None) -> int: ...
11
+ def add_common_args(parser: argparse.ArgumentParser) -> None: ...
12
+ def add_grammar_args(parser: argparse.ArgumentParser) -> None: ...
13
+ def add_grammar_selector_args(parser: argparse.ArgumentParser) -> None: ...
14
+ def add_history_export_args(parser: argparse.ArgumentParser) -> None: ...
15
+ def add_canon_toggle(parser: argparse.ArgumentParser) -> None: ...
16
+ def build_basic_graph(args: argparse.Namespace) -> TNFRGraph: ...
17
+ def apply_cli_config(G: TNFRGraph, args: argparse.Namespace) -> None: ...
18
+ def register_callbacks_and_observer(G: TNFRGraph) -> None: ...
19
+ def resolve_program(
20
+ args: argparse.Namespace, default: Optional[ProgramTokens] = None
21
+ ) -> Optional[ProgramTokens]: ...
22
+ def run_program(
23
+ G: Optional[TNFRGraph],
24
+ program: Optional[ProgramTokens],
25
+ args: argparse.Namespace,
26
+ ) -> TNFRGraph: ...
tnfr/cli/arguments.py CHANGED
@@ -1,13 +1,25 @@
1
+ """Argument parser helpers shared across TNFR CLI commands."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  import argparse
4
- from typing import Any
6
+ from pathlib import Path
7
+ from typing import Any, Iterable
5
8
 
9
+ from ..config.presets import PREFERRED_PRESET_NAMES
6
10
  from ..gamma import GAMMA_REGISTRY
11
+ from ..telemetry.verbosity import TELEMETRY_VERBOSITY_LEVELS
12
+ from ..types import ArgSpec
7
13
  from .utils import spec
8
14
 
15
+ _PRESET_HELP = "Available presets: {}.".format(
16
+ ", ".join(PREFERRED_PRESET_NAMES),
17
+ )
18
+
19
+ TELEMETRY_VERBOSITY_CHOICES = TELEMETRY_VERBOSITY_LEVELS
9
20
 
10
- GRAMMAR_ARG_SPECS = (
21
+
22
+ GRAMMAR_ARG_SPECS: tuple[ArgSpec, ...] = (
11
23
  spec("--grammar.enabled", action=argparse.BooleanOptionalAction),
12
24
  spec("--grammar.zhir_requires_oz_window", type=int),
13
25
  spec("--grammar.zhir_dnfr_min", type=float),
@@ -19,25 +31,35 @@ GRAMMAR_ARG_SPECS = (
19
31
  )
20
32
 
21
33
 
22
- # Especificaciones para opciones relacionadas con el histórico
23
- HISTORY_ARG_SPECS = (
34
+ # History export/save specifications
35
+ HISTORY_ARG_SPECS: tuple[ArgSpec, ...] = (
24
36
  spec("--save-history", type=str),
25
37
  spec("--export-history-base", type=str),
26
38
  spec("--export-format", choices=["csv", "json"], default="json"),
27
39
  )
28
40
 
29
41
 
30
- # Argumentos comunes a los subcomandos
31
- COMMON_ARG_SPECS = (
42
+ # Arguments shared by CLI subcommands
43
+ COMMON_ARG_SPECS: tuple[ArgSpec, ...] = (
32
44
  spec("--nodes", type=int, default=24),
33
45
  spec("--topology", choices=["ring", "complete", "erdos"], default="ring"),
34
46
  spec("--seed", type=int, default=1),
35
47
  spec(
36
48
  "--p",
37
49
  type=float,
38
- help="Probabilidad de arista si topology=erdos",
50
+ help="Edge probability when topology=erdos",
51
+ ),
52
+ spec("--observer", action="store_true", help="Attach standard observer"),
53
+ spec(
54
+ "--trace-verbosity",
55
+ choices=TELEMETRY_VERBOSITY_CHOICES,
56
+ help="Select the trace capture preset",
57
+ ),
58
+ spec(
59
+ "--metrics-verbosity",
60
+ choices=TELEMETRY_VERBOSITY_CHOICES,
61
+ help="Select the metrics capture preset",
39
62
  ),
40
- spec("--observer", action="store_true", help="Adjunta observador estándar"),
41
63
  spec("--config", type=str),
42
64
  spec("--dt", type=float),
43
65
  spec("--integrator", choices=["euler", "rk4"]),
@@ -45,10 +67,13 @@ COMMON_ARG_SPECS = (
45
67
  spec("--gamma-type", choices=list(GAMMA_REGISTRY.keys()), default="none"),
46
68
  spec("--gamma-beta", type=float, default=0.0),
47
69
  spec("--gamma-R0", type=float, default=0.0),
70
+ spec("--um-candidate-count", type=int),
71
+ spec("--stop-early-window", type=int),
72
+ spec("--stop-early-fraction", type=float),
48
73
  )
49
74
 
50
75
 
51
- def add_arg_specs(parser: argparse._ActionsContainer, specs) -> None:
76
+ def add_arg_specs(parser: argparse._ActionsContainer, specs: Iterable[ArgSpec]) -> None:
52
77
  """Register arguments from ``specs`` on ``parser``."""
53
78
  for opt, kwargs in specs:
54
79
  parser.add_argument(opt, **kwargs)
@@ -77,9 +102,7 @@ def add_grammar_args(parser: argparse.ArgumentParser) -> None:
77
102
  def add_grammar_selector_args(parser: argparse.ArgumentParser) -> None:
78
103
  """Add grammar options and glyph selector."""
79
104
  add_grammar_args(parser)
80
- parser.add_argument(
81
- "--selector", choices=["basic", "param"], default="basic"
82
- )
105
+ parser.add_argument("--selector", choices=["basic", "param"], default="basic")
83
106
 
84
107
 
85
108
  def add_history_export_args(parser: argparse.ArgumentParser) -> None:
@@ -94,26 +117,45 @@ def add_canon_toggle(parser: argparse.ArgumentParser) -> None:
94
117
  dest="grammar_canon",
95
118
  action="store_false",
96
119
  default=True,
97
- help="Desactiva gramática canónica",
120
+ help="Disable canonical grammar",
98
121
  )
99
122
 
100
123
 
101
124
  def _add_run_parser(sub: argparse._SubParsersAction) -> None:
102
125
  """Configure the ``run`` subcommand."""
103
- from .execution import cmd_run, DEFAULT_SUMMARY_SERIES_LIMIT
126
+
127
+ from .execution import DEFAULT_SUMMARY_SERIES_LIMIT, cmd_run
104
128
 
105
129
  p_run = sub.add_parser(
106
130
  "run",
107
- help=(
108
- "Correr escenario libre o preset y opcionalmente exportar history"
109
- ),
131
+ help=("Run a free scenario or preset and optionally export history"),
110
132
  )
111
133
  add_common_args(p_run)
112
134
  p_run.add_argument("--steps", type=int, default=100)
135
+ p_run.add_argument(
136
+ "--use-Si",
137
+ dest="use_Si",
138
+ action=argparse.BooleanOptionalAction,
139
+ default=None,
140
+ help="Recompute the Sense Index during the run (use --no-use-Si to disable)",
141
+ )
142
+ p_run.add_argument(
143
+ "--apply-glyphs",
144
+ dest="apply_glyphs",
145
+ action=argparse.BooleanOptionalAction,
146
+ default=None,
147
+ help="Apply glyphs at every step (use --no-apply-glyphs to disable)",
148
+ )
149
+ p_run.add_argument(
150
+ "--dnfr-n-jobs",
151
+ dest="dnfr_n_jobs",
152
+ type=int,
153
+ help="Override ΔNFR parallel jobs forwarded to the runtime",
154
+ )
113
155
  add_canon_toggle(p_run)
114
156
  add_grammar_selector_args(p_run)
115
157
  add_history_export_args(p_run)
116
- p_run.add_argument("--preset", type=str, default=None)
158
+ p_run.add_argument("--preset", type=str, default=None, help=_PRESET_HELP)
117
159
  p_run.add_argument("--sequence-file", type=str, default=None)
118
160
  p_run.add_argument("--summary", action="store_true")
119
161
  p_run.add_argument(
@@ -121,10 +163,68 @@ def _add_run_parser(sub: argparse._SubParsersAction) -> None:
121
163
  type=int,
122
164
  default=DEFAULT_SUMMARY_SERIES_LIMIT,
123
165
  help=(
124
- "Número máximo de muestras por serie en el resumen (<=0 para"
125
- " desactivar el recorte)"
166
+ "Maximum number of samples per series in the summary (<=0 to"
167
+ " disable trimming)"
168
+ ),
169
+ )
170
+
171
+ math_group = p_run.add_argument_group("Mathematical dynamics")
172
+ math_group.add_argument(
173
+ "--math-engine",
174
+ action=argparse.BooleanOptionalAction,
175
+ default=False,
176
+ help=(
177
+ "Enable the spectral mathematical dynamics engine to project nodes"
178
+ " onto Hilbert space vectors and validate norm, coherence and"
179
+ " structural frequency invariants"
180
+ ),
181
+ )
182
+ math_group.add_argument(
183
+ "--math-dimension",
184
+ type=int,
185
+ help="Hilbert space dimension to use when the math engine is enabled",
186
+ )
187
+ math_group.add_argument(
188
+ "--math-coherence-spectrum",
189
+ type=float,
190
+ nargs="+",
191
+ metavar="λ",
192
+ help=(
193
+ "Eigenvalues for the coherence operator (defaults to a flat"
194
+ " spectrum when omitted)"
195
+ ),
196
+ )
197
+ math_group.add_argument(
198
+ "--math-coherence-c-min",
199
+ type=float,
200
+ help="Explicit coherence floor C_min for the operator",
201
+ )
202
+ math_group.add_argument(
203
+ "--math-coherence-threshold",
204
+ type=float,
205
+ help="Coherence expectation threshold enforced during validation",
206
+ )
207
+ math_group.add_argument(
208
+ "--math-frequency-diagonal",
209
+ type=float,
210
+ nargs="+",
211
+ metavar="ν",
212
+ help=(
213
+ "Diagonal entries for the structural frequency operator"
214
+ " (defaults to the identity spectrum)"
126
215
  ),
127
216
  )
217
+ math_group.add_argument(
218
+ "--math-generator-diagonal",
219
+ type=float,
220
+ nargs="+",
221
+ metavar="ω",
222
+ help=(
223
+ "Diagonal ΔNFR generator used by the mathematical dynamics"
224
+ " engine (defaults to the null generator)"
225
+ ),
226
+ )
227
+
128
228
  p_run.set_defaults(func=cmd_run)
129
229
 
130
230
 
@@ -134,10 +234,10 @@ def _add_sequence_parser(sub: argparse._SubParsersAction) -> None:
134
234
 
135
235
  p_seq = sub.add_parser(
136
236
  "sequence",
137
- help="Ejecutar una secuencia (preset o YAML/JSON)",
237
+ help="Execute a sequence (preset or YAML/JSON)",
138
238
  formatter_class=argparse.RawDescriptionHelpFormatter,
139
239
  epilog=(
140
- "Ejemplo de secuencia JSON:\n"
240
+ "JSON sequence example:\n"
141
241
  "[\n"
142
242
  ' "A",\n'
143
243
  ' {"WAIT": 1},\n'
@@ -146,7 +246,7 @@ def _add_sequence_parser(sub: argparse._SubParsersAction) -> None:
146
246
  ),
147
247
  )
148
248
  add_common_args(p_seq)
149
- p_seq.add_argument("--preset", type=str, default=None)
249
+ p_seq.add_argument("--preset", type=str, default=None, help=_PRESET_HELP)
150
250
  p_seq.add_argument("--sequence-file", type=str, default=None)
151
251
  add_history_export_args(p_seq)
152
252
  add_grammar_args(p_seq)
@@ -157,9 +257,7 @@ def _add_metrics_parser(sub: argparse._SubParsersAction) -> None:
157
257
  """Configure the ``metrics`` subcommand."""
158
258
  from .execution import cmd_metrics
159
259
 
160
- p_met = sub.add_parser(
161
- "metrics", help="Correr breve y volcar métricas clave"
162
- )
260
+ p_met = sub.add_parser("metrics", help="Run briefly and export key metrics")
163
261
  add_common_args(p_met)
164
262
  p_met.add_argument("--steps", type=int, default=None)
165
263
  add_canon_toggle(p_met)
@@ -170,8 +268,93 @@ def _add_metrics_parser(sub: argparse._SubParsersAction) -> None:
170
268
  type=int,
171
269
  default=None,
172
270
  help=(
173
- "Número máximo de muestras por serie en el resumen (<=0 para"
174
- " desactivar el recorte)"
271
+ "Maximum number of samples per series in the summary (<=0 to"
272
+ " disable trimming)"
175
273
  ),
176
274
  )
177
275
  p_met.set_defaults(func=cmd_metrics)
276
+
277
+
278
+ def _add_profile_parser(sub: argparse._SubParsersAction) -> None:
279
+ """Configure the ``profile-si`` subcommand."""
280
+
281
+ from .execution import cmd_profile_si
282
+
283
+ p_prof = sub.add_parser(
284
+ "profile-si",
285
+ help="Profile compute_Si with and without NumPy",
286
+ )
287
+ p_prof.add_argument("--nodes", type=int, default=240)
288
+ p_prof.add_argument("--chord-step", type=int, default=7)
289
+ p_prof.add_argument("--loops", type=int, default=5)
290
+ p_prof.add_argument("--output-dir", type=Path, default=Path("profiles"))
291
+ p_prof.add_argument("--format", choices=("pstats", "json"), default="pstats")
292
+ p_prof.add_argument("--sort", choices=("cumtime", "tottime"), default="cumtime")
293
+ p_prof.set_defaults(func=cmd_profile_si)
294
+
295
+
296
+ def _add_profile_pipeline_parser(sub: argparse._SubParsersAction) -> None:
297
+ """Configure the ``profile-pipeline`` subcommand."""
298
+
299
+ from .execution import cmd_profile_pipeline
300
+
301
+ p_profile = sub.add_parser(
302
+ "profile-pipeline",
303
+ help="Profile the Sense Index + ΔNFR pipeline",
304
+ )
305
+ p_profile.add_argument("--nodes", type=int, default=240, help="Number of nodes")
306
+ p_profile.add_argument(
307
+ "--edge-probability",
308
+ type=float,
309
+ default=0.32,
310
+ help="Probability passed to the Erdos-Renyi generator",
311
+ )
312
+ p_profile.add_argument(
313
+ "--loops",
314
+ type=int,
315
+ default=5,
316
+ help="How many times to execute the pipeline inside the profiler",
317
+ )
318
+ p_profile.add_argument(
319
+ "--seed",
320
+ type=int,
321
+ default=42,
322
+ help="Random seed used when generating the graph",
323
+ )
324
+ p_profile.add_argument(
325
+ "--output-dir",
326
+ type=Path,
327
+ default=Path("profiles"),
328
+ help="Directory where profiling artefacts will be written",
329
+ )
330
+ p_profile.add_argument(
331
+ "--sort",
332
+ choices=("cumtime", "tottime"),
333
+ default="cumtime",
334
+ help="Sort order applied to profiling rows",
335
+ )
336
+ p_profile.add_argument(
337
+ "--si-chunk-sizes",
338
+ nargs="+",
339
+ metavar="SIZE",
340
+ help="Chunk sizes forwarded to G.graph['SI_CHUNK_SIZE']; use 'auto' for heuristics",
341
+ )
342
+ p_profile.add_argument(
343
+ "--dnfr-chunk-sizes",
344
+ nargs="+",
345
+ metavar="SIZE",
346
+ help="Chunk sizes forwarded to G.graph['DNFR_CHUNK_SIZE']; use 'auto' for heuristics",
347
+ )
348
+ p_profile.add_argument(
349
+ "--si-workers",
350
+ nargs="+",
351
+ metavar="COUNT",
352
+ help="Worker counts forwarded to G.graph['SI_N_JOBS']; use 'auto' for serial runs",
353
+ )
354
+ p_profile.add_argument(
355
+ "--dnfr-workers",
356
+ nargs="+",
357
+ metavar="COUNT",
358
+ help="Worker counts forwarded to G.graph['DNFR_N_JOBS']; use 'auto' for defaults",
359
+ )
360
+ p_profile.set_defaults(func=cmd_profile_pipeline)
tnfr/cli/arguments.pyi ADDED
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from typing import Any, Iterable
5
+
6
+ from ..gamma import GAMMA_REGISTRY
7
+ from ..types import ArgSpec
8
+ from .utils import spec
9
+
10
+ GRAMMAR_ARG_SPECS: tuple[ArgSpec, ...]
11
+ HISTORY_ARG_SPECS: tuple[ArgSpec, ...]
12
+ COMMON_ARG_SPECS: tuple[ArgSpec, ...]
13
+
14
+ def add_arg_specs(
15
+ parser: argparse._ActionsContainer, specs: Iterable[ArgSpec]
16
+ ) -> None: ...
17
+ def _args_to_dict(args: argparse.Namespace, prefix: str) -> dict[str, Any]: ...
18
+ def add_common_args(parser: argparse.ArgumentParser) -> None: ...
19
+ def add_grammar_args(parser: argparse.ArgumentParser) -> None: ...
20
+ def add_grammar_selector_args(parser: argparse.ArgumentParser) -> None: ...
21
+ def add_history_export_args(parser: argparse.ArgumentParser) -> None: ...
22
+ def add_canon_toggle(parser: argparse.ArgumentParser) -> None: ...
23
+ def _add_run_parser(sub: argparse._SubParsersAction) -> None: ...
24
+ def _add_sequence_parser(sub: argparse._SubParsersAction) -> None: ...
25
+ def _add_metrics_parser(sub: argparse._SubParsersAction) -> None: ...
26
+ def _add_profile_parser(sub: argparse._SubParsersAction) -> None: ...
27
+ def _add_profile_pipeline_parser(sub: argparse._SubParsersAction) -> None: ...