tnfr 1.0__py3-none-any.whl → 2.0.1__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 +47 -34
- tnfr/constants.py +183 -7
- tnfr/dynamics.py +543 -0
- tnfr/helpers.py +198 -0
- tnfr/main.py +0 -0
- tnfr/observers.py +149 -0
- tnfr/ontosim.py +137 -0
- tnfr/operators.py +296 -0
- tnfr-2.0.1.dist-info/METADATA +28 -0
- tnfr-2.0.1.dist-info/RECORD +14 -0
- tnfr-2.0.1.dist-info/entry_points.txt +2 -0
- tnfr-2.0.1.dist-info/top_level.txt +1 -0
- core/ontosim.py +0 -757
- matrix/operators.py +0 -496
- tnfr/core/ontosim.py +0 -1074
- tnfr/matrix/operators.py +0 -500
- tnfr/resonance/dynamics.py +0 -1305
- tnfr/utils/helpers.py +0 -357
- tnfr-1.0.dist-info/METADATA +0 -95
- tnfr-1.0.dist-info/RECORD +0 -14
- tnfr-1.0.dist-info/entry_points.txt +0 -2
- tnfr-1.0.dist-info/top_level.txt +0 -3
- {tnfr-1.0.dist-info → tnfr-2.0.1.dist-info}/WHEEL +0 -0
- {tnfr-1.0.dist-info → tnfr-2.0.1.dist-info}/licenses/LICENSE.txt +0 -0
tnfr/matrix/operators.py
DELETED
|
@@ -1,500 +0,0 @@
|
|
|
1
|
-
import random
|
|
2
|
-
|
|
3
|
-
def aplicar_glifo(G, nodo, nodo_id, nombre_glifo, historial_glifos_por_nodo, paso):
|
|
4
|
-
nodo["glifo"] = nombre_glifo
|
|
5
|
-
nodo["estado"] = "silencio" if nombre_glifo == "SHA" else "activo"
|
|
6
|
-
|
|
7
|
-
# Preservar valor anterior de θ para detección de mutaciones
|
|
8
|
-
if "θ_prev" not in nodo:
|
|
9
|
-
nodo["θ_prev"] = nodo.get("θ", 0)
|
|
10
|
-
else:
|
|
11
|
-
nodo["θ_prev"] = nodo.get("θ", nodo["θ_prev"])
|
|
12
|
-
|
|
13
|
-
# Registro en historial global
|
|
14
|
-
if historial_glifos_por_nodo is not None and paso is not None:
|
|
15
|
-
historial_glifos_por_nodo.setdefault(nodo_id, []).append((paso, nombre_glifo))
|
|
16
|
-
|
|
17
|
-
# Registro en historial local (para EPIs compuestas)
|
|
18
|
-
if paso is not None:
|
|
19
|
-
if "historial_glifos" not in nodo:
|
|
20
|
-
nodo["historial_glifos"] = []
|
|
21
|
-
nodo["historial_glifos"].append((paso, nombre_glifo))
|
|
22
|
-
|
|
23
|
-
# === Transformaciones estructurales por glifo TNFR ===
|
|
24
|
-
|
|
25
|
-
if nombre_glifo == "AL": # Emisión
|
|
26
|
-
nodo["EPI"] += 0.2
|
|
27
|
-
nodo["Si"] += 0.05
|
|
28
|
-
nodo["νf"] *= 1.05
|
|
29
|
-
nodo["ΔNFR"] *= 0.97
|
|
30
|
-
|
|
31
|
-
elif nombre_glifo == "EN": # Recepción
|
|
32
|
-
nodo["Si"] += 0.08
|
|
33
|
-
nodo["νf"] *= 0.95
|
|
34
|
-
nodo["θ"] = max(0.0, nodo["θ"] - random.uniform(0.05, 0.15))
|
|
35
|
-
|
|
36
|
-
elif nombre_glifo == "IL": # Coherencia
|
|
37
|
-
nodo["Si"] += 0.1
|
|
38
|
-
nodo["EPI"] *= 1.05
|
|
39
|
-
nodo["ΔNFR"] *= 0.95
|
|
40
|
-
|
|
41
|
-
elif nombre_glifo == "OZ": # Disonancia
|
|
42
|
-
nodo["EPI"] *= 0.85
|
|
43
|
-
nodo["ΔNFR"] *= 1.4
|
|
44
|
-
nodo["νf"] *= 1.05
|
|
45
|
-
nodo["Si"] *= 0.9
|
|
46
|
-
|
|
47
|
-
elif nombre_glifo == "UM": # Acoplamiento
|
|
48
|
-
vecinos = list(G.neighbors(nodo_id))
|
|
49
|
-
if vecinos:
|
|
50
|
-
media_vf = sum(G.nodes[v]["νf"] for v in vecinos) / len(vecinos)
|
|
51
|
-
nodo["νf"] = (nodo["νf"] + media_vf) * 0.5
|
|
52
|
-
nodo["ΔNFR"] *= 0.9
|
|
53
|
-
|
|
54
|
-
elif nombre_glifo == "RA": # Resonancia
|
|
55
|
-
nodo["Si"] += 0.15
|
|
56
|
-
nodo["EPI"] *= 1.05
|
|
57
|
-
nodo["νf"] *= 1.02
|
|
58
|
-
|
|
59
|
-
elif nombre_glifo == "SHA": # Silencio
|
|
60
|
-
nodo["estado"] = "silencio"
|
|
61
|
-
nodo["νf"] *= 0.3
|
|
62
|
-
nodo["ΔNFR"] *= 0.1
|
|
63
|
-
nodo["Si"] *= 0.5
|
|
64
|
-
nodo["EPI"] *= 0.9
|
|
65
|
-
|
|
66
|
-
elif nombre_glifo == "VAL": # Expansión
|
|
67
|
-
nodo["EPI"] *= 1.15
|
|
68
|
-
nodo["Si"] *= 1.08
|
|
69
|
-
nodo["νf"] *= 1.05
|
|
70
|
-
nodo["EPI"] = min(nodo["EPI"], 3.0) # Límite fijo mientras umbrales no esté disponible
|
|
71
|
-
|
|
72
|
-
elif nombre_glifo == "NUL": # Contracción
|
|
73
|
-
nodo["EPI"] *= 0.82
|
|
74
|
-
nodo["Si"] *= 0.92
|
|
75
|
-
nodo["νf"] *= 0.92
|
|
76
|
-
|
|
77
|
-
elif nombre_glifo == "THOL": # Autoorganización
|
|
78
|
-
nodo["νf"] *= 1.25
|
|
79
|
-
nodo["Si"] *= 1.15
|
|
80
|
-
nodo["θ"] = min(1.0, nodo["θ"] + random.uniform(0.1, 0.2))
|
|
81
|
-
|
|
82
|
-
elif nombre_glifo == "ZHIR": # Mutación
|
|
83
|
-
nodo["EPI"] += 0.5
|
|
84
|
-
nodo["νf"] *= 1.2
|
|
85
|
-
nodo["θ"] = min(1.0, nodo["θ"] + random.uniform(0.15, 0.3))
|
|
86
|
-
nodo["Si"] *= 1.1
|
|
87
|
-
|
|
88
|
-
elif nombre_glifo == "NAV": # Nacimiento
|
|
89
|
-
nodo["νf"] *= 1.08
|
|
90
|
-
nodo["ΔNFR"] *= 0.9
|
|
91
|
-
nodo["Si"] += 0.1
|
|
92
|
-
if nodo["estado"] == "silencio":
|
|
93
|
-
nodo["estado"] = "activo"
|
|
94
|
-
|
|
95
|
-
elif nombre_glifo == "REMESH": # Recursividad
|
|
96
|
-
nodo["EPI"] = (nodo.get("EPI_prev", nodo["EPI"]) + nodo.get("EPI_prev2", nodo["EPI"])) / 2
|
|
97
|
-
nodo["Si"] *= 0.98
|
|
98
|
-
nodo["νf"] *= 0.98
|
|
99
|
-
|
|
100
|
-
def evaluar_patron_glifico(glifos):
|
|
101
|
-
patron = " → ".join(glifos)
|
|
102
|
-
|
|
103
|
-
analisis = {
|
|
104
|
-
"ciclos_REMESH": glifos.count("REMESH"),
|
|
105
|
-
"uso_THOL": glifos.count("THOL"),
|
|
106
|
-
"uso_ZHIR": glifos.count("ZHIR"),
|
|
107
|
-
"latencia_prolongada": any(
|
|
108
|
-
glifos[i] == "SHA" and glifos[i+1] == "SHA"
|
|
109
|
-
for i in range(len(glifos) - 1)
|
|
110
|
-
),
|
|
111
|
-
"inicio_creativo": glifos[0] == "AL" if glifos else False,
|
|
112
|
-
"coherencia_expansiva": "IL" in glifos and "VAL" in glifos,
|
|
113
|
-
"disonancia_sostenida": any(
|
|
114
|
-
glifos[i] == "OZ" and glifos[i+1] == "OZ"
|
|
115
|
-
for i in range(len(glifos) - 1)
|
|
116
|
-
),
|
|
117
|
-
"patron_glifico": patron,
|
|
118
|
-
"tipo_nodal": (
|
|
119
|
-
"creador" if glifos and glifos[0] == "AL" else
|
|
120
|
-
"mutante" if "ZHIR" in glifos else
|
|
121
|
-
"colapsante" if glifos.count("REMESH") > 2 else
|
|
122
|
-
"expansivo" if "VAL" in glifos else
|
|
123
|
-
"latente"
|
|
124
|
-
)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return analisis
|
|
128
|
-
|
|
129
|
-
def glifo_por_estructura(nodo, G):
|
|
130
|
-
n_id = nodo.get("nodo", None)
|
|
131
|
-
vecinos = list(G.neighbors(n_id)) if n_id else []
|
|
132
|
-
|
|
133
|
-
# 1. SHA – Silencio ante alta disonancia
|
|
134
|
-
if nodo["EPI"] < 0.5 and abs(nodo["ΔNFR"]) > 0.8:
|
|
135
|
-
return "SHA"
|
|
136
|
-
|
|
137
|
-
# 2. NAV – Activación desde silencio
|
|
138
|
-
if nodo["estado"] == "silencio" and abs(nodo["ΔNFR"] - nodo["νf"]) < 0.05:
|
|
139
|
-
return "NAV"
|
|
140
|
-
|
|
141
|
-
# 3. AL – Emisión si es latente y sensible
|
|
142
|
-
if nodo["estado"] == "latente" and nodo["Si"] < 0.2 and nodo["νf"] > 1.0:
|
|
143
|
-
return "AL"
|
|
144
|
-
|
|
145
|
-
# 4. EN – Recepción ante apertura sensible
|
|
146
|
-
if nodo["ΔNFR"] > 0.6 and nodo["EPI"] > 1.0 and nodo["Si"] < 0.3:
|
|
147
|
-
return "EN"
|
|
148
|
-
|
|
149
|
-
# 5. OZ – Disonancia fuerte
|
|
150
|
-
if abs(nodo["ΔNFR"]) > 1.0 and nodo["EPI"] > 1.0:
|
|
151
|
-
return "OZ"
|
|
152
|
-
|
|
153
|
-
# 6. ZHIR – Mutación por cambio abrupto
|
|
154
|
-
if abs(nodo["EPI"] - nodo.get("EPI_prev", nodo["EPI"])) > 0.5 and nodo["Si"] > 0.5:
|
|
155
|
-
return "ZHIR"
|
|
156
|
-
|
|
157
|
-
# 7. VAL – Expansión estructural
|
|
158
|
-
if nodo["Si"] > 0.6 and nodo["EPI"] > 1.2:
|
|
159
|
-
return "VAL"
|
|
160
|
-
|
|
161
|
-
# 8. NUL – Contracción por exces
|
|
162
|
-
if nodo["EPI"] > 1.3 and nodo["Si"] < 0.4:
|
|
163
|
-
return "NUL"
|
|
164
|
-
|
|
165
|
-
# 9. THOL – Autoorganización
|
|
166
|
-
if abs(nodo["EPI"] - nodo["EPI_prev2"]) > 0.2 and abs(nodo["ΔNFR"]) < 0.1:
|
|
167
|
-
return "THOL"
|
|
168
|
-
|
|
169
|
-
# 10. IL – Coherencia estable
|
|
170
|
-
if abs(nodo["ΔNFR"]) < 0.05 and abs(nodo["EPI"] - nodo["EPI_prev"]) < 0.05:
|
|
171
|
-
return "IL"
|
|
172
|
-
|
|
173
|
-
# 11. RA – Resonancia coherente
|
|
174
|
-
if nodo["glifo"] == "IL" and nodo["Si"] > 0.5 and nodo["νf"] > 1.2:
|
|
175
|
-
return "RA"
|
|
176
|
-
|
|
177
|
-
# 12. UM – Acoplamiento con vecinos
|
|
178
|
-
for v in vecinos:
|
|
179
|
-
if abs(nodo["νf"] - G.nodes[v]["νf"]) < 0.05:
|
|
180
|
-
return "UM"
|
|
181
|
-
|
|
182
|
-
# 13. REMESH – Recursividad (si ya hay historial)
|
|
183
|
-
hist = nodo.get("historial_glifos", [])
|
|
184
|
-
if (
|
|
185
|
-
len(hist) >= 3
|
|
186
|
-
and hist[-1][1] == hist[-2][1] == hist[-3][1]
|
|
187
|
-
and abs(nodo["EPI"] - nodo["EPI_prev"]) < 0.05
|
|
188
|
-
):
|
|
189
|
-
return "REMESH"
|
|
190
|
-
|
|
191
|
-
return None # si no se detecta un glifo resonante
|
|
192
|
-
|
|
193
|
-
def transicion_glifica_canonica(nodo):
|
|
194
|
-
glifo = nodo["glifo"]
|
|
195
|
-
|
|
196
|
-
if glifo == "ZHIR":
|
|
197
|
-
if nodo["νf"] > 1.5 and nodo["EPI"] > 2.5:
|
|
198
|
-
return "VAL"
|
|
199
|
-
elif nodo["ΔNFR"] < 0:
|
|
200
|
-
return "RA"
|
|
201
|
-
else:
|
|
202
|
-
return "NAV"
|
|
203
|
-
|
|
204
|
-
elif glifo == "IL":
|
|
205
|
-
if nodo["νf"] > 1.2 and nodo["Si"] > 0.4:
|
|
206
|
-
return "RA"
|
|
207
|
-
|
|
208
|
-
elif glifo == "OZ":
|
|
209
|
-
if nodo["EPI"] > 2.2 and nodo["Si"] > 0.3:
|
|
210
|
-
return "THOL"
|
|
211
|
-
|
|
212
|
-
elif glifo == "NAV":
|
|
213
|
-
if abs(nodo["ΔNFR"]) < 0.1:
|
|
214
|
-
return "IL"
|
|
215
|
-
|
|
216
|
-
elif glifo == "RA":
|
|
217
|
-
if nodo["Si"] > 0.6 and nodo["EPI"] > 2.0:
|
|
218
|
-
return "REMESH"
|
|
219
|
-
|
|
220
|
-
elif glifo == "VAL":
|
|
221
|
-
if nodo["EPI"] > 3.0 and nodo["Si"] > 0.4:
|
|
222
|
-
return "NUL"
|
|
223
|
-
|
|
224
|
-
elif glifo == "AL":
|
|
225
|
-
if nodo["Si"] > 0.3 and nodo["ΔNFR"] < 0.2:
|
|
226
|
-
return "UM"
|
|
227
|
-
|
|
228
|
-
return None
|
|
229
|
-
|
|
230
|
-
def acoplar_nodos(G):
|
|
231
|
-
for n in G.nodes:
|
|
232
|
-
vecinos = list(G.neighbors(n))
|
|
233
|
-
if not vecinos:
|
|
234
|
-
vecinos = list(G.nodes)
|
|
235
|
-
Si_vecinos = [G.nodes[v]["Si"] for v in vecinos if v != n]
|
|
236
|
-
if Si_vecinos:
|
|
237
|
-
G.nodes[n]["Si"] = (sum(Si_vecinos) / len(Si_vecinos)) * 0.9 + G.nodes[n]["Si"] * 0.1
|
|
238
|
-
for v in vecinos:
|
|
239
|
-
if v != n:
|
|
240
|
-
if abs(G.nodes[n]["θ"] - G.nodes[v]["θ"]) < 0.1:
|
|
241
|
-
G.nodes[n]["ΔNFR"] *= 0.95
|
|
242
|
-
|
|
243
|
-
def detectar_EPIs_compuestas(G, umbrales=None):
|
|
244
|
-
# Si no se pasan umbrales, usar valores por defecto
|
|
245
|
-
if umbrales is None:
|
|
246
|
-
umbral_theta = 0.12
|
|
247
|
-
umbral_si = 0.2
|
|
248
|
-
else:
|
|
249
|
-
umbral_theta = umbrales.get('θ_conexion', 0.12)
|
|
250
|
-
umbral_si = umbrales.get('Si_conexion', 0.2)
|
|
251
|
-
|
|
252
|
-
compuestas = []
|
|
253
|
-
nodos_por_glifo_y_paso = {}
|
|
254
|
-
|
|
255
|
-
for n in G.nodes:
|
|
256
|
-
historial = G.nodes[n].get("historial_glifos", [])
|
|
257
|
-
for paso, glifo in historial:
|
|
258
|
-
clave = (paso, glifo)
|
|
259
|
-
nodos_por_glifo_y_paso.setdefault(clave, []).append(n)
|
|
260
|
-
|
|
261
|
-
for (paso, glifo), nodos_en_glifo in nodos_por_glifo_y_paso.items():
|
|
262
|
-
if len(nodos_en_glifo) < 3:
|
|
263
|
-
continue
|
|
264
|
-
|
|
265
|
-
grupo_coherente = []
|
|
266
|
-
for i, ni in enumerate(nodos_en_glifo):
|
|
267
|
-
for nj in nodos_en_glifo[i+1:]:
|
|
268
|
-
θi, θj = G.nodes[ni]["θ"], G.nodes[nj]["θ"]
|
|
269
|
-
Sii, Sij = G.nodes[ni].get("Si", 0), G.nodes[nj].get("Si", 0)
|
|
270
|
-
if abs(θi - θj) < umbral_theta and abs(Sii - Sij) < umbral_si:
|
|
271
|
-
grupo_coherente.extend([ni, nj])
|
|
272
|
-
|
|
273
|
-
grupo_final = list(set(grupo_coherente))
|
|
274
|
-
if len(grupo_final) >= 3:
|
|
275
|
-
compuestas.append({
|
|
276
|
-
"paso": paso,
|
|
277
|
-
"glifo": glifo,
|
|
278
|
-
"nodos": grupo_final,
|
|
279
|
-
"tipo": clasificar_epi(glifo)
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
return compuestas
|
|
283
|
-
|
|
284
|
-
def clasificar_epi(glifo):
|
|
285
|
-
if glifo in ["IL", "RA", "REMESH"]:
|
|
286
|
-
return "coherente"
|
|
287
|
-
elif glifo in ["ZHIR", "VAL", "NUL"]:
|
|
288
|
-
return "mutante"
|
|
289
|
-
elif glifo in ["SHA", "OZ"]:
|
|
290
|
-
return "disonante"
|
|
291
|
-
else:
|
|
292
|
-
return "otro"
|
|
293
|
-
|
|
294
|
-
def interpretar_sintaxis_glífica(historial):
|
|
295
|
-
sintaxis = {}
|
|
296
|
-
for nodo, secuencia in historial.items():
|
|
297
|
-
trayecto = [glifo for _, glifo in secuencia]
|
|
298
|
-
transiciones = list(zip(trayecto, trayecto[1:]))
|
|
299
|
-
ciclos_val_nul = sum(
|
|
300
|
-
1 for i in range(len(trayecto)-2)
|
|
301
|
-
if trayecto[i] == "VAL" and trayecto[i+1] == "NUL" and trayecto[i+2] == "VAL"
|
|
302
|
-
)
|
|
303
|
-
|
|
304
|
-
tipo = "desconocido"
|
|
305
|
-
if "ZHIR" in trayecto:
|
|
306
|
-
tipo = "mutante"
|
|
307
|
-
elif "REMESH" in trayecto:
|
|
308
|
-
tipo = "recursivo"
|
|
309
|
-
elif ciclos_val_nul >= 2:
|
|
310
|
-
tipo = "pulsante"
|
|
311
|
-
elif trayecto.count("IL") > 2:
|
|
312
|
-
tipo = "estabilizador"
|
|
313
|
-
|
|
314
|
-
sintaxis[nodo] = {
|
|
315
|
-
"trayectoria": trayecto,
|
|
316
|
-
"transiciones": transiciones,
|
|
317
|
-
"mutaciones": trayecto.count("ZHIR"),
|
|
318
|
-
"colapsos": trayecto.count("SHA"),
|
|
319
|
-
"ciclos_val_nul": ciclos_val_nul,
|
|
320
|
-
"diversidad_glifica": len(set(trayecto)),
|
|
321
|
-
"tipo_nodal": tipo
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
return sintaxis
|
|
325
|
-
|
|
326
|
-
def aplicar_remesh_red(G, historial_glifos_por_nodo, paso):
|
|
327
|
-
for n in G.nodes:
|
|
328
|
-
nodo = G.nodes[n]
|
|
329
|
-
aplicar_glifo(G, nodo, n, "REMESH", historial_glifos_por_nodo, paso)
|
|
330
|
-
|
|
331
|
-
def aplicar_remesh_si_estabilizacion_global(G, historial_glifos_por_nodo, historia_glifos, paso):
|
|
332
|
-
if len(G) == 0:
|
|
333
|
-
return
|
|
334
|
-
|
|
335
|
-
nodos_estables = 0
|
|
336
|
-
|
|
337
|
-
for n in G.nodes:
|
|
338
|
-
nodo = G.nodes[n]
|
|
339
|
-
estabilidad_epi = abs(nodo.get("EPI", 0) - nodo.get("EPI_prev", 0)) < 0.01
|
|
340
|
-
estabilidad_nfr = abs(nodo.get("ΔNFR", 0)) < 0.05
|
|
341
|
-
estabilidad_dEPI = abs(nodo.get("dEPI_dt", 0)) < 0.01
|
|
342
|
-
estabilidad_acel = abs(nodo.get("d2EPI_dt2", 0)) < 0.01
|
|
343
|
-
|
|
344
|
-
if all([estabilidad_epi, estabilidad_nfr, estabilidad_dEPI, estabilidad_acel]):
|
|
345
|
-
nodos_estables += 1
|
|
346
|
-
|
|
347
|
-
fraccion_estables = nodos_estables / len(G)
|
|
348
|
-
|
|
349
|
-
if fraccion_estables > 0.8:
|
|
350
|
-
aplicar_remesh_red(G, historial_glifos_por_nodo, paso)
|
|
351
|
-
for n in G.nodes:
|
|
352
|
-
historial_glifos_por_nodo.setdefault(n, []).append((paso, "REMESH"))
|
|
353
|
-
historia_glifos.append(f"{paso},{n},REMESH")
|
|
354
|
-
|
|
355
|
-
def limpiar_glifo(glifo_raw):
|
|
356
|
-
"""
|
|
357
|
-
Limpia glifos que pueden tener comillas adicionales o formato incorrecto
|
|
358
|
-
"""
|
|
359
|
-
if not isinstance(glifo_raw, str):
|
|
360
|
-
return str(glifo_raw)
|
|
361
|
-
|
|
362
|
-
# Remover comillas simples y dobles del inicio y final
|
|
363
|
-
glifo_limpio = glifo_raw.strip().strip("'").strip('"')
|
|
364
|
-
|
|
365
|
-
# Casos específicos problemáticos
|
|
366
|
-
correcciones = {
|
|
367
|
-
"RE'MESH": "REMESH",
|
|
368
|
-
"T'HOL": "THOL",
|
|
369
|
-
"Z'HIR": "ZHIR",
|
|
370
|
-
"A'L": "AL",
|
|
371
|
-
"E'N": "EN",
|
|
372
|
-
"I'L": "IL",
|
|
373
|
-
"O'Z": "OZ",
|
|
374
|
-
"U'M": "UM",
|
|
375
|
-
"R'A": "RA",
|
|
376
|
-
"SH'A": "SHA",
|
|
377
|
-
"VA'L": "VAL",
|
|
378
|
-
"NU'L": "NUL",
|
|
379
|
-
"NA'V": "NAV"
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
# Buscar coincidencia exacta o parcial
|
|
383
|
-
for glifo_correcto in correcciones.values():
|
|
384
|
-
if glifo_correcto in glifo_limpio or glifo_limpio in glifo_correcto:
|
|
385
|
-
return glifo_correcto
|
|
386
|
-
|
|
387
|
-
return glifo_limpio
|
|
388
|
-
|
|
389
|
-
def normalizar_historial_glifos(historial_glifos_por_nodo, analizar_dinamica=False, expandido=False):
|
|
390
|
-
glifo_codigo = {
|
|
391
|
-
"AL": 1, "EN": 2, "IL": 3, "OZ": 4, "UM": 5,
|
|
392
|
-
"RA": 6, "SHA": 7, "VAL": 8, "NUL": 9, "THOL": 10,
|
|
393
|
-
"ZHIR": 11, "NAV": 12, "REMESH": 13
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
codigo_glifo = {v: k for k, v in glifo_codigo.items()}
|
|
397
|
-
resumen_dinamico = {}
|
|
398
|
-
historial_expandido = {}
|
|
399
|
-
|
|
400
|
-
for nodo_id, historial in historial_glifos_por_nodo.items():
|
|
401
|
-
nuevo_historial = []
|
|
402
|
-
historial_completo = []
|
|
403
|
-
glifos_validos = []
|
|
404
|
-
|
|
405
|
-
for entrada in historial:
|
|
406
|
-
# Validación de entrada básica
|
|
407
|
-
if not isinstance(entrada, (list, tuple)) or len(entrada) != 2:
|
|
408
|
-
continue
|
|
409
|
-
|
|
410
|
-
elemento_a, elemento_b = entrada
|
|
411
|
-
|
|
412
|
-
# CORRECCIÓN: Lógica simplificada y robusta
|
|
413
|
-
glifo = None
|
|
414
|
-
paso = None
|
|
415
|
-
|
|
416
|
-
# Caso 1: (paso_int, "glifo_string")
|
|
417
|
-
if isinstance(elemento_a, (int, float)) and isinstance(elemento_b, str):
|
|
418
|
-
glifo_limpio = limpiar_glifo(elemento_b)
|
|
419
|
-
if glifo_limpio in glifo_codigo:
|
|
420
|
-
paso = elemento_a
|
|
421
|
-
glifo = glifo_limpio
|
|
422
|
-
|
|
423
|
-
# Caso 2: ("glifo_string", paso_int)
|
|
424
|
-
elif isinstance(elemento_a, str) and isinstance(elemento_b, (int, float)):
|
|
425
|
-
glifo_limpio = limpiar_glifo(elemento_a)
|
|
426
|
-
if glifo_limpio in glifo_codigo:
|
|
427
|
-
glifo = glifo_limpio
|
|
428
|
-
paso = elemento_b
|
|
429
|
-
|
|
430
|
-
# Caso 3: (paso_int, codigo_int)
|
|
431
|
-
elif isinstance(elemento_a, (int, float)) and isinstance(elemento_b, (int, float)):
|
|
432
|
-
if elemento_b in codigo_glifo:
|
|
433
|
-
paso = elemento_a
|
|
434
|
-
glifo = codigo_glifo[elemento_b]
|
|
435
|
-
elif elemento_a in codigo_glifo:
|
|
436
|
-
paso = elemento_b
|
|
437
|
-
glifo = codigo_glifo[elemento_a]
|
|
438
|
-
|
|
439
|
-
# Validación final
|
|
440
|
-
if glifo is None or paso is None:
|
|
441
|
-
continue
|
|
442
|
-
|
|
443
|
-
# Conversión segura de paso a entero
|
|
444
|
-
try:
|
|
445
|
-
paso_int = int(float(paso)) # Doble conversión para manejar floats
|
|
446
|
-
if paso_int < 0:
|
|
447
|
-
continue
|
|
448
|
-
except (ValueError, TypeError) as e:
|
|
449
|
-
continue
|
|
450
|
-
|
|
451
|
-
# Validación del glifo
|
|
452
|
-
glifo_final = limpiar_glifo(glifo)
|
|
453
|
-
if glifo_final not in glifo_codigo:
|
|
454
|
-
continue
|
|
455
|
-
glifo = glifo_final
|
|
456
|
-
|
|
457
|
-
# Agregar entrada válida
|
|
458
|
-
codigo = glifo_codigo[glifo]
|
|
459
|
-
nuevo_historial.append((paso_int, codigo))
|
|
460
|
-
historial_completo.append({
|
|
461
|
-
"paso": paso_int,
|
|
462
|
-
"glifo": glifo,
|
|
463
|
-
"codigo": codigo
|
|
464
|
-
})
|
|
465
|
-
glifos_validos.append(glifo)
|
|
466
|
-
|
|
467
|
-
# Actualizar historial procesado
|
|
468
|
-
historial_glifos_por_nodo[nodo_id] = nuevo_historial
|
|
469
|
-
historial_expandido[nodo_id] = historial_completo
|
|
470
|
-
|
|
471
|
-
# Análisis dinámico si se solicita
|
|
472
|
-
if analizar_dinamica and glifos_validos:
|
|
473
|
-
resumen_dinamico[nodo_id] = evaluar_patron_glifico(glifos_validos)
|
|
474
|
-
|
|
475
|
-
# Retornar según parámetros
|
|
476
|
-
if analizar_dinamica and expandido:
|
|
477
|
-
return resumen_dinamico, historial_expandido
|
|
478
|
-
elif expandido:
|
|
479
|
-
return historial_expandido
|
|
480
|
-
elif analizar_dinamica:
|
|
481
|
-
return resumen_dinamico
|
|
482
|
-
|
|
483
|
-
return historial
|
|
484
|
-
|
|
485
|
-
__all__ = [
|
|
486
|
-
'aplicar_glifo',
|
|
487
|
-
'evaluar_patron_glifico',
|
|
488
|
-
'glifo_por_estructura',
|
|
489
|
-
'transicion_glifica_canonica',
|
|
490
|
-
'acoplar_nodos',
|
|
491
|
-
'detectar_EPIs_compuestas',
|
|
492
|
-
'clasificar_epi',
|
|
493
|
-
'normalizar_historial_glifos',
|
|
494
|
-
'interpretar_sintaxis_glífica',
|
|
495
|
-
'aplicar_remesh_red',
|
|
496
|
-
'aplicar_remesh_si_estabilizacion_global',
|
|
497
|
-
'limpiar_glifo',
|
|
498
|
-
]
|
|
499
|
-
|
|
500
|
-
|