tnfr 4.5.1__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 +270 -90
- tnfr/__init__.pyi +40 -0
- tnfr/_compat.py +11 -0
- tnfr/_version.py +7 -0
- tnfr/_version.pyi +7 -0
- tnfr/alias.py +631 -0
- tnfr/alias.pyi +140 -0
- tnfr/cache.py +732 -0
- tnfr/cache.pyi +232 -0
- tnfr/callback_utils.py +381 -0
- tnfr/callback_utils.pyi +105 -0
- tnfr/cli/__init__.py +89 -0
- tnfr/cli/__init__.pyi +47 -0
- tnfr/cli/arguments.py +199 -0
- tnfr/cli/arguments.pyi +33 -0
- tnfr/cli/execution.py +322 -0
- tnfr/cli/execution.pyi +80 -0
- tnfr/cli/utils.py +34 -0
- 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/init.py +36 -0
- 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 +228 -0
- tnfr/constants/__init__.pyi +104 -0
- tnfr/constants/core.py +158 -0
- tnfr/constants/core.pyi +17 -0
- tnfr/constants/init.py +31 -0
- tnfr/constants/init.pyi +12 -0
- tnfr/constants/metric.py +102 -0
- tnfr/constants/metric.pyi +19 -0
- tnfr/constants_glyphs.py +16 -0
- tnfr/constants_glyphs.pyi +12 -0
- tnfr/dynamics/__init__.py +136 -0
- 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 +2315 -0
- tnfr/dynamics/dnfr.pyi +33 -0
- tnfr/dynamics/integrators.py +561 -0
- tnfr/dynamics/integrators.pyi +35 -0
- tnfr/dynamics/runtime.py +521 -0
- tnfr/dynamics/sampling.py +34 -0
- tnfr/dynamics/sampling.pyi +7 -0
- tnfr/dynamics/selectors.py +680 -0
- tnfr/execution.py +216 -0
- tnfr/execution.pyi +65 -0
- tnfr/flatten.py +283 -0
- tnfr/flatten.pyi +28 -0
- tnfr/gamma.py +320 -89
- tnfr/gamma.pyi +40 -0
- tnfr/glyph_history.py +337 -0
- tnfr/glyph_history.pyi +53 -0
- tnfr/grammar.py +23 -153
- tnfr/grammar.pyi +13 -0
- tnfr/helpers/__init__.py +151 -0
- tnfr/helpers/__init__.pyi +66 -0
- tnfr/helpers/numeric.py +88 -0
- tnfr/helpers/numeric.pyi +12 -0
- tnfr/immutable.py +214 -0
- tnfr/immutable.pyi +37 -0
- tnfr/initialization.py +199 -0
- tnfr/initialization.pyi +73 -0
- tnfr/io.py +311 -0
- tnfr/io.pyi +11 -0
- tnfr/locking.py +37 -0
- tnfr/locking.pyi +7 -0
- tnfr/metrics/__init__.py +41 -0
- tnfr/metrics/__init__.pyi +20 -0
- tnfr/metrics/coherence.py +1469 -0
- tnfr/metrics/common.py +149 -0
- tnfr/metrics/common.pyi +15 -0
- tnfr/metrics/core.py +259 -0
- tnfr/metrics/core.pyi +13 -0
- tnfr/metrics/diagnosis.py +840 -0
- tnfr/metrics/diagnosis.pyi +89 -0
- tnfr/metrics/export.py +151 -0
- tnfr/metrics/glyph_timing.py +369 -0
- tnfr/metrics/reporting.py +152 -0
- tnfr/metrics/reporting.pyi +12 -0
- tnfr/metrics/sense_index.py +294 -0
- tnfr/metrics/sense_index.pyi +9 -0
- tnfr/metrics/trig.py +216 -0
- tnfr/metrics/trig.pyi +12 -0
- tnfr/metrics/trig_cache.py +105 -0
- tnfr/metrics/trig_cache.pyi +10 -0
- tnfr/node.py +255 -177
- tnfr/node.pyi +161 -0
- tnfr/observers.py +154 -150
- tnfr/observers.pyi +46 -0
- tnfr/ontosim.py +135 -134
- tnfr/ontosim.pyi +33 -0
- tnfr/operators/__init__.py +452 -0
- tnfr/operators/__init__.pyi +31 -0
- tnfr/operators/definitions.py +181 -0
- tnfr/operators/definitions.pyi +92 -0
- tnfr/operators/jitter.py +266 -0
- tnfr/operators/jitter.pyi +11 -0
- tnfr/operators/registry.py +80 -0
- tnfr/operators/registry.pyi +15 -0
- tnfr/operators/remesh.py +569 -0
- tnfr/presets.py +10 -23
- tnfr/presets.pyi +7 -0
- tnfr/py.typed +0 -0
- tnfr/rng.py +440 -0
- tnfr/rng.pyi +14 -0
- tnfr/selector.py +217 -0
- tnfr/selector.pyi +19 -0
- tnfr/sense.py +307 -142
- tnfr/sense.pyi +30 -0
- tnfr/structural.py +69 -164
- tnfr/structural.pyi +46 -0
- tnfr/telemetry/__init__.py +13 -0
- tnfr/telemetry/verbosity.py +37 -0
- tnfr/tokens.py +61 -0
- tnfr/tokens.pyi +41 -0
- tnfr/trace.py +520 -95
- tnfr/trace.pyi +68 -0
- tnfr/types.py +382 -17
- 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/utils/data.py +267 -0
- 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/utils/io.py +157 -0
- 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/cli.py +0 -322
- tnfr/config.py +0 -41
- tnfr/constants.py +0 -277
- tnfr/dynamics.py +0 -814
- tnfr/helpers.py +0 -264
- tnfr/main.py +0 -47
- tnfr/metrics.py +0 -597
- tnfr/operators.py +0 -525
- tnfr/program.py +0 -176
- tnfr/scenarios.py +0 -34
- tnfr/validators.py +0 -38
- tnfr-4.5.1.dist-info/METADATA +0 -221
- tnfr-4.5.1.dist-info/RECORD +0 -28
- {tnfr-4.5.1.dist-info → tnfr-6.0.0.dist-info}/WHEEL +0 -0
- {tnfr-4.5.1.dist-info → tnfr-6.0.0.dist-info}/entry_points.txt +0 -0
- {tnfr-4.5.1.dist-info → tnfr-6.0.0.dist-info}/licenses/LICENSE.md +0 -0
- {tnfr-4.5.1.dist-info → tnfr-6.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Facade for TNFR dynamics submodules."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from concurrent.futures import ProcessPoolExecutor
|
|
6
|
+
|
|
7
|
+
from . import coordination, dnfr, integrators
|
|
8
|
+
from .adaptation import adapt_vf_by_coherence
|
|
9
|
+
from .aliases import (
|
|
10
|
+
ALIAS_D2EPI,
|
|
11
|
+
ALIAS_DNFR,
|
|
12
|
+
ALIAS_DSI,
|
|
13
|
+
ALIAS_EPI,
|
|
14
|
+
ALIAS_SI,
|
|
15
|
+
ALIAS_VF,
|
|
16
|
+
)
|
|
17
|
+
from .coordination import coordinate_global_local_phase
|
|
18
|
+
from .dnfr import (
|
|
19
|
+
_compute_dnfr,
|
|
20
|
+
_compute_neighbor_means,
|
|
21
|
+
_init_dnfr_cache,
|
|
22
|
+
_prepare_dnfr_data,
|
|
23
|
+
_refresh_dnfr_vectors,
|
|
24
|
+
default_compute_delta_nfr,
|
|
25
|
+
dnfr_epi_vf_mixed,
|
|
26
|
+
dnfr_laplacian,
|
|
27
|
+
dnfr_phase_only,
|
|
28
|
+
set_delta_nfr_hook,
|
|
29
|
+
)
|
|
30
|
+
from .integrators import (
|
|
31
|
+
AbstractIntegrator,
|
|
32
|
+
DefaultIntegrator,
|
|
33
|
+
prepare_integration_params,
|
|
34
|
+
update_epi_via_nodal_equation,
|
|
35
|
+
)
|
|
36
|
+
from .runtime import (
|
|
37
|
+
_maybe_remesh,
|
|
38
|
+
_normalize_job_overrides,
|
|
39
|
+
_prepare_dnfr,
|
|
40
|
+
_resolve_jobs_override,
|
|
41
|
+
_run_after_callbacks,
|
|
42
|
+
_run_before_callbacks,
|
|
43
|
+
_run_validators,
|
|
44
|
+
_update_epi_hist,
|
|
45
|
+
_update_nodes,
|
|
46
|
+
apply_canonical_clamps,
|
|
47
|
+
run,
|
|
48
|
+
step,
|
|
49
|
+
validate_canon,
|
|
50
|
+
)
|
|
51
|
+
from .sampling import update_node_sample as _update_node_sample
|
|
52
|
+
from .selectors import (
|
|
53
|
+
AbstractSelector,
|
|
54
|
+
DefaultGlyphSelector,
|
|
55
|
+
GlyphCode,
|
|
56
|
+
ParametricGlyphSelector,
|
|
57
|
+
_SelectorPreselection,
|
|
58
|
+
_apply_glyphs,
|
|
59
|
+
_apply_selector,
|
|
60
|
+
_choose_glyph,
|
|
61
|
+
_collect_selector_metrics,
|
|
62
|
+
_configure_selector_weights,
|
|
63
|
+
_prepare_selector_preselection,
|
|
64
|
+
_resolve_preselected_glyph,
|
|
65
|
+
_selector_parallel_jobs,
|
|
66
|
+
default_glyph_selector,
|
|
67
|
+
parametric_glyph_selector,
|
|
68
|
+
)
|
|
69
|
+
from ..operators import apply_glyph
|
|
70
|
+
from ..metrics.sense_index import compute_Si
|
|
71
|
+
from ..utils import get_numpy
|
|
72
|
+
from ..validation.grammar import enforce_canonical_grammar, on_applied_glyph
|
|
73
|
+
|
|
74
|
+
__all__ = (
|
|
75
|
+
"coordination",
|
|
76
|
+
"dnfr",
|
|
77
|
+
"integrators",
|
|
78
|
+
"ALIAS_D2EPI",
|
|
79
|
+
"ALIAS_DNFR",
|
|
80
|
+
"ALIAS_DSI",
|
|
81
|
+
"ALIAS_EPI",
|
|
82
|
+
"ALIAS_SI",
|
|
83
|
+
"ALIAS_VF",
|
|
84
|
+
"AbstractSelector",
|
|
85
|
+
"DefaultGlyphSelector",
|
|
86
|
+
"ParametricGlyphSelector",
|
|
87
|
+
"GlyphCode",
|
|
88
|
+
"_SelectorPreselection",
|
|
89
|
+
"_apply_glyphs",
|
|
90
|
+
"_apply_selector",
|
|
91
|
+
"_choose_glyph",
|
|
92
|
+
"_collect_selector_metrics",
|
|
93
|
+
"_configure_selector_weights",
|
|
94
|
+
"ProcessPoolExecutor",
|
|
95
|
+
"_maybe_remesh",
|
|
96
|
+
"_normalize_job_overrides",
|
|
97
|
+
"_prepare_dnfr",
|
|
98
|
+
"_prepare_dnfr_data",
|
|
99
|
+
"_prepare_selector_preselection",
|
|
100
|
+
"_resolve_jobs_override",
|
|
101
|
+
"_resolve_preselected_glyph",
|
|
102
|
+
"_run_after_callbacks",
|
|
103
|
+
"_run_before_callbacks",
|
|
104
|
+
"_run_validators",
|
|
105
|
+
"_selector_parallel_jobs",
|
|
106
|
+
"_update_epi_hist",
|
|
107
|
+
"_update_node_sample",
|
|
108
|
+
"_update_nodes",
|
|
109
|
+
"_compute_dnfr",
|
|
110
|
+
"_compute_neighbor_means",
|
|
111
|
+
"_init_dnfr_cache",
|
|
112
|
+
"_refresh_dnfr_vectors",
|
|
113
|
+
"adapt_vf_by_coherence",
|
|
114
|
+
"apply_canonical_clamps",
|
|
115
|
+
"coordinate_global_local_phase",
|
|
116
|
+
"compute_Si",
|
|
117
|
+
"default_compute_delta_nfr",
|
|
118
|
+
"default_glyph_selector",
|
|
119
|
+
"dnfr_epi_vf_mixed",
|
|
120
|
+
"dnfr_laplacian",
|
|
121
|
+
"dnfr_phase_only",
|
|
122
|
+
"enforce_canonical_grammar",
|
|
123
|
+
"get_numpy",
|
|
124
|
+
"on_applied_glyph",
|
|
125
|
+
"apply_glyph",
|
|
126
|
+
"parametric_glyph_selector",
|
|
127
|
+
"AbstractIntegrator",
|
|
128
|
+
"DefaultIntegrator",
|
|
129
|
+
"prepare_integration_params",
|
|
130
|
+
"run",
|
|
131
|
+
"set_delta_nfr_hook",
|
|
132
|
+
"step",
|
|
133
|
+
"update_epi_via_nodal_equation",
|
|
134
|
+
"validate_canon",
|
|
135
|
+
)
|
|
136
|
+
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from typing import Any, Literal, Sequence
|
|
2
|
+
|
|
3
|
+
from tnfr.types import TNFRGraph
|
|
4
|
+
|
|
5
|
+
__all__: tuple[str, ...]
|
|
6
|
+
|
|
7
|
+
dnfr: Any
|
|
8
|
+
integrators: Any
|
|
9
|
+
|
|
10
|
+
ALIAS_D2EPI: Sequence[str]
|
|
11
|
+
ALIAS_DNFR: Sequence[str]
|
|
12
|
+
ALIAS_DSI: Sequence[str]
|
|
13
|
+
ALIAS_EPI: Sequence[str]
|
|
14
|
+
ALIAS_SI: Sequence[str]
|
|
15
|
+
ALIAS_VF: Sequence[str]
|
|
16
|
+
|
|
17
|
+
AbstractSelector: Any
|
|
18
|
+
DefaultGlyphSelector: Any
|
|
19
|
+
GlyphCode: Any
|
|
20
|
+
ParametricGlyphSelector: Any
|
|
21
|
+
_SelectorPreselection: Any
|
|
22
|
+
_apply_glyphs: Any
|
|
23
|
+
_apply_selector: Any
|
|
24
|
+
_choose_glyph: Any
|
|
25
|
+
_configure_selector_weights: Any
|
|
26
|
+
ProcessPoolExecutor: Any
|
|
27
|
+
_maybe_remesh: Any
|
|
28
|
+
_normalize_job_overrides: Any
|
|
29
|
+
_prepare_dnfr: Any
|
|
30
|
+
_prepare_dnfr_data: Any
|
|
31
|
+
_prepare_selector_preselection: Any
|
|
32
|
+
_resolve_jobs_override: Any
|
|
33
|
+
_resolve_preselected_glyph: Any
|
|
34
|
+
_run_after_callbacks: Any
|
|
35
|
+
_run_before_callbacks: Any
|
|
36
|
+
_run_validators: Any
|
|
37
|
+
_selector_parallel_jobs: Any
|
|
38
|
+
_update_epi_hist: Any
|
|
39
|
+
_update_node_sample: Any
|
|
40
|
+
_update_nodes: Any
|
|
41
|
+
_compute_dnfr: Any
|
|
42
|
+
_compute_neighbor_means: Any
|
|
43
|
+
_init_dnfr_cache: Any
|
|
44
|
+
_refresh_dnfr_vectors: Any
|
|
45
|
+
adapt_vf_by_coherence: Any
|
|
46
|
+
apply_canonical_clamps: Any
|
|
47
|
+
coordinate_global_local_phase: Any
|
|
48
|
+
default_compute_delta_nfr: Any
|
|
49
|
+
default_glyph_selector: Any
|
|
50
|
+
dnfr_epi_vf_mixed: Any
|
|
51
|
+
dnfr_laplacian: Any
|
|
52
|
+
dnfr_phase_only: Any
|
|
53
|
+
enforce_canonical_grammar: Any
|
|
54
|
+
get_numpy: Any
|
|
55
|
+
on_applied_glyph: Any
|
|
56
|
+
apply_glyph: Any
|
|
57
|
+
parametric_glyph_selector: Any
|
|
58
|
+
|
|
59
|
+
AbstractIntegrator: Any
|
|
60
|
+
DefaultIntegrator: Any
|
|
61
|
+
|
|
62
|
+
def prepare_integration_params(
|
|
63
|
+
G: TNFRGraph,
|
|
64
|
+
dt: float | None = ...,
|
|
65
|
+
t: float | None = ...,
|
|
66
|
+
method: Literal["euler", "rk4"] | None = ...,
|
|
67
|
+
) -> tuple[float, int, float, Literal["euler", "rk4"]]: ...
|
|
68
|
+
|
|
69
|
+
run: Any
|
|
70
|
+
set_delta_nfr_hook: Any
|
|
71
|
+
step: Any
|
|
72
|
+
|
|
73
|
+
def update_epi_via_nodal_equation(
|
|
74
|
+
G: TNFRGraph,
|
|
75
|
+
*,
|
|
76
|
+
dt: float | None = ...,
|
|
77
|
+
t: float | None = ...,
|
|
78
|
+
method: Literal["euler", "rk4"] | None = ...,
|
|
79
|
+
n_jobs: int | None = ...,
|
|
80
|
+
) -> None: ...
|
|
81
|
+
|
|
82
|
+
validate_canon: Any
|
|
83
|
+
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""νf adaptation routines for TNFR dynamics."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from concurrent.futures import ProcessPoolExecutor
|
|
7
|
+
from typing import Any, cast
|
|
8
|
+
|
|
9
|
+
from ..alias import collect_attr, set_vf
|
|
10
|
+
from ..constants import get_graph_param
|
|
11
|
+
from ..helpers.numeric import clamp
|
|
12
|
+
from ..metrics.common import ensure_neighbors_map
|
|
13
|
+
from ..types import CoherenceMetric, DeltaNFR, NodeId, TNFRGraph
|
|
14
|
+
from ..utils import get_numpy
|
|
15
|
+
from .aliases import ALIAS_DNFR, ALIAS_SI, ALIAS_VF
|
|
16
|
+
|
|
17
|
+
__all__ = ("adapt_vf_by_coherence",)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _vf_adapt_chunk(
|
|
21
|
+
args: tuple[list[tuple[Any, int, tuple[int, ...]]], tuple[float, ...], float]
|
|
22
|
+
) -> list[tuple[Any, float]]:
|
|
23
|
+
"""Return proposed νf updates for ``chunk`` of stable nodes."""
|
|
24
|
+
|
|
25
|
+
chunk, vf_values, mu = args
|
|
26
|
+
updates: list[tuple[Any, float]] = []
|
|
27
|
+
for node, idx, neighbor_idx in chunk:
|
|
28
|
+
vf = vf_values[idx]
|
|
29
|
+
if neighbor_idx:
|
|
30
|
+
mean = math.fsum(vf_values[j] for j in neighbor_idx) / len(neighbor_idx)
|
|
31
|
+
else:
|
|
32
|
+
mean = vf
|
|
33
|
+
updates.append((node, vf + mu * (mean - vf)))
|
|
34
|
+
return updates
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def adapt_vf_by_coherence(G: TNFRGraph, n_jobs: int | None = None) -> None:
|
|
38
|
+
"""Adjust νf toward neighbour mean in nodes with sustained stability."""
|
|
39
|
+
|
|
40
|
+
tau = get_graph_param(G, "VF_ADAPT_TAU", int)
|
|
41
|
+
mu = float(get_graph_param(G, "VF_ADAPT_MU"))
|
|
42
|
+
eps_dnfr = cast(DeltaNFR, get_graph_param(G, "EPS_DNFR_STABLE"))
|
|
43
|
+
thr_sel = get_graph_param(G, "SELECTOR_THRESHOLDS", dict)
|
|
44
|
+
thr_def = get_graph_param(G, "GLYPH_THRESHOLDS", dict)
|
|
45
|
+
si_hi = cast(
|
|
46
|
+
CoherenceMetric,
|
|
47
|
+
float(thr_sel.get("si_hi", thr_def.get("hi", 0.66))),
|
|
48
|
+
)
|
|
49
|
+
vf_min = float(get_graph_param(G, "VF_MIN"))
|
|
50
|
+
vf_max = float(get_graph_param(G, "VF_MAX"))
|
|
51
|
+
|
|
52
|
+
nodes = list(G.nodes)
|
|
53
|
+
if not nodes:
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
neighbors_map = ensure_neighbors_map(G)
|
|
57
|
+
node_count = len(nodes)
|
|
58
|
+
node_index = {node: idx for idx, node in enumerate(nodes)}
|
|
59
|
+
|
|
60
|
+
jobs: int | None
|
|
61
|
+
if n_jobs is None:
|
|
62
|
+
jobs = None
|
|
63
|
+
else:
|
|
64
|
+
try:
|
|
65
|
+
jobs = int(n_jobs)
|
|
66
|
+
except (TypeError, ValueError):
|
|
67
|
+
jobs = None
|
|
68
|
+
else:
|
|
69
|
+
if jobs <= 1:
|
|
70
|
+
jobs = None
|
|
71
|
+
|
|
72
|
+
np_mod = get_numpy()
|
|
73
|
+
use_np = np_mod is not None
|
|
74
|
+
|
|
75
|
+
si_values = collect_attr(G, nodes, ALIAS_SI, 0.0, np=np_mod if use_np else None)
|
|
76
|
+
dnfr_values = collect_attr(G, nodes, ALIAS_DNFR, 0.0, np=np_mod if use_np else None)
|
|
77
|
+
vf_values = collect_attr(G, nodes, ALIAS_VF, 0.0, np=np_mod if use_np else None)
|
|
78
|
+
|
|
79
|
+
if use_np:
|
|
80
|
+
np = np_mod # type: ignore[assignment]
|
|
81
|
+
assert np is not None
|
|
82
|
+
si_arr = si_values.astype(float, copy=False)
|
|
83
|
+
dnfr_arr = np.abs(dnfr_values.astype(float, copy=False))
|
|
84
|
+
vf_arr = vf_values.astype(float, copy=False)
|
|
85
|
+
|
|
86
|
+
prev_counts = np.fromiter(
|
|
87
|
+
(int(G.nodes[node].get("stable_count", 0)) for node in nodes),
|
|
88
|
+
dtype=int,
|
|
89
|
+
count=node_count,
|
|
90
|
+
)
|
|
91
|
+
stable_mask = (si_arr >= si_hi) & (dnfr_arr <= eps_dnfr)
|
|
92
|
+
new_counts = np.where(stable_mask, prev_counts + 1, 0)
|
|
93
|
+
|
|
94
|
+
for node, count in zip(nodes, new_counts.tolist()):
|
|
95
|
+
G.nodes[node]["stable_count"] = int(count)
|
|
96
|
+
|
|
97
|
+
eligible_mask = new_counts >= tau
|
|
98
|
+
if not bool(eligible_mask.any()):
|
|
99
|
+
return
|
|
100
|
+
|
|
101
|
+
max_degree = 0
|
|
102
|
+
if node_count:
|
|
103
|
+
degree_counts = np.fromiter(
|
|
104
|
+
(len(neighbors_map.get(node, ())) for node in nodes),
|
|
105
|
+
dtype=int,
|
|
106
|
+
count=node_count,
|
|
107
|
+
)
|
|
108
|
+
if degree_counts.size:
|
|
109
|
+
max_degree = int(degree_counts.max())
|
|
110
|
+
|
|
111
|
+
if max_degree > 0:
|
|
112
|
+
neighbor_indices = np.zeros((node_count, max_degree), dtype=int)
|
|
113
|
+
mask = np.zeros((node_count, max_degree), dtype=bool)
|
|
114
|
+
for idx, node in enumerate(nodes):
|
|
115
|
+
neigh = neighbors_map.get(node, ())
|
|
116
|
+
if not neigh:
|
|
117
|
+
continue
|
|
118
|
+
idxs = [node_index[nbr] for nbr in neigh if nbr in node_index]
|
|
119
|
+
if not idxs:
|
|
120
|
+
continue
|
|
121
|
+
length = len(idxs)
|
|
122
|
+
neighbor_indices[idx, :length] = idxs
|
|
123
|
+
mask[idx, :length] = True
|
|
124
|
+
neighbor_values = vf_arr[neighbor_indices]
|
|
125
|
+
sums = (neighbor_values * mask).sum(axis=1)
|
|
126
|
+
counts = mask.sum(axis=1)
|
|
127
|
+
neighbor_means = np.where(counts > 0, sums / counts, vf_arr)
|
|
128
|
+
else:
|
|
129
|
+
neighbor_means = vf_arr
|
|
130
|
+
|
|
131
|
+
vf_updates = vf_arr + mu * (neighbor_means - vf_arr)
|
|
132
|
+
for idx in np.nonzero(eligible_mask)[0]:
|
|
133
|
+
node = nodes[int(idx)]
|
|
134
|
+
vf_new = clamp(float(vf_updates[int(idx)]), vf_min, vf_max)
|
|
135
|
+
set_vf(G, node, vf_new)
|
|
136
|
+
return
|
|
137
|
+
|
|
138
|
+
si_list = [float(val) for val in si_values]
|
|
139
|
+
dnfr_list = [abs(float(val)) for val in dnfr_values]
|
|
140
|
+
vf_list = [float(val) for val in vf_values]
|
|
141
|
+
|
|
142
|
+
prev_counts = [int(G.nodes[node].get("stable_count", 0)) for node in nodes]
|
|
143
|
+
stable_flags = [
|
|
144
|
+
si >= si_hi and dnfr <= eps_dnfr
|
|
145
|
+
for si, dnfr in zip(si_list, dnfr_list)
|
|
146
|
+
]
|
|
147
|
+
new_counts = [prev + 1 if flag else 0 for prev, flag in zip(prev_counts, stable_flags)]
|
|
148
|
+
|
|
149
|
+
for node, count in zip(nodes, new_counts):
|
|
150
|
+
G.nodes[node]["stable_count"] = int(count)
|
|
151
|
+
|
|
152
|
+
eligible_nodes = [node for node, count in zip(nodes, new_counts) if count >= tau]
|
|
153
|
+
if not eligible_nodes:
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
if jobs is None:
|
|
157
|
+
for node in eligible_nodes:
|
|
158
|
+
idx = node_index[node]
|
|
159
|
+
neigh_indices = [
|
|
160
|
+
node_index[nbr]
|
|
161
|
+
for nbr in neighbors_map.get(node, ())
|
|
162
|
+
if nbr in node_index
|
|
163
|
+
]
|
|
164
|
+
if neigh_indices:
|
|
165
|
+
total = math.fsum(vf_list[i] for i in neigh_indices)
|
|
166
|
+
mean = total / len(neigh_indices)
|
|
167
|
+
else:
|
|
168
|
+
mean = vf_list[idx]
|
|
169
|
+
vf_new = vf_list[idx] + mu * (mean - vf_list[idx])
|
|
170
|
+
set_vf(G, node, clamp(float(vf_new), vf_min, vf_max))
|
|
171
|
+
return
|
|
172
|
+
|
|
173
|
+
work_items: list[tuple[Any, int, tuple[int, ...]]] = []
|
|
174
|
+
for node in eligible_nodes:
|
|
175
|
+
idx = node_index[node]
|
|
176
|
+
neigh_indices = tuple(
|
|
177
|
+
node_index[nbr]
|
|
178
|
+
for nbr in neighbors_map.get(node, ())
|
|
179
|
+
if nbr in node_index
|
|
180
|
+
)
|
|
181
|
+
work_items.append((node, idx, neigh_indices))
|
|
182
|
+
|
|
183
|
+
chunk_size = max(1, math.ceil(len(work_items) / jobs))
|
|
184
|
+
chunks = [
|
|
185
|
+
work_items[i : i + chunk_size]
|
|
186
|
+
for i in range(0, len(work_items), chunk_size)
|
|
187
|
+
]
|
|
188
|
+
vf_tuple = tuple(vf_list)
|
|
189
|
+
updates: dict[Any, float] = {}
|
|
190
|
+
with ProcessPoolExecutor(max_workers=jobs) as executor:
|
|
191
|
+
args = ((chunk, vf_tuple, mu) for chunk in chunks)
|
|
192
|
+
for chunk_updates in executor.map(_vf_adapt_chunk, args):
|
|
193
|
+
for node, value in chunk_updates:
|
|
194
|
+
updates[node] = float(value)
|
|
195
|
+
|
|
196
|
+
for node in eligible_nodes:
|
|
197
|
+
vf_new = updates.get(node)
|
|
198
|
+
if vf_new is None:
|
|
199
|
+
continue
|
|
200
|
+
set_vf(G, node, clamp(float(vf_new), vf_min, vf_max))
|
|
201
|
+
|
tnfr/dynamics/aliases.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Shared alias tokens used across TNFR dynamics submodules."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..constants import get_aliases
|
|
6
|
+
|
|
7
|
+
ALIAS_VF = get_aliases("VF")
|
|
8
|
+
ALIAS_DNFR = get_aliases("DNFR")
|
|
9
|
+
ALIAS_EPI = get_aliases("EPI")
|
|
10
|
+
ALIAS_SI = get_aliases("SI")
|
|
11
|
+
ALIAS_D2EPI = get_aliases("D2EPI")
|
|
12
|
+
ALIAS_DSI = get_aliases("DSI")
|
|
13
|
+
|
|
14
|
+
__all__ = (
|
|
15
|
+
"ALIAS_VF",
|
|
16
|
+
"ALIAS_DNFR",
|
|
17
|
+
"ALIAS_EPI",
|
|
18
|
+
"ALIAS_SI",
|
|
19
|
+
"ALIAS_D2EPI",
|
|
20
|
+
"ALIAS_DSI",
|
|
21
|
+
)
|
|
22
|
+
|