tnfr 1.0__py3-none-any.whl → 3.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 +45 -31
- tnfr/constants.py +183 -7
- tnfr/dynamics.py +543 -0
- tnfr/helpers.py +198 -0
- tnfr/main.py +37 -0
- tnfr/observers.py +149 -0
- tnfr/ontosim.py +137 -0
- tnfr/operators.py +296 -0
- tnfr-3.0.0.dist-info/METADATA +35 -0
- tnfr-3.0.0.dist-info/RECORD +13 -0
- tnfr-3.0.0.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-3.0.0.dist-info}/WHEEL +0 -0
- {tnfr-1.0.dist-info → tnfr-3.0.0.dist-info}/licenses/LICENSE.txt +0 -0
core/ontosim.py
DELETED
|
@@ -1,757 +0,0 @@
|
|
|
1
|
-
from typing import List
|
|
2
|
-
import networkx as nx
|
|
3
|
-
|
|
4
|
-
def inicializar_nfr_emergente(forma_base, campo_coherencia=None):
|
|
5
|
-
"""
|
|
6
|
-
Inicializa NFR siguiendo condiciones de emergencia nodal TNFR.
|
|
7
|
-
|
|
8
|
-
Reemplaza las heurísticas ad-hoc por evaluación estructural canónica.
|
|
9
|
-
"""
|
|
10
|
-
# Verificar condiciones de emergencia
|
|
11
|
-
if not cumple_condiciones_emergencia(forma_base, campo_coherencia):
|
|
12
|
-
return None
|
|
13
|
-
|
|
14
|
-
# Calcular parámetros estructurales
|
|
15
|
-
EPI = evaluar_coherencia_estructural(forma_base)
|
|
16
|
-
νf = calcular_frecuencia_resonante(forma_base)
|
|
17
|
-
Wi_t = generar_matriz_coherencia(forma_base)
|
|
18
|
-
fase = sincronizar_con_campo(campo_coherencia, νf)
|
|
19
|
-
|
|
20
|
-
# Calcular parámetros derivados
|
|
21
|
-
# ΔNFR: gradiente nodal basado en estabilidad interna de Wi_t
|
|
22
|
-
estabilidad_interna = np.trace(Wi_t) / len(Wi_t)
|
|
23
|
-
ΔNFR = round((1.0 - estabilidad_interna) * 0.5 - 0.1, 3) # rango típico [-0.1, 0.4]
|
|
24
|
-
|
|
25
|
-
# Si: índice de sentido basado en coherencia estructural y frecuencia
|
|
26
|
-
Si = round((EPI / 2.5) * (νf / 3.0) * (1.0 - fase), 3) # decrece con disonancia
|
|
27
|
-
|
|
28
|
-
# θ: umbral estructural basado en EPI y estabilidad
|
|
29
|
-
θ = round(min(1.0, EPI * estabilidad_interna * 0.4), 3)
|
|
30
|
-
|
|
31
|
-
# Crear NFR canónico
|
|
32
|
-
nfr = {
|
|
33
|
-
"estado": "activo",
|
|
34
|
-
"glifo": "ninguno",
|
|
35
|
-
"categoria": "ninguna",
|
|
36
|
-
"EPI": EPI,
|
|
37
|
-
"EPI_prev": EPI,
|
|
38
|
-
"EPI_prev2": EPI,
|
|
39
|
-
"EPI_prev3": EPI,
|
|
40
|
-
"νf": νf,
|
|
41
|
-
"ΔNFR": ΔNFR,
|
|
42
|
-
"Si": Si,
|
|
43
|
-
"θ": θ,
|
|
44
|
-
"Wi_t": Wi_t,
|
|
45
|
-
"fase": fase,
|
|
46
|
-
"simetria_interna": round(estabilidad_interna, 3)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return nfr
|
|
50
|
-
|
|
51
|
-
def crear_red_desde_datos(datos: List[dict]) -> nx.Graph:
|
|
52
|
-
"""Crea red TNFR desde datos estructurados - NUEVA FUNCIÓN"""
|
|
53
|
-
G = nx.Graph()
|
|
54
|
-
campo_coherencia = {}
|
|
55
|
-
|
|
56
|
-
for nodo_data in datos:
|
|
57
|
-
nodo_id = nodo_data.get('id', f"nodo_{len(G)}")
|
|
58
|
-
|
|
59
|
-
# Usar inicialización canónica existente
|
|
60
|
-
if 'forma_base' in nodo_data:
|
|
61
|
-
nfr = inicializar_nfr_emergente(nodo_data['forma_base'], campo_coherencia)
|
|
62
|
-
if nfr:
|
|
63
|
-
G.add_node(nodo_id, **nfr)
|
|
64
|
-
campo_coherencia[nodo_id] = nfr
|
|
65
|
-
else:
|
|
66
|
-
# Datos ya procesados
|
|
67
|
-
G.add_node(nodo_id, **nodo_data)
|
|
68
|
-
|
|
69
|
-
# Usar conectividad canónica existente
|
|
70
|
-
umbrales, _ = gestionar_conexiones_canonico(G, 0, [])
|
|
71
|
-
return G
|
|
72
|
-
|
|
73
|
-
def _deben_conectarse_canonico(n1: dict, n2: dict) -> bool:
|
|
74
|
-
"""Mejora la lógica existente con umbral áureo"""
|
|
75
|
-
phi = (1 + math.sqrt(5)) / 2 # φ ≈ 1.618
|
|
76
|
-
|
|
77
|
-
diferencia_vf = abs(n1.get('νf', 1) - n2.get('νf', 1))
|
|
78
|
-
diferencia_fase = abs(n1.get('fase', 0) - n2.get('fase', 0)) % (2 * math.pi)
|
|
79
|
-
|
|
80
|
-
return (diferencia_vf < 0.01 * phi and
|
|
81
|
-
diferencia_fase < math.pi / 2)
|
|
82
|
-
|
|
83
|
-
def simular_emergencia(G, pasos=250):
|
|
84
|
-
|
|
85
|
-
umbrales = {
|
|
86
|
-
'θ_min': 0.18,
|
|
87
|
-
'EPI_max_dinamico': 3.0,
|
|
88
|
-
'θ_mutacion': 0.25,
|
|
89
|
-
'θ_colapso': 0.45,
|
|
90
|
-
'bifurcacion_aceleracion': 0.15,
|
|
91
|
-
'EPI_min_coherencia': 0.4, # ← Añade este valor por defecto
|
|
92
|
-
'θ_conexion': 0.12,
|
|
93
|
-
'EPI_conexion': 1.8,
|
|
94
|
-
'νf_conexion': 0.2,
|
|
95
|
-
'Si_conexion': 0.25,
|
|
96
|
-
'θ_autoorganizacion': 0.35,
|
|
97
|
-
'bifurcacion_gradiente': 0.8,
|
|
98
|
-
'sensibilidad_calculada': 1.0,
|
|
99
|
-
'factor_densidad': 1.0,
|
|
100
|
-
'fase': 'emergencia'
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
global historia_Ct
|
|
105
|
-
if 'historia_Ct' not in globals():
|
|
106
|
-
historia_Ct = []
|
|
107
|
-
historia_epi = []
|
|
108
|
-
historia_glifos = ["paso,nodo,glifo"]
|
|
109
|
-
historial_glifos_por_nodo = {}
|
|
110
|
-
G_historia = []
|
|
111
|
-
registro_conexiones = []
|
|
112
|
-
coordinador_temporal = inicializar_coordinador_temporal_canonico()
|
|
113
|
-
bifurcation_manager = BifurcationManagerTNFR()
|
|
114
|
-
|
|
115
|
-
historial_temporal = []
|
|
116
|
-
|
|
117
|
-
glifo_categoria = {
|
|
118
|
-
"AL": "activador", "EN": "receptor", "IL": "estabilizador",
|
|
119
|
-
"OZ": "disonante", "UM": "acoplador", "RA": "resonador",
|
|
120
|
-
"SHA": "latente", "VAL": "expansivo", "NUL": "contractivo",
|
|
121
|
-
"THOL": "autoorganizador", "ZHIR": "mutante", "NAV": "transicional",
|
|
122
|
-
"REMESH": "recursivo"
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
total_pasos = 250
|
|
126
|
-
|
|
127
|
-
# Activación mínima inicial si todos están inactivos o silenciosos
|
|
128
|
-
if all(G.nodes[n]["estado"] in ["latente", "silencio"] for n in G.nodes):
|
|
129
|
-
for n in G.nodes:
|
|
130
|
-
if G.nodes[n]["EPI"] > 0.8 and G.nodes[n]["νf"] > 0.5:
|
|
131
|
-
G.nodes[n]["estado"] = "activo"
|
|
132
|
-
G.nodes[n]["glifo"] = "AL"
|
|
133
|
-
break # activa solo uno, para iniciar pulso
|
|
134
|
-
|
|
135
|
-
for paso in range(total_pasos):
|
|
136
|
-
nodos_activos = [n for n in G.nodes if G.nodes[n]["estado"] == "activo"]
|
|
137
|
-
paso_data = []
|
|
138
|
-
|
|
139
|
-
acoplar_nodos(G)
|
|
140
|
-
|
|
141
|
-
# Cálculo de umbrales adaptativos para emergencia nodal
|
|
142
|
-
vf_values = [G.nodes[n]["νf"] for n in G.nodes if G.nodes[n]["estado"] == "activo"]
|
|
143
|
-
dNFR_values = [G.nodes[n]["ΔNFR"] for n in G.nodes if G.nodes[n]["estado"] == "activo"]
|
|
144
|
-
|
|
145
|
-
media_vf = np.mean(vf_values) if vf_values else 0
|
|
146
|
-
std_dNFR = np.std(dNFR_values) if dNFR_values else 0
|
|
147
|
-
|
|
148
|
-
for n in list(G.nodes):
|
|
149
|
-
|
|
150
|
-
nodo = G.nodes[n]
|
|
151
|
-
def valor_valido(x):
|
|
152
|
-
return x is not None and not isinstance(x, str) and not isnan(x)
|
|
153
|
-
|
|
154
|
-
for n in list(G.nodes):
|
|
155
|
-
nodo = G.nodes[n]
|
|
156
|
-
|
|
157
|
-
for clave in ["EPI_prev", "EPI_prev2", "EPI_prev3"]:
|
|
158
|
-
if not valor_valido(nodo.get(clave)):
|
|
159
|
-
nodo[clave] = nodo.get("EPI", 1.0)
|
|
160
|
-
|
|
161
|
-
if nodo["estado"] == "activo":
|
|
162
|
-
# Dinámica basal influida por νf y sentido
|
|
163
|
-
factor_ruido = random.uniform(0.98, 1.02) + 0.02 * random.uniform(-1, 1) * (1 - nodo["Si"])
|
|
164
|
-
modulador = factor_ruido * (1 + 0.02 * min(nodo.get("νf", 1.0), 5)) # cap νf por seguridad
|
|
165
|
-
|
|
166
|
-
nodo["EPI"] *= modulador
|
|
167
|
-
|
|
168
|
-
# Evitar NaN o valores extremos
|
|
169
|
-
if not np.isfinite(nodo["EPI"]) or nodo["EPI"] > 10:
|
|
170
|
-
nodo["EPI"] = 1.0 + random.uniform(-0.05, 0.05) # reset suave)
|
|
171
|
-
if nodo["EPI"] > 1e4:
|
|
172
|
-
nodo["EPI"] = 1e4
|
|
173
|
-
nodo["ΔNFR"] += random.uniform(-0.08, 0.08) * (1.1 - nodo["Si"])
|
|
174
|
-
nodo["ΔNFR"] = max(min(nodo["ΔNFR"], 1.5), -1.5)
|
|
175
|
-
|
|
176
|
-
# Condición de apagado nodal si pierde coherencia estructural
|
|
177
|
-
if (
|
|
178
|
-
nodo["EPI"] < 0.85
|
|
179
|
-
and abs(nodo["ΔNFR"]) > 0.4
|
|
180
|
-
and nodo["Si"] < 0.3
|
|
181
|
-
):
|
|
182
|
-
nodo["estado"] = "inactivo"
|
|
183
|
-
|
|
184
|
-
evaluar_si_nodal(nodo, paso)
|
|
185
|
-
|
|
186
|
-
if (
|
|
187
|
-
nodo["estado"] == "silencio"
|
|
188
|
-
and abs(nodo["ΔNFR"] - nodo["νf"]) < 0.05
|
|
189
|
-
and nodo.get("Si", 0) > 0.25
|
|
190
|
-
and nodo.get("d2EPI_dt2", 0) > 0.03
|
|
191
|
-
and not reciente_glifo(n, "NAV", historial_glifos_por_nodo, pasos=6)
|
|
192
|
-
):
|
|
193
|
-
aplicar_glifo(G, nodo, n, "NAV", historial_glifos_por_nodo, paso)
|
|
194
|
-
historia_glifos.append(f"{paso},{n},NAV")
|
|
195
|
-
nodo["estado"] = "activo"
|
|
196
|
-
|
|
197
|
-
if (
|
|
198
|
-
nodo["EPI"] < 0.6
|
|
199
|
-
and abs(nodo["ΔNFR"]) > 0.75
|
|
200
|
-
and nodo["Si"] < 0.25
|
|
201
|
-
and not reciente_glifo(n, "SHA", historial_glifos_por_nodo, pasos=6)
|
|
202
|
-
):
|
|
203
|
-
aplicar_glifo(G, nodo, n, "SHA", historial_glifos_por_nodo, paso)
|
|
204
|
-
historia_glifos.append(f"{paso},{n},SHA")
|
|
205
|
-
continue
|
|
206
|
-
|
|
207
|
-
if (
|
|
208
|
-
nodo["estado"] == "latente"
|
|
209
|
-
and abs(nodo["ΔNFR"]) < 0.05
|
|
210
|
-
and nodo["Si"] > 0.3
|
|
211
|
-
and not reciente_glifo(n, "EN", historial_glifos_por_nodo, pasos=10)
|
|
212
|
-
):
|
|
213
|
-
aplicar_glifo(G, nodo, n, "EN", historial_glifos_por_nodo, paso)
|
|
214
|
-
historia_glifos.append(f"{paso},{n},EN")
|
|
215
|
-
|
|
216
|
-
if (
|
|
217
|
-
nodo["glifo"] == "IL"
|
|
218
|
-
and nodo["Si"] > 0.55
|
|
219
|
-
and nodo["νf"] > 1.25
|
|
220
|
-
and abs(nodo["ΔNFR"]) < 0.15 # Baja necesidad de reorganización
|
|
221
|
-
and not reciente_glifo(n, "RA", historial_glifos_por_nodo, pasos=8)
|
|
222
|
-
):
|
|
223
|
-
aplicar_glifo(G, nodo, n, "RA", historial_glifos_por_nodo, paso)
|
|
224
|
-
historia_glifos.append(f"{paso},{n},RA")
|
|
225
|
-
|
|
226
|
-
vecinos = list(G.neighbors(n))
|
|
227
|
-
if (
|
|
228
|
-
nodo["estado"] == "activo"
|
|
229
|
-
and vecinos
|
|
230
|
-
and sum(1 for v in vecinos if abs(G.nodes[v]["θ"] - nodo["θ"]) < 0.08) >= 2
|
|
231
|
-
and not reciente_glifo(n, "UM", historial_glifos_por_nodo, pasos=8)
|
|
232
|
-
):
|
|
233
|
-
aplicar_glifo(G, nodo, n, "UM", historial_glifos_por_nodo, paso)
|
|
234
|
-
historia_glifos.append(f"{paso},{n},UM")
|
|
235
|
-
|
|
236
|
-
if (
|
|
237
|
-
abs(nodo.get("d2EPI_dt2", 0)) > 0.25
|
|
238
|
-
and nodo["Si"] > 0.6
|
|
239
|
-
and not reciente_glifo(n, "ZHIR", historial_glifos_por_nodo, pasos=10)
|
|
240
|
-
):
|
|
241
|
-
aplicar_glifo(G, nodo, n, "ZHIR", historial_glifos_por_nodo, paso)
|
|
242
|
-
historia_glifos.append(f"{paso},{n},ZHIR")
|
|
243
|
-
|
|
244
|
-
if emergencia_nodal(nodo, media_vf, std_dNFR):
|
|
245
|
-
glifo = glifo_por_estructura(nodo, G)
|
|
246
|
-
if glifo:
|
|
247
|
-
aplicar_glifo(G, nodo, n, glifo, historial_glifos_por_nodo, paso)
|
|
248
|
-
historia_glifos.append(f"{paso},{n},{glifo}")
|
|
249
|
-
nodo["categoria"] = glifo_categoria.get(glifo, "ninguna")
|
|
250
|
-
|
|
251
|
-
# Evaluación glífica con umbrales dinámicos (mejora canónica)
|
|
252
|
-
vecinos_data = [G.nodes[v] for v in G.neighbors(n)]
|
|
253
|
-
glifo_dinamico = evaluar_activacion_glifica_dinamica(nodo, umbrales, vecinos_data)
|
|
254
|
-
|
|
255
|
-
if glifo_dinamico and not reciente_glifo(n, glifo_dinamico, historial_glifos_por_nodo, pasos=8):
|
|
256
|
-
aplicar_glifo(G, nodo, n, glifo_dinamico, historial_glifos_por_nodo, paso)
|
|
257
|
-
historia_glifos.append(f"{paso},{n},{glifo_dinamico}")
|
|
258
|
-
|
|
259
|
-
glifo_siguiente = transicion_glifica_canonica(nodo)
|
|
260
|
-
if glifo_siguiente:
|
|
261
|
-
aplicar_glifo(G, nodo, n, glifo_siguiente, historial_glifos_por_nodo, paso)
|
|
262
|
-
historia_glifos.append(f"{paso},{n},{glifo_siguiente}")
|
|
263
|
-
nodo["glifo"] = glifo_siguiente
|
|
264
|
-
nodo["categoria"] = glifo_categoria.get(glifo_siguiente, "ninguna")
|
|
265
|
-
|
|
266
|
-
# Activación estructural de VAL (expansión controlada)
|
|
267
|
-
if (
|
|
268
|
-
nodo["Si"] > 0.8
|
|
269
|
-
and nodo["EPI"] > 1.2
|
|
270
|
-
and abs(nodo["ΔNFR"]) < 0.2
|
|
271
|
-
and nodo.get("dEPI_dt", 0) > 0.15
|
|
272
|
-
and not reciente_glifo(n, "VAL", historial_glifos_por_nodo, pasos=10)
|
|
273
|
-
):
|
|
274
|
-
if "expansiones_val" not in nodo:
|
|
275
|
-
nodo["expansiones_val"] = 0
|
|
276
|
-
|
|
277
|
-
if nodo["expansiones_val"] < 3:
|
|
278
|
-
activar_val_si_estabilidad(n, G, paso, historial_glifos_por_nodo)
|
|
279
|
-
nodo["expansiones_val"] += 1
|
|
280
|
-
else:
|
|
281
|
-
aplicar_glifo(G, nodo, n, "THOL", historial_glifos_por_nodo, paso)
|
|
282
|
-
historia_glifos.append(f"{paso},{n},THOL")
|
|
283
|
-
|
|
284
|
-
if nodo.get("glifo") == "VAL":
|
|
285
|
-
condiciones_contraccion = (
|
|
286
|
-
abs(nodo.get("d2EPI_dt2", 0)) < 0.05 and
|
|
287
|
-
abs(nodo.get("ΔNFR", 0)) < 0.1 and
|
|
288
|
-
nodo.get("νf", 1.0) < 1.0 and
|
|
289
|
-
abs(nodo.get("EPI", 0) - nodo.get("EPI_prev", 0)) < 0.01
|
|
290
|
-
)
|
|
291
|
-
|
|
292
|
-
if condiciones_contraccion:
|
|
293
|
-
aplicar_glifo(G, nodo, n, "NUL", historial_glifos_por_nodo, paso)
|
|
294
|
-
historia_glifos.append(f"{paso},{n},NUL")
|
|
295
|
-
nodo["glifo"] = "NUL"
|
|
296
|
-
nodo["categoria"] = glifo_categoria.get("NUL", "ninguna")
|
|
297
|
-
|
|
298
|
-
paso_data.append({
|
|
299
|
-
"nodo": n,
|
|
300
|
-
"paso": paso,
|
|
301
|
-
"EPI": round(nodo["EPI"], 2)
|
|
302
|
-
})
|
|
303
|
-
nodo["EPI_prev3"] = nodo.get("EPI_prev2", nodo["EPI_prev"])
|
|
304
|
-
nodo["EPI_prev2"] = nodo.get("EPI_prev", nodo["EPI"])
|
|
305
|
-
nodo["EPI_prev"] = nodo["EPI"] if np.isfinite(nodo["EPI"]) else 1.0
|
|
306
|
-
|
|
307
|
-
# Cálculo de ∂EPI/∂t = νf · ΔNFR
|
|
308
|
-
dEPI_dt = nodo["νf"] * nodo["ΔNFR"]
|
|
309
|
-
nodo["dEPI_dt"] = dEPI_dt
|
|
310
|
-
if "historial_dEPI_dt" not in nodo:
|
|
311
|
-
nodo["historial_dEPI_dt"] = []
|
|
312
|
-
nodo["historial_dEPI_dt"].append((paso, dEPI_dt))
|
|
313
|
-
|
|
314
|
-
# Registrar evolución de νf y ΔNFR
|
|
315
|
-
if "historial_vf" not in nodo:
|
|
316
|
-
nodo["historial_vf"] = []
|
|
317
|
-
if "historial_dNFR" not in nodo:
|
|
318
|
-
nodo["historial_dNFR"] = []
|
|
319
|
-
|
|
320
|
-
nodo["historial_vf"].append((paso, nodo["νf"]))
|
|
321
|
-
nodo["historial_dNFR"].append((paso, nodo["ΔNFR"]))
|
|
322
|
-
|
|
323
|
-
# Calcular aceleración estructural ∂²EPI/∂t² solo si los valores son válidos
|
|
324
|
-
if all(np.isfinite([nodo.get("EPI", 0), nodo.get("EPI_prev", 0), nodo.get("EPI_prev2", 0)])):
|
|
325
|
-
aceleracion = nodo["EPI"] - 2 * nodo["EPI_prev"] + nodo["EPI_prev2"]
|
|
326
|
-
else:
|
|
327
|
-
aceleracion = 0.0 # O un valor neutro que no active mutaciones erróneas
|
|
328
|
-
|
|
329
|
-
nodo["d2EPI_dt2"] = aceleracion
|
|
330
|
-
|
|
331
|
-
# Umbral de bifurcación: si se supera, aplicar THOL
|
|
332
|
-
resultado_bifurcaciones = integrar_bifurcaciones_canonicas_en_simulacion(
|
|
333
|
-
G, paso, coordinador_temporal, bifurcation_manager
|
|
334
|
-
)
|
|
335
|
-
|
|
336
|
-
# Evaluar contracción si hay disonancia o colapso de sentido (NU´L)
|
|
337
|
-
if nodo.get("estado") == "activo":
|
|
338
|
-
aplicar_contraccion_nul(n, G, paso, historial_glifos_por_nodo)
|
|
339
|
-
|
|
340
|
-
# === CONTROL DE EXPANSIÓN INFINITA ===
|
|
341
|
-
if "expansiones_val" not in nodo:
|
|
342
|
-
nodo["expansiones_val"] = 0
|
|
343
|
-
|
|
344
|
-
if nodo["expansiones_val"] >= 3:
|
|
345
|
-
continue # evita expansión si ya lo hizo demasiadas veces
|
|
346
|
-
|
|
347
|
-
# Aquí sí puede expandirse:
|
|
348
|
-
activar_val_si_estabilidad(n, G, paso, historial_glifos_por_nodo)
|
|
349
|
-
nodo["expansiones_val"] += 1
|
|
350
|
-
|
|
351
|
-
if (
|
|
352
|
-
nodo.get("estado") == "activo"
|
|
353
|
-
and nodo.get("Si", 0) > 0.8
|
|
354
|
-
and nodo.get("EPI", 0) > 1.1
|
|
355
|
-
and abs(nodo.get("ΔNFR", 0)) < 0.25
|
|
356
|
-
and nodo.get("dEPI_dt", 0) > 0.15
|
|
357
|
-
and not reciente_glifo(n, "VAL", historial_glifos_por_nodo, pasos=8)
|
|
358
|
-
):
|
|
359
|
-
activar_val_si_estabilidad(n, G, paso, historial_glifos_por_nodo)
|
|
360
|
-
|
|
361
|
-
# Guardar aceleración para graficar más tarde
|
|
362
|
-
if "historial_aceleracion" not in nodo:
|
|
363
|
-
nodo["historial_aceleracion"] = []
|
|
364
|
-
nodo["historial_aceleracion"].append((paso, aceleracion))
|
|
365
|
-
|
|
366
|
-
# Gestión temporal topológica TNFR
|
|
367
|
-
resultado_temporal = integrar_tiempo_topologico_en_simulacion(G, paso, coordinador_temporal)
|
|
368
|
-
historial_temporal.append(resultado_temporal['estadisticas'])
|
|
369
|
-
|
|
370
|
-
# Gestión de conexiones con información temporal
|
|
371
|
-
umbrales, estadisticas_conexiones = gestionar_conexiones_canonico(G, paso, historia_Ct)
|
|
372
|
-
|
|
373
|
-
# Calcular coherencia total C(t) al final del paso
|
|
374
|
-
C_t = sum(G.nodes[n]["EPI"] for n in G.nodes) / len(G)
|
|
375
|
-
historia_Ct.append((paso, C_t))
|
|
376
|
-
|
|
377
|
-
historia_epi.append(paso_data)
|
|
378
|
-
|
|
379
|
-
G_snapshot = nx.Graph()
|
|
380
|
-
G_snapshot.add_nodes_from([(n, G.nodes[n].copy()) for n in G.nodes])
|
|
381
|
-
G_snapshot.add_edges_from(G.edges)
|
|
382
|
-
G_historia.append(G_snapshot)
|
|
383
|
-
|
|
384
|
-
for nodo_id in list(historial_glifos_por_nodo.keys()):
|
|
385
|
-
glifos = historial_glifos_por_nodo[nodo_id]
|
|
386
|
-
|
|
387
|
-
if (
|
|
388
|
-
len(glifos) >= 3
|
|
389
|
-
and glifos[-1][1] == glifos[-2][1] == glifos[-3][1]
|
|
390
|
-
and abs(G.nodes[nodo_id]["EPI"] - G.nodes[nodo_id]["EPI_prev"]) < 0.05
|
|
391
|
-
):
|
|
392
|
-
aplicar_glifo(G, G.nodes[nodo_id], nodo_id, "REMESH", historial_glifos_por_nodo, paso)
|
|
393
|
-
historia_glifos.append(f"{paso},{nodo_id},REMESH")
|
|
394
|
-
|
|
395
|
-
aplicar_remesh_si_estabilizacion_global(G, historial_glifos_por_nodo, historia_glifos, paso)
|
|
396
|
-
aplicar_remesh_grupal(G, historial_glifos_por_nodo)
|
|
397
|
-
epi_compuestas = detectar_EPIs_compuestas(G, umbrales)
|
|
398
|
-
if algo_se_mueve(G, historial_glifos_por_nodo, paso):
|
|
399
|
-
historial_macronodos, macronodes_info = detectar_macronodos(G, historial_glifos_por_nodo, epi_compuestas, paso)
|
|
400
|
-
|
|
401
|
-
else:
|
|
402
|
-
macronodes_info = {'nodos': [], 'conexiones': []}
|
|
403
|
-
|
|
404
|
-
# Evaluar exceso de VAL y promover reorganización estructural
|
|
405
|
-
for nodo_id, glifos in historial_glifos_por_nodo.items():
|
|
406
|
-
ultimos = [g for _, g in glifos[-6:]] # últimos 6 glifos del nodo
|
|
407
|
-
if ultimos.count("VAL") >= 4 and "THOL" not in ultimos and "ZHIR" not in ultimos:
|
|
408
|
-
nodo = G.nodes[nodo_id]
|
|
409
|
-
|
|
410
|
-
# Se decide el glifo correctivo en función de su Si y ΔNFR
|
|
411
|
-
if nodo["Si"] > 0.5 and abs(nodo["ΔNFR"]) < 0.2:
|
|
412
|
-
aplicar_glifo(G, nodo, nodo_id, "THOL", historial_glifos_por_nodo, paso)
|
|
413
|
-
historia_glifos.append(f"{paso},{nodo_id},THOL")
|
|
414
|
-
else:
|
|
415
|
-
aplicar_glifo(G, nodo, nodo_id, "ZHIR", historial_glifos_por_nodo, paso)
|
|
416
|
-
historia_glifos.append(f"{paso},{nodo_id},ZHIR")
|
|
417
|
-
|
|
418
|
-
porcentaje = int((paso + 1) / total_pasos * 100)
|
|
419
|
-
barra = "█" * (porcentaje // 2) + "-" * (50 - porcentaje // 2)
|
|
420
|
-
nodos_activos = [n for n in G.nodes if G.nodes[n]["estado"] == "activo"]
|
|
421
|
-
|
|
422
|
-
# Limpiar bifurcaciones obsoletas cada 300 pasos
|
|
423
|
-
if paso % 300 == 0:
|
|
424
|
-
obsoletas = limpiar_bifurcaciones_obsoletas(bifurcation_manager, paso)
|
|
425
|
-
|
|
426
|
-
lecturas = interpretar_sintaxis_glífica(historial_glifos_por_nodo)
|
|
427
|
-
|
|
428
|
-
# Diagnóstico simbólico final
|
|
429
|
-
diagnostico = []
|
|
430
|
-
for nodo in G.nodes:
|
|
431
|
-
nombre = nodo
|
|
432
|
-
datos = G.nodes[nodo]
|
|
433
|
-
glifos_nodo = [g[1] for g in historial_glifos_por_nodo.get(nombre, [])]
|
|
434
|
-
mutó = "ZHIR" in glifos_nodo
|
|
435
|
-
en_epi = any(nombre in grupo["nodos"] for grupo in epi_compuestas)
|
|
436
|
-
lectura = lecturas.get(nombre, {}).get("trayectoria", [])
|
|
437
|
-
|
|
438
|
-
diagnostico.append({
|
|
439
|
-
"palabra": nombre,
|
|
440
|
-
"glifos": glifos_nodo,
|
|
441
|
-
"lectura_sintactica": lectura,
|
|
442
|
-
"mutó": mutó,
|
|
443
|
-
"en_epi_compuesta": en_epi,
|
|
444
|
-
"Si": datos.get("Si", 0),
|
|
445
|
-
"estado": datos.get("estado", "latente"),
|
|
446
|
-
"categoría": datos.get("categoria", "sin categoría")
|
|
447
|
-
})
|
|
448
|
-
|
|
449
|
-
nodos_pulsantes = detectar_nodos_pulsantes(historial_glifos_por_nodo)
|
|
450
|
-
|
|
451
|
-
for nodo_id in nodos_pulsantes:
|
|
452
|
-
nodo = G.nodes[nodo_id]
|
|
453
|
-
historial = historial_glifos_por_nodo.get(nodo_id, [])
|
|
454
|
-
ultimos = [g for _, g in historial][-6:]
|
|
455
|
-
|
|
456
|
-
if nodo["glifo"] in ["THOL", "ZHIR", "REMESH"]:
|
|
457
|
-
continue # ya está mutado o recursivo
|
|
458
|
-
|
|
459
|
-
nodo = G.nodes[nodo_id]
|
|
460
|
-
|
|
461
|
-
# Evaluar emergente canónico
|
|
462
|
-
if abs(nodo["EPI"] - nodo["EPI_prev"]) < 0.01 and abs(nodo["ΔNFR"]) < 0.05:
|
|
463
|
-
glifo = "REMESH"
|
|
464
|
-
elif abs(nodo.get("θ", 0) - nodo.get("θ_prev", 0)) > 0.2:
|
|
465
|
-
glifo = "ZHIR"
|
|
466
|
-
elif nodo.get("Si", 0) > 0.8 and nodo.get("glifo") == "UM":
|
|
467
|
-
glifo = "RA"
|
|
468
|
-
else:
|
|
469
|
-
glifo = "THOL"
|
|
470
|
-
|
|
471
|
-
if nodo_id in G:
|
|
472
|
-
promover_emergente(nodo_id, G, paso, historial_glifos_por_nodo, historia_glifos)
|
|
473
|
-
|
|
474
|
-
bifurcation_stats = bifurcation_manager.obtener_estadisticas_bifurcacion()
|
|
475
|
-
return historia_epi, G, epi_compuestas, lecturas, G_historia, historial_glifos_por_nodo, historial_temporal, bifurcation_stats
|
|
476
|
-
|
|
477
|
-
def aplicar_contraccion_nul(nodo_id, G, paso, historial_glifos_por_nodo):
|
|
478
|
-
nodo = G.nodes[nodo_id]
|
|
479
|
-
|
|
480
|
-
condiciones = (
|
|
481
|
-
nodo.get("Si", 1.0) < 0.3 and
|
|
482
|
-
abs(nodo.get("ΔNFR", 0.0)) > 0.8 and
|
|
483
|
-
nodo.get("estado") == "activo" and
|
|
484
|
-
nodo.get("d2EPI_dt2", 0) < -0.05
|
|
485
|
-
)
|
|
486
|
-
|
|
487
|
-
if not condiciones:
|
|
488
|
-
return False
|
|
489
|
-
|
|
490
|
-
# Aplicar contracción resonante
|
|
491
|
-
nodo["EPI"] = round(nodo["EPI"] * 0.7, 3)
|
|
492
|
-
nodo["estado"] = "latente"
|
|
493
|
-
nodo["glifo"] = "NUL"
|
|
494
|
-
nodo["categoria"] = "contractivo"
|
|
495
|
-
|
|
496
|
-
historial_glifos_por_nodo.setdefault(nodo_id, []).append((paso, "NUL"))
|
|
497
|
-
|
|
498
|
-
return True
|
|
499
|
-
|
|
500
|
-
def activar_val_si_estabilidad(nodo_id, G, paso, historial_glifos_por_nodo):
|
|
501
|
-
nodo = G.nodes[nodo_id]
|
|
502
|
-
|
|
503
|
-
# Restricción por sobreexpansión
|
|
504
|
-
if nodo.get("expansiones_val", 0) >= 3:
|
|
505
|
-
return None
|
|
506
|
-
|
|
507
|
-
condiciones = (
|
|
508
|
-
nodo.get("Si", 0) > 0.85 and
|
|
509
|
-
abs(nodo.get("ΔNFR", 0)) < 0.2 and
|
|
510
|
-
nodo.get("dEPI_dt", 0) > 0.18 and
|
|
511
|
-
nodo.get("d2EPI_dt2", 0) > 0.2 and
|
|
512
|
-
nodo.get("estado") == "activo"
|
|
513
|
-
)
|
|
514
|
-
|
|
515
|
-
if not condiciones:
|
|
516
|
-
return None
|
|
517
|
-
|
|
518
|
-
nuevo_id = f"{nodo_id}_VAL_{random.randint(1000, 9999)}"
|
|
519
|
-
if nuevo_id in G:
|
|
520
|
-
return None
|
|
521
|
-
|
|
522
|
-
nuevo_nodo = {
|
|
523
|
-
"EPI": round(nodo["EPI"] * random.uniform(1.0, 1.1), 3),
|
|
524
|
-
"EPI_prev": nodo["EPI"],
|
|
525
|
-
"EPI_prev2": nodo.get("EPI_prev", nodo["EPI"]),
|
|
526
|
-
"EPI_prev3": nodo.get("EPI_prev2", nodo["EPI"]),
|
|
527
|
-
"glifo": "VAL",
|
|
528
|
-
"categoria": "expansivo",
|
|
529
|
-
"estado": "activo",
|
|
530
|
-
"νf": round(nodo["νf"] * random.uniform(1.0, 1.05), 3),
|
|
531
|
-
"ΔNFR": round(nodo["ΔNFR"] * 0.9, 3),
|
|
532
|
-
"θ": round(nodo["θ"] + random.uniform(-0.01, 0.01), 3),
|
|
533
|
-
"Si": nodo["Si"] * 0.98,
|
|
534
|
-
"historial_glifos": [(paso, "VAL")],
|
|
535
|
-
"historial_vf": [(paso, nodo["νf"])],
|
|
536
|
-
"historial_dNFR": [(paso, nodo["ΔNFR"])],
|
|
537
|
-
"historial_dEPI_dt": [(paso, nodo.get("dEPI_dt", 0))],
|
|
538
|
-
"historial_Si": [(paso, nodo["Si"])]
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
G.add_node(nuevo_id, **nuevo_nodo)
|
|
542
|
-
G.add_edge(nodo_id, nuevo_id)
|
|
543
|
-
|
|
544
|
-
historial_glifos_por_nodo.setdefault(nodo_id, []).append((paso, "VAL"))
|
|
545
|
-
historial_glifos_por_nodo[nuevo_id] = [(paso, "VAL")]
|
|
546
|
-
|
|
547
|
-
nodo["expansiones_val"] = nodo.get("expansiones_val", 0) + 1
|
|
548
|
-
|
|
549
|
-
return nuevo_id
|
|
550
|
-
|
|
551
|
-
def aplicar_remesh_grupal(G, historial_glifos_por_nodo):
|
|
552
|
-
nodos_aplicados = set()
|
|
553
|
-
|
|
554
|
-
for nodo_id in G.nodes:
|
|
555
|
-
if nodo_id in nodos_aplicados:
|
|
556
|
-
continue
|
|
557
|
-
|
|
558
|
-
historial = historial_glifos_por_nodo.get(nodo_id, [])
|
|
559
|
-
if len(historial) < 3:
|
|
560
|
-
continue
|
|
561
|
-
|
|
562
|
-
ultimos_glifos = [g for _, g in historial[-3:]]
|
|
563
|
-
if len(set(ultimos_glifos)) != 1:
|
|
564
|
-
continue
|
|
565
|
-
|
|
566
|
-
glifo_recurrente = ultimos_glifos[0]
|
|
567
|
-
|
|
568
|
-
vecinos = list(G.neighbors(nodo_id))
|
|
569
|
-
grupo = [nodo_id]
|
|
570
|
-
|
|
571
|
-
for v_id in vecinos:
|
|
572
|
-
v_nodo = G.nodes[v_id]
|
|
573
|
-
v_hist = historial_glifos_por_nodo.get(v_id, [])
|
|
574
|
-
if len(v_hist) >= 3:
|
|
575
|
-
if [g for _, g in v_hist[-3:]] == ultimos_glifos:
|
|
576
|
-
if abs(v_nodo.get("θ", 0) - G.nodes[nodo_id].get("θ", 0)) < 0.1:
|
|
577
|
-
if abs(v_nodo.get("EPI", 0) - v_nodo.get("EPI_prev", v_nodo.get("EPI", 0))) < 0.01:
|
|
578
|
-
if v_nodo.get("ΔNFR", 1.0) < 0.2:
|
|
579
|
-
grupo.append(v_id)
|
|
580
|
-
|
|
581
|
-
if len(grupo) >= 3:
|
|
582
|
-
for g_id in grupo:
|
|
583
|
-
g_nodo = G.nodes[g_id]
|
|
584
|
-
g_nodo["EPI_prev"] = g_nodo.get("EPI_prev", g_nodo["EPI"])
|
|
585
|
-
g_nodo["EPI_prev2"] = g_nodo.get("EPI_prev2", g_nodo["EPI"])
|
|
586
|
-
g_nodo["EPI"] = (g_nodo["EPI_prev"] + g_nodo["EPI_prev2"]) / 2
|
|
587
|
-
g_nodo["Si"] *= 0.98
|
|
588
|
-
g_nodo["νf"] *= 0.98
|
|
589
|
-
g_nodo["ΔNFR"] *= 0.95
|
|
590
|
-
g_nodo["glifo"] = "REMESH"
|
|
591
|
-
ultimo_paso = historial_glifos_por_nodo[g_id][-1][0] if historial_glifos_por_nodo[g_id] else 0
|
|
592
|
-
historial_glifos_por_nodo[g_id].append((ultimo_paso + 1, "REMESH"))
|
|
593
|
-
nodos_aplicados.add(g_id)
|
|
594
|
-
|
|
595
|
-
def cumple_condiciones_emergencia(forma_base, campo_coherencia):
|
|
596
|
-
"""
|
|
597
|
-
Evalúa si una forma puede generar un NFR según criterios TNFR.
|
|
598
|
-
|
|
599
|
-
Condiciones de emergencia nodal:
|
|
600
|
-
1. Frecuencia estructural mínima νf > 0.3
|
|
601
|
-
2. Coherencia interna suficiente (estructura no degenerada)
|
|
602
|
-
3. Acoplamiento posible con campo de coherencia
|
|
603
|
-
"""
|
|
604
|
-
if not forma_base or len(forma_base) < 2:
|
|
605
|
-
return False
|
|
606
|
-
|
|
607
|
-
# Evaluar diversidad estructural interna
|
|
608
|
-
diversidad = len(set(forma_base)) / len(forma_base)
|
|
609
|
-
if diversidad < 0.3: # demasiado repetitivo
|
|
610
|
-
return False
|
|
611
|
-
|
|
612
|
-
# Evaluar potencial de frecuencia resonante
|
|
613
|
-
freq_potencial = calcular_frecuencia_resonante(forma_base)
|
|
614
|
-
if freq_potencial < 0.3: # frecuencia insuficiente para emergencia
|
|
615
|
-
return False
|
|
616
|
-
|
|
617
|
-
# Evaluar compatibilidad con campo de coherencia
|
|
618
|
-
if campo_coherencia and len(campo_coherencia) > 0:
|
|
619
|
-
coherencia_promedio = np.mean([nodo.get("EPI", 1.0) for nodo in campo_coherencia.values()])
|
|
620
|
-
if coherencia_promedio > 0 and freq_potencial > coherencia_promedio * 2.5:
|
|
621
|
-
return False # demasiado energético para el campo actual
|
|
622
|
-
|
|
623
|
-
return True
|
|
624
|
-
|
|
625
|
-
def evaluar_coherencia_estructural(forma_base):
|
|
626
|
-
"""
|
|
627
|
-
Calcula EPI basado en estructura interna real según TNFR.
|
|
628
|
-
|
|
629
|
-
Evalúa:
|
|
630
|
-
- Simetría funcional de la forma
|
|
631
|
-
- Estabilidad topológica interna
|
|
632
|
-
- Resistencia a mutaciones
|
|
633
|
-
"""
|
|
634
|
-
if not forma_base:
|
|
635
|
-
return 1.0
|
|
636
|
-
|
|
637
|
-
# Análisis de simetría funcional
|
|
638
|
-
forma_norm = forma_base.lower()
|
|
639
|
-
longitud = len(forma_norm)
|
|
640
|
-
|
|
641
|
-
# Factor de simetría: evalúa patrones internos
|
|
642
|
-
def calcular_simetria(s):
|
|
643
|
-
centro = len(s) // 2
|
|
644
|
-
if len(s) % 2 == 0:
|
|
645
|
-
izq, der = s[:centro], s[centro:][::-1]
|
|
646
|
-
else:
|
|
647
|
-
izq, der = s[:centro], s[centro+1:][::-1]
|
|
648
|
-
|
|
649
|
-
coincidencias = sum(1 for a, b in zip(izq, der) if a == b)
|
|
650
|
-
return coincidencias / max(len(izq), 1)
|
|
651
|
-
|
|
652
|
-
simetria = calcular_simetria(forma_norm)
|
|
653
|
-
|
|
654
|
-
# Factor de diversidad estructural
|
|
655
|
-
diversidad = len(set(forma_norm)) / longitud
|
|
656
|
-
|
|
657
|
-
# Factor de estabilidad (resistencia a mutaciones puntuales)
|
|
658
|
-
# Basado en la distribución de caracteres
|
|
659
|
-
contador = Counter(forma_norm)
|
|
660
|
-
entropia = -sum((freq/longitud) * np.log2(freq/longitud) for freq in contador.values())
|
|
661
|
-
estabilidad = min(1.0, entropia / 3.0) # normalizada
|
|
662
|
-
|
|
663
|
-
# Factor de coherencia por patrones vocálicos/consonánticos
|
|
664
|
-
vocales = "aeiouáéíóúü"
|
|
665
|
-
patron_vocal = sum(1 for c in forma_norm if c in vocales) / longitud
|
|
666
|
-
coherencia_fonetica = min(1.0, abs(0.4 - patron_vocal) * 2.5) # óptimo cerca de 40% vocales
|
|
667
|
-
|
|
668
|
-
# Combinar factores según pesos TNFR
|
|
669
|
-
EPI = (
|
|
670
|
-
0.3 * simetria + # simetría estructural
|
|
671
|
-
0.25 * diversidad + # diversidad interna
|
|
672
|
-
0.25 * estabilidad + # resistencia mutacional
|
|
673
|
-
0.2 * coherencia_fonetica # coherencia fónica
|
|
674
|
-
)
|
|
675
|
-
|
|
676
|
-
# Normalizar al rango [0.5, 2.5] típico de EPIs
|
|
677
|
-
EPI_normalizada = 0.5 + EPI * 2.0
|
|
678
|
-
|
|
679
|
-
return round(EPI_normalizada, 3)
|
|
680
|
-
|
|
681
|
-
def generar_matriz_coherencia(forma_base):
|
|
682
|
-
"""
|
|
683
|
-
Crea matriz Wi(t) para evaluar estabilidad topológica interna.
|
|
684
|
-
|
|
685
|
-
Modela subnodos internos como caracteres y sus acoplamientos.
|
|
686
|
-
"""
|
|
687
|
-
if not forma_base or len(forma_base) < 2:
|
|
688
|
-
return np.array([[1.0]])
|
|
689
|
-
|
|
690
|
-
longitud = len(forma_base)
|
|
691
|
-
Wi = np.zeros((longitud, longitud))
|
|
692
|
-
|
|
693
|
-
# Acoplamiento entre caracteres adyacentes (fuerte)
|
|
694
|
-
for i in range(longitud - 1):
|
|
695
|
-
Wi[i][i+1] = Wi[i+1][i] = 0.8
|
|
696
|
-
|
|
697
|
-
# Acoplamiento entre caracteres similares (débil)
|
|
698
|
-
for i in range(longitud):
|
|
699
|
-
for j in range(i+2, longitud):
|
|
700
|
-
if forma_base[i].lower() == forma_base[j].lower():
|
|
701
|
-
Wi[i][j] = Wi[j][i] = 0.3
|
|
702
|
-
|
|
703
|
-
# Autocoherencia (diagonal)
|
|
704
|
-
np.fill_diagonal(Wi, 1.0)
|
|
705
|
-
|
|
706
|
-
# Normalizar filas para que sumen aproximadamente 1
|
|
707
|
-
for i in range(longitud):
|
|
708
|
-
suma_fila = np.sum(Wi[i])
|
|
709
|
-
if suma_fila > 0:
|
|
710
|
-
Wi[i] = Wi[i] / suma_fila
|
|
711
|
-
|
|
712
|
-
return Wi
|
|
713
|
-
|
|
714
|
-
def sincronizar_con_campo(campo_coherencia, νf_nodo):
|
|
715
|
-
"""
|
|
716
|
-
Calcula fase del nodo respecto al campo de coherencia global.
|
|
717
|
-
|
|
718
|
-
La fase determina si el nodo está sincronizado o en disonancia
|
|
719
|
-
con el estado actual de la red.
|
|
720
|
-
"""
|
|
721
|
-
if not campo_coherencia or len(campo_coherencia) == 0:
|
|
722
|
-
return 0.0 # fase neutra si no hay campo
|
|
723
|
-
|
|
724
|
-
# Calcular frecuencia promedio del campo
|
|
725
|
-
frecuencias_campo = [nodo.get("νf", 1.0) for nodo in campo_coherencia.values()]
|
|
726
|
-
freq_promedio_campo = np.mean(frecuencias_campo)
|
|
727
|
-
|
|
728
|
-
# Calcular diferencia de fase basada en frecuencias
|
|
729
|
-
diferencia_freq = abs(νf_nodo - freq_promedio_campo)
|
|
730
|
-
|
|
731
|
-
# Convertir a fase: diferencias pequeñas = sincronización, grandes = disonancia
|
|
732
|
-
if diferencia_freq < 0.1:
|
|
733
|
-
fase = 0.0 # sincronización perfecta
|
|
734
|
-
elif diferencia_freq < 0.3:
|
|
735
|
-
fase = 0.25 # sincronización parcial
|
|
736
|
-
elif diferencia_freq < 0.6:
|
|
737
|
-
fase = 0.5 # neutral
|
|
738
|
-
elif diferencia_freq < 1.0:
|
|
739
|
-
fase = 0.75 # disonancia parcial
|
|
740
|
-
else:
|
|
741
|
-
fase = 1.0 # disonancia completa
|
|
742
|
-
|
|
743
|
-
return round(fase, 3)
|
|
744
|
-
|
|
745
|
-
__all__ = [
|
|
746
|
-
'inicializar_nfr_emergente',
|
|
747
|
-
'_deben_conectarse_canonico',
|
|
748
|
-
'crear_red_desde_datos',
|
|
749
|
-
'simular_emergencia',
|
|
750
|
-
'aplicar_contraccion_nul',
|
|
751
|
-
'activar_val_si_estabilidad',
|
|
752
|
-
'aplicar_remesh_grupal',
|
|
753
|
-
'cumple_condiciones_emergencia',
|
|
754
|
-
'evaluar_coherencia_estructural',
|
|
755
|
-
'generar_matriz_coherencia',
|
|
756
|
-
'sincronizar_con_campo'
|
|
757
|
-
]
|