tnfr 6.0.0__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.
- tnfr/__init__.py +50 -5
- tnfr/__init__.pyi +0 -7
- tnfr/_compat.py +0 -1
- tnfr/_generated_version.py +34 -0
- tnfr/_version.py +44 -2
- tnfr/alias.py +14 -13
- tnfr/alias.pyi +5 -37
- tnfr/cache.py +9 -729
- tnfr/cache.pyi +8 -224
- tnfr/callback_utils.py +16 -31
- tnfr/callback_utils.pyi +3 -29
- tnfr/cli/__init__.py +17 -11
- tnfr/cli/__init__.pyi +0 -21
- tnfr/cli/arguments.py +175 -14
- tnfr/cli/arguments.pyi +5 -11
- tnfr/cli/execution.py +434 -48
- tnfr/cli/execution.pyi +14 -24
- tnfr/cli/utils.py +20 -3
- tnfr/cli/utils.pyi +5 -5
- tnfr/config/__init__.py +2 -1
- tnfr/config/__init__.pyi +2 -0
- tnfr/config/feature_flags.py +83 -0
- tnfr/config/init.py +1 -1
- tnfr/config/operator_names.py +1 -14
- tnfr/config/presets.py +6 -26
- tnfr/constants/__init__.py +10 -13
- tnfr/constants/__init__.pyi +10 -22
- tnfr/constants/aliases.py +31 -0
- tnfr/constants/core.py +4 -3
- tnfr/constants/init.py +1 -1
- tnfr/constants/metric.py +3 -3
- tnfr/dynamics/__init__.py +64 -10
- tnfr/dynamics/__init__.pyi +3 -4
- tnfr/dynamics/adaptation.py +79 -13
- tnfr/dynamics/aliases.py +10 -9
- tnfr/dynamics/coordination.py +77 -35
- tnfr/dynamics/dnfr.py +575 -274
- tnfr/dynamics/dnfr.pyi +1 -10
- tnfr/dynamics/integrators.py +47 -33
- tnfr/dynamics/integrators.pyi +0 -1
- tnfr/dynamics/runtime.py +489 -129
- tnfr/dynamics/sampling.py +2 -0
- tnfr/dynamics/selectors.py +101 -62
- tnfr/execution.py +15 -8
- tnfr/execution.pyi +5 -25
- tnfr/flatten.py +7 -3
- tnfr/flatten.pyi +1 -8
- tnfr/gamma.py +22 -26
- tnfr/gamma.pyi +0 -6
- tnfr/glyph_history.py +37 -26
- tnfr/glyph_history.pyi +1 -19
- tnfr/glyph_runtime.py +16 -0
- tnfr/glyph_runtime.pyi +9 -0
- tnfr/immutable.py +20 -15
- tnfr/immutable.pyi +4 -7
- tnfr/initialization.py +5 -7
- tnfr/initialization.pyi +1 -9
- tnfr/io.py +6 -305
- tnfr/io.pyi +13 -8
- tnfr/mathematics/__init__.py +81 -0
- tnfr/mathematics/backend.py +426 -0
- tnfr/mathematics/dynamics.py +398 -0
- tnfr/mathematics/epi.py +254 -0
- tnfr/mathematics/generators.py +222 -0
- tnfr/mathematics/metrics.py +119 -0
- tnfr/mathematics/operators.py +233 -0
- tnfr/mathematics/operators_factory.py +71 -0
- tnfr/mathematics/projection.py +78 -0
- tnfr/mathematics/runtime.py +173 -0
- tnfr/mathematics/spaces.py +247 -0
- tnfr/mathematics/transforms.py +292 -0
- tnfr/metrics/__init__.py +10 -10
- tnfr/metrics/coherence.py +123 -94
- tnfr/metrics/common.py +22 -13
- tnfr/metrics/common.pyi +42 -11
- tnfr/metrics/core.py +72 -14
- tnfr/metrics/diagnosis.py +48 -57
- tnfr/metrics/diagnosis.pyi +3 -7
- tnfr/metrics/export.py +3 -5
- tnfr/metrics/glyph_timing.py +41 -31
- tnfr/metrics/reporting.py +13 -6
- tnfr/metrics/sense_index.py +884 -114
- tnfr/metrics/trig.py +167 -11
- tnfr/metrics/trig.pyi +1 -0
- tnfr/metrics/trig_cache.py +112 -15
- tnfr/node.py +400 -17
- tnfr/node.pyi +55 -38
- tnfr/observers.py +111 -8
- tnfr/observers.pyi +0 -15
- tnfr/ontosim.py +9 -6
- tnfr/ontosim.pyi +0 -5
- tnfr/operators/__init__.py +529 -42
- tnfr/operators/__init__.pyi +14 -0
- tnfr/operators/definitions.py +350 -18
- tnfr/operators/definitions.pyi +0 -14
- tnfr/operators/grammar.py +760 -0
- tnfr/operators/jitter.py +28 -22
- tnfr/operators/registry.py +7 -12
- tnfr/operators/registry.pyi +0 -2
- tnfr/operators/remesh.py +38 -61
- tnfr/rng.py +17 -300
- tnfr/schemas/__init__.py +8 -0
- tnfr/schemas/grammar.json +94 -0
- tnfr/selector.py +3 -4
- tnfr/selector.pyi +1 -1
- tnfr/sense.py +22 -24
- tnfr/sense.pyi +0 -7
- tnfr/structural.py +504 -21
- tnfr/structural.pyi +41 -18
- tnfr/telemetry/__init__.py +23 -1
- tnfr/telemetry/cache_metrics.py +226 -0
- tnfr/telemetry/nu_f.py +423 -0
- tnfr/telemetry/nu_f.pyi +123 -0
- tnfr/tokens.py +1 -4
- tnfr/tokens.pyi +1 -6
- tnfr/trace.py +20 -53
- tnfr/trace.pyi +9 -37
- tnfr/types.py +244 -15
- tnfr/types.pyi +200 -14
- tnfr/units.py +69 -0
- tnfr/units.pyi +16 -0
- tnfr/utils/__init__.py +107 -48
- tnfr/utils/__init__.pyi +80 -11
- tnfr/utils/cache.py +1705 -65
- tnfr/utils/cache.pyi +370 -58
- tnfr/utils/chunks.py +104 -0
- tnfr/utils/chunks.pyi +21 -0
- tnfr/utils/data.py +95 -5
- tnfr/utils/data.pyi +8 -17
- tnfr/utils/graph.py +2 -4
- tnfr/utils/init.py +31 -7
- tnfr/utils/init.pyi +4 -11
- tnfr/utils/io.py +313 -14
- tnfr/{helpers → utils}/numeric.py +50 -24
- tnfr/utils/numeric.pyi +21 -0
- tnfr/validation/__init__.py +92 -4
- tnfr/validation/__init__.pyi +77 -17
- tnfr/validation/compatibility.py +79 -43
- tnfr/validation/compatibility.pyi +4 -6
- tnfr/validation/grammar.py +55 -133
- tnfr/validation/grammar.pyi +37 -8
- tnfr/validation/graph.py +138 -0
- tnfr/validation/graph.pyi +17 -0
- tnfr/validation/rules.py +161 -74
- tnfr/validation/rules.pyi +55 -18
- tnfr/validation/runtime.py +263 -0
- tnfr/validation/runtime.pyi +31 -0
- tnfr/validation/soft_filters.py +170 -0
- tnfr/validation/soft_filters.pyi +37 -0
- tnfr/validation/spectral.py +159 -0
- tnfr/validation/spectral.pyi +46 -0
- tnfr/validation/syntax.py +28 -139
- tnfr/validation/syntax.pyi +7 -4
- tnfr/validation/window.py +39 -0
- tnfr/validation/window.pyi +1 -0
- tnfr/viz/__init__.py +9 -0
- tnfr/viz/matplotlib.py +246 -0
- {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/METADATA +63 -19
- tnfr-7.0.0.dist-info/RECORD +185 -0
- {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/licenses/LICENSE.md +1 -1
- tnfr/constants_glyphs.py +0 -16
- tnfr/constants_glyphs.pyi +0 -12
- tnfr/grammar.py +0 -25
- tnfr/grammar.pyi +0 -13
- tnfr/helpers/__init__.py +0 -151
- tnfr/helpers/__init__.pyi +0 -66
- tnfr/helpers/numeric.pyi +0 -12
- tnfr/presets.py +0 -15
- tnfr/presets.pyi +0 -7
- tnfr/utils/io.pyi +0 -10
- tnfr/utils/validators.py +0 -130
- tnfr/utils/validators.pyi +0 -19
- tnfr-6.0.0.dist-info/RECORD +0 -157
- {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/WHEEL +0 -0
- {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/entry_points.txt +0 -0
- {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/top_level.txt +0 -0
tnfr/node.pyi
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from collections.abc import Hashable, Iterable, MutableMapping
|
|
3
|
+
from collections.abc import Hashable, Iterable, MutableMapping, Sequence
|
|
4
4
|
from typing import Any, Callable, Optional, Protocol, SupportsFloat, TypeVar
|
|
5
5
|
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from .mathematics import (
|
|
9
|
+
CoherenceOperator,
|
|
10
|
+
FrequencyOperator,
|
|
11
|
+
HilbertSpace,
|
|
12
|
+
NFRValidator,
|
|
13
|
+
StateProjector,
|
|
14
|
+
)
|
|
6
15
|
from .types import (
|
|
7
16
|
CouplingWeight,
|
|
8
17
|
DeltaNFR,
|
|
@@ -19,7 +28,6 @@ T = TypeVar("T")
|
|
|
19
28
|
|
|
20
29
|
__all__ = ("NodeNX", "NodeProtocol", "add_edge")
|
|
21
30
|
|
|
22
|
-
|
|
23
31
|
class AttrSpec:
|
|
24
32
|
aliases: tuple[str, ...]
|
|
25
33
|
default: Any
|
|
@@ -31,7 +39,6 @@ class AttrSpec:
|
|
|
31
39
|
|
|
32
40
|
def build_property(self) -> property: ...
|
|
33
41
|
|
|
34
|
-
|
|
35
42
|
ALIAS_EPI: tuple[str, ...]
|
|
36
43
|
ALIAS_VF: tuple[str, ...]
|
|
37
44
|
ALIAS_THETA: tuple[str, ...]
|
|
@@ -42,14 +49,11 @@ ALIAS_D2EPI: tuple[str, ...]
|
|
|
42
49
|
|
|
43
50
|
ATTR_SPECS: dict[str, AttrSpec]
|
|
44
51
|
|
|
45
|
-
|
|
46
52
|
def _add_edge_common(
|
|
47
53
|
n1: NodeId,
|
|
48
54
|
n2: NodeId,
|
|
49
55
|
weight: CouplingWeight | SupportsFloat | str,
|
|
50
56
|
) -> Optional[CouplingWeight]: ...
|
|
51
|
-
|
|
52
|
-
|
|
53
57
|
def add_edge(
|
|
54
58
|
graph: TNFRGraph,
|
|
55
59
|
n1: NodeId,
|
|
@@ -58,7 +62,6 @@ def add_edge(
|
|
|
58
62
|
overwrite: bool = ...,
|
|
59
63
|
) -> None: ...
|
|
60
64
|
|
|
61
|
-
|
|
62
65
|
class NodeProtocol(Protocol):
|
|
63
66
|
EPI: EPIValue
|
|
64
67
|
vf: StructuralFrequency
|
|
@@ -70,11 +73,8 @@ class NodeProtocol(Protocol):
|
|
|
70
73
|
graph: MutableMapping[str, Any]
|
|
71
74
|
|
|
72
75
|
def neighbors(self) -> Iterable[NodeProtocol | Hashable]: ...
|
|
73
|
-
|
|
74
76
|
def _glyph_storage(self) -> MutableMapping[str, object]: ...
|
|
75
|
-
|
|
76
77
|
def has_edge(self, other: NodeProtocol) -> bool: ...
|
|
77
|
-
|
|
78
78
|
def add_edge(
|
|
79
79
|
self,
|
|
80
80
|
other: NodeProtocol,
|
|
@@ -82,70 +82,72 @@ class NodeProtocol(Protocol):
|
|
|
82
82
|
*,
|
|
83
83
|
overwrite: bool = ...,
|
|
84
84
|
) -> None: ...
|
|
85
|
-
|
|
86
85
|
def offset(self) -> int: ...
|
|
87
|
-
|
|
88
86
|
def all_nodes(self) -> Iterable[NodeProtocol]: ...
|
|
89
87
|
|
|
90
|
-
|
|
91
88
|
class NodeNX(NodeProtocol):
|
|
92
89
|
G: TNFRGraph
|
|
93
90
|
n: NodeId
|
|
94
91
|
graph: MutableMapping[str, Any]
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
state_projector: StateProjector
|
|
93
|
+
hilbert_space: HilbertSpace
|
|
94
|
+
coherence_operator: CoherenceOperator | None
|
|
95
|
+
frequency_operator: FrequencyOperator | None
|
|
96
|
+
coherence_threshold: float | None
|
|
97
|
+
validator: NFRValidator | None
|
|
98
|
+
rng: np.random.Generator | None
|
|
99
|
+
|
|
100
|
+
def __init__(
|
|
101
|
+
self,
|
|
102
|
+
G: TNFRGraph,
|
|
103
|
+
n: NodeId,
|
|
104
|
+
*,
|
|
105
|
+
state_projector: StateProjector | None = ...,
|
|
106
|
+
enable_math_validation: Optional[bool] = ...,
|
|
107
|
+
hilbert_space: HilbertSpace | None = ...,
|
|
108
|
+
coherence_operator: CoherenceOperator | None = ...,
|
|
109
|
+
coherence_dim: int | None = ...,
|
|
110
|
+
coherence_spectrum: Sequence[float] | np.ndarray | None = ...,
|
|
111
|
+
coherence_c_min: float | None = ...,
|
|
112
|
+
frequency_operator: FrequencyOperator | None = ...,
|
|
113
|
+
frequency_matrix: Sequence[Sequence[complex]] | np.ndarray | None = ...,
|
|
114
|
+
coherence_threshold: float | None = ...,
|
|
115
|
+
validator: NFRValidator | None = ...,
|
|
116
|
+
rng: np.random.Generator | None = ...,
|
|
117
|
+
) -> None: ...
|
|
98
118
|
@classmethod
|
|
99
119
|
def from_graph(cls, G: TNFRGraph, n: NodeId) -> "NodeNX": ...
|
|
100
|
-
|
|
101
120
|
def _glyph_storage(self) -> MutableMapping[str, Any]: ...
|
|
102
|
-
|
|
103
121
|
@property
|
|
104
122
|
def EPI(self) -> EPIValue: ...
|
|
105
|
-
|
|
106
123
|
@EPI.setter
|
|
107
124
|
def EPI(self, value: EPIValue) -> None: ...
|
|
108
|
-
|
|
109
125
|
@property
|
|
110
126
|
def vf(self) -> StructuralFrequency: ...
|
|
111
|
-
|
|
112
127
|
@vf.setter
|
|
113
128
|
def vf(self, value: StructuralFrequency) -> None: ...
|
|
114
|
-
|
|
115
129
|
@property
|
|
116
130
|
def theta(self) -> Phase: ...
|
|
117
|
-
|
|
118
131
|
@theta.setter
|
|
119
132
|
def theta(self, value: Phase) -> None: ...
|
|
120
|
-
|
|
121
133
|
@property
|
|
122
134
|
def Si(self) -> SenseIndex: ...
|
|
123
|
-
|
|
124
135
|
@Si.setter
|
|
125
136
|
def Si(self, value: SenseIndex) -> None: ...
|
|
126
|
-
|
|
127
137
|
@property
|
|
128
138
|
def epi_kind(self) -> str: ...
|
|
129
|
-
|
|
130
139
|
@epi_kind.setter
|
|
131
140
|
def epi_kind(self, value: str) -> None: ...
|
|
132
|
-
|
|
133
141
|
@property
|
|
134
142
|
def dnfr(self) -> DeltaNFR: ...
|
|
135
|
-
|
|
136
143
|
@dnfr.setter
|
|
137
144
|
def dnfr(self, value: DeltaNFR) -> None: ...
|
|
138
|
-
|
|
139
145
|
@property
|
|
140
146
|
def d2EPI(self) -> SecondDerivativeEPI: ...
|
|
141
|
-
|
|
142
147
|
@d2EPI.setter
|
|
143
148
|
def d2EPI(self, value: SecondDerivativeEPI) -> None: ...
|
|
144
|
-
|
|
145
149
|
def neighbors(self) -> Iterable[NodeId]: ...
|
|
146
|
-
|
|
147
150
|
def has_edge(self, other: NodeProtocol) -> bool: ...
|
|
148
|
-
|
|
149
151
|
def add_edge(
|
|
150
152
|
self,
|
|
151
153
|
other: NodeProtocol,
|
|
@@ -153,9 +155,24 @@ class NodeNX(NodeProtocol):
|
|
|
153
155
|
*,
|
|
154
156
|
overwrite: bool = ...,
|
|
155
157
|
) -> None: ...
|
|
156
|
-
|
|
157
158
|
def offset(self) -> int: ...
|
|
158
|
-
|
|
159
159
|
def all_nodes(self) -> Iterable[NodeProtocol]: ...
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
def run_sequence_with_validation(
|
|
161
|
+
self,
|
|
162
|
+
ops: Iterable[Callable[[TNFRGraph, NodeId], None]],
|
|
163
|
+
*,
|
|
164
|
+
projector: StateProjector | None = ...,
|
|
165
|
+
hilbert_space: HilbertSpace | None = ...,
|
|
166
|
+
coherence_operator: CoherenceOperator | None = ...,
|
|
167
|
+
coherence_dim: int | None = ...,
|
|
168
|
+
coherence_spectrum: Sequence[float] | np.ndarray | None = ...,
|
|
169
|
+
coherence_c_min: float | None = ...,
|
|
170
|
+
coherence_threshold: float | None = ...,
|
|
171
|
+
frequency_operator: FrequencyOperator | None = ...,
|
|
172
|
+
frequency_matrix: Sequence[Sequence[complex]] | np.ndarray | None = ...,
|
|
173
|
+
validator: NFRValidator | None = ...,
|
|
174
|
+
enforce_frequency_positivity: bool | None = ...,
|
|
175
|
+
enable_validation: bool | None = ...,
|
|
176
|
+
rng: np.random.Generator | None = ...,
|
|
177
|
+
log_metrics: bool = ...,
|
|
178
|
+
) -> dict[str, Any]: ...
|
tnfr/observers.py
CHANGED
|
@@ -2,30 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import statistics
|
|
5
6
|
from collections.abc import Mapping
|
|
6
7
|
from functools import partial
|
|
7
|
-
import statistics
|
|
8
8
|
from statistics import StatisticsError, pvariance
|
|
9
9
|
|
|
10
10
|
from .alias import get_theta_attr
|
|
11
|
-
from .helpers.numeric import angle_diff
|
|
12
11
|
from .callback_utils import CallbackEvent, callback_manager
|
|
12
|
+
from .config.constants import GLYPH_GROUPS
|
|
13
|
+
from .gamma import kuramoto_R_psi
|
|
13
14
|
from .glyph_history import (
|
|
14
|
-
ensure_history,
|
|
15
|
-
count_glyphs,
|
|
16
15
|
append_metric,
|
|
16
|
+
count_glyphs,
|
|
17
|
+
ensure_history,
|
|
17
18
|
)
|
|
19
|
+
from .utils import angle_diff
|
|
20
|
+
from .metrics.common import compute_coherence
|
|
18
21
|
from .types import Glyph, GlyphLoadDistribution, TNFRGraph
|
|
19
22
|
from .utils import (
|
|
20
23
|
get_logger,
|
|
21
24
|
get_numpy,
|
|
22
25
|
mix_groups,
|
|
23
26
|
normalize_counter,
|
|
24
|
-
validate_window,
|
|
25
27
|
)
|
|
26
|
-
from .
|
|
27
|
-
from .
|
|
28
|
-
from .metrics.common import compute_coherence
|
|
28
|
+
from .validation import validate_window
|
|
29
|
+
from .telemetry import ensure_nu_f_telemetry, record_nu_f_window
|
|
29
30
|
|
|
30
31
|
__all__ = (
|
|
31
32
|
"attach_standard_observer",
|
|
@@ -58,15 +59,114 @@ _STD_CALLBACKS = {
|
|
|
58
59
|
CallbackEvent.BEFORE_STEP.value: partial(_std_log, "before"),
|
|
59
60
|
CallbackEvent.AFTER_STEP.value: partial(_std_log, "after"),
|
|
60
61
|
CallbackEvent.ON_REMESH.value: partial(_std_log, "remesh"),
|
|
62
|
+
CallbackEvent.CACHE_METRICS.value: partial(_std_log, "cache"),
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
|
|
66
|
+
_REORG_STATE_KEY = "_std_observer_reorg"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _resolve_reorg_state(G: TNFRGraph) -> dict[str, object]:
|
|
70
|
+
state = G.graph.get(_REORG_STATE_KEY)
|
|
71
|
+
if not isinstance(state, dict):
|
|
72
|
+
state = {}
|
|
73
|
+
G.graph[_REORG_STATE_KEY] = state
|
|
74
|
+
return state
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _before_step_reorg(G: TNFRGraph, ctx: Mapping[str, object] | None) -> None:
|
|
78
|
+
"""Capture structural time metadata before the step starts."""
|
|
79
|
+
|
|
80
|
+
ensure_nu_f_telemetry(G, confidence_level=None)
|
|
81
|
+
state = _resolve_reorg_state(G)
|
|
82
|
+
step_idx = ctx.get("step") if ctx else None
|
|
83
|
+
try:
|
|
84
|
+
state["step"] = int(step_idx) if step_idx is not None else None
|
|
85
|
+
except (TypeError, ValueError):
|
|
86
|
+
state["step"] = None
|
|
87
|
+
start_t = float(G.graph.get("_t", 0.0))
|
|
88
|
+
state["start_t"] = start_t
|
|
89
|
+
dt_raw = ctx.get("dt") if ctx else None
|
|
90
|
+
try:
|
|
91
|
+
state["dt"] = float(dt_raw) if dt_raw is not None else None
|
|
92
|
+
except (TypeError, ValueError):
|
|
93
|
+
state["dt"] = None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _after_step_reorg(G: TNFRGraph, ctx: Mapping[str, object] | None) -> None:
|
|
97
|
+
"""Record the reorganisation window for νf telemetry."""
|
|
98
|
+
|
|
99
|
+
state = _resolve_reorg_state(G)
|
|
100
|
+
pending_step = state.get("step")
|
|
101
|
+
ctx_step = ctx.get("step") if ctx else None
|
|
102
|
+
if pending_step is not None and ctx_step is not None and pending_step != ctx_step:
|
|
103
|
+
# Ignore mismatched callbacks to avoid double counting.
|
|
104
|
+
return
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
start_t = float(state.get("start_t", float(G.graph.get("_t", 0.0))))
|
|
108
|
+
except (TypeError, ValueError):
|
|
109
|
+
start_t = float(G.graph.get("_t", 0.0))
|
|
110
|
+
end_t = float(G.graph.get("_t", start_t))
|
|
111
|
+
dt_raw = state.get("dt")
|
|
112
|
+
try:
|
|
113
|
+
duration = float(dt_raw) if dt_raw is not None else end_t - start_t
|
|
114
|
+
except (TypeError, ValueError):
|
|
115
|
+
duration = end_t - start_t
|
|
116
|
+
if duration <= 0.0:
|
|
117
|
+
duration = end_t - start_t
|
|
118
|
+
if duration <= 0.0:
|
|
119
|
+
return
|
|
120
|
+
|
|
121
|
+
stable_frac = ctx.get("stable_frac") if ctx else None
|
|
122
|
+
if stable_frac is None:
|
|
123
|
+
hist = ensure_history(G)
|
|
124
|
+
series = hist.get("stable_frac", [])
|
|
125
|
+
stable_frac = series[-1] if series else None
|
|
126
|
+
try:
|
|
127
|
+
stable_frac_f = float(stable_frac) if stable_frac is not None else None
|
|
128
|
+
except (TypeError, ValueError):
|
|
129
|
+
stable_frac_f = None
|
|
130
|
+
total_nodes = G.number_of_nodes()
|
|
131
|
+
if stable_frac_f is None:
|
|
132
|
+
reorganisations = total_nodes
|
|
133
|
+
else:
|
|
134
|
+
frac = min(max(stable_frac_f, 0.0), 1.0)
|
|
135
|
+
stable_nodes = int(round(frac * total_nodes))
|
|
136
|
+
reorganisations = max(total_nodes - stable_nodes, 0)
|
|
137
|
+
|
|
138
|
+
record_nu_f_window(
|
|
139
|
+
G,
|
|
140
|
+
reorganisations,
|
|
141
|
+
duration,
|
|
142
|
+
start=start_t,
|
|
143
|
+
end=end_t,
|
|
144
|
+
)
|
|
145
|
+
state["last_duration"] = duration
|
|
146
|
+
state["last_reorganisations"] = reorganisations
|
|
147
|
+
state["last_end_t"] = end_t
|
|
148
|
+
state["step"] = None
|
|
149
|
+
|
|
150
|
+
|
|
64
151
|
def attach_standard_observer(G: TNFRGraph) -> TNFRGraph:
|
|
65
152
|
"""Register standard callbacks: before_step, after_step, on_remesh."""
|
|
66
153
|
if G.graph.get("_STD_OBSERVER"):
|
|
67
154
|
return G
|
|
68
155
|
for event, fn in _STD_CALLBACKS.items():
|
|
69
156
|
callback_manager.register_callback(G, event, fn)
|
|
157
|
+
callback_manager.register_callback(
|
|
158
|
+
G,
|
|
159
|
+
CallbackEvent.BEFORE_STEP.value,
|
|
160
|
+
_before_step_reorg,
|
|
161
|
+
name="std_reorg_before",
|
|
162
|
+
)
|
|
163
|
+
callback_manager.register_callback(
|
|
164
|
+
G,
|
|
165
|
+
CallbackEvent.AFTER_STEP.value,
|
|
166
|
+
_after_step_reorg,
|
|
167
|
+
name="std_reorg_after",
|
|
168
|
+
)
|
|
169
|
+
ensure_nu_f_telemetry(G, confidence_level=None)
|
|
70
170
|
G.graph["_STD_OBSERVER"] = "attached"
|
|
71
171
|
return G
|
|
72
172
|
|
|
@@ -90,6 +190,8 @@ def phase_sync(
|
|
|
90
190
|
R: float | None = None,
|
|
91
191
|
psi: float | None = None,
|
|
92
192
|
) -> float:
|
|
193
|
+
"""Return a [0, 1] synchrony index derived from phase dispersion."""
|
|
194
|
+
|
|
93
195
|
if not _ensure_nodes(G):
|
|
94
196
|
return 1.0
|
|
95
197
|
if R is None or psi is None:
|
|
@@ -98,6 +200,7 @@ def phase_sync(
|
|
|
98
200
|
R = R_calc
|
|
99
201
|
if psi is None:
|
|
100
202
|
psi = psi_calc
|
|
203
|
+
|
|
101
204
|
def _theta(nd: Mapping[str, object]) -> float:
|
|
102
205
|
value = get_theta_attr(nd, 0.0)
|
|
103
206
|
return float(value) if value is not None else 0.0
|
tnfr/observers.pyi
CHANGED
|
@@ -10,37 +10,22 @@ __all__: tuple[str, ...]
|
|
|
10
10
|
DEFAULT_GLYPH_LOAD_SPAN: Final[int]
|
|
11
11
|
DEFAULT_WBAR_SPAN: Final[int]
|
|
12
12
|
|
|
13
|
-
|
|
14
13
|
def _std_log(kind: str, G: TNFRGraph, ctx: Mapping[str, object]) -> None: ...
|
|
15
|
-
|
|
16
|
-
|
|
17
14
|
def attach_standard_observer(G: TNFRGraph) -> TNFRGraph: ...
|
|
18
|
-
|
|
19
|
-
|
|
20
15
|
def _ensure_nodes(G: TNFRGraph) -> bool: ...
|
|
21
|
-
|
|
22
|
-
|
|
23
16
|
def kuramoto_metrics(G: TNFRGraph) -> tuple[float, float]: ...
|
|
24
|
-
|
|
25
|
-
|
|
26
17
|
def phase_sync(
|
|
27
18
|
G: TNFRGraph,
|
|
28
19
|
R: float | None = ...,
|
|
29
20
|
psi: float | None = ...,
|
|
30
21
|
) -> float: ...
|
|
31
|
-
|
|
32
|
-
|
|
33
22
|
def kuramoto_order(
|
|
34
23
|
G: TNFRGraph,
|
|
35
24
|
R: float | None = ...,
|
|
36
25
|
psi: float | None = ...,
|
|
37
26
|
) -> float: ...
|
|
38
|
-
|
|
39
|
-
|
|
40
27
|
def glyph_load(
|
|
41
28
|
G: TNFRGraph,
|
|
42
29
|
window: int | None = ...,
|
|
43
30
|
) -> GlyphLoadDistribution: ...
|
|
44
|
-
|
|
45
|
-
|
|
46
31
|
def wbar(G: TNFRGraph, window: int | None = ...) -> float: ...
|
tnfr/ontosim.py
CHANGED
|
@@ -6,11 +6,12 @@ from collections import deque
|
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
from .callback_utils import CallbackEvent
|
|
9
|
-
from .constants import METRIC_DEFAULTS,
|
|
10
|
-
from .dynamics import step as _step, run as _run
|
|
9
|
+
from .constants import METRIC_DEFAULTS, get_param, inject_defaults
|
|
11
10
|
from .dynamics import default_compute_delta_nfr
|
|
12
|
-
from .
|
|
11
|
+
from .dynamics import run as _run
|
|
12
|
+
from .dynamics import step as _step
|
|
13
13
|
from .glyph_history import append_metric
|
|
14
|
+
from .initialization import init_node_attrs
|
|
14
15
|
from .utils import cached_import
|
|
15
16
|
|
|
16
17
|
if TYPE_CHECKING: # pragma: no cover
|
|
@@ -46,9 +47,7 @@ def prepare_network(
|
|
|
46
47
|
merge_overrides(G, **overrides)
|
|
47
48
|
# Initialize history buffers
|
|
48
49
|
ph_len = int(
|
|
49
|
-
G.graph.get(
|
|
50
|
-
"PHASE_HISTORY_MAXLEN", METRIC_DEFAULTS["PHASE_HISTORY_MAXLEN"]
|
|
51
|
-
)
|
|
50
|
+
G.graph.get("PHASE_HISTORY_MAXLEN", METRIC_DEFAULTS["PHASE_HISTORY_MAXLEN"])
|
|
52
51
|
)
|
|
53
52
|
hist_keys = [
|
|
54
53
|
"C_steps",
|
|
@@ -127,6 +126,8 @@ def step(
|
|
|
127
126
|
use_Si: bool = True,
|
|
128
127
|
apply_glyphs: bool = True,
|
|
129
128
|
) -> None:
|
|
129
|
+
"""Advance the ontosim runtime by a single step."""
|
|
130
|
+
|
|
130
131
|
_step(G, dt=dt, use_Si=use_Si, apply_glyphs=apply_glyphs)
|
|
131
132
|
|
|
132
133
|
|
|
@@ -138,4 +139,6 @@ def run(
|
|
|
138
139
|
use_Si: bool = True,
|
|
139
140
|
apply_glyphs: bool = True,
|
|
140
141
|
) -> None:
|
|
142
|
+
"""Advance the ontosim runtime ``steps`` times with optional overrides."""
|
|
143
|
+
|
|
141
144
|
_run(G, steps=steps, dt=dt, use_Si=use_Si, apply_glyphs=apply_glyphs)
|
tnfr/ontosim.pyi
CHANGED
|
@@ -4,7 +4,6 @@ from .types import TNFRConfigValue, TNFRGraph
|
|
|
4
4
|
|
|
5
5
|
__all__: tuple[str, ...]
|
|
6
6
|
|
|
7
|
-
|
|
8
7
|
def prepare_network(
|
|
9
8
|
G: TNFRGraph,
|
|
10
9
|
*,
|
|
@@ -12,8 +11,6 @@ def prepare_network(
|
|
|
12
11
|
override_defaults: bool = False,
|
|
13
12
|
**overrides: TNFRConfigValue,
|
|
14
13
|
) -> TNFRGraph: ...
|
|
15
|
-
|
|
16
|
-
|
|
17
14
|
def step(
|
|
18
15
|
G: TNFRGraph,
|
|
19
16
|
*,
|
|
@@ -21,8 +18,6 @@ def step(
|
|
|
21
18
|
use_Si: bool = True,
|
|
22
19
|
apply_glyphs: bool = True,
|
|
23
20
|
) -> None: ...
|
|
24
|
-
|
|
25
|
-
|
|
26
21
|
def run(
|
|
27
22
|
G: TNFRGraph,
|
|
28
23
|
steps: int,
|