tnfr 4.1.0__py3-none-any.whl → 4.5.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 +34 -4
- tnfr/cli.py +138 -9
- tnfr/config.py +41 -0
- tnfr/constants.py +102 -41
- tnfr/dynamics.py +255 -49
- tnfr/gamma.py +35 -8
- tnfr/helpers.py +50 -17
- tnfr/metrics.py +416 -30
- tnfr/node.py +202 -0
- tnfr/operators.py +341 -146
- tnfr/presets.py +3 -0
- tnfr/scenarios.py +9 -3
- tnfr/sense.py +6 -21
- tnfr/structural.py +201 -0
- tnfr/trace.py +4 -20
- tnfr/types.py +2 -1
- tnfr/validators.py +38 -0
- {tnfr-4.1.0.dist-info → tnfr-4.5.0.dist-info}/METADATA +10 -4
- tnfr-4.5.0.dist-info/RECORD +28 -0
- tnfr-4.1.0.dist-info/RECORD +0 -24
- {tnfr-4.1.0.dist-info → tnfr-4.5.0.dist-info}/WHEEL +0 -0
- {tnfr-4.1.0.dist-info → tnfr-4.5.0.dist-info}/entry_points.txt +0 -0
- {tnfr-4.1.0.dist-info → tnfr-4.5.0.dist-info}/licenses/LICENSE.md +0 -0
- {tnfr-4.1.0.dist-info → tnfr-4.5.0.dist-info}/top_level.txt +0 -0
tnfr/node.py
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import Deque, Dict, Iterable, List, Optional, Protocol
|
|
4
|
+
from collections import deque
|
|
5
|
+
|
|
6
|
+
from .constants import DEFAULTS
|
|
7
|
+
from .helpers import push_glifo
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class NodoProtocol(Protocol):
|
|
11
|
+
"""Protocolo mínimo para nodos TNFR."""
|
|
12
|
+
|
|
13
|
+
EPI: float
|
|
14
|
+
vf: float
|
|
15
|
+
theta: float
|
|
16
|
+
Si: float
|
|
17
|
+
epi_kind: str
|
|
18
|
+
dnfr: float
|
|
19
|
+
d2EPI: float
|
|
20
|
+
graph: Dict[str, object]
|
|
21
|
+
|
|
22
|
+
def neighbors(self) -> Iterable["NodoProtocol"]:
|
|
23
|
+
...
|
|
24
|
+
|
|
25
|
+
def push_glifo(self, glifo: str, window: int) -> None:
|
|
26
|
+
...
|
|
27
|
+
|
|
28
|
+
def has_edge(self, other: "NodoProtocol") -> bool:
|
|
29
|
+
...
|
|
30
|
+
|
|
31
|
+
def add_edge(self, other: "NodoProtocol", weight: float) -> None:
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
def offset(self) -> int:
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
def all_nodes(self) -> Iterable["NodoProtocol"]:
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class NodoTNFR:
|
|
43
|
+
"""Representa un nodo TNFR autónomo."""
|
|
44
|
+
|
|
45
|
+
EPI: float = 0.0
|
|
46
|
+
vf: float = 0.0
|
|
47
|
+
theta: float = 0.0
|
|
48
|
+
Si: float = 0.0
|
|
49
|
+
epi_kind: str = ""
|
|
50
|
+
dnfr: float = 0.0
|
|
51
|
+
d2EPI: float = 0.0
|
|
52
|
+
graph: Dict[str, object] = field(default_factory=dict)
|
|
53
|
+
_neighbors: List["NodoTNFR"] = field(default_factory=list)
|
|
54
|
+
_hist_glifos: Deque[str] = field(default_factory=lambda: deque(maxlen=DEFAULTS.get("GLYPH_HYSTERESIS_WINDOW", 7)))
|
|
55
|
+
|
|
56
|
+
def neighbors(self) -> Iterable["NodoTNFR"]:
|
|
57
|
+
return list(self._neighbors)
|
|
58
|
+
|
|
59
|
+
def has_edge(self, other: "NodoTNFR") -> bool:
|
|
60
|
+
return other in self._neighbors
|
|
61
|
+
|
|
62
|
+
def add_edge(self, other: "NodoTNFR", weight: float = 1.0) -> None:
|
|
63
|
+
if other not in self._neighbors:
|
|
64
|
+
self._neighbors.append(other)
|
|
65
|
+
other._neighbors.append(self)
|
|
66
|
+
|
|
67
|
+
def push_glifo(self, glifo: str, window: int) -> None:
|
|
68
|
+
self._hist_glifos.append(glifo)
|
|
69
|
+
while len(self._hist_glifos) > window:
|
|
70
|
+
self._hist_glifos.popleft()
|
|
71
|
+
self.epi_kind = glifo
|
|
72
|
+
|
|
73
|
+
def offset(self) -> int:
|
|
74
|
+
return 0
|
|
75
|
+
|
|
76
|
+
def all_nodes(self) -> Iterable["NodoTNFR"]:
|
|
77
|
+
return list(getattr(self.graph, "_all_nodes", [self]))
|
|
78
|
+
|
|
79
|
+
def aplicar_glifo(self, glifo: str, window: Optional[int] = None) -> None:
|
|
80
|
+
from .operators import aplicar_glifo_obj
|
|
81
|
+
aplicar_glifo_obj(self, glifo, window=window)
|
|
82
|
+
|
|
83
|
+
def integrar(self, dt: float) -> None:
|
|
84
|
+
self.EPI += self.dnfr * dt
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class NodoNX(NodoProtocol):
|
|
88
|
+
"""Adaptador para nodos ``networkx``."""
|
|
89
|
+
|
|
90
|
+
def __init__(self, G, n):
|
|
91
|
+
self.G = G
|
|
92
|
+
self.n = n
|
|
93
|
+
self.graph = G.graph
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def EPI(self) -> float:
|
|
97
|
+
from .helpers import _get_attr
|
|
98
|
+
from .constants import ALIAS_EPI
|
|
99
|
+
return float(_get_attr(self.G.nodes[self.n], ALIAS_EPI, 0.0))
|
|
100
|
+
|
|
101
|
+
@EPI.setter
|
|
102
|
+
def EPI(self, v: float) -> None:
|
|
103
|
+
from .helpers import _set_attr
|
|
104
|
+
from .constants import ALIAS_EPI
|
|
105
|
+
_set_attr(self.G.nodes[self.n], ALIAS_EPI, float(v))
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def vf(self) -> float:
|
|
109
|
+
from .helpers import _get_attr
|
|
110
|
+
from .constants import ALIAS_VF
|
|
111
|
+
return float(_get_attr(self.G.nodes[self.n], ALIAS_VF, 0.0))
|
|
112
|
+
|
|
113
|
+
@vf.setter
|
|
114
|
+
def vf(self, v: float) -> None:
|
|
115
|
+
from .helpers import _set_attr
|
|
116
|
+
from .constants import ALIAS_VF
|
|
117
|
+
_set_attr(self.G.nodes[self.n], ALIAS_VF, float(v))
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def theta(self) -> float:
|
|
121
|
+
from .helpers import _get_attr
|
|
122
|
+
from .constants import ALIAS_THETA
|
|
123
|
+
return float(_get_attr(self.G.nodes[self.n], ALIAS_THETA, 0.0))
|
|
124
|
+
|
|
125
|
+
@theta.setter
|
|
126
|
+
def theta(self, v: float) -> None:
|
|
127
|
+
from .helpers import _set_attr
|
|
128
|
+
from .constants import ALIAS_THETA
|
|
129
|
+
_set_attr(self.G.nodes[self.n], ALIAS_THETA, float(v))
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def Si(self) -> float:
|
|
133
|
+
from .helpers import _get_attr
|
|
134
|
+
from .constants import ALIAS_SI
|
|
135
|
+
return float(_get_attr(self.G.nodes[self.n], ALIAS_SI, 0.0))
|
|
136
|
+
|
|
137
|
+
@Si.setter
|
|
138
|
+
def Si(self, v: float) -> None:
|
|
139
|
+
from .helpers import _set_attr
|
|
140
|
+
from .constants import ALIAS_SI
|
|
141
|
+
_set_attr(self.G.nodes[self.n], ALIAS_SI, float(v))
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def epi_kind(self) -> str:
|
|
145
|
+
from .helpers import _get_attr_str
|
|
146
|
+
from .constants import ALIAS_EPI_KIND
|
|
147
|
+
return _get_attr_str(self.G.nodes[self.n], ALIAS_EPI_KIND, "")
|
|
148
|
+
|
|
149
|
+
@epi_kind.setter
|
|
150
|
+
def epi_kind(self, v: str) -> None:
|
|
151
|
+
from .helpers import _set_attr_str
|
|
152
|
+
from .constants import ALIAS_EPI_KIND
|
|
153
|
+
_set_attr_str(self.G.nodes[self.n], ALIAS_EPI_KIND, str(v))
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def dnfr(self) -> float:
|
|
157
|
+
from .helpers import _get_attr
|
|
158
|
+
from .constants import ALIAS_DNFR
|
|
159
|
+
return float(_get_attr(self.G.nodes[self.n], ALIAS_DNFR, 0.0))
|
|
160
|
+
|
|
161
|
+
@dnfr.setter
|
|
162
|
+
def dnfr(self, v: float) -> None:
|
|
163
|
+
from .helpers import _set_attr
|
|
164
|
+
from .constants import ALIAS_DNFR
|
|
165
|
+
_set_attr(self.G.nodes[self.n], ALIAS_DNFR, float(v))
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def d2EPI(self) -> float:
|
|
169
|
+
from .helpers import _get_attr
|
|
170
|
+
from .constants import ALIAS_D2EPI
|
|
171
|
+
return float(_get_attr(self.G.nodes[self.n], ALIAS_D2EPI, 0.0))
|
|
172
|
+
|
|
173
|
+
@d2EPI.setter
|
|
174
|
+
def d2EPI(self, v: float) -> None:
|
|
175
|
+
from .helpers import _set_attr
|
|
176
|
+
from .constants import ALIAS_D2EPI
|
|
177
|
+
_set_attr(self.G.nodes[self.n], ALIAS_D2EPI, float(v))
|
|
178
|
+
|
|
179
|
+
def neighbors(self) -> Iterable[NodoProtocol]:
|
|
180
|
+
return [NodoNX(self.G, v) for v in self.G.neighbors(self.n)]
|
|
181
|
+
|
|
182
|
+
def push_glifo(self, glifo: str, window: int) -> None:
|
|
183
|
+
push_glifo(self.G.nodes[self.n], glifo, window)
|
|
184
|
+
self.epi_kind = glifo
|
|
185
|
+
|
|
186
|
+
def has_edge(self, other: NodoProtocol) -> bool:
|
|
187
|
+
if isinstance(other, NodoNX):
|
|
188
|
+
return self.G.has_edge(self.n, other.n)
|
|
189
|
+
raise NotImplementedError
|
|
190
|
+
|
|
191
|
+
def add_edge(self, other: NodoProtocol, weight: float) -> None:
|
|
192
|
+
if isinstance(other, NodoNX):
|
|
193
|
+
self.G.add_edge(self.n, other.n, weight=float(weight))
|
|
194
|
+
else:
|
|
195
|
+
raise NotImplementedError
|
|
196
|
+
|
|
197
|
+
def offset(self) -> int:
|
|
198
|
+
from .operators import _node_offset
|
|
199
|
+
return _node_offset(self.G, self.n)
|
|
200
|
+
|
|
201
|
+
def all_nodes(self) -> Iterable[NodoProtocol]:
|
|
202
|
+
return [NodoNX(self.G, v) for v in self.G.nodes()]
|