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/metrics/common.py
CHANGED
|
@@ -6,12 +6,10 @@ from types import MappingProxyType
|
|
|
6
6
|
from typing import Any, Iterable, Mapping, Sequence
|
|
7
7
|
|
|
8
8
|
from ..alias import collect_attr, get_attr, multi_recompute_abs_max
|
|
9
|
-
from ..collections_utils import normalize_weights
|
|
10
9
|
from ..constants import DEFAULTS, get_aliases
|
|
11
|
-
from ..cache import edge_version_cache
|
|
12
10
|
from ..helpers.numeric import clamp01, kahan_sum_nd
|
|
13
|
-
from ..import_utils import get_numpy
|
|
14
11
|
from ..types import GraphLike
|
|
12
|
+
from ..utils import edge_version_cache, get_numpy, normalize_weights
|
|
15
13
|
|
|
16
14
|
ALIAS_DNFR = get_aliases("DNFR")
|
|
17
15
|
ALIAS_D2EPI = get_aliases("D2EPI")
|
tnfr/metrics/common.pyi
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
__all__: Any
|
|
4
|
+
|
|
5
|
+
def __getattr__(name: str) -> Any: ...
|
|
6
|
+
|
|
7
|
+
GraphLike: Any
|
|
8
|
+
_get_vf_dnfr_max: Any
|
|
9
|
+
compute_coherence: Any
|
|
10
|
+
compute_dnfr_accel_max: Any
|
|
11
|
+
ensure_neighbors_map: Any
|
|
12
|
+
merge_and_normalize_weights: Any
|
|
13
|
+
merge_graph_weights: Any
|
|
14
|
+
min_max_range: Any
|
|
15
|
+
normalize_dnfr: Any
|
tnfr/metrics/core.py
CHANGED
|
@@ -2,12 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from typing import Any, NamedTuple, cast
|
|
7
|
+
|
|
8
|
+
from ..types import (
|
|
9
|
+
GlyphSelector,
|
|
10
|
+
NodeId,
|
|
11
|
+
SelectorPreselectionChoices,
|
|
12
|
+
SelectorPreselectionMetrics,
|
|
13
|
+
SelectorPreselectionPayload,
|
|
14
|
+
TNFRGraph,
|
|
15
|
+
TraceCallback,
|
|
16
|
+
TraceFieldFn,
|
|
17
|
+
TraceFieldMap,
|
|
18
|
+
TraceFieldRegistry,
|
|
19
|
+
)
|
|
6
20
|
|
|
7
21
|
from ..callback_utils import CallbackEvent, callback_manager
|
|
8
22
|
from ..constants import get_param
|
|
9
23
|
from ..glyph_history import append_metric, ensure_history
|
|
10
|
-
from ..
|
|
24
|
+
from ..utils import get_logger
|
|
25
|
+
from ..telemetry.verbosity import (
|
|
26
|
+
TelemetryVerbosity,
|
|
27
|
+
TELEMETRY_VERBOSITY_DEFAULT,
|
|
28
|
+
TELEMETRY_VERBOSITY_LEVELS,
|
|
29
|
+
)
|
|
11
30
|
from .coherence import (
|
|
12
31
|
_aggregate_si,
|
|
13
32
|
_track_stability,
|
|
@@ -15,9 +34,10 @@ from .coherence import (
|
|
|
15
34
|
_update_phase_sync,
|
|
16
35
|
_update_sigma,
|
|
17
36
|
register_coherence_callbacks,
|
|
37
|
+
GLYPH_LOAD_STABILIZERS_KEY,
|
|
18
38
|
)
|
|
19
39
|
from .diagnosis import register_diagnosis_callbacks
|
|
20
|
-
from .glyph_timing import _compute_advanced_metrics
|
|
40
|
+
from .glyph_timing import _compute_advanced_metrics, GlyphMetricsHistory
|
|
21
41
|
from .reporting import (
|
|
22
42
|
Tg_by_node,
|
|
23
43
|
Tg_global,
|
|
@@ -29,6 +49,16 @@ from .reporting import (
|
|
|
29
49
|
logger = get_logger(__name__)
|
|
30
50
|
|
|
31
51
|
__all__ = [
|
|
52
|
+
"TNFRGraph",
|
|
53
|
+
"NodeId",
|
|
54
|
+
"GlyphSelector",
|
|
55
|
+
"SelectorPreselectionMetrics",
|
|
56
|
+
"SelectorPreselectionChoices",
|
|
57
|
+
"SelectorPreselectionPayload",
|
|
58
|
+
"TraceCallback",
|
|
59
|
+
"TraceFieldFn",
|
|
60
|
+
"TraceFieldMap",
|
|
61
|
+
"TraceFieldRegistry",
|
|
32
62
|
"_metrics_step",
|
|
33
63
|
"register_metrics_callbacks",
|
|
34
64
|
"Tg_global",
|
|
@@ -39,32 +69,124 @@ __all__ = [
|
|
|
39
69
|
]
|
|
40
70
|
|
|
41
71
|
|
|
42
|
-
|
|
72
|
+
class MetricsVerbositySpec(NamedTuple):
|
|
73
|
+
"""Runtime configuration for metrics verbosity tiers."""
|
|
74
|
+
|
|
75
|
+
name: str
|
|
76
|
+
enable_phase_sync: bool
|
|
77
|
+
enable_sigma: bool
|
|
78
|
+
enable_aggregate_si: bool
|
|
79
|
+
enable_advanced: bool
|
|
80
|
+
attach_coherence_hooks: bool
|
|
81
|
+
attach_diagnosis_hooks: bool
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
METRICS_VERBOSITY_DEFAULT = TELEMETRY_VERBOSITY_DEFAULT
|
|
85
|
+
|
|
86
|
+
_METRICS_VERBOSITY_PRESETS: dict[str, MetricsVerbositySpec] = {}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _register_metrics_preset(spec: MetricsVerbositySpec) -> None:
|
|
90
|
+
if spec.name not in TELEMETRY_VERBOSITY_LEVELS:
|
|
91
|
+
raise ValueError(
|
|
92
|
+
"Unknown metrics verbosity '%s'; use %s" % (
|
|
93
|
+
spec.name,
|
|
94
|
+
", ".join(TELEMETRY_VERBOSITY_LEVELS),
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
_METRICS_VERBOSITY_PRESETS[spec.name] = spec
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
_register_metrics_preset(
|
|
101
|
+
MetricsVerbositySpec(
|
|
102
|
+
name=TelemetryVerbosity.BASIC.value,
|
|
103
|
+
enable_phase_sync=False,
|
|
104
|
+
enable_sigma=False,
|
|
105
|
+
enable_aggregate_si=False,
|
|
106
|
+
enable_advanced=False,
|
|
107
|
+
attach_coherence_hooks=False,
|
|
108
|
+
attach_diagnosis_hooks=False,
|
|
109
|
+
)
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
_detailed_spec = MetricsVerbositySpec(
|
|
113
|
+
name=TelemetryVerbosity.DETAILED.value,
|
|
114
|
+
enable_phase_sync=True,
|
|
115
|
+
enable_sigma=True,
|
|
116
|
+
enable_aggregate_si=True,
|
|
117
|
+
enable_advanced=False,
|
|
118
|
+
attach_coherence_hooks=True,
|
|
119
|
+
attach_diagnosis_hooks=False,
|
|
120
|
+
)
|
|
121
|
+
_register_metrics_preset(_detailed_spec)
|
|
122
|
+
_register_metrics_preset(
|
|
123
|
+
_detailed_spec._replace(
|
|
124
|
+
name=TelemetryVerbosity.DEBUG.value,
|
|
125
|
+
enable_advanced=True,
|
|
126
|
+
attach_diagnosis_hooks=True,
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
_METRICS_BASE_HISTORY_KEYS = ("C_steps", "stable_frac", "delta_Si", "B")
|
|
132
|
+
_METRICS_PHASE_HISTORY_KEYS = ("phase_sync", "kuramoto_R")
|
|
133
|
+
_METRICS_SIGMA_HISTORY_KEYS = (
|
|
134
|
+
GLYPH_LOAD_STABILIZERS_KEY,
|
|
135
|
+
"glyph_load_disr",
|
|
136
|
+
"sense_sigma_x",
|
|
137
|
+
"sense_sigma_y",
|
|
138
|
+
"sense_sigma_mag",
|
|
139
|
+
"sense_sigma_angle",
|
|
140
|
+
)
|
|
141
|
+
_METRICS_SI_HISTORY_KEYS = ("Si_mean", "Si_hi_frac", "Si_lo_frac")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _resolve_metrics_verbosity(cfg: Mapping[str, Any]) -> MetricsVerbositySpec:
|
|
145
|
+
"""Return the preset matching ``cfg['verbosity']``."""
|
|
146
|
+
|
|
147
|
+
raw_value = cfg.get("verbosity", METRICS_VERBOSITY_DEFAULT)
|
|
148
|
+
key = str(raw_value).lower()
|
|
149
|
+
spec = _METRICS_VERBOSITY_PRESETS.get(key)
|
|
150
|
+
if spec is not None:
|
|
151
|
+
return spec
|
|
152
|
+
logger.warning(
|
|
153
|
+
"Unknown METRICS verbosity '%s'; falling back to '%s'",
|
|
154
|
+
raw_value,
|
|
155
|
+
METRICS_VERBOSITY_DEFAULT,
|
|
156
|
+
)
|
|
157
|
+
return _METRICS_VERBOSITY_PRESETS[METRICS_VERBOSITY_DEFAULT]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _metrics_step(G: TNFRGraph, ctx: dict[str, Any] | None = None) -> None:
|
|
43
161
|
"""Update operational TNFR metrics per step."""
|
|
44
162
|
|
|
45
163
|
del ctx
|
|
46
164
|
|
|
47
|
-
cfg = get_param(G, "METRICS")
|
|
165
|
+
cfg = cast(Mapping[str, Any], get_param(G, "METRICS"))
|
|
48
166
|
if not cfg.get("enabled", True):
|
|
49
167
|
return
|
|
50
168
|
|
|
169
|
+
spec = _resolve_metrics_verbosity(cfg)
|
|
51
170
|
hist = ensure_history(G)
|
|
171
|
+
if "glyph_load_estab" in hist:
|
|
172
|
+
raise ValueError(
|
|
173
|
+
"History payloads using 'glyph_load_estab' are no longer supported. "
|
|
174
|
+
"Rename the series to 'glyph_load_stabilizers' before loading the graph."
|
|
175
|
+
)
|
|
52
176
|
metrics_sentinel_key = "_metrics_history_id"
|
|
53
177
|
history_id = id(hist)
|
|
54
178
|
if G.graph.get(metrics_sentinel_key) != history_id:
|
|
55
|
-
for
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
):
|
|
67
|
-
hist.setdefault(k, [])
|
|
179
|
+
for key in _METRICS_BASE_HISTORY_KEYS:
|
|
180
|
+
hist.setdefault(key, [])
|
|
181
|
+
if spec.enable_phase_sync:
|
|
182
|
+
for key in _METRICS_PHASE_HISTORY_KEYS:
|
|
183
|
+
hist.setdefault(key, [])
|
|
184
|
+
if spec.enable_sigma:
|
|
185
|
+
for key in _METRICS_SIGMA_HISTORY_KEYS:
|
|
186
|
+
hist.setdefault(key, [])
|
|
187
|
+
if spec.enable_aggregate_si:
|
|
188
|
+
for key in _METRICS_SI_HISTORY_KEYS:
|
|
189
|
+
hist.setdefault(key, [])
|
|
68
190
|
G.graph[metrics_sentinel_key] = history_id
|
|
69
191
|
|
|
70
192
|
dt = float(get_param(G, "DT"))
|
|
@@ -73,29 +195,65 @@ def _metrics_step(G, ctx: dict[str, Any] | None = None):
|
|
|
73
195
|
t = float(G.graph.get("_t", 0.0))
|
|
74
196
|
|
|
75
197
|
_update_coherence(G, hist)
|
|
76
|
-
|
|
198
|
+
|
|
199
|
+
raw_jobs = cfg.get("n_jobs")
|
|
200
|
+
metrics_jobs: int | None
|
|
77
201
|
try:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
202
|
+
metrics_jobs = None if raw_jobs is None else int(raw_jobs)
|
|
203
|
+
except (TypeError, ValueError):
|
|
204
|
+
metrics_jobs = None
|
|
205
|
+
else:
|
|
206
|
+
if metrics_jobs <= 0:
|
|
207
|
+
metrics_jobs = None
|
|
208
|
+
|
|
209
|
+
_track_stability(
|
|
210
|
+
G,
|
|
211
|
+
hist,
|
|
212
|
+
dt,
|
|
213
|
+
eps_dnfr,
|
|
214
|
+
eps_depi,
|
|
215
|
+
n_jobs=metrics_jobs,
|
|
216
|
+
)
|
|
217
|
+
if spec.enable_phase_sync or spec.enable_sigma:
|
|
218
|
+
try:
|
|
219
|
+
if spec.enable_phase_sync:
|
|
220
|
+
_update_phase_sync(G, hist)
|
|
221
|
+
if spec.enable_sigma:
|
|
222
|
+
_update_sigma(G, hist)
|
|
223
|
+
except (KeyError, AttributeError, TypeError) as exc:
|
|
224
|
+
logger.debug("observer update failed: %s", exc)
|
|
225
|
+
|
|
226
|
+
if hist.get("C_steps") and hist.get("stable_frac"):
|
|
227
|
+
append_metric(
|
|
228
|
+
hist,
|
|
229
|
+
"iota",
|
|
230
|
+
hist["C_steps"][-1] * hist["stable_frac"][-1],
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
if spec.enable_aggregate_si:
|
|
234
|
+
_aggregate_si(G, hist, n_jobs=metrics_jobs)
|
|
88
235
|
|
|
89
|
-
|
|
90
|
-
|
|
236
|
+
if spec.enable_advanced:
|
|
237
|
+
_compute_advanced_metrics(
|
|
238
|
+
G,
|
|
239
|
+
cast(GlyphMetricsHistory, hist),
|
|
240
|
+
t,
|
|
241
|
+
dt,
|
|
242
|
+
cfg,
|
|
243
|
+
n_jobs=metrics_jobs,
|
|
244
|
+
)
|
|
91
245
|
|
|
92
246
|
|
|
93
|
-
def register_metrics_callbacks(G) -> None:
|
|
247
|
+
def register_metrics_callbacks(G: TNFRGraph) -> None:
|
|
248
|
+
cfg = cast(Mapping[str, Any], get_param(G, "METRICS"))
|
|
249
|
+
spec = _resolve_metrics_verbosity(cfg)
|
|
94
250
|
callback_manager.register_callback(
|
|
95
251
|
G,
|
|
96
252
|
event=CallbackEvent.AFTER_STEP.value,
|
|
97
253
|
func=_metrics_step,
|
|
98
254
|
name="metrics_step",
|
|
99
255
|
)
|
|
100
|
-
|
|
101
|
-
|
|
256
|
+
if spec.attach_coherence_hooks:
|
|
257
|
+
register_coherence_callbacks(G)
|
|
258
|
+
if spec.attach_diagnosis_hooks:
|
|
259
|
+
register_diagnosis_callbacks(G)
|
tnfr/metrics/core.pyi
ADDED