tnfr 4.5.2__py3-none-any.whl → 6.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.
- tnfr/__init__.py +228 -49
- tnfr/__init__.pyi +40 -0
- tnfr/_compat.py +11 -0
- tnfr/_version.py +7 -0
- tnfr/_version.pyi +7 -0
- tnfr/alias.py +106 -21
- tnfr/alias.pyi +140 -0
- tnfr/cache.py +666 -512
- tnfr/cache.pyi +232 -0
- tnfr/callback_utils.py +2 -9
- tnfr/callback_utils.pyi +105 -0
- tnfr/cli/__init__.py +21 -7
- tnfr/cli/__init__.pyi +47 -0
- tnfr/cli/arguments.py +42 -20
- tnfr/cli/arguments.pyi +33 -0
- tnfr/cli/execution.py +54 -20
- tnfr/cli/execution.pyi +80 -0
- tnfr/cli/utils.py +0 -2
- tnfr/cli/utils.pyi +8 -0
- tnfr/config/__init__.py +12 -0
- tnfr/config/__init__.pyi +8 -0
- tnfr/config/constants.py +104 -0
- tnfr/config/constants.pyi +12 -0
- tnfr/{config.py → config/init.py} +11 -7
- tnfr/config/init.pyi +8 -0
- tnfr/config/operator_names.py +106 -0
- tnfr/config/operator_names.pyi +28 -0
- tnfr/config/presets.py +104 -0
- tnfr/config/presets.pyi +7 -0
- tnfr/constants/__init__.py +78 -24
- tnfr/constants/__init__.pyi +104 -0
- tnfr/constants/core.py +1 -2
- tnfr/constants/core.pyi +17 -0
- tnfr/constants/init.pyi +12 -0
- tnfr/constants/metric.py +4 -12
- tnfr/constants/metric.pyi +19 -0
- tnfr/constants_glyphs.py +9 -91
- tnfr/constants_glyphs.pyi +12 -0
- tnfr/dynamics/__init__.py +112 -634
- tnfr/dynamics/__init__.pyi +83 -0
- tnfr/dynamics/adaptation.py +201 -0
- tnfr/dynamics/aliases.py +22 -0
- tnfr/dynamics/coordination.py +343 -0
- tnfr/dynamics/dnfr.py +1936 -354
- tnfr/dynamics/dnfr.pyi +33 -0
- tnfr/dynamics/integrators.py +369 -75
- tnfr/dynamics/integrators.pyi +35 -0
- tnfr/dynamics/runtime.py +521 -0
- tnfr/dynamics/sampling.py +8 -5
- tnfr/dynamics/sampling.pyi +7 -0
- tnfr/dynamics/selectors.py +680 -0
- tnfr/execution.py +56 -41
- tnfr/execution.pyi +65 -0
- tnfr/flatten.py +7 -7
- tnfr/flatten.pyi +28 -0
- tnfr/gamma.py +54 -37
- tnfr/gamma.pyi +40 -0
- tnfr/glyph_history.py +85 -38
- tnfr/glyph_history.pyi +53 -0
- tnfr/grammar.py +19 -338
- tnfr/grammar.pyi +13 -0
- tnfr/helpers/__init__.py +110 -30
- tnfr/helpers/__init__.pyi +66 -0
- tnfr/helpers/numeric.py +1 -0
- tnfr/helpers/numeric.pyi +12 -0
- tnfr/immutable.py +55 -19
- tnfr/immutable.pyi +37 -0
- tnfr/initialization.py +12 -10
- tnfr/initialization.pyi +73 -0
- tnfr/io.py +99 -34
- tnfr/io.pyi +11 -0
- tnfr/locking.pyi +7 -0
- tnfr/metrics/__init__.pyi +20 -0
- tnfr/metrics/coherence.py +934 -294
- tnfr/metrics/common.py +1 -3
- tnfr/metrics/common.pyi +15 -0
- tnfr/metrics/core.py +192 -34
- tnfr/metrics/core.pyi +13 -0
- tnfr/metrics/diagnosis.py +707 -101
- tnfr/metrics/diagnosis.pyi +89 -0
- tnfr/metrics/export.py +27 -13
- tnfr/metrics/glyph_timing.py +218 -38
- tnfr/metrics/reporting.py +22 -18
- tnfr/metrics/reporting.pyi +12 -0
- tnfr/metrics/sense_index.py +199 -25
- tnfr/metrics/sense_index.pyi +9 -0
- tnfr/metrics/trig.py +53 -18
- tnfr/metrics/trig.pyi +12 -0
- tnfr/metrics/trig_cache.py +3 -7
- tnfr/metrics/trig_cache.pyi +10 -0
- tnfr/node.py +148 -125
- tnfr/node.pyi +161 -0
- tnfr/observers.py +44 -30
- tnfr/observers.pyi +46 -0
- tnfr/ontosim.py +14 -13
- tnfr/ontosim.pyi +33 -0
- tnfr/operators/__init__.py +84 -52
- tnfr/operators/__init__.pyi +31 -0
- tnfr/operators/definitions.py +181 -0
- tnfr/operators/definitions.pyi +92 -0
- tnfr/operators/jitter.py +86 -23
- tnfr/operators/jitter.pyi +11 -0
- tnfr/operators/registry.py +80 -0
- tnfr/operators/registry.pyi +15 -0
- tnfr/operators/remesh.py +141 -57
- tnfr/presets.py +9 -54
- tnfr/presets.pyi +7 -0
- tnfr/py.typed +0 -0
- tnfr/rng.py +259 -73
- tnfr/rng.pyi +14 -0
- tnfr/selector.py +24 -17
- tnfr/selector.pyi +19 -0
- tnfr/sense.py +55 -43
- tnfr/sense.pyi +30 -0
- tnfr/structural.py +44 -267
- tnfr/structural.pyi +46 -0
- tnfr/telemetry/__init__.py +13 -0
- tnfr/telemetry/verbosity.py +37 -0
- tnfr/tokens.py +3 -2
- tnfr/tokens.pyi +41 -0
- tnfr/trace.py +272 -82
- tnfr/trace.pyi +68 -0
- tnfr/types.py +345 -6
- tnfr/types.pyi +145 -0
- tnfr/utils/__init__.py +158 -0
- tnfr/utils/__init__.pyi +133 -0
- tnfr/utils/cache.py +755 -0
- tnfr/utils/cache.pyi +156 -0
- tnfr/{collections_utils.py → utils/data.py} +57 -90
- tnfr/utils/data.pyi +73 -0
- tnfr/utils/graph.py +87 -0
- tnfr/utils/graph.pyi +10 -0
- tnfr/utils/init.py +746 -0
- tnfr/utils/init.pyi +85 -0
- tnfr/{json_utils.py → utils/io.py} +13 -18
- tnfr/utils/io.pyi +10 -0
- tnfr/utils/validators.py +130 -0
- tnfr/utils/validators.pyi +19 -0
- tnfr/validation/__init__.py +25 -0
- tnfr/validation/__init__.pyi +17 -0
- tnfr/validation/compatibility.py +59 -0
- tnfr/validation/compatibility.pyi +8 -0
- tnfr/validation/grammar.py +149 -0
- tnfr/validation/grammar.pyi +11 -0
- tnfr/validation/rules.py +194 -0
- tnfr/validation/rules.pyi +18 -0
- tnfr/validation/syntax.py +151 -0
- tnfr/validation/syntax.pyi +7 -0
- tnfr-6.0.0.dist-info/METADATA +135 -0
- tnfr-6.0.0.dist-info/RECORD +157 -0
- tnfr/graph_utils.py +0 -84
- tnfr/import_utils.py +0 -228
- tnfr/logging_utils.py +0 -116
- tnfr/validators.py +0 -84
- tnfr/value_utils.py +0 -59
- tnfr-4.5.2.dist-info/METADATA +0 -379
- tnfr-4.5.2.dist-info/RECORD +0 -67
- {tnfr-4.5.2.dist-info → tnfr-6.0.0.dist-info}/WHEEL +0 -0
- {tnfr-4.5.2.dist-info → tnfr-6.0.0.dist-info}/entry_points.txt +0 -0
- {tnfr-4.5.2.dist-info → tnfr-6.0.0.dist-info}/licenses/LICENSE.md +0 -0
- {tnfr-4.5.2.dist-info → tnfr-6.0.0.dist-info}/top_level.txt +0 -0
tnfr/cli/execution.py
CHANGED
|
@@ -2,10 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
|
|
5
|
+
from copy import deepcopy
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import Any, Optional
|
|
7
8
|
|
|
8
|
-
import networkx as nx
|
|
9
|
+
import networkx as nx
|
|
9
10
|
|
|
10
11
|
from ..constants import METRIC_DEFAULTS
|
|
11
12
|
from ..sense import register_sigma_callback
|
|
@@ -17,21 +18,24 @@ from ..metrics import (
|
|
|
17
18
|
)
|
|
18
19
|
from ..metrics.core import _metrics_step
|
|
19
20
|
from ..trace import register_trace
|
|
20
|
-
from ..execution import CANONICAL_PRESET_NAME, play
|
|
21
|
+
from ..execution import CANONICAL_PRESET_NAME, play
|
|
21
22
|
from ..dynamics import (
|
|
22
23
|
run,
|
|
23
24
|
default_glyph_selector,
|
|
24
25
|
parametric_glyph_selector,
|
|
25
26
|
validate_canon,
|
|
26
27
|
)
|
|
27
|
-
from ..presets import
|
|
28
|
+
from ..config.presets import (
|
|
29
|
+
PREFERRED_PRESET_NAMES,
|
|
30
|
+
get_preset,
|
|
31
|
+
legacy_preset_guidance,
|
|
32
|
+
)
|
|
28
33
|
from ..config import apply_config
|
|
29
34
|
from ..io import read_structured_file, safe_write, StructuredFileError
|
|
30
35
|
from ..glyph_history import ensure_history
|
|
31
|
-
from ..ontosim import
|
|
32
|
-
from ..
|
|
33
|
-
from ..
|
|
34
|
-
from ..json_utils import json_dumps
|
|
36
|
+
from ..ontosim import prepare_network
|
|
37
|
+
from ..types import ProgramTokens
|
|
38
|
+
from ..utils import get_logger, json_dumps
|
|
35
39
|
from ..flatten import parse_program_tokens
|
|
36
40
|
|
|
37
41
|
from .arguments import _args_to_dict
|
|
@@ -43,6 +47,8 @@ logger = get_logger(__name__)
|
|
|
43
47
|
# inspect the full glyphogram series when needed.
|
|
44
48
|
DEFAULT_SUMMARY_SERIES_LIMIT = 10
|
|
45
49
|
|
|
50
|
+
_PREFERRED_PRESETS_DISPLAY = ", ".join(PREFERRED_PRESET_NAMES)
|
|
51
|
+
|
|
46
52
|
|
|
47
53
|
def _save_json(path: str, data: Any) -> None:
|
|
48
54
|
payload = json_dumps(data, ensure_ascii=False, indent=2, default=list)
|
|
@@ -133,6 +139,18 @@ def apply_cli_config(G: "nx.Graph", args: argparse.Namespace) -> None:
|
|
|
133
139
|
"R0": args.gamma_R0,
|
|
134
140
|
}
|
|
135
141
|
|
|
142
|
+
for attr, key in (
|
|
143
|
+
("trace_verbosity", "TRACE"),
|
|
144
|
+
("metrics_verbosity", "METRICS"),
|
|
145
|
+
):
|
|
146
|
+
cfg = G.graph.get(key)
|
|
147
|
+
if not isinstance(cfg, dict):
|
|
148
|
+
cfg = deepcopy(METRIC_DEFAULTS[key])
|
|
149
|
+
G.graph[key] = cfg
|
|
150
|
+
value = getattr(args, attr, None)
|
|
151
|
+
if value is not None:
|
|
152
|
+
cfg["verbosity"] = value
|
|
153
|
+
|
|
136
154
|
|
|
137
155
|
def register_callbacks_and_observer(G: "nx.Graph") -> None:
|
|
138
156
|
_attach_callbacks(G)
|
|
@@ -144,12 +162,12 @@ def _build_graph_from_args(args: argparse.Namespace) -> "nx.Graph":
|
|
|
144
162
|
apply_cli_config(G, args)
|
|
145
163
|
if getattr(args, "observer", False):
|
|
146
164
|
G.graph["ATTACH_STD_OBSERVER"] = True
|
|
147
|
-
|
|
165
|
+
prepare_network(G)
|
|
148
166
|
register_callbacks_and_observer(G)
|
|
149
167
|
return G
|
|
150
168
|
|
|
151
169
|
|
|
152
|
-
def _load_sequence(path: Path) ->
|
|
170
|
+
def _load_sequence(path: Path) -> ProgramTokens:
|
|
153
171
|
try:
|
|
154
172
|
data = read_structured_file(path)
|
|
155
173
|
except (StructuredFileError, OSError) as exc:
|
|
@@ -163,15 +181,29 @@ def _load_sequence(path: Path) -> list[Any]:
|
|
|
163
181
|
|
|
164
182
|
|
|
165
183
|
def resolve_program(
|
|
166
|
-
args: argparse.Namespace, default: Optional[
|
|
167
|
-
) -> Optional[
|
|
184
|
+
args: argparse.Namespace, default: Optional[ProgramTokens] = None
|
|
185
|
+
) -> Optional[ProgramTokens]:
|
|
168
186
|
if getattr(args, "preset", None):
|
|
169
187
|
try:
|
|
170
188
|
return get_preset(args.preset)
|
|
171
189
|
except KeyError as exc:
|
|
190
|
+
guidance = legacy_preset_guidance(args.preset)
|
|
191
|
+
if guidance is not None:
|
|
192
|
+
details = guidance
|
|
193
|
+
else:
|
|
194
|
+
details = (
|
|
195
|
+
exc.args[0]
|
|
196
|
+
if exc.args
|
|
197
|
+
else "Legacy preset identifier rejected."
|
|
198
|
+
)
|
|
172
199
|
logger.error(
|
|
173
|
-
|
|
200
|
+
(
|
|
201
|
+
"Unknown preset '%s'. Available presets: %s. %s "
|
|
202
|
+
"Use --sequence-file to execute custom sequences."
|
|
203
|
+
),
|
|
174
204
|
args.preset,
|
|
205
|
+
_PREFERRED_PRESETS_DISPLAY,
|
|
206
|
+
details,
|
|
175
207
|
)
|
|
176
208
|
raise SystemExit(1) from exc
|
|
177
209
|
if getattr(args, "sequence_file", None):
|
|
@@ -180,7 +212,9 @@ def resolve_program(
|
|
|
180
212
|
|
|
181
213
|
|
|
182
214
|
def run_program(
|
|
183
|
-
G: Optional["nx.Graph"],
|
|
215
|
+
G: Optional["nx.Graph"],
|
|
216
|
+
program: Optional[ProgramTokens],
|
|
217
|
+
args: argparse.Namespace,
|
|
184
218
|
) -> "nx.Graph":
|
|
185
219
|
if G is None:
|
|
186
220
|
G = _build_graph_from_args(args)
|
|
@@ -208,7 +242,7 @@ def run_program(
|
|
|
208
242
|
def _run_cli_program(
|
|
209
243
|
args: argparse.Namespace,
|
|
210
244
|
*,
|
|
211
|
-
default_program: Optional[
|
|
245
|
+
default_program: Optional[ProgramTokens] = None,
|
|
212
246
|
graph: Optional["nx.Graph"] = None,
|
|
213
247
|
) -> tuple[int, Optional["nx.Graph"]]:
|
|
214
248
|
try:
|
|
@@ -229,23 +263,23 @@ def _log_run_summaries(G: "nx.Graph", args: argparse.Namespace) -> None:
|
|
|
229
263
|
if cfg_coh.get("enabled", True):
|
|
230
264
|
Wstats = hist.get(cfg_coh.get("stats_history_key", "W_stats"), [])
|
|
231
265
|
if Wstats:
|
|
232
|
-
logger.info("[COHERENCE]
|
|
266
|
+
logger.info("[COHERENCE] last step: %s", Wstats[-1])
|
|
233
267
|
|
|
234
268
|
if cfg_diag.get("enabled", True):
|
|
235
269
|
last_diag = hist.get(cfg_diag.get("history_key", "nodal_diag"), [])
|
|
236
270
|
if last_diag:
|
|
237
271
|
sample = list(last_diag[-1].values())[:3]
|
|
238
|
-
logger.info("[DIAGNOSIS]
|
|
272
|
+
logger.info("[DIAGNOSIS] sample: %s", sample)
|
|
239
273
|
|
|
240
274
|
if args.summary:
|
|
241
275
|
summary_limit = getattr(args, "summary_limit", DEFAULT_SUMMARY_SERIES_LIMIT)
|
|
242
276
|
summary, has_latency_values = build_metrics_summary(
|
|
243
277
|
G, series_limit=summary_limit
|
|
244
278
|
)
|
|
245
|
-
logger.info("Tg
|
|
246
|
-
logger.info("Top
|
|
279
|
+
logger.info("Global Tg: %s", summary["Tg_global"])
|
|
280
|
+
logger.info("Top operators by Tg: %s", glyph_top(G, k=5))
|
|
247
281
|
if has_latency_values:
|
|
248
|
-
logger.info("
|
|
282
|
+
logger.info("Average latency: %s", summary["latency_mean"])
|
|
249
283
|
|
|
250
284
|
|
|
251
285
|
def cmd_run(args: argparse.Namespace) -> int:
|
|
@@ -261,7 +295,7 @@ def cmd_run(args: argparse.Namespace) -> int:
|
|
|
261
295
|
def cmd_sequence(args: argparse.Namespace) -> int:
|
|
262
296
|
if args.preset and args.sequence_file:
|
|
263
297
|
logger.error(
|
|
264
|
-
"
|
|
298
|
+
"Cannot use --preset and --sequence-file at the same time"
|
|
265
299
|
)
|
|
266
300
|
return 1
|
|
267
301
|
code, _ = _run_cli_program(
|
tnfr/cli/execution.pyi
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
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 ..constants import METRIC_DEFAULTS
|
|
10
|
+
from ..dynamics import (
|
|
11
|
+
run,
|
|
12
|
+
default_glyph_selector,
|
|
13
|
+
parametric_glyph_selector,
|
|
14
|
+
validate_canon,
|
|
15
|
+
)
|
|
16
|
+
from ..execution import CANONICAL_PRESET_NAME, play, seq
|
|
17
|
+
from ..flatten import parse_program_tokens
|
|
18
|
+
from ..glyph_history import ensure_history
|
|
19
|
+
from ..io import read_structured_file, safe_write, StructuredFileError
|
|
20
|
+
from ..metrics import (
|
|
21
|
+
register_metrics_callbacks,
|
|
22
|
+
glyph_top,
|
|
23
|
+
export_metrics,
|
|
24
|
+
build_metrics_summary,
|
|
25
|
+
)
|
|
26
|
+
from ..metrics.core import _metrics_step
|
|
27
|
+
from ..ontosim import prepare_network
|
|
28
|
+
from ..sense import register_sigma_callback
|
|
29
|
+
from ..trace import register_trace
|
|
30
|
+
from ..types import Glyph, ProgramTokens
|
|
31
|
+
from ..utils import get_logger, json_dumps
|
|
32
|
+
from ..config import apply_config
|
|
33
|
+
from ..config.presets import get_preset
|
|
34
|
+
|
|
35
|
+
from .arguments import _args_to_dict
|
|
36
|
+
|
|
37
|
+
DEFAULT_SUMMARY_SERIES_LIMIT: int
|
|
38
|
+
logger: Any
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _save_json(path: str, data: Any) -> None: ...
|
|
42
|
+
|
|
43
|
+
def _attach_callbacks(G: nx.Graph) -> None: ...
|
|
44
|
+
|
|
45
|
+
def _persist_history(G: nx.Graph, args: argparse.Namespace) -> None: ...
|
|
46
|
+
|
|
47
|
+
def build_basic_graph(args: argparse.Namespace) -> nx.Graph: ...
|
|
48
|
+
|
|
49
|
+
def apply_cli_config(G: nx.Graph, args: argparse.Namespace) -> None: ...
|
|
50
|
+
|
|
51
|
+
def register_callbacks_and_observer(G: nx.Graph) -> None: ...
|
|
52
|
+
|
|
53
|
+
def _build_graph_from_args(args: argparse.Namespace) -> nx.Graph: ...
|
|
54
|
+
|
|
55
|
+
def _load_sequence(path: Path) -> ProgramTokens: ...
|
|
56
|
+
|
|
57
|
+
def resolve_program(
|
|
58
|
+
args: argparse.Namespace, default: Optional[ProgramTokens] = ...
|
|
59
|
+
) -> Optional[ProgramTokens]: ...
|
|
60
|
+
|
|
61
|
+
def run_program(
|
|
62
|
+
G: Optional[nx.Graph],
|
|
63
|
+
program: Optional[ProgramTokens],
|
|
64
|
+
args: argparse.Namespace,
|
|
65
|
+
) -> nx.Graph: ...
|
|
66
|
+
|
|
67
|
+
def _run_cli_program(
|
|
68
|
+
args: argparse.Namespace,
|
|
69
|
+
*,
|
|
70
|
+
default_program: Optional[ProgramTokens] = ...,
|
|
71
|
+
graph: Optional[nx.Graph] = ...,
|
|
72
|
+
) -> tuple[int, Optional[nx.Graph]]: ...
|
|
73
|
+
|
|
74
|
+
def _log_run_summaries(G: nx.Graph, args: argparse.Namespace) -> None: ...
|
|
75
|
+
|
|
76
|
+
def cmd_run(args: argparse.Namespace) -> int: ...
|
|
77
|
+
|
|
78
|
+
def cmd_sequence(args: argparse.Namespace) -> int: ...
|
|
79
|
+
|
|
80
|
+
def cmd_metrics(args: argparse.Namespace) -> int: ...
|
tnfr/cli/utils.py
CHANGED
tnfr/cli/utils.pyi
ADDED
tnfr/config/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
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 .init import apply_config, load_config
|
|
11
|
+
|
|
12
|
+
__all__ = ("load_config", "apply_config")
|
tnfr/config/__init__.pyi
ADDED
tnfr/config/constants.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Canonical glyph constants tied to configuration presets."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from types import MappingProxyType
|
|
7
|
+
from typing import Mapping
|
|
8
|
+
|
|
9
|
+
from ..types import Glyph
|
|
10
|
+
|
|
11
|
+
# -------------------------
|
|
12
|
+
# Canonical order and functional classifications
|
|
13
|
+
# -------------------------
|
|
14
|
+
|
|
15
|
+
GLYPHS_CANONICAL: tuple[str, ...] = (
|
|
16
|
+
Glyph.AL.value, # 0
|
|
17
|
+
Glyph.EN.value, # 1
|
|
18
|
+
Glyph.IL.value, # 2
|
|
19
|
+
Glyph.OZ.value, # 3
|
|
20
|
+
Glyph.UM.value, # 4
|
|
21
|
+
Glyph.RA.value, # 5
|
|
22
|
+
Glyph.SHA.value, # 6
|
|
23
|
+
Glyph.VAL.value, # 7
|
|
24
|
+
Glyph.NUL.value, # 8
|
|
25
|
+
Glyph.THOL.value, # 9
|
|
26
|
+
Glyph.ZHIR.value, # 10
|
|
27
|
+
Glyph.NAV.value, # 11
|
|
28
|
+
Glyph.REMESH.value, # 12
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
GLYPHS_CANONICAL_SET: frozenset[str] = frozenset(GLYPHS_CANONICAL)
|
|
32
|
+
|
|
33
|
+
STABILIZERS: tuple[str, ...] = (
|
|
34
|
+
Glyph.IL.value,
|
|
35
|
+
Glyph.RA.value,
|
|
36
|
+
Glyph.UM.value,
|
|
37
|
+
Glyph.SHA.value,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
DISRUPTORS: tuple[str, ...] = (
|
|
41
|
+
Glyph.OZ.value,
|
|
42
|
+
Glyph.ZHIR.value,
|
|
43
|
+
Glyph.NAV.value,
|
|
44
|
+
Glyph.THOL.value,
|
|
45
|
+
)
|
|
46
|
+
|
|
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.
|
|
53
|
+
GLYPH_GROUPS: Mapping[str, tuple[str, ...]] = MappingProxyType(
|
|
54
|
+
{
|
|
55
|
+
"stabilizers": STABILIZERS,
|
|
56
|
+
"disruptors": DISRUPTORS,
|
|
57
|
+
# Auxiliary groups for morphosyntactic metrics
|
|
58
|
+
"ID": (Glyph.OZ.value,),
|
|
59
|
+
"CM": (Glyph.ZHIR.value, Glyph.NAV.value),
|
|
60
|
+
"NE": (Glyph.IL.value, Glyph.THOL.value),
|
|
61
|
+
"PP_num": (Glyph.SHA.value,),
|
|
62
|
+
"PP_den": (Glyph.REMESH.value,),
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# -------------------------
|
|
67
|
+
# Glyph angle map
|
|
68
|
+
# -------------------------
|
|
69
|
+
|
|
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.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _build_angle_map() -> dict[str, float]:
|
|
76
|
+
"""Build the angle map in the σ-plane."""
|
|
77
|
+
|
|
78
|
+
step = 2 * math.pi / len(GLYPHS_CANONICAL)
|
|
79
|
+
canonical = {g: i * step for i, g in enumerate(GLYPHS_CANONICAL)}
|
|
80
|
+
angles = dict(canonical)
|
|
81
|
+
|
|
82
|
+
# Orientation rules
|
|
83
|
+
for idx, g in enumerate(STABILIZERS):
|
|
84
|
+
angles[g] = idx * math.pi / 4
|
|
85
|
+
for idx, g in enumerate(DISRUPTORS):
|
|
86
|
+
angles[g] = math.pi + idx * math.pi / 4
|
|
87
|
+
|
|
88
|
+
# Manual exceptions
|
|
89
|
+
angles[Glyph.VAL.value] = canonical[Glyph.RA.value]
|
|
90
|
+
angles[Glyph.NUL.value] = canonical[Glyph.ZHIR.value]
|
|
91
|
+
angles[Glyph.AL.value] = 0.0
|
|
92
|
+
return angles
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
ANGLE_MAP: Mapping[str, float] = MappingProxyType(_build_angle_map())
|
|
96
|
+
|
|
97
|
+
__all__ = (
|
|
98
|
+
"GLYPHS_CANONICAL",
|
|
99
|
+
"GLYPHS_CANONICAL_SET",
|
|
100
|
+
"STABILIZERS",
|
|
101
|
+
"DISRUPTORS",
|
|
102
|
+
"GLYPH_GROUPS",
|
|
103
|
+
"ANGLE_MAP",
|
|
104
|
+
)
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Core configuration helpers."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
from collections.abc import Mapping
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
8
|
|
|
9
|
-
from
|
|
9
|
+
from ..constants import inject_defaults
|
|
10
|
+
from ..io import read_structured_file
|
|
10
11
|
|
|
11
12
|
if TYPE_CHECKING: # pragma: no cover - only for type checkers
|
|
12
|
-
import networkx as nx
|
|
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
|
|
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,106 @@
|
|
|
1
|
+
"""Canonical operator name constants and reusable sets."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Canonical operator identifiers (English tokens)
|
|
9
|
+
EMISSION = "emission"
|
|
10
|
+
RECEPTION = "reception"
|
|
11
|
+
COHERENCE = "coherence"
|
|
12
|
+
DISSONANCE = "dissonance"
|
|
13
|
+
COUPLING = "coupling"
|
|
14
|
+
RESONANCE = "resonance"
|
|
15
|
+
SILENCE = "silence"
|
|
16
|
+
EXPANSION = "expansion"
|
|
17
|
+
CONTRACTION = "contraction"
|
|
18
|
+
SELF_ORGANIZATION = "self_organization"
|
|
19
|
+
MUTATION = "mutation"
|
|
20
|
+
TRANSITION = "transition"
|
|
21
|
+
RECURSIVITY = "recursivity"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Canonical collections -------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
CANONICAL_OPERATOR_NAMES = frozenset(
|
|
27
|
+
{
|
|
28
|
+
EMISSION,
|
|
29
|
+
RECEPTION,
|
|
30
|
+
COHERENCE,
|
|
31
|
+
DISSONANCE,
|
|
32
|
+
COUPLING,
|
|
33
|
+
RESONANCE,
|
|
34
|
+
SILENCE,
|
|
35
|
+
EXPANSION,
|
|
36
|
+
CONTRACTION,
|
|
37
|
+
SELF_ORGANIZATION,
|
|
38
|
+
MUTATION,
|
|
39
|
+
TRANSITION,
|
|
40
|
+
RECURSIVITY,
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
ALL_OPERATOR_NAMES = CANONICAL_OPERATOR_NAMES
|
|
45
|
+
ENGLISH_OPERATOR_NAMES = CANONICAL_OPERATOR_NAMES
|
|
46
|
+
|
|
47
|
+
VALID_START_OPERATORS = frozenset({EMISSION, RECURSIVITY})
|
|
48
|
+
INTERMEDIATE_OPERATORS = frozenset({DISSONANCE, COUPLING, RESONANCE})
|
|
49
|
+
VALID_END_OPERATORS = frozenset({SILENCE, TRANSITION, RECURSIVITY})
|
|
50
|
+
SELF_ORGANIZATION_CLOSURES = frozenset({SILENCE, CONTRACTION})
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
_LEGACY_COLLECTION_ALIASES: dict[str, str] = {
|
|
54
|
+
"INICIO_VALIDOS": "VALID_START_OPERATORS",
|
|
55
|
+
"TRAMO_INTERMEDIO": "INTERMEDIATE_OPERATORS",
|
|
56
|
+
"CIERRE_VALIDO": "VALID_END_OPERATORS",
|
|
57
|
+
"AUTOORGANIZACION_CIERRES": "SELF_ORGANIZATION_CLOSURES",
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
def canonical_operator_name(name: str) -> str:
|
|
61
|
+
"""Return the canonical operator token for ``name``."""
|
|
62
|
+
|
|
63
|
+
return name
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def operator_display_name(name: str) -> str:
|
|
67
|
+
"""Return the display label for ``name`` (currently the canonical token)."""
|
|
68
|
+
|
|
69
|
+
return canonical_operator_name(name)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
__all__ = [
|
|
73
|
+
"EMISSION",
|
|
74
|
+
"RECEPTION",
|
|
75
|
+
"COHERENCE",
|
|
76
|
+
"DISSONANCE",
|
|
77
|
+
"COUPLING",
|
|
78
|
+
"RESONANCE",
|
|
79
|
+
"SILENCE",
|
|
80
|
+
"EXPANSION",
|
|
81
|
+
"CONTRACTION",
|
|
82
|
+
"SELF_ORGANIZATION",
|
|
83
|
+
"MUTATION",
|
|
84
|
+
"TRANSITION",
|
|
85
|
+
"RECURSIVITY",
|
|
86
|
+
"CANONICAL_OPERATOR_NAMES",
|
|
87
|
+
"ENGLISH_OPERATOR_NAMES",
|
|
88
|
+
"ALL_OPERATOR_NAMES",
|
|
89
|
+
"VALID_START_OPERATORS",
|
|
90
|
+
"INTERMEDIATE_OPERATORS",
|
|
91
|
+
"VALID_END_OPERATORS",
|
|
92
|
+
"SELF_ORGANIZATION_CLOSURES",
|
|
93
|
+
"canonical_operator_name",
|
|
94
|
+
"operator_display_name",
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def __getattr__(name: str) -> Any:
|
|
99
|
+
"""Provide guidance for legacy operator collection aliases."""
|
|
100
|
+
|
|
101
|
+
canonical = _LEGACY_COLLECTION_ALIASES.get(name)
|
|
102
|
+
if canonical is not None:
|
|
103
|
+
raise AttributeError(
|
|
104
|
+
f"module '{__name__}' has no attribute '{name}'; use '{canonical}' instead."
|
|
105
|
+
)
|
|
106
|
+
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
|