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.

Files changed (176) hide show
  1. tnfr/__init__.py +50 -5
  2. tnfr/__init__.pyi +0 -7
  3. tnfr/_compat.py +0 -1
  4. tnfr/_generated_version.py +34 -0
  5. tnfr/_version.py +44 -2
  6. tnfr/alias.py +14 -13
  7. tnfr/alias.pyi +5 -37
  8. tnfr/cache.py +9 -729
  9. tnfr/cache.pyi +8 -224
  10. tnfr/callback_utils.py +16 -31
  11. tnfr/callback_utils.pyi +3 -29
  12. tnfr/cli/__init__.py +17 -11
  13. tnfr/cli/__init__.pyi +0 -21
  14. tnfr/cli/arguments.py +175 -14
  15. tnfr/cli/arguments.pyi +5 -11
  16. tnfr/cli/execution.py +434 -48
  17. tnfr/cli/execution.pyi +14 -24
  18. tnfr/cli/utils.py +20 -3
  19. tnfr/cli/utils.pyi +5 -5
  20. tnfr/config/__init__.py +2 -1
  21. tnfr/config/__init__.pyi +2 -0
  22. tnfr/config/feature_flags.py +83 -0
  23. tnfr/config/init.py +1 -1
  24. tnfr/config/operator_names.py +1 -14
  25. tnfr/config/presets.py +6 -26
  26. tnfr/constants/__init__.py +10 -13
  27. tnfr/constants/__init__.pyi +10 -22
  28. tnfr/constants/aliases.py +31 -0
  29. tnfr/constants/core.py +4 -3
  30. tnfr/constants/init.py +1 -1
  31. tnfr/constants/metric.py +3 -3
  32. tnfr/dynamics/__init__.py +64 -10
  33. tnfr/dynamics/__init__.pyi +3 -4
  34. tnfr/dynamics/adaptation.py +79 -13
  35. tnfr/dynamics/aliases.py +10 -9
  36. tnfr/dynamics/coordination.py +77 -35
  37. tnfr/dynamics/dnfr.py +575 -274
  38. tnfr/dynamics/dnfr.pyi +1 -10
  39. tnfr/dynamics/integrators.py +47 -33
  40. tnfr/dynamics/integrators.pyi +0 -1
  41. tnfr/dynamics/runtime.py +489 -129
  42. tnfr/dynamics/sampling.py +2 -0
  43. tnfr/dynamics/selectors.py +101 -62
  44. tnfr/execution.py +15 -8
  45. tnfr/execution.pyi +5 -25
  46. tnfr/flatten.py +7 -3
  47. tnfr/flatten.pyi +1 -8
  48. tnfr/gamma.py +22 -26
  49. tnfr/gamma.pyi +0 -6
  50. tnfr/glyph_history.py +37 -26
  51. tnfr/glyph_history.pyi +1 -19
  52. tnfr/glyph_runtime.py +16 -0
  53. tnfr/glyph_runtime.pyi +9 -0
  54. tnfr/immutable.py +20 -15
  55. tnfr/immutable.pyi +4 -7
  56. tnfr/initialization.py +5 -7
  57. tnfr/initialization.pyi +1 -9
  58. tnfr/io.py +6 -305
  59. tnfr/io.pyi +13 -8
  60. tnfr/mathematics/__init__.py +81 -0
  61. tnfr/mathematics/backend.py +426 -0
  62. tnfr/mathematics/dynamics.py +398 -0
  63. tnfr/mathematics/epi.py +254 -0
  64. tnfr/mathematics/generators.py +222 -0
  65. tnfr/mathematics/metrics.py +119 -0
  66. tnfr/mathematics/operators.py +233 -0
  67. tnfr/mathematics/operators_factory.py +71 -0
  68. tnfr/mathematics/projection.py +78 -0
  69. tnfr/mathematics/runtime.py +173 -0
  70. tnfr/mathematics/spaces.py +247 -0
  71. tnfr/mathematics/transforms.py +292 -0
  72. tnfr/metrics/__init__.py +10 -10
  73. tnfr/metrics/coherence.py +123 -94
  74. tnfr/metrics/common.py +22 -13
  75. tnfr/metrics/common.pyi +42 -11
  76. tnfr/metrics/core.py +72 -14
  77. tnfr/metrics/diagnosis.py +48 -57
  78. tnfr/metrics/diagnosis.pyi +3 -7
  79. tnfr/metrics/export.py +3 -5
  80. tnfr/metrics/glyph_timing.py +41 -31
  81. tnfr/metrics/reporting.py +13 -6
  82. tnfr/metrics/sense_index.py +884 -114
  83. tnfr/metrics/trig.py +167 -11
  84. tnfr/metrics/trig.pyi +1 -0
  85. tnfr/metrics/trig_cache.py +112 -15
  86. tnfr/node.py +400 -17
  87. tnfr/node.pyi +55 -38
  88. tnfr/observers.py +111 -8
  89. tnfr/observers.pyi +0 -15
  90. tnfr/ontosim.py +9 -6
  91. tnfr/ontosim.pyi +0 -5
  92. tnfr/operators/__init__.py +529 -42
  93. tnfr/operators/__init__.pyi +14 -0
  94. tnfr/operators/definitions.py +350 -18
  95. tnfr/operators/definitions.pyi +0 -14
  96. tnfr/operators/grammar.py +760 -0
  97. tnfr/operators/jitter.py +28 -22
  98. tnfr/operators/registry.py +7 -12
  99. tnfr/operators/registry.pyi +0 -2
  100. tnfr/operators/remesh.py +38 -61
  101. tnfr/rng.py +17 -300
  102. tnfr/schemas/__init__.py +8 -0
  103. tnfr/schemas/grammar.json +94 -0
  104. tnfr/selector.py +3 -4
  105. tnfr/selector.pyi +1 -1
  106. tnfr/sense.py +22 -24
  107. tnfr/sense.pyi +0 -7
  108. tnfr/structural.py +504 -21
  109. tnfr/structural.pyi +41 -18
  110. tnfr/telemetry/__init__.py +23 -1
  111. tnfr/telemetry/cache_metrics.py +226 -0
  112. tnfr/telemetry/nu_f.py +423 -0
  113. tnfr/telemetry/nu_f.pyi +123 -0
  114. tnfr/tokens.py +1 -4
  115. tnfr/tokens.pyi +1 -6
  116. tnfr/trace.py +20 -53
  117. tnfr/trace.pyi +9 -37
  118. tnfr/types.py +244 -15
  119. tnfr/types.pyi +200 -14
  120. tnfr/units.py +69 -0
  121. tnfr/units.pyi +16 -0
  122. tnfr/utils/__init__.py +107 -48
  123. tnfr/utils/__init__.pyi +80 -11
  124. tnfr/utils/cache.py +1705 -65
  125. tnfr/utils/cache.pyi +370 -58
  126. tnfr/utils/chunks.py +104 -0
  127. tnfr/utils/chunks.pyi +21 -0
  128. tnfr/utils/data.py +95 -5
  129. tnfr/utils/data.pyi +8 -17
  130. tnfr/utils/graph.py +2 -4
  131. tnfr/utils/init.py +31 -7
  132. tnfr/utils/init.pyi +4 -11
  133. tnfr/utils/io.py +313 -14
  134. tnfr/{helpers → utils}/numeric.py +50 -24
  135. tnfr/utils/numeric.pyi +21 -0
  136. tnfr/validation/__init__.py +92 -4
  137. tnfr/validation/__init__.pyi +77 -17
  138. tnfr/validation/compatibility.py +79 -43
  139. tnfr/validation/compatibility.pyi +4 -6
  140. tnfr/validation/grammar.py +55 -133
  141. tnfr/validation/grammar.pyi +37 -8
  142. tnfr/validation/graph.py +138 -0
  143. tnfr/validation/graph.pyi +17 -0
  144. tnfr/validation/rules.py +161 -74
  145. tnfr/validation/rules.pyi +55 -18
  146. tnfr/validation/runtime.py +263 -0
  147. tnfr/validation/runtime.pyi +31 -0
  148. tnfr/validation/soft_filters.py +170 -0
  149. tnfr/validation/soft_filters.pyi +37 -0
  150. tnfr/validation/spectral.py +159 -0
  151. tnfr/validation/spectral.pyi +46 -0
  152. tnfr/validation/syntax.py +28 -139
  153. tnfr/validation/syntax.pyi +7 -4
  154. tnfr/validation/window.py +39 -0
  155. tnfr/validation/window.pyi +1 -0
  156. tnfr/viz/__init__.py +9 -0
  157. tnfr/viz/matplotlib.py +246 -0
  158. {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/METADATA +63 -19
  159. tnfr-7.0.0.dist-info/RECORD +185 -0
  160. {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/licenses/LICENSE.md +1 -1
  161. tnfr/constants_glyphs.py +0 -16
  162. tnfr/constants_glyphs.pyi +0 -12
  163. tnfr/grammar.py +0 -25
  164. tnfr/grammar.pyi +0 -13
  165. tnfr/helpers/__init__.py +0 -151
  166. tnfr/helpers/__init__.pyi +0 -66
  167. tnfr/helpers/numeric.pyi +0 -12
  168. tnfr/presets.py +0 -15
  169. tnfr/presets.pyi +0 -7
  170. tnfr/utils/io.pyi +0 -10
  171. tnfr/utils/validators.py +0 -130
  172. tnfr/utils/validators.pyi +0 -19
  173. tnfr-6.0.0.dist-info/RECORD +0 -157
  174. {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/WHEEL +0 -0
  175. {tnfr-6.0.0.dist-info → tnfr-7.0.0.dist-info}/entry_points.txt +0 -0
  176. {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
- def __init__(self, G: TNFRGraph, n: NodeId) -> None: ...
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 .config.constants import GLYPH_GROUPS
27
- from .gamma import kuramoto_R_psi
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, inject_defaults, get_param
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 .initialization import init_node_attrs
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,