tnfr 3.5.0__py3-none-any.whl → 4.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 +51 -17
- tnfr/cli.py +177 -0
- tnfr/constants.py +41 -11
- tnfr/dynamics.py +32 -3
- tnfr/gamma.py +91 -0
- tnfr/grammar.py +149 -0
- tnfr/helpers.py +37 -11
- tnfr/main.py +20 -10
- tnfr/metrics.py +211 -0
- tnfr/operators.py +12 -0
- tnfr/presets.py +24 -0
- tnfr/program.py +168 -0
- tnfr/scenarios.py +28 -0
- tnfr/sense.py +215 -0
- tnfr/trace.py +145 -0
- tnfr/types.py +17 -0
- {tnfr-3.5.0.dist-info → tnfr-4.0.0.dist-info}/METADATA +10 -1
- tnfr-4.0.0.dist-info/RECORD +24 -0
- tnfr-4.0.0.dist-info/entry_points.txt +2 -0
- tnfr-3.5.0.dist-info/RECORD +0 -14
- tnfr-3.5.0.dist-info/entry_points.txt +0 -2
- {tnfr-3.5.0.dist-info → tnfr-4.0.0.dist-info}/WHEEL +0 -0
- {tnfr-3.5.0.dist-info → tnfr-4.0.0.dist-info}/licenses/LICENSE.md +0 -0
- {tnfr-3.5.0.dist-info → tnfr-4.0.0.dist-info}/top_level.txt +0 -0
tnfr/sense.py
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Dict, Any, List, Tuple
|
|
3
|
+
import math
|
|
4
|
+
from collections import Counter
|
|
5
|
+
|
|
6
|
+
from .constants import DEFAULTS, ALIAS_SI, ALIAS_EPI
|
|
7
|
+
from .helpers import _get_attr, clamp01, register_callback
|
|
8
|
+
|
|
9
|
+
# -------------------------
|
|
10
|
+
# Canon: orden circular de glifos y ángulos
|
|
11
|
+
# -------------------------
|
|
12
|
+
GLYPHS_CANONICAL: List[str] = [
|
|
13
|
+
"A’L", # 0
|
|
14
|
+
"E’N", # 1
|
|
15
|
+
"I’L", # 2
|
|
16
|
+
"U’M", # 3
|
|
17
|
+
"R’A", # 4
|
|
18
|
+
"VA’L", # 5
|
|
19
|
+
"O’Z", # 6
|
|
20
|
+
"Z’HIR",# 7
|
|
21
|
+
"NA’V", # 8
|
|
22
|
+
"T’HOL",# 9
|
|
23
|
+
"NU’L", #10
|
|
24
|
+
"SH’A", #11
|
|
25
|
+
"RE’MESH" #12
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
_SIGMA_ANGLES: Dict[str, float] = {g: (2.0*math.pi * i / len(GLYPHS_CANONICAL)) for i, g in enumerate(GLYPHS_CANONICAL)}
|
|
29
|
+
|
|
30
|
+
# -------------------------
|
|
31
|
+
# Config por defecto
|
|
32
|
+
# -------------------------
|
|
33
|
+
DEFAULTS.setdefault("SIGMA", {
|
|
34
|
+
"enabled": True,
|
|
35
|
+
"weight": "Si", # "Si" | "EPI" | "1"
|
|
36
|
+
"smooth": 0.0, # EMA sobre el vector global (0=off)
|
|
37
|
+
"history_key": "sigma_global", # dónde guardar en G.graph['history']
|
|
38
|
+
"per_node": False, # si True, guarda trayectoria σ por nodo (más pesado)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
# -------------------------
|
|
42
|
+
# Utilidades básicas
|
|
43
|
+
# -------------------------
|
|
44
|
+
|
|
45
|
+
def glyph_angle(g: str) -> float:
|
|
46
|
+
return float(_SIGMA_ANGLES.get(g, 0.0))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def glyph_unit(g: str) -> complex:
|
|
50
|
+
a = glyph_angle(g)
|
|
51
|
+
return complex(math.cos(a), math.sin(a))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _weight(G, n, mode: str) -> float:
|
|
55
|
+
nd = G.nodes[n]
|
|
56
|
+
if mode == "Si":
|
|
57
|
+
return clamp01(_get_attr(nd, ALIAS_SI, 0.5))
|
|
58
|
+
if mode == "EPI":
|
|
59
|
+
return max(0.0, float(_get_attr(nd, ALIAS_EPI, 0.0)))
|
|
60
|
+
return 1.0
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _last_glifo(nd: Dict[str, Any]) -> str | None:
|
|
64
|
+
hist = nd.get("hist_glifos")
|
|
65
|
+
if not hist:
|
|
66
|
+
return None
|
|
67
|
+
try:
|
|
68
|
+
return list(hist)[-1]
|
|
69
|
+
except Exception:
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# -------------------------
|
|
74
|
+
# σ por nodo y σ global
|
|
75
|
+
# -------------------------
|
|
76
|
+
|
|
77
|
+
def sigma_vector_node(G, n, weight_mode: str | None = None) -> Dict[str, float] | None:
|
|
78
|
+
nd = G.nodes[n]
|
|
79
|
+
g = _last_glifo(nd)
|
|
80
|
+
if g is None:
|
|
81
|
+
return None
|
|
82
|
+
w = _weight(G, n, weight_mode or G.graph.get("SIGMA", DEFAULTS["SIGMA"]).get("weight", "Si"))
|
|
83
|
+
z = glyph_unit(g) * w
|
|
84
|
+
x, y = z.real, z.imag
|
|
85
|
+
mag = math.hypot(x, y)
|
|
86
|
+
ang = math.atan2(y, x) if mag > 0 else glyph_angle(g)
|
|
87
|
+
return {"x": float(x), "y": float(y), "mag": float(mag), "angle": float(ang), "glifo": g, "w": float(w)}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def sigma_vector_global(G, weight_mode: str | None = None) -> Dict[str, float]:
|
|
91
|
+
"""Vector global del plano del sentido σ.
|
|
92
|
+
|
|
93
|
+
Mapea el último glifo de cada nodo a un vector unitario en S¹, ponderado
|
|
94
|
+
por `Si` (o `EPI`/1), y promedia para obtener:
|
|
95
|
+
- componentes (x, y), magnitud |σ| y ángulo arg(σ).
|
|
96
|
+
|
|
97
|
+
Interpretación TNFR: |σ| mide cuán alineada está la red en su
|
|
98
|
+
**recorrido glífico**; arg(σ) indica la **dirección funcional** dominante
|
|
99
|
+
(p. ej., torno a I’L/RA para consolidación/distribución, O’Z/Z’HIR para cambio).
|
|
100
|
+
"""
|
|
101
|
+
cfg = G.graph.get("SIGMA", DEFAULTS["SIGMA"])
|
|
102
|
+
weight_mode = weight_mode or cfg.get("weight", "Si")
|
|
103
|
+
acc = complex(0.0, 0.0)
|
|
104
|
+
cnt = 0
|
|
105
|
+
for n in G.nodes():
|
|
106
|
+
v = sigma_vector_node(G, n, weight_mode)
|
|
107
|
+
if v is None:
|
|
108
|
+
continue
|
|
109
|
+
acc += complex(v["x"], v["y"])
|
|
110
|
+
cnt += 1
|
|
111
|
+
if cnt == 0:
|
|
112
|
+
return {"x": 1.0, "y": 0.0, "mag": 1.0, "angle": 0.0, "n": 0}
|
|
113
|
+
x, y = acc.real / max(1, cnt), acc.imag / max(1, cnt)
|
|
114
|
+
mag = math.hypot(x, y)
|
|
115
|
+
ang = math.atan2(y, x)
|
|
116
|
+
return {"x": float(x), "y": float(y), "mag": float(mag), "angle": float(ang), "n": cnt}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# -------------------------
|
|
120
|
+
# Historia / series
|
|
121
|
+
# -------------------------
|
|
122
|
+
|
|
123
|
+
def _ensure_history(G):
|
|
124
|
+
if "history" not in G.graph:
|
|
125
|
+
G.graph["history"] = {}
|
|
126
|
+
return G.graph["history"]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def push_sigma_snapshot(G, t: float | None = None) -> None:
|
|
130
|
+
cfg = G.graph.get("SIGMA", DEFAULTS["SIGMA"])
|
|
131
|
+
if not cfg.get("enabled", True):
|
|
132
|
+
return
|
|
133
|
+
hist = _ensure_history(G)
|
|
134
|
+
key = cfg.get("history_key", "sigma_global")
|
|
135
|
+
|
|
136
|
+
# Global
|
|
137
|
+
sv = sigma_vector_global(G, cfg.get("weight", "Si"))
|
|
138
|
+
|
|
139
|
+
# Suavizado exponencial (EMA) opcional
|
|
140
|
+
alpha = float(cfg.get("smooth", 0.0))
|
|
141
|
+
if alpha > 0 and hist.get(key):
|
|
142
|
+
prev = hist[key][-1]
|
|
143
|
+
x = (1-alpha)*prev["x"] + alpha*sv["x"]
|
|
144
|
+
y = (1-alpha)*prev["y"] + alpha*sv["y"]
|
|
145
|
+
mag = math.hypot(x, y)
|
|
146
|
+
ang = math.atan2(y, x)
|
|
147
|
+
sv = {"x": x, "y": y, "mag": mag, "angle": ang, "n": sv.get("n", 0)}
|
|
148
|
+
|
|
149
|
+
sv["t"] = float(G.graph.get("_t", 0.0) if t is None else t)
|
|
150
|
+
|
|
151
|
+
hist.setdefault(key, []).append(sv)
|
|
152
|
+
|
|
153
|
+
# Conteo de glifos por paso (útil para rosa glífica)
|
|
154
|
+
counts = Counter()
|
|
155
|
+
for n in G.nodes():
|
|
156
|
+
g = _last_glifo(G.nodes[n])
|
|
157
|
+
if g:
|
|
158
|
+
counts[g] += 1
|
|
159
|
+
hist.setdefault("sigma_counts", []).append({"t": sv["t"], **counts})
|
|
160
|
+
|
|
161
|
+
# Trayectoria por nodo (opcional)
|
|
162
|
+
if cfg.get("per_node", False):
|
|
163
|
+
per = hist.setdefault("sigma_per_node", {})
|
|
164
|
+
for n in G.nodes():
|
|
165
|
+
nd = G.nodes[n]
|
|
166
|
+
g = _last_glifo(nd)
|
|
167
|
+
if not g:
|
|
168
|
+
continue
|
|
169
|
+
a = glyph_angle(g)
|
|
170
|
+
d = per.setdefault(n, [])
|
|
171
|
+
d.append({"t": sv["t"], "g": g, "angle": a})
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# -------------------------
|
|
175
|
+
# Registro como callback automático (after_step)
|
|
176
|
+
# -------------------------
|
|
177
|
+
|
|
178
|
+
def register_sigma_callback(G) -> None:
|
|
179
|
+
register_callback(G, when="after_step", func=push_sigma_snapshot, name="sigma_snapshot")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
# -------------------------
|
|
183
|
+
# Series de utilidad
|
|
184
|
+
# -------------------------
|
|
185
|
+
|
|
186
|
+
def sigma_series(G, key: str | None = None) -> Dict[str, List[float]]:
|
|
187
|
+
cfg = G.graph.get("SIGMA", DEFAULTS["SIGMA"])
|
|
188
|
+
key = key or cfg.get("history_key", "sigma_global")
|
|
189
|
+
hist = G.graph.get("history", {})
|
|
190
|
+
xs = hist.get(key, [])
|
|
191
|
+
if not xs:
|
|
192
|
+
return {"t": [], "angle": [], "mag": []}
|
|
193
|
+
return {
|
|
194
|
+
"t": [float(x.get("t", i)) for i, x in enumerate(xs)],
|
|
195
|
+
"angle": [float(x["angle"]) for x in xs],
|
|
196
|
+
"mag": [float(x["mag"]) for x in xs],
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def sigma_rose(G, steps: int | None = None) -> Dict[str, int]:
|
|
201
|
+
"""Histograma de glifos en los últimos `steps` pasos (o todos)."""
|
|
202
|
+
hist = G.graph.get("history", {})
|
|
203
|
+
counts = hist.get("sigma_counts", [])
|
|
204
|
+
if not counts:
|
|
205
|
+
return {g: 0 for g in GLYPHS_CANONICAL}
|
|
206
|
+
if steps is None or steps >= len(counts):
|
|
207
|
+
agg = Counter()
|
|
208
|
+
for row in counts:
|
|
209
|
+
agg.update({k: v for k, v in row.items() if k != "t"})
|
|
210
|
+
out = {g: int(agg.get(g, 0)) for g in GLYPHS_CANONICAL}
|
|
211
|
+
return out
|
|
212
|
+
agg = Counter()
|
|
213
|
+
for row in counts[-int(steps):]:
|
|
214
|
+
agg.update({k: v for k, v in row.items() if k != "t"})
|
|
215
|
+
return {g: int(agg.get(g, 0)) for g in GLYPHS_CANONICAL}
|
tnfr/trace.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Any, Dict, List, Optional
|
|
3
|
+
from collections import Counter
|
|
4
|
+
|
|
5
|
+
from .constants import DEFAULTS
|
|
6
|
+
from .helpers import register_callback
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from .gamma import kuramoto_R_psi
|
|
10
|
+
except Exception: # pragma: no cover
|
|
11
|
+
def kuramoto_R_psi(G):
|
|
12
|
+
return 0.0, 0.0
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from .sense import sigma_vector_global
|
|
16
|
+
except Exception: # pragma: no cover
|
|
17
|
+
def sigma_vector_global(G, *args, **kwargs):
|
|
18
|
+
return {"x": 1.0, "y": 0.0, "mag": 1.0, "angle": 0.0, "n": 0}
|
|
19
|
+
|
|
20
|
+
# -------------------------
|
|
21
|
+
# Defaults
|
|
22
|
+
# -------------------------
|
|
23
|
+
DEFAULTS.setdefault("TRACE", {
|
|
24
|
+
"enabled": True,
|
|
25
|
+
"capture": ["gamma", "grammar", "selector", "dnfr_mix", "callbacks", "thol_state", "sigma", "kuramoto", "glifo_counts"],
|
|
26
|
+
"history_key": "trace_meta",
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
# -------------------------
|
|
30
|
+
# Helpers
|
|
31
|
+
# -------------------------
|
|
32
|
+
|
|
33
|
+
def _ensure_history(G):
|
|
34
|
+
if "history" not in G.graph:
|
|
35
|
+
G.graph["history"] = {}
|
|
36
|
+
return G.graph["history"]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _last_glifo(nd: Dict[str, Any]) -> str | None:
|
|
40
|
+
h = nd.get("hist_glifos")
|
|
41
|
+
if not h:
|
|
42
|
+
return None
|
|
43
|
+
try:
|
|
44
|
+
return list(h)[-1]
|
|
45
|
+
except Exception:
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# -------------------------
|
|
50
|
+
# Snapshots
|
|
51
|
+
# -------------------------
|
|
52
|
+
|
|
53
|
+
def _trace_before(G, *args, **kwargs):
|
|
54
|
+
if not G.graph.get("TRACE", DEFAULTS["TRACE"]).get("enabled", True):
|
|
55
|
+
return
|
|
56
|
+
cfg = G.graph.get("TRACE", DEFAULTS["TRACE"])
|
|
57
|
+
capture: List[str] = list(cfg.get("capture", []))
|
|
58
|
+
hist = _ensure_history(G)
|
|
59
|
+
key = cfg.get("history_key", "trace_meta")
|
|
60
|
+
|
|
61
|
+
meta: Dict[str, Any] = {"t": float(G.graph.get("_t", 0.0)), "phase": "before"}
|
|
62
|
+
|
|
63
|
+
if "gamma" in capture:
|
|
64
|
+
meta["gamma"] = dict(G.graph.get("GAMMA", {}))
|
|
65
|
+
|
|
66
|
+
if "grammar" in capture:
|
|
67
|
+
meta["grammar"] = dict(G.graph.get("GRAMMAR_CANON", {}))
|
|
68
|
+
|
|
69
|
+
if "selector" in capture:
|
|
70
|
+
sel = G.graph.get("glyph_selector")
|
|
71
|
+
meta["selector"] = getattr(sel, "__name__", str(sel)) if sel else None
|
|
72
|
+
|
|
73
|
+
if "dnfr_mix" in capture:
|
|
74
|
+
# tratar de capturar varias convenciones posibles
|
|
75
|
+
mix = G.graph.get("DNFR_MIX") or G.graph.get("DELTA_NFR_MIX") or G.graph.get("NFR_MIX")
|
|
76
|
+
meta["dnfr_mix"] = mix if isinstance(mix, dict) else {"value": mix}
|
|
77
|
+
|
|
78
|
+
if "callbacks" in capture:
|
|
79
|
+
# si el motor guarda los callbacks, exponer nombres por fase
|
|
80
|
+
cb = G.graph.get("_callbacks")
|
|
81
|
+
if isinstance(cb, dict):
|
|
82
|
+
out = {k: [getattr(f, "__name__", "fn") for (_, f, *_rest) in v] if isinstance(v, list) else None for k, v in cb.items()}
|
|
83
|
+
meta["callbacks"] = out
|
|
84
|
+
|
|
85
|
+
if "thol_state" in capture:
|
|
86
|
+
# cuántos nodos tienen bloque T’HOL abierto
|
|
87
|
+
th_open = 0
|
|
88
|
+
for n in G.nodes():
|
|
89
|
+
st = G.nodes[n].get("_GRAM", {})
|
|
90
|
+
if st.get("thol_open", False):
|
|
91
|
+
th_open += 1
|
|
92
|
+
meta["thol_open_nodes"] = th_open
|
|
93
|
+
|
|
94
|
+
hist.setdefault(key, []).append(meta)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _trace_after(G, *args, **kwargs):
|
|
98
|
+
if not G.graph.get("TRACE", DEFAULTS["TRACE"]).get("enabled", True):
|
|
99
|
+
return
|
|
100
|
+
cfg = G.graph.get("TRACE", DEFAULTS["TRACE"])
|
|
101
|
+
capture: List[str] = list(cfg.get("capture", []))
|
|
102
|
+
hist = _ensure_history(G)
|
|
103
|
+
key = cfg.get("history_key", "trace_meta")
|
|
104
|
+
|
|
105
|
+
meta: Dict[str, Any] = {"t": float(G.graph.get("_t", 0.0)), "phase": "after"}
|
|
106
|
+
|
|
107
|
+
if "kuramoto" in capture:
|
|
108
|
+
R, psi = kuramoto_R_psi(G)
|
|
109
|
+
meta["kuramoto"] = {"R": float(R), "psi": float(psi)}
|
|
110
|
+
|
|
111
|
+
if "sigma" in capture:
|
|
112
|
+
sv = sigma_vector_global(G)
|
|
113
|
+
meta["sigma"] = {"x": float(sv.get("x", 1.0)), "y": float(sv.get("y", 0.0)), "mag": float(sv.get("mag", 1.0)), "angle": float(sv.get("angle", 0.0))}
|
|
114
|
+
|
|
115
|
+
if "glifo_counts" in capture:
|
|
116
|
+
cnt = Counter()
|
|
117
|
+
for n in G.nodes():
|
|
118
|
+
g = _last_glifo(G.nodes[n])
|
|
119
|
+
if g:
|
|
120
|
+
cnt[g] += 1
|
|
121
|
+
meta["glifos"] = dict(cnt)
|
|
122
|
+
|
|
123
|
+
hist.setdefault(key, []).append(meta)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# -------------------------
|
|
127
|
+
# API
|
|
128
|
+
# -------------------------
|
|
129
|
+
|
|
130
|
+
def register_trace(G) -> None:
|
|
131
|
+
"""Activa snapshots before/after step y vuelca metadatos operativos en history.
|
|
132
|
+
|
|
133
|
+
Guarda en G.graph['history'][TRACE.history_key] una lista de entradas {'phase': 'before'|'after', ...} con:
|
|
134
|
+
- gamma: especificación activa de Γi(R)
|
|
135
|
+
- grammar: configuración de gramática canónica
|
|
136
|
+
- selector: nombre del selector glífico
|
|
137
|
+
- dnfr_mix: mezcla (si el motor la expone en G.graph)
|
|
138
|
+
- callbacks: callbacks registrados por fase (si están en G.graph['_callbacks'])
|
|
139
|
+
- thol_open_nodes: cuántos nodos tienen bloque T’HOL abierto
|
|
140
|
+
- kuramoto: (R, ψ) de la red
|
|
141
|
+
- sigma: vector global del plano del sentido
|
|
142
|
+
- glifos: conteos por glifo tras el paso
|
|
143
|
+
"""
|
|
144
|
+
register_callback(G, when="before_step", func=_trace_before, name="trace_before")
|
|
145
|
+
register_callback(G, when="after_step", func=_trace_after, name="trace_after")
|
tnfr/types.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import Dict, Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class NodeState:
|
|
8
|
+
EPI: float = 0.0
|
|
9
|
+
vf: float = 1.0 # νf
|
|
10
|
+
theta: float = 0.0 # θ
|
|
11
|
+
Si: float = 0.5
|
|
12
|
+
extra: Dict[str, Any] = field(default_factory=dict)
|
|
13
|
+
|
|
14
|
+
def to_attrs(self) -> Dict[str, Any]:
|
|
15
|
+
d = {"EPI": self.EPI, "νf": self.vf, "θ": self.theta, "Si": self.Si}
|
|
16
|
+
d.update(self.extra)
|
|
17
|
+
return d
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tnfr
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
4
4
|
Summary: TNFR canónica: dinámica glífica modular sobre redes.
|
|
5
5
|
Author: fmg
|
|
6
6
|
License: MIT
|
|
@@ -81,6 +81,9 @@ Dynamic: license-file
|
|
|
81
81
|
|
|
82
82
|
**Mastering these pieces will let you extend the simulation, build analysis pipelines and connect the theory with computational applications.**
|
|
83
83
|
|
|
84
|
+
## Optional Node environment
|
|
85
|
+
The repository includes a minimal `package.json` and `netlify.toml` used for an experimental Remix web demo. They are not required for the core Python package; feel free to ignore them unless you plan to build the demo via `npm run build`.
|
|
86
|
+
|
|
84
87
|
## Testing
|
|
85
88
|
|
|
86
89
|
Install the dependencies and project in editable mode before running the test suite with `pytest`:
|
|
@@ -89,4 +92,10 @@ Install the dependencies and project in editable mode before running the test su
|
|
|
89
92
|
pip install networkx
|
|
90
93
|
pip install -e .
|
|
91
94
|
pytest
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Installation
|
|
99
|
+
```
|
|
100
|
+
pip install tnfr
|
|
92
101
|
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
tnfr/__init__.py,sha256=nN8P2Xm26kvJvqDhmRITnimew3SgBgw4fSUHPOAiYts,1880
|
|
2
|
+
tnfr/cli.py,sha256=fdzmIOVerg6J1j6cBuu7m2-nKFG_WqiNu-e2Wg8eECQ,5980
|
|
3
|
+
tnfr/constants.py,sha256=PUhps2gBXeh_rJIrCF9HpWRdi02sfRXvVp066AOgkyQ,8912
|
|
4
|
+
tnfr/dynamics.py,sha256=FeFv7h4m9e8qhbU9tIRss3K6P2uz4Hfmtbldf2AhfyQ,25286
|
|
5
|
+
tnfr/gamma.py,sha256=1hGqYTBYIYirgmSSSbvSuFWPVy_KGzPNH3eD7wmRUu0,2689
|
|
6
|
+
tnfr/grammar.py,sha256=X50-BzTzaYkFIi-ljcgB_XXC6c2srvqzDqOKa91nsuA,5090
|
|
7
|
+
tnfr/helpers.py,sha256=foJgwyC__6lQeOpPY02slFRggY3tCy1CxeFlEQcI-gY,7014
|
|
8
|
+
tnfr/main.py,sha256=XqjI1YEdF-OqRzTMa5dYIxCig4qyAR-l1FPcyxpC8WY,1926
|
|
9
|
+
tnfr/metrics.py,sha256=XusywHo1-GgLqYy1Jz43Xc4zRsggrn_DwoaFWfAy82M,6640
|
|
10
|
+
tnfr/observers.py,sha256=PTw3hxk7KD-Yx_CvCIU09icuhyYD6uNU6SvF80UvP-Y,5354
|
|
11
|
+
tnfr/ontosim.py,sha256=9GfEtiLIdJOPJUTufcq_MssAA9J8AfChHU6HKb3DIJY,5628
|
|
12
|
+
tnfr/operators.py,sha256=Q2QvtK2oQUuMsq_CPdfaK9eCrhniI1NaWEfwQH08zSk,12936
|
|
13
|
+
tnfr/presets.py,sha256=vaqgqz1pVU93hEOITQn-2CUGfMbN2n47A9GBFmjWRpo,661
|
|
14
|
+
tnfr/program.py,sha256=qGqj74qBqXILm-Yrw73__0uIlx2gJiSF9dDHxOGTbCs,5798
|
|
15
|
+
tnfr/scenarios.py,sha256=FgsXzA6ENRkalENnG5ZuBNFguEGaKZTM6y0quW5fJI4,808
|
|
16
|
+
tnfr/sense.py,sha256=1yVlphcs4o_uOQ51MDqW9dphydMiDNKv1Z1EdgbJgpU,6778
|
|
17
|
+
tnfr/trace.py,sha256=YtqSKJM2tCH5eLa22nObPLnYgsn4Bm6inipY0n_mwXY,4887
|
|
18
|
+
tnfr/types.py,sha256=xyFHp0PptEqPNUekAFH6DcAnyMx4bCQutMyFUXMd2sA,457
|
|
19
|
+
tnfr-4.0.0.dist-info/licenses/LICENSE.md,sha256=SRvvhXLrKtseuK6DARbuJffuXOXqAyk3wvF2n0t1SWA,1109
|
|
20
|
+
tnfr-4.0.0.dist-info/METADATA,sha256=xzcC2N34E82NmkgYly3jpfgzLVgI9fQLNnMiXLWk2RQ,5898
|
|
21
|
+
tnfr-4.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
22
|
+
tnfr-4.0.0.dist-info/entry_points.txt,sha256=j4-QRHqeT2WnchHe_mvK7npGTLjlyfLpvRONFe9Z4MU,39
|
|
23
|
+
tnfr-4.0.0.dist-info/top_level.txt,sha256=Q2HJnvc5Rt2VHwVvyBTnNPT4SfmJWnCj7XUxxEvQa7c,5
|
|
24
|
+
tnfr-4.0.0.dist-info/RECORD,,
|
tnfr-3.5.0.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
tnfr/__init__.py,sha256=LYIpDLjPnC4MxrviM2-Lg8KudbzXM_56aepRg_BEJG4,581
|
|
2
|
-
tnfr/constants.py,sha256=_775sPHussR9vgkWRCLC6dzwgk_1_lLnSlWT8sBWR3U,7677
|
|
3
|
-
tnfr/dynamics.py,sha256=btDyC3jIOmND1c1qqA2RDo0f3NraJKZwggO5BqBAmCA,23967
|
|
4
|
-
tnfr/helpers.py,sha256=3DT7nb2FBrJxSEFcZ_Q9qiR9JGbjCNJOzA49bzN6hbM,6067
|
|
5
|
-
tnfr/main.py,sha256=TEngteuC9MD7Ec9bNGuCC9ym-2ohbh202-HGArCR4tk,1506
|
|
6
|
-
tnfr/observers.py,sha256=PTw3hxk7KD-Yx_CvCIU09icuhyYD6uNU6SvF80UvP-Y,5354
|
|
7
|
-
tnfr/ontosim.py,sha256=9GfEtiLIdJOPJUTufcq_MssAA9J8AfChHU6HKb3DIJY,5628
|
|
8
|
-
tnfr/operators.py,sha256=ONUC0tzB7y0Ad4MppLjFc8bmlTjPol-l_xdEB_84uaw,12293
|
|
9
|
-
tnfr-3.5.0.dist-info/licenses/LICENSE.md,sha256=SRvvhXLrKtseuK6DARbuJffuXOXqAyk3wvF2n0t1SWA,1109
|
|
10
|
-
tnfr-3.5.0.dist-info/METADATA,sha256=N420pHD6T9d8kkDwi202Klyh7mu7oIx3-CmwYZo_CwA,5576
|
|
11
|
-
tnfr-3.5.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
-
tnfr-3.5.0.dist-info/entry_points.txt,sha256=6ZYrYA3Z-kKvqiYddIAj9c8ZcoVlK7pj-qCBvlNtuLE,40
|
|
13
|
-
tnfr-3.5.0.dist-info/top_level.txt,sha256=Q2HJnvc5Rt2VHwVvyBTnNPT4SfmJWnCj7XUxxEvQa7c,5
|
|
14
|
-
tnfr-3.5.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|