File size: 5,352 Bytes
e26f4cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env python3
"""48_suite_som.py — Suíte SOM v0.5.0: 4D-SOM, T-SOM, GNG, H-SOM.

Demos com estrutura topológica CONHECIDA (critérios de falsificação das
provas r-19):
  - 4D-SOM: 4 aglomerados em 4D — EQ deve cair, TE deve cair (Teos S4-1/S4-2)
  - T-SOM:  deriva linear — EQ temporal estabiliza (Teo T-1, rastreio)
  - GNG:    3 aglomerados — crescimento + componentes conexas (Teo G-1)
  - H-SOM:  decomposição — cota do Teo H-1 respeitada E QE_hier ≤ QE_grosso
Saída: resultados/suite_som_v050.json
"""
import json, os, random, sys, time

def main():
    import khtst_rust.nucleo_rust as nr

    pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    res = {"versao": "0.5.0", "modulo": nr.versao(), "suites": {}}

    # ---------------------------------------------------------------- 4D-SOM
    print("=== 4D-SOM (grade neuronal 4D) ===", flush=True)
    rng = random.Random(7)
    dados = []
    for _ in range(240):
        bloco = rng.randrange(4)
        c = [[-3, -3, -3, -3], [3, -3, 3, -3], [-3, 3, -3, 3], [3, 3, 3, 3]][bloco]
        dados.append([v + rng.gauss(0, 0.4) for v in c])
    t0 = time.time()
    som = nr.treinar_som4d(dados, json.dumps({
        "nx": 4, "ny": 4, "nz": 2, "nt": 2, "epocas": 150,
        "sigma0": 1.2, "sigma1": 0.4, "eta0": 0.6, "eta1": 0.1,
        "espalhada": True,
    }))
    dt = time.time() - t0
    queda_eq = 100.0 * (1 - som["eq_final"] / som["eq_inicial"])
    print(f"  EQ: {som['eq_inicial']:.4f} -> {som['eq_final']:.4f} (-{queda_eq:.1f}%) | TE: {som['te_final']:.4f} | {dt:.1f}s")
    res["suites"]["som4d"] = {
        **{k: som[k] for k in ("eq_inicial", "eq_final", "te_final", "celulas", "grade", "massa_soma")},
        "queda_eq_pct": queda_eq, "tempo_s": dt,
        "gate_eq_cai": som["eq_final"] < som["eq_inicial"],
        "gate_te_baixo": som["te_final"] < 0.3,
        "gate_massa_valida": abs(som["massa_soma"] - 1.0) < 1e-6,
    }

    # ---------------------------------------------------------------- T-SOM
    print("=== T-SOM (Time SOM 4D com esquecimento) ===", flush=True)
    rng = random.Random(11)
    iniciais = [[rng.gauss(0, 0.5) for _ in range(3)] for _ in range(96)]
    tsom = nr.demo_tsom(iniciais, [[rng.gauss(0, 0.5) for _ in range(3)] for _ in range(32)], 25, 0.9)
    hist = tsom["eq_temporal_historico"]
    # com deriva simulada DENTRO da janela (recência pondera mais), o EQ
    # temporal fica limitado — o filtro acompanha (Teo T-1)
    print(f"  EQ temporal: inicio {hist[0]:.4f} | fim {hist[-1]:.4f} | max {max(hist):.4f}")
    res["suites"]["tsom"] = {
        "gamma": tsom["gamma"],
        "eq_temporal_historico": hist,
        "gate_rastreio_limitado": max(hist) < 2.0 and hist[-1] < hist[0] * 1.5 + 0.5,
    }

    # ---------------------------------------------------------------- GNG
    print("=== GNG (Growing Neural Gas) ===", flush=True)
    rng = random.Random(3)
    dados_gng = []
    for c in [[-5, 0, 0, 0], [5, 0, 0, 0], [0, 5, 0, 0]]:
        for _ in range(70):
            dados_gng.append([v + rng.gauss(0, 0.3) for v in c])
    t0 = time.time()
    gng = nr.treinar_gng(dados_gng, json.dumps({"passos": 8000, "max_vertices": 45, "lambda": 60}))
    dt = time.time() - t0
    print(f"  vertices: {gng['vertices']} | arestas: {gng['arestas']} | EQ medio: {gng['eq_medio']:.4f} | {dt:.1f}s")
    res["suites"]["gng"] = {
        **{k: gng[k] for k in ("vertices", "arestas", "componentes_conexas", "insercoes", "eq_medio")},
        "tempo_s": dt,
        "gate_cresceu": gng["vertices"] >= 10,
        "gate_eq_baixo": gng["eq_medio"] < 0.8,
    }

    # ---------------------------------------------------------------- H-SOM
    print("=== H-SOM (hierárquico) ===", flush=True)
    rng = random.Random(21)
    dados_h = []
    for c in [[-2, -2, 0], [2, -2, 0], [-2, 2, 0], [2, 2, 0]]:
        for _ in range(60):
            dados_h.append([v + rng.gauss(0, 0.5) for v in c])
    t0 = time.time()
    hsom = nr.treinar_hsom(dados_h, json.dumps({"celulas_finas": 9, "epocas_finas": 20}))
    dt = time.time() - t0
    print(f"  QE hier: {hsom['eq_hierarquico']:.4f} | QE grosso: {hsom['eq_grosso']:.4f} | R_fino: {hsom['r_fino']:.4f} | {dt:.1f}s")
    res["suites"]["hsom"] = {
        **{k: hsom[k] for k in ("eq_hierarquico", "eq_grosso", "r_fino", "cota_teo_h1", "cota_respeitada")},
        "tempo_s": dt,
        "gate_hier_melhora": hsom["eq_hierarquico"] <= hsom["eq_grosso"] + 1e-9,
    }

    # ---------------------------------------------------------------- resumo
    gates = []
    for nome, s in res["suites"].items():
        gates += [(f"{nome}.{g[5:]}", v) for g, v in s.items() if g.startswith("gate_")]
    ok = sum(1 for _, v in gates if v)
    res["resumo"] = {"gates_totais": len(gates), "gates_ok": ok,
                     "todos_verdes": ok == len(gates)}
    print(f"\n=== RESUMO: {ok}/{len(gates)} gates verdes ===")
    for g, v in gates:
        print(f"  {'OK ' if v else 'FALHOU'} {g}")

    os.makedirs(os.path.join(pasta, "resultados"), exist_ok=True)
    with open(os.path.join(pasta, "resultados", "suite_som_v050.json"), "w") as f:
        json.dump(res, f, indent=1, ensure_ascii=False)
    print("salvo: resultados/suite_som_v050.json")
    if not res["resumo"]["todos_verdes"]:
        sys.exit(1)

if __name__ == "__main__":
    main()