File size: 6,046 Bytes
bb2363d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/env python3
"""57_moe_redirecionavel.py — v0.6.0: MoEs de codificação/decodificação
REDIRECIONÁVEIS com Mecanismo de Atenção próprio independente (paralelo)
para as variantes JEPA e Kohonen SOM (provas r-25).

Demos (com dados REAIS da Wikipédia PT-BR):
  1. M-R1..M-R5: neutralidade no nascimento, invariância sob
     redirecionamento, paralelismo medido (2 threads), water-filling;
  2. JEPA com MoE — ablação de 3 braços (pequena / densa / moe) em patches
     de texto REAL (a "densa" isola o ganho do roteamento);
  3. SOM 4D refinado por MoE com alocação por QE (water-filling vs
     uniforme) + redirecionamento p/ decodificador;
  4. AcopladorDuplo: protocolo duplex Pensamento↔backbone (AC-1/AC-2).

Saída: resultados/moe_redirecionavel_v060.json
"""
import json, math, os, time

def main():
    import khtst_rust.nucleo_rust as nr

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

    # ---------- dados REAIS: texto da Wikipédia PT-BR → patches ----------
    with open(os.path.join(pasta, "dados", "shard_validacao.jsonl")) as f:
        texto = json.loads(f.readline())["texto"]
    # normaliza para [0,1] por código de caractere (canal único)
    serie = [min(ord(c), 255) / 255.0 for c in texto[:2048] if c.strip()]
    patches = nr.patches_serie(serie, 1, len(serie), 16)  # (n, 16) reais
    print(f"dados reais: {len(patches)} patches de 16 dims "
          f"({len(texto[:2048])} caracteres da Wikipédia PT-BR)", flush=True)
    res["dados_reais"] = {"n_patches": len(patches), "d_patch": 16,
                          "fonte": "wikimedia/wikipedia 20231101.pt (validação)"}

    # -------------------------------------------- 1: M-R1..M-R5
    print("\n=== MoE redirecionável: provas M-R1..M-R5 ===", flush=True)
    t0 = time.time()
    m = nr.demo_moe_redirecionavel(d=16, n=96, semente=42)
    dt = time.time() - t0
    print(f"  M-R2 neutralidade no nascimento: gate={m['valor_gate_no_nascimento']}, dif={m['neutralidade_dif']:.2e}")
    print(f"  M-R1 capacidade: {m['carga_antes']} == {m['carga_depois']} | perda aux {m['perda_aux_antes']:.4f} ~ {m['perda_aux_depois']:.4f}")
    print(f"  M-R3 paralelismo: t_par={m['t_paralelo_s']*1000:.1f}ms < t_seq={m['t_sequencial_s']*1000:.1f}ms (speedup {m['speedup']:.2f}x)")
    print(f"  M-R5 water-filling: cota {m['cota_wf']:.4f} <= uniforme {m['cota_uniforme']:.4f} | alocacao {m['alocacao_water_filling']}")
    res["demos"]["provas_mr"] = {**m, "tempo_s": dt}

    # -------------------------------------------- 2: JEPA com MoE (3 braços)
    print("\n=== JEPA com MoE redirecionável (3 braços, dados reais) ===", flush=True)
    bracos = {}
    for modo in ("pequena", "densa", "moe"):
        t0 = time.time()
        r = nr.jepa_com_moe(patches, modo, passos=90, frac_mascara=0.45, semente=7)
        dt = time.time() - t0
        bracos[modo] = r
        print(f"  {modo:8s}: perda preditiva {r['perda_pred_inicial']:.4f} -> {r['perda_pred_final']:.4f} "
              f"(queda {r['queda_abs']:.4f}, {dt:.1f}s, std_emb {r['std_emb']:.3f})")
    moe_melhor_densa = bracos["moe"]["perda_pred_final"] < bracos["densa"]["perda_pred_final"]
    moe_melhor_pequena = bracos["moe"]["perda_pred_final"] < bracos["pequena"]["perda_pred_final"]
    res["demos"]["jepa_moe"] = {
        "bracos": bracos,
        "moe_melhor_que_densa": moe_melhor_densa,
        "moe_melhor_que_pequena": moe_melhor_pequena,
        "gate_jepa_moe_aprende": bracos["moe"]["aprendeu"],
        "gate_jepa_moe_vs_densa": moe_melhor_densa,
        "gate_jepa_moe_vs_pequena": moe_melhor_pequena,
    }

    # -------------------------------------------- 3: SOM refinado por MoE
    print("\n=== SOM 4D refinado por MoE (water-filling + redirect) ===", flush=True)
    t0 = time.time()
    patches_f64 = [[float(x) for x in p] for p in patches]
    s = nr.som_com_moe(patches_f64, lado=2, passos=90, semente=42)
    dt = time.time() - t0
    print(f"  QE: {s['qe_antes']:.4f} -> {s['qe_depois_water_filling']:.4f} "
          f"(water-filling, {s['reducao_qe_pct']:.1f}% | uniforme: {s['qe_depois_uniforme']:.4f})")
    print(f"  carga por célula (water-filling ∝ QE): {s['carga_por_celula']}")
    print(f"  MSE do decodificador pós-redirect: {s['mse_decodificador_pos_redirect']:.6f} "
          f"(vs QE² {s['qe_antes']**2:.6f})")
    res["demos"]["som_moe"] = {**s, "tempo_s": dt}

    # -------------------------------------------- 4: AcopladorDuplo
    print("\n=== AcopladorDuplo: protocolo duplex Pensamento↔backbone ===", flush=True)
    t0 = time.time()
    a = nr.demo_acoplador_duplo(rodadas=120, timeout_ms=1500)
    dt = time.time() - t0
    print(f"  rodadas: {a['rodadas']} | timeouts: {a['timeouts']} | tempo {a['tempo_total_ms']:.1f}ms")
    print(f"  duplex simultâneo: A→B {a['envios_a_para_b']} == B→A {a['envios_b_para_a']} | "
          f"sobreposição máx {a['maior_sobreposicao_us']}µs")
    res["demos"]["acoplador_duplo"] = {**a, "tempo_s": dt}

    # ------------------------------------------------------------------ resumo
    gates = []
    for nome, sd in res["demos"].items():
        gates += [(f"{nome}.{g[5:]}", val) for g, val in sd.items() if g.startswith("gate_")]
        if isinstance(sd.get("gates"), dict):
            gates += [(f"{nome}.{g[5:]}", val) for g, val in sd["gates"].items() if g.startswith("gate_")]
    ok = sum(1 for _, val in gates if val)
    res["resumo"] = {"gates_totais": len(gates), "gates_ok": ok, "todos_verdes": ok == len(gates)}
    print(f"\n=== RESUMO: {ok}/{len(gates)} gates verdes ===")

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

if __name__ == "__main__":
    main()