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